On Mon, Jun 23, 2014 at 6:58 PM, Gary Martin <[email protected]> wrote: > Thanks for that Dammina! I'll try to get a proper look in a bit. Thanks Gary. > > I was just thinking that you should be able to get a quick win by > redirecting to a query page that displays the created tickets as, > presumably, that will inform you of the query you need to provide to the > TicketQuery widget for display. The thing is my initial plan was to render the created tickets in the same page replacing the empty table. But yes this might also be an easy method. May I think on it a bit more and let you know? > > Out of interest, how are you thinking of making sure you don't have any > false positives in the query at the moment? Gary I'm not really clear on what did you meant by "false positives in the query". Can you please clarify it a bit. > > Also, as an open question, do you envisage the ability to batch create > tickets from a page without requiring edit permissions for the page? Yes. Here the requirement for the edit permission is, I have appended the Batch Create button to the modifypage form in wiki view template. And to view that part of the template the users required to have the admin perm or modify perm or delete perm. But appending it to a different place in the template will solve this problem. And of course I'm going to change it later and do some modifications to the UI.
I thought it would be better to commit the basic changes before these optimizations so you'll be able to use it and give me a feedback. > > Cheers, > Gary > > > > On 23/06/14 12:50, Dammina Sahabandu wrote: >> >> Now the user can add any number of tickets at once(User need to have the >> permissions TICKET_BATCH_CREATE + WIKI_ADMIN/WIKI_DELETE). After logging >> in >> the component will display a text field and button (Batch Create) where >> the >> users can enter the number of tickets that they are going to create. Then >> the component will generate a empty table where the users can enter the >> relevant details of the tickets and create that batch of tickets. >> Currently >> after creating the tickets the component will redirect the users into a >> blank page. So now I'm working on that, to render the ticket table with >> the >> details of that created batch instead of the black page. >> >> >> On Mon, Jun 23, 2014 at 12:45 PM, <[email protected]> wrote: >> >>> Author: dammina >>> Date: Mon Jun 23 11:45:24 2014 >>> New Revision: 1604759 >>> >>> URL: http://svn.apache.org/r1604759 >>> Log: >>> User interaction capability added to the component >>> >>> Added: >>> >>> >>> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/batchcreate.js >>> (with props) >>> Modified: >>> >>> >>> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/theme.py >>> >>> Added: >>> >>> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/batchcreate.js >>> URL: >>> >>> http://svn.apache.org/viewvc/bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/batchcreate.js?rev=1604759&view=auto >>> >>> >>> ============================================================================== >>> --- >>> >>> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/batchcreate.js >>> (added) >>> +++ >>> >>> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/batchcreate.js >>> Mon Jun 23 11:45:24 2014 >>> @@ -0,0 +1,204 @@ >>> +function emptyTable(products,href,token) { >>> + var numOfRows = document.getElementById("numOfRows").value; >>> + form_token = token.split(";")[0].split("=")[1];//I'm not really >>> sure about this method >>> + if(numOfRows != "" && document.getElementById("empty-table") == >>> null){ >>> + var contentDiv = document.getElementById("content"); >>> + //var headers = >>> >>> {"summary":"Summary","description":"Description","product":"Product","status":"Status","priority":"Priority","type":"Types","owner":"Owner","cc":"Cc","milestone":"Milestone","keywords":"Keywords"} >>> + var headers = >>> >>> {"summary":"Summary","description":"Description","product":"Product","status":"Status","priority":"Priority"} >>> + statuses = ["accepted", "assigned", "closed", "new", "reopened"]; >>> + priorities = ["blocker", "critical", "major", "minor", >>> "trivial"]; >>> + types = ["defect", "enhancement", "task"]; >>> + >>> + var div = document.createElement("div"); >>> + div.setAttribute("class","span12"); >>> + div.setAttribute("id","empty-table"); >>> + var h2 = document.createElement("h2"); >>> + h2.appendChild(document.createTextNode("Batch Create Tickets")); >>> + div.appendChild(h2); >>> + >>> + var form = document.createElement("form"); >>> + form.setAttribute("id","bct-form"); >>> + form.setAttribute("name","bct"); >>> + form.setAttribute("method","post"); >>> + form.setAttribute("action",href); >>> + >>> + var div_token = document.createElement("div"); >>> + var form_token_val = document.createElement("input"); >>> + form_token_val.setAttribute("type","hidden"); >>> + form_token_val.setAttribute("name","__FORM_TOKEN"); >>> + form_token_val.setAttribute("value",form_token); >>> + div_token.appendChild(form_token_val); >>> + form.appendChild(div_token); >>> + >>> + var table = document.createElement("table"); >>> + table.setAttribute("class","listing tickets table table-bordered >>> table-condensed query"); >>> + table.setAttribute("style","border-radius: 0px 0px 4px 4px"); >>> + >>> + var tr = document.createElement("tr"); >>> + tr.setAttribute("class","trac-columns"); >>> + for (header in headers){ >>> + font = document.createElement("font"); >>> + font.setAttribute("color","#1975D1"); >>> + >>> font.appendChild(document.createTextNode(headers[header])) >>> + th = document.createElement("th"); >>> + th.appendChild(font); >>> + tr.appendChild(th); >>> + } >>> + table.appendChild(tr); >>> + >>> + tbody = document.createElement("tbody"); >>> + for (i=0;i<numOfRows;i++){ >>> + tr_rows = document.createElement("tr"); >>> + for (header in headers){ >>> + if (header == "summary"){ >>> + td_row = document.createElement("td"); >>> + input_summary = >>> document.createElement("input"); >>> + >>> input_summary.setAttribute("type","text"); >>> + >>> input_summary.setAttribute("id","field-summary"+i); >>> + >>> input_summary.setAttribute("class","input-block-level"); >>> + >>> input_summary.setAttribute("name","field_summary"+i); >>> + td_row.appendChild(input_summary); >>> + tr_rows.appendChild(td_row); >>> + } >>> + else if (header == "description") { >>> + td_row = document.createElement("td"); >>> + input_description = >>> document.createElement("textarea"); >>> + >>> input_description.setAttribute("id","field-description"+i); >>> + >>> input_description.setAttribute("class","input-block-level"); >>> + >>> input_description.setAttribute("name","field_description"+i); >>> + >>> input_description.setAttribute("rows","2"); >>> + >>> input_description.setAttribute("cols","28"); >>> + td_row.appendChild(input_description); >>> + tr_rows.appendChild(td_row); >>> + } >>> + else if (header == "status") { >>> + td_row = document.createElement("td"); >>> + input_status = >>> document.createElement("select"); >>> + >>> input_status.setAttribute("id","field-status"+i); >>> + >>> input_status.setAttribute("class","input-block-level"); >>> + >>> input_status.setAttribute("name","field_status"+i); >>> + for (status in statuses){ >>> + option = >>> document.createElement("option"); >>> + >>> option.setAttribute("value",statuses[status]); >>> + >>> option.appendChild(document.createTextNode(statuses[status])); >>> + input_status.appendChild(option); >>> + } >>> + td_row.appendChild(input_status); >>> + tr_rows.appendChild(td_row); >>> + } >>> + else if (header == "priority") { >>> + td_row = document.createElement("td"); >>> + input_priority = >>> document.createElement("select"); >>> + >>> input_priority.setAttribute("id","field-priority"+i); >>> + >>> input_priority.setAttribute("class","input-block-level"); >>> + >>> input_priority.setAttribute("name","field_priority"+i); >>> + for (priority in priorities){ >>> + option = >>> document.createElement("option"); >>> + >>> option.setAttribute("value",priorities[priority]); >>> + >>> option.appendChild(document.createTextNode(priorities[priority])); >>> + >>> input_priority.appendChild(option); >>> + } >>> + td_row.appendChild(input_priority); >>> + tr_rows.appendChild(td_row); >>> + } >>> + else if (header == "type") { >>> + td_row = document.createElement("td"); >>> + input_type = >>> document.createElement("select"); >>> + >>> input_type.setAttribute("id","field-type"+i); >>> + >>> input_type.setAttribute("class","input-block-level"); >>> + >>> input_type.setAttribute("name","field_type"+i); >>> + for (type in types){ >>> + option = >>> document.createElement("option"); >>> + >>> option.setAttribute("value",types[type]); >>> + >>> option.appendChild(document.createTextNode(types[type])); >>> + input_type.appendChild(option); >>> + } >>> + td_row.appendChild(input_type); >>> + tr_rows.appendChild(td_row); >>> + } >>> + else if (header == "product") { >>> + td_row = document.createElement("td"); >>> + field_product = >>> document.createElement("select"); >>> + >>> field_product.setAttribute("id","field-product"+i); >>> + >>> field_product.setAttribute("class","input-block-level"); >>> + >>> field_product.setAttribute("name","field_product"+i); >>> + for (product in products){ >>> + option = >>> document.createElement("option"); >>> + >>> option.setAttribute("value",(products[product])[0]); >>> + >>> option.appendChild(document.createTextNode((products[product])[1])); >>> + >>> field_product.appendChild(option); >>> + } >>> + td_row.appendChild(field_product); >>> + tr_rows.appendChild(td_row); >>> + } >>> + else if (header == "owner"){ >>> + td_row = document.createElement("td"); >>> + input_owner = >>> document.createElement("input"); >>> + input_owner.setAttribute("type","text"); >>> + >>> input_owner.setAttribute("id","field-owner"+i); >>> + >>> input_owner.setAttribute("class","input-block-level"); >>> + >>> input_owner.setAttribute("name","field_owner"+i); >>> + td_row.appendChild(input_owner); >>> + tr_rows.appendChild(td_row); >>> + } >>> + else if (header == "cc"){ >>> + td_row = document.createElement("td"); >>> + input_cc = >>> document.createElement("input"); >>> + input_cc.setAttribute("type","text"); >>> + input_cc.setAttribute("id","field-cc"+i); >>> + >>> input_cc.setAttribute("class","input-block-level"); >>> + >>> input_cc.setAttribute("name","field_cc"+i); >>> + td_row.appendChild(input_cc); >>> + tr_rows.appendChild(td_row); >>> + } >>> + else if (header == "milestone"){ >>> + td_row = document.createElement("td"); >>> + input_milestone = >>> document.createElement("input"); >>> + >>> input_milestone.setAttribute("type","text"); >>> + >>> input_milestone.setAttribute("id","field-milestone"+i); >>> + >>> input_milestone.setAttribute("class","input-block-level"); >>> + >>> input_milestone.setAttribute("name","field_milestone"+i); >>> + td_row.appendChild(input_milestone); >>> + tr_rows.appendChild(td_row); >>> + } >>> + else if (header == "keywords"){ >>> + td_row = document.createElement("td"); >>> + input_keywords = >>> document.createElement("input"); >>> + >>> input_keywords.setAttribute("type","text"); >>> + >>> input_keywords.setAttribute("id","field-keywords"+i); >>> + >>> input_keywords.setAttribute("class","input-block-level"); >>> + >>> input_keywords.setAttribute("name","field_keywords"+i); >>> + td_row.appendChild(input_keywords); >>> + tr_rows.appendChild(td_row); >>> + } >>> + } >>> + tbody.appendChild(tr_rows); >>> + } >>> + table.appendChild(tbody); >>> + form.appendChild(table); >>> + >>> + submit_button = document.createElement("button"); >>> + submit_button.setAttribute("class","btn pull-right"); >>> + submit_button.setAttribute("type","button"); >>> + submit_button.setAttribute("onclick","submitForm()"); >>> + submit_button.appendChild(document.createTextNode("save")); >>> + form.appendChild(submit_button); >>> + div.appendChild(form); >>> + contentDiv.appendChild(div); >>> + } >>> + >>> + //var rowCount = table.rows.length; >>> + //var row = table.insertRow(rowCount); >>> +} >>> + >>> +function submitForm(){ >>> + document.getElementById("bct-form").submit(); >>> +} >>> + >>> +//function deleteRow(obj) { >>> + >>> +// var index = obj.parentNode.parentNode.rowIndex; >>> +// var table = document.getElementById("myTableData"); >>> +// table.deleteRow(index); >>> + >>> +//} >>> >>> Propchange: >>> >>> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/htdocs/js/batchcreate.js >>> >>> >>> ------------------------------------------------------------------------------ >>> svn:eol-style = native >>> >>> Modified: >>> >>> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/theme.py >>> URL: >>> >>> http://svn.apache.org/viewvc/bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/theme.py?rev=1604759&r1=1604758&r2=1604759&view=diff >>> >>> >>> ============================================================================== >>> --- >>> >>> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/theme.py >>> (original) >>> +++ >>> >>> bloodhound/branches/bep_0011_batch_create_tickets/bloodhound_theme/bhtheme/theme.py >>> Mon Jun 23 11:45:24 2014 >>> @@ -800,6 +800,7 @@ class BatchCreateTicketDialog(Component) >>> 'url': get_resource_url(self.env, tres, >>> href)}), >>> 'application/json') >>> >>> + >>> def _get_ticket_module(self): >>> ptm = None >>> if ProductTicketModule is not None: >>> @@ -813,124 +814,29 @@ class BatchCreateTicketDialog(Component) >>> >>> #Template Stream Filter methods >>> def filter_stream(self, req, method, filename, stream, data): >>> - if (filename == 'bh_wiki_view.html') and >>> (req.perm.has_permission('TICKET_ADMIN') or >>> req.perm.has_permission('TICKET_BATCH_CREATE')): >>> - #(req.perm.has_permission('TICKET_ADMIN') or >>> req.perm.has_permission('TICKET_CREATE') >>> - #headers = >>> >>> {'summary':'Summary','description':'Description','product':'Product','status':'Status','priority':'Priority','type':'Type','owner':'Owner','cc':'Cc','keywords':'Keywords','milestone':'Milestone'} >>> - headers = >>> >>> {'summary':'Summary','description':'Description','product':'Product','status':'Status'} >>> + if (filename == 'bh_wiki_view.html') and >>> (req.perm.has_permission('TRAC_ADMIN') or >>> req.perm.has_permission('TICKET_BATCH_CREATE')): >>> + add_script(req,'theme/js/batchcreate.js') >>> + xpath = '//form[@id=modifypage]' >>> products = self.env.db_query("SELECT * FROM >>> bloodhound_product") >>> - xpath = '//div[@id="content"]' >>> - div = tag.div(class_="span12", >>> id="batch_create_empty_table") >>> - text = tag.text("Batch Create Tickets") >>> - h1 = tag.h1(text) >>> - div.append(h1) >>> - form = tag.form(id="qct-form", name="bct", method="post", >>> action=req.href()+"/bct") >>> - table = tag.table(class_="listing tickets table >>> table-bordered table-condensed query", style="border-radius: 0px 0px 4px >>> 4px") >>> - tr = tag.tr(class_="trac-columns") >>> - for header in sorted(headers): >>> - font = tag.font(color="#1975D1") >>> - text = tag.text(headers[header]) >>> - font.append(text) >>> - th = tag.th(font) >>> - tr.append(th) >>> - table.append(tr) >>> - tbody = tag.tbody() >>> - for num in range(0,5): >>> - tr_rows = tag.tr() >>> - for header in sorted(headers): >>> - if header == "summary": >>> - td_row = tag.td() >>> - input_summary = tag.input(type="text", id = >>> "field-summary"+str(num), class_="input-block-level", >>> name="field_summary"+str(num)) >>> - td_row.append(input_summary) >>> - tr_rows.append(td_row) >>> - elif header == "description": >>> - td_row = tag.td() >>> - input_description = tag.textarea(id = >>> "field-description"+str(num), name="field_description"+str(num), >>> class_="input-block-level", rows="1", cols="28") >>> - td_row.append(input_description) >>> - tr_rows.append(td_row) >>> - elif header == "status": >>> - statuses = ["accepted", "assigned", "closed", >>> "new", "reopened"] >>> - td_row = tag.td() >>> - input_status = tag.select(id = >>> "field-status"+str(num), name="field_status"+str(num)) >>> - for status in statuses: >>> - option = tag.option(value=str(status)) >>> - text = tag.text(str(status)) >>> - option.append(text) >>> - input_status.append(option) >>> - td_row.append(input_status) >>> - tr_rows.append(td_row) >>> - elif header == "priority": >>> - priorities = ["blocker", "critical", "major", >>> "minor", "trivial"] >>> - td_row = tag.td() >>> - input_priority = tag.select(id = >>> "field-priority"+str(num), name="field_priority"+str(num)) >>> - for priority in priorities: >>> - option = tag.option(value=str(priority)) >>> - text = tag.text(str(priority)) >>> - option.append(text) >>> - input_priority.append(option) >>> - td_row.append(input_priority) >>> - tr_rows.append(td_row) >>> - elif header=="type": >>> - types = ["defect", "enhancement", "task"] >>> - td_row = tag.td() >>> - input_type = tag.select(id = >>> "field-type"+str(num), name="field_type"+str(num)) >>> - for type in types: >>> - option = tag.option(value=str(type)) >>> - text = tag.text(str(type)) >>> - option.append(text) >>> - input_type.append(option) >>> - td_row.append(input_type) >>> - tr_rows.append(td_row) >>> - elif header == "product": >>> - td_row = tag.td() >>> - input_product = tag.select(id = >>> "field-product"+str(num), name="field_product"+str(num)) >>> - option = tag.option(value="") >>> - text = tag.text("Choose...") >>> - option.append(text) >>> - input_product.append(option) >>> - for product in products: >>> - option = tag.option(value=str(product[0])) >>> - text = tag.text(str(product[1])) >>> - option.append(text) >>> - input_product.append(option) >>> - td_row.append(input_product) >>> - tr_rows.append(td_row) >>> - elif header == "owner": >>> - td_row = tag.td() >>> - input_owner = tag.input(type="text", id = >>> "field-owner"+str(num), class_="input-block-level", >>> name="field_owner"+str(num)) >>> - td_row.append(input_owner) >>> - tr_rows.append(td_row) >>> - elif header == "cc": >>> - td_row = tag.td() >>> - input_cc = tag.input(type="text", id = >>> "field-cc"+str(num), class_="input-block-level", >>> name="field_cc"+str(num)) >>> - td_row.append(input_cc) >>> - tr_rows.append(td_row) >>> - elif header == "milestone": >>> - td_row = tag.td() >>> - input_cc = tag.input(type="text", id = >>> "field-milestone"+str(num), class_="input-block-level", >>> name="field_milestone"+str(num)) >>> - td_row.append(input_cc) >>> - tr_rows.append(td_row) >>> - elif header == "keywords": >>> - td_row = tag.td() >>> - input_cc = tag.input(type="text", id = >>> "field-keywords"+str(num), class_="input-block-level", >>> name="field_keywords"+str(num)) >>> - td_row.append(input_cc) >>> - tr_rows.append(td_row) >>> - tbody.append(tr_rows) >>> - table.append(tbody) >>> - form.append(table) >>> - div_button = tag.div(class_="btn-group pull-right") >>> - input_button = tag.input(type="submit", class_="btn >>> pull-right", name="save", value="save") >>> - div_button.append(input_button) >>> - form.append(div_button) >>> - div.append(form) >>> - div.append("\n") >>> - stream |= Transformer(xpath).append(div) >>> + form = tag.form(method="get", style="display:inline", >>> id="batchcreate") >>> + div = tag.div(class_="btn-group") >>> + span = tag.span(class_="input-group-btn") >>> + button = tag.button(class_="btn btn-default", type="button", >>> >>> onclick="Javascript:emptyTable("+to_json(products)+","+to_json(req.href()+"/bct")+","+to_json(str(req.environ["HTTP_COOKIE"]))+")") >>> + input = tag.input(id="numOfRows",type="text", >>> style="width:110px;", class_="form-control", placeholder="How many >>> tickets?") >>> + text = tag.text("Batch Create") >>> + button.append(text) >>> + span.append(button) >>> + span.append(input) >>> + div.append(span) >>> + form.append(div) >>> + stream |= Transformer(xpath).append(form) >>> return stream >>> >>> # Public API >>> def batch_create(self, req, attributes={}, notify=False): >>> """ Create batch of tickets, returning created tickets.4586. >>> >>> """ >>> - num_of_tkts = attributes.__len__()/4 >>> + num_of_tkts = attributes.__len__()/5 >>> for i in range(0,num_of_tkts): >>> if 'product'+str(i) in attributes: >>> env = self.env.parent or self.env >>> @@ -942,6 +848,7 @@ class BatchCreateTicketDialog(Component) >>> status = attributes.pop('status'+str(i)) >>> summary = attributes.pop('summary'+str(i)) >>> product = attributes.pop('product'+str(i)) >>> + priority = attributes.pop('priority'+str(i)) >>> >>> t = Ticket(env) >>> t['summary'] = summary >>> @@ -950,6 +857,7 @@ class BatchCreateTicketDialog(Component) >>> t['status'] = status >>> t['resolution'] = '' >>> t['product'] = product >>> + t['priority'] = priority >>> t.insert() >>> >>> if notify: >>> >>> >>> >> > -- Dammina Sahabandu. Committer for ASF (Apache Bloodhound) Undergraduate Department of Computer Science and Engineering University of Moratuwa Sri Lanka.
