diff --git a/module/bug/config.php b/module/bug/config.php index 82fa60c9ad..6e5ac647c1 100644 --- a/module/bug/config.php +++ b/module/bug/config.php @@ -1,5 +1,6 @@ bug = new stdClass(); +$config->bug->batchCreate = 10; $config->bug->create = new stdclass(); $config->bug->edit = new stdclass(); diff --git a/module/bug/control.php b/module/bug/control.php index 0c3f398b4c..8a7ab5672b 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -336,6 +336,56 @@ class bug extends control $this->display(); } + /** + * Batch create. + * + * @param int $productID + * @param int $projectID + * @param int $moduleID + * @access public + * @return void + */ + public function batchCreate($productID, $projectID = 0, $moduleID = 0) + { + if(!empty($_POST)) + { + $actions = $this->bug->batchCreate($productID); + foreach($actions as $bugID => $action) $this->sendmail($bugID, $actionID); + die(js::locate($this->session->bugList, 'parent')); + } + + /* Get product, then set menu. */ + $productID = $this->product->saveState($productID, $this->products); + $this->bug->setMenu($this->products, $productID); + + /* If projectID is setted, get builds and stories of this project. */ + if($projectID) + { + $builds = $this->loadModel('build')->getProjectBuildPairs($projectID, $productID, 'noempty'); + $stories = $this->story->getProjectStoryPairs($projectID); + } + else + { + $builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty'); + $stories = $this->story->getProductStoryPairs($productID); + } + + $this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->batchCreate; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->batchCreate; + + $this->view->projectBuilds = $projectBuilds; + $this->view->productID = $productID; + $this->view->stories = $stories; + $this->view->builds = $builds; + $this->view->users = $this->user->getPairs('nodeleted,devfirst'); + $this->view->projects = $this->product->getProjectPairs($productID, $params = 'nodeleted'); + $this->view->projectID = $projectID; + $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0); + $this->view->moduleID = $moduleID; + $this->display(); + } + /** * View a bug. * diff --git a/module/bug/css/batchcreate.css b/module/bug/css/batchcreate.css new file mode 100644 index 0000000000..d9973e6914 --- /dev/null +++ b/module/bug/css/batchcreate.css @@ -0,0 +1,2 @@ +textarea {height:16px} +.w-220px {width:220px} diff --git a/module/bug/js/batchcreate.js b/module/bug/js/batchcreate.js new file mode 100644 index 0000000000..c58f7a11fd --- /dev/null +++ b/module/bug/js/batchcreate.js @@ -0,0 +1,37 @@ +$(function() +{ + $(".chosenBox select").chosen({no_results_text: noResultsMatch}); + $(".chzn-container-multi .chzn-choices li.search-field input").attr('value', chooseBuilds); +}) + +/** + * Load project builds + * + * @param int $productID + * @param int $projectID + * @param int $index + * @access public + * @return void + */ +function loadProjectBuilds(productID, projectID, index) +{ + if(projectID) + { + link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild'); + } + else + { + link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild'); + } + + $.get(link, function(builds) + { + $('#buildBox' + index).html(builds); + $('#openedBuilds' + index + '_chzn').remove(); + $('#buildBox' + index + ' select').removeClass('select-3'); + $('#buildBox' + index + ' select').addClass('select-1'); + $('#buildBox' + index + ' select').attr('id', 'openedBuilds[' + index + '][]'); + $('#buildBox' + index + ' select').chosen({no_results_text: ''}); + $('#buildBox' + index + ' .chzn-container-multi .chzn-choices li.search-field input').attr('value', chooseBuilds); + }); +} diff --git a/module/bug/lang/en.php b/module/bug/lang/en.php index dd6cc7fcd5..09506b40eb 100644 --- a/module/bug/lang/en.php +++ b/module/bug/lang/en.php @@ -69,6 +69,7 @@ $lang->bug->toCase = 'To case'; /* Actions. */ $lang->bug->index = 'Index'; $lang->bug->create = 'Create Bug'; +$lang->bug->batchCreate = 'Batch create'; $lang->bug->confirmBug = 'Confirm Bug'; $lang->bug->edit = 'Edit Bug'; $lang->bug->batchEdit = 'Batch edit'; @@ -357,5 +358,5 @@ $lang->bug->action->tostory = array('main' => '$date, To story by $acto $lang->bug->action->totask = array('main' => '$date, To task by $actor, ID is $extra.'); $lang->bug->placeholder = new stdclass(); -$lang->bug->placeholder->mailto = 'you can input the user account to select users to mail to.'; -$lang->bug->placeholder->keywords = 'keywords'; +$lang->bug->placeholder->mailto = 'you can input the user account to select users to mail to.'; +$lang->bug->placeholder->chooseBuilds = 'Choose builds...'; diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php index b4d033ff6f..d8055a9828 100644 --- a/module/bug/lang/zh-cn.php +++ b/module/bug/lang/zh-cn.php @@ -69,6 +69,7 @@ $lang->bug->toCase = '生成用例'; /* 方法列表。*/ $lang->bug->index = '首页'; $lang->bug->create = '提Bug'; +$lang->bug->batchCreate = '批量添加'; $lang->bug->confirmBug = '确认'; $lang->bug->edit = '编辑'; $lang->bug->batchEdit = '批量编辑'; @@ -357,4 +358,5 @@ $lang->bug->action->tostory = array('main' => '$date, 由 $actorbug->action->totask = array('main' => '$date, 由 $actor 导入为任务,编号为 $extra。'); $lang->bug->placeholder = new stdclass(); -$lang->bug->placeholder->mailto = '输入用户名自动选择'; +$lang->bug->placeholder->mailto = '输入用户名自动选择'; +$lang->bug->placeholder->chooseBuilds = '选择相关版本...'; diff --git a/module/bug/model.php b/module/bug/model.php index fc0efbb243..992c97c30b 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -63,6 +63,45 @@ class bugModel extends model return false; } + /** + * Batch create + * + * @param int $productID + * @access public + * @return void + */ + public function batchCreate($productID) + { + $this->loadModel('action'); + $now = helper::now(); + $data = fixer::input('post')->get(); + $actions = array(); + for($i = 0; $i < $this->config->bug->batchCreate; $i++) + { + if(empty($data->titles[$i])) continue; + $bug = new stdClass(); + $bug->openedBy = $this->app->user->account; + $bug->openedDate = $now; + $bug->product = $productID; + $bug->module = $data->modules[$i]; + $bug->project = $data->projects[$i]; + $bug->openedBuild = implode(',', $data->openedBuilds[$i]); + $bug->title = $data->titles[$i]; + $bug->steps = $data->stepses[$i]; + $bug->type = $data->types[$i]; + $bug->severity = $data->severities[$i]; + $bug->os = $data->oses[$i]; + $bug->browser = $data->browsers[$i]; + + $this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec(); + $bugID = $this->dao->lastInsertID(); + + if(dao::isError()) die(js::error('bug#' . ($i+1) . dao::getError(true))); + $actions[$bugID] = $this->action->create('bug', $bugID, 'Opened'); + } + return $actions; + } + /** * Get bugs of a module. * diff --git a/module/bug/view/batchcreate.html.php b/module/bug/view/batchcreate.html.php new file mode 100644 index 0000000000..4dd22e882e --- /dev/null +++ b/module/bug/view/batchcreate.html.php @@ -0,0 +1,51 @@ + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +bug->placeholder->chooseBuilds);?> +
+ + + + + + + + + + + + + + bug->batchCreate; $i++):?> + + + + + + + + + + + + +
bug->project . $lang->colon . $lang->bug->batchCreate;?>
idAB;?> bug->module;?> bug->project;?>bug->openedBuild;?> bug->title;?> bug->steps;?> bug->lblTypeAndSeverity;?> bug->lblSystemBrowserAndHardware;?>
+ bug->typeList, '');?> + bug->severityList, '');?> + + bug->osList, '');?> + bug->browserList, '');?> +
+
+ diff --git a/module/bug/view/browse.html.php b/module/bug/view/browse.html.php index d5768492b1..500ad0c40b 100644 --- a/module/bug/view/browse.html.php +++ b/module/bug/view/browse.html.php @@ -48,6 +48,7 @@ js::set('customed', $customed); common::printIcon('bug', 'report', "productID=$productID&browseType=$browseType&moduleID=$moduleID"); if($browseType != 'needconfirm') common::printIcon('bug', 'export', "productID=$productID&orderBy=$orderBy"); common::printIcon('bug', 'customFields'); + common::printIcon('bug', 'batchCreate', "productID=$productID&projectID=0&moduleID=$moduleID"); common::printIcon('bug', 'create', "productID=$productID&extra=moduleID=$moduleID"); ?> diff --git a/module/common/lang/en.php b/module/common/lang/en.php index 9c7584f8c4..ccf0780b3e 100644 --- a/module/common/lang/en.php +++ b/module/common/lang/en.php @@ -203,7 +203,7 @@ $lang->bug = new stdclass(); $lang->bug->menu = new stdclass(); $lang->bug->menu->product = '%s'; -$lang->bug->menu->bug = array('link' => 'Bug|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report,batchedit,confirmbug,assignto', 'subModule' => 'tree'); +$lang->bug->menu->bug = array('link' => 'Bug|bug|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit,resolve,close,activate,report,batchedit,confirmbug,assignto', 'subModule' => 'tree'); $lang->bug->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s', 'alias' => 'view,create,edit'); $lang->bug->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s'); diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index bc6d1168af..06344a31f4 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -203,7 +203,7 @@ $lang->bug = new stdclass(); $lang->bug->menu = new stdclass(); $lang->bug->menu->product = '%s'; -$lang->bug->menu->bug = array('link' => 'Bug|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report,batchedit,confirmbug,assignto', 'subModule' => 'tree'); +$lang->bug->menu->bug = array('link' => 'Bug|bug|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit,resolve,close,activate,report,batchedit,confirmbug,assignto', 'subModule' => 'tree'); $lang->bug->menu->testcase = array('link' => '用例|testcase|browse|productID=%s', 'alias' => 'view,create,edit'); $lang->bug->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s'); diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index f707009979..d686169ec3 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -345,6 +345,7 @@ $lang->resource->bug = new stdclass(); $lang->resource->bug->index = 'index'; $lang->resource->bug->browse = 'browse'; $lang->resource->bug->create = 'create'; +$lang->resource->bug->batchCreate = 'batchCreate'; $lang->resource->bug->confirmBug = 'confirmBug'; $lang->resource->bug->view = 'view'; $lang->resource->bug->edit = 'edit'; @@ -364,20 +365,21 @@ $lang->resource->bug->customFields = 'customFields'; $lang->bug->methodOrder[0] = 'index'; $lang->bug->methodOrder[5] = 'browse'; $lang->bug->methodOrder[10] = 'create'; -$lang->bug->methodOrder[15] = 'confirmBug'; -$lang->bug->methodOrder[20] = 'view'; -$lang->bug->methodOrder[25] = 'edit'; -$lang->bug->methodOrder[30] = 'assignTo'; -$lang->bug->methodOrder[35] = 'resolve'; -$lang->bug->methodOrder[40] = 'activate'; -$lang->bug->methodOrder[45] = 'close'; -$lang->bug->methodOrder[50] = 'report'; -$lang->bug->methodOrder[55] = 'export'; -$lang->bug->methodOrder[60] = 'confirmStoryChange'; -$lang->bug->methodOrder[65] = 'delete'; -$lang->bug->methodOrder[70] = 'saveTemplate'; -$lang->bug->methodOrder[75] = 'deleteTemplate'; -$lang->bug->methodOrder[80] = 'customFields'; +$lang->bug->methodOrder[15] = 'batchCreate'; +$lang->bug->methodOrder[20] = 'confirmBug'; +$lang->bug->methodOrder[25] = 'view'; +$lang->bug->methodOrder[30] = 'edit'; +$lang->bug->methodOrder[35] = 'assignTo'; +$lang->bug->methodOrder[40] = 'resolve'; +$lang->bug->methodOrder[45] = 'activate'; +$lang->bug->methodOrder[50] = 'close'; +$lang->bug->methodOrder[55] = 'report'; +$lang->bug->methodOrder[60] = 'export'; +$lang->bug->methodOrder[65] = 'confirmStoryChange'; +$lang->bug->methodOrder[70] = 'delete'; +$lang->bug->methodOrder[75] = 'saveTemplate'; +$lang->bug->methodOrder[80] = 'deleteTemplate'; +$lang->bug->methodOrder[85] = 'customFields'; /* Test case. */ $lang->resource->testcase = new stdclass(); diff --git a/www/theme/default/chosen.css b/www/theme/default/chosen.css index 28dfd4ef92..4ba0492ebb 100644 --- a/www/theme/default/chosen.css +++ b/www/theme/default/chosen.css @@ -139,6 +139,75 @@ } /* @end */ +/* Multiple select. */ +.chzn-container-multi .chzn-choices { + -moz-box-sizing: border-box; + background-color: #FFFFFF; + background-image: linear-gradient(#EEEEEE 1%, #FFFFFF 15%); + border: 1px solid #AAAAAA; + cursor: text; + height: auto !important; + margin: 0; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.chzn-container-multi .chzn-choices li.search-choice { + background-clip: padding-box; + background-color: #E4E4E4; + background-image: linear-gradient(#F4F4F4 20%, #F0F0F0 50%, #E8E8E8 52%, #EEEEEE 100%); + border: 1px solid #AAAAAA; + border-radius: 3px 3px 3px 3px; + box-shadow: 0 0 2px white inset, 0 1px 0 rgba(0, 0, 0, 0.05); + color: #333333; + cursor: default; + line-height: 13px; + margin: 3px 0 3px 5px; + padding: 3px 20px 3px 5px; + position: relative; +} +.chzn-container-multi .chzn-choices li { + float: left; + list-style: none outside none; +} + +.chzn-container-multi .chzn-choices li.search-choice .search-choice-close { + background: url("chosen-sprite.png") no-repeat scroll -42px 1px transparent; + display: block; + font-size: 1px; + height: 12px; + position: absolute; + right: 3px; + top: 4px; + width: 12px; +} + +.chzn-container-multi .chzn-choices li.search-field input { + background: none repeat scroll 0 0 transparent !important; + border: 0 none !important; + box-shadow: none; + color: #666666; + font-family: sans-serif; + font-size: 100%; + height: 15px; + margin: 1px 0; + outline: 0 none; + padding: 5px; +} + +.chzn-container-multi .chzn-choices li.search-choice .search-choice-close { + background: url("./images/chosen/chosen-sprite.png") no-repeat scroll -47px 1px transparent; + display: block; + font-size: 1px; + height: 12px; + position: absolute; + right: 3px; + top: 4px; + width: 12px; +} +/* @end */ /* Product and project seleteGroup. */ .chzn-container-single .chzn-single div b {background: url('./images/chosen/chosen-sprite.png') no-repeat 0 -2px;} diff --git a/www/theme/default/style.css b/www/theme/default/style.css index 972c2fc739..5e908462b2 100644 --- a/www/theme/default/style.css +++ b/www/theme/default/style.css @@ -535,6 +535,8 @@ table.tablesorter thead tr .headerSortDown {background-image: url(./images/table .icon-green-bug-createBug {padding:2px 8px; background:url(images/main/zt-icons.png) 0px -282px;} .icon-gray-bug-createBug {padding:2px 8px; background:url(images/main/zt-icons.png) 0px -302px;} +#featurebar .f-right .icon-green-bug-batchCreate {padding:2px 8px; background:url(images/main/zt-icons.png) -20px -320px;} + .icon-green-bug-resolve {padding:2px 8px; background:url(images/main/zt-icons.png) -60px -281px;} .icon-gray-bug-resolve {padding:2px 8px; background:url(images/main/zt-icons.png) -60px -301px;}