diff options
author | Anand Aiyer <aaiyer@gmail.com> | 2016-10-31 16:27:01 +0530 |
---|---|---|
committer | Matěj Cepl <mcepl@cepl.eu> | 2024-01-18 19:01:59 +0100 |
commit | 4f7099d9c808fa646f24540039af4ee8e7f943ab (patch) | |
tree | 326e4a847a448791ae9c0f4ee0af89c1257adc94 /interfaces | |
parent | 5e1b5fe911d4805133357e329d009f998300867d (diff) | |
download | bugseverywhere-4f7099d9c808fa646f24540039af4ee8e7f943ab.tar.gz |
* Forked bugseverywhere -- so update the README
* Fix web interface issue with editing a bug
* Integrate the web interface into the be command line, so it can be
invoked easily using 'be web'
Diffstat (limited to 'interfaces')
-rw-r--r-- | interfaces/web/.hgignore | 6 | ||||
-rw-r--r-- | interfaces/web/.hgtags | 2 | ||||
-rw-r--r-- | interfaces/web/LICENSE | 24 | ||||
-rw-r--r-- | interfaces/web/README | 20 | ||||
-rw-r--r-- | interfaces/web/__init__.py | 0 | ||||
-rwxr-xr-x | interfaces/web/cfbe.py | 42 | ||||
-rw-r--r-- | interfaces/web/static/scripts/jquery.corners.min.js | 7 | ||||
-rw-r--r-- | interfaces/web/static/style/aal.css | 99 | ||||
-rw-r--r-- | interfaces/web/static/style/cfbe.css | 180 | ||||
-rw-r--r-- | interfaces/web/templates/base.html | 123 | ||||
-rw-r--r-- | interfaces/web/templates/bug.html | 160 | ||||
-rw-r--r-- | interfaces/web/templates/empty-list.html | 11 | ||||
-rw-r--r-- | interfaces/web/templates/list.html | 25 | ||||
-rw-r--r-- | interfaces/web/web.py | 211 |
14 files changed, 0 insertions, 910 deletions
diff --git a/interfaces/web/.hgignore b/interfaces/web/.hgignore deleted file mode 100644 index a0e81b7..0000000 --- a/interfaces/web/.hgignore +++ /dev/null @@ -1,6 +0,0 @@ -syntax: glob -*.pyc -.DS_Store -*.log -*.tmproj - diff --git a/interfaces/web/.hgtags b/interfaces/web/.hgtags deleted file mode 100644 index eeea432..0000000 --- a/interfaces/web/.hgtags +++ /dev/null @@ -1,2 +0,0 @@ -8d8c7f52f3afb6026dd47d7303a7f6a734b3177d alpha -abfe7aa4bdf3cd019ad1d51278c293a4e008b397 alpha diff --git a/interfaces/web/LICENSE b/interfaces/web/LICENSE deleted file mode 100644 index 44f0935..0000000 --- a/interfaces/web/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ - -copyrev: 566007698e1bb8a4f0bc4929a68ecc068ab28890 -copy: LICENSE.txt - -Copyright (c) 2009 Steve Losh - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/interfaces/web/README b/interfaces/web/README deleted file mode 100644 index 6bd04e5..0000000 --- a/interfaces/web/README +++ /dev/null @@ -1,20 +0,0 @@ --*- markdown -*- - -Cherry Flavored Bugs Everywhere -=============================== - -CFBE is a quick web interface to [BugsEverywhere](http://bugseverywhere.org/). It's still very much a work-in-progress. - -Installing ----------- - -I intend to streamline the installation once I'm satisfied with the interface itself. For now, the install process goes something like this: - -* Install [CherryPy](http://cherrypy.org/) if you don't have it. -* Install [Jinja2](http://jinja.pocoo.org/2/) if you don't have it. -* Install [BugsEverywhere](http://bugseverywhere.org/) if you don't have it. -* Download a zip/tar of CFBE (or hg clone) from the [Mercurial repository](http://bitbucket.org/sjl/cherryflavoredbugseverywhere/). -* Unzip (if you grabbed a zip) and put the folder in your Python site-packages directory (or put it anywhere and symlink it to site-packages). -* Symlink `site-packages/cherryflavoredbugseverywhere/cfbe.py` to `/usr/local/bin/cfbe` -* Use `cfbe [project_root]` to start up the web interface for that project. -* Visit http://localhost:8080/ in a browser. diff --git a/interfaces/web/__init__.py b/interfaces/web/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/interfaces/web/__init__.py +++ /dev/null diff --git a/interfaces/web/cfbe.py b/interfaces/web/cfbe.py deleted file mode 100755 index 68c484d..0000000 --- a/interfaces/web/cfbe.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python - -import cherrypy -import web -from optparse import OptionParser -from os import path - -module_dir = path.dirname(path.abspath(web.__file__)) -template_dir = path.join(module_dir, 'templates') - -def build_parser(): - """Builds and returns the command line option parser.""" - - usage = 'usage: %prog bug_directory' - parser = OptionParser(usage) - return parser - -def parse_arguments(): - """Parse the command line arguments.""" - - parser = build_parser() - (options, args) = parser.parse_args() - - if len(args) != 1: - parser.error('You need to specify a bug directory.') - - return { 'bug_root': args[0], } - - -config = path.join(module_dir, 'cfbe.config') -options = parse_arguments() - -WebInterface = web.WebInterface(path.abspath(options['bug_root']), template_dir) - -cherrypy.config.update({ - 'tools.encode.on': True, - 'tools.encode.encoding': 'utf8', - 'tools.staticdir.root': path.join(module_dir, 'static'), - }) -app_config = { '/static': { 'tools.staticdir.on': True, - 'tools.staticdir.dir': '', } } -cherrypy.quickstart(WebInterface, '/', app_config) diff --git a/interfaces/web/static/scripts/jquery.corners.min.js b/interfaces/web/static/scripts/jquery.corners.min.js deleted file mode 100644 index 0b2f979..0000000 --- a/interfaces/web/static/scripts/jquery.corners.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/* - * jQuery Corners 0.3 - * Copyright (c) 2008 David Turnbull, Steven Wittens - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - */ -jQuery.fn.corners=function(C){var N="rounded_by_jQuery_corners";var V=B(C);var F=false;try{F=(document.body.style.WebkitBorderRadius!==undefined);var Y=navigator.userAgent.indexOf("Chrome");if(Y>=0){F=false}}catch(E){}var W=false;try{W=(document.body.style.MozBorderRadius!==undefined);var Y=navigator.userAgent.indexOf("Firefox");if(Y>=0&&parseInt(navigator.userAgent.substring(Y+8))<3){W=false}}catch(E){}return this.each(function(b,h){$e=jQuery(h);if($e.hasClass(N)){return }$e.addClass(N);var a=/{(.*)}/.exec(h.className);var c=a?B(a[1],V):V;var j=h.nodeName.toLowerCase();if(j=="input"){h=O(h)}if(F&&c.webkit){K(h,c)}else{if(W&&c.mozilla&&(c.sizex==c.sizey)){M(h,c)}else{var d=D(h.parentNode);var f=D(h);switch(j){case"a":case"input":Z(h,c,d,f);break;default:R(h,c,d,f);break}}}});function K(d,c){var a=""+c.sizex+"px "+c.sizey+"px";var b=jQuery(d);if(c.tl){b.css("WebkitBorderTopLeftRadius",a)}if(c.tr){b.css("WebkitBorderTopRightRadius",a)}if(c.bl){b.css("WebkitBorderBottomLeftRadius",a)}if(c.br){b.css("WebkitBorderBottomRightRadius",a)}}function M(d,c){var a=""+c.sizex+"px";var b=jQuery(d);if(c.tl){b.css("-moz-border-radius-topleft",a)}if(c.tr){b.css("-moz-border-radius-topright",a)}if(c.bl){b.css("-moz-border-radius-bottomleft",a)}if(c.br){b.css("-moz-border-radius-bottomright",a)}}function Z(k,n,l,a){var m=S("table");var i=S("tbody");m.appendChild(i);var j=S("tr");var d=S("td","top");j.appendChild(d);var h=S("tr");var c=T(k,n,S("td"));h.appendChild(c);var f=S("tr");var b=S("td","bottom");f.appendChild(b);if(n.tl||n.tr){i.appendChild(j);X(d,n,l,a,true)}i.appendChild(h);if(n.bl||n.br){i.appendChild(f);X(b,n,l,a,false)}k.appendChild(m);if(jQuery.browser.msie){m.onclick=Q}k.style.overflow="hidden"}function Q(){if(!this.parentNode.onclick){this.parentNode.click()}}function O(c){var b=document.createElement("a");b.id=c.id;b.className=c.className;if(c.onclick){b.href="javascript:";b.onclick=c.onclick}else{jQuery(c).parent("form").each(function(){b.href=this.action});b.onclick=I}var a=document.createTextNode(c.value);b.appendChild(a);c.parentNode.replaceChild(b,c);return b}function I(){jQuery(this).parent("form").each(function(){this.submit()});return false}function R(d,a,b,c){var f=T(d,a,document.createElement("div"));d.appendChild(f);if(a.tl||a.tr){X(d,a,b,c,true)}if(a.bl||a.br){X(d,a,b,c,false)}}function T(j,i,k){var b=jQuery(j);var l;while(l=j.firstChild){k.appendChild(l)}if(j.style.height){var f=parseInt(b.css("height"));k.style.height=f+"px";f+=parseInt(b.css("padding-top"))+parseInt(b.css("padding-bottom"));j.style.height=f+"px"}if(j.style.width){var a=parseInt(b.css("width"));k.style.width=a+"px";a+=parseInt(b.css("padding-left"))+parseInt(b.css("padding-right"));j.style.width=a+"px"}k.style.paddingLeft=b.css("padding-left");k.style.paddingRight=b.css("padding-right");if(i.tl||i.tr){k.style.paddingTop=U(j,i,b.css("padding-top"),true)}else{k.style.paddingTop=b.css("padding-top")}if(i.bl||i.br){k.style.paddingBottom=U(j,i,b.css("padding-bottom"),false)}else{k.style.paddingBottom=b.css("padding-bottom")}j.style.padding=0;return k}function U(f,a,d,c){if(d.indexOf("px")<0){try{console.error("%s padding not in pixels",(c?"top":"bottom"),f)}catch(b){}d=a.sizey+"px"}d=parseInt(d);if(d-a.sizey<0){try{console.error("%s padding is %ipx for %ipx corner:",(c?"top":"bottom"),d,a.sizey,f)}catch(b){}d=a.sizey}return d-a.sizey+"px"}function S(b,a){var c=document.createElement(b);c.style.border="none";c.style.borderCollapse="collapse";c.style.borderSpacing=0;c.style.padding=0;c.style.margin=0;if(a){c.style.verticalAlign=a}return c}function D(b){try{var d=jQuery.css(b,"background-color");if(d.match(/^(transparent|rgba\(0,\s*0,\s*0,\s*0\))$/i)&&b.parentNode){return D(b.parentNode)}if(d==null){return"#ffffff"}if(d.indexOf("rgb")>-1){d=A(d)}if(d.length==4){d=L(d)}return d}catch(a){return"#ffffff"}}function L(a){return"#"+a.substring(1,2)+a.substring(1,2)+a.substring(2,3)+a.substring(2,3)+a.substring(3,4)+a.substring(3,4)}function A(h){var a=255;var d="";var b;var e=/([0-9]+)[, ]+([0-9]+)[, ]+([0-9]+)/;var f=e.exec(h);for(b=1;b<4;b++){d+=("0"+parseInt(f[b]).toString(16)).slice(-2)}return"#"+d}function B(b,d){var b=b||"";var c={sizex:5,sizey:5,tl:false,tr:false,bl:false,br:false,webkit:true,mozilla:true,transparent:false};if(d){c.sizex=d.sizex;c.sizey=d.sizey;c.webkit=d.webkit;c.transparent=d.transparent;c.mozilla=d.mozilla}var a=false;var e=false;jQuery.each(b.split(" "),function(f,j){j=j.toLowerCase();var h=parseInt(j);if(h>0&&j==h+"px"){c.sizey=h;if(!a){c.sizex=h}a=true}else{switch(j){case"no-native":c.webkit=c.mozilla=false;break;case"webkit":c.webkit=true;break;case"no-webkit":c.webkit=false;break;case"mozilla":c.mozilla=true;break;case"no-mozilla":c.mozilla=false;break;case"anti-alias":c.transparent=false;break;case"transparent":c.transparent=true;break;case"top":e=c.tl=c.tr=true;break;case"right":e=c.tr=c.br=true;break;case"bottom":e=c.bl=c.br=true;break;case"left":e=c.tl=c.bl=true;break;case"top-left":e=c.tl=true;break;case"top-right":e=c.tr=true;break;case"bottom-left":e=c.bl=true;break;case"bottom-right":e=c.br=true;break}}});if(!e){if(!d){c.tl=c.tr=c.bl=c.br=true}else{c.tl=d.tl;c.tr=d.tr;c.bl=d.bl;c.br=d.br}}return c}function P(f,d,h){var e=Array(parseInt("0x"+f.substring(1,3)),parseInt("0x"+f.substring(3,5)),parseInt("0x"+f.substring(5,7)));var c=Array(parseInt("0x"+d.substring(1,3)),parseInt("0x"+d.substring(3,5)),parseInt("0x"+d.substring(5,7)));r="0"+Math.round(e[0]+(c[0]-e[0])*h).toString(16);g="0"+Math.round(e[1]+(c[1]-e[1])*h).toString(16);d="0"+Math.round(e[2]+(c[2]-e[2])*h).toString(16);return"#"+r.substring(r.length-2)+g.substring(g.length-2)+d.substring(d.length-2)}function X(f,a,b,d,c){if(a.transparent){G(f,a,b,c)}else{J(f,a,b,d,c)}}function J(k,z,p,a,n){var h,f;var l=document.createElement("div");l.style.fontSize="1px";l.style.backgroundColor=p;var b=0;for(h=1;h<=z.sizey;h++){var u,t,q;arc=Math.sqrt(1-Math.pow(1-h/z.sizey,2))*z.sizex;var c=z.sizex-Math.ceil(arc);var w=Math.floor(b);var v=z.sizex-c-w;var o=document.createElement("div");var m=l;o.style.margin="0px "+c+"px";o.style.height="1px";o.style.overflow="hidden";for(f=1;f<=v;f++){if(f==1){if(f==v){u=((arc+b)*0.5)-w}else{t=Math.sqrt(1-Math.pow(1-(c+1)/z.sizex,2))*z.sizey;u=(t-(z.sizey-h))*(arc-w-v+1)*0.5}}else{if(f==v){t=Math.sqrt(1-Math.pow((z.sizex-c-f+1)/z.sizex,2))*z.sizey;u=1-(1-(t-(z.sizey-h)))*(1-(b-w))*0.5}else{q=Math.sqrt(1-Math.pow((z.sizex-c-f)/z.sizex,2))*z.sizey;t=Math.sqrt(1-Math.pow((z.sizex-c-f+1)/z.sizex,2))*z.sizey;u=((t+q)*0.5)-(z.sizey-h)}}H(z,o,m,n,P(p,a,u));m=o;var o=m.cloneNode(false);o.style.margin="0px 1px"}H(z,o,m,n,a);b=arc}if(n){k.insertBefore(l,k.firstChild)}else{k.appendChild(l)}}function H(c,a,e,d,b){if(d&&!c.tl){a.style.marginLeft=0}if(d&&!c.tr){a.style.marginRight=0}if(!d&&!c.bl){a.style.marginLeft=0}if(!d&&!c.br){a.style.marginRight=0}a.style.backgroundColor=b;if(d){e.appendChild(a)}else{e.insertBefore(a,e.firstChild)}}function G(c,o,l,h){var f=document.createElement("div");f.style.fontSize="1px";var a=document.createElement("div");a.style.overflow="hidden";a.style.height="1px";a.style.borderColor=l;a.style.borderStyle="none solid";var m=o.sizex-1;var j=o.sizey-1;if(!j){j=1}for(var b=0;b<o.sizey;b++){var n=m-Math.floor(Math.sqrt(1-Math.pow(1-b/j,2))*m);if(b==2&&o.sizex==6&&o.sizey==6){n=2}var k=a.cloneNode(false);k.style.borderWidth="0 "+n+"px";if(h){k.style.borderWidth="0 "+(o.tr?n:0)+"px 0 "+(o.tl?n:0)+"px"}else{k.style.borderWidth="0 "+(o.br?n:0)+"px 0 "+(o.bl?n:0)+"px"}h?f.appendChild(k):f.insertBefore(k,f.firstChild)}if(h){c.insertBefore(f,c.firstChild)}else{c.appendChild(f)}}};
\ No newline at end of file diff --git a/interfaces/web/static/style/aal.css b/interfaces/web/static/style/aal.css deleted file mode 100644 index 9bad98f..0000000 --- a/interfaces/web/static/style/aal.css +++ /dev/null @@ -1,99 +0,0 @@ -/* - aardvark.legs by Anatoli Papirovski - http://fecklessmind.com/ - Licensed under the MIT license. http://www.opensource.org/licenses/mit-license.php -*/ - -/* - Reset first. Modified version of Eric Meyer and Paul Chaplin reset - from http://meyerweb.com/eric/tools/css/reset/ -*/ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, font, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -header, nav, section, article, aside, footer -{border: 0; margin: 0; outline: 0; padding: 0; background: transparent; vertical-align: baseline;} - -blockquote, q {quotes: none;} -blockquote:before,blockquote:after,q:before,q:after {content: ''; content: none;} - -header, nav, section, article, aside, footer {display: block;} - -/* Basic styles */ -body {background: #fff; color: #000; font: 0.875em/1.5em "Helvetica Neue", Helvetica, Arial, "Liberation Sans", "Bitstream Vera Sans", sans-serif;} -html>body {font-size: 14px;} - -img {display: inline-block; vertical-align: bottom;} - -h1,h2,h3,h4,h5,h6,strong,b,dt,th {font-weight: 700;} -address,cite,em,i,caption,dfn,var {font-style: italic;} - -h1 {margin: 0 0 0.75em; font-size: 2em;} -h2 {margin: 0 0 1em; font-size: 1.5em;} -h3 {margin: 0 0 1.286em; font-size: 1.167em;} -h4 {margin: 0 0 1.5em; font-size: 1em;} -h5 {margin: 0 0 1.8em; font-size: .834em;} -h6 {margin: 0 0 2em; font-size: .75em;} - -p,ul,ol,dl,blockquote,pre {margin: 0 0 1.5em;} - -li ul,li ol {margin: 0;} -ul {list-style: outside disc;} -ol {list-style: outside decimal;} -li {margin: 0 0 0 2em;} -dd {padding-left: 1.5em;} -blockquote {padding: 0 1.5em;} - -a {text-decoration: underline;} -a:hover {text-decoration: none;} -abbr,acronym {border-bottom: 1px dotted; cursor: help;} -del {text-decoration: line-through;} -ins {text-decoration: overline;} -sub {font-size: .834em; line-height: 1em; vertical-align: sub;} -sup {font-size: .834em; line-height: 1em; vertical-align: super;} - -tt,code,kbd,samp,pre {font-size: 1em; font-family: "Courier New", Courier, monospace;} - -/* Table styles */ -table {border-collapse: collapse; border-spacing: 0; margin: 0 0 1.5em;} -caption {text-align: left;} -th, td {padding: .25em .5em;} -tbody td, tbody th {border: 1px solid #000;} -tfoot {font-style: italic;} - -/* Form styles */ -fieldset {clear: both;} -legend {padding: 0 0 1.286em; font-size: 1.167em; font-weight: 700;} -fieldset fieldset legend {padding: 0 0 1.5em; font-size: 1em;} -* html legend {margin-left: -7px;} -*+html legend {margin-left: -7px;} - -form .field, form .buttons {clear: both; margin: 0 0 1.5em;} -form .field label {display: block;} -form ul.fields li {list-style-type: none; margin: 0;} -form ul.inline li, form ul.inline label {display: inline;} -form ul.inline li {padding: 0 .75em 0 0;} - -input.radio, input.checkbox {vertical-align: top;} -label, button, input.submit, input.image {cursor: pointer;} -* html input.radio, * html input.checkbox {vertical-align: middle;} -*+html input.radio, *+html input.checkbox {vertical-align: middle;} - -textarea {overflow: auto;} -input.text, input.password, textarea, select {margin: 0; font: 1em/1.3 Helvetica, Arial, "Liberation Sans", "Bitstream Vera Sans", sans-serif; vertical-align: bottom;} -input.text, input.password, textarea {border: 1px solid #444; border-bottom-color: #666; border-right-color: #666; padding: 2px;} - -* html button {margin: 0 .34em 0 0;} -*+html button {margin: 0 .34em 0 0;} - -form.horizontal .field {padding-left: 150px;} -form.horizontal .field label {display: inline; float: left; width: 140px; margin-left: -150px;} - -/* Useful classes */ -img.left {display: inline; float: left; margin: 0 1.5em .75em 0;} -img.right {display: inline; float: right; margin: 0 0 .75em .75em;}
\ No newline at end of file diff --git a/interfaces/web/static/style/cfbe.css b/interfaces/web/static/style/cfbe.css deleted file mode 100644 index 2d7b90b..0000000 --- a/interfaces/web/static/style/cfbe.css +++ /dev/null @@ -1,180 +0,0 @@ -/* @override http://localhost:8080/static/style/cfbe.css */ - -body { - background-color: #eee; -} - -div#main-pane { - width: 960px; - margin: 3em auto; - border: 1px solid #888; - background-color: #fcfcfc; -} -.inside-main-pane { - padding: 0em 3em; -} - -div#header { - background-color: #D8004A; - height: 6em; -} -div#header h1 { - font-size: 4em; - line-height: 1.5em; - margin-bottom: 0em; - color: #fff; - font-weight: normal; - font-family: "Helvetica Neue Ultra Light", "HelveticaNeue-UltraLight", "Helvetica", "Arial", sans-serif; - letter-spacing: 1px; -} - -div#navigation { - height: 3em; - line-height: 3em; - border-bottom: 1px solid #888; -} -div#content-pane { - margin: 1.5em 0em 3em; -} - -div#filter-pane { - display: none; - border-bottom: 1px solid #888; - line-height: 3em; - text-align: right; -} -ul.filter-items { - list-style-type: none; - margin: 0em; - padding: 0em; -} -ul.filter-items li { - display: inline; - margin-left: 1.5em; -} - -div#footer { - text-align: center; - height: 3em; - border-top: 1px solid #888; -} -div#footer p { - font-size: 0.9em; - line-height: 3.333em; -} - -span#filters { - float: right; -} -span#filters a { - margin-left: 1.5em; -} - -a:link, a:visited, a:active { - color: #d03; text-decoration: none; font-weight: bold; -} -a:hover { - color: #60b305; -} - -.header-with-link { - display: inline-block; -} -.header-link { - margin-left: 1em; -} - -table#bug-list { - width: 100%; border-collapse: collapse; border: 0.084em solid #ccc; -} -table#bug-list td, table#bug-list th { - border: 0em; border-bottom: 0.084em solid #ccc; text-align: left; -} -table tr td, table tr th { - padding: 0px 5px; -} -table tr td { - line-height: 2.832em; padding-bottom: 0.084em; -} -table tr th { - line-height: 2.916em; -} -table { - margin-bottom: 1.417em; -} -tr.stripe { - background-color: #fcecf8; -} - -div#assignees, div#targets, div#tags { - display: none; -} - -p.creation-info { - color: #888; -} -span.detail-field-header { - font-weight: 700; - width: 7.5em; - padding-right: 1em; - display: inline-block; - text-align: right; -} - -div.bug-comment { - margin-left: 2em; -} -p.bug-comment-body { - white-space: pre; - margin: 0em 0em 0em 0em; -} -p.bug-comment-footer { - margin: 0em 0em; color: #888; -} -h4.bug-comment-header { - margin: 1.5em 0em 0em; -} - -#create-form { - display: none; -} -#create-form fieldset { - clear: none; -} -#create-form input#create-summary { - width: 20em; - border: 1px solid #888; - margin-right: 1.5em; -} -#create-button { - margin: 0em; -} - -form#add-comment-form { - display: none; - margin-top: 1.5em; -} -p#add-comment-link { - margin-top: 1.5em; -} - -form#bug-details-edit-form { - display: none; -} -form#bug-details-edit-form label { - font-weight: 700; - width: 7.5em; - margin-left: 0em; - margin-right: 1em; - text-align: right; -} -form#bug-details-edit-form .field { - padding-left: 0em; -} - -form#bug-summary-edit-form { - display: none; -} -input#bug-summary-edit-body { - width: 95%; -} diff --git a/interfaces/web/templates/base.html b/interfaces/web/templates/base.html deleted file mode 100644 index 5287470..0000000 --- a/interfaces/web/templates/base.html +++ /dev/null @@ -1,123 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - -<html> - <head> - <title>Cherry Flavored Bugs Everywhere!</title> - - <link rel="stylesheet" type="text/css" media="screen" - href="/static/style/aal.css" /> - <link rel="stylesheet" type="text/css" media="screen" - href="/static/style/cfbe.css" /> - - <script type="text/javascript" - src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"> - </script> - - <script type="text/javascript" - src="/static/scripts/jquery.corners.min.js"> - </script> - - <script type="text/javascript"> - $(function() { - $('#filter-assignee').click(function(e) { - $('#filter-pane').html($('#assignees').html()); - $('#filter-pane').fadeIn('fast'); - e.preventDefault(); - }); - - $('#filter-target').click(function(e) { - $('#filter-pane').html($('#targets').html()); - $('#filter-pane').fadeIn('fast'); - e.preventDefault(); - }); - - $('#filter-tag').click(function(e) { - $('#filter-pane').html($('#tags').html()); - $('#filter-pane').fadeIn('fast'); - e.preventDefault(); - }); - - $('#create-bug').click(function(e) { - $('#create-bug').hide(); - $('#create-form').fadeIn('fast'); - e.preventDefault(); - }); - - $('table tr:odd').addClass('stripe'); - }); - </script> - - {% block script %}{% endblock %} - </head> - - <body> - <div id="main-pane"> - <div id="header" class="inside-main-pane"> - <h1>{{ repository_name }}</h1> - </div> - <div id="navigation" class="inside-main-pane"> - <span id="filters"> - <a href="/">Open</a> - <a href="/?status=closed">Closed</a> - <a href="" id="filter-assignee">Assigned to...</a> - <a href="" id="filter-target">Scheduled for...</a> - <a href="" id="filter-tag">Tags...</a> - </span> - <span id="create"> - <a href="" id="create-bug">+ Create a new bug</a> - </span> - <span id="create-form"> - <form action="/create" method="post"> - <fieldset> - <input type="text" - id="create-summary" name="summary" /> - <button id="create-button" - type="submit">Create</button> - </fieldset> - </form> - </span> - </div> - <div id="filter-pane" class="inside-main-pane"></div> - <div id="content-pane" class="inside-main-pane"> - <h2>{% block page_title %} {% endblock %}</h2> - {% block content %}{% endblock %} - </div> - <div id="footer" class="inside-main-pane"> - <p> - <a href="">Cherry Flavored Bugs Everywhere</a> - was created by <a href="http://stevelosh.com">Steve Losh</a> and a very nice <a href="http://fecklessmind.com/2009/01/20/aardvark-css-framework/">aardvark</a> - using <a href="http://cherrypy.org">CherryPy</a>, - <a href="http://jinja.pocoo.org/2/">Jinja2</a>, - and <a href="http://jquery.com">jQuery</a>. - </p> - </div> - </div> - <div id="assignees"> - <ul class="filter-items"> - <li><a href="/?assignee=None">Unassigned</a></li> - {% for assignee in assignees %} - {% if assignee != "None" %} - <li><a href="/?assignee={{ assignee|e }}">{{ assignee|e }}</a></li> - {% endif %} - {% endfor %} - </ul> - </div> - <div id="targets"> - <ul class="filter-items"> - <li><a href="/?target=None">Unscheduled</a></li> - {% for target in targets %} - <li><a href="/?target={{ target }}">{{ target }}</a></li> - {% endfor %} - </ul> - </div> - <div id="tags"> - <ul class="filter-items"> - <li><a href="/?tag=None">All</a></li> - {% for tag in tags %} - <li><a href="/?tag={{ tag }}">{{ tag }}</a></li> - {% endfor %} - </ul> - </div> - </body> -</html> diff --git a/interfaces/web/templates/bug.html b/interfaces/web/templates/bug.html deleted file mode 100644 index b6986a9..0000000 --- a/interfaces/web/templates/bug.html +++ /dev/null @@ -1,160 +0,0 @@ -{% extends "base.html" %} - -{% block page_title %} - Bug {{ bug.id.user() }} – {{ bug.summary|truncate(70) }} -{% endblock %} - -{% block script %} - <script type="text/javascript"> - $(function() { - function set_current_detail_default_values() { - $('#bug-details-edit-status option[value="{{ bug.status }}"]').attr('selected', 'yes'); - $('#bug-details-edit-target option[value="{{ bug.target|e }}"]').attr('selected', 'yes'); - $('#bug-details-edit-assignee option[value^="{{ bug.assigned|striptags }}"]').attr('selected', 'yes'); - $('#bug-details-edit-severity option[value="{{ bug.severity }}"]').attr('selected', 'yes'); - } - - $('#add-comment').click(function(e) { - $('#add-comment-link').hide(); - $('#add-comment-form').fadeIn('fast'); - e.preventDefault(); - }); - - $('#edit-bug-details').click(function(e) { - $('#bug-details').hide(); - $('#bug-details-edit-form').fadeIn('fast'); - e.preventDefault(); - }); - - $('#bug-details-edit-form button[type="reset"]').click(function(e) { - $('#bug-details-edit-form').hide(); - $('#bug-details').fadeIn('fast', function() { set_current_detail_default_values(); } ); - }); - - $('#edit-bug-summary').click(function(e) { - $('#bug-summary').hide(); - $('#bug-summary-edit-form').fadeIn('fast'); - e.preventDefault(); - }); - - $('#bug-summary-edit-form button[type="reset"]').click(function(e) { - $('#bug-summary-edit-form').hide(); - $('#bug-summary').fadeIn('fast', function() { set_current_detail_default_values(); } ); - }); - - set_current_detail_default_values(); - }); - </script> -{% endblock %} - -{% block content %} - <p class="creation-info">Created on {{ bug.time|datetimeformat }} by {{ bug.creator|e }}</p> - - <h3 class="header-with-link">Bug Details</h3> - <span class="header-link"> - <a href="" id="edit-bug-details">edit</a> - </span> - - <p id="bug-details"> - <span class="detail-field-header">Status:</span> - <span class="detail-field-contents">{{ bug.status }}</span><br /> - - <span class="detail-field-header">Severity:</span> - <span class="detail-field-contents">{{ bug.severity }}</span><br /> - - <span class="detail-field-header">Scheduled for:</span> - <span class="detail-field-contents">{{ target }}</span><br /> - - <span class="detail-field-header">Assigned to:</span> - <span class="detail-field-contents">{{ assignee|e }}</span><br /> - - <span class="detail-field-header">Permanent ID:</span> - <span class="detail-field-contents">{{ bug.uuid }}</span><br /> - </p> - - <form id="bug-details-edit-form" class="horizontal" action="/edit" method="post"> - <fieldset> - <input type="hidden" name="id" value="{{ bug.uuid }}" /> - <div class="field"> - <label for="bug-details-edit-status">Status:</label> - <select id="bug-details-edit-status" name="status"> - {% for status in statuses %} - <option value="{{ status }}">{{ status }}</option> - {% endfor %} - </select> - </div> - <div class="field"> - <label for="bug-details-edit-severity">Severity:</label> - <select id="bug-details-edit-severity" name="severity"> - {% for severity in severities %} - <option value="{{ severity }}">{{ severity }}</option> - {% endfor %} - </select> - </div> - <div class="field"> - <label for="bug-details-edit-target">Scheduled for:</label> - <select id="bug-details-edit-target" name="target"> - <option value="None">Unscheduled</option> - {% for target in targets %} - <option value="{{ target|e }}">{{ target }}</option> - {% endfor %} - </select> - </div> - <div class="field"> - <label for="bug-details-edit-assignee">Assigned to:</label> - <select id="bug-details-edit-assignee" name="assignee"> - <option value="None">Unassigned</option> - {% for assignee in assignees %} - <option value="{{ assignee|e }}">{{ assignee|e }}</option> - {% endfor %} - </select> - </div> - <div class="buttons"> - <button type="submit">Save Changes</button> - <button type="reset">Discard Changes</button> - </div> - </fieldset> - </form> - - <h3 class="header-with-link">Summary</h3> - <span class="header-link"> - <a href="" id="edit-bug-summary">edit</a> - </span> - <p id="bug-summary"> - {{ bug.summary }} - </p> - - <form id="bug-summary-edit-form" class="vertical" action="/edit" method="post"> - <fieldset> - <input type="hidden" name="id" value="{{ bug.uuid }}" /> - <div class="field"> - <input type="text" class="text" id="bug-summary-edit-body" name="summary" value="{{ bug.summary }}" /> - </div> - <div class="buttons"> - <button type="submit">Save Changes</button> - <button type="reset">Discard Changes</button> - </div> - </fieldset> - </form> - - <h3>Comments</h3> - {% for comment in bug.comments() %} - <div class="bug-comment"> - <h4 class="bug-comment-header">{{ comment.author|striptags|e }} said:</h4> - <p class="bug-comment-body">{{ comment.body|trim|e }}</p> - <p class="bug-comment-footer">on {{ comment.time|datetimeformat }}</p> - </div> - {% endfor %} - <form id="add-comment-form" class="vertical" action="/comment" method="post"> - <fieldset> - <input type="hidden" name="id" value="{{ bug.uuid }}" /> - <div class="field"> - <textarea cols="60" rows="6" id="add-comment-body" name="body"></textarea> - </div> - <div class="buttons"> - <button type="submit">Submit</button> - </div> - </fieldset> - </form> - <p id="add-comment-link"><a href="" id="add-comment">+ Add a comment</a></p> -{% endblock %} diff --git a/interfaces/web/templates/empty-list.html b/interfaces/web/templates/empty-list.html deleted file mode 100644 index 4c01cb2..0000000 --- a/interfaces/web/templates/empty-list.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base.html" %} - -{% block page_title %} - {{ label }} -{% endblock %} - -{% block content %} - <p> - No matching bugs. - </p> -{% endblock %} diff --git a/interfaces/web/templates/list.html b/interfaces/web/templates/list.html deleted file mode 100644 index 65e6fe2..0000000 --- a/interfaces/web/templates/list.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "base.html" %} - -{% block page_title %} - {{ label }} -{% endblock %} - -{% block content %} - <table id="bug-list"> - <tr> - <th>ID</th> - <th>Summary</th> - <th>Status</th> - <th>Assigned To</th> - </tr> - {% for bug in bugs %} - <tr> - <td>{{ bug.id.user() }}</td> - <td><a href="/bug?{{ urlencode({'id':bug.id.long_user()}) }}"> - {{ bug.summary|e|truncate(70) }}</a></td> - <td>{{ bug.status }}</td> - <td>{{ bug.assigned|striptags }}</td> - </tr> - {% endfor %} - </table> -{% endblock %} diff --git a/interfaces/web/web.py b/interfaces/web/web.py deleted file mode 100644 index 2907932..0000000 --- a/interfaces/web/web.py +++ /dev/null @@ -1,211 +0,0 @@ -from datetime import datetime -from urllib import urlencode - -from jinja2 import Environment, FileSystemLoader -import cherrypy - -from libbe import storage -from libbe import bugdir -from libbe.command.depend import get_blocked_by, get_blocks -from libbe.command.target import add_target, remove_target -from libbe.command.target import bug_from_target_summary, bug_target -from libbe.command.util import bugdir_bug_comment_from_user_id -from libbe.storage.util import settings_object -import libbe.command.tag - - -EMPTY = settings_object.EMPTY - -def datetimeformat(value, format='%B %d, %Y at %I:%M %p'): - """Takes a timestamp and revormats it into a human-readable string.""" - return datetime.fromtimestamp(value).strftime(format) - - -class WebInterface: - """The web interface to CFBE.""" - - def __init__(self, bug_root, template_root): - """Initialize the bug repository for this web interface.""" - self.bug_root = bug_root - store = storage.get_storage(self.bug_root) - store.connect() - version = store.storage_version() - print version - self.bd = bugdir.BugDir(store, from_storage=True) - self.repository_name = self.bug_root.split('/')[-1] - self.env = Environment(loader=FileSystemLoader(template_root)) - self.env.filters['datetimeformat'] = datetimeformat - - def get_common_information(self): - """Returns a dict of common information that most pages will need.""" - possible_assignees = list(set( - [unicode(bug.assigned) for bug in self.bd if bug.assigned != EMPTY])) - possible_assignees.sort(key=unicode.lower) - - possible_targets = list(set( - [unicode(bug.summary.rstrip("\n")) for bug in self.bd \ - if bug.severity == u"target"])) - - possible_targets.sort(key=unicode.lower) - - possible_statuses = [u'open', u'assigned', u'test', u'unconfirmed', - u'closed', u'disabled', u'fixed', u'wontfix'] - - possible_severities = [u'minor', u'serious', u'critical', u'fatal', - u'wishlist'] - - return {'possible_assignees': possible_assignees, - 'possible_targets': possible_targets, - 'possible_statuses': possible_statuses, - 'possible_severities': possible_severities, - 'tags': libbe.command.tag.get_all_tags(self.bd), - 'repository_name': self.repository_name,} - - def filter_bugs(self, status, assignee, target, tag): - """Filter the list of bugs to return only those desired.""" - bugs = [bug for bug in self.bd if bug.status in status] - - if assignee != '': - assignee = None if assignee == 'None' else assignee - bugs = [bug for bug in bugs if bug.assigned == assignee] - - if tag != '' and tag != 'None': - bugs = [bug for bug in bugs - if tag in libbe.command.tag.get_tags(bug)] - - if target != '': - target = None if target == 'None' else target - if target == None: - # Return all bugs that don't block any targets. - return [bug for bug in bugs if not bug_target(self.bd, bug)] - else: - # Return all bugs that block the supplied target. - targetbug = bug_from_target_summary(self.bd, target) - if targetbug == None: - return [] - bugs = [bug for bug in get_blocked_by(self.bd, targetbug) if - bug.active] - - return bugs - - - @cherrypy.expose - def index(self, status='open', assignee='', target='', tag=''): - """The main bug page. - Bugs can be filtered by assignee or target. - The bug database will be reloaded on each visit.""" - - self.bd.load_all_bugs() - - if status == 'open': - status = ['open', 'assigned', 'test', 'unconfirmed', 'wishlist'] - label = 'All Open Bugs' - elif status == 'closed': - status = ['closed', 'disabled', 'fixed', 'wontfix'] - label = 'All Closed Bugs' - - if assignee != '': - label += ' Currently Unassigned' if assignee == 'None' \ - else ' Assigned to %s' % (assignee,) - if target != '': - label += ' Currently Unscheduled' if target == 'None' \ - else ' Scheduled for %s' % (target,) - if tag != '' and tag != 'None': - label += ' Tagged %s' % (tag,) - - bugs = self.filter_bugs(status, assignee, target, tag) - if len(bugs) == 0: - template = self.env.get_template('empty-list.html') - else: - template = self.env.get_template('list.html') - - common_info = self.get_common_information() - return template.render(bugs=bugs, bd=self.bd, label=label, - assignees=common_info['possible_assignees'], - targets=common_info['possible_targets'], - statuses=common_info['possible_statuses'], - severities=common_info['possible_severities'], - repository_name=common_info['repository_name'], - tags=common_info['tags'], - urlencode=urlencode) - - - @cherrypy.expose - def bug(self, id=''): - """The page for viewing a single bug.""" - - self.bd.load_all_bugs() - - bugdir, bug, comment = bugdir_bug_comment_from_user_id( - {self.bd.uuid: self.bd}, id) - - template = self.env.get_template('bug.html') - common_info = self.get_common_information() - - # Determine which targets a bug has. - # First, is this bug blocking any other bugs? - targets = '' - blocks = get_blocks(self.bd, bug) - for targetbug in blocks: - # Are any of those blocked bugs targets? - blocker = self.bd.bug_from_uuid(targetbug.uuid) - if blocker.severity == "target": - targets += "%s " % blocker.summary - - return template.render(bug=bug, bd=self.bd, - assignee='' if bug.assigned == EMPTY else bug.assigned, - target=targets, - assignees=common_info['possible_assignees'], - targets=common_info['possible_targets'], - statuses=common_info['possible_statuses'], - severities=common_info['possible_severities'], - repository_name=common_info['repository_name']) - - - @cherrypy.expose - def create(self, summary): - """The view that handles the creation of a new bug.""" - if summary.strip() != '': - self.bd.new_bug(summary=summary).save() - raise cherrypy.HTTPRedirect('/', status=302) - - - @cherrypy.expose - def comment(self, id, body): - """The view that handles adding a comment.""" - bug = self.bd.bug_from_uuid(id) - - if body.strip() != '': - bug.comment_root.new_reply(body=body) - bug.save() - - raise cherrypy.HTTPRedirect( - '/bug?%s' % urlencode({'id':bug.id.long_user()}), - status=302) - - @cherrypy.expose - def edit(self, id, status=None, target=None, assignee=None, severity=None, summary=None): - """The view that handles editing bug details.""" - bug = self.bd.bug_from_uuid(id) - - if summary != None: - bug.summary = summary - else: - bug.status = status if status != 'None' else None - bug.assigned = assignee if assignee != 'None' else None - bug.severity = severity if severity != 'None' else None - - if target: - current_target = bug_target(self.bd, bug) - if current_target: - remove_target(self.bd, bug) - if target != "None": - add_target(self.bd, bug, target) - else: - add_target(self.bd, bug, target) - - bug.save() - - raise cherrypy.HTTPRedirect( - '/bug?%s' % urlencode({'id':bug.id.long_user()}), - status=302) |