You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by ah...@apache.org on 2013/08/12 20:05:02 UTC
svn commit: r1513212 - in /bloodhound/branches/bep_0007_embeddable_objects:
./ bloodhound_dashboard/bhdashboard/layouts/templates/
bloodhound_dashboard/bhdashboard/widgets/ bloodhound_multiproduct/
bloodhound_multiproduct/multiproduct/ bloodhound_multi...
Author: ahorincar
Date: Mon Aug 12 18:05:01 2013
New Revision: 1513212
URL: http://svn.apache.org/r1513212
Log:
Merged trunk to bep_0007_embeddable_objects branch
Added:
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/ticket/batch.py
- copied unchanged from r1513209, bloodhound/trunk/bloodhound_multiproduct/multiproduct/ticket/batch.py
Modified:
bloodhound/branches/bep_0007_embeddable_objects/ (props changed)
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/layouts/templates/bs_btnbar_full.html
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/layouts/templates/bs_grid_full.html
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/widgets/query.py
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/widgets/ticket.py
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/env.py
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/hooks.py
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/ticket/query.py
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/setup.py
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/env.py
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/product-query-link-tests.txt
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/wikisyntax.py
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/templates/manage.html
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/tests/base.py
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/web_ui.py
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/htdocs/bloodhound.css
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_admin_plugins.html
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_milestone_view.html
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket.html
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket_box.html
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket_change.html
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_wiki_view.html
bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/theme.py
bloodhound/branches/bep_0007_embeddable_objects/installer/bloodhound_setup.py
bloodhound/branches/bep_0007_embeddable_objects/installer/requirements-dev.txt
bloodhound/branches/bep_0007_embeddable_objects/installer/requirements.txt
bloodhound/branches/bep_0007_embeddable_objects/trac/ (props changed)
bloodhound/branches/bep_0007_embeddable_objects/trac/trac/ticket/tests/query.py
Propchange: bloodhound/branches/bep_0007_embeddable_objects/
------------------------------------------------------------------------------
Merged /bloodhound/trunk:r1507815-1513209
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/layouts/templates/bs_btnbar_full.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/layouts/templates/bs_btnbar_full.html?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/layouts/templates/bs_btnbar_full.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/layouts/templates/bs_btnbar_full.html Mon Aug 12 18:05:01 2013
@@ -32,7 +32,7 @@
<xi:include href="bs_btnbar.html" />
<div id="ft" class="row">
<div id="help" class="span8">
- <strong>Note:</strong> See
+ <span class="label label-info">Note:</span> See
<a href="${href.wiki('BloodhoundDashboard')}">BloodhoundDashboard</a>
for help on using the dashboard.
</div>
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/layouts/templates/bs_grid_full.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/layouts/templates/bs_grid_full.html?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/layouts/templates/bs_grid_full.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/layouts/templates/bs_grid_full.html Mon Aug 12 18:05:01 2013
@@ -83,7 +83,7 @@
<xi:include href="bs_grid.html" />
<div id="ft" class="row">
<div id="help" class="span8">
- <strong>Note:</strong> See
+ <span class="label label-info">Note:</span> See
<a href="${href.wiki('BloodhoundDashboard')}">BloodhoundDashboard</a>
for help on using the dashboard.
</div>
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/widgets/query.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/widgets/query.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/widgets/query.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/widgets/query.py Mon Aug 12 18:05:01 2013
@@ -42,7 +42,6 @@ from bhdashboard.util import WidgetBase,
trac_tags
from multiproduct.env import ProductEnvironment
-from multiproduct.ticket.query import ProductQueryModule
class TicketQueryWidget(WidgetBase):
"""Display tickets matching a TracQuery using a grid
@@ -94,12 +93,11 @@ class TicketQueryWidget(WidgetBase):
more_link_href = req.href('query', args)
args.update({'page' : page, 'max': maxrows})
- qrymdl = self.env[QueryModule
- if isinstance(self.env, ProductEnvironment)
- else ProductQueryModule]
+ qrymdl = self.env[QueryModule]
if qrymdl is None :
raise TracError('Query module not available (disabled?)')
- data = qrymdl.process_request(fakereq)[1]
+
+ data = qrymdl.process_request(fakereq, self.env)[1]
except TracError, exc:
if data is not None:
exc.title = data.get('title', 'TracQuery')
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/widgets/ticket.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/widgets/ticket.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/widgets/ticket.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_dashboard/bhdashboard/widgets/ticket.py Mon Aug 12 18:05:01 2013
@@ -34,6 +34,7 @@ from trac.ticket.api import TicketSystem
from trac.ticket.query import Query
from trac.ticket.roadmap import apply_ticket_permissions, get_ticket_stats, \
ITicketGroupStatsProvider, RoadmapModule
+from trac.util.text import unicode_urlencode
from trac.util.translation import _
from trac.web.chrome import add_stylesheet
@@ -217,7 +218,7 @@ class TicketFieldValuesWidget(WidgetBase
query_href = query.get_href(req.href)
item_link= lambda item: query_href + \
- '&' + urlencode([(fieldnm, item[0])])
+ '&' + unicode_urlencode([(fieldnm, item[0])])
if fieldnm in self.DASH_ITEM_HREF_MAP:
def dash_item_link(item):
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/env.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/env.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/env.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/env.py Mon Aug 12 18:05:01 2013
@@ -1,3 +1,5 @@
+# -*- coding: UTF-8 -*-
+#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -47,10 +49,12 @@ class ComponentEnvironmentContext(object
def __init__(self, env, component):
self._env = env
self._component = component
+
def __enter__(self):
self._old_env = self._component.env
self._env.component_activated(self._component)
return self
+
def __exit__(self, type, value, traceback):
self._old_env.component_activated(self._component)
@@ -262,6 +266,7 @@ class Environment(trac.env.Environment):
# replace trac.env.Environment with Environment
trac.env.Environment = Environment
+
# this must follow the monkey patch (trac.env.Environment) above, otherwise
# trac.test.EnvironmentStub will not be correct as the class will derive from
# not replaced trac.env.Environment
@@ -333,6 +338,7 @@ class EnvironmentStub(trac.test.Environm
# replace trac.test.EnvironmentStub
trac.test.EnvironmentStub = EnvironmentStub
+
class ProductEnvironment(Component, ComponentManager):
"""Bloodhound product-aware environment manager.
@@ -342,7 +348,7 @@ class ProductEnvironment(Component, Comp
Product environments contain among other things:
- * configuration key-value pairs stored in the database,
+ * configuration key-value pairs stored in the database,
* product-aware clones of the wiki and ticket attachments files,
Product environments do not have:
@@ -536,7 +542,6 @@ class ProductEnvironment(Component, Comp
self.parent = env
self.product = product
self.systeminfo = []
- self._href = self._abs_href = None
self.setup_config()
@@ -852,44 +857,45 @@ class ProductEnvironment(Component, Comp
@lazy
def href(self):
"""The application root path"""
- if not self._href:
- self._href = Href(urlsplit(self.abs_href.base)[2])
- return self._href
+ return Href(urlsplit(self.abs_href.base).path)
@lazy
def abs_href(self):
"""The application URL"""
- if not self._abs_href:
- if not self.base_url:
- urlpattern = MultiProductSystem(self.parent).product_base_url
- if not urlpattern:
- self.log.warn("product_base_url option not set in "
- "configuration, generated links may be "
- "incorrect")
- urlpattern = 'products/$(prefix)s'
- envname = os.path.basename(self.parent.path)
- prefix = unicode_quote(self.product.prefix, safe="")
- name = unicode_quote(self.product.name, safe="")
- url = urlpattern.replace('$(', '%(') \
- .replace('%(envname)s', envname) \
- .replace('%(prefix)s', prefix) \
- .replace('%(name)s', name)
- if urlsplit(url).netloc:
- # Absolute URLs
- self._abs_href = Href(url)
- else:
- # Relative URLs
- parent_href = Href(self.parent.abs_href(),
- path_safe="/!~*'()%",
- query_safe="!~*'()%")
- self._abs_href = Href(parent_href(url))
+ if not self.base_url:
+ urlpattern = MultiProductSystem(self.parent).product_base_url
+ if not urlpattern:
+ self.log.warn("product_base_url option not set in "
+ "configuration, generated links may be "
+ "incorrect")
+ urlpattern = 'products/$(prefix)s'
+ envname = os.path.basename(self.parent.path)
+ prefix = unicode_quote(self.product.prefix, safe="")
+ name = unicode_quote(self.product.name, safe="")
+ url = urlpattern.replace('$(', '%(') \
+ .replace('%(envname)s', envname) \
+ .replace('%(prefix)s', prefix) \
+ .replace('%(name)s', name)
+ if urlsplit(url).netloc:
+ # Absolute URLs
+ _abs_href = Href(url)
else:
- self._abs_href = Href(self.base_url)
- return self._abs_href
+ # Relative URLs
+ parent_href = Href(self.parent.abs_href(),
+ path_safe="/!~*'()%",
+ query_safe="!~*'()%")
+ _abs_href = Href(parent_href(url))
+ else:
+ _abs_href = Href(self.base_url)
+ return _abs_href
# Multi-product API extensions
@classmethod
+ def lookup_global_env(cls, env):
+ return env.parent if isinstance(env, ProductEnvironment) else env
+
+ @classmethod
def lookup_env(cls, env, prefix=None, name=None):
"""Instantiate environment according to product prefix or name
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/hooks.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/hooks.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/hooks.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/hooks.py Mon Aug 12 18:05:01 2013
@@ -20,6 +20,8 @@
import multiproduct.env
import multiproduct.dbcursor
import multiproduct.versioncontrol
+import multiproduct.ticket.query
+import multiproduct.ticket.batch
import re
@@ -31,13 +33,15 @@ from trac.web.main import RequestWithSes
PRODUCT_RE = re.compile(r'^/products(?:/(?P<pid>[^/]*)(?P<pathinfo>.*))?')
REDIRECT_DEFAULT_RE = \
- re.compile(r'^/(?P<section>milestone|roadmap|query|report|newticket|'
+ re.compile(r'^/(?P<section>milestone|roadmap|report|newticket|'
r'ticket|qct|timeline|diff|batchmodify|search|'
r'(raw-|zip-)?attachment/(ticket|milestone))(?P<pathinfo>.*)')
class MultiProductEnvironmentFactory(EnvironmentFactoryBase):
def open_environment(self, environ, env_path, global_env, use_cache=False):
+ environ.setdefault('SCRIPT_NAME', '') # bh:ticket:594
+
env = pid = None
path_info = environ.get('PATH_INFO')
if not path_info:
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/ticket/query.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/ticket/query.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/ticket/query.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/multiproduct/ticket/query.py Mon Aug 12 18:05:01 2013
@@ -20,6 +20,8 @@
from __future__ import with_statement
+import re
+
from itertools import groupby
from math import ceil
from datetime import datetime, timedelta
@@ -52,6 +54,9 @@ class ProductQuery(Query):
"""
def _count(self, sql, args):
+ if isinstance(self.env, ProductEnvironment):
+ return super(ProductQuery, self)._count(sql, args)
+
cnt = self.env.db_direct_query("SELECT COUNT(*) FROM (%s) AS x"
% sql, args)[0][0]
# "AS x" is needed for MySQL ("Subqueries in the FROM Clause")
@@ -79,6 +84,10 @@ class ProductQuery(Query):
:since 1.0: the `db` parameter is no longer needed and will be removed
in version 1.1.1
"""
+ if isinstance(self.env, ProductEnvironment):
+ return super(ProductQuery, self).execute(req, db, cached_ids, authname,
+ tzinfo, href, locale)
+
if req is not None:
href = req.href
with self.env.db_direct_query as db:
@@ -142,184 +151,68 @@ class ProductQuery(Query):
cursor.close()
return results
+import trac.ticket.query
+trac.ticket.query.Query = ProductQuery
+trac.ticket.Query = ProductQuery
-class ProductQueryModule(QueryModule):
- def process_request(self, req):
- req.perm.assert_permission('TICKET_VIEW')
-
- constraints = self._get_constraints(req)
- args = req.args
- if not constraints and not 'order' in req.args:
- # If no constraints are given in the URL, use the default ones.
- if req.authname and req.authname != 'anonymous':
- qstring = self.default_query
- user = req.authname
- else:
- email = req.session.get('email')
- name = req.session.get('name')
- qstring = self.default_anonymous_query
- user = email or name or None
-
- self.log.debug('QueryModule: Using default query: %s', str(qstring))
- if qstring.startswith('?'):
- arg_list = parse_arg_list(qstring[1:])
- args = arg_list_to_args(arg_list)
- constraints = self._get_constraints(arg_list=arg_list)
- else:
- query = ProductQuery.from_string(self.env, qstring)
- args = {'order': query.order, 'group': query.group,
- 'col': query.cols, 'max': query.max}
- if query.desc:
- args['desc'] = '1'
- if query.groupdesc:
- args['groupdesc'] = '1'
- constraints = query.constraints
-
- # Substitute $USER, or ensure no field constraints that depend
- # on $USER are used if we have no username.
- for clause in constraints:
- for field, vals in clause.items():
- for (i, val) in enumerate(vals):
- if user:
- vals[i] = val.replace('$USER', user)
- elif val.endswith('$USER'):
- del clause[field]
- break
-
- cols = args.get('col')
- if isinstance(cols, basestring):
- cols = [cols]
- # Since we don't show 'id' as an option to the user,
- # we need to re-insert it here.
- if cols and 'id' not in cols:
- cols.insert(0, 'id')
- rows = args.get('row', [])
- if isinstance(rows, basestring):
- rows = [rows]
- format = req.args.get('format')
- max = args.get('max')
- if max is None and format in ('csv', 'tab'):
- max = 0 # unlimited unless specified explicitly
- query = ProductQuery(self.env, req.args.get('report'),
- constraints, cols, args.get('order'),
- 'desc' in args, args.get('group'),
- 'groupdesc' in args, 'verbose' in args,
- rows,
- args.get('page'),
- max)
-
- if 'update' in req.args:
- # Reset session vars
- for var in ('query_constraints', 'query_time', 'query_tickets'):
- if var in req.session:
- del req.session[var]
- req.redirect(query.get_href(req.href))
-
- # Add registered converters
- for conversion in Mimeview(self.env).get_supported_conversions(
- 'trac.ticket.Query'):
- add_link(req, 'alternate',
- query.get_href(req.href, format=conversion[0]),
- conversion[1], conversion[4], conversion[0])
-
- if format:
- filename = 'query' if format != 'rss' else None
- Mimeview(self.env).send_converted(req, 'trac.ticket.Query', query,
- format, filename=filename)
-
- return self.display_html(req, query)
-
- def display_html(self, req, query):
- # The most recent query is stored in the user session;
- orig_list = None
- orig_time = datetime.now(utc)
- query_time = int(req.session.get('query_time', 0))
- query_time = datetime.fromtimestamp(query_time, utc)
- query_constraints = unicode(query.constraints)
- try:
- if query_constraints != req.session.get('query_constraints') \
- or query_time < orig_time - timedelta(hours=1):
- tickets = query.execute(req)
- # New or outdated query, (re-)initialize session vars
- req.session['query_constraints'] = query_constraints
- req.session['query_tickets'] = ' '.join([str(t['id'])
- for t in tickets])
- else:
- orig_list = [int(id) for id
- in req.session.get('query_tickets', '').split()]
- tickets = query.execute(req, cached_ids=orig_list)
- orig_time = query_time
- except QueryValueError, e:
- tickets = []
- for error in e.errors:
- add_warning(req, error)
-
- context = web_context(req, 'query')
- owner_field = [f for f in query.fields if f['name'] == 'owner']
- if owner_field:
- TicketSystem(self.env).eventually_restrict_owner(owner_field[0])
- data = query.template_data(context, tickets, orig_list, orig_time, req)
-
- req.session['query_href'] = query.get_href(context.href)
- req.session['query_time'] = to_timestamp(orig_time)
- req.session['query_tickets'] = ' '.join([str(t['id'])
- for t in tickets])
- title = _('Custom Query')
-
- # Only interact with the report module if it is actually enabled.
- #
- # Note that with saved custom queries, there will be some convergence
- # between the report module and the query module.
- from trac.ticket.report import ReportModule
- if 'REPORT_VIEW' in req.perm and \
- self.env.is_component_enabled(ReportModule):
- data['report_href'] = req.href.report()
- add_ctxtnav(req, _('Available Reports'), req.href.report())
- add_ctxtnav(req, _('Custom Query'), req.href.query())
- if query.id:
- for title, description in self.env.db_query("""
- SELECT title, description FROM report WHERE id=%s
- """, (query.id,)):
- data['report_resource'] = Resource('report', query.id)
- data['description'] = description
- else:
- data['report_href'] = None
- # Only interact with the batch modify module it it is enabled
- # TODO: fix this for multiproduct
- """
- from trac.ticket.batch import BatchModifyModule
- if 'TICKET_BATCH_MODIFY' in req.perm and \
- self.env.is_component_enabled(BatchModifyModule):
- self.env[BatchModifyModule].add_template_data(req, data, tickets)
- """
-
- data.setdefault('report', None)
- data.setdefault('description', None)
- data['title'] = title
-
- data['all_columns'] = query.get_all_columns()
- # Don't allow the user to remove the id column
- data['all_columns'].remove('id')
- data['all_textareas'] = query.get_all_textareas()
-
- properties = dict((name, dict((key, field[key])
- for key in ('type', 'label', 'options',
- 'optgroups')
- if key in field))
- for name, field in data['fields'].iteritems())
- add_script_data(req, properties=properties, modes=data['modes'])
-
- add_stylesheet(req, 'common/css/report.css')
- Chrome(self.env).add_jquery_ui(req)
- add_script(req, 'common/js/query.js')
+class ProductQueryModule(QueryModule):
+ def process_request(self, req, env=None):
+ tmpenv = self.env
+ if isinstance(self.env, ProductEnvironment) and env is not None:
+ self.env = env
+ result = super(ProductQueryModule, self).process_request(req)
+ self.env = tmpenv
+ return result
- return 'query.html', data, None
+trac.ticket.query.QueryModule = ProductQueryModule
+trac.ticket.QueryModule = ProductQueryModule
class ProductTicketQueryMacro(TicketQueryMacro):
"""TracQuery macro retrieving results across product boundaries.
"""
+ @staticmethod
+ def parse_args(content):
+ """Parse macro arguments and translate them to a query string."""
+ clauses = [{}]
+ argv = []
+ kwargs = {}
+ for arg in TicketQueryMacro._comma_splitter.split(content):
+ arg = arg.replace(r'\,', ',')
+ m = re.match(r'\s*[^=]+=', arg)
+ if m:
+ kw = arg[:m.end() - 1].strip()
+ value = arg[m.end():]
+ if kw in ('order', 'max', 'format', 'col', 'product'):
+ kwargs[kw] = value
+ else:
+ clauses[-1][kw] = value
+ elif arg.strip() == 'or':
+ clauses.append({})
+ else:
+ argv.append(arg)
+ clauses = filter(None, clauses)
+
+ if len(argv) > 0 and not 'format' in kwargs: # 0.10 compatibility hack
+ kwargs['format'] = argv[0]
+ if 'order' not in kwargs:
+ kwargs['order'] = 'id'
+ if 'max' not in kwargs:
+ kwargs['max'] = '0' # unlimited by default
+
+ format = kwargs.pop('format', 'list').strip().lower()
+ if format in ('list', 'compact'): # we need 'status' and 'summary'
+ if 'col' in kwargs:
+ kwargs['col'] = 'status|summary|' + kwargs['col']
+ else:
+ kwargs['col'] = 'status|summary'
+
+ query_string = '&or&'.join('&'.join('%s=%s' % item
+ for item in clause.iteritems())
+ for clause in clauses)
+ return query_string, kwargs, format
+
def expand_macro(self, formatter, name, content):
req = formatter.req
query_string, kwargs, format = self.parse_args(content)
@@ -327,7 +220,9 @@ class ProductTicketQueryMacro(TicketQuer
query_string += '&'
query_string += '&'.join('%s=%s' % item
for item in kwargs.iteritems())
- query = ProductQuery.from_string(self.env, query_string)
+
+ env = ProductEnvironment.lookup_global_env(self.env)
+ query = ProductQuery.from_string(env, query_string)
if format == 'count':
cnt = query.count(req)
@@ -342,7 +237,7 @@ class ProductTicketQueryMacro(TicketQuer
add_stylesheet(req, 'common/css/report.css')
- return Chrome(self.env).render_template(
+ return Chrome(env).render_template(
req, 'query_results.html', data, None, fragment=True)
if format == 'progress':
@@ -354,7 +249,7 @@ class ProductTicketQueryMacro(TicketQuer
add_stylesheet(req, 'common/css/roadmap.css')
def query_href(extra_args, group_value = None):
- q = Query.from_string(self.env, query_string)
+ q = ProductQuery.from_string(env, query_string)
if q.group:
extra_args[q.group] = group_value
q.group = None
@@ -363,9 +258,9 @@ class ProductTicketQueryMacro(TicketQuer
if not q.constraints:
q.constraints.append(extra_args)
return q.get_href(formatter.context)
- chrome = Chrome(self.env)
- tickets = apply_ticket_permissions(self.env, req, tickets)
- stats_provider = RoadmapModule(self.env).stats_provider
+ chrome = Chrome(env)
+ tickets = apply_ticket_permissions(env, req, tickets)
+ stats_provider = RoadmapModule(env).stats_provider
by = query.group
if not by:
stat = get_ticket_stats(stats_provider, tickets)
@@ -393,7 +288,7 @@ class ProductTicketQueryMacro(TicketQuer
'legend': False,
}
- groups = grouped_stats_data(self.env, stats_provider, tickets, by,
+ groups = grouped_stats_data(env, stats_provider, tickets, by,
per_group_stats_data)
data = {
'groups': groups, 'grouped_by': by,
@@ -438,7 +333,7 @@ class ProductTicketQueryMacro(TicketQuer
def ticket_groups():
groups = []
for v, g in groupby(tickets, lambda t: t[query.group]):
- q = Query.from_string(self.env, query_string)
+ q = ProductQuery.from_string(env, query_string)
# produce the hint for the group
q.group = q.groupdesc = None
order = q.order
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/setup.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/setup.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/setup.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/setup.py Mon Aug 12 18:05:01 2013
@@ -17,10 +17,22 @@
# under the License.
"""setup for multi product plugin"""
-import sys
+import sys, codecs
from pkg_resources import parse_version
from setuptools import setup
+
+# Force UTF-8 for stdout/err if --utf8 option is specified.
+# For some reason python doesn't obey LANG/LC_CTYPE settings
+# if output is not a terminal (e.g. pipes don't work).
+if __name__ == '__main__':
+ for ac,av in enumerate(sys.argv):
+ if av == '--utf8':
+ sys.stdout = codecs.getwriter('utf8')(sys.stdout)
+ sys.stderr = codecs.getwriter('utf8')(sys.stderr)
+ del sys.argv[ac]
+ break
+
setup(
name = 'BloodhoundMultiProduct',
version = '0.7.0',
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/env.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/env.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/env.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/env.py Mon Aug 12 18:05:01 2013
@@ -486,6 +486,18 @@ class ProductEnvApiTestCase(Multiproduct
# Unregister class C as its fake module might break something else.
ComponentMeta._components.remove(C)
+ def test_href_is_lazy(self):
+ href = self.product_env.href
+ self.assertIs(href, self.product_env.href)
+
+ def test_abs_href_is_lazy(self):
+ abs_href = self.product_env.abs_href
+ self.assertIs(abs_href, self.product_env.abs_href)
+
+ def test_path_is_lazy(self):
+ path = self.product_env.path
+ self.assertIs(path, self.product_env.path)
+
def test_path(self):
"""Testing env.path"""
self.assertEqual(self.product_env.path,
@@ -582,12 +594,15 @@ class ProductEnvHrefTestCase(Multiproduc
def test_href_subdomain(self):
"""Test product sub domain base URL
"""
+ self.assertEqual('/', self.product_env.href())
self.assertEqual('http://tp1.domain.tld', self.product_env.abs_href())
@product_base_url('/path/to/bloodhound/$(prefix)s')
def test_href_sibling_paths(self):
"""Test product base URL at sibling paths
"""
+ self.assertEqual('/trac.cgi/path/to/bloodhound/tp1',
+ self.product_env.href())
self.assertEqual('http://globalenv.com/trac.cgi/path/to/bloodhound/tp1',
self.product_env.abs_href())
@@ -595,6 +610,7 @@ class ProductEnvHrefTestCase(Multiproduc
def test_href_inherit_sibling_paths(self):
"""Test product base URL at sibling paths inheriting configuration.
"""
+ self.assertEqual('/trac.cgi/env/tp1', self.product_env.href())
self.assertEqual('http://globalenv.com/trac.cgi/env/tp1',
self.product_env.abs_href())
@@ -602,6 +618,7 @@ class ProductEnvHrefTestCase(Multiproduc
def test_href_default(self):
"""Test product base URL is to a default
"""
+ self.assertEqual('/trac.cgi/products/tp1', self.product_env.href())
self.assertEqual('http://globalenv.com/trac.cgi/products/tp1',
self.product_env.abs_href())
@@ -609,6 +626,7 @@ class ProductEnvHrefTestCase(Multiproduc
def test_href_embed(self):
"""Test default product base URL /products/prefix
"""
+ self.assertEqual('/trac.cgi/products/tp1', self.product_env.href())
self.assertEqual('http://globalenv.com/trac.cgi/products/tp1',
self.product_env.abs_href())
@@ -616,6 +634,7 @@ class ProductEnvHrefTestCase(Multiproduc
def test_href_complex(self):
"""Test complex product base URL
"""
+ self.assertEqual('/bh/tp1', self.product_env.href())
self.assertEqual('http://env.tld/bh/tp1', self.product_env.abs_href())
@product_base_url('http://$(prefix)s.$(envname)s.tld/')
@@ -626,10 +645,12 @@ class ProductEnvHrefTestCase(Multiproduc
"""
# Global URLs
self.assertEqual('http://globalenv.com/trac.cgi', self.env.base_url)
+ self.assertEqual('/trac.cgi', self.env.href())
self.assertEqual('http://globalenv.com/trac.cgi', self.env.abs_href())
# Product URLs
self.assertEqual('', self.product_env.base_url)
+ self.assertEqual('/', self.product_env.href())
self.assertEqual('http://tp1.env.tld', self.product_env.abs_href())
@product_base_url('http://$(prefix)s.$(envname)s.tld/')
@@ -643,6 +664,7 @@ class ProductEnvHrefTestCase(Multiproduc
self.product_env.config.save()
self.assertEqual('http://productenv.com', self.product_env.base_url)
+ self.assertEqual('/', self.product_env.href())
self.assertEqual('http://productenv.com', self.product_env.abs_href())
@product_base_url('http://$(prefix)s.$(envname)s.tld/')
@@ -656,6 +678,7 @@ class ProductEnvHrefTestCase(Multiproduc
self.product_env.config.save()
self.assertEqual('', self.product_env.base_url)
+ self.assertEqual('/', self.product_env.href())
self.assertEqual('http://tp1.env.tld', self.product_env.abs_href())
product_base_url = staticmethod(product_base_url)
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/product-query-link-tests.txt
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/product-query-link-tests.txt?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/product-query-link-tests.txt (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/product-query-link-tests.txt Mon Aug 12 18:05:01 2013
@@ -52,7 +52,7 @@
============================== %(tc_title_prefix)s - ProductTicketQuery macro: no results, list form
Reopened tickets: [[ProductTicketQuery(status=reopened)]]
-Reopened tickets: [[ProductTicketQuery(status=reopened, product=%(setup_product_name)s)]]
+Reopened tickets: [[ProductTicketQuery(status=reopened, product=%(setup_product)s)]]
------------------------------
<p>
Reopened tickets: <span class="query_no_results">No results</span>
@@ -64,19 +64,19 @@ Reopened tickets: <span class="query_no_
============================== %(tc_title_prefix)s - ProductTicketQuery macro: no results, count 0
Reopened tickets: [[ProductTicketQuery(status=reopened, format=count)]]
-Reopened tickets: [[ProductTicketQuery(status=reopened, format=count, product=%(setup_product_name)s)]]
+Reopened tickets: [[ProductTicketQuery(status=reopened, format=count, product=%(setup_product)s)]]
------------------------------
<p>
Reopened tickets: <span class="query_count" title="0 tickets for which status=reopened&max=0&order=id">0</span>
</p>
<p>
-Reopened tickets: <span class="query_count" title="0 tickets for which status=reopened&product=%(setup_product_name)s&max=0&order=id">0</span>
+Reopened tickets: <span class="query_count" title="0 tickets for which status=reopened&max=0&product=%(setup_product)s&order=id">0</span>
</p>
------------------------------
============================== %(tc_title_prefix)s - ProductTicketQuery macro: no results, compact form
Reopened tickets: [[ProductTicketQuery(status=reopened, format=compact)]]
-Reopened tickets: [[ProductTicketQuery(status=reopened, format=compact, product=%(setup_product_name)s)]]
+Reopened tickets: [[ProductTicketQuery(status=reopened, format=compact, product=%(setup_product)s)]]
------------------------------
<p>
Reopened tickets: <span class="query_no_results">No results</span>
@@ -88,7 +88,7 @@ Reopened tickets: <span class="query_no_
============================== %(tc_title_prefix)s - ProductTicketQuery macro: one result, list form
New tickets: [[ProductTicketQuery(status=new)]]
-New tickets: [[ProductTicketQuery(status=new, product=%(setup_product_name)s)]]
+New tickets: [[ProductTicketQuery(status=new, product=%(setup_product)s)]]
------------------------------
<p>
New tickets: </p><div><dl class="wiki compact"><dt><a class="new" href="%(path_prefix)s/ticket/1" title="This is the summary">#1</a></dt><dd>This is the summary</dd></dl></div><p>
@@ -100,19 +100,19 @@ New tickets: </p><div><dl class="wiki co
============================== %(tc_title_prefix)s - ProductTicketQuery macro: one result, count 1
New tickets: [[ProductTicketQuery(status=new, format=count)]]
-New tickets: [[ProductTicketQuery(status=new, format=count, product=%(setup_product_name)s)]]
+New tickets: [[ProductTicketQuery(status=new, format=count, product=%(setup_product)s)]]
------------------------------
<p>
New tickets: <span class="query_count" title="1 tickets for which status=new&max=0&order=id">1</span>
</p>
<p>
-New tickets: <span class="query_count" title="1 tickets for which status=new&product=%(setup_product_name)s&max=0&order=id">1</span>
+New tickets: <span class="query_count" title="1 tickets for which status=new&max=0&product=%(setup_product)s&order=id">1</span>
</p>
------------------------------
============================== %(tc_title_prefix)s - ProductTicketQuery macro: one result, compact form
New tickets: [[ProductTicketQuery(status=new, format=compact)]]
-New tickets: [[ProductTicketQuery(status=new, format=compact, product=%(setup_product_name)s)]]
+New tickets: [[ProductTicketQuery(status=new, format=compact, product=%(setup_product)s)]]
------------------------------
<p>
New tickets: <span><a class="new" href="%(path_prefix)s/ticket/1" title="This is the summary">#1</a></span>
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/wikisyntax.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/wikisyntax.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/wikisyntax.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_multiproduct/tests/wikisyntax.py Mon Aug 12 18:05:01 2013
@@ -65,7 +65,7 @@ def ticket_setup(tc):
'status': 'new'})
# FIXME : UGLY ! Should not be explicit for product environments
- ticket['product'] = (tc.env.product.name
+ ticket['product'] = (tc.env.product.prefix
if isinstance(tc.env, ProductEnvironment)
else '')
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/templates/manage.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/templates/manage.html?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/templates/manage.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/templates/manage.html Mon Aug 12 18:05:01 2013
@@ -47,27 +47,27 @@
<form id="addrelation" class="well form-horizontal" method="post" action="">
<fieldset>
- <legend>Add relation:</legend>
+ <legend>Add relation</legend>
</fieldset>
<div class="control-group">
- <label class="control-label" for="dest_tid">Related ticket:</label>
+ <label class="control-label" for="reltype">This ticket</label>
<div class="controls">
- <input type="text" id="dest_tid" class="span4" name="dest_tid" value="$relation.destination" />
+ <select class="span4" id="reltype" name="reltype">
+ <option py:for="reltype,label in reltypes" value="$reltype" selected="${True if reltype == relation.type else None}">$label</option>
+ </select>
</div>
</div>
<div class="control-group">
- <label class="control-label" for="reltype">Relation type:</label>
+ <label class="control-label" for="dest_tid">Related ticket</label>
<div class="controls">
- <select class="span4" id="reltype" name="reltype">
- <option py:for="reltype,label in reltypes.iteritems()" value="$reltype" selected="${True if reltype == relation.type else None}">$label</option>
- </select>
+ <input type="text" id="dest_tid" class="span4" name="dest_tid" value="$relation.destination" />
</div>
</div>
<div class="control-group">
- <label class="control-label" for="comment">Comment:</label>
+ <label class="control-label" for="comment">Comment</label>
<div class="controls">
<textarea name="comment" rows="3" class="span4">${relation.comment}</textarea>
</div>
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/tests/base.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/tests/base.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/tests/base.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/tests/base.py Mon Aug 12 18:05:01 2013
@@ -59,8 +59,8 @@ class BaseRelationsTestCase(Multiproduct
env.config.set(config_name, 'oneway', 'refersto')
env.config.set(config_name, 'duplicate', 'duplicateof,duplicatedby')
env.config.set(config_name, 'duplicate.validators', 'ReferencesOlder')
- env.config.set(config_name, 'duplicateof.label', 'Duplicate of')
- env.config.set(config_name, 'duplicatedby.label', 'Duplicated by')
+ env.config.set(config_name, 'duplicateof.label', 'is a duplicate of')
+ env.config.set(config_name, 'duplicatedby.label', 'duplicates')
env.config.set(config_name, 'blocker', 'blockedby,blocks')
env.config.set(config_name, 'blockedby.blocks', 'true')
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/web_ui.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/web_ui.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/web_ui.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_relations/bhrelations/web_ui.py Mon Aug 12 18:05:01 2013
@@ -111,7 +111,8 @@ class RelationManagementModule(Component
data.update({
'ticket': ticket,
- 'reltypes': relsys.get_relation_types(),
+ 'reltypes': sorted(relsys.get_relation_types().iteritems(),
+ key=lambda x: x[0]),
'relations': self.get_ticket_relations(ticket),
})
return 'manage.html', data, None
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/htdocs/bloodhound.css
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/htdocs/bloodhound.css?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/htdocs/bloodhound.css (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/htdocs/bloodhound.css Mon Aug 12 18:05:01 2013
@@ -221,6 +221,10 @@ div.reports h2 {
/* @group Wiki */
+div.trac-content {
+ padding: 19px;
+}
+
.wiki-toc {
float: right;
margin-left: 25px;
@@ -388,6 +392,10 @@ h1, h2, h3, h4 {
margin: 0.5em;
}
+#content textarea, .popover-content textarea {
+ font-family: monospace;
+}
+
/* copied from bootstrap for appropriate focus/unfocused state for contenteditable*/
[contenteditable="true"] {
border-radius: 4px 4px 4px 4px;
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_admin_plugins.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_admin_plugins.html?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_admin_plugins.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_admin_plugins.html Mon Aug 12 18:05:01 2013
@@ -136,7 +136,7 @@
<i class="icon-tag"></i>
<span class="label">${module_name}.*</span>
<span py:if="module.summary" class="help-inline">
- — ${module.summary}
+ — ${wiki_to_oneliner(context, module.summary)}
</span>
</td>
<td class="sel"></td>
@@ -149,7 +149,7 @@
</span>
<span py:if="component.summary" class="help-inline"
style="display: inline;">
- — ${component.summary}
+ — ${wiki_to_oneliner(context, component.summary)}
</span>
</td>
<td class="sel">
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_milestone_view.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_milestone_view.html?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_milestone_view.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_milestone_view.html Mon Aug 12 18:05:01 2013
@@ -51,20 +51,9 @@
</py:choose>
</py:def>
- <py:def function="milestone_owner()">
- <py:choose>
- <py:when test="milestone.owner">
- Assigned to
- <a href="${href.query(owner=milestone.owner, status='!closed',
- milestone=milestone.name, order='priority')}">${milestone.name}</a>
- </py:when>
- <py:otherwise> </py:otherwise>
- </py:choose>
- </py:def>
-
<py:def function="milestone_heading()">
<h1>Milestone ${milestone.name}</h1>
- <h6>${milestone_date()} ${milestone_owner()}</h6>
+ <h6>${milestone_date()}</h6>
</py:def>
<py:def function="milestone_buttons()">
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket.html?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket.html Mon Aug 12 18:05:01 2013
@@ -329,7 +329,17 @@
<h5 id="trac-ticket-title" py:choose="">
<py:when test="t.exists">
<a href="${href.ticket(t.id)}"
- i18n:msg="id">Ticket #${t.id}</a> -
+ i18n:msg="id">Ticket #${t.id}</a>
+ <small py:if="version is not None">
+ <py:choose test="">
+ <py:when test="version == 0">
+ <i18n:msg>at <a href="#comment:description" class="muted">Initial Version</a></i18n:msg>
+ </py:when>
+ <py:otherwise>
+ <i18n:msg params="version">at <a href="#comment:$version" class="muted">Version $version</a></i18n:msg>
+ </py:otherwise>
+ </py:choose>
+ </small> —
</py:when>
<py:otherwise>
New Ticket <small><span py:if="preview_mode and t.type" class="status">(${t.type})</span></small>
@@ -345,7 +355,8 @@
<span py:if="not t.exists" class="label label-warning">(ticket not yet created)</span>
</span>
</h5>
- <span id="inplace-edit-button" py:if="can_modify or can_edit or can_create" class="btn-toolbar" style="${'display: None;' if not t.exists else ''}">
+ <span id="inplace-edit-button" py:if="has_property_editor"
+ class="btn-toolbar" style="${'display: None;' if not t.exists else ''}">
<button id="inplace-edit" class="btn">
<i class="icon-edit"></i>
<span>${_('Modify Ticket')}</span>
@@ -406,7 +417,7 @@
</span>
</py:def>
- <div class="ticket">
+ <div id="content" class="ticket">
<div class="trac-topnav span2" py:if="has_property_editor">
<a href="#propertyform" title="Go to the ticket editor">Modify</a> ↓
</div>
@@ -433,14 +444,14 @@
${render_ticket_summary_details(ticket)}
</div>
- <div id="content">
+ <div>
<div id="belowStatus">
<!--! ticket details -->
<!--! main ticket info -->
<div class="properties">
<xi:include href="bh_ticket_box.html"
py:with="preview_mode = change_preview.fields if change_preview else False;
- colcount = 4 if bhdb else 6"/>
+ colcount = 4 if bhdb else 6"/>
</div>
<div id="dummy-vc-summary" style="display: none"></div>
@@ -481,7 +492,7 @@
</div>
</form>
- <div py:if="bhrelations and ticket.exists" class="relations">
+ <div py:if="bhrelations and ticket.exists and has_property_editor" class="relations">
<bh:widget urn="TicketRelations">
<bh:args>
<bh:arg name="tid">$ticket.id</bh:arg>
@@ -525,7 +536,7 @@
<!--! Add comment -->
<div id="trac-add-comment" class="field">
<div class="trac-nav">
- <a href="#content" title="View ticket fields and description">View</a> ↑
+ <a href="#belowStatus" title="View ticket fields and description">View</a> ↑
</div>
<div id="trac-edit-warning" class="warning system-message alert"
style="${'display: none' if start_time == ticket['changetime'] else None}"
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket_box.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket_box.html?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket_box.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket_box.html Mon Aug 12 18:05:01 2013
@@ -123,11 +123,10 @@ Arguments:
<!--! Quote the description (only for existing tickets) -->
<div class="pull-right">
- <form py:if="ticket.exists and ticket.description and can_append"
- id="addreply" method="get" action="#comment">
- <a href="?replyto=description#trac-add-comment" class="btn btn-mini"
- title="Reply, quoting this description" type="submit">Reply</a>
- </form>
+ <a py:if="ticket.exists and ticket.description and can_append"
+ id="addreply" class="btn btn-mini" type="submit"
+ href="?replyto=description#trac-add-comment"
+ title="Reply, quoting this description">Reply</a>
</div>
<div class="searchable" xml:space="preserve"
data-edit="${'inplace' if can_edit or can_create else None}"
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket_change.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket_change.html?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket_change.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_ticket_change.html Mon Aug 12 18:05:01 2013
@@ -84,7 +84,7 @@ Arguments:
action="${href.ticket(ticket.id) + '#comment:%d' % cnum}">
<div>
<textarea name="edited_comment" class="wikitext trac-resizable" rows="10" cols="78">
- ${edited_comment if edited_comment is not None else change.comment}</textarea>
+${edited_comment if edited_comment is not None else change.comment}</textarea>
<input type="hidden" name="cnum_edit" value="${cnum}"/>
</div>
<div class="btn-toolbar buttons">
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_wiki_view.html
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_wiki_view.html?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_wiki_view.html (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/templates/bh_wiki_view.html Mon Aug 12 18:05:01 2013
@@ -83,7 +83,7 @@
</span>
<span class="trac-print" i18n:msg="date">Last modified on ${format_datetime(page.time)}</span>
</div>
- <div id="wikipage" py:content="wiki_to_html(context, text)" />
+ <div id="wikipage" class="trac-content" py:content="wiki_to_html(context, text)" />
</py:when>
<py:otherwise>
<p i18n:msg="name">The page ${name_of(page.resource)} does not exist. You can create it here.</p>
Modified: bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/theme.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/theme.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/theme.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/bloodhound_theme/bhtheme/theme.py Mon Aug 12 18:05:01 2013
@@ -430,7 +430,8 @@ class BloodhoundTheme(ThemeBase):
def _add_products_general_breadcrumb(self, req, template, data,
content_type, is_active):
- data['resourcepath_template'] = 'bh_path_general.html'
+ if isinstance(req.perm.env, ProductEnvironment):
+ data['resourcepath_template'] = 'bh_path_general.html'
# INavigationContributor methods
Modified: bloodhound/branches/bep_0007_embeddable_objects/installer/bloodhound_setup.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/installer/bloodhound_setup.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/installer/bloodhound_setup.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/installer/bloodhound_setup.py Mon Aug 12 18:05:01 2013
@@ -97,22 +97,23 @@ BASE_CONFIG = {'components': {'bhtheme.*
'duplicateof',
},
'bhrelations_links': {
- 'children.label': 'Child',
+ 'children.label': 'is a child of',
'dependency': 'dependson,dependent',
'dependency.validators': 'NoCycles,SingleProduct',
'dependson.blocks': 'true',
- 'dependson.label': 'Depends on',
- 'dependent.label': 'Dependent',
+ 'dependson.label': 'depends on',
+ 'dependent.label': 'is a dependency of',
'oneway': 'refersto',
'parent_children': 'parent,children',
'parent.exclusive': 'true',
+ 'parent.label': 'is a parent of',
'parent_children.validators':
'OneToMany,SingleProduct,NoCycles',
- 'refersto.label': 'Refers to',
+ 'refersto.label': 'refers to',
'duplicate': 'duplicateof,duplicatedby',
'duplicate.validators': 'ReferencesOlder',
- 'duplicateof.label': 'Duplicate of',
- 'duplicatedby.label': 'Duplicated by',
+ 'duplicateof.label': 'is a duplicate of',
+ 'duplicatedby.label': 'is duplicated by',
},
}
Modified: bloodhound/branches/bep_0007_embeddable_objects/installer/requirements-dev.txt
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/installer/requirements-dev.txt?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/installer/requirements-dev.txt (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/installer/requirements-dev.txt Mon Aug 12 18:05:01 2013
@@ -18,8 +18,8 @@
Pygments
pytz
sqlparse==0.1.7
-Babel
-Genshi
+Babel==0.9.6
+Genshi==0.6.1
-e ../trac
TracAccountManager
-e ../bloodhound_multiproduct
Modified: bloodhound/branches/bep_0007_embeddable_objects/installer/requirements.txt
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/installer/requirements.txt?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/installer/requirements.txt (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/installer/requirements.txt Mon Aug 12 18:05:01 2013
@@ -18,8 +18,8 @@
Pygments
pytz
sqlparse==0.1.7
-Babel
-Genshi
+Babel==0.9.6
+Genshi==0.6.1
../trac
TracAccountManager
../bloodhound_multiproduct
Propchange: bloodhound/branches/bep_0007_embeddable_objects/trac/
------------------------------------------------------------------------------
Merged /bloodhound/trunk/trac:r1507815-1513209
Modified: bloodhound/branches/bep_0007_embeddable_objects/trac/trac/ticket/tests/query.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0007_embeddable_objects/trac/trac/ticket/tests/query.py?rev=1513212&r1=1513211&r2=1513212&view=diff
==============================================================================
--- bloodhound/branches/bep_0007_embeddable_objects/trac/trac/ticket/tests/query.py (original)
+++ bloodhound/branches/bep_0007_embeddable_objects/trac/trac/ticket/tests/query.py Mon Aug 12 18:05:01 2013
@@ -110,7 +110,7 @@ ORDER BY COALESCE(priority.value,'')=''
query = Query(self.env, order='version')
sql, args = query.get_sql()
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.version AS version,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.version AS version,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
LEFT OUTER JOIN version ON (version.name=version)
@@ -122,7 +122,7 @@ ORDER BY COALESCE(t.version,'')='',COALE
query = Query(self.env, order='version', desc=1)
sql, args = query.get_sql()
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.version AS version,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.version AS version,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
LEFT OUTER JOIN version ON (version.name=version)
@@ -134,7 +134,7 @@ ORDER BY COALESCE(t.version,'')='' DESC,
query = Query.from_string(self.env, 'milestone=milestone1', order='id')
sql, args = query.get_sql()
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.component AS component,t.time AS time,t.changetime AS changetime,t.milestone AS milestone,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.component AS component,t.time AS time,t.changetime AS changetime,t.milestone AS milestone,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
WHERE ((COALESCE(t.milestone,'')=%s))
@@ -146,7 +146,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""")
query = Query(self.env, order='id', group='milestone')
sql, args = query.get_sql()
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.component AS component,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.component AS component,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
LEFT OUTER JOIN milestone ON (milestone.name=milestone)
@@ -158,7 +158,7 @@ ORDER BY COALESCE(t.milestone,'')='',COA
query = Query(self.env, order='id', group='milestone', groupdesc=1)
sql, args = query.get_sql()
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.component AS component,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.component AS component,t.milestone AS milestone,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
LEFT OUTER JOIN milestone ON (milestone.name=milestone)
@@ -170,7 +170,7 @@ ORDER BY COALESCE(t.milestone,'')='' DES
query = Query(self.env, group='priority')
sql, args = query.get_sql()
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.milestone AS milestone,t.component AS component,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.owner AS owner,t.type AS type,t.status AS status,t.milestone AS milestone,t.component AS component,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
ORDER BY COALESCE(priority.value,'')='',%(cast_priority)s,t.id""" % {
@@ -182,7 +182,7 @@ ORDER BY COALESCE(priority.value,'')='',
query = Query.from_string(self.env, 'milestone!=milestone1', order='id')
sql, args = query.get_sql()
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.milestone AS milestone,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.milestone AS milestone,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
WHERE ((COALESCE(t.milestone,'')!=%s))
@@ -357,7 +357,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""")
query = Query.from_string(self.env, 'created=2008-08-01..2008-09-01', order='id')
sql, args = query.get_sql(self.req)
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
WHERE (((%(cast_time)s>=%%s AND %(cast_time)s<%%s)))
@@ -370,7 +370,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""" % {
query = Query.from_string(self.env, 'created!=2008-08-01..2008-09-01', order='id')
sql, args = query.get_sql(self.req)
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
WHERE ((NOT (%(cast_time)s>=%%s AND %(cast_time)s<%%s)))
@@ -383,7 +383,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""" % {
query = Query.from_string(self.env, 'created=2008-08-01..', order='id')
sql, args = query.get_sql(self.req)
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
WHERE ((%(cast_time)s>=%%s))
@@ -396,7 +396,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""" % {
query = Query.from_string(self.env, 'created=..2008-09-01', order='id')
sql, args = query.get_sql(self.req)
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.time AS time,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
WHERE ((%(cast_time)s<%%s))
@@ -409,7 +409,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""" % {
query = Query.from_string(self.env, 'modified=2008-08-01..2008-09-01', order='id')
sql, args = query.get_sql(self.req)
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.changetime AS changetime,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.changetime AS changetime,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
WHERE (((%(cast_changetime)s>=%%s AND %(cast_changetime)s<%%s)))
@@ -423,7 +423,7 @@ ORDER BY COALESCE(t.id,0)=0,t.id""" % {
order='id')
sql, args = query.get_sql()
self.assertEqualSQL(sql,
-"""SELECT t.id AS id,t.summary AS summary,t.keywords AS keywords,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
+"""SELECT t.product AS product,t.id AS id,t.summary AS summary,t.keywords AS keywords,t.owner AS owner,t.type AS type,t.status AS status,t.priority AS priority,t.time AS time,t.changetime AS changetime,priority.value AS priority_value
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
WHERE (((COALESCE(t.keywords,'') %(like)s AND COALESCE(t.keywords,'') NOT %(like)s AND COALESCE(t.keywords,'') %(like)s)))