GanttCalendarPlugin: file names of template have ganttcalendar_ prefix
@@ -235,7 +235,7 @@ | ||
235 | 235 | 'show_my_ticket': show_my_ticket, 'show_closed_ticket': show_closed_ticket, 'selected_milestone': selected_milestone, |
236 | 236 | '_':_,'dateFormat':dateFormat, 'holidays':holidays, 'month_tbl': month_tbl} |
237 | 237 | |
238 | - return 'calendar.html', data, None | |
238 | + return 'ganttcalendar_calendar.html', data, None | |
239 | 239 | |
240 | 240 | def get_templates_dirs(self): |
241 | 241 | from pkg_resources import resource_filename |
@@ -664,7 +664,7 @@ | ||
664 | 664 | # only Trac 0.12, not compatible with Trac 0.11.x |
665 | 665 | add_script(req, 'tc/js/query.js') |
666 | 666 | |
667 | - return 'gantt.html', data, None | |
667 | + return 'ganttcalendar_gantt.html', data, None | |
668 | 668 | |
669 | 669 | def get_templates_dirs(self): |
670 | 670 | from pkg_resources import resource_filename |
@@ -1,246 +0,0 @@ | ||
1 | -<html xmlns="http://www.w3.org/1999/xhtml" | |
2 | - xmlns:py="http://genshi.edgewall.org/" | |
3 | - xmlns:xi="http://www.w3.org/2001/XInclude"> | |
4 | - <xi:include href="layout.html" /> | |
5 | - <xi:include href="macros.html" /> | |
6 | - <head> | |
7 | - <script type="text/javascript" src="${chrome.htdocs_location}js/folding.js"></script> | |
8 | - <script type="text/javascript"> | |
9 | - jQuery(document).ready(function($) { | |
10 | - $("fieldset legend.foldable").enableFolding(false); | |
11 | - /* Hide the filters for saved queries. */ | |
12 | - $("#options").toggleClass("collapsed"); | |
13 | - }); | |
14 | - </script> | |
15 | - | |
16 | - <style type="text/css"> | |
17 | - form fieldset.collapsed { | |
18 | - border-width: 0px; | |
19 | - margin-bottom: 0px; | |
20 | - padding: 0px .5em; | |
21 | - } | |
22 | - fieldset legend.foldable :link, | |
23 | - fieldset legend.foldable :visited { | |
24 | - background: url(${chrome.htdocs_location}expanded.png) 0 50% no-repeat; | |
25 | - border: none; | |
26 | - color: #666; | |
27 | - font-size: 110%; | |
28 | - padding-left: 16px; | |
29 | - } | |
30 | - fieldset legend.foldable :link:hover, fieldset legend.foldable :visited:hover { | |
31 | - background-color: transparent; | |
32 | - } | |
33 | - | |
34 | - fieldset.collapsed legend.foldable :link, fieldset.collapsed legend.foldable :visited { | |
35 | - background-image: url(${chrome.htdocs_location}collapsed.png); | |
36 | - } | |
37 | - fieldset.collapsed table, fieldset.collapsed div { display: none } | |
38 | - | |
39 | - table.list { | |
40 | - width:100%; | |
41 | - border-collapse: collapse; | |
42 | - margin-bottom: 6px; | |
43 | - } | |
44 | - | |
45 | - table.with-cells td { | |
46 | - border: 1px solid #d7d7d7; | |
47 | - } | |
48 | - | |
49 | - table.list td { | |
50 | - padding:2px; | |
51 | - } | |
52 | - | |
53 | - table.list thead th { | |
54 | - text-align: center; | |
55 | - background: #eee; | |
56 | - border: 1px solid #d7d7d7; | |
57 | - color: #777; | |
58 | - } | |
59 | - | |
60 | - table.list tbody th { | |
61 | - font-weight: bold; | |
62 | - background: #eed; | |
63 | - border: 1px solid #d7d7d7; | |
64 | - color: #777; | |
65 | - } | |
66 | - | |
67 | - | |
68 | - .ticket { | |
69 | - font-size: 10px; | |
70 | - } | |
71 | - | |
72 | - | |
73 | - .textright { | |
74 | - text-align:right; | |
75 | - } | |
76 | - | |
77 | - td.active { | |
78 | - background-color:#fff; | |
79 | - } | |
80 | - .holiday { | |
81 | - background-color: #f6f7f8; | |
82 | - color: black; | |
83 | - } | |
84 | - .today { | |
85 | - background-color: #ffe0e0; | |
86 | - } | |
87 | - | |
88 | - .tip { | |
89 | - position: static; | |
90 | - } | |
91 | - | |
92 | - .tip span.popup{ | |
93 | - position: absolute; | |
94 | - visibility: hidden; | |
95 | - color: black; | |
96 | - border:1px solid #555; | |
97 | - background-color: #ffe; | |
98 | - font-size: 8pt; | |
99 | - padding: 3px; | |
100 | - /*IE6 Hack*/ min-width: 400px; width: auto; _width: 400px; | |
101 | - } | |
102 | - | |
103 | - .tip:hover span.popup{ | |
104 | - visibility: visible; | |
105 | - z-index: 100; | |
106 | - } | |
107 | - | |
108 | - </style> | |
109 | - </head> | |
110 | - <body> | |
111 | - <form> | |
112 | - <fieldset id="options"> | |
113 | - <legend class="foldable">${_('Options')}</legend> | |
114 | - <table class="list"> | |
115 | - <tr> | |
116 | - <td> | |
117 | - </td> | |
118 | - <td> | |
119 | - <label> | |
120 | - ${_('Milestone')} | |
121 | - <select name="selected_milestone"> | |
122 | - <option py:for="m in milestones" value="${m.name}" selected="${selected_milestone==m.name or None}">${m.name}</option> | |
123 | - </select> | |
124 | - </label> | |
125 | - <label> | |
126 | - <input type="checkbox" name="show_my_ticket" checked="$show_my_ticket" | |
127 | - />${_('Show only my tickets')} | |
128 | - </label> | |
129 | - <label> | |
130 | - <input type="checkbox" name="show_closed_ticket" checked="$show_closed_ticket" | |
131 | - />${_('Include closed tickets')} | |
132 | - </label> | |
133 | - </td> | |
134 | - <td align="right"> | |
135 | - <input type="submit" value="${_('Update')}" /> | |
136 | - </td> | |
137 | - </tr> | |
138 | - </table> | |
139 | - </fieldset> | |
140 | - <table class="list"> | |
141 | - <tr> | |
142 | - <td py:with="btntxt = weekly and '%s %s' % (_(month_tbl[prev.month]), prev.day) or _(month_tbl[prev.month])"> | |
143 | - <input type="button" value="<< ${btntxt}" ACCESSKEY="J" onclick="form.year.value = ${prev.year}; form.month.value = ${prev.month}; form.day.value = ${prev.day}; form.submit();"/> | |
144 | - </td> | |
145 | - <td align="center"> | |
146 | - <select name="year" onchange="form.day.value = 1; form.weekly.value = 0;"> | |
147 | - <option py:for="y in range(current.year-3,current.year+4)" | |
148 | - value="$y" | |
149 | - selected="${y==current.year or None}">$y</option> | |
150 | - </select> | |
151 | - ${_('Year')} | |
152 | - <select name="month" onchange="form.day.value = 1; form.weekly.value = 0;"> | |
153 | - <option py:for="m in [1,2,3,4,5,6,7,8,9,10,11,12]" | |
154 | - value="$m" selected="${m==current.month or None}">${_(month_tbl[m])}</option> | |
155 | - </select> | |
156 | - | |
157 | - <input type="submit" value="${_('Update')}" /> | |
158 | - <label ACCESSKEY="M" onclick="form.year.value = ${date.today().year}; form.month.value = ${date.today().month}; form.day.value = ${date.today().day}; form.submit();"/> | |
159 | - <py:choose> | |
160 | - <input py:when="not weekly" type="image" ACCESSKEY="I" onclick="form.weekly.value = 1" src="${href.chrome('tc/img/zoom_in.png')}" alt="${_('Zoom In')}"/> | |
161 | - <input py:otherwise="" type="image" disabled="disabled" src="${href.chrome('tc/img/zoom_in_g.png')}"/> | |
162 | - </py:choose> | |
163 | - <py:choose> | |
164 | - <input py:when="weekly" type="image" ACCESSKEY="K" onclick="form.weekly.value = 0;" src="${href.chrome('tc/img/zoom_out.png')}" alt="${_('Zoom Out')}"/> | |
165 | - <input py:otherwise="" type="image" disabled="disabled" src="${href.chrome('tc/img/zoom_out_g.png')}"/> | |
166 | - </py:choose> | |
167 | - <input name="day" type="hidden" value="${current.day}" /> | |
168 | - <input name="weekly" type="hidden" value="${weekly}" /> | |
169 | - </td> | |
170 | - <td align="right" py:with="btntxt = weekly and '%s %s' % (_(month_tbl[next.month]), next.day) or _(month_tbl[next.month])"> | |
171 | - <input type="button" value="${btntxt} >>" ACCESSKEY="L" onclick="form.year.value = ${next.year}; form.month.value = ${next.month}; form.day.value = ${next.day}; form.submit();"/> | |
172 | - </td> | |
173 | - </tr> | |
174 | - </table> | |
175 | - </form> | |
176 | - <table py:if="sum_estimatedhours != None" class="list"> | |
177 | - <div style="font-size:11px;"> ${_('Total Hours')}: ${sum_totalhours}h / | |
178 | - ${_('Estimated Hours')}: ${sum_estimatedhours}h</div> | |
179 | - </table> | |
180 | - <table class="list with-cells"> | |
181 | - <thead> | |
182 | - <tr py:with="weekdays = [_('Monday'), _('Tuesday'), _('Wednesday'), | |
183 | - _('Thursday'), _('Friday'), _('Saturday'), _('Sunday')]"> | |
184 | - <th></th> | |
185 | - <py:for each="d in range(7)" py:with="mday= first+ timedelta(d);wk=mday.weekday();"> | |
186 | - <th style="width: 14%;">${weekdays[wk]}</th> | |
187 | - </py:for> | |
188 | - </tr> | |
189 | - </thead> | |
190 | - | |
191 | - <tbody> | |
192 | - <tr py:for="w in range(((last - first).days + 1)/7)" style="height: ${weekly and 300 or 60}px;"> | |
193 | - <th></th> | |
194 | - <py:for each="d in range(7)" py:with="mday= first+ timedelta(w*7+d);holiday_desc= days[mday].get('holiday_desc');"> | |
195 | - <td class="${days[mday]['kind']}" style="width: 14%;" valign="top"> | |
196 | - <div class="textright"> | |
197 | - <span py:attrs="{'title':holiday_desc}" py:strip="holiday_desc==None" > | |
198 | - <py:if test="weekly or mday.day==1">${mday.month}/</py:if>${mday.day} | |
199 | - </span> | |
200 | - </div> | |
201 | - <py:for each="c in range(len(days[mday]['ticket']))"> | |
202 | - <div class="ticket" py:with="t=tickets[days[mday]['ticket'][c]['num']]"> | |
203 | - <a class="tip" href="${req.href.ticket()}/${t['id']}"> | |
204 | - <img src="${href.chrome('tc/img/arrow_'+days[mday]['ticket'][c]['img']+'.png')}" alt="+" /> | |
205 | - <s py:strip="t['status']!='closed'"><span class="type">${t['type']}</span>#${t['id']}</s>:${t['summary']} | |
206 | - <span class="popup"> | |
207 | - <br /> | |
208 | - <s py:strip="t['status']!='closed'"> ${t['type']}#${t['id']}</s>: ${t['summary']}<br /> | |
209 | - <br /> | |
210 | - <strong>${_('Start date')}</strong>: <span py:if="t['due_assign'] != None">${t['due_assign'].strftime(dateFormat)}</span> | |
211 | - <span py:if="t['status']!='closed'">(${t['status']} ${t['complete']}%)</span><br/> | |
212 | - <strong>${_('End date')}</strong>: <span py:if="t['due_close'] != None">${t['due_close'].strftime(dateFormat)}</span> | |
213 | - <span py:if="t['status']=='closed'">(${t['status']}: ${t['resolution']})</span><br/> | |
214 | - <strong>${_('Owner')}</strong>: ${format_author(t['owner'])}<br /> | |
215 | - <strong>${_('Priority')}</strong>: ${t['priority']}<br/> | |
216 | - <py:if test="t['estimatedhours']!=None"> | |
217 | - <strong>${_('Total Hours')}</strong>: ${t['totalhours']}h / | |
218 | - <strong>${_('Estimated Hours')}</strong>: ${t['estimatedhours']}h<br/> | |
219 | - </py:if> | |
220 | - <pre> ${t['description']}</pre> | |
221 | - </span> | |
222 | - </a> | |
223 | - </div> | |
224 | - </py:for> | |
225 | - | |
226 | - <py:for each="c in range(len(days[mday]['milestone']))" py:if="'MILESTONE_VIEW' in req.perm"> | |
227 | - <div class="ticket" py:with="m=milestones[days[mday]['milestone'][c]]"> | |
228 | - <a class="tip" href="${req.href.milestone()}/${m['name']}"> | |
229 | - <s py:strip="m['completed']!=True"><img src="${href.chrome('tc/img/package.png')}" />${m['name']}</s> | |
230 | - <span class="popup"> | |
231 | - <br /> | |
232 | - <img src="${href.chrome('tc/img/package.png')}" />${m['name']}<br /> | |
233 | - <br /> | |
234 | - <strong>${_('Due')}</strong>: ${m['due'].strftime(dateFormat)}<br /> | |
235 | - <pre> ${m['description']}</pre> | |
236 | - </span> | |
237 | - </a> | |
238 | - </div> | |
239 | - </py:for> | |
240 | - </td> | |
241 | - </py:for> | |
242 | - </tr> | |
243 | - </tbody> | |
244 | - </table> | |
245 | - </body> | |
246 | -</html> |
@@ -1,67 +0,0 @@ | ||
1 | -<!DOCTYPE html | |
2 | - PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |
3 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
4 | -<html xmlns="http://www.w3.org/1999/xhtml" | |
5 | - xmlns:xi="http://www.w3.org/2001/XInclude" | |
6 | - xmlns:py="http://genshi.edgewall.org/"> | |
7 | - <xi:include href="admin.html" /> | |
8 | - <head> | |
9 | - <title>${_('Holidays')}</title> | |
10 | - </head> | |
11 | - | |
12 | - <body> | |
13 | - <h2>${_('Holiday Setting')}</h2> | |
14 | - <py:if test="tbl_chk"> | |
15 | - <form class="addnew" method="post" action=""> | |
16 | - <fieldset> | |
17 | - <legend>${_('Add Holiday')}<span/>:</legend> | |
18 | - <div class="field"> | |
19 | - <label>${_('date')}<span/>:<br /><input type="text" name="date" /></label> | |
20 | - </div> | |
21 | - <label>${_('description')}<span/>:<br /><input type="text" name="description" /></label> | |
22 | - <div class="buttons"> | |
23 | - <input type="submit" name="add" value="${_('submit')}"/> | |
24 | - </div> | |
25 | - </fieldset> | |
26 | - </form> | |
27 | - <form class="addnew" method="post" action=""> | |
28 | - <fieldset> | |
29 | - <legend>${_('Drop table')}<span/>:</legend> | |
30 | - <div class="buttons"> | |
31 | - <input type="submit" name="drop_table" value="${_('DROP holiday table.')}"/> | |
32 | - </div> | |
33 | - </fieldset> | |
34 | - </form> | |
35 | - | |
36 | - <form id="holidays_table" method="post" action=""> | |
37 | - <table class="listing"> | |
38 | - <thead> | |
39 | - <th class="sel"> </th> | |
40 | - <th>${_('date')}</th> | |
41 | - <th>${_('description')}</th> | |
42 | - </thead> | |
43 | - <tr py:for="m in holidays"> | |
44 | - <td class="sel"><input type="checkbox" name="sel" value="${m.get('date','')}" /></td> | |
45 | - <td class="name">${m.get('date','')}</td> | |
46 | - <td class="name">${m.get('description','')}</td> | |
47 | - </tr> | |
48 | - </table> | |
49 | - <div class="buttons"> | |
50 | - <input type="submit" name="remove" value="${_('Remove selected items')}" /> | |
51 | - </div> | |
52 | - <p class="help"> | |
53 | - </p> | |
54 | - </form> | |
55 | - </py:if> | |
56 | - <py:if test= "not tbl_chk"> | |
57 | - <form class="addnew" method="post" action=""> | |
58 | - <fieldset> | |
59 | - <legend>${_('Add Holiday')}<span/>:</legend> | |
60 | - <div class="buttons"> | |
61 | - <input type="submit" name="create_table" value="${_('Create table and insert some holidays.')}"/> | |
62 | - </div> | |
63 | - </fieldset> | |
64 | - </form> | |
65 | - </py:if> | |
66 | - </body> | |
67 | -</html> |
@@ -1,461 +0,0 @@ | ||
1 | -<html xmlns="http://www.w3.org/1999/xhtml" | |
2 | - xmlns:py="http://genshi.edgewall.org/" | |
3 | - xmlns:i18n="http://genshi.edgewall.org/i18n" | |
4 | - xmlns:xi="http://www.w3.org/2001/XInclude" | |
5 | - py:with="px_ti=30;px_hd=46;px_dw=36/zoom;px_ch=10;maxtic=len(tickets);px_left=3;px_top=13;px_height=px_top+px_ch;"> | |
6 | - <xi:include href="layout.html" /> | |
7 | - <xi:include href="macros.html" /> | |
8 | - <head> | |
9 | - <script type="text/javascript" src="${chrome.htdocs_location}js/folding.js"></script> | |
10 | - <script type="text/javascript">/*<![CDATA[*/ | |
11 | - jQuery(document).ready(function($) { | |
12 | - initializeFilters(); | |
13 | - $("fieldset legend.foldable").enableFolding(false); | |
14 | - /* Hide the filters for saved queries. */ | |
15 | - $("#options").toggleClass("collapsed"); | |
16 | - }); | |
17 | - /*]]>*/</script> | |
18 | - | |
19 | - <style type="text/css"> | |
20 | - form fieldset.collapsed { | |
21 | - border-width: 0px; | |
22 | - margin-bottom: 0px; | |
23 | - padding: 0px .5em; | |
24 | - } | |
25 | - fieldset legend.foldable :link, | |
26 | - fieldset legend.foldable :visited { | |
27 | - background: url(${chrome.htdocs_location}expanded.png) 0 50% no-repeat; | |
28 | - border: none; | |
29 | - color: #666; | |
30 | - font-size: 110%; | |
31 | - padding-left: 16px; | |
32 | - } | |
33 | - fieldset legend.foldable :link:hover, fieldset legend.foldable :visited:hover { | |
34 | - background-color: transparent; | |
35 | - } | |
36 | - | |
37 | - fieldset.collapsed legend.foldable :link, fieldset.collapsed legend.foldable :visited { | |
38 | - background-image: url(${chrome.htdocs_location}collapsed.png); | |
39 | - } | |
40 | - fieldset.collapsed table, fieldset.collapsed div { display: none } | |
41 | - table.list {width:100%;border-collapse: collapse;margin-bottom: 6px;} | |
42 | - table.list td {padding:2px;} | |
43 | - .border_line {background-color: gray;} | |
44 | - .hdr {position: absolute;background-color: #eee;} | |
45 | - .hdr_title {display:block;position: absolute; width:100%;text-align:center;font-size:10px;} | |
46 | - .bdy {position: absolute;background-color: #fff;text-align: left;top:${px_hd}px;height:${maxtic*px_ti+px_height}px;} | |
47 | - .bdy_elem {position: absolute;font-size: 10px;left:1px;height:${px_ti-2}px;} | |
48 | - .tic_summary {position: absolute;font-size: 10px;color: #000; background-color: #fff; height: 11px; line-height: 11px; white-space:nowrap;} | |
49 | - .stripe {position: absolute; overflow: hidden; background: #e8f0f8;} | |
50 | - .tip {position: static;} | |
51 | - .tip span.popup{position: absolute;visibility: hidden;background-color: #ffe;color: black;border: 1px solid #555;left: 20px;top: 30px;padding: 3px; | |
52 | - /*IE6 Hack*/ min-width: 400px; width: auto; _width: 400px; | |
53 | - } | |
54 | - .tip:hover span.popup | |
55 | - {visibility: visible; z-index: 100;font-size: 11px;} | |
56 | - | |
57 | - .tic_done {position: absolute; overflow: hidden; cursor: pointer; background:lightgreen;} | |
58 | - .tic_late {position: absolute; overflow: hidden; cursor: pointer; background:pink;} | |
59 | - .tic_todo {position: absolute; overflow: hidden; cursor: pointer; background:lightgrey;} | |
60 | - .tic_done_bl {position: absolute; overflow: hidden; background:green;} | |
61 | - .tic_late_bl {position: absolute; overflow: hidden; background:red;} | |
62 | - .tic_todo_bl {position: absolute; overflow: hidden; background:gray;} | |
63 | - | |
64 | - .baseline {position: absolute; overflow: hidden; border-left: 1px dashed red;} | |
65 | - div.milestone {position: absolute; overflow: hidden; background-color: red;} | |
66 | - </style> | |
67 | - </head> | |
68 | - <body py:with="weekdays = [_('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa'), _('Su')]"> | |
69 | - <form id="query" method="get" | |
70 | - py:with="field_names = sorted(fields.iterkeys(), key=lambda name: fields[name].label.lower())"> | |
71 | - <fieldset id="filters"> | |
72 | - <legend class="foldable">Filters</legend> | |
73 | - <table summary="Query filters"> | |
74 | - <tbody py:for="clause_num, constraints in enumerate(clauses or [{}])" | |
75 | - py:with="clause_pre = '%d_' % clause_num"> | |
76 | - <tr style="${clause_num == 0 and 'display: none' or None}"> | |
77 | - <td> | |
78 | - <div class="trac-clause-lsep"> <hr /></div> | |
79 | - <div class="trac-clause-msep">Or</div> | |
80 | - <div class="trac-clause-rsep"> <hr /></div> | |
81 | - </td> | |
82 | - </tr> | |
83 | - <tr><td class="trac-clause"> | |
84 | - <table class="trac-clause"> | |
85 | - <tbody py:for="field_name in field_names" py:if="field_name in constraints" | |
86 | - py:with="field = fields[field_name]; n_field_name = clause_pre + field_name; | |
87 | - constraint = constraints[field_name]; | |
88 | - multiline = field.type in ('select', 'text', 'textarea', 'time')"> | |
89 | - <tr py:for="constraint_idx, constraint_value in enumerate(constraint['values'])" | |
90 | - class="${field_name}" py:if="multiline or constraint_idx == 0"> | |
91 | - <td> | |
92 | - <div class="inlinebuttons"> | |
93 | - <input type="submit" name="rm_filter_${n_field_name}_${constraint_idx}" value="–" /> | |
94 | - </div> | |
95 | - </td> | |
96 | - <py:choose test="constraint_idx"> | |
97 | - <py:when test="0"> | |
98 | - <th scope="row"><label id="label_${n_field_name}">${fields[field_name].label}</label></th> | |
99 | - <td py:if="field.type not in ('radio', 'checkbox', 'time')" class="mode"> | |
100 | - <select name="${n_field_name}_mode"> | |
101 | - <option py:for="mode in modes[field.type]" value="$mode.value" | |
102 | - selected="${mode.value == constraint.mode and 'selected' or None}">$mode.name</option> | |
103 | - </select> | |
104 | - </td> | |
105 | - </py:when> | |
106 | - <py:otherwise><!--! not the first line of a multiline constraint --> | |
107 | - <th colspan="${field.type == 'time' and 1 or 2}"><label>or</label></th> | |
108 | - </py:otherwise> | |
109 | - </py:choose> | |
110 | - | |
111 | - <td class="filter" colspan="${field.type in ('radio', 'checkbox', 'time') and 2 or None}" | |
112 | - py:choose=""> | |
113 | - | |
114 | - <py:when test="field.type == 'select'"> | |
115 | - <select name="${n_field_name}"> | |
116 | - <option></option> | |
117 | - <option py:for="option in field.options" | |
118 | - selected="${option == constraint_value and 'selected' or None}" | |
119 | - value="$option" py:content="option"></option> | |
120 | - </select> | |
121 | - </py:when> | |
122 | - | |
123 | - <py:when test="field.type == 'radio'"> | |
124 | - <py:for each="option in field.options"> | |
125 | - <input type="checkbox" id="_${n_field_name}_$option" name="${n_field_name}" | |
126 | - value="$option" | |
127 | - checked="${((constraint['mode'] == '') == (option in constraint['values'])) | |
128 | - and 'checked' or None}" /> | |
129 | - <label for="_${n_field_name}_$option" class="control">${option or 'none'}</label> | |
130 | - </py:for> | |
131 | - </py:when> | |
132 | - | |
133 | - <py:when test="field.type == 'checkbox'"> | |
134 | - <input type="radio" id="_${n_field_name}_on" name="$n_field_name" value="1" | |
135 | - checked="${constraint.mode != '!' or constraint_value == '1' or None}" /> | |
136 | - <label for="_${n_field_name}_on" class="control">yes</label> | |
137 | - <input type="radio" id="_${n_field_name}_off" name="$n_field_name" value="0" | |
138 | - checked="${constraint.mode == '!' or constraint_value != '1' or None}" /> | |
139 | - <label for="_${n_field_name}_off" class="control">no</label> | |
140 | - </py:when> | |
141 | - | |
142 | - <py:when test="field.type in ('text', 'textarea', 'id')"> | |
143 | - <input type="text" name="${n_field_name}" value="$constraint_value" size="42" /> | |
144 | - </py:when> | |
145 | - | |
146 | - <py:when test="field.type == 'time'" | |
147 | - py:with="(start, end) = '..' in constraint_value and constraint_value.split('..', 1) | |
148 | - or (constraint_value, '')"> | |
149 | - <i18n:msg> | |
150 | - <label>between</label> | |
151 | - <input type="text" name="${n_field_name}" value="$start" size="14" /> | |
152 | - <label>and</label> | |
153 | - <input type="text" name="${n_field_name}_end" value="$end" size="14" /> | |
154 | - </i18n:msg> | |
155 | - </py:when> | |
156 | - </td> | |
157 | - </tr> | |
158 | - </tbody> | |
159 | - | |
160 | - <tbody py:with="last_clause = clause_num == (len(clauses) or 1) - 1"> | |
161 | - <tr class="actions"> | |
162 | - <td class="and" colspan="2"> | |
163 | - <label for="add_filter_${clause_num}">And</label> | |
164 | - <select name="add_filter_${clause_num}" id="add_filter_${clause_num}"> | |
165 | - <option></option> | |
166 | - <option py:for="field_name in field_names" py:with="field = fields[field_name]" | |
167 | - value="$field_name" | |
168 | - disabled="${(field.type in ('radio', 'checkbox', 'id') and | |
169 | - field_name in constraints and | |
170 | - len(constraints[field_name])) or None}">${field.label}</option> | |
171 | - </select> | |
172 | - <div class="inlinebuttons"> | |
173 | - <input type="submit" name="add_${clause_num}" value="+" /> | |
174 | - </div> | |
175 | - </td> | |
176 | - <td py:if="last_clause" class="or" colspan="2"> | |
177 | - <label for="add_clause">Or</label> | |
178 | - <select name="add_clause_${clause_num + 1}" id="add_clause"> | |
179 | - <option></option> | |
180 | - <option py:for="field_name in field_names" value="$field_name">${fields[field_name].label}</option> | |
181 | - </select> | |
182 | - <div class="inlinebuttons"> | |
183 | - <input type="submit" name="add_${clause_num + 1}" value="+" /> | |
184 | - </div> | |
185 | - </td> | |
186 | - </tr> | |
187 | - </tbody> | |
188 | - </table> | |
189 | - </td></tr> | |
190 | - </tbody> | |
191 | - </table> | |
192 | - </fieldset> | |
193 | - <fieldset id="options" style="font-size:100%"> | |
194 | - <legend class="foldable">${_('Options')}</legend> | |
195 | - <table class="list"> | |
196 | - <tr> | |
197 | - <td> | |
198 | - <label> | |
199 | - ${_('Base Day')} | |
200 | - <input type="text" id="field-baseday" name="baseday" | |
201 | - value="${baseday.strftime(dateFormat)}" length="10" style="font-size:100%"/> | |
202 | - </label> | |
203 | - </td> | |
204 | - </tr> | |
205 | - <tr> | |
206 | - <td> | |
207 | - <label> | |
208 | - ${_('Sort by')} | |
209 | - <select name="sorted_field" style="font-size:100%"> | |
210 | - <option value="milestone" selected="${sorted_field=='milestone' or None}">${_('Milestone')}</option> | |
211 | - <option value="component" selected="${sorted_field=='component' or None}">${_('Component')}</option> | |
212 | - </select> | |
213 | - </label><br/> | |
214 | - </td> | |
215 | - </tr> | |
216 | - <tr> | |
217 | - <td> | |
218 | - ${_('Selected')} | |
219 | - <label> | |
220 | - ${_('Milestone')} = | |
221 | - <select name="selected_milestone"> | |
222 | - <py:for each="i in milestones.keys()"> | |
223 | - <option selected="${selected_milestone==i or None}" value="$i">$i</option> | |
224 | - </py:for> | |
225 | - </select> | |
226 | - </label> | |
227 | - AND | |
228 | - <label> | |
229 | - ${_('Component')} = | |
230 | - <select name="selected_component"> | |
231 | - <py:for each="i in components"> | |
232 | - <option selected="${selected_component==i.name or None}" value="${i.name}">${i.name}</option> | |
233 | - </py:for> | |
234 | - </select> | |
235 | - </label> | |
236 | - </td> | |
237 | - </tr> | |
238 | - <tr> | |
239 | - <td> | |
240 | - <label><input type="checkbox" name="show_my_ticket" checked="$show_my_ticket" />${_('Show only my tickets')}</label> | |
241 | - <label><input type="checkbox" name="show_closed_ticket" checked="$show_closed_ticket" />${_('Include closed tickets')}</label> | |
242 | - | |
243 | - <label><input type="checkbox" name="show_ticket_summary" checked="$show_ticket_summary" />${_('Show ticket summary')}</label> | |
244 | - <label><input type="checkbox" name="show_ticket_status" checked="$show_ticket_status" />${_('Show ticket status')}</label><br/> | |
245 | - | |
246 | - </td> | |
247 | - <td align="right" valign="bottom"> | |
248 | - <input type="submit" value="${_('Update')}" /> | |
249 | - </td> | |
250 | - </tr> | |
251 | - </table> | |
252 | - </fieldset> | |
253 | - <table class="list"> | |
254 | - <tr> | |
255 | - <td> | |
256 | - <input type="button" value="<< ${_(month_tbl[prev.month])}" ACCESSKEY="J" onclick="form.year.value = ${prev.year}; form.month.value = ${prev.month}; form.submit();"/> | |
257 | - </td> | |
258 | - <td align="center"> | |
259 | - <select name="year"> | |
260 | - <option py:for="y in range(current.year-3,current.year+4)" | |
261 | - value="$y" | |
262 | - selected="${y==current.year or None}">$y</option> | |
263 | - </select> | |
264 | - ${_('Year')} | |
265 | - <select name="month"> | |
266 | - <option py:for="m in [1,2,3,4,5,6,7,8,9,10,11,12]" | |
267 | - value="$m" selected="${m==current.month or None}">${_(month_tbl[m])}</option> | |
268 | - </select> | |
269 | - <input type="submit" value="${_('Update')}" /> | |
270 | - <label ACCESSKEY="M" onclick="form.year.value = ${date.today().year}; form.month.value = ${date.today().month}; form.submit();"/> | |
271 | - <py:choose> | |
272 | - <input py:when="zoom > 1" type="image" ACCESSKEY="I" onclick="form.zoom.value = ${zoom-1};" src="${href.chrome('tc/img/zoom_in.png')}" alt="${_('Zoom In')}"/> | |
273 | - <input py:otherwise="" type="image" disabled="disabled" src="${href.chrome('tc/img/zoom_in_g.png')}"/> | |
274 | - </py:choose> | |
275 | - <label style="cursor: pointer;" ACCESSKEY="N" onclick="form.zoom.value = ${normal}; form.submit();">${zoom}</label> | |
276 | - <py:choose> | |
277 | - <input py:when="zoom < 6" type="image" ACCESSKEY="K" onclick="form.zoom.value = ${zoom+1};" src="${href.chrome('tc/img/zoom_out.png')}" alt="${_('Zoom Out')}"/> | |
278 | - <input py:otherwise="" type="image" disabled="disabled" src="${href.chrome('tc/img/zoom_out_g.png')}"/> | |
279 | - </py:choose> | |
280 | - <input name="normal" type="hidden" value="${normal}" /> | |
281 | - <input name="zoom" type="hidden" value="${zoom}" /> | |
282 | - </td> | |
283 | - <td align="right"> | |
284 | - <input type="button" value="${_(month_tbl[next.month])} >>" ACCESSKEY="L" onclick="form.year.value = ${next.year}; form.month.value = ${next.month}; form.submit();"/> | |
285 | - </td> | |
286 | - </tr> | |
287 | - </table> | |
288 | - </form> | |
289 | - <div py:if="sum_estimatedhours != None" style="font-size:11px;"> | |
290 | - ${_('Total Hours')}: ${sum_totalhours}h / ${_('Estimated Hours')}: ${sum_estimatedhours}h | |
291 | - </div> | |
292 | - <!-- gantt --> | |
293 | - <div style="position:relative;left:1px;top:1px;width:100%;height:${maxtic*px_ti+px_hd+1+40+px_height}px;"> | |
294 | - <!-- right side --> | |
295 | - <div style="overflow:auto;margin-left:384px;margin-right:4px;position:relative;left:0px;top:1px;height:${maxtic*px_ti+px_hd+1+30+px_height}px;"> | |
296 | - <div class="border_line" style="left:0px;top:1px;width:${px_dw*days_term+1}px;height:${maxtic*px_ti+px_hd+1+px_height}px;"> | |
297 | - <!-- head and sun,sta,holiday --> | |
298 | - <div class="bdy" style="position:relative;left:1px;top:${px_hd}px;width:${px_dw*days_term-1}px;height:${maxtic*px_ti+px_height}px;"/> | |
299 | - <!-- back ground stripe --> | |
300 | -<py:for each="cnt in reversed(range(maxtic))"> | |
301 | - <py:if test="(cnt%2)!=0"> | |
302 | - <div class="stripe" style="left: 1px; top: ${px_ti*cnt+px_hd+px_top}px; width: ${px_dw*days_term-1}px; height: ${px_ti}px;"></div> | |
303 | - </py:if> | |
304 | -</py:for> | |
305 | -<py:for each="cnt in reversed(range(days_term))" py:with="cur=first_date+timedelta(cnt);wk=cur.weekday()"> | |
306 | - <div py:if="cur.day == 1" py:with="days_thismonth=calendar.monthrange(cur.year,cur.month)[1];" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${(px_hd-4)/3*0+1}px;width: ${days_thismonth*px_dw-1}px;height:${(px_hd-4)/3}px;">${cur.year}/${cur.month}</div> | |
307 | - <div py:if="wk==first_wkday and(cur-first_date).days+7<=days_term" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${(px_hd-4)/3*1+2}px;width: ${px_dw*7-1}px;height:${(px_hd-4)/3}px;">${cur.month}/${cur.day}</div> | |
308 | - <div py:if="wk==first_wkday and(cur-first_date).days+7>days_term" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${(px_hd-4)/3*1+2}px;width: ${px_dw*(days_term-(cur-first_date).days)-1}px;height:${(px_hd-4)/3}px;"/> | |
309 | - <py:choose> | |
310 | - <div py:when="zoom < 4" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${(px_hd-4)/3*2+3}px;width: ${px_dw-1}px;height:${(px_hd-4)/3}px;">${weekdays[wk]}</div> | |
311 | - <div py:otherwise="" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${(px_hd-4)/3*2+3}px;width: ${px_dw-1}px;height:${(px_hd-4)/3}px;" /> | |
312 | - </py:choose> | |
313 | - <py:with vars="holiday_desc = holidays.get(cur.isoformat());"> | |
314 | - <py:if test="cur.weekday()>4or holiday_desc"> | |
315 | - <div class="border_line" style="position:absolute;top:${px_hd}px; left: ${px_dw*cnt}px; width: ${px_dw+1}px; height: ${maxtic*px_ti+1+px_height}px;"> | |
316 | - <div class="hdr" py:attrs="{'title':holiday_desc}" style="top:0px; left:1px; width: ${px_dw-1}px; height: ${maxtic*px_ti+px_height}px;"/> | |
317 | - </div> | |
318 | - </py:if> | |
319 | - </py:with> | |
320 | - <div py:if="zoom < 3" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${px_hd}px;width: ${px_dw-1}px;height:${(px_hd-4)/3}px;">${cur.day}</div> | |
321 | -</py:for> | |
322 | - <div py:if="first_date.weekday() < first_wkday" class="hdr hdr_title" style="left:1px;top:${(px_hd-4)/3*1+2}px;width: ${px_dw*(first_wkday-first_date.weekday())-1}px;height:${(px_hd-4)/3}px;"/> | |
323 | - <div py:if="first_date.weekday() > first_wkday" class="hdr hdr_title" style="left:1px;top:${(px_hd-4)/3*1+2}px;width: ${px_dw*(first_wkday+7-first_date.weekday())-1}px;height:${(px_hd-4)/3}px;"/> | |
324 | - <!-- chart --> | |
325 | -<py:def function="print_chart(kind)"> | |
326 | - <py:with vars="s=tickets[cnt].get('all_start');e=tickets[cnt].get(kind +'_end');t=tickets[cnt];"> | |
327 | - <py:if test="e!=None and e-s!= 0"> | |
328 | - <py:with vars="tic_due='(%d/%d ~ %d/%d)' % (t['due_assign'].month, t['due_assign'].day, t['due_close'].month, t['due_close'].day ); | |
329 | - tic_tip='%s#%d: %s - %s %s%s' % (t['type'], t['id'], t['summary'], format_author(t['owner']), tic_due, (t['estimatedhours']!=None and ' '+ str(t['estimatedhours']) +'h' or '') );"> | |
330 | - <div class="${'tic_'+kind+'_bl'}" style="left:${int(s*px_dw+1)}px;top:${px_ti*cnt+px_hd+((px_ti-px_ch)/2)+(ti_mrgn/2)+px_top}px;width: ${int((e-s)*px_dw)}px;height:${px_ch}px;"/> | |
331 | - <div class="${'tic_'+kind}" onclick="location.href='${req.href.ticket()}/${t['id']}';" py:attrs="{'title':tic_tip}" style="left:${int(s*px_dw+2)}px;top:${px_ti*cnt+px_hd+((px_ti-px_ch)/2+1)+(ti_mrgn/2)+px_top}px;width: ${int((e-s)*px_dw)-2}px;height:${px_ch-2}px;"/> | |
332 | - </py:with> | |
333 | - </py:if> | |
334 | - </py:with> | |
335 | -</py:def> | |
336 | -<py:def function="print_ticket_summary()"> | |
337 | - <py:with vars="s=tickets[cnt].get('all_start');e=tickets[cnt].get('all_end');t=tickets[cnt];"> | |
338 | - <py:if test="e!=None and e-s!= 0"> | |
339 | - <py:with vars="tic_due='(%d/%d ~ %d/%d)' % (t['due_assign'].month, t['due_assign'].day, t['due_close'].month, t['due_close'].day ); | |
340 | - tic_tip='%s#%d: %s - %s %s%s' % (t['type'], t['id'], t['summary'], format_author(t['owner']), tic_due, (t['estimatedhours']!=None and ' '+ str(t['estimatedhours']) +'h' or '') );"> | |
341 | - <div py:if="show_ticket_summary == 'on'" py:attrs="{'title': | |
342 | - _('Description') + ': %s' % (t['description'] )}" class="tic_summary" style="left:${int(s*px_dw+1)+2}px;top:${px_ti*cnt+px_hd+(px_ti-px_ch)/2+(ti_mrgn/2+1)}px;"> | |
343 | - <a href="${req.href.ticket()}/${t['id']}"> | |
344 | - <s py:strip="t['status']!='closed'">${t['type']}#${t['id']}</s>: ${t['summary'][0:20]}<span py:if="len(t['summary'])>20">...</span> | |
345 | - ${tic_due}<span py:if="t['estimatedhours']!=None"> ${t['estimatedhours']}h</span> | |
346 | - </a> | |
347 | - </div> | |
348 | - <div py:if="show_ticket_status == 'on'" py:attrs="{'title':tic_tip}" py:choose="" class="tic_summary" style="left:${int(e*px_dw)+5}px;top:${px_ti*cnt+px_hd+(px_ti-px_ch)/2+(ti_mrgn/2-1)+px_top}px;"> | |
349 | - ${t['status']}<span py:when="t['status']!='closed'"> ${t['complete']}%</span><span py:otherwise="">: ${t['resolution']}</span><span py:if="t['estimatedhours']!=None"> ${t['totalhours']}h</span> ${t['owner']} | |
350 | - </div> | |
351 | - </py:with> | |
352 | - </py:if> | |
353 | - </py:with> | |
354 | -</py:def> | |
355 | -<py:if test="show_ticket_status == 'on' or show_ticket_summary == 'on'"> | |
356 | - <py:for each="cnt in range(maxtic)"> | |
357 | - ${print_ticket_summary()} | |
358 | - </py:for> | |
359 | -</py:if> | |
360 | -<py:for each="cnt in reversed(range(maxtic))"> | |
361 | - ${print_chart('todo')} | |
362 | - ${print_chart('late')} | |
363 | - ${print_chart('done')} | |
364 | - <py:if test="'MILESTONE_VIEW' in req.perm and (sorted_field == 'milestone' or (selected_milestone != '' and selected_milestone != None))"> | |
365 | - <py:if test="tickets[cnt].get('milestone')!= None and tickets[cnt].get('milestone') in milestones" py:with="d= milestones[tickets[cnt]['milestone']].get('due')"> | |
366 | - <py:if test="d!=None and 0 <= (d-first_date).days+1 <= days_term" py:with="d=(d-first_date).days+1"> | |
367 | - <div py:if="show_ticket_summary != 'on'" class="milestone" style="left: ${d*px_dw}px; top: ${cnt*px_ti+px_hd+px_top}px; width: 2px; height: ${px_ti}px;"></div> | |
368 | - </py:if> | |
369 | - </py:if> | |
370 | - </py:if> | |
371 | -</py:for> | |
372 | -<py:with vars="base = (baseday-first_date).days+1"> | |
373 | - <!-- baseline --> | |
374 | - <div py:if="0 <= base <= days_term" class="baseline" style="left:${base*px_dw}px;top:${px_hd}px; height:${maxtic*px_ti+px_height}px; width: 0px;"/> | |
375 | -</py:with> | |
376 | - </div> | |
377 | - </div> | |
378 | - <!-- left side --> | |
379 | - <div style="position:absolute;background-color:gray;left:1px;top:1px;width:380px;height:${maxtic*px_ti+px_hd+1+px_height}px;"> | |
380 | - <div py:choose="" class="hdr" style="left:1px;top:1px;width: 89px;height:${px_hd-2}px;"> | |
381 | - <span class="hdr_title" style="top:${(px_hd-2-16)/2}px;font-size:12px;"> | |
382 | - <span py:when="sorted_field=='milestone'">${_('Milestone')}</span><span py:otherwise="">${_('Component')}</span> | |
383 | - </span> | |
384 | - </div> | |
385 | - <div class="hdr" style="left:91px;top:1px;width:288px;height:${px_hd-2}px;"><span class="hdr_title" style="top:${(px_hd-2-16)/2}px;font-size:12px;">${_('Ticket')}</span></div> | |
386 | - | |
387 | -<py:def function="print_field(px_x,px_w,ticket_col,dupchk=False)"> | |
388 | - <div class="bdy" style="left:${px_x}px;width:${px_w}px;"> | |
389 | - <py:for each="cnt in reversed(range(maxtic))" py:with="t=tickets[cnt]"> | |
390 | - <py:choose> | |
391 | - <py:when test="ticket_col=='ticket'"> | |
392 | - <py:if test="(cnt%2)!=0"> | |
393 | - <div class="stripe" style="top: ${cnt*px_ti+px_top}px;width: ${px_w}px; height: ${px_ti}px;"></div> | |
394 | - </py:if> | |
395 | - <div class="bdy_elem" style="top: ${cnt*px_ti+px_top}px;left: ${px_left-1}px;width: ${px_w-2}px;"> | |
396 | - <a class="tip" href="${req.href.ticket()}/${t['id']}">${t['type']} <s py:strip="t['status']!='closed'">#${t['id']}</s>: ${t['summary'][0:32]}<span py:if="len(t['summary'])>32">...</span> | |
397 | - <span class="popup"> | |
398 | - <br/> | |
399 | - <s py:strip="t['status']!='closed'"> ${t['type']} #${t['id']}</s>: ${t['summary']}<br/> | |
400 | - <br/> | |
401 | - <strong>${_('Start date')}</strong>: | |
402 | - ${t['due_assign'].strftime(dateFormat)} | |
403 | - <span py:if="t['status']!='closed'">(${t['status']} ${t['complete']}%)</span><br/> | |
404 | - <strong>${_('End date')}</strong>: | |
405 | - ${t['due_close'].strftime(dateFormat)} | |
406 | - <span py:if="t['status']=='closed'">(${t['status']}: ${t['resolution']})</span><br/> | |
407 | - <strong>${_('Owner')}</strong>: ${format_author(t['owner'])}<br/> | |
408 | - <strong>${_('Priority')}</strong>: ${t['priority']}<br/> | |
409 | - <py:if test="t['estimatedhours']!=None"> | |
410 | - <strong>${_('Total Hours')}</strong>: ${t['totalhours']}h / <strong>${_('Estimated Hours')}</strong>: ${t['estimatedhours']}h<br/> | |
411 | - </py:if> | |
412 | - <pre> ${t['description']}</pre> | |
413 | - </span> | |
414 | - </a> | |
415 | - </div> | |
416 | - </py:when> | |
417 | - <py:otherwise> | |
418 | - <py:choose> | |
419 | - <py:when test="dupchk"> | |
420 | - <py:if test="(cnt%2)!=0"> | |
421 | - <div class="stripe" style="top: ${cnt*px_ti+px_top}px;width: ${px_w}px; height: ${px_ti}px;"></div> | |
422 | - </py:if> | |
423 | - <div py:if="not cnt or t[ticket_col]!=tickets[cnt-1][ticket_col]" class="bdy_elem" style="top:${cnt*px_ti+px_top}px;left: ${px_left}px;width: ${px_w-2}px;"> | |
424 | - <span py:choose=""> | |
425 | - <span py:when="ticket_col=='milestone' and 'MILESTONE_VIEW' in req.perm"> | |
426 | - <a py:strip="t['milestone']=='*'" class="tip" href="${req.href.milestone()}/${t['milestone']}">${t['milestone']} | |
427 | - <span py:if="t['milestone']!='*'" py:with="m=milestones[t['milestone']]" class="popup"> | |
428 | - <br/> | |
429 | - <img src="${href.chrome('tc/img/package.png')}" />${t['milestone']}<br/> | |
430 | - <br/> | |
431 | - <strong>${_('Due')}</strong>: <span py:if="m['due'] != | |
432 | - None">${m['due'].strftime(dateFormat)}</span><br/> | |
433 | - <pre> ${m['description']}</pre> | |
434 | - </span> | |
435 | - </a> | |
436 | - </span> | |
437 | - <span py:otherwise="">${t[ticket_col]}</span> | |
438 | - </span> | |
439 | - </div> | |
440 | - </py:when> | |
441 | - <py:otherwise> | |
442 | - <py:if test="(cnt%2)!=0"> | |
443 | - <div class="stripe" style="top: ${cnt*px_ti+px_top}px;width: ${px_w}px; height: ${px_ti}px;"></div> | |
444 | - </py:if> | |
445 | - <div class="bdy_elem" style="top: ${cnt*px_ti+px_top}px;left: ${px_left}px;width: ${px_w-2}px;">${ticket_col in ('owner','reporter') and format_author(t[ticket_col]) or t[ticket_col]}</div> | |
446 | - </py:otherwise> | |
447 | - </py:choose> | |
448 | - </py:otherwise> | |
449 | - </py:choose> | |
450 | - </py:for> | |
451 | - </div> | |
452 | -</py:def> | |
453 | - | |
454 | - ${print_field( 91,288,'ticket')} | |
455 | - ${print_field( 1, 89,sorted_field,dupchk=True)} | |
456 | - | |
457 | - </div> | |
458 | - </div> | |
459 | - <!-- gantt --> | |
460 | - </body> | |
461 | -</html> |
@@ -0,0 +1,461 @@ | ||
1 | +<html xmlns="http://www.w3.org/1999/xhtml" | |
2 | + xmlns:py="http://genshi.edgewall.org/" | |
3 | + xmlns:i18n="http://genshi.edgewall.org/i18n" | |
4 | + xmlns:xi="http://www.w3.org/2001/XInclude" | |
5 | + py:with="px_ti=30;px_hd=46;px_dw=36/zoom;px_ch=10;maxtic=len(tickets);px_left=3;px_top=13;px_height=px_top+px_ch;"> | |
6 | + <xi:include href="layout.html" /> | |
7 | + <xi:include href="macros.html" /> | |
8 | + <head> | |
9 | + <script type="text/javascript" src="${chrome.htdocs_location}js/folding.js"></script> | |
10 | + <script type="text/javascript">/*<![CDATA[*/ | |
11 | + jQuery(document).ready(function($) { | |
12 | + initializeFilters(); | |
13 | + $("fieldset legend.foldable").enableFolding(false); | |
14 | + /* Hide the filters for saved queries. */ | |
15 | + $("#options").toggleClass("collapsed"); | |
16 | + }); | |
17 | + /*]]>*/</script> | |
18 | + | |
19 | + <style type="text/css"> | |
20 | + form fieldset.collapsed { | |
21 | + border-width: 0px; | |
22 | + margin-bottom: 0px; | |
23 | + padding: 0px .5em; | |
24 | + } | |
25 | + fieldset legend.foldable :link, | |
26 | + fieldset legend.foldable :visited { | |
27 | + background: url(${chrome.htdocs_location}expanded.png) 0 50% no-repeat; | |
28 | + border: none; | |
29 | + color: #666; | |
30 | + font-size: 110%; | |
31 | + padding-left: 16px; | |
32 | + } | |
33 | + fieldset legend.foldable :link:hover, fieldset legend.foldable :visited:hover { | |
34 | + background-color: transparent; | |
35 | + } | |
36 | + | |
37 | + fieldset.collapsed legend.foldable :link, fieldset.collapsed legend.foldable :visited { | |
38 | + background-image: url(${chrome.htdocs_location}collapsed.png); | |
39 | + } | |
40 | + fieldset.collapsed table, fieldset.collapsed div { display: none } | |
41 | + table.list {width:100%;border-collapse: collapse;margin-bottom: 6px;} | |
42 | + table.list td {padding:2px;} | |
43 | + .border_line {background-color: gray;} | |
44 | + .hdr {position: absolute;background-color: #eee;} | |
45 | + .hdr_title {display:block;position: absolute; width:100%;text-align:center;font-size:10px;} | |
46 | + .bdy {position: absolute;background-color: #fff;text-align: left;top:${px_hd}px;height:${maxtic*px_ti+px_height}px;} | |
47 | + .bdy_elem {position: absolute;font-size: 10px;left:1px;height:${px_ti-2}px;} | |
48 | + .tic_summary {position: absolute;font-size: 10px;color: #000; background-color: #fff; height: 11px; line-height: 11px; white-space:nowrap;} | |
49 | + .stripe {position: absolute; overflow: hidden; background: #e8f0f8;} | |
50 | + .tip {position: static;} | |
51 | + .tip span.popup{position: absolute;visibility: hidden;background-color: #ffe;color: black;border: 1px solid #555;left: 20px;top: 30px;padding: 3px; | |
52 | + /*IE6 Hack*/ min-width: 400px; width: auto; _width: 400px; | |
53 | + } | |
54 | + .tip:hover span.popup | |
55 | + {visibility: visible; z-index: 100;font-size: 11px;} | |
56 | + | |
57 | + .tic_done {position: absolute; overflow: hidden; cursor: pointer; background:lightgreen;} | |
58 | + .tic_late {position: absolute; overflow: hidden; cursor: pointer; background:pink;} | |
59 | + .tic_todo {position: absolute; overflow: hidden; cursor: pointer; background:lightgrey;} | |
60 | + .tic_done_bl {position: absolute; overflow: hidden; background:green;} | |
61 | + .tic_late_bl {position: absolute; overflow: hidden; background:red;} | |
62 | + .tic_todo_bl {position: absolute; overflow: hidden; background:gray;} | |
63 | + | |
64 | + .baseline {position: absolute; overflow: hidden; border-left: 1px dashed red;} | |
65 | + div.milestone {position: absolute; overflow: hidden; background-color: red;} | |
66 | + </style> | |
67 | + </head> | |
68 | + <body py:with="weekdays = [_('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa'), _('Su')]"> | |
69 | + <form id="query" method="get" | |
70 | + py:with="field_names = sorted(fields.iterkeys(), key=lambda name: fields[name].label.lower())"> | |
71 | + <fieldset id="filters"> | |
72 | + <legend class="foldable">Filters</legend> | |
73 | + <table summary="Query filters"> | |
74 | + <tbody py:for="clause_num, constraints in enumerate(clauses or [{}])" | |
75 | + py:with="clause_pre = '%d_' % clause_num"> | |
76 | + <tr style="${clause_num == 0 and 'display: none' or None}"> | |
77 | + <td> | |
78 | + <div class="trac-clause-lsep"> <hr /></div> | |
79 | + <div class="trac-clause-msep">Or</div> | |
80 | + <div class="trac-clause-rsep"> <hr /></div> | |
81 | + </td> | |
82 | + </tr> | |
83 | + <tr><td class="trac-clause"> | |
84 | + <table class="trac-clause"> | |
85 | + <tbody py:for="field_name in field_names" py:if="field_name in constraints" | |
86 | + py:with="field = fields[field_name]; n_field_name = clause_pre + field_name; | |
87 | + constraint = constraints[field_name]; | |
88 | + multiline = field.type in ('select', 'text', 'textarea', 'time')"> | |
89 | + <tr py:for="constraint_idx, constraint_value in enumerate(constraint['values'])" | |
90 | + class="${field_name}" py:if="multiline or constraint_idx == 0"> | |
91 | + <td> | |
92 | + <div class="inlinebuttons"> | |
93 | + <input type="submit" name="rm_filter_${n_field_name}_${constraint_idx}" value="–" /> | |
94 | + </div> | |
95 | + </td> | |
96 | + <py:choose test="constraint_idx"> | |
97 | + <py:when test="0"> | |
98 | + <th scope="row"><label id="label_${n_field_name}">${fields[field_name].label}</label></th> | |
99 | + <td py:if="field.type not in ('radio', 'checkbox', 'time')" class="mode"> | |
100 | + <select name="${n_field_name}_mode"> | |
101 | + <option py:for="mode in modes[field.type]" value="$mode.value" | |
102 | + selected="${mode.value == constraint.mode and 'selected' or None}">$mode.name</option> | |
103 | + </select> | |
104 | + </td> | |
105 | + </py:when> | |
106 | + <py:otherwise><!--! not the first line of a multiline constraint --> | |
107 | + <th colspan="${field.type == 'time' and 1 or 2}"><label>or</label></th> | |
108 | + </py:otherwise> | |
109 | + </py:choose> | |
110 | + | |
111 | + <td class="filter" colspan="${field.type in ('radio', 'checkbox', 'time') and 2 or None}" | |
112 | + py:choose=""> | |
113 | + | |
114 | + <py:when test="field.type == 'select'"> | |
115 | + <select name="${n_field_name}"> | |
116 | + <option></option> | |
117 | + <option py:for="option in field.options" | |
118 | + selected="${option == constraint_value and 'selected' or None}" | |
119 | + value="$option" py:content="option"></option> | |
120 | + </select> | |
121 | + </py:when> | |
122 | + | |
123 | + <py:when test="field.type == 'radio'"> | |
124 | + <py:for each="option in field.options"> | |
125 | + <input type="checkbox" id="_${n_field_name}_$option" name="${n_field_name}" | |
126 | + value="$option" | |
127 | + checked="${((constraint['mode'] == '') == (option in constraint['values'])) | |
128 | + and 'checked' or None}" /> | |
129 | + <label for="_${n_field_name}_$option" class="control">${option or 'none'}</label> | |
130 | + </py:for> | |
131 | + </py:when> | |
132 | + | |
133 | + <py:when test="field.type == 'checkbox'"> | |
134 | + <input type="radio" id="_${n_field_name}_on" name="$n_field_name" value="1" | |
135 | + checked="${constraint.mode != '!' or constraint_value == '1' or None}" /> | |
136 | + <label for="_${n_field_name}_on" class="control">yes</label> | |
137 | + <input type="radio" id="_${n_field_name}_off" name="$n_field_name" value="0" | |
138 | + checked="${constraint.mode == '!' or constraint_value != '1' or None}" /> | |
139 | + <label for="_${n_field_name}_off" class="control">no</label> | |
140 | + </py:when> | |
141 | + | |
142 | + <py:when test="field.type in ('text', 'textarea', 'id')"> | |
143 | + <input type="text" name="${n_field_name}" value="$constraint_value" size="42" /> | |
144 | + </py:when> | |
145 | + | |
146 | + <py:when test="field.type == 'time'" | |
147 | + py:with="(start, end) = '..' in constraint_value and constraint_value.split('..', 1) | |
148 | + or (constraint_value, '')"> | |
149 | + <i18n:msg> | |
150 | + <label>between</label> | |
151 | + <input type="text" name="${n_field_name}" value="$start" size="14" /> | |
152 | + <label>and</label> | |
153 | + <input type="text" name="${n_field_name}_end" value="$end" size="14" /> | |
154 | + </i18n:msg> | |
155 | + </py:when> | |
156 | + </td> | |
157 | + </tr> | |
158 | + </tbody> | |
159 | + | |
160 | + <tbody py:with="last_clause = clause_num == (len(clauses) or 1) - 1"> | |
161 | + <tr class="actions"> | |
162 | + <td class="and" colspan="2"> | |
163 | + <label for="add_filter_${clause_num}">And</label> | |
164 | + <select name="add_filter_${clause_num}" id="add_filter_${clause_num}"> | |
165 | + <option></option> | |
166 | + <option py:for="field_name in field_names" py:with="field = fields[field_name]" | |
167 | + value="$field_name" | |
168 | + disabled="${(field.type in ('radio', 'checkbox', 'id') and | |
169 | + field_name in constraints and | |
170 | + len(constraints[field_name])) or None}">${field.label}</option> | |
171 | + </select> | |
172 | + <div class="inlinebuttons"> | |
173 | + <input type="submit" name="add_${clause_num}" value="+" /> | |
174 | + </div> | |
175 | + </td> | |
176 | + <td py:if="last_clause" class="or" colspan="2"> | |
177 | + <label for="add_clause">Or</label> | |
178 | + <select name="add_clause_${clause_num + 1}" id="add_clause"> | |
179 | + <option></option> | |
180 | + <option py:for="field_name in field_names" value="$field_name">${fields[field_name].label}</option> | |
181 | + </select> | |
182 | + <div class="inlinebuttons"> | |
183 | + <input type="submit" name="add_${clause_num + 1}" value="+" /> | |
184 | + </div> | |
185 | + </td> | |
186 | + </tr> | |
187 | + </tbody> | |
188 | + </table> | |
189 | + </td></tr> | |
190 | + </tbody> | |
191 | + </table> | |
192 | + </fieldset> | |
193 | + <fieldset id="options" style="font-size:100%"> | |
194 | + <legend class="foldable">${_('Options')}</legend> | |
195 | + <table class="list"> | |
196 | + <tr> | |
197 | + <td> | |
198 | + <label> | |
199 | + ${_('Base Day')} | |
200 | + <input type="text" id="field-baseday" name="baseday" | |
201 | + value="${baseday.strftime(dateFormat)}" length="10" style="font-size:100%"/> | |
202 | + </label> | |
203 | + </td> | |
204 | + </tr> | |
205 | + <tr> | |
206 | + <td> | |
207 | + <label> | |
208 | + ${_('Sort by')} | |
209 | + <select name="sorted_field" style="font-size:100%"> | |
210 | + <option value="milestone" selected="${sorted_field=='milestone' or None}">${_('Milestone')}</option> | |
211 | + <option value="component" selected="${sorted_field=='component' or None}">${_('Component')}</option> | |
212 | + </select> | |
213 | + </label><br/> | |
214 | + </td> | |
215 | + </tr> | |
216 | + <tr> | |
217 | + <td> | |
218 | + ${_('Selected')} | |
219 | + <label> | |
220 | + ${_('Milestone')} = | |
221 | + <select name="selected_milestone"> | |
222 | + <py:for each="i in milestones.keys()"> | |
223 | + <option selected="${selected_milestone==i or None}" value="$i">$i</option> | |
224 | + </py:for> | |
225 | + </select> | |
226 | + </label> | |
227 | + AND | |
228 | + <label> | |
229 | + ${_('Component')} = | |
230 | + <select name="selected_component"> | |
231 | + <py:for each="i in components"> | |
232 | + <option selected="${selected_component==i.name or None}" value="${i.name}">${i.name}</option> | |
233 | + </py:for> | |
234 | + </select> | |
235 | + </label> | |
236 | + </td> | |
237 | + </tr> | |
238 | + <tr> | |
239 | + <td> | |
240 | + <label><input type="checkbox" name="show_my_ticket" checked="$show_my_ticket" />${_('Show only my tickets')}</label> | |
241 | + <label><input type="checkbox" name="show_closed_ticket" checked="$show_closed_ticket" />${_('Include closed tickets')}</label> | |
242 | + | |
243 | + <label><input type="checkbox" name="show_ticket_summary" checked="$show_ticket_summary" />${_('Show ticket summary')}</label> | |
244 | + <label><input type="checkbox" name="show_ticket_status" checked="$show_ticket_status" />${_('Show ticket status')}</label><br/> | |
245 | + | |
246 | + </td> | |
247 | + <td align="right" valign="bottom"> | |
248 | + <input type="submit" value="${_('Update')}" /> | |
249 | + </td> | |
250 | + </tr> | |
251 | + </table> | |
252 | + </fieldset> | |
253 | + <table class="list"> | |
254 | + <tr> | |
255 | + <td> | |
256 | + <input type="button" value="<< ${_(month_tbl[prev.month])}" ACCESSKEY="J" onclick="form.year.value = ${prev.year}; form.month.value = ${prev.month}; form.submit();"/> | |
257 | + </td> | |
258 | + <td align="center"> | |
259 | + <select name="year"> | |
260 | + <option py:for="y in range(current.year-3,current.year+4)" | |
261 | + value="$y" | |
262 | + selected="${y==current.year or None}">$y</option> | |
263 | + </select> | |
264 | + ${_('Year')} | |
265 | + <select name="month"> | |
266 | + <option py:for="m in [1,2,3,4,5,6,7,8,9,10,11,12]" | |
267 | + value="$m" selected="${m==current.month or None}">${_(month_tbl[m])}</option> | |
268 | + </select> | |
269 | + <input type="submit" value="${_('Update')}" /> | |
270 | + <label ACCESSKEY="M" onclick="form.year.value = ${date.today().year}; form.month.value = ${date.today().month}; form.submit();"/> | |
271 | + <py:choose> | |
272 | + <input py:when="zoom > 1" type="image" ACCESSKEY="I" onclick="form.zoom.value = ${zoom-1};" src="${href.chrome('tc/img/zoom_in.png')}" alt="${_('Zoom In')}"/> | |
273 | + <input py:otherwise="" type="image" disabled="disabled" src="${href.chrome('tc/img/zoom_in_g.png')}"/> | |
274 | + </py:choose> | |
275 | + <label style="cursor: pointer;" ACCESSKEY="N" onclick="form.zoom.value = ${normal}; form.submit();">${zoom}</label> | |
276 | + <py:choose> | |
277 | + <input py:when="zoom < 6" type="image" ACCESSKEY="K" onclick="form.zoom.value = ${zoom+1};" src="${href.chrome('tc/img/zoom_out.png')}" alt="${_('Zoom Out')}"/> | |
278 | + <input py:otherwise="" type="image" disabled="disabled" src="${href.chrome('tc/img/zoom_out_g.png')}"/> | |
279 | + </py:choose> | |
280 | + <input name="normal" type="hidden" value="${normal}" /> | |
281 | + <input name="zoom" type="hidden" value="${zoom}" /> | |
282 | + </td> | |
283 | + <td align="right"> | |
284 | + <input type="button" value="${_(month_tbl[next.month])} >>" ACCESSKEY="L" onclick="form.year.value = ${next.year}; form.month.value = ${next.month}; form.submit();"/> | |
285 | + </td> | |
286 | + </tr> | |
287 | + </table> | |
288 | + </form> | |
289 | + <div py:if="sum_estimatedhours != None" style="font-size:11px;"> | |
290 | + ${_('Total Hours')}: ${sum_totalhours}h / ${_('Estimated Hours')}: ${sum_estimatedhours}h | |
291 | + </div> | |
292 | + <!-- gantt --> | |
293 | + <div style="position:relative;left:1px;top:1px;width:100%;height:${maxtic*px_ti+px_hd+1+40+px_height}px;"> | |
294 | + <!-- right side --> | |
295 | + <div style="overflow:auto;margin-left:384px;margin-right:4px;position:relative;left:0px;top:1px;height:${maxtic*px_ti+px_hd+1+30+px_height}px;"> | |
296 | + <div class="border_line" style="left:0px;top:1px;width:${px_dw*days_term+1}px;height:${maxtic*px_ti+px_hd+1+px_height}px;"> | |
297 | + <!-- head and sun,sta,holiday --> | |
298 | + <div class="bdy" style="position:relative;left:1px;top:${px_hd}px;width:${px_dw*days_term-1}px;height:${maxtic*px_ti+px_height}px;"/> | |
299 | + <!-- back ground stripe --> | |
300 | +<py:for each="cnt in reversed(range(maxtic))"> | |
301 | + <py:if test="(cnt%2)!=0"> | |
302 | + <div class="stripe" style="left: 1px; top: ${px_ti*cnt+px_hd+px_top}px; width: ${px_dw*days_term-1}px; height: ${px_ti}px;"></div> | |
303 | + </py:if> | |
304 | +</py:for> | |
305 | +<py:for each="cnt in reversed(range(days_term))" py:with="cur=first_date+timedelta(cnt);wk=cur.weekday()"> | |
306 | + <div py:if="cur.day == 1" py:with="days_thismonth=calendar.monthrange(cur.year,cur.month)[1];" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${(px_hd-4)/3*0+1}px;width: ${days_thismonth*px_dw-1}px;height:${(px_hd-4)/3}px;">${cur.year}/${cur.month}</div> | |
307 | + <div py:if="wk==first_wkday and(cur-first_date).days+7<=days_term" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${(px_hd-4)/3*1+2}px;width: ${px_dw*7-1}px;height:${(px_hd-4)/3}px;">${cur.month}/${cur.day}</div> | |
308 | + <div py:if="wk==first_wkday and(cur-first_date).days+7>days_term" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${(px_hd-4)/3*1+2}px;width: ${px_dw*(days_term-(cur-first_date).days)-1}px;height:${(px_hd-4)/3}px;"/> | |
309 | + <py:choose> | |
310 | + <div py:when="zoom < 4" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${(px_hd-4)/3*2+3}px;width: ${px_dw-1}px;height:${(px_hd-4)/3}px;">${weekdays[wk]}</div> | |
311 | + <div py:otherwise="" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${(px_hd-4)/3*2+3}px;width: ${px_dw-1}px;height:${(px_hd-4)/3}px;" /> | |
312 | + </py:choose> | |
313 | + <py:with vars="holiday_desc = holidays.get(cur.isoformat());"> | |
314 | + <py:if test="cur.weekday()>4or holiday_desc"> | |
315 | + <div class="border_line" style="position:absolute;top:${px_hd}px; left: ${px_dw*cnt}px; width: ${px_dw+1}px; height: ${maxtic*px_ti+1+px_height}px;"> | |
316 | + <div class="hdr" py:attrs="{'title':holiday_desc}" style="top:0px; left:1px; width: ${px_dw-1}px; height: ${maxtic*px_ti+px_height}px;"/> | |
317 | + </div> | |
318 | + </py:if> | |
319 | + </py:with> | |
320 | + <div py:if="zoom < 3" class="hdr hdr_title" style="left:${px_dw*cnt+1}px;top:${px_hd}px;width: ${px_dw-1}px;height:${(px_hd-4)/3}px;">${cur.day}</div> | |
321 | +</py:for> | |
322 | + <div py:if="first_date.weekday() < first_wkday" class="hdr hdr_title" style="left:1px;top:${(px_hd-4)/3*1+2}px;width: ${px_dw*(first_wkday-first_date.weekday())-1}px;height:${(px_hd-4)/3}px;"/> | |
323 | + <div py:if="first_date.weekday() > first_wkday" class="hdr hdr_title" style="left:1px;top:${(px_hd-4)/3*1+2}px;width: ${px_dw*(first_wkday+7-first_date.weekday())-1}px;height:${(px_hd-4)/3}px;"/> | |
324 | + <!-- chart --> | |
325 | +<py:def function="print_chart(kind)"> | |
326 | + <py:with vars="s=tickets[cnt].get('all_start');e=tickets[cnt].get(kind +'_end');t=tickets[cnt];"> | |
327 | + <py:if test="e!=None and e-s!= 0"> | |
328 | + <py:with vars="tic_due='(%d/%d ~ %d/%d)' % (t['due_assign'].month, t['due_assign'].day, t['due_close'].month, t['due_close'].day ); | |
329 | + tic_tip='%s#%d: %s - %s %s%s' % (t['type'], t['id'], t['summary'], format_author(t['owner']), tic_due, (t['estimatedhours']!=None and ' '+ str(t['estimatedhours']) +'h' or '') );"> | |
330 | + <div class="${'tic_'+kind+'_bl'}" style="left:${int(s*px_dw+1)}px;top:${px_ti*cnt+px_hd+((px_ti-px_ch)/2)+(ti_mrgn/2)+px_top}px;width: ${int((e-s)*px_dw)}px;height:${px_ch}px;"/> | |
331 | + <div class="${'tic_'+kind}" onclick="location.href='${req.href.ticket()}/${t['id']}';" py:attrs="{'title':tic_tip}" style="left:${int(s*px_dw+2)}px;top:${px_ti*cnt+px_hd+((px_ti-px_ch)/2+1)+(ti_mrgn/2)+px_top}px;width: ${int((e-s)*px_dw)-2}px;height:${px_ch-2}px;"/> | |
332 | + </py:with> | |
333 | + </py:if> | |
334 | + </py:with> | |
335 | +</py:def> | |
336 | +<py:def function="print_ticket_summary()"> | |
337 | + <py:with vars="s=tickets[cnt].get('all_start');e=tickets[cnt].get('all_end');t=tickets[cnt];"> | |
338 | + <py:if test="e!=None and e-s!= 0"> | |
339 | + <py:with vars="tic_due='(%d/%d ~ %d/%d)' % (t['due_assign'].month, t['due_assign'].day, t['due_close'].month, t['due_close'].day ); | |
340 | + tic_tip='%s#%d: %s - %s %s%s' % (t['type'], t['id'], t['summary'], format_author(t['owner']), tic_due, (t['estimatedhours']!=None and ' '+ str(t['estimatedhours']) +'h' or '') );"> | |
341 | + <div py:if="show_ticket_summary == 'on'" py:attrs="{'title': | |
342 | + _('Description') + ': %s' % (t['description'] )}" class="tic_summary" style="left:${int(s*px_dw+1)+2}px;top:${px_ti*cnt+px_hd+(px_ti-px_ch)/2+(ti_mrgn/2+1)}px;"> | |
343 | + <a href="${req.href.ticket()}/${t['id']}"> | |
344 | + <s py:strip="t['status']!='closed'">${t['type']}#${t['id']}</s>: ${t['summary'][0:20]}<span py:if="len(t['summary'])>20">...</span> | |
345 | + ${tic_due}<span py:if="t['estimatedhours']!=None"> ${t['estimatedhours']}h</span> | |
346 | + </a> | |
347 | + </div> | |
348 | + <div py:if="show_ticket_status == 'on'" py:attrs="{'title':tic_tip}" py:choose="" class="tic_summary" style="left:${int(e*px_dw)+5}px;top:${px_ti*cnt+px_hd+(px_ti-px_ch)/2+(ti_mrgn/2-1)+px_top}px;"> | |
349 | + ${t['status']}<span py:when="t['status']!='closed'"> ${t['complete']}%</span><span py:otherwise="">: ${t['resolution']}</span><span py:if="t['estimatedhours']!=None"> ${t['totalhours']}h</span> ${t['owner']} | |
350 | + </div> | |
351 | + </py:with> | |
352 | + </py:if> | |
353 | + </py:with> | |
354 | +</py:def> | |
355 | +<py:if test="show_ticket_status == 'on' or show_ticket_summary == 'on'"> | |
356 | + <py:for each="cnt in range(maxtic)"> | |
357 | + ${print_ticket_summary()} | |
358 | + </py:for> | |
359 | +</py:if> | |
360 | +<py:for each="cnt in reversed(range(maxtic))"> | |
361 | + ${print_chart('todo')} | |
362 | + ${print_chart('late')} | |
363 | + ${print_chart('done')} | |
364 | + <py:if test="'MILESTONE_VIEW' in req.perm and (sorted_field == 'milestone' or (selected_milestone != '' and selected_milestone != None))"> | |
365 | + <py:if test="tickets[cnt].get('milestone')!= None and tickets[cnt].get('milestone') in milestones" py:with="d= milestones[tickets[cnt]['milestone']].get('due')"> | |
366 | + <py:if test="d!=None and 0 <= (d-first_date).days+1 <= days_term" py:with="d=(d-first_date).days+1"> | |
367 | + <div py:if="show_ticket_summary != 'on'" class="milestone" style="left: ${d*px_dw}px; top: ${cnt*px_ti+px_hd+px_top}px; width: 2px; height: ${px_ti}px;"></div> | |
368 | + </py:if> | |
369 | + </py:if> | |
370 | + </py:if> | |
371 | +</py:for> | |
372 | +<py:with vars="base = (baseday-first_date).days+1"> | |
373 | + <!-- baseline --> | |
374 | + <div py:if="0 <= base <= days_term" class="baseline" style="left:${base*px_dw}px;top:${px_hd}px; height:${maxtic*px_ti+px_height}px; width: 0px;"/> | |
375 | +</py:with> | |
376 | + </div> | |
377 | + </div> | |
378 | + <!-- left side --> | |
379 | + <div style="position:absolute;background-color:gray;left:1px;top:1px;width:380px;height:${maxtic*px_ti+px_hd+1+px_height}px;"> | |
380 | + <div py:choose="" class="hdr" style="left:1px;top:1px;width: 89px;height:${px_hd-2}px;"> | |
381 | + <span class="hdr_title" style="top:${(px_hd-2-16)/2}px;font-size:12px;"> | |
382 | + <span py:when="sorted_field=='milestone'">${_('Milestone')}</span><span py:otherwise="">${_('Component')}</span> | |
383 | + </span> | |
384 | + </div> | |
385 | + <div class="hdr" style="left:91px;top:1px;width:288px;height:${px_hd-2}px;"><span class="hdr_title" style="top:${(px_hd-2-16)/2}px;font-size:12px;">${_('Ticket')}</span></div> | |
386 | + | |
387 | +<py:def function="print_field(px_x,px_w,ticket_col,dupchk=False)"> | |
388 | + <div class="bdy" style="left:${px_x}px;width:${px_w}px;"> | |
389 | + <py:for each="cnt in reversed(range(maxtic))" py:with="t=tickets[cnt]"> | |
390 | + <py:choose> | |
391 | + <py:when test="ticket_col=='ticket'"> | |
392 | + <py:if test="(cnt%2)!=0"> | |
393 | + <div class="stripe" style="top: ${cnt*px_ti+px_top}px;width: ${px_w}px; height: ${px_ti}px;"></div> | |
394 | + </py:if> | |
395 | + <div class="bdy_elem" style="top: ${cnt*px_ti+px_top}px;left: ${px_left-1}px;width: ${px_w-2}px;"> | |
396 | + <a class="tip" href="${req.href.ticket()}/${t['id']}">${t['type']} <s py:strip="t['status']!='closed'">#${t['id']}</s>: ${t['summary'][0:32]}<span py:if="len(t['summary'])>32">...</span> | |
397 | + <span class="popup"> | |
398 | + <br/> | |
399 | + <s py:strip="t['status']!='closed'"> ${t['type']} #${t['id']}</s>: ${t['summary']}<br/> | |
400 | + <br/> | |
401 | + <strong>${_('Start date')}</strong>: | |
402 | + ${t['due_assign'].strftime(dateFormat)} | |
403 | + <span py:if="t['status']!='closed'">(${t['status']} ${t['complete']}%)</span><br/> | |
404 | + <strong>${_('End date')}</strong>: | |
405 | + ${t['due_close'].strftime(dateFormat)} | |
406 | + <span py:if="t['status']=='closed'">(${t['status']}: ${t['resolution']})</span><br/> | |
407 | + <strong>${_('Owner')}</strong>: ${format_author(t['owner'])}<br/> | |
408 | + <strong>${_('Priority')}</strong>: ${t['priority']}<br/> | |
409 | + <py:if test="t['estimatedhours']!=None"> | |
410 | + <strong>${_('Total Hours')}</strong>: ${t['totalhours']}h / <strong>${_('Estimated Hours')}</strong>: ${t['estimatedhours']}h<br/> | |
411 | + </py:if> | |
412 | + <pre> ${t['description']}</pre> | |
413 | + </span> | |
414 | + </a> | |
415 | + </div> | |
416 | + </py:when> | |
417 | + <py:otherwise> | |
418 | + <py:choose> | |
419 | + <py:when test="dupchk"> | |
420 | + <py:if test="(cnt%2)!=0"> | |
421 | + <div class="stripe" style="top: ${cnt*px_ti+px_top}px;width: ${px_w}px; height: ${px_ti}px;"></div> | |
422 | + </py:if> | |
423 | + <div py:if="not cnt or t[ticket_col]!=tickets[cnt-1][ticket_col]" class="bdy_elem" style="top:${cnt*px_ti+px_top}px;left: ${px_left}px;width: ${px_w-2}px;"> | |
424 | + <span py:choose=""> | |
425 | + <span py:when="ticket_col=='milestone' and 'MILESTONE_VIEW' in req.perm"> | |
426 | + <a py:strip="t['milestone']=='*'" class="tip" href="${req.href.milestone()}/${t['milestone']}">${t['milestone']} | |
427 | + <span py:if="t['milestone']!='*'" py:with="m=milestones[t['milestone']]" class="popup"> | |
428 | + <br/> | |
429 | + <img src="${href.chrome('tc/img/package.png')}" />${t['milestone']}<br/> | |
430 | + <br/> | |
431 | + <strong>${_('Due')}</strong>: <span py:if="m['due'] != | |
432 | + None">${m['due'].strftime(dateFormat)}</span><br/> | |
433 | + <pre> ${m['description']}</pre> | |
434 | + </span> | |
435 | + </a> | |
436 | + </span> | |
437 | + <span py:otherwise="">${t[ticket_col]}</span> | |
438 | + </span> | |
439 | + </div> | |
440 | + </py:when> | |
441 | + <py:otherwise> | |
442 | + <py:if test="(cnt%2)!=0"> | |
443 | + <div class="stripe" style="top: ${cnt*px_ti+px_top}px;width: ${px_w}px; height: ${px_ti}px;"></div> | |
444 | + </py:if> | |
445 | + <div class="bdy_elem" style="top: ${cnt*px_ti+px_top}px;left: ${px_left}px;width: ${px_w-2}px;">${ticket_col in ('owner','reporter') and format_author(t[ticket_col]) or t[ticket_col]}</div> | |
446 | + </py:otherwise> | |
447 | + </py:choose> | |
448 | + </py:otherwise> | |
449 | + </py:choose> | |
450 | + </py:for> | |
451 | + </div> | |
452 | +</py:def> | |
453 | + | |
454 | + ${print_field( 91,288,'ticket')} | |
455 | + ${print_field( 1, 89,sorted_field,dupchk=True)} | |
456 | + | |
457 | + </div> | |
458 | + </div> | |
459 | + <!-- gantt --> | |
460 | + </body> | |
461 | +</html> |
@@ -0,0 +1,67 @@ | ||
1 | +<!DOCTYPE html | |
2 | + PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |
3 | + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
4 | +<html xmlns="http://www.w3.org/1999/xhtml" | |
5 | + xmlns:xi="http://www.w3.org/2001/XInclude" | |
6 | + xmlns:py="http://genshi.edgewall.org/"> | |
7 | + <xi:include href="admin.html" /> | |
8 | + <head> | |
9 | + <title>${_('Holidays')}</title> | |
10 | + </head> | |
11 | + | |
12 | + <body> | |
13 | + <h2>${_('Holiday Setting')}</h2> | |
14 | + <py:if test="tbl_chk"> | |
15 | + <form class="addnew" method="post" action=""> | |
16 | + <fieldset> | |
17 | + <legend>${_('Add Holiday')}<span/>:</legend> | |
18 | + <div class="field"> | |
19 | + <label>${_('date')}<span/>:<br /><input type="text" name="date" /></label> | |
20 | + </div> | |
21 | + <label>${_('description')}<span/>:<br /><input type="text" name="description" /></label> | |
22 | + <div class="buttons"> | |
23 | + <input type="submit" name="add" value="${_('submit')}"/> | |
24 | + </div> | |
25 | + </fieldset> | |
26 | + </form> | |
27 | + <form class="addnew" method="post" action=""> | |
28 | + <fieldset> | |
29 | + <legend>${_('Drop table')}<span/>:</legend> | |
30 | + <div class="buttons"> | |
31 | + <input type="submit" name="drop_table" value="${_('DROP holiday table.')}"/> | |
32 | + </div> | |
33 | + </fieldset> | |
34 | + </form> | |
35 | + | |
36 | + <form id="holidays_table" method="post" action=""> | |
37 | + <table class="listing"> | |
38 | + <thead> | |
39 | + <th class="sel"> </th> | |
40 | + <th>${_('date')}</th> | |
41 | + <th>${_('description')}</th> | |
42 | + </thead> | |
43 | + <tr py:for="m in holidays"> | |
44 | + <td class="sel"><input type="checkbox" name="sel" value="${m.get('date','')}" /></td> | |
45 | + <td class="name">${m.get('date','')}</td> | |
46 | + <td class="name">${m.get('description','')}</td> | |
47 | + </tr> | |
48 | + </table> | |
49 | + <div class="buttons"> | |
50 | + <input type="submit" name="remove" value="${_('Remove selected items')}" /> | |
51 | + </div> | |
52 | + <p class="help"> | |
53 | + </p> | |
54 | + </form> | |
55 | + </py:if> | |
56 | + <py:if test= "not tbl_chk"> | |
57 | + <form class="addnew" method="post" action=""> | |
58 | + <fieldset> | |
59 | + <legend>${_('Add Holiday')}<span/>:</legend> | |
60 | + <div class="buttons"> | |
61 | + <input type="submit" name="create_table" value="${_('Create table and insert some holidays.')}"/> | |
62 | + </div> | |
63 | + </fieldset> | |
64 | + </form> | |
65 | + </py:if> | |
66 | + </body> | |
67 | +</html> |
@@ -0,0 +1,246 @@ | ||
1 | +<html xmlns="http://www.w3.org/1999/xhtml" | |
2 | + xmlns:py="http://genshi.edgewall.org/" | |
3 | + xmlns:xi="http://www.w3.org/2001/XInclude"> | |
4 | + <xi:include href="layout.html" /> | |
5 | + <xi:include href="macros.html" /> | |
6 | + <head> | |
7 | + <script type="text/javascript" src="${chrome.htdocs_location}js/folding.js"></script> | |
8 | + <script type="text/javascript"> | |
9 | + jQuery(document).ready(function($) { | |
10 | + $("fieldset legend.foldable").enableFolding(false); | |
11 | + /* Hide the filters for saved queries. */ | |
12 | + $("#options").toggleClass("collapsed"); | |
13 | + }); | |
14 | + </script> | |
15 | + | |
16 | + <style type="text/css"> | |
17 | + form fieldset.collapsed { | |
18 | + border-width: 0px; | |
19 | + margin-bottom: 0px; | |
20 | + padding: 0px .5em; | |
21 | + } | |
22 | + fieldset legend.foldable :link, | |
23 | + fieldset legend.foldable :visited { | |
24 | + background: url(${chrome.htdocs_location}expanded.png) 0 50% no-repeat; | |
25 | + border: none; | |
26 | + color: #666; | |
27 | + font-size: 110%; | |
28 | + padding-left: 16px; | |
29 | + } | |
30 | + fieldset legend.foldable :link:hover, fieldset legend.foldable :visited:hover { | |
31 | + background-color: transparent; | |
32 | + } | |
33 | + | |
34 | + fieldset.collapsed legend.foldable :link, fieldset.collapsed legend.foldable :visited { | |
35 | + background-image: url(${chrome.htdocs_location}collapsed.png); | |
36 | + } | |
37 | + fieldset.collapsed table, fieldset.collapsed div { display: none } | |
38 | + | |
39 | + table.list { | |
40 | + width:100%; | |
41 | + border-collapse: collapse; | |
42 | + margin-bottom: 6px; | |
43 | + } | |
44 | + | |
45 | + table.with-cells td { | |
46 | + border: 1px solid #d7d7d7; | |
47 | + } | |
48 | + | |
49 | + table.list td { | |
50 | + padding:2px; | |
51 | + } | |
52 | + | |
53 | + table.list thead th { | |
54 | + text-align: center; | |
55 | + background: #eee; | |
56 | + border: 1px solid #d7d7d7; | |
57 | + color: #777; | |
58 | + } | |
59 | + | |
60 | + table.list tbody th { | |
61 | + font-weight: bold; | |
62 | + background: #eed; | |
63 | + border: 1px solid #d7d7d7; | |
64 | + color: #777; | |
65 | + } | |
66 | + | |
67 | + | |
68 | + .ticket { | |
69 | + font-size: 10px; | |
70 | + } | |
71 | + | |
72 | + | |
73 | + .textright { | |
74 | + text-align:right; | |
75 | + } | |
76 | + | |
77 | + td.active { | |
78 | + background-color:#fff; | |
79 | + } | |
80 | + .holiday { | |
81 | + background-color: #f6f7f8; | |
82 | + color: black; | |
83 | + } | |
84 | + .today { | |
85 | + background-color: #ffe0e0; | |
86 | + } | |
87 | + | |
88 | + .tip { | |
89 | + position: static; | |
90 | + } | |
91 | + | |
92 | + .tip span.popup{ | |
93 | + position: absolute; | |
94 | + visibility: hidden; | |
95 | + color: black; | |
96 | + border:1px solid #555; | |
97 | + background-color: #ffe; | |
98 | + font-size: 8pt; | |
99 | + padding: 3px; | |
100 | + /*IE6 Hack*/ min-width: 400px; width: auto; _width: 400px; | |
101 | + } | |
102 | + | |
103 | + .tip:hover span.popup{ | |
104 | + visibility: visible; | |
105 | + z-index: 100; | |
106 | + } | |
107 | + | |
108 | + </style> | |
109 | + </head> | |
110 | + <body> | |
111 | + <form> | |
112 | + <fieldset id="options"> | |
113 | + <legend class="foldable">${_('Options')}</legend> | |
114 | + <table class="list"> | |
115 | + <tr> | |
116 | + <td> | |
117 | + </td> | |
118 | + <td> | |
119 | + <label> | |
120 | + ${_('Milestone')} | |
121 | + <select name="selected_milestone"> | |
122 | + <option py:for="m in milestones" value="${m.name}" selected="${selected_milestone==m.name or None}">${m.name}</option> | |
123 | + </select> | |
124 | + </label> | |
125 | + <label> | |
126 | + <input type="checkbox" name="show_my_ticket" checked="$show_my_ticket" | |
127 | + />${_('Show only my tickets')} | |
128 | + </label> | |
129 | + <label> | |
130 | + <input type="checkbox" name="show_closed_ticket" checked="$show_closed_ticket" | |
131 | + />${_('Include closed tickets')} | |
132 | + </label> | |
133 | + </td> | |
134 | + <td align="right"> | |
135 | + <input type="submit" value="${_('Update')}" /> | |
136 | + </td> | |
137 | + </tr> | |
138 | + </table> | |
139 | + </fieldset> | |
140 | + <table class="list"> | |
141 | + <tr> | |
142 | + <td py:with="btntxt = weekly and '%s %s' % (_(month_tbl[prev.month]), prev.day) or _(month_tbl[prev.month])"> | |
143 | + <input type="button" value="<< ${btntxt}" ACCESSKEY="J" onclick="form.year.value = ${prev.year}; form.month.value = ${prev.month}; form.day.value = ${prev.day}; form.submit();"/> | |
144 | + </td> | |
145 | + <td align="center"> | |
146 | + <select name="year" onchange="form.day.value = 1; form.weekly.value = 0;"> | |
147 | + <option py:for="y in range(current.year-3,current.year+4)" | |
148 | + value="$y" | |
149 | + selected="${y==current.year or None}">$y</option> | |
150 | + </select> | |
151 | + ${_('Year')} | |
152 | + <select name="month" onchange="form.day.value = 1; form.weekly.value = 0;"> | |
153 | + <option py:for="m in [1,2,3,4,5,6,7,8,9,10,11,12]" | |
154 | + value="$m" selected="${m==current.month or None}">${_(month_tbl[m])}</option> | |
155 | + </select> | |
156 | + | |
157 | + <input type="submit" value="${_('Update')}" /> | |
158 | + <label ACCESSKEY="M" onclick="form.year.value = ${date.today().year}; form.month.value = ${date.today().month}; form.day.value = ${date.today().day}; form.submit();"/> | |
159 | + <py:choose> | |
160 | + <input py:when="not weekly" type="image" ACCESSKEY="I" onclick="form.weekly.value = 1" src="${href.chrome('tc/img/zoom_in.png')}" alt="${_('Zoom In')}"/> | |
161 | + <input py:otherwise="" type="image" disabled="disabled" src="${href.chrome('tc/img/zoom_in_g.png')}"/> | |
162 | + </py:choose> | |
163 | + <py:choose> | |
164 | + <input py:when="weekly" type="image" ACCESSKEY="K" onclick="form.weekly.value = 0;" src="${href.chrome('tc/img/zoom_out.png')}" alt="${_('Zoom Out')}"/> | |
165 | + <input py:otherwise="" type="image" disabled="disabled" src="${href.chrome('tc/img/zoom_out_g.png')}"/> | |
166 | + </py:choose> | |
167 | + <input name="day" type="hidden" value="${current.day}" /> | |
168 | + <input name="weekly" type="hidden" value="${weekly}" /> | |
169 | + </td> | |
170 | + <td align="right" py:with="btntxt = weekly and '%s %s' % (_(month_tbl[next.month]), next.day) or _(month_tbl[next.month])"> | |
171 | + <input type="button" value="${btntxt} >>" ACCESSKEY="L" onclick="form.year.value = ${next.year}; form.month.value = ${next.month}; form.day.value = ${next.day}; form.submit();"/> | |
172 | + </td> | |
173 | + </tr> | |
174 | + </table> | |
175 | + </form> | |
176 | + <table py:if="sum_estimatedhours != None" class="list"> | |
177 | + <div style="font-size:11px;"> ${_('Total Hours')}: ${sum_totalhours}h / | |
178 | + ${_('Estimated Hours')}: ${sum_estimatedhours}h</div> | |
179 | + </table> | |
180 | + <table class="list with-cells"> | |
181 | + <thead> | |
182 | + <tr py:with="weekdays = [_('Monday'), _('Tuesday'), _('Wednesday'), | |
183 | + _('Thursday'), _('Friday'), _('Saturday'), _('Sunday')]"> | |
184 | + <th></th> | |
185 | + <py:for each="d in range(7)" py:with="mday= first+ timedelta(d);wk=mday.weekday();"> | |
186 | + <th style="width: 14%;">${weekdays[wk]}</th> | |
187 | + </py:for> | |
188 | + </tr> | |
189 | + </thead> | |
190 | + | |
191 | + <tbody> | |
192 | + <tr py:for="w in range(((last - first).days + 1)/7)" style="height: ${weekly and 300 or 60}px;"> | |
193 | + <th></th> | |
194 | + <py:for each="d in range(7)" py:with="mday= first+ timedelta(w*7+d);holiday_desc= days[mday].get('holiday_desc');"> | |
195 | + <td class="${days[mday]['kind']}" style="width: 14%;" valign="top"> | |
196 | + <div class="textright"> | |
197 | + <span py:attrs="{'title':holiday_desc}" py:strip="holiday_desc==None" > | |
198 | + <py:if test="weekly or mday.day==1">${mday.month}/</py:if>${mday.day} | |
199 | + </span> | |
200 | + </div> | |
201 | + <py:for each="c in range(len(days[mday]['ticket']))"> | |
202 | + <div class="ticket" py:with="t=tickets[days[mday]['ticket'][c]['num']]"> | |
203 | + <a class="tip" href="${req.href.ticket()}/${t['id']}"> | |
204 | + <img src="${href.chrome('tc/img/arrow_'+days[mday]['ticket'][c]['img']+'.png')}" alt="+" /> | |
205 | + <s py:strip="t['status']!='closed'"><span class="type">${t['type']}</span>#${t['id']}</s>:${t['summary']} | |
206 | + <span class="popup"> | |
207 | + <br /> | |
208 | + <s py:strip="t['status']!='closed'"> ${t['type']}#${t['id']}</s>: ${t['summary']}<br /> | |
209 | + <br /> | |
210 | + <strong>${_('Start date')}</strong>: <span py:if="t['due_assign'] != None">${t['due_assign'].strftime(dateFormat)}</span> | |
211 | + <span py:if="t['status']!='closed'">(${t['status']} ${t['complete']}%)</span><br/> | |
212 | + <strong>${_('End date')}</strong>: <span py:if="t['due_close'] != None">${t['due_close'].strftime(dateFormat)}</span> | |
213 | + <span py:if="t['status']=='closed'">(${t['status']}: ${t['resolution']})</span><br/> | |
214 | + <strong>${_('Owner')}</strong>: ${format_author(t['owner'])}<br /> | |
215 | + <strong>${_('Priority')}</strong>: ${t['priority']}<br/> | |
216 | + <py:if test="t['estimatedhours']!=None"> | |
217 | + <strong>${_('Total Hours')}</strong>: ${t['totalhours']}h / | |
218 | + <strong>${_('Estimated Hours')}</strong>: ${t['estimatedhours']}h<br/> | |
219 | + </py:if> | |
220 | + <pre> ${t['description']}</pre> | |
221 | + </span> | |
222 | + </a> | |
223 | + </div> | |
224 | + </py:for> | |
225 | + | |
226 | + <py:for each="c in range(len(days[mday]['milestone']))" py:if="'MILESTONE_VIEW' in req.perm"> | |
227 | + <div class="ticket" py:with="m=milestones[days[mday]['milestone'][c]]"> | |
228 | + <a class="tip" href="${req.href.milestone()}/${m['name']}"> | |
229 | + <s py:strip="m['completed']!=True"><img src="${href.chrome('tc/img/package.png')}" />${m['name']}</s> | |
230 | + <span class="popup"> | |
231 | + <br /> | |
232 | + <img src="${href.chrome('tc/img/package.png')}" />${m['name']}<br /> | |
233 | + <br /> | |
234 | + <strong>${_('Due')}</strong>: ${m['due'].strftime(dateFormat)}<br /> | |
235 | + <pre> ${m['description']}</pre> | |
236 | + </span> | |
237 | + </a> | |
238 | + </div> | |
239 | + </py:for> | |
240 | + </td> | |
241 | + </py:for> | |
242 | + </tr> | |
243 | + </tbody> | |
244 | + </table> | |
245 | + </body> | |
246 | +</html> |
@@ -110,4 +110,5 @@ | ||
110 | 110 | cursor.execute(sql) |
111 | 111 | for hol_date,hol_desc in cursor: |
112 | 112 | holidays.append( { 'date': hol_date, 'description': hol_desc}) |
113 | - return 'admin_holiday.html',{'_': _, 'holidays': holidays,'tbl_chk':tbl_chk} | |
113 | + data = {'_': _, 'holidays': holidays, 'tbl_chk': tbl_chk} | |
114 | + return 'ganttcalendar_admin_holiday.html', data |