def render(self, ticketset): return_div = tag.div(class_=self.cssclass+' projectplanrender' ) # check for missing parameters missingparameter = False if self.rows == [] or self.rows == None: return_div(tag.div('Missing parameter "rows": use a semicolon-separated list to input the "'+self.rowtype+'".', class_='ppwarning')) missingparameter = True if self.rowtype == None or str(self.rowtype).strip() == '': return_div(tag.div('Missing parameter "rowtype": specifies the ticket attribute that should be showed at the rows.', class_='ppwarning')) missingparameter = True if self.cols == [] or self.cols == None: return_div(tag.div('Missing parameter: use a semicolon-separated list to input the "cols".', class_='ppwarning')) missingparameter = True if self.coltype == None or str(self.coltype).strip() == '': return_div(tag.div('Missing parameter "coltype": specifies the ticket attribute that should be showed in the columns.', class_='ppwarning')) missingparameter = True if missingparameter: return return_div #ul = tag.ul() #for tid in ticketset.getIDSortedList(): #ticket = ticketset.getTicket(tid) #ul( tag.li(tid, " ",ticket.getfield('component') , " ", ticket.getfield('owner') )) #return_div(ul) def getstatistictitle( statusdict ): mytitle = '' mysum = 0 for status in statusdict: mytitle += "%s: %s\n" % (status, str(statusdict[status]) ) mysum += int(statusdict[status]) mytitle += "%s: %s" % ('number', mysum) return mytitle def setKV( myStruct, myKey, newValue ): ''' shortcut to set the values correctly used to reduce the code needed while using a list as key of a dict ''' myStruct[str(myKey)] = newValue def tableKeyPrettyPrint( mylist ) : ''' transform a list of keys to a user readable string in: ['a','b'] --> out: 'a|b' ''' return '|'.join(mylist) def tableKeyQueryParameter( parameter, mylist ) : ''' transform a list of keys to a Trac query string parameter (OR) in: x, ['a','b'] --> out: 'x=a&x=b' ''' return '&'.join([ "%s=%s" % (parameter, s) for s in mylist ]) chartheight=80 chartwidth=170 data = {} statistics = {} # init table data for row in self.rows : colstatistics = {} colkeys = {} for col in self.cols : # colkeys[col] = [] setKV( colkeys, col, [] ) # colstatistics[col] = {} setKV( colstatistics, col, {} ) # data[row] = colkeys setKV( data, row, colkeys ) # statistics[row] = colstatistics setKV( statistics, row, colstatistics ) for tid in ticketset.getIDSortedList(): ticket = ticketset.getTicket(tid) ticket_rowtype = ticket.getfield(self.rowtype) ticket_coltype = ticket.getfield(self.coltype) # determine the data cell where the ticket has to be added, keep in mind that rows and cols are list of lists for row in self.rows : for col in self.cols : if ticket_rowtype in row and ticket_coltype in col : data[str(row)][str(col)].append(ticket) # save tickets at precise values of row and col self.log_debug('row:%s col:%s append:%s' % (row,col,tid)) # if ticket_rowtype in self.rows and ticket_coltype in self.cols : # create HTML table table = tag.table( class_="data pptableticketperday" , border = "1", style = 'width:auto;') # create HTML table head thead = tag.thead() tr = tag.tr() tr( tag.th("%s vs %s" % (self.rowtype,self.coltype) ) ) for colkey in self.cols : tr( tag.th(tag.h4(tag.a( tableKeyPrettyPrint(colkey), href=self.macroenv.tracenv.href()+('/query?%s&order=%s' % ( tableKeyQueryParameter(self.coltype, colkey),self.rowtype)) )),title="%s is %s" % (self.coltype, tableKeyPrettyPrint(colkey) ) ) ) # first line with all colkeys if self.showsummarypiechart: tr( tag.th(tag.h4( "Ticket Overview" ) ) ) thead(tr) table(thead) # create HTML table body tbody = tag.tbody() counter=0 for rowkey in self.rows : # switch line color if counter % 2 == 1: class_ = 'odd' else: class_ = 'even' counter += 1 tr = tag.tr( class_=class_ ) # new line td = tag.td() # new cell td(tag.h5(tag.a( tableKeyPrettyPrint(rowkey), href=self.macroenv.tracenv.href()+('/query?%s&order=%s' % ( tableKeyQueryParameter( self.rowtype,rowkey),self.coltype)) )),title="%s is %s" % (self.rowtype, tableKeyPrettyPrint(rowkey) ) ) # first cell contains row key tr(td) for colkey in self.cols : td = tag.td() for ticket in data[str(rowkey)][str(colkey)] : td( tag.span(self.createTicketLink(ticket), class_ = 'ticket_inner' ), " " , mytitle="%s is %s and %s is %s" % (self.rowtype,rowkey,self.coltype,colkey) ) # mytitle might be used later by javascript if not statistics[str(rowkey)][str(colkey)].has_key( ticket.getstatus() ) : statistics[str(rowkey)][str(colkey)][ticket.getstatus()] = 0 statistics[str(rowkey)][str(colkey)][ticket.getstatus()] += 1 tr(td) # compute statistics rowstatistics = {} count = 0 for colkey in statistics[str(rowkey)] : for status in statistics[str(rowkey)][str(colkey)] : if not rowstatistics.has_key(status) : rowstatistics[status] = 0 try: rowstatistics[status] += statistics[str(rowkey)][str(colkey)][status] count += statistics[str(rowkey)][str(colkey)][status] except: pass if self.showsummarypiechart: tr(tag.td(tag.img(src=self.createGoogleChartFromDict('ColorForStatus', rowstatistics, '%s tickets' % (count,), height=chartheight )), class_='ppstatistics' , title=getstatistictitle(rowstatistics)) ) # Summary tbody(tr) table(tbody) # create HTML table foot if self.showsummarypiechart : fullstatistics = {} tfoot = tag.tfoot() tr = tag.tr() tr( tag.td(tag.h5('Ticket Overview') ) ) # create statistics for col fullcount = 0 for colkey in self.cols : colstatistics = {} colcount = 0 for rowkey in self.rows : for status in statistics[str(rowkey)][str(colkey)] : if not fullstatistics.has_key(status) : fullstatistics[status] = 0 if not colstatistics.has_key(status) : colstatistics[status] = 0 try: colstatistics[status] += statistics[str(rowkey)][str(colkey)][status] colcount += statistics[str(rowkey)][str(colkey)][status] fullstatistics[status] += statistics[str(rowkey)][str(colkey)][status] fullcount += statistics[str(rowkey)][str(colkey)][status] except: pass tr(tag.td(tag.img(src=self.createGoogleChartFromDict('ColorForStatus', colstatistics, '%s tickets' % (colcount,), height=chartheight)), title=getstatistictitle(colstatistics) )) # Col Summary tr(tag.td(tag.img(src=self.createGoogleChartFromDict('ColorForStatus', fullstatistics, '%s tickets' % (fullcount,), height=chartheight)), class_='ppstatistics', title=getstatistictitle(fullstatistics))) # Full Summary tfoot(tr) table(tfoot) return_div(table) return return_div
td_div(tag.div( tag.span(self.createTicketLink(ticket), class_ = 'ticket_inner') ) ) if ticket.getfield('status') in countStatus.keys(): # count values countStatus[ticket.getfield('status')] += 1 else: countStatus[ticket.getfield('status')] = 1 #tr(tag.td( tag.div( td_div, style = 'border-left:3px solid %s;' % (color) ) ) ) tr(tag.td( tag.div( td_div ), self.render_statistics(orderedtickets[segment][o]), class_ = '%s %s %s' % (color_class, class_, self.statistics_class) ) ) if self.showsummarypiechart: tr(tag.td(tag.img(src=self.createGoogleChartFromDict('ColorForStatus', countStatus)))) # Summary tbody(tr) table(tbody) countTickets = 0 tfoot = tag.tfoot() tr = tag.tr() tr(tag.td(tag.h5(self.rowtype+': '+str(len(self.rows))))) for segment in self.segments: tr(tag.td(tag.h5(str(counttickets[segment])+' tickets'))) countTickets += counttickets[segment] if self.showsummarypiechart: tr(tag.td(tag.h5(str(str(countTickets))+' tickets'))) # Summary tfoot(tr) table(tfoot) div(table) return div
def render(self, ticketset): return_div = tag.div(class_=self.cssclass + ' projectplanrender') # check for missing parameters missingparameter = False if self.rows == [] or self.rows == None: return_div( tag.div( 'Missing parameter "rows": use a semicolon-separated list to input the "' + self.rowtype + '".', class_='ppwarning')) missingparameter = True if self.rowtype == None or str(self.rowtype).strip() == '': return_div( tag.div( 'Missing parameter "rowtype": specifies the ticket attribute that should be showed at the rows.', class_='ppwarning')) missingparameter = True if self.cols == [] or self.cols == None: return_div( tag.div( 'Missing parameter: use a semicolon-separated list to input the "cols".', class_='ppwarning')) missingparameter = True if self.coltype == None or str(self.coltype).strip() == '': return_div( tag.div( 'Missing parameter "coltype": specifies the ticket attribute that should be showed in the columns.', class_='ppwarning')) missingparameter = True if missingparameter: return return_div #ul = tag.ul() #for tid in ticketset.getIDSortedList(): #ticket = ticketset.getTicket(tid) #ul( tag.li(tid, " ",ticket.getfield('component') , " ", ticket.getfield('owner') )) #return_div(ul) def getstatistictitle(statusdict): mytitle = '' mysum = 0 for status in statusdict: mytitle += "%s: %s\n" % (status, str(statusdict[status])) mysum += int(statusdict[status]) mytitle += "%s: %s" % ('number', mysum) return mytitle def setKV(myStruct, myKey, newValue): ''' shortcut to set the values correctly used to reduce the code needed while using a list as key of a dict ''' myStruct[str(myKey)] = newValue def tableKeyPrettyPrint(mylist): ''' transform a list of keys to a user readable string in: ['a','b'] --> out: 'a|b' ''' return '|'.join(mylist) def tableKeyQueryParameter(parameter, mylist): ''' transform a list of keys to a Trac query string parameter (OR) in: x, ['a','b'] --> out: 'x=a&x=b' ''' return '&'.join(["%s=%s" % (parameter, s) for s in mylist]) chartheight = 80 chartwidth = 170 data = {} statistics = {} # init table data for row in self.rows: colstatistics = {} colkeys = {} for col in self.cols: # colkeys[col] = [] setKV(colkeys, col, []) # colstatistics[col] = {} setKV(colstatistics, col, {}) # data[row] = colkeys setKV(data, row, colkeys) # statistics[row] = colstatistics setKV(statistics, row, colstatistics) for tid in ticketset.getIDSortedList(): ticket = ticketset.getTicket(tid) ticket_rowtype = ticket.getfield(self.rowtype) ticket_coltype = ticket.getfield(self.coltype) # determine the data cell where the ticket has to be added, keep in mind that rows and cols are list of lists for row in self.rows: for col in self.cols: if ticket_rowtype in row and ticket_coltype in col: data[str(row)][str(col)].append( ticket ) # save tickets at precise values of row and col self.log_debug('row:%s col:%s append:%s' % (row, col, tid)) # if ticket_rowtype in self.rows and ticket_coltype in self.cols : # create HTML table table = tag.table(class_="data pptableticketperday", border="1", style='width:auto;') # create HTML table head thead = tag.thead() tr = tag.tr() tr(tag.th("%s vs %s" % (self.rowtype, self.coltype))) for colkey in self.cols: tr( tag.th(tag.h4( tag.a(tableKeyPrettyPrint(colkey), href=self.macroenv.tracenv.href() + ('/query?%s&order=%s' % (tableKeyQueryParameter( self.coltype, colkey), self.rowtype)))), title="%s is %s" % (self.coltype, tableKeyPrettyPrint(colkey))) ) # first line with all colkeys if self.showsummarypiechart: tr(tag.th(tag.h4("Ticket Overview"))) thead(tr) table(thead) # create HTML table body tbody = tag.tbody() counter = 0 for rowkey in self.rows: # switch line color if counter % 2 == 1: class_ = 'odd' else: class_ = 'even' counter += 1 tr = tag.tr(class_=class_) # new line td = tag.td() # new cell td(tag.h5( tag.a(tableKeyPrettyPrint(rowkey), href=self.macroenv.tracenv.href() + ('/query?%s&order=%s' % (tableKeyQueryParameter( self.rowtype, rowkey), self.coltype)))), title="%s is %s" % (self.rowtype, tableKeyPrettyPrint(rowkey))) # first cell contains row key tr(td) for colkey in self.cols: td = tag.td() for ticket in data[str(rowkey)][str(colkey)]: td(tag.span(self.createTicketLink(ticket), class_='ticket_inner'), " ", mytitle="%s is %s and %s is %s" % (self.rowtype, rowkey, self.coltype, colkey)) # mytitle might be used later by javascript if not statistics[str(rowkey)][str(colkey)].has_key( ticket.getstatus()): statistics[str(rowkey)][str(colkey)][ ticket.getstatus()] = 0 statistics[str(rowkey)][str(colkey)][ ticket.getstatus()] += 1 tr(td) # compute statistics rowstatistics = {} count = 0 for colkey in statistics[str(rowkey)]: for status in statistics[str(rowkey)][str(colkey)]: if not rowstatistics.has_key(status): rowstatistics[status] = 0 try: rowstatistics[status] += statistics[str(rowkey)][str( colkey)][status] count += statistics[str(rowkey)][str(colkey)][status] except: pass if self.showsummarypiechart: tr( tag.td(tag.img(src=self.createGoogleChartFromDict( 'ColorForStatus', rowstatistics, '%s tickets' % (count, ), height=chartheight)), class_='ppstatistics', title=getstatistictitle(rowstatistics))) # Summary tbody(tr) table(tbody) # create HTML table foot if self.showsummarypiechart: fullstatistics = {} tfoot = tag.tfoot() tr = tag.tr() tr(tag.td(tag.h5('Ticket Overview'))) # create statistics for col fullcount = 0 for colkey in self.cols: colstatistics = {} colcount = 0 for rowkey in self.rows: for status in statistics[str(rowkey)][str(colkey)]: if not fullstatistics.has_key(status): fullstatistics[status] = 0 if not colstatistics.has_key(status): colstatistics[status] = 0 try: colstatistics[status] += statistics[str(rowkey)][ str(colkey)][status] colcount += statistics[str(rowkey)][str( colkey)][status] fullstatistics[status] += statistics[str(rowkey)][ str(colkey)][status] fullcount += statistics[str(rowkey)][str( colkey)][status] except: pass tr( tag.td( tag.img(src=self.createGoogleChartFromDict( 'ColorForStatus', colstatistics, '%s tickets' % (colcount, ), height=chartheight)), title=getstatistictitle(colstatistics))) # Col Summary tr( tag.td( tag.img(src=self.createGoogleChartFromDict( 'ColorForStatus', fullstatistics, '%s tickets' % (fullcount, ), height=chartheight)), class_='ppstatistics', title=getstatistictitle(fullstatistics))) # Full Summary tfoot(tr) table(tfoot) return_div(table) return return_div
#tr(tag.td( tag.div( td_div, style = 'border-left:3px solid %s;' % (color) ) ) ) tr( tag.td(tag.div(td_div), self.render_statistics(orderedtickets[segment][o]), class_='%s %s %s' % (color_class, class_, self.statistics_class))) if self.showsummarypiechart: tr( tag.td( tag.img(src=self.createGoogleChartFromDict( 'ColorForStatus', countStatus)))) # Summary tbody(tr) table(tbody) countTickets = 0 tfoot = tag.tfoot() tr = tag.tr() tr(tag.td(tag.h5(self.rowtype + ': ' + str(len(self.rows))))) for segment in self.segments: tr(tag.td(tag.h5(str(counttickets[segment]) + ' tickets'))) countTickets += counttickets[segment] if self.showsummarypiechart: tr(tag.td(tag.h5(str(str(countTickets)) + ' tickets'))) # Summary tfoot(tr) table(tfoot) div(table) return div class TicketTableAvsB(RenderImpl):
def render(self, ticketset): # add needed javascript and css files self.addJsChartFiles() if self.firstsegment == None or self.lastsegment == None: return self.divWarning('you have to set the time period via the macro parameters. Example: first=2012-02-03, last=2012-02-19 .') tickets = ticketset.getIDList() # stop if no tickets available if len(tickets) == 0: return self.divWarning('No tickets available.') changes = {} initalvalues = {} creationdates = {} (firstday,lastday) = self.getBoundaries({}) alldates = self.getAllRelevantDates(firstday, lastday) lastdaySecs = lastday firstday = self.normalizeToDay(firstday) lastday = self.normalizeToDay(lastday) (ticketCount, relevantChanges) = self.computeInformationAboutSegment( ticketset, firstday, lastday ) # count only the tickets that are relevant within the requested time period (firstday,lastday) relevantTickets = ticketCount closedTickets = {} # change this openTickets = {} # change this changeDateStrings = relevantChanges.keys() changeDateStrings.sort() # ticketCount = 70 # DEBUG for changeDateStr in changeDateStrings: # for each day self.macroenv.tracenv.log.debug("changes %4s: %3s (%s)" % (changeDateStr,relevantChanges[changeDateStr], ticketCount)) self.setKeyIfNotExistsInt( closedTickets, changeDateStr, -1*relevantChanges[changeDateStr] ) ticketCount = ticketCount + relevantChanges[changeDateStr] # reduce the number of open tickets self.setKeyIfNotExistsInt( openTickets , changeDateStr, ticketCount) # generate HTML holderid = "%s_%s_%d_%d" % (self.getNameOfRenderFrame(),'holder',int(time.time()*1000000),random.randint(1,1024) ) # compute unique element id currentday = firstday frame = tag.div( class_= 'invisible ppConfBurnDown', id=self.getNameOfRenderFrame()+holderid ) tableData = tag.table( class_="invisible data" , border = "1", style = 'width:auto;') trDays = tag.tr() trDaysAxis = tag.tr() trOpenTickets = tag.tr() trClosedTickets = tag.tr() trReopenedTickets = tag.tr() alldates.sort() lastOpenTicket = relevantTickets # fallback: all tickets lastClosedTickets = 0 counter = 0 todaySecs = self.datetime2seconds( datetime.datetime.today() ) todayStr = self.getDateString(todaySecs) todayid = 0 maxValue = 0 if lastdaySecs <= todaySecs: # if today is later then the shown time frame then mark the last column todayid = len(alldates) for currentday in alldates: if currentday == todayStr: # capture the column with the current date todayid = counter counter = counter + 1 trDays(tag.th(currentday.replace("\n"," "))) # text for info box, no line breaks here, because it is limited to 3 lines trDaysAxis(tag.th(currentday)) if openTickets.has_key(currentday) : lastOpenTicket = openTickets[currentday] trOpenTickets(tag.td(lastOpenTicket)) if closedTickets.has_key(currentday) : lastClosedTickets = closedTickets[currentday] else: lastClosedTickets = 0 trClosedTickets(tag.td(lastClosedTickets)) maxValue = max(len(str(lastClosedTickets)),len(str(lastOpenTicket)),maxValue) trReopenedTickets(tag.td('0')) tableData(tag.thead(trDays)) tableData(tag.tfoot(trDaysAxis)) tableData(tag.tbody(trOpenTickets, trClosedTickets, trReopenedTickets )) (label1,label2) = self.getLabel() # caculate the scale factor for the info box within the chart maxGlobal = max( len(str(label1))+maxValue, len(str(label2))+maxValue ) if self.segment in ['week','twoweek']: # they use long descriptions in the info box maxGlobal = max(maxGlobal, 27) # configuration of renderer frame(tag.div( str(relevantTickets), class_ = 'maxTasks' )) frame(tag.div( self.width, class_ = 'width' )) frame(tag.div( self.height, class_ = 'height' )) frame(tag.div( str(maxGlobal), class_ = 'maxlength' )) frame(tag.div( label1, class_ = 'label1' )) frame(tag.div( label2, class_ = 'label2' )) frame(tag.div( str(todayid), class_ = 'today' )) # number of column with the current date frame(tag.div( holderid, class_ = 'holder' )) # where to put the chart in frame(tableData) outerframe = tag.div() # div as global container #outerframe(outer) # DEBUG outerframe(frame) outerframe(tag.div( id = holderid ), style="border-width:1px" ) outerframe(tag.script("$.getScript('%s'); $.getScript('%s'); $.getScript('%s'); " % ('projectplan/js/jquery-burndown/raphael.js', 'projectplan/js/jquery-burndown/raphael_002.js','projectplan/js/jquery-burndown/burndown.js' ) ) ) return outerframe
def render(self, ticketset): # add needed javascript and css files self.addJsChartFiles() if self.firstsegment == None or self.lastsegment == None: return self.divWarning( 'you have to set the time period via the macro parameters. Example: first=2012-02-03, last=2012-02-19 .' ) tickets = ticketset.getIDList() # stop if no tickets available if len(tickets) == 0: return self.divWarning('No tickets available.') changes = {} initalvalues = {} creationdates = {} (firstday, lastday) = self.getBoundaries({}) alldates = self.getAllRelevantDates(firstday, lastday) lastdaySecs = lastday firstday = self.normalizeToDay(firstday) lastday = self.normalizeToDay(lastday) (ticketCount, relevantChanges) = self.computeInformationAboutSegment( ticketset, firstday, lastday) # count only the tickets that are relevant within the requested time period (firstday,lastday) relevantTickets = ticketCount closedTickets = {} # change this openTickets = {} # change this changeDateStrings = relevantChanges.keys() changeDateStrings.sort() # ticketCount = 70 # DEBUG for changeDateStr in changeDateStrings: # for each day self.macroenv.tracenv.log.debug( "changes %4s: %3s (%s)" % (changeDateStr, relevantChanges[changeDateStr], ticketCount)) self.setKeyIfNotExistsInt(closedTickets, changeDateStr, -1 * relevantChanges[changeDateStr]) ticketCount = ticketCount + relevantChanges[ changeDateStr] # reduce the number of open tickets self.setKeyIfNotExistsInt(openTickets, changeDateStr, ticketCount) # generate HTML holderid = "%s_%s_%d_%d" % ( self.getNameOfRenderFrame(), 'holder', int(time.time() * 1000000), random.randint(1, 1024)) # compute unique element id currentday = firstday frame = tag.div(class_='invisible ppConfBurnDown', id=self.getNameOfRenderFrame() + holderid) tableData = tag.table(class_="invisible data", border="1", style='width:auto;') trDays = tag.tr() trDaysAxis = tag.tr() trOpenTickets = tag.tr() trClosedTickets = tag.tr() trReopenedTickets = tag.tr() alldates.sort() lastOpenTicket = relevantTickets # fallback: all tickets lastClosedTickets = 0 counter = 0 todaySecs = self.datetime2seconds(datetime.datetime.today()) todayStr = self.getDateString(todaySecs) todayid = 0 maxValue = 0 if lastdaySecs <= todaySecs: # if today is later then the shown time frame then mark the last column todayid = len(alldates) for currentday in alldates: if currentday == todayStr: # capture the column with the current date todayid = counter counter = counter + 1 trDays( tag.th(currentday.replace("\n", " ")) ) # text for info box, no line breaks here, because it is limited to 3 lines trDaysAxis(tag.th(currentday)) if openTickets.has_key(currentday): lastOpenTicket = openTickets[currentday] trOpenTickets(tag.td(lastOpenTicket)) if closedTickets.has_key(currentday): lastClosedTickets = closedTickets[currentday] else: lastClosedTickets = 0 trClosedTickets(tag.td(lastClosedTickets)) maxValue = max(len(str(lastClosedTickets)), len(str(lastOpenTicket)), maxValue) trReopenedTickets(tag.td('0')) tableData(tag.thead(trDays)) tableData(tag.tfoot(trDaysAxis)) tableData(tag.tbody(trOpenTickets, trClosedTickets, trReopenedTickets)) (label1, label2) = self.getLabel() # caculate the scale factor for the info box within the chart maxGlobal = max( len(str(label1)) + maxValue, len(str(label2)) + maxValue) if self.segment in ['week', 'twoweek' ]: # they use long descriptions in the info box maxGlobal = max(maxGlobal, 27) # configuration of renderer frame(tag.div(str(relevantTickets), class_='maxTasks')) frame(tag.div(self.width, class_='width')) frame(tag.div(self.height, class_='height')) frame(tag.div(str(maxGlobal), class_='maxlength')) frame(tag.div(label1, class_='label1')) frame(tag.div(label2, class_='label2')) frame( tag.div(str(todayid), class_='today')) # number of column with the current date frame(tag.div(holderid, class_='holder')) # where to put the chart in frame(tableData) outerframe = tag.div() # div as global container #outerframe(outer) # DEBUG outerframe(frame) outerframe(tag.div(id=holderid), style="border-width:1px") return outerframe