* resolve conflict of task model, add method for task searching.

This commit is contained in:
文睿 李
2022-12-08 03:44:50 +00:00
206 changed files with 4383 additions and 1903 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
$filter = new stdclass();
$filter->rules = new stdclass();
$filter->rules->md5 = '/^[a-z0-9]{32}$/';
$filter->rules->base64 = '/^[a-zA-Z0-9\+\/\=]+$/';
$filter->rules->base64 = '/^[a-zA-Z0-9\+\/\=\.]+$/';
$filter->rules->checked = '/^[0-9,\-]+$/';
$filter->rules->idList = '/^[0-9\|]+$/';
$filter->rules->lang = '/^[a-zA-Z_\-]+$/';
+4
View File
@@ -0,0 +1,4 @@
ALTER TABLE `zt_story` ADD COLUMN `siblings` varchar(255) NOT NULL AFTER `linkRequirements`;
ALTER TABLE `zt_productplan` MODIFY COLUMN `branch` varchar(255) NOT NULL DEFAULT '0';
ALTER TABLE `zt_effort` ADD `extra` text COLLATE 'utf8_general_ci' NOT NULL AFTER `end`;
ALTER TABLE `zt_build` MODIFY COLUMN `branch` varchar(255) NOT NULL DEFAULT '0';
+6 -2
View File
@@ -321,7 +321,7 @@ CREATE TABLE IF NOT EXISTS `zt_build` (
`id` mediumint(8) unsigned NOT NULL auto_increment,
`project` mediumint(8) unsigned NOT NULL,
`product` mediumint(8) unsigned NOT NULL default '0',
`branch` mediumint(8) unsigned NOT NULL default '0',
`branch` varchar(255) NOT NULL DEFAULT '0',
`execution` mediumint(8) unsigned NOT NULL default '0',
`builds` varchar(255) NOT NULL,
`name` char(150) NOT NULL,
@@ -1129,7 +1129,7 @@ CREATE TABLE IF NOT EXISTS `zt_product` (
CREATE TABLE IF NOT EXISTS `zt_productplan` (
`id` mediumint(8) unsigned NOT NULL auto_increment,
`product` mediumint(8) unsigned NOT NULL,
`branch` mediumint(8) unsigned NOT NULL,
`branch` varchar(255) NOT NULL DEFAULT '0',
`parent` mediumint(9) NOT NULL DEFAULT '0',
`title` varchar(90) NOT NULL,
`status` enum('wait','doing','done','closed') NOT NULL default 'wait',
@@ -1480,6 +1480,7 @@ CREATE TABLE IF NOT EXISTS `zt_story` (
`childStories` varchar(255) NOT NULL,
`linkStories` varchar(255) NOT NULL,
`linkRequirements` varchar(255) NOT NULL,
`siblings` varchar(255) NOT NULL,
`duplicateStory` mediumint(8) unsigned NOT NULL,
`version` smallint(6) NOT NULL default '1',
`feedbackBy` varchar(100) NOT NULL,
@@ -6553,6 +6554,7 @@ ALTER TABLE `zt_effort` CHANGE `begin` `begin` smallint(4) unsigned zerofill NOT
ALTER TABLE `zt_effort` CHANGE `end` `end` smallint(4) unsigned zerofill NOT NULL AFTER `begin`;
ALTER TABLE `zt_effort` ADD `deleted` enum('0','1') NOT NULL DEFAULT '0' AFTER `end`;
ALTER TABLE `zt_effort` ADD `order` tinyint unsigned NOT NULL DEFAULT '0' AFTER `end`;
ALTER TABLE `zt_effort` ADD `extra` text COLLATE 'utf8_general_ci' NULL AFTER `end`;
ALTER TABLE `zt_effort` ADD INDEX `execution` (`execution`);
ALTER TABLE `zt_effort` ADD INDEX `objectID` (`objectID`);
ALTER TABLE `zt_effort` ADD INDEX `date` (`date`);
@@ -7177,6 +7179,7 @@ CREATE TABLE IF NOT EXISTS `zt_ticket` (
key `product` (`product`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_ticketsource`;
CREATE TABLE IF NOT EXISTS `zt_ticketsource` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`ticketId` mediumint(8) unsigned NOT NULL,
@@ -7188,6 +7191,7 @@ CREATE TABLE IF NOT EXISTS `zt_ticketsource` (
key `ticketId` (`ticketId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_ticketrelation`;
CREATE TABLE IF NOT EXISTS `zt_ticketrelation` (
`id` mediumint unsigned NOT NULL AUTO_INCREMENT,
`ticketId` mediumint unsigned NOT NULL,
+1 -2
View File
@@ -600,7 +600,6 @@ class baseControl
if(!empty($jsExtPath))
{
$realModulePath = realPath($modulePath);
foreach($jsExtPath as $jsPath)
{
if(empty($jsPath)) continue;
@@ -730,7 +729,7 @@ class baseControl
chdir(dirname($viewFile));
/**
* 使用extract安定ob方法渲染$viewFile里面的代码。
* 使用extract和ob方法渲染$viewFile里面的代码。
* Use extract and ob functions to eval the codes in $viewFile.
*/
extract((array)$this->view);
+25 -16
View File
@@ -87,7 +87,7 @@ class baseHelper
/* 生成url链接的开始部分。Set the begin parts of the link. */
if($config->requestType == 'PATH_INFO') $link = $config->webRoot . $appName;
if($config->requestType != 'PATH_INFO') $link = $config->webRoot . $appName . basename($_SERVER['SCRIPT_NAME']);
if($config->requestType == 'PATH_INFO2') $link .= '/';
if($config->requestType == 'PATH_INFO2') $link = '/';
/**
* #1: RequestType为GET。When the requestType is GET.
@@ -178,7 +178,7 @@ class baseHelper
* Check in only body mode or not.
*
* @access public
* @return void
* @return bool
*/
public static function inOnlyBodyMode()
{
@@ -464,7 +464,7 @@ class baseHelper
$agent = $_SERVER["HTTP_USER_AGENT"];
/* Chrome should checked before safari.*/
/* Chrome should check before safari.*/
if(strpos($agent, 'Firefox') !== false) $browser['name'] = "firefox";
if(strpos($agent, 'Opera') !== false) $browser['name'] = 'opera';
if(strpos($agent, 'Safari') !== false) $browser['name'] = 'safari';
@@ -853,7 +853,7 @@ function a($var)
* Judge the server ip is local or not.
*
* @access public
* @return void
* @return bool
*/
function isLocalIP()
{
@@ -954,33 +954,42 @@ function htmlSpecialString($string, $flags = '', $encoding = 'UTF-8')
return htmlspecialchars($string, $flags, $encoding);
}
if (!function_exists('array_column'))
if(!function_exists('array_column'))
{
function array_column(array $input, $columnKey, $indexKey = null)
{
$output = array();
foreach ($input as $row) {
$key = $value = null;
foreach($input as $row)
{
$key = $value = null;
$keySet = $valueSet = false;
if (null !== $indexKey && array_key_exists($indexKey, $row)) {
if(null !== $indexKey && array_key_exists($indexKey, $row))
{
$keySet = true;
$key = (string) $row[$indexKey];
$key = (string) $row[$indexKey];
}
if (null === $columnKey) {
if(null === $columnKey)
{
$valueSet = true;
$value = $row;
} elseif (\is_array($row) && \array_key_exists($columnKey, $row)) {
$value = $row;
}
elseif(\is_array($row) && \array_key_exists($columnKey, $row))
{
$valueSet = true;
$value = $row[$columnKey];
$value = $row[$columnKey];
}
if ($valueSet) {
if ($keySet) {
if($valueSet)
{
if($keySet)
{
$output[$key] = $value;
} else {
}
else
{
$output[] = $value;
}
}
+1 -1
View File
@@ -281,8 +281,8 @@ class baseModel
/* 设置扩展的名字和相应的文件。Set extenson name and extension file. */
$moduleExtPath = $this->app->getModuleExtPath($this->appName, $moduleName, $type);
if(!empty($moduleExtPath['site'])) $extensionFile = $moduleExtPath['site'] . 'class/' . $extensionName . '.class.php';
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['custom'] . 'class/' . $extensionName . '.class.php';
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['saas'] . 'class/' . $extensionName . '.class.php';
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['custom'] . 'class/' . $extensionName . '.class.php';
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['vision'] . 'class/' . $extensionName . '.class.php';
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['xuan'] . 'class/' . $extensionName . '.class.php';
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['common'] . 'class/' . $extensionName . '.class.php';
+12 -10
View File
@@ -734,10 +734,13 @@ class baseRouter
$account = $sql->quote($account);
$vision = $this->dbh->query("SELECT * FROM " . TABLE_CONFIG . " WHERE owner = $account AND `key` = 'vision' LIMIT 1")->fetch();
if($vision) $vision = $vision->value;
if(empty($vision))
$user = $this->dbh->query("SELECT * FROM " . TABLE_USER . " WHERE account = $account AND deleted = '0' LIMIT 1")->fetch();
if(!empty($user->visions))
{
$user = $this->dbh->query("SELECT * FROM " . TABLE_USER . " WHERE account = $account AND deleted = '0' LIMIT 1")->fetch();
if(!empty($user->visions)) list($vision) = explode(',', $user->visions);
$userVisions = explode(',', $user->visions);
if(!in_array($vision, $userVisions)) $vision = '';
if(empty($vision)) list($vision) = $userVisions;
}
}
@@ -1716,7 +1719,7 @@ class baseRouter
}
/* 1. 如果extensionLevel == 2,且扩展文件存在,返回该站点扩展文件。 If extensionLevel == 2 and site extensionFile exists, return it. */
if($this->config->framework->extensionLevel == 2 and !empty( $moduleExtPaths['site']))
if($this->config->framework->extensionLevel == 2 and !empty($moduleExtPaths['site']))
{
$this->extActionFile = $moduleExtPaths['site'] . $this->methodName . '.php';
if(file_exists($this->extActionFile)) return true;
@@ -1754,7 +1757,7 @@ class baseRouter
if(empty($moduleExtPaths)) return false;
/* 如果extensionLevel == 2,且扩展文件存在,返回该站点扩展文件。If extensionLevel == 2 and site extensionFile exists, return it. */
if($this->config->framework->extensionLevel == 2 and !empty( $moduleExtPaths['site']))
if($this->config->framework->extensionLevel == 2 and !empty($moduleExtPaths['site']))
{
$locateFile = $moduleExtPaths['site'] . $this->methodName . '.302';
if(file_exists($locateFile)) $this->sendAPI($locateFile);
@@ -2494,9 +2497,8 @@ class baseRouter
*
* @param string $moduleName module name
* @param string $appName app name
* @param bool $exitIfNone exit or not
* @access public
* @return object|bool the config object or false.
* @return void
*/
public function loadModuleConfig($moduleName, $appName = '')
{
@@ -2522,7 +2524,7 @@ class baseRouter
if(!empty($extConfigPath['saas'])) $commonExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['saas'], '.php'));
if(!empty($extConfigPath['custom'])) $commonExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['custom'], '.php'));
}
if($config->framework->extensionLevel == 2 and !empty($extConfigPath['site'])) $siteExtConfigFiles = helper::ls($extConfigPath['site'], '.php');
if($config->framework->extensionLevel == 2 and !empty($extConfigPath['site'])) $siteExtConfigFiles = helper::ls($extConfigPath['site'], '.php');
$extConfigFiles = array_merge($commonExtConfigFiles, $siteExtConfigFiles);
/* 将主配置文件和扩展配置文件合并在一起。Put the main config file and extension config files together. */
@@ -2687,12 +2689,12 @@ class baseRouter
if($this->config->framework->extensionLevel >= 1)
{
if(!empty($extLangPath['common'])) $commonExtLangFiles = helper::ls($extLangPath['common'] . $this->clientLang, '.php');
if(!empty($extLangPath['xuan'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['xuan'] . $this->clientLang, '.php'));
if(!empty($extLangPath['xuan'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['xuan'] . $this->clientLang, '.php'));
if(!empty($extLangPath['vision'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['vision'] . $this->clientLang, '.php'));
if(!empty($extLangPath['custom'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['custom'] . $this->clientLang, '.php'));
if(!empty($extLangPath['saas'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['saas'] . $this->clientLang, '.php'));
}
if($this->config->framework->extensionLevel == 2 and !empty($extLangPath['site'])) $siteExtLangFiles = helper::ls($extLangPath['site'] . $this->clientLang, '.php');
if($this->config->framework->extensionLevel == 2 and !empty($extLangPath['site'])) $siteExtLangFiles = helper::ls($extLangPath['site'] . $this->clientLang, '.php');
$extLangFiles = array_merge($commonExtLangFiles, $siteExtLangFiles);
}
+1 -2
View File
@@ -315,9 +315,8 @@ class router extends baseRouter
*
* @param string $moduleName module name
* @param string $appName app name
* @param bool $exitIfNone exit or not
* @access public
* @return object|bool the config object or false.
* @return void
*/
public function loadModuleConfig($moduleName, $appName = '')
{
+5 -1
View File
@@ -130,7 +130,11 @@ class pager extends basePager
}
}
echo "<ul class='pager' $pageSizeOptions data-page-cookie='{$this->pageCookie}' data-ride='pager' data-rec-total='{$this->recTotal}' data-rec-per-page='{$this->recPerPage}' data-page='{$this->pageID}' data-link-creator='" . helper::createLink($this->moduleName, $this->methodName, $params) . "'></ul>";
global $app, $lang;
$appendApp = '';
$moduleName = $this->moduleName;
if(isset($lang->navGroup->{$moduleName}) and $lang->navGroup->{$moduleName} != $app->tab) $appendApp = "#app={$app->tab}";
echo "<ul class='pager' $pageSizeOptions data-page-cookie='{$this->pageCookie}' data-ride='pager' data-rec-total='{$this->recTotal}' data-rec-per-page='{$this->recPerPage}' data-page='{$this->pageID}' data-link-creator='" . helper::createLink($this->moduleName, $this->methodName, $params) . $appendApp . "'></ul>";
}
}
else
+3 -1
View File
@@ -28,7 +28,9 @@ class GitRepo
if($branch)
{
$branches = $this->branch();
if(isset($branches[$branch])) $branch = "origin/$branch";
$cmd = escapeCmd("$this->client branch -r");
execCmd($cmd . ' 2>&1', 'string', $result);
if(isset($branches[$branch]) and !empty($result)) $branch = "origin/$branch";
}
$this->branch = $branch;
$this->repo = $repo;
+18 -6
View File
@@ -18,10 +18,12 @@ class zfile
* @param string $to
* @param bool $logLevel
* @param string $logFile
* @param array $excludeFiles
* @param bool $toIsLink
* @access public
* @return array copied files, count, size or message.
*/
public function copyDir($from, $to, $logLevel = false, $logFile = '')
public function copyDir($from, $to, $logLevel = false, $logFile = '', $excludeFiles = array(), $toIsLink = false)
{
static $copiedFiles = array();
static $errorFiles = array();
@@ -41,12 +43,21 @@ class zfile
if(!empty($log['message'])) return $log;
$from = realpath($from) . '/';
$to = realpath($to) . '/';
if(is_link($to) || $toIsLink)
{
$to = $to . '/';
$toIsLink = true;
}
else
{
$to = realpath($to) . '/';
}
$entries = scandir($from);
foreach($entries as $entry)
{
if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git') continue;
if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git' or in_array($entry, $excludeFiles)) continue;
$fullEntry = $from . $entry;
if(is_file($fullEntry))
@@ -82,7 +93,7 @@ class zfile
{
$nextFrom = $fullEntry;
$nextTo = $to . $entry;
$result = $this->copyDir($nextFrom, $nextTo, $logLevel, $logFile);
$result = $this->copyDir($nextFrom, $nextTo, $logLevel, $logFile, array(), $toIsLink);
$count += $result['count'];
$size += $result['size'];
}
@@ -101,10 +112,11 @@ class zfile
* Get count.
*
* @param string $dir
* @param array $excludeFiles
* @access public
* @return int
*/
public function getCount($dir)
public function getCount($dir, $excludeFiles = array())
{
if(!file_exists($dir)) return 0;
if(is_file($dir)) return 1;
@@ -113,7 +125,7 @@ class zfile
$entries = scandir($dir);
foreach($entries as $entry)
{
if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git') continue;
if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git' or in_array($entry, $excludeFiles)) continue;
$fullEntry = $dir . '/' . $entry;
$count += $this->getCount($fullEntry);
+1 -1
View File
@@ -62,7 +62,7 @@ $config->action->majorList['project'] = array('opened', 'edited');
$config->action->majorList['execution'] = array('opened', 'edited');
$config->action->needGetProjectType = 'build,task,bug,case,testcase,caselib,testtask,testsuite,testreport,doc,issue,release,risk,design,opportunity,trainplan,gapanalysis,researchplan,researchreport,';
$config->action->needGetRelateField = ',story,productplan,release,task,build,bug,testcase,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,kanbanlane,kanbancolumn,module,';
$config->action->needGetRelateField = ',story,productplan,release,task,build,bug,testcase,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,kanbanlane,kanbancolumn,module,review,';
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,gitea,gogs,sonarqube,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,execution,project,traincategory,apistruct,program,product,user,entry,repo,';
$config->action->ignoreObjectType4Dynamic = 'kanbanregion,kanbanlane,kanbancolumn';
+4 -1
View File
@@ -225,8 +225,9 @@ $lang->action->desc->reopen = '$date, reopened by <strong>$actor</
$lang->action->desc->merged = '$date, merged by <strong>$actor</strong> .' . "\n";
$lang->action->desc->submitreview = '$date, submitted for review by <strong>$actor</strong>.' . "\n";
$lang->action->desc->ganttmove = '$date, sort by <strong>$actor</strong> .' . "\n";
$lang->action->desc->relieved = '$date, relieved by <strong>$actor</strong> .' . "\n";
$lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by <strong>'. $lang->admin->system .'</strong>.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the sprints of the project from the $extra.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n";
/* Used to describe the history of operations related to parent-child tasks. */
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> created a child task <strong>$extra</strong>。' . "\n";
@@ -395,6 +396,8 @@ $lang->action->label->tolib = 'imported';
$lang->action->label->updatetolib = 'updated';
$lang->action->label->ganttmove = 'sorted';
$lang->action->label->submitreview = 'submitted';
$lang->action->label->syncsiblings = 'synchronized changes';
$lang->action->label->relieved = 'relieved';
$lang->action->label->switchtolight = 'switch from ALM mode to light mode';
$lang->action->label->linkedrepo = 'Linked Code Repo';
$lang->action->label->unlinkedrepo = 'Unlinked Code Repo';
+4 -1
View File
@@ -225,8 +225,9 @@ $lang->action->desc->reopen = '$date, reopened by <strong>$actor</
$lang->action->desc->merged = '$date, merged by <strong>$actor</strong> .' . "\n";
$lang->action->desc->submitreview = '$date, submitted for review by <strong>$actor</strong>.' . "\n";
$lang->action->desc->ganttmove = '$date, sort by <strong>$actor</strong> .' . "\n";
$lang->action->desc->relieved = '$date, relieved by <strong>$actor</strong> .' . "\n";
$lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by <strong>'. $lang->admin->system .'</strong>.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the sprints of the project from the $extra.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n";
/* Used to describe the history of operations related to parent-child tasks. */
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> created a child task <strong>$extra</strong>。' . "\n";
@@ -395,6 +396,8 @@ $lang->action->label->tolib = 'imported';
$lang->action->label->updatetolib = 'updated';
$lang->action->label->ganttmove = 'sorted';
$lang->action->label->submitreview = 'submitted';
$lang->action->label->syncsiblings = 'synchronized changes';
$lang->action->label->relieved = 'relieved';
$lang->action->label->switchtolight = 'switch from ALM mode to light mode';
$lang->action->label->linkedrepo = 'Linked Code Repo';
$lang->action->label->unlinkedrepo = 'Unlinked Code Repo';
+4 -1
View File
@@ -225,8 +225,9 @@ $lang->action->desc->reopen = '$date, reopened by <strong>$actor</
$lang->action->desc->merged = '$date, merged by <strong>$actor</strong> .' . "\n";
$lang->action->desc->submitreview = '$date, submitted for review by <strong>$actor</strong>.' . "\n";
$lang->action->desc->ganttmove = '$date, sort by <strong>$actor</strong> .' . "\n";
$lang->action->desc->relieved = '$date, relieved by <strong>$actor</strong> .' . "\n";
$lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by <strong>'. $lang->admin->system .'</strong>.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the sprints of the project from the $extra.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n";
/* Used to describe the history of operations related to parent-child tasks. */
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> a créé un sous-tâche <strong>$extra</strong>。' . "\n";
@@ -395,6 +396,8 @@ $lang->action->label->tolib = 'Importé';
$lang->action->label->updatetolib = 'MàJ';
$lang->action->label->ganttmove = 'sorted';
$lang->action->label->submitreview = 'submitted';
$lang->action->label->syncsiblings = 'synchronized changes';
$lang->action->label->relieved = 'relieved';
$lang->action->label->switchtolight = 'switch from ALM mode to light mode';
$lang->action->label->linkedrepo = 'Linked Code Repo';
$lang->action->label->unlinkedrepo = 'Unlinked Code Repo';
+1
View File
@@ -306,6 +306,7 @@ $lang->action->label->syncproject = 'start';
$lang->action->label->syncexecution = 'start';
$lang->action->label->startProgram = '(The start of the project sets the status of the program as Ongoing)';
$lang->action->label->submitreview = 'submitted';
$lang->action->label->syncsiblings = 'synchronized changes';
$lang->action->label->linkedrepo = 'Linked Code Repo';
$lang->action->label->unlinkedrepo = 'Unlinked Code Repo';
+4 -1
View File
@@ -225,8 +225,9 @@ $lang->action->desc->reopen = '$date, 由 <strong>$actor</strong>
$lang->action->desc->merged = '$date, 由 <strong>$actor</strong> 合并。' . "\n";
$lang->action->desc->submitreview = '$date, 由 <strong>$actor</strong> 提交评审。' . "\n";
$lang->action->desc->ganttmove = '$date, 由 <strong>$actor</strong> 排序。' . "\n";
$lang->action->desc->relieved = '$date, 由 <strong>$actor</strong> 解除孪生需求关系。' . "\n";
$lang->action->desc->switchtolight = '$date, 由于 <strong>'. $lang->admin->system .'</strong> 从全生命周期管理模式切换为轻量管理模式,项目访问控制由项目集内公开调整为私有。' . "\n";
$lang->action->desc->unlinkproduct = '$date, 系统判断由于迭代所属项目与$extra取消关联,同步将迭代与$extra取消关联。' . "\n";
$lang->action->desc->unlinkproduct = '$date, 系统判断由于' . $lang->executionCommon . '所属项目与$extra取消关联,同步将' . $lang->executionCommon . '与$extra取消关联。' . "\n";
/* 用来描述和父子任务相关的操作历史记录。*/
$lang->action->desc->createchildren = '$date, 由 <strong>$actor</strong> 创建子任务 <strong>$extra</strong>。' . "\n";
@@ -395,6 +396,8 @@ $lang->action->label->tolib = '导入了';
$lang->action->label->updatetolib = '更新了';
$lang->action->label->ganttmove = '排序了';
$lang->action->label->submitreview = '提交了评审';
$lang->action->label->syncsiblings = '同步修改了';
$lang->action->label->relieved = '解除了';
$lang->action->label->switchtolight = '从全生命周期管理模式切换为轻量管理模式';
$lang->action->label->linkedrepo = '关联代码库到';
$lang->action->label->unlinkedrepo = '取消了项目与代码库的关联';
+21 -1
View File
@@ -50,7 +50,7 @@ class actionModel extends model
$action->extra = $extra;
if(!defined('IN_UPGRADE')) $action->vision = $this->config->vision;
if($objectType == 'story' and strpos(',reviewpassed,reviewrejected,reviewclarified,reviewreverted,', ",$actionType,") !== false) $action->actor = $this->lang->action->system;
if($objectType == 'story' and strpos(',reviewpassed,reviewrejected,reviewclarified,reviewreverted,syncsiblings,', ",$actionType,") !== false) $action->actor = $this->lang->action->system;
/* Use purifier to process comment. Fix bug #2683. */
$action->comment = fixer::stripDataTags($comment);
@@ -287,6 +287,15 @@ class actionModel extends model
if(strpos(',deleted,', ",$actionType,") !== false) $module = $this->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($objectID)->fetch();
if(!empty($module) and $module->type == 'story') $record['product'] = $module->root;
break;
case 'review':
$result = $this->dao->select('*')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
if($result)
{
$products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($result->project)->fetchPairs('product');
$record['product'] = join(',', array_keys($products));
$record['project'] = zget($result, 'project', 0);
}
break;
default:
$result = $this->dao->select('*')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
$record['product'] = zget($result, 'product', '0');
@@ -952,6 +961,17 @@ class actionModel extends model
}
}
if($action->objectType == 'story' and $action->action == 'syncsiblings')
{
if(!empty($extra) and strpos($extra, '|') !== false)
{
list($operate, $storyID) = explode('|', $extra);
$desc['operate'] = $this->lang->$objectType->{$desc['operate']};
$link = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$storyID"), "#$storyID ") : "#$storyID";
$actionDesc = str_replace(array('$extra', '$operate'), array($link, $desc['operate'][$operate]), $desc['main']);
}
}
if($action->objectType == 'module' and strpos(',created,moved,', $action->action) !== false)
{
$moduleNames = $this->loadModel('tree')->getOptionMenu($action->objectID, 'story', 0, 'all', '');
+1
View File
@@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = 'Off';
$lang->admin->safe->noticeMode = 'The password will be checked when creating and modifying user information, and changing passwords.';
$lang->admin->safe->noticeWeakMode = 'The password will be checked when logging into the system, creating and modifying user information, and changing passwords.';
$lang->admin->safe->noticeStrong = 'The longer the password, the more letters, numbers, or special characters it contains, and the less repetitive the password, the more secure it is!';
$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.';
+1
View File
@@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = 'Off';
$lang->admin->safe->noticeMode = 'The password will be checked when creating and modifying user information, and changing passwords.';
$lang->admin->safe->noticeWeakMode = 'The password will be checked when logging into the system, creating and modifying user information, and changing passwords.';
$lang->admin->safe->noticeStrong = 'The longer the password, the more letters, numbers, or special characters it contains, and the less repetitive the password, the more secure it is!';
$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.';
+1
View File
@@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = 'Off';
$lang->admin->safe->noticeMode = "Le mot de passe sera vérifié lors de la création et de la modification des coordonnées de l'utilisateur, et du changement de mot de passe.";
$lang->admin->safe->noticeWeakMode = "Le mot de passe sera vérifié lors de la connexion au système, de la création et de la modification des coordonnées de l'utilisateur, et du changement de mot de passe.";
$lang->admin->safe->noticeStrong = "Le mot de passe est d'autant plus sécurisé qu'il est long, qu'il contient plus de lettres, de chiffres ou de caractères spéciaux, et que les lettres du mot de passe sont peu répétitives !";
$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.';
+1
View File
@@ -84,3 +84,4 @@ $lang->admin->safe->loginCaptchaList[0] = 'No';
$lang->admin->safe->noticeMode = 'Mật khẩu sẽ được kiểm tra khi người dùng đăng nhập hoặc người dùng thêm hoặc sửa.';
$lang->admin->safe->noticeStrong = '';
$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.';
+1
View File
@@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = '关闭';
$lang->admin->safe->noticeMode = '系统会在创建和修改用户、修改密码的时候检查用户口令。';
$lang->admin->safe->noticeWeakMode = '系统会在登录、创建和修改用户、修改密码的时候检查用户口令。';
$lang->admin->safe->noticeStrong = '密码长度越长,含有大写字母或数字或特殊符号越多,密码字母越不重复,安全度越强!';
$lang->admin->safe->noticeGd = '系统检测到您的服务器未安装GD模块,无法使用验证码功能,请安装后使用。';
+4 -2
View File
@@ -82,5 +82,7 @@ $lang->admin->safe->modifyPasswordList[0] = '不強制';
$lang->admin->safe->loginCaptchaList[1] = '是';
$lang->admin->safe->loginCaptchaList[0] = '否';
$lang->admin->safe->noticeMode = '系統會在登錄、創建和修改用戶、修改密碼的時候檢查用戶口令。';
$lang->admin->safe->noticeStrong = '密碼長度越長,含有大寫字母或數字或特殊符號越多,密碼字母越不重複,安全度越強!';
$lang->admin->safe->noticeMode = '系統會在創建和修改用戶、修改密碼的時候檢查用戶口令。';
$lang->admin->safe->noticeWeakMode = '系統會在登錄、創建和修改用戶、修改密碼的時候檢查用戶口令。';
$lang->admin->safe->noticeStrong = '密碼長度越長,含有大寫字母或數字或特殊符號越多,密碼字母越不重複,安全度越強!';
$lang->admin->safe->noticeGd = '系統檢測到您的伺服器未安裝GD模組,無法使用驗證碼功能,請安裝後使用。';
+4 -1
View File
@@ -16,6 +16,7 @@
.notice {color:#2667E3; margin-left: 12px;}
</style>
<?php js::set('adminLang', $lang->admin);?>
<?php js::set('loadedGD', extension_loaded('gd'));?>
<?php include '../../common/view/header.html.php';?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
@@ -71,7 +72,8 @@
</tr>
<tr>
<th><?php echo $lang->admin->safe->loginCaptcha?></th>
<td colspan='2'><?php echo html::radio('loginCaptcha', $lang->admin->safe->loginCaptchaList, isset($config->safe->loginCaptcha) ? $config->safe->loginCaptcha : 0)?></td>
<td><?php echo html::radio('loginCaptcha', $lang->admin->safe->loginCaptchaList, isset($config->safe->loginCaptcha) ? $config->safe->loginCaptcha : 0)?></td>
<td class='notice'><?php if(!extension_loaded('gd')) echo $lang->admin->safe->noticeGd;?></td>
</tr>
<tr>
<td colspan='3' class='text-center form-actions'>
@@ -89,6 +91,7 @@ $(function()
{
var mode = $("input[name='mode']:checked").val();
showModeRule(mode);
if(!loadedGD) $('#loginCaptcha1').attr('disabled', true);
});
function showModeRule(mode)
{
+4 -4
View File
@@ -33,7 +33,7 @@
<?php $code = $group . ucfirst($feature);?>
<?php if(strpos(",$disabledFeatures,", ",$code,") !== false) continue;?>
<?php $hasData = true;?>
<?php endForeach;?>
<?php endforeach;?>
<?php if($hasData):?>
<tr>
@@ -52,11 +52,11 @@
<?php echo html::checkbox("module[{$code}]", array('1' => $lang->admin->setModule->{$feature}), $value, "data-code='{$code}'", 'inline');?>
<?php echo html::hidden("module[{$code}][]", $value, $value ? 'disabled' : '');?>
</div>
<?php endForeach;?>
<?php endforeach;?>
</td>
</tr>
<?php endif;?>
<?php endForeach;?>
<?php endforeach;?>
<tr>
<td class='text-middle text-right thWidth'>
<div class="checkbox-primary checkbox-inline checkbox-right check-all">
@@ -68,7 +68,7 @@
</tr>
</tbody>
</table>
</form>`
</form>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+3 -2
View File
@@ -34,6 +34,7 @@ class backupModel extends model
public function backFile($backupFile)
{
$zfile = $this->app->loadClass('zfile');
$return = new stdclass();
$return->result = true;
$return->error = '';
@@ -42,10 +43,10 @@ class backupModel extends model
$tmpLogFile = $this->getTmpLogFile($backupFile);
$dataDir = $this->app->getAppRoot() . 'www/data/';
$count = $zfile->getCount($dataDir);
$count = $zfile->getCount($dataDir, array('course'));
file_put_contents($tmpLogFile, json_encode(array('allCount' => $count)));
$result = $zfile->copyDir($dataDir, $backupFile, $logLevel = false, $tmpLogFile);
$result = $zfile->copyDir($dataDir, $backupFile, $logLevel = false, $tmpLogFile, array('course'));
$this->processSummary($backupFile, $result['count'], $result['size'], $result['errorFiles'], $count);
unlink($tmpLogFile);
@@ -19,8 +19,9 @@
<?php $isFirstTab = true;?>
<?php $printMore = false;?>
<?php $i = 0;?>
<?php $maxItem = common::checkNotCN() ? 6 : 8;?>
<?php foreach($hasViewPriv as $type => $bool):?>
<?php if(!common::checkNotCN() or $i <= 6):?>
<?php if($i <= $maxItem):?>
<li<?php if($isFirstTab) {echo ' class="active"';}?>>
<a data-tab href='#assigntomeTab-<?php echo $type;?>' onClick="changeLabel('<?php echo $type;?>')">
<?php echo $type == 'review' ? $lang->my->audit : $lang->block->availableBlocks->$type;?>
@@ -36,7 +37,7 @@
<?php endif;?>
<li<?php if($isFirstTab) {echo ' class="active"';}?>>
<a data-tab href='#assigntomeTab-<?php echo $type;?>' class='<?php echo "$type"?>' onClick="changeMoreBtn('<?php echo $type;?>', this);">
<?php echo $lang->block->availableBlocks->$type;?>
<?php echo $type == 'review' ? $lang->my->audit : $lang->block->availableBlocks->$type;?>
<span class='label label-light label-badge label-assignto <?php echo $type . "-count "; echo $isFirstTab ? '' : 'hidden'; $isFirstTab = false ?>'><?php echo $count[$type];?></span>
</a>
</li>
@@ -86,12 +86,12 @@
minTimeGap = Math.min(minTimeGap, endDatetime - startDatetime);
item.tasks = [];
item.completeTasks = [];
item.progress = 0;
item.progress = Number.parseFloat(item.taskProgress.replace('%', ''), 10);
plans.push(item);
}
else if(item.type === 'task')
{
item.progress = Number.parseInt(item.taskProgress.replace('%', ''), 10);
item.progress = Number.parseFloat(item.taskProgress.replace('%', ''), 10);
tasks.push(item);
}
});
@@ -105,7 +105,6 @@
plan = plansMap[plan.parent];
if(typeof(plan) != 'object') return;
}
plan.progress += task.progress;
if(task.progress === 100) plan.completeTasks.push(task);
plan.tasks.push(task);
});
@@ -122,7 +121,6 @@
/* Update gantt plans and bars */
$.each(plans, function(index, plan)
{
plan.progress = !plan.tasks.length ? 0 : plan.progress / plan.tasks.length;
var $plan = $('<div class="gantt-plan"></div>');
$plan.append('<div class="strong" title="' + plan.name + '">' + plan.text + '</div>');
$plans.append($plan);
+10 -4
View File
@@ -257,18 +257,21 @@ class branch extends control
*
* @param int $productID
* @param int $oldBranch
* @param string $param
* @param string $browseType
* @param int $projectID
* @param bool $withMainBranch
* @param string $isSiblings
* @param string $fieldID
* @param string $multiple
* @access public
* @return void
*/
public function ajaxGetBranches($productID, $oldBranch = 0, $param = 'all', $projectID = 0, $withMainBranch = true)
public function ajaxGetBranches($productID, $oldBranch = 0, $browseType = 'all', $projectID = 0, $withMainBranch = true, $isSiblings = 'no', $fieldID = '0', $multiple = '')
{
$product = $this->loadModel('product')->getById($productID);
if(empty($product) or $product->type == 'normal') return;
$branches = $this->loadModel('branch')->getList($productID, $projectID, $param, 'order', null, $withMainBranch);
$branches = $this->loadModel('branch')->getList($productID, $projectID, $browseType, 'order', null, $withMainBranch);
$branchTagOption = array();
foreach($branches as $branchInfo)
{
@@ -280,7 +283,10 @@ class branch extends control
$branchTagOption[$oldBranch] = $oldBranch == BRANCH_MAIN ? $branch : ($branch->name . ($branch->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : ''));
}
return print(html::select('branch', $branchTagOption, $oldBranch, "class='form-control' onchange='loadBranch(this)' data-last='{$oldBranch}'"));
$name = $multiple == 'multiple' ? 'branch[]' : 'branch';
if($isSiblings == 'yes') return print(html::select("branches[$fieldID]", $branchTagOption, $oldBranch, "onchange='loadBranchRelation(this.value, $fieldID);' class='form-control chosen control-branch'"));
return print(html::select($name, $branchTagOption, $oldBranch, "class='form-control' $multiple onchange='loadBranch(this)' data-last='{$oldBranch}'"));
}
/**
+2
View File
@@ -328,11 +328,13 @@ $config->bug->datatable->fieldList['os']['title'] = 'os';
$config->bug->datatable->fieldList['os']['fixed'] = 'no';
$config->bug->datatable->fieldList['os']['width'] = '80';
$config->bug->datatable->fieldList['os']['required'] = 'no';
$config->bug->datatable->fieldList['os']['control'] = 'multiple';
$config->bug->datatable->fieldList['browser']['title'] = 'browser';
$config->bug->datatable->fieldList['browser']['fixed'] = 'no';
$config->bug->datatable->fieldList['browser']['width'] = '80';
$config->bug->datatable->fieldList['browser']['required'] = 'no';
$config->bug->datatable->fieldList['browser']['control'] = 'multiple';
$config->bug->datatable->fieldList['mailto']['title'] = 'mailto';
$config->bug->datatable->fieldList['mailto']['fixed'] = 'no';
+40 -24
View File
@@ -227,7 +227,8 @@ class bug extends control
$this->view->product = $product;
$this->view->projectProducts = $this->product->getProducts($this->projectID);
$this->view->productName = $productName;
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'withreleased');
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch);
$this->view->releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch);
$this->view->modules = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch);
$this->view->moduleTree = $moduleTree;
$this->view->moduleName = $moduleID ? $this->tree->getById($moduleID)->name : $this->lang->tree->all;
@@ -487,7 +488,7 @@ class bug extends control
$steps = $this->lang->bug->tplStep . $this->lang->bug->tplResult . $this->lang->bug->tplExpect;
$os = '';
$browser = '';
$assignedTo = '';
$assignedTo = isset($currentProduct->QD) ? $currentProduct->QD : '';
$deadline = '';
$mailto = '';
$keywords = '';
@@ -558,13 +559,13 @@ class bug extends control
/* If executionID is setted, get builds and stories of this execution. */
if($executionID)
{
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone', $executionID, 'execution');
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone,noreleased', $executionID, 'execution');
$stories = $this->story->getExecutionStoryPairs($executionID);
if(!$projectID) $projectID = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($executionID)->fetch('project');
}
else
{
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone,withbranch');
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone,withbranch,noreleased');
$stories = $this->story->getProductStoryPairs($productID, $branch, 0, 'all','id_desc', 0, 'full', 'story', false);
}
@@ -655,6 +656,7 @@ class bug extends control
$this->view->projectExecutionPairs = $this->loadModel('project')->getProjectExecutionPairs();
$this->view->executions = defined('TUTORIAL') ? $this->loadModel('tutorial')->getExecutionPairs() : $executions;
$this->view->builds = $builds;
$this->view->releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch);
$this->view->moduleID = (int)$moduleID;
$this->view->projectID = $projectID;
$this->view->projectModel = $projectModel;
@@ -765,7 +767,7 @@ class bug extends control
/* If executionID is setted, get builds and stories of this execution. */
if($executionID)
{
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty', $executionID, 'execution');
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noreleased', $executionID, 'execution');
$stories = $this->story->getExecutionStoryPairs($executionID);
$execution = $this->loadModel('execution')->getById($executionID);
if($execution->type == 'kanban')
@@ -785,7 +787,7 @@ class bug extends control
}
else
{
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty');
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noreleased');
$stories = $this->story->getProductStoryPairs($productID, $branch);
}
@@ -933,7 +935,7 @@ class bug extends control
$this->view->branchName = $product->type == 'normal' ? '' : zget($branches, $bug->branch, '');
$this->view->users = $this->user->getPairs('noletter');
$this->view->actions = $this->action->getList('bug', $bugID);
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'withreleased');
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, 'all');
$this->view->preAndNext = $this->loadModel('common')->getPreAndNextObject('bug', $bugID);
$this->view->product = $product;
@@ -1079,18 +1081,18 @@ class bug extends control
$this->view->position[] = $this->lang->bug->edit;
/* Assign. */
$allBuilds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty,withreleased');
$allBuilds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty');
if($executionID)
{
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch', $executionID, 'execution');
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch,noreleased', $executionID, 'execution');
}
elseif($projectID)
{
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch', $projectID, 'project');
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch,noreleased', $projectID, 'project');
}
else
{
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch');
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch,noreleased');
}
/* Set the openedBuilds list. */
@@ -1163,7 +1165,6 @@ class bug extends control
if($product->shadow) $this->view->project = $this->loadModel('project')->getByShadowProduct($bug->product);
$this->view->bug = $bug;
$this->view->productID = $productID;
$this->view->product = $product;
$this->view->execution = $execution;
$this->view->productBugs = $productBugs;
@@ -1828,15 +1829,15 @@ class bug extends control
$this->bug->checkBugExecutionPriv($bug);
$this->qa->setMenu($this->products, $productID, $bug->branch);
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve;
$this->view->bug = $bug;
$this->view->users = $users;
$this->view->assignedTo = $assignedTo;
$this->view->productBugs = $productBugs;
$this->view->executions = $this->loadModel('product')->getExecutionPairsByProduct($productID, $bug->branch ? "0,{$bug->branch}" : 0, 'id_desc', $projectID, 'stagefilter');
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'withbranch');
$this->view->actions = $this->action->getList('bug', $bugID);
$this->view->execution = isset($execution) ? $execution : '';
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve;
$this->view->bug = $bug;
$this->view->users = $users;
$this->view->assignedTo = $assignedTo;
$this->view->productBugs = $productBugs;
$this->view->executions = $this->loadModel('product')->getExecutionPairsByProduct($productID, $bug->branch ? "0,{$bug->branch}" : 0, 'id_desc', $projectID, 'stagefilter');
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'withbranch,noreleased');
$this->view->actions = $this->action->getList('bug', $bugID);
$this->view->execution = isset($execution) ? $execution : '';
$this->display();
}
@@ -1933,7 +1934,7 @@ class bug extends control
$this->view->bug = $bug;
$this->view->users = $this->user->getPairs('noclosed', $bug->resolvedBy);
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'noempty', 0, 'execution', $bug->openedBuild);
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'noempty,noreleased', 0, 'execution', $bug->openedBuild);
$this->view->actions = $this->action->getList('bug', $bugID);
$this->display();
@@ -2150,7 +2151,7 @@ class bug extends control
$this->view->bugs = $bugs;
$this->view->users = $this->user->getPairs();
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty');
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noreleased');
$this->display();
}
@@ -2412,7 +2413,7 @@ class bug extends control
public function ajaxGetBugFieldOptions($productID, $executionID = 0)
{
$modules = $this->loadModel('tree')->getOptionMenu($productID, 'bug');
$builds = $this->loadModel('build')->getBuildPairs($productID, 'all', '', $executionID, 'execution');
$builds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noreleased', $executionID, 'execution');
$type = $this->lang->bug->typeList;
$pri = $this->lang->bug->priList;
$severity = $this->lang->bug->severityList;
@@ -2500,4 +2501,19 @@ class bug extends control
if($project->model == 'kanban') return print($this->lang->bug->kanban);
return print($this->lang->bug->execution);
}
/**
* Ajax get released builds.
*
* @param int $productID
* @param int|string $branch
* @access public
* @return string
*/
public function ajaxGetReleasedBuilds($productID, $branch = 'all')
{
$releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch);
return print(helper::jsonEncode($releasedBuilds));
}
}
+1 -1
View File
@@ -57,4 +57,4 @@ html[lang='de'] #keywordsAddonLabel, .task {width: 73px;}
#openedBuildLabel {display: inline; position: relative; width: 50%; left: 14%;}
#bugTypeInputGroup > .table-col {width: 40% !important;}
.pri-text > .label-pri {padding: 1px 5px;}
.pri-text > .label-pri {padding: 2px 6px;}
+2 -2
View File
@@ -38,13 +38,13 @@ function setOpenedBuilds(link, index)
var selected = $('#buildBox' + index).find('select').val();
$('#buildBox' + index).html(builds);
$('#buildBox' + index).find('select').val(selected);
$('#openedBuilds' + index + '_chosen').remove();
$('#pickerDropMenu-pk_openedBuild' + index).remove();
$('#openedBuilds' + index).next('.picker').remove();
$('#buildBox' + index + ' select').removeClass('select-3');
$('#buildBox' + index + ' select').addClass('select-1');
$('#buildBox' + index + ' select').attr('name','openedBuilds[' + index + '][]');
$('#buildBox' + index + ' select').attr('id','openedBuilds' + index);
$('#buildBox' + index + ' select').chosen();
$('#buildBox' + index + ' select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
index++;
if($('#executions' + index).val() != 'ditto') break;
+99 -26
View File
@@ -19,6 +19,27 @@ $(function()
}
});
if($('#openedBuild').length || $('#resolvedBuild').length || $('[name^=openedBuilds]').length)
{
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
$('#openedBuild, #resolvedBuild, [name^=openedBuilds]').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
}
function markReleasedBuilds($option)
{
var build = $option.attr('data-value');
if($.inArray(build, releasedBuilds) != -1)
{
if(!$option.find('.label-released').length)
{
var optionText = $option.find('.picker-option-text').html();
$option.find('.picker-option-text').replaceWith("<p class='picker-option-text no-margin'>" + optionText + " <span class='label label-released label-primary label-outline'>" + released + "</span></p>");
}
}
}
/**
* Load all fields.
*
@@ -178,6 +199,8 @@ function loadAllExecutionBuilds(executionID, productID, buildBox)
{
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
if(page == 'create')
{
oldOpenedBuild = $('#openedBuild').val() ? $('#openedBuild').val() : 0;
@@ -186,10 +209,10 @@ function loadAllExecutionBuilds(executionID, productID, buildBox)
{
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control" multiple=multiple></select>';
$('#openedBuild').replaceWith(data);
$('#openedBuild_chosen').remove();
$('#pickerDropMenu-pk_openedBuild').remove();
$('#openedBuild').next('.picker').remove();
$("#openedBuild").chosen();
notice();
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
})
}
if(page == 'edit')
@@ -197,12 +220,12 @@ function loadAllExecutionBuilds(executionID, productID, buildBox)
if(buildBox == 'openedBuildBox')
{
link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&needCreate=true&type=all');
$('#openedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
if(buildBox == 'resolvedBuildBox')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch + '&index=0&type=all');
$('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
}
}
@@ -219,6 +242,9 @@ function loadAllProductBuilds(productID, buildBox)
{
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
if(page == 'create')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&type=all');
@@ -226,10 +252,10 @@ function loadAllProductBuilds(productID, buildBox)
{
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control" multiple=multiple></select>';
$('#openedBuild').replaceWith(data);
$('#openedBuild_chosen').remove();
$('#pickerDropMenu-pk_openedBuild').remove();
$('#openedBuild').next('.picker').remove();
$("#openedBuild").chosen();
notice();
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
})
}
if(page == 'edit')
@@ -237,12 +263,12 @@ function loadAllProductBuilds(productID, buildBox)
if(buildBox == 'openedBuildBox')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&type=all');
$('#openedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
if(buildBox == 'resolvedBuildBox')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch + '&index=0&type=all');
$('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
}
}
@@ -294,7 +320,7 @@ function loadProductStories(productID)
function loadProductProjects(productID)
{
required = $('#project_chosen').hasClass('required');
branch = $('#branch').val();
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
link = createLink('product', 'ajaxGetProjects', 'productID=' + productID + '&branch=' + branch + '&projectID=' + oldProjectID);
$('#projectBox').load(link, function()
@@ -437,23 +463,25 @@ function loadProductBuilds(productID)
if(typeof(oldOpenedBuild) == 'undefined') oldOpenedBuild = 0;
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch);
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
if(page == 'create')
{
$.get(link, function(data)
{
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control" multiple=multiple></select>';
$('#openedBuild').replaceWith(data);
$('#openedBuild_chosen').remove();
$('#pickerDropMenu-pk_openedBuild').remove();
$('#openedBuild').next('.picker').remove();
$("#openedBuild").chosen();
notice();
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
})
}
else
{
$('#openedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
$('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
}
@@ -466,9 +494,12 @@ function loadProductBuilds(productID)
*/
function loadExecutionRelated(executionID)
{
executionID = parseInt(executionID);
executionID = parseInt(executionID);
currentProjectID = $('#project').val() == 'undefined' ? 0 : $('#project').val();
if(executionID)
{
if(currentProjectID == 0) loadProjectByExecutionID(executionID);
loadExecutionTasks(executionID);
loadExecutionStories(executionID);
loadExecutionBuilds(executionID);
@@ -477,7 +508,6 @@ function loadExecutionRelated(executionID)
}
else
{
var currentProjectID = $('#project').val() == 'undefined' ? 0 : $('#project').val();
var currentProductID = $('#product').val();
$('#taskIdBox').innerHTML = '<select id="task"></select>'; // Reset the task.
@@ -496,6 +526,43 @@ function loadExecutionRelated(executionID)
}
}
/**
* Load a project by execution id.
*
* @param executionID $executionID
* @access public
* @return void
*/
function loadProjectByExecutionID(executionID)
{
link = createLink('project', 'ajaxGetPairsByExecution', 'executionID=' + executionID, 'json');
required = $('#project_chosen').hasClass('required');
productID = $('#product').val();
$.post(link, function(data)
{
var originProject = $('#project').html();
if($('#project').find('option[value="' + data.id + '"]').length > 0)
{
$('#project').find('option[value="' + data.id + '"]').attr('selected', 'selected');
originProject = $('#project').html();
$('#project').replaceWith('<select id="project" name="project" class="form-control" onchange="loadProductExecutions(' + productID + ', this.value)">' + originProject + '</select>');
}
else
{
var newProject = '<option value="' + data.id + '" data-keys="' + data.namePinyin + '" selected="selected">' + data.name + '</option>';
$('#project').replaceWith('<select id="project" name="project" class="form-control" onchange="loadProductExecutions(' + productID + ', this.value)">' + originProject + newProject+ '</select>');
}
$('#project_chosen').remove();
$('#project').next('.picker').remove();
$('#project').chosen();
if(required) $('#project_chosen').addClass('required');
}, 'json')
}
/**
* Load execution tasks.
*
@@ -552,28 +619,30 @@ function loadProjectBuilds(projectID)
var productID = $('#product').val();
var oldOpenedBuild = $('#openedBuild').val() ? $('#openedBuild').val() : 0;
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
if(page == 'create')
{
var link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=&branch=' + branch);
$.get(link, function(data)
{
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control" multiple=multiple></select>';
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control picker-select" multiple=multiple></select>';
$('#openedBuild').replaceWith(data);
$('#openedBuild').val(oldOpenedBuild);
$('#openedBuild_chosen').remove();
$('#pickerDropMenu-pk_openedBuild').remove();
$('#openedBuild').next('.picker').remove();
$("#openedBuild").chosen();
notice();
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
})
}
else
{
var link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch);
$('#openedBuildBox').load(link, function(){$(this).find('select').val(oldOpenedBuild).chosen()});
$('#openedBuildBox').load(link, function(){$(this).find('select').val(oldOpenedBuild).picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
var oldResolvedBuild = $('#resolvedBuild').val() ? $('#resolvedBuild').val() : 0;
var link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
$('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).chosen()});
$('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
}
@@ -595,28 +664,30 @@ function loadExecutionBuilds(executionID, num)
if(typeof(branch) == 'undefined') var branch = 0;
if(typeof(productID) == 'undefined') var productID = 0;
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
if(page == 'create')
{
link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + "&branch=" + branch + "&index=0&needCreate=true");
$.get(link, function(data)
{
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control" multiple=multiple></select>';
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control picker-select" multiple=multiple></select>';
$('#openedBuild').replaceWith(data);
$('#openedBuild').val(oldOpenedBuild);
$('#openedBuild_chosen').remove();
$('#pickerDropMenu-pk_openedBuild').remove();
$('#openedBuild').next('.picker').remove();
$("#openedBuild").chosen();
notice();
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
})
}
else
{
link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&needCreate=false&type=normal&number=' + num);
$('#openedBuildBox' + num).load(link, function(){$(this).find('select').val(oldOpenedBuild).chosen()});
$('#openedBuildBox' + num).load(link, function(){$(this).find('select').val(oldOpenedBuild).picker({optionRender: markReleaseBuilds, dropWidth: 'auto'})});
oldResolvedBuild = $('#resolvedBuild').val() ? $('#resolvedBuild').val() : 0;
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
$('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).chosen()});
$('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
}
@@ -776,7 +847,9 @@ function notice()
if(page == 'edit') return;
$('#buildBoxActions').empty().hide();
if($('#openedBuild').find('option').length <= 1)
var itemCount = $('#openedBuild').find('option').length;
if($('#openedBuild').attr('data-items') != undefined) var itemCount = $('#openedBuild').attr('data-items');
if(itemCount <= 1)
{
var html = '';
if($('#execution').length == 0 || $('#execution').val() == 0)
+2 -1
View File
@@ -124,6 +124,7 @@ $(function()
});
});
$(window).unload(function(){
$(window).unload(function()
{
if(blockID) window.parent.refreshBlock($('#block' + blockID));
});
+3 -5
View File
@@ -81,8 +81,6 @@ class bugModel extends model
->remove('files,labels,uid,oldTaskID,contactListMenu,region,lane,ticket')
->get();
if($bug->execution != 0) $bug->project = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($bug->execution)->fetch('project');
/* Check repeat bug. */
$result = $this->loadModel('common')->removeDuplicate('bug', $bug, "product={$bug->product}");
if($result and $result['stop']) return array('status' => 'exists', 'id' => $result['duplicate']);
@@ -219,8 +217,6 @@ class bugModel extends model
if(isset($data->lanes[$i])) $bug->laneID = $data->lanes[$i];
if($bug->execution != 0) $bug->project = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($bug->execution)->fetch('project');
/* Assign the bug to the person in charge of the module. */
if(!empty($moduleOwners[$bug->module]))
{
@@ -1623,7 +1619,7 @@ class bugModel extends model
$this->config->bug->search['params']['module']['values'] = $modules;
$this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($productID, 0, 'id_desc', $projectID);
$this->config->bug->search['params']['severity']['values'] = array(0 => '') + $this->lang->bug->severityList; //Fix bug #939.
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, 'all', 'withbranch');
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, 'all', 'withbranch|releasetag');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
if($this->session->currentProductType == 'normal')
{
@@ -3027,6 +3023,8 @@ class bugModel extends model
}
$allBranch = "`branch` = 'all'";
$branch = trim($branch, ',');
if(strpos($branch, ',') !== false) $branch = str_replace(',', "','", $branch);
if($branch !== 'all' and strpos($bugQuery, '`branch` =') === false) $bugQuery .= " AND `branch` in('0','$branch')";
if(strpos($bugQuery, $allBranch) !== false) $bugQuery = str_replace($allBranch, '1', $bugQuery);
+5 -1
View File
@@ -37,7 +37,7 @@
<?php $this->printExtendFields($bug, 'table');?>
<tr>
<th><?php echo $lang->bug->openedBuild;?></th>
<td colspan='2'><?php echo html::select('openedBuild[]', $builds, $bug->openedBuild, 'size=4 multiple=multiple class="form-control chosen"');?></td>
<td colspan='2'><?php echo html::select('openedBuild[]', $builds, $bug->openedBuild, 'size=4 multiple=multiple class="form-control picker-select"');?></td>
</tr>
<tr>
<th><?php echo $lang->comment;?></th>
@@ -56,4 +56,8 @@
<div class='main'><?php include '../../common/view/action.html.php';?></div>
</div>
</div>
<?php
js::set('productID', $bug->product);
js::set('released', $lang->build->released);
?>
<?php include '../../common/view/footer.html.php';?>
+6 -4
View File
@@ -13,6 +13,8 @@
<?php
include '../../common/view/header.html.php';
js::set('requiredFields', $config->bug->create->requiredFields);
js::set('productID', $productID);
js::set('released', $lang->build->released);
?>
<?php
$visibleFields = array();
@@ -107,7 +109,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field)
<td><?php echo html::select("modules[$i]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'project', ' hidden')?> projectBox' style='overflow:visible'><?php echo html::select("projects[$i]", $projects, $projectID, "class='form-control chosen' onchange='loadProductExecutionsByProject($productID, this.value, $i)'");?></td>
<td class='<?php echo zget($visibleFields, 'execution', ' hidden')?> executionBox' style='overflow:visible'><?php echo html::select("executions[$i]", $executions, $executionID, "class='form-control chosen' onchange='loadExecutionBuilds($productID, this.value, $i)'");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, 'trunk', "class='form-control chosen' multiple");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, 'trunk', "class='form-control picker-select' multiple");?></td>
<td>
<div class='input-group'>
<div class="input-control has-icon-right">
@@ -163,7 +165,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field)
<td><?php echo html::select("modules[$i]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'project', ' hidden')?> projectBox' style='overflow:visible'><?php echo html::select("projects[$i]", $projects, $projectID, "class='form-control chosen' onchange = 'loadProductExecutionsByProject($productID, this.value, $i)'");?></td>
<td class='<?php echo zget($visibleFields, 'execution', ' hidden')?> executionBox' style='overflow:visible'><?php echo html::select("executions[$i]", $executions, $executionID, "class='form-control chosen' onchange='loadExecutionBuilds($productID, this.value, $i)'");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, '', "class='form-control chosen' multiple");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, '', "class='form-control picker-select' multiple");?></td>
<td>
<div class='input-group'>
<div class="input-control has-icon-right">
@@ -224,7 +226,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field)
<td><?php echo html::select("modules[%s]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'project', ' hidden')?> projectBox' style='overflow:visible'><?php echo html::select("projects[%s]", $projects, $projectID, "class='form-control chosen' onchange = 'loadProductExecutionsByProject($productID, this.value, \"%s\")'");?></td>
<td class='<?php echo zget($visibleFields, 'execution', ' hidden')?> executionBox' style='overflow:visible'><?php echo html::select("executions[%s]", $executions, $executionID, "class='form-control chosen' onchange='loadExecutionBuilds($productID, this.value, \"%s\")'");?></td>
<td id='buildBox%s'><?php echo html::select("openedBuilds[%s][]", $builds, '', "class='form-control chosen' multiple");?></td>
<td id='buildBox%s'><?php echo html::select("openedBuilds[%s][]", $builds, '', "class='form-control picker-select' multiple");?></td>
<td>
<div class='input-group'>
<div class="input-control has-icon-right">
@@ -267,7 +269,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field)
<td><?php echo html::select("modules[$i]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'project', ' hidden')?> projectBox' style='overflow:visible'><?php echo html::select("projects[$i]", $projects, $projectID, "class='form-control chosen' onchange = 'loadProductExecutionsByProject($productID, this.value, $i)'");?></td>
<td class='<?php echo zget($visibleFields, 'execution', ' hidden')?> executionBox' style='overflow:visible'><?php echo html::select("executions[$i]", $executions, $executionID, "class='form-control chosen' onchange='loadExecutionBuilds($productID, this.value, $i)'");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, '', "class='form-control chosen' multiple");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, '', "class='form-control picker-select' multiple");?></td>
<td>
<div class='input-group'>
<div class="input-control has-icon-right">
+1 -1
View File
@@ -328,7 +328,7 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow
{
$actionLink = $this->createLink('bug', 'batchResolve', "resolution=fixed&resolvedBuild=$key");
echo "<li class='option' data-key='$key'>";
echo html::a('javascript:;', $build, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#bugList')\"");
echo html::a('javascript:;', $build . (in_array($key, $releasedBuilds) ? " <span class='label label-primary label-outline'>{$lang->build->released}</span> " : ''), '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#bugList')\"");
echo "</li>";
}
echo "</ul>";
+3 -1
View File
@@ -30,6 +30,8 @@ js::set('tab', $this->app->tab);
js::set('requiredFields', $config->bug->create->requiredFields);
js::set('showFields', $showFields);
js::set('projectExecutionPairs', $projectExecutionPairs);
js::set('productID', $productID);
js::set('released', $lang->build->released);
if($this->app->tab == 'execution') js::set('objectID', zget($execution, 'id', ''));
if($this->app->tab == 'project') js::set('objectID', $projectID);
?>
@@ -128,7 +130,7 @@ if($this->app->tab == 'project') js::set('objectID', $projectID);
<td>
<div class='input-group' id='buildBox'>
<span class="input-group-addon"><?php echo $lang->bug->openedBuild?></span>
<?php echo html::select('openedBuild[]', $builds, empty($buildID) ? '' : $buildID, "multiple=multiple class='chosen form-control'");?>
<?php echo html::select('openedBuild[]', $builds, empty($buildID) ? '' : $buildID, "multiple=multiple class='picker-select form-control' data-items='" . count($builds) . "'");?>
<span class='input-group-addon fix-border' id='buildBoxActions'></span>
<div class='input-group-btn'><?php echo html::commonButton($lang->bug->allBuilds, "class='btn' id='all' data-toggle='tooltip' onclick='loadAllBuilds()'")?></div>
</div>
+7 -5
View File
@@ -30,6 +30,8 @@ js::set('bugID' , $bug->id);
js::set('bugBranch' , $bug->branch);
js::set('isClosedBug' , $bug->status == 'closed');
js::set('projectExecutionPairs' , $projectExecutionPairs);
js::set('productID' , $product->id);
js::set('released' , $lang->build->released);
if($this->app->tab == 'execution') js::set('objectID', $bug->execution);
if($this->app->tab == 'project') js::set('objectID', $bug->project);
?>
@@ -100,7 +102,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
<th class='w-80px'><?php echo $lang->bug->product;?></th>
<td>
<div class='input-group'>
<?php echo html::select('product', $products, $productID, "onchange='loadAll(this.value)' class='form-control chosen'");?>
<?php echo html::select('product', $products, $product->id, "onchange='loadAll(this.value)' class='form-control chosen'");?>
<?php if($product->type != 'normal') echo html::select('branch', $branchTagOption, $bug->branch, "onchange='loadBranch();' class='form-control'");?>
</div>
</td>
@@ -114,9 +116,9 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
if(count($moduleOptionMenu) == 1)
{
echo "<span class='input-group-addon'>";
echo html::a($this->createLink('tree', 'browse', "rootID=$productID&view=bug&currentModuleID=0&branch=$bug->branch", '', true), $lang->tree->manage, '', "class='text-primary' data-toggle='modal' data-type='iframe' data-width='95%'");
echo html::a($this->createLink('tree', 'browse', "rootID={$product->id}&view=bug&currentModuleID=0&branch=$bug->branch", '', true), $lang->tree->manage, '', "class='text-primary' data-toggle='modal' data-type='iframe' data-width='95%'");
echo '&nbsp; ';
echo html::a("javascript:void(0)", $lang->refreshIcon, '', "class='refresh' title='$lang->refresh' onclick='loadProductModules($productID)'");
echo html::a("javascript:void(0)", $lang->refreshIcon, '', "class='refresh' title='$lang->refresh' onclick='loadProductModules($product->id)'");
echo '</span>';
}
?>
@@ -240,7 +242,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
<th><?php echo $lang->bug->openedBuild;?></th>
<td>
<div id='openedBuildBox' class='input-group'>
<?php echo html::select('openedBuild[]', $openedBuilds, $bug->openedBuild, 'size=4 multiple=multiple class="chosen form-control"');?>
<?php echo html::select('openedBuild[]', $openedBuilds, $bug->openedBuild, 'size=4 multiple=multiple class="picker-select form-control"');?>
<span class='input-group-btn'><?php echo html::commonButton($lang->bug->allBuilds, "class='btn' onclick='loadAllBuilds(this)'")?></span>
</div>
</td>
@@ -257,7 +259,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
<th><?php echo $lang->bug->resolvedBuild;?></th>
<td>
<div id='resolvedBuildBox' class='input-group'>
<?php echo html::select('resolvedBuild', $resolvedBuilds, $bug->resolvedBuild, "class='form-control chosen'");?>
<?php echo html::select('resolvedBuild', $resolvedBuilds, $bug->resolvedBuild, "class='form-control picker-select'");?>
<span class='input-group-btn'><?php echo html::commonButton($lang->bug->allBuilds, "class='btn' onclick='loadAllBuilds(this)'")?></span>
</div>
</td>
+4 -3
View File
@@ -14,8 +14,9 @@
<?php include '../../common/view/kindeditor.html.php';?>
<?php include '../../common/view/datepicker.html.php';?>
<?php
js::set('page' , 'resolve');
js::set('productID' , $bug->product);
js::set('page', 'resolve');
js::set('productID', $bug->product);
js::set('released', $lang->build->released);
?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
@@ -49,7 +50,7 @@ js::set('productID' , $bug->product);
</div>
</td>
<td>
<div id='resolvedBuildBox'><?php echo html::select('resolvedBuild', $builds, '', "class='form-control chosen'");?></div>
<div id='resolvedBuildBox'><?php echo html::select('resolvedBuild', $builds, '', "class='form-control picker-select'");?></div>
<div id='newBuildBox' class='hidden required'><?php echo html::input('buildName', '', "class='form-control' placeholder='{$lang->bug->placeholder->newBuildName}'");?></div>
</td>
<td>
+36 -15
View File
@@ -181,6 +181,7 @@ class build extends control
}
$executions = $this->product->getExecutionPairsByProduct($build->product, $build->branch, 'id_desc', $this->session->project, 'stagefilter');
if($build->execution and !isset($executions[$build->execution])) $executions[$build->execution] = $this->loadModel('execution')->getById($build->execution)->name;
/* Get stories and bugs. */
$orderBy = 'status_asc, stage_asc, id_desc';
@@ -198,7 +199,10 @@ class build extends control
{
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
if(!isset($branchTagOption[$build->branch])) $branchTagOption[$build->branch] = $this->branch->getById($build->branch, 0, 'name');
foreach(explode(',', $build->branch) as $buildBranch)
{
if(!isset($branchTagOption[$buildBranch])) $branchTagOption[$buildBranch] = $this->branch->getById($buildBranch, 0, 'name');
}
foreach($productGroups as $product) $products[$product->id] = $product->name;
@@ -305,6 +309,16 @@ class build extends control
$this->view->generatedBugPager = $generatedBugPager;
$this->executeHooks($buildID);
$branchName = '';
if($build->productType != 'normal')
{
foreach(explode(',', $build->branch) as $buildBranch)
{
$branchName .= $this->loadModel('branch')->getById($buildBranch);
$branchName .= ',';
}
$branchName = trim($branchName, ',');
}
/* Assign. */
$this->view->canBeChanged = common::canBeChanged('build', $build); // Determines whether an object is editable.
@@ -320,7 +334,8 @@ class build extends control
$this->view->bugs = $bugs;
$this->view->type = $type;
$this->view->bugPager = $bugPager;
$this->view->branchName = $build->productType == 'normal' ? '' : $this->loadModel('branch')->getById($build->branch);
$this->view->branchName = empty($branchName) ? $this->lang->branch->main : $branchName;
$this->view->childBuilds = empty($build->builds) ? array() : $this->dao->select('id,name,bugs,stories')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchAll();
if($this->app->getViewType() == 'json')
{
@@ -385,32 +400,38 @@ class build extends control
* @param string|int $branch
* @param int $index the index of batch create bug.
* @param string $type get all builds or some builds belong to normal releases and executions are not done.
* @param string $extra
* @access public
* @return string
*/
public function ajaxGetProductBuilds($productID, $varName, $build = '', $branch = 'all', $index = 0, $type = 'normal')
public function ajaxGetProductBuilds($productID, $varName, $build = '', $branch = 'all', $index = 0, $type = 'normal', $extra = '')
{
$isJsonView = $this->app->getViewType() == 'json';
if($varName == 'openedBuild' )
{
$params = ($type == 'all') ? 'noempty,withbranch' : 'noempty,noterminate,nodone,withbranch';
$params = ($type == 'all') ? 'noempty,withbranch,noreleased' : 'noempty,noterminate,nodone,withbranch,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, 0, 'project', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName . '[]', $builds, $build, 'size=4 class=form-control multiple'));
}
if($varName == 'openedBuilds' )
{
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty', 0, 'project', $build);
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty,noreleased', 0, 'project', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName . "[$index][]", $builds, $build, 'size=4 class=form-control multiple'));
}
if($varName == 'resolvedBuild')
{
$params = ($type == 'all') ? 'withbranch' : 'noterminate,nodone,withbranch';
$params = ($type == 'all') ? 'withbranch,noreleased' : 'noterminate,nodone,withbranch,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, 0, 'project', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName, $builds, $build, "class='form-control'"));
}
$builds = $this->build->getBuildPairs($productID, $branch, $type, 0, 'project', $build, false);
if(strpos($extra, 'multiple') !== false) $varName .= '[]';
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName, $builds, $build, "class='form-control chosen' $extra"));
}
/**
@@ -434,7 +455,7 @@ class build extends control
{
if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$params = ($type == 'all') ? 'noempty,withbranch' : 'noempty,noterminate,nodone,withbranch';
$params = ($type == 'all') ? 'noempty,withbranch,noreleased' : 'noempty,noterminate,nodone,withbranch,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, $projectID, 'project', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName . '[]', $builds , '', 'size=4 class=form-control multiple'));
@@ -443,13 +464,13 @@ class build extends control
{
if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$params = ($type == 'all') ? 'withbranch' : 'noterminate,nodone,withbranch';
$params = ($type == 'all') ? 'withbranch,noreleased' : 'noterminate,nodone,withbranch,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, $projectID, 'project', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName, $builds, $build, "class='form-control'"));
}
if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type, $extra);
$builds = $this->build->getBuildPairs($productID, $branch, $type, $projectID, 'project', $build, false);
if(strpos($extra, 'multiple') !== false) $varName .= '[]';
if($isJsonView) return print(json_encode($builds));
@@ -478,7 +499,7 @@ class build extends control
{
if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$params = ($type == 'all') ? 'noempty' : 'noempty,noterminate,nodone';
$params = ($type == 'all') ? 'noempty,noreleased' : 'noempty,noterminate,nodone,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, $executionID, 'execution', $build);
if($isJsonView) return print(json_encode($builds));
@@ -489,7 +510,7 @@ class build extends control
{
if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty', $executionID, 'execution', $build);
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty,noreleased', $executionID, 'execution', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName . "[$index][]", $builds , $build, 'size=4 class=form-control multiple'));
}
@@ -497,14 +518,14 @@ class build extends control
{
if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$params = ($type == 'all') ? '' : 'noterminate,nodone';
$params = ($type == 'all') ? ',noreleased' : 'noterminate,nodone,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, $executionID, 'execution', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName, $builds, $build, "class='form-control'"));
}
if($varName == 'testTaskBuild')
{
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty,notrunk', $executionID, 'execution');
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty,notrunk', $executionID, 'execution', '', false);
if($isJsonView) return print(json_encode($builds));
if(empty($builds))
@@ -543,7 +564,7 @@ class build extends control
{
$lastBuild = $this->build->getLast($executionID, $projectID);
if($lastBuild)
{
{
echo "<div class='help-block'> &nbsp; " . $this->lang->build->last . ": <a class='code label label-badge label-light' id='lastBuildBtn'>" . $lastBuild->name . "</a></div>";
}
else
@@ -714,7 +735,7 @@ class build extends control
$this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairsForStory($build->product, $build->branch, 'skipParent');
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($build->product, 'bug', 0, $build->branch);
$this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($build->product, $build->branch, 'id_desc', $this->session->project);
$this->config->bug->search['params']['openedBuild']['values'] = $this->build->getBuildPairs($build->product, $branch = 'all', $params = '');
$this->config->bug->search['params']['openedBuild']['values'] = $this->build->getBuildPairs($build->product, $branch = 'all', $params = 'releasetag');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
unset($this->config->bug->search['fields']['product']);
+2 -1
View File
@@ -1,8 +1,9 @@
.linkBox #queryBox .search-form .form-actions {padding-bottom: 5px;}
.linkBox .table-header {padding: 8px 15px; border-bottom: 1px solid #cbd0db;}
#unlinkStoryList, #unlinkBugList {border-top: 1px solid #cbd0db;}
.page-title .dropdown-menu {top: 20px; left: 170px;}
.page-title .dropdown-menu {top: 20px; left: 170px; max-height:300px; overflow:auto;}
.page-title .text>a {font-weight: 700;}
.body-modal #mainContent {min-height: 200px;}
td.article-content{overflow:auto !important;}
td.c-build{white-space: nowrap; overflow:hidden;}
+12 -2
View File
@@ -7,6 +7,11 @@
*/
function loadBranches(productID)
{
if($('input[name=isIntegrated]:checked').val() == 'yes')
{
$('#branchBox').closest('tr').addClass('hidden');
return false;
}
$('#branch').remove();
$('#branch_chosen').remove();
var oldBranch = 0;
@@ -16,12 +21,17 @@ function loadBranches(productID)
}
projectID = currentTab == 'execution' ? executionID : projectID;
$.get(createLink('branch', 'ajaxGetBranches', 'productID=' + productID + '&oldBranch=0&param=active&projectID=' + projectID), function(data)
$.get(createLink('branch', 'ajaxGetBranches', 'productID=' + productID + '&oldBranch=0&param=active&projectID=' + projectID + '&withMainBranch=true&isSiblings=no&fieldID=0&multiple=multiple'), function(data)
{
if(data)
{
$('#product').closest('.input-group').append(data);
$('#branchBox').append(data);
$('#branch').chosen();
$('#branchBox').closest('tr').removeClass('hidden');
}
else
{
$('#branchBox').closest('tr').addClass('hidden');
}
});
}
+12 -2
View File
@@ -9,12 +9,16 @@ $().ready(function()
{
var projectID = $('#project').val();
var productID = $('#product').val();
var branch = $('#branch').length > 0 ? $('#branch').val() : '';
$.get(createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=builds&build=&branch=' + branch + '&index=&needCreate=&type=noempty,notrunk,separate,singled&extra=multiple'), function(data)
$.get(createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=builds&build=&branch=all&index=&needCreate=&type=noempty,notrunk,separate,singled&extra=multiple'), function(data)
{
if(data) $('#buildBox').html(data);
$('#builds').attr('data-placeholder', multipleSelect).chosen();
});
$.get(createLink('product', 'ajaxGetProductById', 'produtID=' + productID), function(data)
{
$('#branchBox').closest('tr').find('th').text(data.branchName);
}, 'json');
});
$('input[name=isIntegrated]').change(function()
@@ -70,6 +74,12 @@ function loadProducts(executionID)
loadBranches($("#product").val());
}
});
$.get(createLink('product', 'ajaxGetProductById', 'produtID=' + $("#product").val()), function(data)
{
$('#branchBox').closest('tr').find('th').text(data.branchName);
}, 'json');
loadLastBuild();
}
+8 -3
View File
@@ -3,20 +3,25 @@ $().ready(function()
var oldExecutionID = $('#execution').val();
$(document).on('change', '#product, #branch', function()
{
var productID = $('#product').val();
if(executionID)
{
loadExecutions(oldExecutionID);
}
else
{
var productID = $('#product').val();
var branch = $('#branch').val();
$.get(createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=builds&build=&branch=' + branch + '&index=&needCreate=&type=noempty,notrunk,separate,singled&extra=multiple'), function(data)
$.get(createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=builds&build=&branch=all&index=&needCreate=&type=noempty,notrunk,separate,singled&extra=multiple'), function(data)
{
if(data) $('#buildBox').html(data);
$('#builds').attr('data-placeholder', multipleSelect).chosen();
});
}
$.get(createLink('product', 'ajaxGetProductById', 'produtID=' + productID), function(data)
{
$('#branchBox').closest('tr').find('th').text(data.branchName);
}, 'json');
});
});
+3
View File
@@ -36,9 +36,11 @@ $lang->build->execution = $lang->executionCommon;
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Included Builds';
$lang->build->released = 'Released';
$lang->build->name = 'Name';
$lang->build->date = 'Datum';
$lang->build->builder = 'Builder';
$lang->build->url = 'URL';
$lang->build->scmPath = 'SCM Pfad';
$lang->build->filePath = 'Dateipfad';
$lang->build->desc = 'Beschreibung';
@@ -60,6 +62,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers
$lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}";
$lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds";
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
$lang->build->finishStories = " %s {$lang->SRCommon} sind abgeschlossen.";
$lang->build->resolvedBugs = ' %s Bugs sind gelöst.';
+3
View File
@@ -36,9 +36,11 @@ $lang->build->execution = $lang->executionCommon;
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Included Builds';
$lang->build->released = 'Released';
$lang->build->name = 'Name';
$lang->build->date = 'Date';
$lang->build->builder = 'Builder';
$lang->build->url = 'URL';
$lang->build->scmPath = 'SCM Path';
$lang->build->filePath = 'File Path';
$lang->build->desc = 'Description';
@@ -60,6 +62,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers
$lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}";
$lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds";
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
$lang->build->finishStories = " Finished {$lang->SRCommon} %s";
$lang->build->resolvedBugs = ' Resolved Bug %s';
+3
View File
@@ -36,9 +36,11 @@ $lang->build->execution = $lang->executionCommon;
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Included Builds';
$lang->build->released = 'Released';
$lang->build->name = 'Nom';
$lang->build->date = 'Date';
$lang->build->builder = 'Builder';
$lang->build->url = 'URL';
$lang->build->scmPath = 'Chemin SCM';
$lang->build->filePath = 'Chemin Fichier';
$lang->build->desc = 'Description';
@@ -60,6 +62,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers
$lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}";
$lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds";
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
$lang->build->finishStories = " {$lang->SRCommon} Terminées %s";
$lang->build->resolvedBugs = ' Bugs Résolus %s';
+1
View File
@@ -54,6 +54,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers
$lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}";
$lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds";
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
$lang->build->finishStories = " {$lang->SRCommon} đã kết thúc %s";
$lang->build->resolvedBugs = ' Bug đã giải quyết %s';
+4 -1
View File
@@ -28,7 +28,7 @@ $lang->build->confirmUnlinkBug = "您确认移除该Bug吗?";
$lang->build->basicInfo = '基本信息';
$lang->build->id = 'ID';
$lang->build->product = $lang->productCommon;
$lang->build->product = '所属' . $lang->productCommon;
$lang->build->project = '所属项目';
$lang->build->branch = '平台/分支';
$lang->build->branchName = '所属%s';
@@ -36,9 +36,11 @@ $lang->build->execution = '所属' . $lang->executionCommon;
$lang->build->integrated = '集成版本';
$lang->build->singled = '单一版本';
$lang->build->builds = '包含版本';
$lang->build->released = '发布';
$lang->build->name = '名称编号';
$lang->build->date = '打包日期';
$lang->build->builder = '构建者';
$lang->build->url = '地址';
$lang->build->scmPath = '源代码地址';
$lang->build->filePath = '下载地址';
$lang->build->desc = '描述';
@@ -60,6 +62,7 @@ $lang->build->notice->changeProduct = "已经关联{$lang->SRCommon}、Bug或
$lang->build->notice->changeExecution = "提交测试单的版本,不能修改其所属{$lang->executionCommon}";
$lang->build->notice->changeBuilds = "提交测试单的版本,不能修改关联版本";
$lang->build->notice->autoRelation = "相关版本下完成的需求、解决的Bug、产生的Bug将会自动关联到项目版本中";
$lang->build->notice->createTest = "该版本所属执行已删除,不能提交测试";
$lang->build->finishStories = " 本次共完成 %s 个{$lang->SRCommon}";
$lang->build->resolvedBugs = ' 本次共解决 %s 个Bug';
+87 -15
View File
@@ -63,11 +63,10 @@ class buildModel extends model
*/
public function getProjectBuilds($projectID = 0, $type = 'all', $param = 0, $orderBy = 't1.date_desc,t1.id_desc', $pager = null)
{
return $this->dao->select('t1.*, t2.name as executionName, t2.id as executionID, t3.name as productName, t4.name as branchName')
return $this->dao->select('t1.*, t2.name as executionName, t2.id as executionID, t3.name as productName')
->from(TABLE_BUILD)->alias('t1')
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')
->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id')
->leftJoin(TABLE_BRANCH)->alias('t4')->on('t1.branch = t4.id')
->where('t1.deleted')->eq(0)
->andWhere('t1.project')->ne(0)
->beginIF($projectID)->andWhere('t1.project')->eq((int)$projectID)->fi()
@@ -129,11 +128,10 @@ class buildModel extends model
*/
public function getExecutionBuilds($executionID, $type = '', $param = '', $orderBy = 't1.date_desc,t1.id_desc', $pager = null)
{
return $this->dao->select('t1.*, t2.name as executionName, t3.name as productName, t4.name as branchName')
return $this->dao->select('t1.*, t2.name as executionName, t3.name as productName')
->from(TABLE_BUILD)->alias('t1')
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')
->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id')
->leftJoin(TABLE_BRANCH)->alias('t4')->on('t1.branch = t4.id')
->where('t1.deleted')->eq(0)
->beginIF($executionID)->andWhere('t1.execution')->eq((int)$executionID)->fi()
->beginIF($type == 'product' and $param)->andWhere('t1.product')->eq($param)->fi()
@@ -181,6 +179,38 @@ class buildModel extends model
return $this->getExecutionBuilds($executionID, 'bysearch', $buildQuery);
}
/**
* Filter linked stories or bugs builds.
*
* @param array $buildIdList
* @access public
* @return array
*/
public function filterLinked($buildIdList)
{
$linkeds = array();
$buildList = $this->getByList($buildIdList);
foreach($buildList as $build)
{
if(!$build->execution && !empty($build->builds))
{
$childBuilds = $this->getByList($build->builds);
foreach($childBuilds as $childBuild)
{
$childBuild->stories = trim($childBuild->stories, ',');
$childBuild->bugs = trim($childBuild->bugs, ',');
if($childBuild->stories) $build->stories .= ',' . $childBuild->stories;
if($childBuild->bugs) $build->bugs .= ',' . $childBuild->bugs;
}
}
if(!empty($build->stories) or !empty($build->bugs)) $linkeds[$build->id] = $build->id;
}
return $linkeds;
}
/**
* Get story builds.
*
@@ -202,7 +232,7 @@ class buildModel extends model
*
* @param int|array $products
* @param string|int $branch
* @param string $params noempty|notrunk|noterminate|withbranch|hasproject|noDeleted|singled|withreleased, can be a set of them
* @param string $params noempty|notrunk|noterminate|withbranch|hasproject|noDeleted|singled|noreleased|releasedtag, can be a set of them
* @param string|int $objectID
* @param string $objectType
* @param int|array $buildIdList
@@ -226,14 +256,16 @@ class buildModel extends model
->fetchPairs();
}
$shadows = $this->dao->select('shadow')->from(TABLE_RELEASE)->where('product')->in($products)->fetchPairs('shadow', 'shadow');
$branchs = strpos($params, 'separate') === false ? "0,$branch" : $branch;
$allBuilds = $this->dao->select('t1.id, t1.name, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName, t5.type as productType')->from(TABLE_BUILD)->alias('t1')
$allBuilds = $this->dao->select('t1.id, t1.name, t1.execution, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName, t5.type as productType')->from(TABLE_BUILD)->alias('t1')
->beginIF($objectType === 'execution')->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')->fi()
->beginIF($objectType === 'project')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')->fi()
->leftJoin(TABLE_RELEASE)->alias('t3')->on("FIND_IN_SET(t1.id,t3.build)")
->leftJoin(TABLE_BRANCH)->alias('t4')->on('t1.branch = t4.id')
->leftJoin(TABLE_PRODUCT)->alias('t5')->on('t1.product = t5.id')
->where('1=1')
->andWhere('t1.id')->notIN($shadows)
->beginIF(strpos($params, 'hasDeleted') === false)->andWhere('t1.deleted')->eq(0)->fi()
->beginIF(strpos($params, 'hasproject') !== false)->andWhere('t1.project')->ne(0)->fi()
->beginIF(strpos($params, 'singled') !== false)->andWhere('t1.execution')->ne(0)->fi()
@@ -243,6 +275,8 @@ class buildModel extends model
->beginIF($branch !== 'all')->andWhere('t1.branch')->in("$branchs")->fi()
->orderBy('t1.date desc, t1.id desc')->fetchAll('id');
$deletedExecutions = $this->dao->select('id, deleted')->from(TABLE_EXECUTION)->where('type')->eq('sprint')->andWhere('deleted')->eq('1')->fetchPairs();
/* Set builds and filter done executions and terminate releases. */
$builds = array();
$buildIdList = array();
@@ -251,6 +285,7 @@ class buildModel extends model
{
if(empty($build->releaseID) and (strpos($params, 'nodone') !== false) and ($build->objectStatus === 'done')) continue;
if((strpos($params, 'noterminate') !== false) and ($build->releaseStatus === 'terminate')) continue;
if((strpos($params, 'withexecution') !== false) and $build->execution and isset($executions[$build->execution])) continue;
if($build->deleted == 1) $build->name .= ' (' . $this->lang->build->deleted . ')';
$branchName = $build->branchName ? $build->branchName : $this->lang->branch->main;
@@ -292,12 +327,13 @@ class buildModel extends model
$releaseName = $release->name;
$branchName = $release->branchName ? $release->branchName : $this->lang->branch->main;
if($release->productType != 'normal') $releaseName = (strpos($params, 'withbranch') !== false ? $branchName . '/' : '') . $releaseName;
if(strpos($params, 'releasetag') !== false) $releaseName = $releaseName . " [{$this->lang->build->released}]";
$builds[$release->date][$release->shadow] = $releaseName;
foreach(explode(',', trim($release->build, ',')) as $buildID)
{
if(!isset($allBuilds[$buildID])) continue;
$build = $allBuilds[$buildID];
if(strpos($params, 'withreleased') === false) unset($builds[$build->date][$buildID]);
if(strpos($params, 'noreleased') !== false) unset($builds[$build->date][$buildID]);
}
}
}
@@ -346,21 +382,44 @@ class buildModel extends model
->setDefault('product', 0)
->setDefault('branch', 0)
->setDefault('builds', '')
->cleanInt('product,branch')
->cleanInt('product')
->add('createdBy', $this->app->user->account)
->add('createdDate', helper::now())
->stripTags($this->config->build->editor->create['id'], $this->config->allowedTags)
->join('builds', ',')
->join('branch', ',')
->remove('resolvedBy,allchecker,files,labels,isIntegrated,uid')
->get();
if($this->post->isIntegrated == 'yes') $build->execution = 0;
if($this->post->isIntegrated == 'yes')
{
$build->execution = 0;
$branchPairs = $this->dao->select('branch')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchPairs();
$relationBranch = array();
foreach($branchPairs as $branches)
{
foreach(explode(',', $branches) as $branch)
{
if(!isset($relationBranch[$branch])) $relationBranch[$branch] = $branch;
}
}
$build->branch = implode(',', $relationBranch);
}
$product = $this->loadModel('product')->getByID($build->product);
if($product->type != 'normal' and $this->post->isIntegrated == 'no' and !isset($_POST['branch']))
{
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
dao::$errors['branch'] = sprintf($this->lang->error->notempty, $this->lang->product->branch);
}
if(dao::isError()) return false;
$build = $this->loadModel('file')->processImgURL($build, $this->config->build->editor->create['id'], $this->post->uid);
$this->dao->insert(TABLE_BUILD)->data($build)
->autoCheck()
->batchCheck($this->config->build->create->requiredFields, 'notempty')
->check('name', 'unique', "product = {$build->product} AND branch = {$build->branch} AND deleted = '0'")
->check('name', 'unique', "product = {$build->product} AND branch = '{$build->branch}' AND deleted = '0'")
->checkFlow()
->exec();
@@ -390,17 +449,27 @@ class buildModel extends model
->setIF(!isset($_POST['branch']), 'branch', $oldBuild->branch)
->setDefault('product', $oldBuild->product)
->setDefault('builds', '')
->cleanInt('product,branch,execution')
->cleanInt('product,execution')
->join('builds', ',')
->join('branch', ',')
->remove('allchecker,resolvedBy,files,labels,uid')
->get();
$product = $this->loadModel('product')->getByID($build->product);
if($product->type != 'normal' and $this->post->isIntegrated == 'no' and !isset($_POST['branch']))
{
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
dao::$errors['branch'] = sprintf($this->lang->error->notempty, $this->lang->product->branch);
}
if(dao::isError()) return false;
$build = $this->loadModel('file')->processImgURL($build, $this->config->build->editor->edit['id'], $this->post->uid);
$this->dao->update(TABLE_BUILD)->data($build)
->autoCheck()
->batchCheck($this->config->build->edit->requiredFields, 'notempty')
->where('id')->eq($buildID)
->check('name', 'unique', "id != $buildID AND product = {$build->product} AND branch = {$build->branch} AND deleted = '0'")
->check('name', 'unique', "id != $buildID AND product = {$build->product} AND branch = '{$build->branch}' AND deleted = '0'")
->checkFlow()
->exec();
if(isset($build->branch) and $oldBuild->branch != $build->branch) $this->dao->update(TABLE_RELEASE)->set('branch')->eq($build->branch)->where('build')->eq($buildID)->exec();
@@ -592,8 +661,8 @@ class buildModel extends model
{
$build->allBugs = $build->bugs;
$build->allStories = $build->stories;
$childBuilds = $this->dao->select('bugs, stories')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchAll();
$childBuilds = $this->dao->select('id,name,bugs,stories')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchAll();
foreach($childBuilds as $childBuild)
{
if($childBuild->bugs) $build->allBugs .= ",{$childBuild->bugs}";
@@ -621,7 +690,7 @@ class buildModel extends model
{
$action = strtolower($action);
if($module == 'testtask' && $action == 'create') return !!$object->execution;
if($module == 'testtask' and $action == 'create') return !$object->executionDeleted;
return true;
}
@@ -651,11 +720,14 @@ class buildModel extends model
{
$executionID = $tab == 'execution' ? $extraParams['executionID'] : $build->execution;
$execution = $this->loadModel('execution')->getByID($executionID);
$build->executionDeleted = $execution ? $execution->deleted : 0;
$testtaskApp = (!empty($execution->type) and $execution->type == 'kanban') ? 'data-app="qa"' : "data-app='{$tab}'";
if(common::hasPriv($module, 'linkstory') and common::canBeChanged('build', $build)) $menu .= $this->buildMenu($module, 'view', "{$params}&type=story&link=true", $build, $type, 'link', '', '', '', "data-app={$tab}", $this->lang->build->linkStory);
$menu .= $this->buildMenu('testtask', 'create', "product=$build->product&execution={$executionID}&build=$build->id&projectID=$build->project", $build, $type, 'bullhorn', '', '', '', $testtaskApp);
$title = ($execution and $execution->deleted === '1') ? $this->lang->build->notice->createTest : '';
$menu .= $this->buildMenu('testtask', 'create', "product=$build->product&execution={$executionID}&build=$build->id&projectID=$build->project", $build, $type, 'bullhorn', '', '', '', $testtaskApp, $title);
if($tab == 'execution' and !empty($execution->type) and $execution->type != 'kanban') $menu .= $this->buildMenu('execution', 'bug', "execution={$extraParams['executionID']}&productID={$extraParams['productID']}&branchID=all&orderBy=status&build=$build->id", $build, $type, '', '', '', '', $this->lang->execution->viewBug);
if($tab == 'project' or empty($execution->type) or $execution->type == 'kanban') $menu .= $this->buildMenu($module, 'view', "{$params}&type=generatedBug", $build, $type, 'bug', '', '', '', "data-app='$tab'", $this->lang->project->bug);
+8 -6
View File
@@ -33,12 +33,6 @@
<td>
<div class='input-group' id='productBox'>
<?php echo html::select('product', $products, empty($product) ? '' : $product->id, "onchange='loadBranches(this.value);' class='form-control chosen' required");?>
<?php
if(!empty($product) and $product->type != 'normal')
{
echo "<span class='input-group-addon fix-padding fix-border'></span>" . html::select('branch', $branches, key($product->branches), "class='form-control chosen'");
}
?>
</div>
</td>
<?php else:?>
@@ -50,6 +44,14 @@
<?php endif;?>
<td></td>
</tr>
<tr class='<?php if(!empty($product) and $product->type == 'normal') echo 'hidden'?>'>
<th class='w-120px'><?php echo $product->type == 'normal' ? '' : $lang->product->branchName[$product->type]?></th>
<td>
<div class='input-group' id='branchBox'>
<?php echo html::select('branch[]', $branches, key($product->branches), "class='form-control chosen' multiple required"); ?>
</div>
</td>
</tr>
<tr class='hide'>
<th class='w-120px'><?php echo $lang->build->builds;?></th>
<td id='buildBox'><?php echo html::select('builds[]', array(), '', "class='form-control chosen' multiple data-placeholder='{$lang->build->placeholder->multipleSelect}'");?></td>
+9 -6
View File
@@ -32,16 +32,19 @@
?>
<div class='input-group'>
<?php echo html::select('product', $products, $build->product, "onchange='loadBranches(this.value);' class='form-control chosen' $disabled required");?>
<?php
if($build->productType != 'normal')
{
echo "<span class='input-group-addon fix-padding fix-border'></span>" . html::select('branch', $branchTagOption, $build->branch, "class='form-control chosen' $disabled");
}
?>
</div>
</td>
<td><?php if($disabled) echo $lang->build->notice->changeProduct;?></td>
</tr>
<tr>
<tr class='<?php if(!empty($product) and $product->type == 'normal') echo 'hidden'?>'>
<th class='w-120px'><?php echo $product->type == 'normal' ? '' : $lang->product->branchName[$product->type]?></th>
<td>
<div class='input-group' id='branchBox'>
<?php echo html::select('branch[]', $branchTagOption, $build->branch, "class='form-control chosen' multiple required $disabled"); ?>
</div>
</td>
</tr>
<?php $disabled = $testtaskID ? 'disabled' : '';?>
<?php if(!$build->execution):?>
<tr>
+55 -5
View File
@@ -26,7 +26,11 @@ tbody tr td:first-child input {display: none;}
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php $browseLink = $this->session->buildList ? $this->session->buildList : $this->createLink('execution', 'build', "executionID=$build->execution");?>
<?php common::printBack($browseLink, 'btn btn-secondary');?>
<?php
$dataApp = strpos($browseLink, 'release') !== false ? 'data-app=product' : '';
if(strpos($browseLink, 'projectrelease') !== false) $dataApp = 'data-app=project';
?>
<?php common::printBack($browseLink, 'btn btn-secondary', $dataApp);?>
<div class='divider'></div>
<div class='page-title'>
<span title='<?php echo $build->name;?>'>
@@ -84,8 +88,11 @@ tbody tr td:first-child input {display: none;}
<?php endif;?>
<?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?>
</th>
<th class='c-id' title=<?php echo $lang->pri;?>><?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
<th class='c-pri' title=<?php echo $lang->pri;?>><?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
<th class='text-left'><?php common::printOrderLink('title', $orderBy, $vars, $lang->story->title);?></th>
<?php if($childBuilds):?>
<th class='c-build w-200px text-left'><?php echo $lang->build->common;?></th>
<?php endif;?>
<th class='c-user'><?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='c-id text-right'><?php common::printOrderLink('estimate', $orderBy, $vars, $lang->story->estimateAB);?></th>
<th class='c-status'><?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
@@ -95,7 +102,21 @@ tbody tr td:first-child input {display: none;}
</thead>
<tbody class='text-center'>
<?php foreach($stories as $storyID => $story):?>
<?php $unlinkClass = strpos(",$build->stories,", ",$story->id,") !== false ? '' : "disabled";?>
<?php
$unlinkClass = strpos(",$build->stories,", ",$story->id,") !== false ? '' : "disabled";
$buildName = $build->name;
if($unlinkClass == 'disabled')
{
foreach($childBuilds as $childBuild)
{
if(strpos(",$childBuild->stories,", ",$story->id,") !== false)
{
$buildName = $childBuild->name;
break;
}
}
}
?>
<tr>
<td class='c-id text-left'>
<?php if($canBatchUnlink):?>
@@ -126,6 +147,9 @@ tbody tr td:first-child input {display: none;}
}
?>
</td>
<?php if($childBuilds):?>
<td class='c-build text-left' title='<?php echo $buildName?>'><?php echo $buildName;?></td>
<?php endif;?>
<td><?php echo zget($users, $story->openedBy);?></td>
<td class='text-right' title="<?php echo $story->estimate . ' ' . $lang->hourCommon;?>"><?php echo $story->estimate . $config->hourUnit;?></td>
<td>
@@ -186,6 +210,9 @@ tbody tr td:first-child input {display: none;}
</th>
<th class='text-left'> <?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
<th class='c-status'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
<?php if($childBuilds):?>
<th class='c-build w-200px text-left'><?php echo $lang->build->common?></th>
<?php endif;?>
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='c-date'> <?php common::printOrderLink('openedDate', $orderBy, $vars, $lang->bug->openedDateAB);?></th>
<th class='c-user'> <?php common::printOrderLink('resolvedBy', $orderBy, $vars, $lang->bug->resolvedByAB);?></th>
@@ -195,8 +222,22 @@ tbody tr td:first-child input {display: none;}
</thead>
<tbody class='text-center'>
<?php foreach($bugs as $bug):?>
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bug->id", '', true);?>
<?php $unlinkClass = strpos(",$build->bugs,", ",$bug->id,") !== false ? '' : "disabled";?>
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bug->id", '', true);?>
<?php
$unlinkClass = strpos(",$build->bugs,", ",$bug->id,") !== false ? '' : "disabled";
$buildName = $build->name;
if($unlinkClass == 'disabled')
{
foreach($childBuilds as $childBuild)
{
if(strpos(",$childBuild->bugs,", ",$bug->id,") !== false)
{
$buildName = $childBuild->name;
break;
}
}
}
?>
<tr>
<td class='c-id text-left'>
<?php if($canBatchUnlink):?>
@@ -212,6 +253,9 @@ tbody tr td:first-child input {display: none;}
<?php echo $this->processStatus('bug', $bug);?>
</span>
</td>
<?php if($childBuilds):?>
<td class='c-build text-left' title='<?php echo $buildName?>'><?php echo $buildName;?></td>
<?php endif;?>
<td><?php echo zget($users, $bug->openedBy);?></td>
<td><?php echo helper::isZeroDate($bug->openedDate) ? '' : substr($bug->openedDate, 5, 11);?></td>
<td><?php echo zget($users, $bug->resolvedBy);?></td>
@@ -257,6 +301,7 @@ tbody tr td:first-child input {display: none;}
<th class='c-status' title=<?php echo $lang->bug->severity;?>><?php common::printOrderLink('severity', $orderBy, $vars, $lang->bug->severityAB);?></th>
<th class='text-left'><?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
<th class='c-status'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
<th class='c-build w-200px text-left'><?php echo $lang->bug->openedBuild;?></th>
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='c-date'> <?php common::printOrderLink('openedDate', $orderBy, $vars, $lang->bug->openedDateAB);?></th>
<th class='c-user'> <?php common::printOrderLink('resolvedBy', $orderBy, $vars, $lang->bug->resolvedByAB);?></th>
@@ -294,6 +339,11 @@ tbody tr td:first-child input {display: none;}
<?php echo $this->processStatus('bug', $bug);?>
</span>
</td>
<?php
$openedBuilds = '';
foreach(explode(',', $bug->openedBuild) as $buildID) $openedBuilds .= ($buildID == 'trunk' ? 'Trunk' : zget($buildPairs, $buildID, '')) . ' ';
?>
<td class='c-build text-left' title='<?php echo $openedBuilds;?>'><?php echo $openedBuilds;?></td>
<td><?php echo zget($users, $bug->openedBy);?></td>
<td><?php echo helper::isZeroDate($bug->openedDate) ? '' : substr($bug->openedDate, 5, 11);?></td>
<td><?php echo zget($users, $bug->resolvedBy);?></td>
+2
View File
@@ -2365,6 +2365,8 @@ EOD;
*/
public function checkSafeFile()
{
if($this->app->isContainer()) return false;
if($this->app->getModuleName() == 'upgrade' and $this->session->upgrading) return false;
$statusFile = $this->app->getAppRoot() . 'www' . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'ok.txt';
+1
View File
@@ -249,6 +249,7 @@ $lang->doc->errorEmptyLib = 'No data in document library.';
$lang->doc->confirmUpdateContent = 'You have a document that is not saved from last time. Do you want to continue editing it?';
$lang->doc->selectLibType = 'Please select a type of doc library.';
$lang->doc->noLibreOffice = 'You does not have access to office conversion settings!';
$lang->doc->errorParentChapter = 'The parent chapter cannot be its own chapter or sub chapter!';
$lang->doc->noticeAcl['lib']['product']['default'] = 'Users who can access the selected product can access it.';
$lang->doc->noticeAcl['lib']['product']['custom'] = 'Users who can access the selected product or users in the whiltelist can access it.';
+1
View File
@@ -249,6 +249,7 @@ $lang->doc->errorEmptyLib = 'No data in document library.';
$lang->doc->confirmUpdateContent = 'You have a document that is not saved from last time. Do you want to continue editing it?';
$lang->doc->selectLibType = 'Please select a type of doc library.';
$lang->doc->noLibreOffice = 'You does not have access to office conversion settings!';
$lang->doc->errorParentChapter = 'The parent chapter cannot be its own chapter or sub chapter!';
$lang->doc->noticeAcl['lib']['product']['default'] = 'Users who can access the selected product can access it.';
$lang->doc->noticeAcl['lib']['product']['custom'] = 'Users who can access the selected product or users in the whiltelist can access it.';
+1
View File
@@ -249,6 +249,7 @@ $lang->doc->errorEmptyLib = 'No data in document library.';
$lang->doc->confirmUpdateContent = 'You have a document that is not saved from last time. Do you want to continue editing it?';
$lang->doc->selectLibType = 'Please select a type of doc library.';
$lang->doc->noLibreOffice = 'You does not have access to office conversion settings!';
$lang->doc->errorParentChapter = 'The parent chapter cannot be its own chapter or sub chapter!';
$lang->doc->noticeAcl['lib']['product']['default'] = 'Les utilisateurs qui ont accès au Product peuvent y accéder.';
$lang->doc->noticeAcl['lib']['product']['custom'] = 'Les utilisateurs qui ont accès au Product ou les utilisateurs de la Liste Blanche peuvent y accéder.';
+1
View File
@@ -249,6 +249,7 @@ $lang->doc->errorEmptyLib = '文档库暂无数据。';
$lang->doc->confirmUpdateContent = '检查到您有未保存的文档内容,是否继续编辑?';
$lang->doc->selectLibType = '请选择文档库类型';
$lang->doc->noLibreOffice = '您还没有office转换设置访问权限!';
$lang->doc->errorParentChapter = '父章节不能是自身章节及子章节!';
$lang->doc->noticeAcl['lib']['product']['default'] = '有所选产品访问权限的用户可以访问。';
$lang->doc->noticeAcl['lib']['product']['custom'] = '有所选产品访问权限或白名单里的用户可以访问。';
+10
View File
@@ -821,6 +821,16 @@ class docModel extends model
->remove('comment,files,labels,uid,contactListMenu')
->get();
if($doc->type == 'chapter' and $doc->parent)
{
$parentDoc = $this->dao->select('*')->from(TABLE_DOC)->where('id')->eq((int)$doc->parent)->fetch();
if(strpos($parentDoc->path, ",$docID,") !== false)
{
dao::$errors['parent'] = $this->lang->doc->errorParentChapter;
return false;
}
}
if(!empty($doc->acl) and $doc->acl == 'private') $doc->users = $oldDoc->addedBy;
$oldDocContent = $this->dao->select('*')->from(TABLE_DOCCONTENT)->where('doc')->eq($docID)->andWhere('version')->eq($oldDoc->version)->fetch();
+1 -1
View File
@@ -84,7 +84,7 @@
<?php if(common::hasPriv('doc', 'collect')):?>
<a data-url="<?php echo $this->createLink('doc', 'collect', "objectID=$doc->id&objectType=doc");?>" title="<?php echo $collectTitle;?>" class='btn btn-link ajaxCollect'><i class='icon <?php echo $star;?>'></i></a>
<?php endif;?>
<?php common::printLink('doc', 'edit', "docID=$doc->id&comment=false", "<i class='icon icon-edit'></i>", '', "title='{$lang->edit}' class='btn btn-link iframe'", true, true)?>
<?php common::printLink('doc', 'edit', "docID=$doc->id&comment=false", "<i class='icon icon-edit'></i>", '', "title='{$lang->edit}' class='btn btn-link'", true, false)?>
<?php common::printLink('doc', 'delete', "docID=$doc->id&confirm=no", "<i class='icon icon-trash'></i>", 'hiddenwin', "title='{$lang->delete}' class='btn btn-link'")?>
<?php endif;?>
</td>
+76 -36
View File
@@ -898,7 +898,7 @@ class execution extends control
$storyBugs = $this->loadModel('bug')->getStoryBugCounts($storyIdList, $executionID);
$storyCases = $this->loadModel('testcase')->getStoryCaseCounts($storyIdList);
$plans = $this->execution->getPlans($products, 'skipParent|withMainPlan');
$plans = $this->execution->getPlans($products, 'skipParent|withMainPlan', $executionID);
$allPlans = array('' => '');
if(!empty($plans))
{
@@ -1097,7 +1097,7 @@ class execution extends control
$modules = $this->tree->getAllModulePairs('bug');
/* Get module tree.*/
$extra = array('executionID' => $executionID, 'orderBy' => $orderBy, 'type' => $type, 'build' => $build, 'branchID' => $branch);
$extra = array('projectID' => $executionID, 'orderBy' => $orderBy, 'type' => $type, 'build' => $build, 'branchID' => $branch);
if($executionID and empty($productID) and count($products) > 1)
{
$moduleTree = $this->tree->getBugTreeMenu($executionID, $productID, 0, array('treeModel', 'createBugLink'), $extra);
@@ -1205,7 +1205,7 @@ class execution extends control
}
else
{
$moduleTree = $this->tree->getTreeMenu($productID, 'case', 0, array('treeModel', 'createCaseLink'), array('executionID' => $executionID, 'productID' => $productID), $branchID);
$moduleTree = $this->tree->getTreeMenu($productID, 'case', 0, array('treeModel', 'createCaseLink'), array('projectID' => $executionID, 'productID' => $productID), $branchID);
}
$tree = $moduleID ? $this->tree->getByID($moduleID) : '';
@@ -1298,21 +1298,26 @@ class execution extends control
/* Set execution builds. */
$executionBuilds = array();
$productList = $this->product->getProducts($executionID);
$this->app->loadLang('branch');
$showBranch = false;
if(!empty($builds))
{
foreach($builds as $build) $executionBuilds[$build->product][] = $build;
/* Get branch name. */
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($executionBuilds));
foreach($builds as $build)
{
/* If product is normal, unset branch name. */
if(isset($productList[$build->product]) and $productList[$build->product]->type == 'normal')
$build->branchName = '';
if(isset($branchGroups[$build->product]))
{
$build->branchName = '';
$showBranch = true;
$branchPairs = $branchGroups[$build->product];
foreach(explode(',', trim($build->branch, ',')) as $branchID)
{
if(isset($branchPairs[$branchID])) $build->branchName .= "{$branchPairs[$branchID]},";
}
$build->branchName = trim($build->branchName, ',');
}
else
{
$build->branchName = isset($build->branchName) ? $build->branchName : $this->lang->branch->main;
}
$executionBuilds[$build->product][] = $build;
}
}
@@ -1328,6 +1333,7 @@ class execution extends control
$this->view->product = $type == 'product' ? $param : 'all';
$this->view->products = $products;
$this->view->type = $type;
$this->view->showBranch = $showBranch;
$this->display();
}
@@ -1579,6 +1585,7 @@ class execution extends control
$execution = $this->commonAction($executionID);
$executionID = $execution->id;
$deptID = $this->app->user->admin ? 0 : $this->app->user->dept;
$title = $execution->name . $this->lang->colon . $this->lang->execution->team;
$position[] = html::a($this->createLink('execution', 'browse', "executionID=$executionID"), $execution->name);
@@ -1586,7 +1593,7 @@ class execution extends control
$this->view->title = $title;
$this->view->position = $position;
$this->view->deptUsers = $this->loadModel('dept')->getDeptUserPairs($this->app->user->dept, 'id');
$this->view->deptUsers = $this->loadModel('dept')->getDeptUserPairs($deptID, 'id');
$this->view->canBeChanged = common::canModify('execution', $execution); // Determines whether an object is editable.
$this->display();
@@ -1645,7 +1652,20 @@ class execution extends control
}
else
{
return print(js::confirm($this->lang->execution->importPlanStory, inlink('create', "projectID=$projectID&executionID=$executionID&copyExecutionID=&planID=$planID&confirm=yes"), inlink('create', "projectID=$projectID&executionID=$executionID")));
$executionProductList = $this->loadModel('product')->getProducts($executionID);
$multiBranchProduct = false;
foreach($executionProductList as $executionProduct)
{
if($executionProduct->type != 'normal')
{
$multiBranchProduct = true;
break;
}
}
$importPlanStoryTips = $multiBranchProduct ? $this->lang->execution->importBranchPlanStory : $this->lang->execution->importPlanStory;
return print(js::confirm($importPlanStoryTips, inlink('create', "projectID=$projectID&executionID=$executionID&copyExecutionID=&planID=$planID&confirm=yes"), inlink('create', "projectID=$projectID&executionID=$executionID")));
}
}
@@ -1689,10 +1709,11 @@ class execution extends control
$linkedBranches = array();
foreach($products as $productIndex => $product)
{
$productPlans[$productIndex] = array();
foreach($branches[$productIndex] as $branchID => $branch)
{
$linkedBranches[$productIndex][$branchID] = $branchID;
$productPlans[$productIndex][$branchID] = isset($plans[$productIndex][$branchID]) ? $plans[$productIndex][$branchID] : array();
$productPlans[$productIndex] += isset($plans[$productIndex][$branchID]) ? $plans[$productIndex][$branchID] : array();
}
}
@@ -1724,10 +1745,11 @@ class execution extends control
$linkedBranches = array();
foreach($products as $productIndex => $product)
{
$productPlans[$productIndex] = array();
foreach($branches[$productIndex] as $branchID => $branch)
{
$linkedBranches[$productIndex][$branchID] = $branchID;
$productPlans[$productIndex][$branchID] = isset($plans[$productIndex][$branchID]) ? $plans[$productIndex][$branchID] : array();
$productPlans[$productIndex] += isset($plans[$productIndex][$branchID]) ? $plans[$productIndex][$branchID] : array();
}
}
@@ -1776,27 +1798,15 @@ class execution extends control
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('doc', 'objectLibs', "type=execution")));
}
$planID = '';
if(isset($_POST['plans']))
{
foreach($_POST['plans'] as $plans)
{
foreach($plans as $planID)
{
if(!empty($planID)) break;
}
}
}
if(!empty($projectID) and $project->model == 'kanban')
{
$execution = $this->execution->getById($executionID);
$this->loadModel('kanban')->createRDKanban($execution);
}
if(!empty($planID))
if(!empty($_POST['plans']))
{
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('create', "projectID=$projectID&executionID=$executionID&copyExecutionID=&planID=$planID&confirm=no")));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('create', "projectID=$projectID&executionID=$executionID&copyExecutionID=&planID=1&confirm=no")));
}
else
{
@@ -1904,7 +1914,20 @@ class execution extends control
}
elseif(!empty($newPlans))
{
return print(js::confirm($this->lang->execution->importEditPlanStory, inlink('edit', "executionID=$executionID&action=edit&extra=&newPlans=$newPlans&confirm=yes"), inlink('view', "executionID=$executionID")));
$executionProductList = $this->loadModel('product')->getProducts($executionID);
$multiBranchProduct = false;
foreach($executionProductList as $executionProduct)
{
if($executionProduct->type != 'normal')
{
$multiBranchProduct = true;
break;
}
}
$importEditPlanStoryTips = $multiBranchProduct ? $this->lang->execution->importBranchEditPlanStory : $this->lang->execution->importEditPlanStory;
return print(js::confirm($importEditPlanStoryTips, inlink('edit', "executionID=$executionID&action=edit&extra=&newPlans=$newPlans&confirm=yes"), inlink('view', "executionID=$executionID")));
}
/* Set menu. */
@@ -2003,12 +2026,15 @@ class execution extends control
foreach($linkedProducts as $productID => $linkedProduct)
{
if(!isset($allProducts[$productID])) $allProducts[$productID] = $linkedProduct->name;
$productPlans[$productID] = array();
foreach($branches[$productID] as $branchID => $branch)
{
$productPlans[$productID] += isset($plans[$productID][$branchID]) ? $plans[$productID][$branchID] : array();
$linkedBranchList[$branchID] = $branchID;
$linkedBranches[$productID][$branchID] = $branchID;
$productPlans[$productID][$branchID] = isset($plans[$productID][$branchID]) ? $plans[$productID][$branchID] : array();
if($branchID != BRANCH_MAIN and isset($plans[$productID][BRANCH_MAIN])) $productPlans[$productID][$branchID] += $plans[$productID][BRANCH_MAIN];
if($branchID != BRANCH_MAIN and isset($plans[$productID][BRANCH_MAIN])) $productPlans[$productID] += $plans[$productID][BRANCH_MAIN];
if(!empty($executionStories[$productID][$branchID]))
{
array_push($unmodifiableProducts, $productID);
@@ -4121,9 +4147,11 @@ class execution extends control
$count = 0;
if(!empty($planStory))
{
$projectProducts = $this->loadModel('project')->getBranchesByProject($executionID);
foreach($planStory as $id => $story)
{
if($story->status == 'draft' or $story->status == 'reviewing')
$projectBranches = zget($projectProducts, $story->product, array());
if($story->status != 'active' or (!empty($story->branch) and !empty($projectBranches) and !isset($projectBranches[$story->branch])))
{
$count++;
unset($planStory[$id]);
@@ -4155,8 +4183,20 @@ class execution extends control
include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php';
}
$haveDraft = sprintf($this->lang->execution->haveDraft, $count);
if(!$execution->multiple) $haveDraft = str_replace($this->lang->executionCommon, $this->lang->projectCommon, $haveDraft);
$executionProductList = $this->loadModel('product')->getProducts($executionID);
$multiBranchProduct = false;
foreach($executionProductList as $executionProduct)
{
if($executionProduct->type != 'normal')
{
$multiBranchProduct = true;
break;
}
}
$importPlanStoryTips = $multiBranchProduct ? $this->lang->execution->haveBranchDraft : $this->lang->execution->haveDraft;
$haveDraft = sprintf($importPlanStoryTips, $count);
if(!$execution->multiple or $moduleName == 'projectstory') $haveDraft = str_replace($this->lang->executionCommon, $this->lang->projectCommon, $haveDraft);
if($count != 0) echo js::alert($haveDraft) . js::locate($this->createLink($moduleName, $fromMethod, $param));
return print(js::locate(helper::createLink($moduleName, $fromMethod, $param)));
}
+9 -3
View File
@@ -21,9 +21,9 @@
.chosen-container.chosen-highlight-selected .disabled-result.result-selected {background: none;}
#productsBox .row .col-sm-4 {padding-right: 13px;}
#plansBox .row {display: inline-table; width: 102%;}
#plansBox .row .col-sm-4 {display: inline-block; float: none; padding-right: 13px;}
.productsBox .row .col-sm-4 {padding-right: 13px;}
.plansBox .row {display: inline-table; width: 102%;}
.plansBox .row .col-sm-4 {display: inline-block; float: none; padding-right: 13px;}
#dateRange {vertical-align: top; padding-top: 13px;}
#dateRangeOption {vertical-align: top; padding-top: 13px;}
@@ -32,3 +32,9 @@
#copyProjectModal .projectSelect {display: inline-block; margin-left: 10px; width: 20%;}
#copyProjectModal .titleBox{position: relative; bottom: 3px; display: inline-block;}
a.chosen-single > div > b {top: -4px !important;}
.productsBox a {border-radius: 2px !important;}
.productsBox .required:after {right: -9.5px !important;}
.productsBox .input-group-addon > div {display: inline-block !important;}
.productsBox .required + .text-danger.help-text {position: relative; left: 10px;}
.productsBox > #productNameLabel {padding-top: 8px;}
+89 -74
View File
@@ -113,6 +113,15 @@ function computeEndDate(delta)
computeWorkDays();
}
/* Auto compute the work days. */
$(function()
{
$(".date").bind('dateSelected', function()
{
computeWorkDays(this.id);
})
});
/**
* Load branches.
*
@@ -122,118 +131,127 @@ function computeEndDate(delta)
*/
function loadBranches(product)
{
if($('#productsBox .input-group:last select:first').val() != 0)
/* When selecting a product, delete a plan that is empty by default. */
$("#planDefault").remove();
$(".productsBox select[name^='products']").each(function()
{
if(model !== 'waterfall')
var $product = $(product);
var productID = $(this).val();
if($product.val() != 0 && $product.val() == $(this).val() && $product.attr('id') != $(this).attr('id') && !multiBranchProducts[$product.val()])
{
var length = $('#productsBox .input-group').size();
$('#productsBox .row').append('<div class="col-sm-4">' + $('#productsBox .col-sm-4:last').html().replace('required', '') + '</div>');
if($('#productsBox .input-group:last select').size() >= 2) $('#productsBox .input-group:last select:last').remove();
$('#productsBox .input-group:last .chosen-container').remove();
$('#productsBox .input-group:last select:first').attr('name', 'products[' + length + ']').attr('id', 'products' + length);
$('#productsBox .input-group:last .chosen').chosen();
bootbox.alert(errorSameProducts);
$product.val(0);
$product.trigger("chosen:updated");
return false;
}
adjustProductBoxMargin();
});
var $tableRow = $(product).closest('.table-row');
var index = $tableRow.find('select:first').attr('id').replace('products' , '');
var oldBranch = $(product).attr('data-branch') !== undefined ? $(product).attr('data-branch') : 0;
if($(product).val() != 0)
{
$(product).closest('tr').find('.newProduct').addClass('hidden')
}
else
{
$(product).closest('tr').find('.newProduct').removeClass('hidden')
}
var $inputgroup = $(product).closest('.input-group');
if($inputgroup.find('select').size() >= 2) $inputgroup.removeClass('has-branch').find('select:last').remove();
if($inputgroup.find('.chosen-container').size() >= 2) $inputgroup.find('.chosen-container:last').remove();
if(!multiBranchProducts[$(product).val()])
{
$tableRow.find('.table-col:last select').val('').trigger('chosen:updated');
$tableRow.find('.table-col:last').addClass('hidden');
}
var projectID = $('#project').val();
if(typeof(projectID) == 'undefined') projectID = 0;
var index = $inputgroup.find('select:first').attr('id').replace('products' , '');
$.get(createLink('branch', 'ajaxGetBranches', "productID=" + $(product).val() + "&oldBranch=0&param=active&projectID=" + projectID + "&withMainBranch=true"), function(data)
$.get(createLink('branch', 'ajaxGetBranches', "productID=" + $(product).val() + "&oldBranch=" + oldBranch + "&param=active&projectID=" + projectID + "&withMainBranch=true"), function(data)
{
if(data)
{
$inputgroup.addClass('has-branch').append(data);
$inputgroup.find('select:last').attr('name', 'branch[' + index + ']').attr('id', 'branch' + index).attr('onchange', "loadPlans('#products" + index + "', this.value)").chosen();
$tableRow.find("select[name^='branch']").replaceWith(data);
$tableRow.find('.table-col:last .chosen-container').remove();
$tableRow.find('.table-col:last').removeClass('hidden');
$tableRow.find("select[name^='branch']").attr('multiple', '').attr('name', 'branch[' + index + '][]').attr('id', 'branch' + index).attr('onchange', "loadPlans('#products" + index + "', this)").chosen();
$inputgroup.find('select:last').each(disableSelectedBranch);
disableSelectedProduct();
}
var branchID = $('#branch' + index).val();
loadPlans(product, branchID);
var branch = $('#branch' + index);
loadPlans(product, branch);
});
if(!multiBranchProducts[$(product).val()]) disableSelectedProduct();
}
/**
* Load plans by product id.
* Load plans.
*
* @param int $product
* @param int $branchID
* @param obj $product
* @param obj $branchID
* @access public
* @return void
*/
function loadPlans(product, branchID)
function loadPlans(product, branch)
{
if($('#plansBox').size() == 0) return false;
var productID = $(product).val();
var branchID = typeof(branchID) == 'undefined' ? 0 : branchID;
var branchID = $(branch).val() == null ? 0 : '0,' + $(branch).val();
var planID = $(product).attr('data-plan') !== undefined ? $(product).attr('data-plan') : 0;
var index = $(product).attr('id').replace('products', '');
$.get(createLink('product', 'ajaxGetPlans', "productID=" + productID + '&branch=0,' + branchID + '&planID=0&fieldID&needCreate=&expired=noclosed,unexpired&param=skipParent,multiple'), function(data)
$.get(createLink('product', 'ajaxGetPlans', "productID=" + productID + '&branch=' + branchID + '&planID=' + planID + '&fieldID&needCreate=&expired=unexpired,noclosed&param=skipParent,multiple'), function(data)
{
if(data)
{
if($("div#plan" + index).size() == 0) $("#plansBox .row").append('<div class="col-sm-4" id="plan' + index + '"></div>');
$("div#plan" + index).html(data).find('select').attr('name', 'plans[' + productID + '][' + branchID + '][]').attr('id', 'plans' + productID).chosen();
adjustPlanBoxMargin();
$("div#plan" + index).find("select[name^='plans']").replaceWith(data);
$("div#plan" + index).find('.chosen-container').remove();
$("div#plan" + index).find('select').attr('name', 'plans[' + productID + ']' + '[]').attr('id', 'plans' + productID).chosen();
}
});
}
/**
* Adjust product box margin.
*
* Add new line for link product.
*
* @param obj $obj
* @access public
* @return void
*/
function adjustProductBoxMargin()
function addNewLine(obj)
{
var productRows = Math.ceil($('#productsBox > .row > .col-sm-4').length / 3);
if(productRows > 1)
var newLine = $(obj).closest('tr').clone();
var index = 0;
$(".productsBox select[name^='products']").each(function()
{
for(i = 1; i <= productRows - 1; i++)
{
$('#productsBox .col-sm-4:lt(' + (i * 3) + ')').css('margin-bottom', '10px');
}
}
}
var id = $(this).attr('id').replace('products' , '');
/**
* Adjust plan box margin.
*
* @access public
* @return void
*/
function adjustPlanBoxMargin()
{
var planRows = Math.ceil($('#plansBox > .row > .col-sm-4').length / 3);
if(planRows > 1)
{
for(j = 1; j <= planRows - 1; j++)
{
$('#plansBox .col-sm-4:lt(' + (j * 3) + ')').css('margin-bottom', '10px');
}
}
}
id = parseInt(id);
id ++;
/* Auto compute the work days. */
$(function()
{
$(".date").bind('dateSelected', function()
{
computeWorkDays(this.id);
index = id > index ? id : index;
})
});
newLine.find('.newProduct').remove();
newLine.find('.addProduct').remove();
newLine.addClass('newLine');
newLine.find('th').html('');
newLine.find('.removeLine').css('visibility', 'visible');
newLine.find('.chosen-container').remove();
newLine.find('.productsBox .table-col:last').addClass('hidden');
newLine.find("select[name^='products']").attr('name', 'products[' + index + ']').attr('id', 'products' + index).val('').chosen();
newLine.find("select[name^='plans']").attr('name', 'plans[' + index + '][' + 0 + '][]').chosen();
newLine.find("div[id^='plan']").attr('id', 'plan' + index);
$(obj).closest('tr').after(newLine);
var product = newLine.find("select[name^='products']");
var branch = newLine.find("select[name^='branch']");
loadPlans(product, branch);
disableSelectedProduct();
}
function removeLine(obj)
{
$(obj).closest('tr').remove();
disableSelectedProduct();
}
$(function()
{
@@ -247,9 +265,6 @@ $(function()
e.stopPropagation();
e.preventDefault();
});
adjustProductBoxMargin();
adjustPlanBoxMargin();
});
/**
+5 -3
View File
@@ -67,7 +67,8 @@ function renderUserAvatar(user, objectType, objectID, size, objectStatus)
if(objectType == 'bug' && !priv.canAssignBug) return $noPrivAvatar;
var realname = user.realname ? user.realname : user.account;
return objectStatus == 'closed' ? '' : $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + realname + '" href="' + link + '"/>').avatar({user: user});
var title = user.title ? user.title : realname;
return objectStatus == 'closed' ? '' : $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + title + '" href="' + link + '"/>').avatar({user: user});
}
/**
@@ -286,8 +287,9 @@ function renderTaskItem(item, $item, col)
{
var priHtml = '<span class="info info-pri' + (item.pri ? ' label-pri label-pri-' + item.pri : '') + '" title="' + item.pri + '">' + item.pri + '</span>';
var hoursHtml = scaleSize <= 1 && item.status != 'wait' ? ('<span class="info info-estimate text-muted">' + taskLang.leftAB + ' ' + item.left + 'h</span>') : ('<span class="info info-estimate text-muted">' + taskLang.estimateAB + ' ' + item.estimate + 'h</span>');
var avatarHtml = renderUserAvatar(item.assignedTo, 'task', item.id, '', col.type);
var avatarHtml = '';
if(item.assignedTo == '' && item.mode == 'multi') avatarHtml = renderUserAvatar({title: item.teamMembers, realname: teamWords}, 'task', item.id, '', col.type);
else avatarHtml = renderUserAvatar(item.assignedTo, 'task', item.id, '', col.type);
var $infos = $item.find('.infos');
if(!$infos.length) $infos = $('<div class="infos"></div>');
$infos.html([priHtml, hoursHtml].join(''));
+83 -78
View File
@@ -209,82 +209,84 @@ $lang->execution->burnByList['estimate'] = "View by plan hours";
$lang->execution->burnByList['storyPoint'] = 'View by story point';
/* Method list. */
$lang->execution->index = "Home";
$lang->execution->task = 'Aufgaben';
$lang->execution->groupTask = 'Nach Gruppen';
$lang->execution->story = 'Storys';
$lang->execution->qa = 'QA';
$lang->execution->bug = 'Bugs';
$lang->execution->testcase = 'Testcase List';
$lang->execution->dynamic = 'Verlauf';
$lang->execution->latestDynamic = 'Letzter Verlauf';
$lang->execution->build = 'Builds';
$lang->execution->testtask = 'Testaufgaben';
$lang->execution->burn = 'Burndown';
$lang->execution->computeBurn = 'Aktualisieren';
$lang->execution->CFD = 'Cumulative Flow diagrams';
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
$lang->execution->burnData = 'Burndown Daten';
$lang->execution->fixFirst = 'Bearbeite Mannstunden des ersten Tags';
$lang->execution->team = 'Teammitglieder';
$lang->execution->doc = 'Dok';
$lang->execution->doclib = 'Dok Bibliothek';
$lang->execution->manageProducts = 'Verküpfe ' . $lang->productCommon;
$lang->execution->linkStory = 'Link Stories';
$lang->execution->linkStoryByPlan = 'Verküpfe Story aus Plan';
$lang->execution->linkPlan = 'Verküpfe Plan';
$lang->execution->unlinkStoryTasks = 'Verknüpfung aufheben';
$lang->execution->linkedProducts = 'Verküpfte Produkte';
$lang->execution->unlinkedProducts = 'Produkt verknüpfung aufheben';
$lang->execution->view = "Übersicht";
$lang->execution->startAction = "Start Execution";
$lang->execution->activateAction = "Activate Execution";
$lang->execution->delayAction = "Delay Execution";
$lang->execution->suspendAction = "Suspend Execution";
$lang->execution->closeAction = "Close Execution";
$lang->execution->testtaskAction = "Execution Request";
$lang->execution->teamAction = "Execution Members";
$lang->execution->kanbanAction = "Execution Kanban";
$lang->execution->printKanbanAction = "Print Kanban";
$lang->execution->treeAction = "Execution Tree View";
$lang->execution->exportAction = "Export Execution";
$lang->execution->computeBurnAction = "Compute Burn";
$lang->execution->create = "Erstelle Projekt";
$lang->execution->createExec = "Create Execution";
$lang->execution->createAction = "Create {$lang->execution->common}";
$lang->execution->copyExec = "Copy Execution";
$lang->execution->copy = "Kopiere {$lang->executionCommon}";
$lang->execution->delete = "Lösche";
$lang->execution->deleteAB = "Lösche Execution";
$lang->execution->browse = "Durchsuchen";
$lang->execution->edit = "Bearbeiten";
$lang->execution->editAction = "Edit Execution";
$lang->execution->batchEdit = "Mehere bearbeiten";
$lang->execution->batchEditAction = "Batch Edit";
$lang->execution->manageMembers = 'Teams verwalten';
$lang->execution->unlinkMember = 'Mitgliefer entfernen';
$lang->execution->unlinkStory = 'Story entfernen';
$lang->execution->unlinkStoryAB = 'Unlink';
$lang->execution->batchUnlinkStory = 'Mehere Storys entfernen';
$lang->execution->importTask = 'Importiere Aufgaben';
$lang->execution->importPlanStories = 'Verknüpfe Story aus Plan';
$lang->execution->importBug = 'Importiere Bugs';
$lang->execution->tree = 'Baum';
$lang->execution->treeTask = 'Aufgabe anzeigen';
$lang->execution->treeStory = 'Story anzeigen';
$lang->execution->treeViewTask = 'Tree View Task';
$lang->execution->treeViewStory = 'Tree View Story';
$lang->execution->storyKanban = 'Story Kanban';
$lang->execution->storySort = 'Story sortieren';
$lang->execution->importPlanStory = '' . $lang->executionCommon . ' wurde erstellt!\nMöchten Sie Storys aus dem Plan importieren?';
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
$lang->execution->iteration = 'Iteration';
$lang->execution->iterationInfo = '%s Iterationen';
$lang->execution->viewAll = 'Alle anzeigen';
$lang->execution->testreport = 'Test Report';
$lang->execution->taskKanban = 'Task Kanban';
$lang->execution->RDKanban = 'Research & Development Kanban';
$lang->execution->index = "Home";
$lang->execution->task = 'Aufgaben';
$lang->execution->groupTask = 'Nach Gruppen';
$lang->execution->story = 'Storys';
$lang->execution->qa = 'QA';
$lang->execution->bug = 'Bugs';
$lang->execution->testcase = 'Testcase List';
$lang->execution->dynamic = 'Verlauf';
$lang->execution->latestDynamic = 'Letzter Verlauf';
$lang->execution->build = 'Builds';
$lang->execution->testtask = 'Testaufgaben';
$lang->execution->burn = 'Burndown';
$lang->execution->computeBurn = 'Aktualisieren';
$lang->execution->CFD = 'Cumulative Flow diagrams';
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
$lang->execution->burnData = 'Burndown Daten';
$lang->execution->fixFirst = 'Bearbeite Mannstunden des ersten Tags';
$lang->execution->team = 'Teammitglieder';
$lang->execution->doc = 'Dok';
$lang->execution->doclib = 'Dok Bibliothek';
$lang->execution->manageProducts = 'Verküpfe ' . $lang->productCommon;
$lang->execution->linkStory = 'Link Stories';
$lang->execution->linkStoryByPlan = 'Verküpfe Story aus Plan';
$lang->execution->linkPlan = 'Verküpfe Plan';
$lang->execution->unlinkStoryTasks = 'Verknüpfung aufheben';
$lang->execution->linkedProducts = 'Verküpfte Produkte';
$lang->execution->unlinkedProducts = 'Produkt verknüpfung aufheben';
$lang->execution->view = "Übersicht";
$lang->execution->startAction = "Start Execution";
$lang->execution->activateAction = "Activate Execution";
$lang->execution->delayAction = "Delay Execution";
$lang->execution->suspendAction = "Suspend Execution";
$lang->execution->closeAction = "Close Execution";
$lang->execution->testtaskAction = "Execution Request";
$lang->execution->teamAction = "Execution Members";
$lang->execution->kanbanAction = "Execution Kanban";
$lang->execution->printKanbanAction = "Print Kanban";
$lang->execution->treeAction = "Execution Tree View";
$lang->execution->exportAction = "Export Execution";
$lang->execution->computeBurnAction = "Compute Burn";
$lang->execution->create = "Erstelle Projekt";
$lang->execution->createExec = "Create Execution";
$lang->execution->createAction = "Create {$lang->execution->common}";
$lang->execution->copyExec = "Copy Execution";
$lang->execution->copy = "Kopiere {$lang->executionCommon}";
$lang->execution->delete = "Lösche";
$lang->execution->deleteAB = "Lösche Execution";
$lang->execution->browse = "Durchsuchen";
$lang->execution->edit = "Bearbeiten";
$lang->execution->editAction = "Edit Execution";
$lang->execution->batchEdit = "Mehere bearbeiten";
$lang->execution->batchEditAction = "Batch Edit";
$lang->execution->manageMembers = 'Teams verwalten';
$lang->execution->unlinkMember = 'Mitgliefer entfernen';
$lang->execution->unlinkStory = 'Story entfernen';
$lang->execution->unlinkStoryAB = 'Unlink';
$lang->execution->batchUnlinkStory = 'Mehere Storys entfernen';
$lang->execution->importTask = 'Importiere Aufgaben';
$lang->execution->importPlanStories = 'Verknüpfe Story aus Plan';
$lang->execution->importBug = 'Importiere Bugs';
$lang->execution->tree = 'Baum';
$lang->execution->treeTask = 'Aufgabe anzeigen';
$lang->execution->treeStory = 'Story anzeigen';
$lang->execution->treeViewTask = 'Tree View Task';
$lang->execution->treeViewStory = 'Tree View Story';
$lang->execution->storyKanban = 'Story Kanban';
$lang->execution->storySort = 'Story sortieren';
$lang->execution->importPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->importBranchPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
$lang->execution->importBranchEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
$lang->execution->iteration = 'Iteration';
$lang->execution->iterationInfo = '%s Iterationen';
$lang->execution->viewAll = 'Alle anzeigen';
$lang->execution->testreport = 'Test Report';
$lang->execution->taskKanban = 'Task Kanban';
$lang->execution->RDKanban = 'Research & Development Kanban';
/* Group browsing. */
$lang->execution->allTasks = 'Alle';
@@ -345,11 +347,12 @@ $lang->execution->timeSummary = '<div class="table-col"><div class="cle
$lang->execution->groupSummaryAB = "<div>Aufgaben <strong>%s</strong></div><div><span class='text-muted'>Wartend</span> %s &nbsp; <span class='text-muted'>In Arbeit</span> %s</div><div>Geplant <strong>%s</strong></div><div><span class='text-muted'>Genutzt</span> %s &nbsp; <span class='text-muted'>Rest</span> %s</div>";
$lang->execution->wbs = "Aufgaben aufteilen";
$lang->execution->batchWBS = "Mehrere aufteilen";
$lang->execution->howToUpdateBurn = "<a href='http://api.zentao.net/goto.php?item=burndown&lang=zh-cn' target='_blank' title='Wie wird der Burndown Chart aktualisiert?' class='btn btn-link'>Hilfe <i class='icon icon-help'></i></a>";
$lang->execution->howToUpdateBurn = "<a href='https://api.zentao.pm/goto.php?item=burndown' target='_blank' title='Wie wird der Burndown Chart aktualisiert?' class='btn btn-link'>Hilfe <i class='icon icon-help'></i></a>";
$lang->execution->whyNoStories = "Keine Story kann verknüpft werden. Bitte prüfen Sie ob ein Story mit {$lang->executionCommon} verknüpft ist {$lang->productCommon} und stellen Sie sicher das diese geprüft ist.";
$lang->execution->projectNoStories = "No story can be linked. Please check whether there is any story in project and make sure it has been reviewed.";
$lang->execution->productStories = "{$lang->executionCommon} verknüpfte Story ist ein Subset von {$lang->productCommon}, welche nur nach überprüfung verknüpft werden kann. Bitte <a href='%s'> Story verknüpfen</a>。";
$lang->execution->haveDraft = "There are %s draft stories can't be linked.";
$lang->execution->haveBranchDraft = "There are %s draft stories or not associated with this {$lang->executionCommon} can't be linked.";
$lang->execution->haveDraft = "There are %s draft stories with this {$lang->executionCommon} can't be linked.";
$lang->execution->doneExecutions = 'Erledigt';
$lang->execution->selectDept = 'Abteilung wählen';
$lang->execution->selectDeptTitle = 'Abteilung wählen';
@@ -478,6 +481,8 @@ $lang->execution->kanbanViewList['story'] = "{$lang->SRCommon}";
$lang->execution->kanbanViewList['bug'] = 'Bug';
$lang->execution->kanbanViewList['task'] = 'Task';
$lang->execution->teamWords = 'Team';
$lang->kanbanSetting = new stdclass();
$lang->kanbanSetting->noticeReset = 'Möchten Sie die Einstellungen des Kanbans zurücksetzen?';
$lang->kanbanSetting->optionList['0'] = 'Verstecken';
+82 -77
View File
@@ -209,82 +209,84 @@ $lang->execution->burnByList['estimate'] = "View by plan hours";
$lang->execution->burnByList['storyPoint'] = 'View by story point';
/* Method list. */
$lang->execution->index = "{$lang->executionCommon} Home";
$lang->execution->task = 'Task List';
$lang->execution->groupTask = 'Group View';
$lang->execution->story = 'Story List';
$lang->execution->qa = 'QA';
$lang->execution->bug = 'Bug List';
$lang->execution->testcase = 'Testcase List';
$lang->execution->dynamic = 'Dynamics';
$lang->execution->latestDynamic = 'Dynamics';
$lang->execution->build = 'Build List';
$lang->execution->testtask = 'Request';
$lang->execution->burn = 'Burndown';
$lang->execution->computeBurn = 'Update';
$lang->execution->CFD = 'Cumulative Flow diagrams';
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
$lang->execution->burnData = 'Burndown Data';
$lang->execution->fixFirst = 'Edit 1st-Day Estimates';
$lang->execution->team = 'Members';
$lang->execution->doc = 'Document';
$lang->execution->doclib = 'Docoment Library';
$lang->execution->manageProducts = 'Linked ' . $lang->productCommon . 's';
$lang->execution->linkStory = 'Link Stories';
$lang->execution->linkStoryByPlan = 'Link Stories By Plan';
$lang->execution->linkPlan = 'Linked Plan';
$lang->execution->unlinkStoryTasks = 'Unlink';
$lang->execution->linkedProducts = "Linked {$lang->productCommon}s";
$lang->execution->unlinkedProducts = "Unlinked {$lang->productCommon}s";
$lang->execution->view = "Execution Detail";
$lang->execution->startAction = "Start Execution";
$lang->execution->activateAction = "Activate Execution";
$lang->execution->delayAction = "Delay Execution";
$lang->execution->suspendAction = "Suspend Execution";
$lang->execution->closeAction = "Close Execution";
$lang->execution->testtaskAction = "Execution Request";
$lang->execution->teamAction = "Execution Members";
$lang->execution->kanbanAction = "Execution Kanban";
$lang->execution->printKanbanAction = "Print Kanban";
$lang->execution->treeAction = "Execution Tree View";
$lang->execution->exportAction = "Export Execution";
$lang->execution->computeBurnAction = "Update Burndown";
$lang->execution->create = "Create {$lang->executionCommon}";
$lang->execution->createExec = "Create {$lang->execution->common}";
$lang->execution->createAction = "Create {$lang->execution->common}";
$lang->execution->copyExec = "Copy {$lang->execution->common}";
$lang->execution->copy = "Copy {$lang->executionCommon}";
$lang->execution->delete = "Delete {$lang->executionCommon}";
$lang->execution->deleteAB = "Delete Execution";
$lang->execution->browse = "{$lang->executionCommon} List";
$lang->execution->edit = "Edit {$lang->executionCommon}";
$lang->execution->editAction = "Edit Execution";
$lang->execution->batchEdit = "Edit";
$lang->execution->batchEditAction = "Batch Edit";
$lang->execution->manageMembers = 'Manage Team';
$lang->execution->unlinkMember = 'Remove Member';
$lang->execution->unlinkStory = 'Unlink Story';
$lang->execution->unlinkStoryAB = 'Unlink';
$lang->execution->batchUnlinkStory = 'Batch Unlink Stories';
$lang->execution->importTask = 'Transfer Task';
$lang->execution->importPlanStories = 'Link Stories By Plan';
$lang->execution->importBug = 'Import Bug';
$lang->execution->tree = 'Tree';
$lang->execution->treeTask = 'Show Task Only';
$lang->execution->treeStory = 'Show Story Only';
$lang->execution->treeViewTask = 'Tree View Task';
$lang->execution->treeViewStory = 'Tree View Story';
$lang->execution->storyKanban = 'Story Kanban';
$lang->execution->storySort = 'Rank Story';
$lang->execution->importPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
$lang->execution->iteration = 'Iterations';
$lang->execution->iterationInfo = '%s Iterations';
$lang->execution->viewAll = 'View All';
$lang->execution->testreport = 'Test Report';
$lang->execution->taskKanban = 'Task Kanban';
$lang->execution->RDKanban = 'Research & Development Kanban';
$lang->execution->index = "{$lang->executionCommon} Home";
$lang->execution->task = 'Task List';
$lang->execution->groupTask = 'Group View';
$lang->execution->story = 'Story List';
$lang->execution->qa = 'QA';
$lang->execution->bug = 'Bug List';
$lang->execution->testcase = 'Testcase List';
$lang->execution->dynamic = 'Dynamics';
$lang->execution->latestDynamic = 'Dynamics';
$lang->execution->build = 'Build List';
$lang->execution->testtask = 'Request';
$lang->execution->burn = 'Burndown';
$lang->execution->computeBurn = 'Update';
$lang->execution->CFD = 'Cumulative Flow diagrams';
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
$lang->execution->burnData = 'Burndown Data';
$lang->execution->fixFirst = 'Edit 1st-Day Estimates';
$lang->execution->team = 'Members';
$lang->execution->doc = 'Document';
$lang->execution->doclib = 'Docoment Library';
$lang->execution->manageProducts = 'Linked ' . $lang->productCommon . 's';
$lang->execution->linkStory = 'Link Stories';
$lang->execution->linkStoryByPlan = 'Link Stories By Plan';
$lang->execution->linkPlan = 'Linked Plan';
$lang->execution->unlinkStoryTasks = 'Unlink';
$lang->execution->linkedProducts = "Linked {$lang->productCommon}s";
$lang->execution->unlinkedProducts = "Unlinked {$lang->productCommon}s";
$lang->execution->view = "Execution Detail";
$lang->execution->startAction = "Start Execution";
$lang->execution->activateAction = "Activate Execution";
$lang->execution->delayAction = "Delay Execution";
$lang->execution->suspendAction = "Suspend Execution";
$lang->execution->closeAction = "Close Execution";
$lang->execution->testtaskAction = "Execution Request";
$lang->execution->teamAction = "Execution Members";
$lang->execution->kanbanAction = "Execution Kanban";
$lang->execution->printKanbanAction = "Print Kanban";
$lang->execution->treeAction = "Execution Tree View";
$lang->execution->exportAction = "Export Execution";
$lang->execution->computeBurnAction = "Update Burndown";
$lang->execution->create = "Create {$lang->executionCommon}";
$lang->execution->createExec = "Create {$lang->execution->common}";
$lang->execution->createAction = "Create {$lang->execution->common}";
$lang->execution->copyExec = "Copy {$lang->execution->common}";
$lang->execution->copy = "Copy {$lang->executionCommon}";
$lang->execution->delete = "Delete {$lang->executionCommon}";
$lang->execution->deleteAB = "Delete Execution";
$lang->execution->browse = "{$lang->executionCommon} List";
$lang->execution->edit = "Edit {$lang->executionCommon}";
$lang->execution->editAction = "Edit Execution";
$lang->execution->batchEdit = "Edit";
$lang->execution->batchEditAction = "Batch Edit";
$lang->execution->manageMembers = 'Manage Team';
$lang->execution->unlinkMember = 'Remove Member';
$lang->execution->unlinkStory = 'Unlink Story';
$lang->execution->unlinkStoryAB = 'Unlink';
$lang->execution->batchUnlinkStory = 'Batch Unlink Stories';
$lang->execution->importTask = 'Transfer Task';
$lang->execution->importPlanStories = 'Link Stories By Plan';
$lang->execution->importBug = 'Import Bug';
$lang->execution->tree = 'Tree';
$lang->execution->treeTask = 'Show Task Only';
$lang->execution->treeStory = 'Show Story Only';
$lang->execution->treeViewTask = 'Tree View Task';
$lang->execution->treeViewStory = 'Tree View Story';
$lang->execution->storyKanban = 'Story Kanban';
$lang->execution->storySort = 'Rank Story';
$lang->execution->importPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->importBranchPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
$lang->execution->importBranchEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
$lang->execution->iteration = 'Iterations';
$lang->execution->iterationInfo = '%s Iterations';
$lang->execution->viewAll = 'View All';
$lang->execution->testreport = 'Test Report';
$lang->execution->taskKanban = 'Task Kanban';
$lang->execution->RDKanban = 'Research & Development Kanban';
/* Group browsing. */
$lang->execution->allTasks = 'All';
@@ -349,7 +351,8 @@ $lang->execution->howToUpdateBurn = "<a href='https://api.zentao.pm/goto.ph
$lang->execution->whyNoStories = "No story can be linked. Please check whether there is any story in {$lang->executionCommon} which is linked to {$lang->productCommon} and make sure it has been reviewed.";
$lang->execution->projectNoStories = "No story can be linked. Please check whether there is any story in project and make sure it has been reviewed.";
$lang->execution->productStories = "Stories linked to {$lang->executionCommon} are the subeset of stories linked to {$lang->productCommon}. Stories can only be linked after they pass the review. <a href='%s'> Link Stories</a> now.";
$lang->execution->haveDraft = "%s stories in draft, so they can't be linked.";
$lang->execution->haveBranchDraft = "There are %s draft stories or not associated with this {$lang->executionCommon} can't be linked.";
$lang->execution->haveDraft = "There are %s draft stories with this {$lang->executionCommon} can't be linked.";
$lang->execution->doneExecutions = 'Finished';
$lang->execution->selectDept = 'Select Department';
$lang->execution->selectDeptTitle = 'Select User';
@@ -478,6 +481,8 @@ $lang->execution->kanbanViewList['story'] = "{$lang->SRCommon}";
$lang->execution->kanbanViewList['bug'] = 'Bug';
$lang->execution->kanbanViewList['task'] = 'Task';
$lang->execution->teamWords = 'Team';
$lang->kanbanSetting = new stdclass();
$lang->kanbanSetting->noticeReset = 'Do you want to reset Kanban?';
$lang->kanbanSetting->optionList['0'] = 'Hide';
+82 -77
View File
@@ -209,82 +209,84 @@ $lang->execution->burnByList['estimate'] = "View by plan hours";
$lang->execution->burnByList['storyPoint'] = 'View by story point';
/* Method list. */
$lang->execution->index = "Accueil {$lang->executionCommon}";
$lang->execution->task = 'Liste Tâches';
$lang->execution->groupTask = 'Vision Groupée';
$lang->execution->story = 'Liste Stories';
$lang->execution->qa = 'QA';
$lang->execution->bug = 'Liste Bugs';
$lang->execution->testcase = 'Testcase List';
$lang->execution->dynamic = 'Historique';
$lang->execution->latestDynamic = 'Historique';
$lang->execution->build = 'Liste Builds';
$lang->execution->testtask = 'Recette';
$lang->execution->burn = ' Atterrissage';
$lang->execution->computeBurn = 'Calculer';
$lang->execution->CFD = 'Cumulative Flow diagrams';
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
$lang->execution->burnData = "Données d'atterrissage";
$lang->execution->fixFirst = 'Fixer 1er-Jour Estimation';
$lang->execution->team = 'Membres';
$lang->execution->doc = 'Documents';
$lang->execution->doclib = 'Répertoire de Documents';
$lang->execution->manageProducts = 'Liaisons du ' . $lang->executionCommon . ' avec les ' . $lang->productCommon . 's';
$lang->execution->linkStory = 'Stories liées';
$lang->execution->linkStoryByPlan = 'Stories liées par Plan';
$lang->execution->linkPlan = 'Plans liés';
$lang->execution->unlinkStoryTasks = 'Dissocier';
$lang->execution->linkedProducts = "{$lang->productCommon}s liés à ce {$lang->executionCommon}";
$lang->execution->unlinkedProducts = "{$lang->productCommon}s dissociés de ce {$lang->executionCommon}";
$lang->execution->view = "Détail du Execution";
$lang->execution->startAction = "Start Execution";
$lang->execution->activateAction = "Activer le Execution";
$lang->execution->delayAction = "Ajourner le Execution";
$lang->execution->suspendAction = "Suspendre le Execution";
$lang->execution->closeAction = "Fermer le Execution";
$lang->execution->testtaskAction = "Recettes du Execution";
$lang->execution->teamAction = "Membres du Execution";
$lang->execution->kanbanAction = "Kaban Execution";
$lang->execution->printKanbanAction = "Imprimer le Kanban";
$lang->execution->treeAction = "Arborescence Execution";
$lang->execution->exportAction = "Exporter Execution";
$lang->execution->computeBurnAction = "Calculer Atterrissage";
$lang->execution->create = "Créer {$lang->executionCommon}";
$lang->execution->createExec = "Create Execution";
$lang->execution->createAction = "Create {$lang->execution->common}";
$lang->execution->copyExec = "Copy Execution";
$lang->execution->copy = "Copier {$lang->executionCommon}";
$lang->execution->delete = "Supprimer {$lang->executionCommon}";
$lang->execution->deleteAB = "Delete Execution";
$lang->execution->browse = "Liste du {$lang->executionCommon}";
$lang->execution->edit = "Editer {$lang->executionCommon}";
$lang->execution->editAction = "Edit Execution";
$lang->execution->batchEdit = "Edition par lot";
$lang->execution->batchEditAction = "Batch Edit";
$lang->execution->manageMembers = 'Organiser Equipe';
$lang->execution->unlinkMember = 'Retirer le membre';
$lang->execution->unlinkStory = 'Dissocier Story';
$lang->execution->unlinkStoryAB = 'Dissocier';
$lang->execution->batchUnlinkStory = 'Dissocier Stories par lot';
$lang->execution->importTask = 'Transfert Tâche';
$lang->execution->importPlanStories = 'Lier Stories Par Plan';
$lang->execution->importBug = 'Importer Bug';
$lang->execution->tree = 'Arboressence';
$lang->execution->treeTask = 'Seulement les Tâches';
$lang->execution->treeStory = 'Seulement les Stories';
$lang->execution->treeViewTask = 'Seulement les Tâches';
$lang->execution->treeViewStory = 'Seulement les Stories';
$lang->execution->storyKanban = 'Story Kanban';
$lang->execution->storySort = 'Rang Story';
$lang->execution->importPlanStory = $lang->executionCommon . ' est créé!\nVoulez-vous importer des stories qui ont été ajoutées au Plan ?';
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
$lang->execution->iteration = 'Itérations';
$lang->execution->iterationInfo = '%s Itérations';
$lang->execution->viewAll = 'Voir Tout';
$lang->execution->testreport = 'Test Report';
$lang->execution->taskKanban = 'Task Kanban';
$lang->execution->RDKanban = 'Research & Development Kanban';
$lang->execution->index = "{$lang->executionCommon} Home";
$lang->execution->task = 'Task List';
$lang->execution->groupTask = 'Group View';
$lang->execution->story = 'Story List';
$lang->execution->qa = 'QA';
$lang->execution->bug = 'Bug List';
$lang->execution->testcase = 'Testcase List';
$lang->execution->dynamic = 'Dynamics';
$lang->execution->latestDynamic = 'Dynamics';
$lang->execution->build = 'Build List';
$lang->execution->testtask = 'Request';
$lang->execution->burn = 'Burndown';
$lang->execution->computeBurn = 'Update';
$lang->execution->CFD = 'Cumulative Flow diagrams';
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
$lang->execution->burnData = 'Burndown Data';
$lang->execution->fixFirst = 'Edit 1st-Day Estimates';
$lang->execution->team = 'Members';
$lang->execution->doc = 'Document';
$lang->execution->doclib = 'Docoment Library';
$lang->execution->manageProducts = 'Linked ' . $lang->productCommon . 's';
$lang->execution->linkStory = 'Link Stories';
$lang->execution->linkStoryByPlan = 'Link Stories By Plan';
$lang->execution->linkPlan = 'Linked Plan';
$lang->execution->unlinkStoryTasks = 'Unlink';
$lang->execution->linkedProducts = "Linked {$lang->productCommon}s";
$lang->execution->unlinkedProducts = "Unlinked {$lang->productCommon}s";
$lang->execution->view = "Execution Detail";
$lang->execution->startAction = "Start Execution";
$lang->execution->activateAction = "Activate Execution";
$lang->execution->delayAction = "Delay Execution";
$lang->execution->suspendAction = "Suspend Execution";
$lang->execution->closeAction = "Close Execution";
$lang->execution->testtaskAction = "Execution Request";
$lang->execution->teamAction = "Execution Members";
$lang->execution->kanbanAction = "Execution Kanban";
$lang->execution->printKanbanAction = "Print Kanban";
$lang->execution->treeAction = "Execution Tree View";
$lang->execution->exportAction = "Export Execution";
$lang->execution->computeBurnAction = "Update Burndown";
$lang->execution->create = "Create {$lang->executionCommon}";
$lang->execution->createExec = "Create {$lang->execution->common}";
$lang->execution->createAction = "Create {$lang->execution->common}";
$lang->execution->copyExec = "Copy {$lang->execution->common}";
$lang->execution->copy = "Copy {$lang->executionCommon}";
$lang->execution->delete = "Delete {$lang->executionCommon}";
$lang->execution->deleteAB = "Delete Execution";
$lang->execution->browse = "{$lang->executionCommon} List";
$lang->execution->edit = "Edit {$lang->executionCommon}";
$lang->execution->editAction = "Edit Execution";
$lang->execution->batchEdit = "Edit";
$lang->execution->batchEditAction = "Batch Edit";
$lang->execution->manageMembers = 'Manage Team';
$lang->execution->unlinkMember = 'Remove Member';
$lang->execution->unlinkStory = 'Unlink Story';
$lang->execution->unlinkStoryAB = 'Unlink';
$lang->execution->batchUnlinkStory = 'Batch Unlink Stories';
$lang->execution->importTask = 'Transfer Task';
$lang->execution->importPlanStories = 'Link Stories By Plan';
$lang->execution->importBug = 'Import Bug';
$lang->execution->tree = 'Tree';
$lang->execution->treeTask = 'Show Task Only';
$lang->execution->treeStory = 'Show Story Only';
$lang->execution->treeViewTask = 'Tree View Task';
$lang->execution->treeViewStory = 'Tree View Story';
$lang->execution->storyKanban = 'Story Kanban';
$lang->execution->storySort = 'Rank Story';
$lang->execution->importPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->importBranchPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
$lang->execution->importBranchEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
$lang->execution->iteration = 'Iterations';
$lang->execution->iterationInfo = '%s Iterations';
$lang->execution->viewAll = 'View All';
$lang->execution->testreport = 'Test Report';
$lang->execution->taskKanban = 'Task Kanban';
$lang->execution->RDKanban = 'Research & Development Kanban';
/* Group browsing. */
$lang->execution->allTasks = 'Toutes';
@@ -349,7 +351,8 @@ $lang->execution->howToUpdateBurn = "<a href='https://api.zentao.pm/goto.ph
$lang->execution->whyNoStories = "Aucune story ne peut être associée. Vérifiez s'il existe des stories dans {$lang->executionCommon} qui sont associées à {$lang->productCommon} et vérifiez qu'elles ont bien été validées.";
$lang->execution->projectNoStories = "No story can be linked. Please check whether there is any story in project and make sure it has been reviewed.";
$lang->execution->productStories = "Les stories associées au {$lang->executionCommon} sont une portion des stories associées au {$lang->productCommon}. Les stories ne peuvent être associées à un {$lang->executionCommon} qu'après avoir été validées. <a href='%s'> Associer Stories</a> maintenant.";
$lang->execution->haveDraft = "%s stories sont encore en conception, elles ne peuvent pas être associées au {$lang->executionCommon} actuellement.";
$lang->execution->haveBranchDraft = "There are %s draft stories or not associated with this {$lang->executionCommon} can't be linked.";
$lang->execution->haveDraft = "There are %s draft stories with this {$lang->executionCommon} can't be linked.";
$lang->execution->doneExecutions = 'Terminé';
$lang->execution->selectDept = 'Sélection Compartiment';
$lang->execution->selectDeptTitle = 'Sélection Utilisateur';
@@ -478,6 +481,8 @@ $lang->execution->kanbanViewList['story'] = "{$lang->SRCommon}";
$lang->execution->kanbanViewList['bug'] = 'Bug';
$lang->execution->kanbanViewList['task'] = 'Task';
$lang->execution->teamWords = 'Team';
$lang->kanbanSetting = new stdclass();
$lang->kanbanSetting->noticeReset = 'Voulez-vous réinitialiser le tableau Kanban ?';
$lang->kanbanSetting->optionList['0'] = 'Masquer';
+2
View File
@@ -436,4 +436,6 @@ $lang->execution->statusColorList['doing'] = '#0BD986';
$lang->execution->statusColorList['suspended'] = '#fdc137';
$lang->execution->statusColorList['closed'] = '#838A9D';
$lang->execution->teamWords = 'đội';
$lang->execution->boardColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761');
+82 -77
View File
@@ -209,82 +209,84 @@ $lang->execution->burnByList['estimate'] = "按计划工时查看";
$lang->execution->burnByList['storyPoint'] = '按故事点查看';
/* 方法列表。*/
$lang->execution->index = "{$lang->execution->common}主页";
$lang->execution->task = '任务列表';
$lang->execution->groupTask = '分组浏览任务';
$lang->execution->story = "{$lang->SRCommon}列表";
$lang->execution->qa = '测试仪表盘';
$lang->execution->bug = 'Bug列表';
$lang->execution->testcase = '用例列表';
$lang->execution->dynamic = '动态';
$lang->execution->latestDynamic = '最新动态';
$lang->execution->build = '所有版本';
$lang->execution->testtask = '测试单';
$lang->execution->burn = '燃尽图';
$lang->execution->computeBurn = '更新燃尽图';
$lang->execution->CFD = '累积流图';
$lang->execution->computeCFD = '更新累积流图';
$lang->execution->burnData = '燃尽图数据';
$lang->execution->fixFirst = '修改首天工时';
$lang->execution->team = '团队成员';
$lang->execution->doc = '文档列表';
$lang->execution->doclib = '文档库列表';
$lang->execution->manageProducts = '关联' . $lang->productCommon;
$lang->execution->linkStory = "关联{$lang->SRCommon}";
$lang->execution->linkStoryByPlan = "按照计划关联";
$lang->execution->linkPlan = "关联计划";
$lang->execution->unlinkStoryTasks = "未关联{$lang->SRCommon}任务";
$lang->execution->linkedProducts = '已关联';
$lang->execution->unlinkedProducts = '未关联';
$lang->execution->view = "{$lang->execution->common}概况";
$lang->execution->startAction = "开始{$lang->execution->common}";
$lang->execution->activateAction = "激活{$lang->execution->common}";
$lang->execution->delayAction = "延期{$lang->execution->common}";
$lang->execution->suspendAction = "挂起{$lang->execution->common}";
$lang->execution->closeAction = "关闭{$lang->execution->common}";
$lang->execution->testtaskAction = "{$lang->execution->common}测试单";
$lang->execution->teamAction = "{$lang->execution->common}团队";
$lang->execution->kanbanAction = "{$lang->execution->common}看板";
$lang->execution->printKanbanAction = "打印看板";
$lang->execution->treeAction = "{$lang->execution->common}树状图";
$lang->execution->exportAction = "导出{$lang->execution->common}";
$lang->execution->computeBurnAction = "计算燃尽图";
$lang->execution->create = "添加{$lang->executionCommon}";
$lang->execution->createExec = "添加{$lang->execution->common}";
$lang->execution->createAction = "添加{$lang->execution->common}";
$lang->execution->copyExec = "复制{$lang->execution->common}";
$lang->execution->copy = "复制{$lang->executionCommon}";
$lang->execution->delete = "删除{$lang->executionCommon}";
$lang->execution->deleteAB = "删除{$lang->execution->common}";
$lang->execution->browse = "浏览{$lang->execution->common}";
$lang->execution->edit = "设置{$lang->executionCommon}";
$lang->execution->editAction = "编辑{$lang->execution->common}";
$lang->execution->batchEdit = "编辑";
$lang->execution->batchEditAction = "批量编辑";
$lang->execution->manageMembers = '团队管理';
$lang->execution->unlinkMember = '移除成员';
$lang->execution->unlinkStory = "移除{$lang->SRCommon}";
$lang->execution->unlinkStoryAB = "移除{$lang->SRCommon}";
$lang->execution->batchUnlinkStory = "批量移除{$lang->SRCommon}";
$lang->execution->importTask = '转入任务';
$lang->execution->importPlanStories = "按计划关联{$lang->SRCommon}";
$lang->execution->importBug = '导入Bug';
$lang->execution->tree = '树状图';
$lang->execution->treeTask = '只看任务';
$lang->execution->treeStory = "只看{$lang->SRCommon}";
$lang->execution->treeViewTask = '树状图查看任务';
$lang->execution->treeViewStory = "树状图查看{$lang->SRCommon}";
$lang->execution->storyKanban = "{$lang->SRCommon}看板";
$lang->execution->storySort = "{$lang->SRCommon}排序";
$lang->execution->importPlanStory = '创建' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将自动过滤掉草稿状态的' . $lang->SRCommon . '。';
$lang->execution->importEditPlanStory = '编辑' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将自动过滤掉草稿状态的' . $lang->SRCommon . '。';
$lang->execution->needLinkProducts = '该执行还未关联任何产品,相关功能无法使用,请先关联产品后再试。';
$lang->execution->iteration = '版本迭代';
$lang->execution->iterationInfo = '迭代%s次';
$lang->execution->viewAll = '查看所有';
$lang->execution->testreport = '测试报告';
$lang->execution->taskKanban = '任务看板';
$lang->execution->RDKanban = '研发看板';
$lang->execution->index = "{$lang->execution->common}主页";
$lang->execution->task = '任务列表';
$lang->execution->groupTask = '分组浏览任务';
$lang->execution->story = "{$lang->SRCommon}列表";
$lang->execution->qa = '测试仪表盘';
$lang->execution->bug = 'Bug列表';
$lang->execution->testcase = '用例列表';
$lang->execution->dynamic = '动态';
$lang->execution->latestDynamic = '最新动态';
$lang->execution->build = '所有版本';
$lang->execution->testtask = '测试单';
$lang->execution->burn = '燃尽图';
$lang->execution->computeBurn = '更新燃尽图';
$lang->execution->CFD = '累积流图';
$lang->execution->computeCFD = '更新累积流图';
$lang->execution->burnData = '燃尽图数据';
$lang->execution->fixFirst = '修改首天工时';
$lang->execution->team = '团队成员';
$lang->execution->doc = '文档列表';
$lang->execution->doclib = '文档库列表';
$lang->execution->manageProducts = '关联' . $lang->productCommon;
$lang->execution->linkStory = "关联{$lang->SRCommon}";
$lang->execution->linkStoryByPlan = "按照计划关联";
$lang->execution->linkPlan = "关联计划";
$lang->execution->unlinkStoryTasks = "未关联{$lang->SRCommon}任务";
$lang->execution->linkedProducts = '已关联';
$lang->execution->unlinkedProducts = '未关联';
$lang->execution->view = "{$lang->execution->common}概况";
$lang->execution->startAction = "开始{$lang->execution->common}";
$lang->execution->activateAction = "激活{$lang->execution->common}";
$lang->execution->delayAction = "延期{$lang->execution->common}";
$lang->execution->suspendAction = "挂起{$lang->execution->common}";
$lang->execution->closeAction = "关闭{$lang->execution->common}";
$lang->execution->testtaskAction = "{$lang->execution->common}测试单";
$lang->execution->teamAction = "{$lang->execution->common}团队";
$lang->execution->kanbanAction = "{$lang->execution->common}看板";
$lang->execution->printKanbanAction = "打印看板";
$lang->execution->treeAction = "{$lang->execution->common}树状图";
$lang->execution->exportAction = "导出{$lang->execution->common}";
$lang->execution->computeBurnAction = "计算燃尽图";
$lang->execution->create = "添加{$lang->executionCommon}";
$lang->execution->createExec = "添加{$lang->execution->common}";
$lang->execution->createAction = "添加{$lang->execution->common}";
$lang->execution->copyExec = "复制{$lang->execution->common}";
$lang->execution->copy = "复制{$lang->executionCommon}";
$lang->execution->delete = "删除{$lang->executionCommon}";
$lang->execution->deleteAB = "删除{$lang->execution->common}";
$lang->execution->browse = "浏览{$lang->execution->common}";
$lang->execution->edit = "设置{$lang->executionCommon}";
$lang->execution->editAction = "编辑{$lang->execution->common}";
$lang->execution->batchEdit = "编辑";
$lang->execution->batchEditAction = "批量编辑";
$lang->execution->manageMembers = '团队管理';
$lang->execution->unlinkMember = '移除成员';
$lang->execution->unlinkStory = "移除{$lang->SRCommon}";
$lang->execution->unlinkStoryAB = "移除{$lang->SRCommon}";
$lang->execution->batchUnlinkStory = "批量移除{$lang->SRCommon}";
$lang->execution->importTask = '转入任务';
$lang->execution->importPlanStories = "按计划关联{$lang->SRCommon}";
$lang->execution->importBug = '导入Bug';
$lang->execution->tree = '树状图';
$lang->execution->treeTask = '只看任务';
$lang->execution->treeStory = "只看{$lang->SRCommon}";
$lang->execution->treeViewTask = '树状图查看任务';
$lang->execution->treeViewStory = "树状图查看{$lang->SRCommon}";
$lang->execution->storyKanban = "{$lang->SRCommon}看板";
$lang->execution->storySort = "{$lang->SRCommon}排序";
$lang->execution->importPlanStory = '创建' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将自动过滤掉草稿状态的' . $lang->SRCommon . '。';
$lang->execution->importEditPlanStory = '编辑' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将自动过滤掉草稿状态的' . $lang->SRCommon . '。';
$lang->execution->importBranchPlanStory = '创建' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将只关联本' . $lang->executionCommon . '所关联分支的激活需求。';
$lang->execution->importBranchEditPlanStory = '编辑' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将只关联本' . $lang->executionCommon . '所关联分支的激活需求。';
$lang->execution->needLinkProducts = '该执行还未关联任何产品,相关功能无法使用,请先关联产品后再试。';
$lang->execution->iteration = '版本迭代';
$lang->execution->iterationInfo = '迭代%s次';
$lang->execution->viewAll = '查看所有';
$lang->execution->testreport = '测试报告';
$lang->execution->taskKanban = '任务看板';
$lang->execution->RDKanban = '研发看板';
/* 分组浏览。*/
$lang->execution->allTasks = '所有';
@@ -349,7 +351,8 @@ $lang->execution->howToUpdateBurn = "<a href='https://api.zentao.net/goto.p
$lang->execution->whyNoStories = "看起来没有{$lang->SRCommon}可以关联。请检查下{$lang->executionCommon}关联的{$lang->productCommon}中有没有{$lang->SRCommon},而且要确保它们已经审核通过。";
$lang->execution->projectNoStories = "看起来没有{$lang->SRCommon}可以关联。请检查下项目中有没有{$lang->SRCommon},而且要确保它们已经审核通过。";
$lang->execution->productStories = "{$lang->executionCommon}关联的{$lang->SRCommon}是{$lang->productCommon}{$lang->SRCommon}的子集,并且只有评审通过的{$lang->SRCommon}才能关联。请<a href='%s'>关联{$lang->SRCommon}</a>。";
$lang->execution->haveDraft = "有%s条草稿状态的{$lang->SRCommon}无法关联到该{$lang->executionCommon}";
$lang->execution->haveBranchDraft = "有%s条非激活状态或不是{$lang->executionCommon}关联分支的{$lang->SRCommon}无法导入";
$lang->execution->haveDraft = "有%s条非激活状态的{$lang->SRCommon}无法导入";
$lang->execution->doneExecutions = '已结束';
$lang->execution->selectDept = '选择部门';
$lang->execution->selectDeptTitle = '选择一个部门的成员';
@@ -478,6 +481,8 @@ $lang->execution->kanbanViewList['story'] = "{$lang->SRCommon}看板";
$lang->execution->kanbanViewList['bug'] = 'Bug看板';
$lang->execution->kanbanViewList['task'] = '任务看板';
$lang->execution->teamWords = '团队';
$lang->kanbanSetting = new stdclass();
$lang->kanbanSetting->noticeReset = '是否恢复看板默认设置?';
$lang->kanbanSetting->optionList['0'] = '隐藏';
+2
View File
@@ -453,4 +453,6 @@ $lang->execution->statusColorList['doing'] = '#0BD986';
$lang->execution->statusColorList['suspended'] = '#fdc137';
$lang->execution->statusColorList['closed'] = '#838A9D';
$lang->execution->teamWords = '團隊';
$lang->execution->boardColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761');
+84 -26
View File
@@ -332,6 +332,20 @@ class executionModel extends model
$this->checkBeginAndEndDate($_POST['project'], $_POST['begin'], $_POST['end']);
if(dao::isError()) return false;
if($_POST['products'])
{
$this->app->loadLang('project');
$multipleProducts = $this->loadModel('product')->getMultiBranchPairs();
foreach($_POST['products'] as $index => $productID)
{
if(isset($multipleProducts[$productID]) and empty($_POST['branch'][$index]))
{
dao::$errors[] = $this->lang->project->emptyBranch;
return false;
}
}
}
/* Determine whether to add a sprint or a stage according to the model of the execution. */
$project = $this->loadModel('project')->getByID($_POST['project']);
$type = 'sprint';
@@ -514,6 +528,20 @@ class executionModel extends model
return false;
}
if($_POST['products'])
{
$this->app->loadLang('project');
$multipleProducts = $this->loadModel('product')->getMultiBranchPairs();
foreach($_POST['products'] as $index => $productID)
{
if(isset($multipleProducts[$productID]) and empty($_POST['branch'][$index]))
{
dao::$errors[] = $this->lang->project->emptyBranch;
return false;
}
}
}
/* Get the data from the post. */
$execution = fixer::input('post')
->add('id', $executionID)
@@ -1554,14 +1582,17 @@ class executionModel extends model
->andWhere('type')->eq('execution')
->fetchPairs();
}
$project = $this->loadModel('project')->getByID($projectID);
$executions = $this->dao->select('t1.*,t2.name projectName, t2.model as projectModel')->from(TABLE_EXECUTION)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
->beginIF($productID)->leftJoin(TABLE_PROJECTPRODUCT)->alias('t3')->on('t1.id=t3.project')->fi()
->leftJoin(TABLE_PROJECTPRODUCT)->alias('t3')->on('t1.id=t3.project')
->beginIF(!empty($project->division))->leftJoin(TABLE_PRODUCT)->alias('t4')->on('t4.id=t3.product')->fi()
->where('t1.type')->in('sprint,stage,kanban')
->andWhere('t1.deleted')->eq('0')
->andWhere('t1.vision')->eq($this->config->vision)
->andWhere('t1.multiple')->eq('1')
->beginIF(!empty($project->division))->andWhere('t4.deleted')->eq('0')->fi()
->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->sprints)->fi()
->beginIF(!empty($executionQuery))->andWhere($executionQuery)->fi()
->beginIF($productID)->andWhere('t3.product')->eq($productID)->fi()
@@ -2370,23 +2401,28 @@ class executionModel extends model
$oldPlan = 0;
$branch = isset($branches[$i]) ? $branches[$i] : 0;
if(isset($existedProducts[$productID][$branch])) continue;
if(!is_array($branch)) $branch = array($branch);
if(isset($oldProducts[$productID][$branch]))
foreach($branch as $branchID)
{
$oldProduct = $oldProducts[$productID][$branch];
if($this->app->rawMethod != 'edit') $oldPlan = $oldProduct->plan;
}
if(isset($existedProducts[$productID][$branchID])) continue;
$data = new stdclass();
$data->project = $executionID;
$data->product = $productID;
$data->branch = $branch;
$data->plan = isset($plans[$productID][$branch]) ? implode(',', $plans[$productID][$branch]) : $oldPlan;
$data->plan = trim($data->plan, ',');
$data->plan = empty($data->plan) ? 0 : ",$data->plan,";
$this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec();
$existedProducts[$productID][$branch] = true;
if(isset($oldProducts[$productID][$branchID]))
{
$oldProduct = $oldProducts[$productID][$branchID];
if($this->app->rawMethod != 'edit') $oldPlan = $oldProduct->plan;
}
$data = new stdclass();
$data->project = $executionID;
$data->product = $productID;
$data->branch = $branchID;
$data->plan = isset($plans[$productID]) ? implode(',', $plans[$productID]) : $oldPlan;
$data->plan = trim($data->plan, ',');
$data->plan = empty($data->plan) ? 0 : ",$data->plan,";
$this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec();
$existedProducts[$productID][$branchID] = true;
}
}
$oldProductKeys = array_keys($oldProducts);
@@ -2882,19 +2918,21 @@ class executionModel extends model
*/
public function linkStories($executionID)
{
$plans = $this->dao->select('plan')->from(TABLE_PROJECTPRODUCT)
$plans = $this->dao->select('product, plan')->from(TABLE_PROJECTPRODUCT)
->where('project')->eq($executionID)
->fetchPairs('plan');
->fetchPairs('product', 'plan');
$planStories = array();
$planProducts = array();
$this->loadModel('story');
if(!empty($plans))
{
foreach($plans as $planIdList)
$executionProducts = $this->loadModel('project')->getBranchesByProject($executionID);
foreach($plans as $productID => $planIdList)
{
if(empty($planIdList)) continue;
$planIdList = explode(',', $planIdList);
$executionBranches = zget($executionProducts, $productID, array());
foreach($planIdList as $planID)
{
$planStory = $this->story->getPlanStories($planID);
@@ -2902,7 +2940,7 @@ class executionModel extends model
{
foreach($planStory as $id => $story)
{
if($story->status == 'draft' or $story->status == 'reviewing')
if($story->status != 'active' or (!empty($story->branch) and !empty($executionBranches) and !isset($executionBranches[$story->branch])))
{
unset($planStory[$id]);
continue;
@@ -4623,17 +4661,36 @@ class executionModel extends model
$branchGroups = $this->getBranchByProduct(array_keys($products), $executionID, 'noclosed');
foreach($branchGroups as $branches)
{
foreach($branches as $branchID => $branchName) $branchIdList[$branchID] = $branchID;
foreach($branches as $branchID => $branchName) $branchIdList[] = $branchID;
}
$plans = $this->dao->select('id,title,product,parent,begin,end')->from(TABLE_PRODUCTPLAN)
->where('product')->in(array_keys($products))
->andWhere('deleted')->eq(0)
->andWhere('branch')->in($branchIdList)->fi()
->orderBy('begin desc')
$branchQuery = '(';
if(!empty($branchIdList))
{
$branchCount = count($branchIdList);
foreach($branchIdList as $index => $branchID)
{
$branchQuery .= "FIND_IN_SET('$branchID', branch)";
if($index < $branchCount - 1) $branchQuery .= ' OR ';
}
}
else
{
$branchQuery .= "FIND_IN_SET('0', branch)";
}
$branchQuery .= ')';
$plans = $this->dao->select('t1.id,t1.title,t1.product,t1.parent,t1.begin,t1.end,t1.branch,t2.type as productType')->from(TABLE_PRODUCTPLAN)->alias('t1')
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t2.id=t1.product')
->where('t1.product')->in(array_keys($products))
->andWhere('t1.deleted')->eq(0)
->andWhere($branchQuery)
->orderBy('t1.begin desc')
->fetchAll('id');
$plans = $this->productplan->reorder4Children($plans);
$plans = $this->productplan->relationBranch($plans);
$productPlans = array();
foreach($plans as $plan)
{
@@ -4641,6 +4698,7 @@ class executionModel extends model
if($plan->parent > 0 and isset($plans[$plan->parent])) $plan->title = $plans[$plan->parent]->title . ' /' . $plan->title;
$productPlans[$plan->product][$plan->id] = $plan->title . " [{$plan->begin} ~ {$plan->end}]";
if($plan->begin == '2030-01-01' and $plan->end == '2030-01-01') $productPlans[$plan->product][$plan->id] = $plan->title . ' ' . $this->lang->productplan->future;
if($plan->productType != 'normal') $productPlans[$plan->product][$plan->id] = $productPlans[$plan->product][$plan->id] . ' / ' . ($plan->branchName ? $plan->branchName : $this->lang->branch->main);
}
return $productPlans;
@@ -5202,7 +5260,7 @@ class executionModel extends model
$_POST['status'] = $project->status;
$_POST['acl'] = 'open';
if(!empty($_POST['code'])) $_POST['code'] = $project->code;
if(!isset($this->config->setCode) or $this->config->setCode == 1) $_POST['code'] = $project->code;
$projectProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchAll();
foreach($projectProducts as $projectProduct)
+14 -8
View File
@@ -49,10 +49,12 @@
<thead>
<tr>
<th class="c-id-sm"><?php echo $lang->build->id;?></th>
<th class="c-name w-200px text-left <?php echo $hidden;?>"><?php echo $lang->build->product;?></th>
<th class="c-name w-150px text-left <?php echo $hidden;?>"><?php echo $lang->build->product;?></th>
<?php if($showBranch):?>
<th class="c-name w-150px text-left <?php echo $hidden;?>"><?php echo $lang->build->branch;?></th>
<?php endif;?>
<th class="c-name text-left"><?php echo $lang->build->name;?></th>
<th class="c-url"><?php echo $lang->build->scmPath;?></th>
<th class="c-url"><?php echo $lang->build->filePath;?></th>
<th class="c-url w-200px text-left"><?php echo $lang->build->url;?></th>
<th class="c-date"><?php echo $lang->build->date;?></th>
<th class="c-user"><?php echo $lang->build->builder;?></th>
<th class="c-actions-5"><?php echo $lang->actions;?></th>
@@ -64,12 +66,16 @@
<tr data-id="<?php echo $productID;?>">
<td class="c-id-sm text-muted"><?php echo html::a(helper::createLink('build', 'view', "buildID=$build->id"), sprintf('%03d', $build->id));?></td>
<td class="c-name text-left <?php echo $hidden;?>" title='<?php echo $build->productName;?>'><?php echo $build->productName;?></td>
<td class="c-name">
<?php if($build->branchName) echo "<span class='label label-outline label-badge'>{$build->branchName}</span>"?>
<?php echo html::a($this->createLink('build', 'view', "build=$build->id"), $build->name);?>
<?php if($showBranch):?>
<td class="c-name text-left <?php echo $hidden;?>" title='<?php echo $build->branchName;?>'><?php echo $build->branchName;?></td>
<?php endif;?>
<td class="c-name"><?php echo html::a($this->createLink('build', 'view', "build=$build->id"), $build->name);?></td>
<td class="c-url text-left">
<?php
if($build->scmPath) echo "<div><i class='icon icon-file-code' title='{$lang->build->scmPath}'></i> <span title='{$build->scmPath}'>" . (strpos($build->scmPath, 'http') === 0 ? html::a($build->scmPath, $build->scmPath, '_blank') : $build->scmPath) . '</span></div>';
if($build->filePath) echo "<div><i class='icon icon-file-archive' title='{$lang->build->filePath}'></i> <span title='{$build->filePath}'>" . (strpos($build->filePath, 'http') === 0 ? html::a($build->filePath, $build->filePath, '_blank') : $build->filePath) . '</span></div>';
?>
</td>
<td class="c-url" title="<?php echo $build->scmPath?>"><?php echo strpos($build->scmPath, 'http') === 0 ? html::a($build->scmPath) : $build->scmPath;?></td>
<td class="c-url" title="<?php echo $build->filePath?>"><?php echo strpos($build->filePath, 'http') === 0 ? html::a($build->filePath) : $build->filePath;?></td>
<td class="c-date"><?php echo $build->date?></td>
<td class="c-user em"><?php echo zget($users, $build->builder);?></td>
<td class="c-actions"><?php echo $this->build->buildOperateMenu($build, 'browse', "executionID={$execution->id}&productID={$productID}");?></td>
+62 -42
View File
@@ -130,61 +130,81 @@
<?php $this->printExtendFields('', 'table', 'columns=3');?>
<?php $hidden = 'hide'?>
<?php if(!empty($project->hasProduct)) $hidden = ''?>
<?php if($products):?>
<?php $i = 0;?>
<?php foreach($products as $product):?>
<tr class="<?php echo $hidden;?>">
<th><?php echo $lang->execution->manageProducts;?></th>
<td class='text-left' id='productsBox' colspan="3">
<th><?php echo $lang->project->manageProductPlan;?></th>
<td class='text-left productsBox' colspan="3">
<div class='row'>
<?php $i = 0;?>
<?php $class = $division ? '' : 'disabled';?>
<?php foreach($products as $product):?>
<?php $hasBranch = ($product->type != 'normal' and isset($branchGroups[$product->id]));?>
<?php foreach($linkedBranches[$product->id] as $branchID => $branch):?>
<div class='col-sm-4'>
<div class="input-group<?php if($hasBranch) echo ' has-branch';?>">
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' $class onchange='loadBranches(this)' data-last='" . $product->id . "'");?>
<?php if($class) echo html::hidden("products[$i]", $product->id);?>
<span class='input-group-addon fix-border'></span>
<?php if($hasBranch) echo html::select("branch[$i]", $branchGroups[$product->id], $branchID, "class='form-control chosen' onchange=\"loadPlans('#products{$i}', this.value)\"");?>
<div class="col-sm-6">
<div class='table-row'>
<div class='table-col'>
<?php $hasBranch = $product->type != 'normal' and isset($branchGroups[$product->id]);?>
<div class='input-group <?php if($hasBranch) echo ' has-branch';?>'>
<span class='input-group-addon'><?php echo $lang->product->common;?></span>
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='" . $product->type . "'");?>
</div>
</div>
<div class='table-col <?php if(!$hasBranch) echo 'hidden';?>'>
<div class='input-group required'>
<span class='input-group-addon fix-border'><?php echo $lang->product->branchName['branch'];?></span>
<?php $branchIdList = join(',', $product->branches);?>
<?php echo html::select("branch[$i][]", isset($branchGroups[$product->id]) ? $branchGroups[$product->id] : array(), $branchIdList, "class='form-control chosen' multiple onchange=\"loadPlans('#products{$i}', this)\"");?>
</div>
</div>
</div>
</div>
<?php $i++;?>
<?php endforeach;?>
<?php endforeach;?>
<?php if((isset($project->model) and $project->model == 'scrum') or empty($products)):?>
<div class='col-sm-4'>
<div class="input-group">
<?php echo html::select("products[$i]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
<span class='input-group-addon fix-border'></span>
<div class="col-sm-6">
<div class='input-group' <?php echo "id='plan$i'";?>>
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
<?php echo html::select("plans[$product->id][]", isset($productPlans[$product->id]) ? $productPlans[$product->id] : array(), $product->plans, "class='form-control chosen' multiple");?>
<div class='input-group-btn'>
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' <?php if($i == 0) echo "style='visibility: hidden'";?>><i class='icon-close'></i></a>
</div>
</div>
</div>
<?php endif;?>
</div>
</td>
</tr>
<?php if(isset($project->model) and $project->model == 'scrum') $hidden = '';?>
<tr class="<?php echo $hidden?>">
<th><?php echo $lang->execution->linkPlan;?></th>
<td colspan="3" id="plansBox">
<?php $i ++;?>
<?php endforeach;?>
<?php else:?>
<tr class='<?php echo $hidden;?>'>
<th id='productTitle'><?php echo $lang->project->manageProductPlan;?></th>
<td class='text-left productsBox' colspan='3'>
<div class='row'>
<?php if(isset($plan) && !empty($plan->begin)):?>
<div class="col-sm-4" id="plan0"><?php echo html::select("plans[{$plan->product}][{$plan->branch}][]", $productPlan, $plan->id, "class='form-control chosen' multiple");?></div>
<?php js::set('currentPlanID', $plan->id)?>
<?php elseif($copyExecutionID):?>
<?php $i = 0;?>
<?php foreach($products as $product):?>
<?php foreach($linkedBranches[$product->id] as $branchID => $branch):?>
<?php $plans = isset($productPlans[$product->id][$branchID]) ? $productPlans[$product->id][$branchID] : array();?>
<div class="col-sm-4" id="plan<?php echo $i;?>"><?php echo html::select("plans[{$product->id}][$branchID][]", $plans, $branches[$product->id][$branchID]->plan, "class='form-control chosen' multiple");?></div>
<?php $i++;?>
<?php endforeach;?>
<?php endforeach;?>
<?php else:?>
<div class="col-sm-4" id="plan0"><?php echo html::select("plans[][][]", $productPlan, '', "class='form-control chosen' multiple");?></div>
<?php js::set('currentPlanID', '')?>
<?php endif;?>
<div class="col-sm-6">
<div class='table-row'>
<div class='table-col'>
<div class='input-group'>
<span class='input-group-addon'><?php echo $lang->product->common;?></span>
<?php echo html::select("products[0]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
</div>
</div>
<div class='table-col hidden'>
<div class='input-group required'>
<span class='input-group-addon fix-border'><?php echo $lang->product->branchName['branch'];?></span>
<?php echo html::select("branch", '', '', "class='form-control chosen' multiple");?>
</div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class='input-group' id='plan0'>
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
<?php echo html::select("plans[][]", $productPlan, '', "class='form-control chosen' multiple");?>
<div class='input-group-btn'>
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' style='visibility: hidden'><i class='icon-close'></i></a>
</div>
</div>
</div>
</div>
</td>
</tr>
<?php endif;?>
<tr>
<th><?php echo $lang->execution->teamname;?></th>
<td><?php echo html::input('team', $team, "class='form-control'");?></td>
+63 -37
View File
@@ -141,56 +141,81 @@
<?php if(!in_array($execution->attribute, array('request', 'design', 'review'))): ?>
<?php $hidden = 'hide'?>
<?php if(!empty($project->hasProduct)) $hidden = ''?>
<?php if($linkedProducts):?>
<?php $i = 0;?>
<?php foreach($linkedProducts as $product):?>
<tr class="<?php echo $hidden;?>">
<th><?php echo $lang->execution->manageProducts;?></th>
<td class='text-left' id='productsBox' colspan="2">
<?php $class = ($execution->grade == 2 or $execution->type == 'stage') ? "disabled" : '';?>
<th><?php if($i == 0) echo $lang->project->manageProductPlan;?></th>
<td class='text-left productsBox' colspan="3">
<div class='row'>
<?php $i = 0;?>
<?php foreach($linkedProducts as $product):?>
<?php $hasBranch = $product->type != 'normal' and isset($branchGroups[$product->id]);?>
<?php foreach($linkedBranches[$product->id] as $branchID => $branch):?>
<div class='col-sm-4'>
<div class="input-group<?php if($hasBranch) echo ' has-branch';?>">
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' $class onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='". $product->type ."' data-lastBranch='" . $branchID . "'");?>
<span class='input-group-addon fix-border'></span>
<?php if($hasBranch) echo html::select("branch[$i]", $branchGroups[$product->id], $branchID, "class='form-control chosen' $class onchange=\"loadPlans('#products{$i}', this.value)\" data-last='" . $branchID . "'");?>
<div class="col-sm-6">
<div class='table-row'>
<div class='table-col'>
<?php $hasBranch = $product->type != 'normal' and isset($branchGroups[$product->id]);?>
<div class='input-group <?php if($hasBranch) echo ' has-branch';?>'>
<span class='input-group-addon'><?php echo $lang->product->common;?></span>
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='" . $product->type . "'");?>
</div>
</div>
<div class='table-col <?php if(!$hasBranch) echo 'hidden';?>'>
<div class='input-group required'>
<span class='input-group-addon fix-border'><?php echo $lang->product->branchName['branch'];?></span>
<?php $branchIdList = join(',', $product->branches);?>
<?php echo html::select("branch[$i][]", isset($branchGroups[$product->id]) ? $branchGroups[$product->id] : array(), $branchIdList, "class='form-control chosen' multiple onchange=\"loadPlans('#products{$i}', this)\"");?>
</div>
</div>
</div>
</div>
<?php $i++; ?>
<?php endforeach;?>
<?php endforeach;?>
<?php if($execution->type != 'stage'):?>
<div class='col-sm-4'>
<div class="input-group">
<?php echo html::select("products[$i]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
<span class='input-group-addon fix-border'></span>
<div class="col-sm-6">
<div class='input-group' <?php echo "id='plan$i'";?>>
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
<?php echo html::select("plans[$product->id][]", isset($productPlans[$product->id]) ? $productPlans[$product->id] : array(), $product->plans, "class='form-control chosen' multiple");?>
<div class='input-group-btn'>
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' <?php if($i == 0) echo "style='visibility: hidden'";?>><i class='icon-close'></i></a>
</div>
</div>
</div>
<?php endif;?>
</div>
</td>
</tr>
<?php if(isset($project->model) and $project->model == 'scrum') $hidden = '';?>
<tr class="<?php echo $hidden?>">
<th><?php echo $lang->execution->linkPlan;?></th>
<td id="plansBox" colspan="2">
<?php $i ++;?>
<?php endforeach;?>
<?php else:?>
<tr class='<?php echo $hidden;?>'>
<th id='productTitle'><?php echo $lang->project->manageProductPlan;?></th>
<td class='text-left productsBox' colspan='3'>
<div class='row'>
<?php $i = 0;?>
<?php if(empty($linkedProducts)):?>
<div class="col-sm-4" id="plan0"><?php echo html::select("plans[][][]", $productPlans, '', "class='form-control chosen' multiple");?></div>
<?php else:?>
<?php foreach($linkedProducts as $product):?>
<?php foreach($linkedBranches[$product->id] as $branchID => $branch):?>
<?php $plans = isset($productPlans[$product->id][$branchID]) ? $productPlans[$product->id][$branchID] : array();?>
<div class="col-sm-4" id="plan<?php echo $i;?>"><?php echo html::select("plans[{$product->id}][{$branchID}][]", $plans, $branches[$product->id][$branchID]->plan, "class='form-control chosen' multiple");?></div>
<?php $i++;?>
<?php endforeach;?>
<?php endforeach;?>
<?php endif;?>
<div class="col-sm-6">
<div class='table-row'>
<div class='table-col'>
<div class='input-group'>
<span class='input-group-addon'><?php echo $lang->product->common;?></span>
<?php echo html::select("products[0]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
</div>
</div>
<div class='table-col hidden'>
<div class='input-group required'>
<span class='input-group-addon fix-border'><?php echo $lang->product->branchName['branch'];?></span>
<?php echo html::select("branch", '', '', "class='form-control chosen' multiple");?>
</div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class='input-group' id='plan0'>
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
<?php echo html::select("plans[][]", '', '', "class='form-control chosen' multiple");?>
<div class='input-group-btn'>
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' style='visibility: hidden'><i class='icon-close'></i></a>
</div>
</div>
</div>
</div>
</td>
</tr>
<?php endif; ?>
<?php else: ?>
<?php echo html::hidden("products[]", key($linkedProducts));?>
<?php endif; ?>
@@ -232,5 +257,6 @@
<?php js::set('confirmSync', $lang->execution->confirmSync);?>
<?php js::set('allProducts', $allProducts);?>
<?php js::set('branchGroups', $branchGroups);?>
<?php js::set('projectID', $execution->project);?>
<?php js::set('unLinkProductTip', $lang->project->unLinkProductTip);?>
<?php include '../../common/view/footer.html.php';?>
@@ -231,4 +231,5 @@ js::set('priv',
<?php js::set('orderBy', $storyOrder);?>
<?php js::set('defaultMinColWidth', $this->config->minColWidth);?>
<?php js::set('defaultMaxColWidth', $this->config->maxColWidth);?>
<?php js::set('teamWords', $lang->execution->teamWords);?>
<?php include '../../common/view/footer.html.php';?>
+3 -4
View File
@@ -780,11 +780,10 @@ class extensionModel extends model
/**
* Update an extension.
*
* @param string $extension
* @param string $status
* @param array $files
* @param string $extension
* @param array|object $data
* @access public
* @return void
* @return int
*/
public function updateExtension($extension, $data)
{
+9 -23
View File
@@ -221,34 +221,20 @@ class file extends control
$this->view->fields = $this->post->fields;
$this->view->rows = $this->post->rows;
$this->host = common::getSysURL();
$kind = $this->post->kind;
switch($this->post->kind)
foreach($this->view->rows as $row)
{
case 'task':
foreach($this->view->rows as $row)
foreach($row as &$field)
{
$row->name = html::a($this->host . $this->createLink('task', 'view', "taskID=$row->id"), $row->name);
if(empty($field)) continue;
$field = preg_replace('/ src="{([0-9]+)(\.(\w+))?}" /', ' src="' . $this->host . helper::createLink('file', 'read', "fileID=$1", "$3") . '" ', $field);
}
break;
case 'story':
foreach($this->view->rows as $row)
{
$row->title= html::a($this->host . $this->createLink('story', 'view', "storyID=$row->id"), $row->title);
}
break;
case 'bug':
foreach($this->view->rows as $row)
{
$row->title= html::a($this->host . $this->createLink('bug', 'view', "bugID=$row->id"), $row->title);
}
break;
case 'testcase':
foreach($this->view->rows as $row)
{
$row->title= html::a($this->host . $this->createLink('testcase', 'view', "caseID=$row->id"), $row->title);
}
break;
if(in_array($kind, array('story', 'bug', 'testcase'))) $row->title = html::a($this->host . $this->createLink($kind, 'view', "{$kind}ID=$row->id"), $row->title);
if($kind == 'task') $row->name = html::a($this->host . $this->createLink('task', 'view', "taskID=$row->id"), $row->name);
}
$this->view->fileName = $this->post->fileName;
$output = $this->parse('file', 'export2Html');
+2 -2
View File
@@ -667,7 +667,6 @@ class fileModel extends model
public function pasteImage($data, $uid = '', $safe = false)
{
if(empty($data)) return '';
$data = str_replace('\"', '"', $data);
$dataLength = strlen($data);
if(ini_get('pcre.backtrack_limit') < $dataLength) ini_set('pcre.backtrack_limit', $dataLength);
@@ -676,7 +675,8 @@ class fileModel extends model
{
foreach($out[3] as $key => $base64Image)
{
$extension = strtolower($out[2][$key]);
$base64Image = str_replace('\"', '"', $base64Image);
$extension = strtolower($out[2][$key]);
if(!in_array($extension, $this->config->file->imageExtensions)) helper::end();
$imageData = base64_decode($base64Image);
+2
View File
@@ -546,6 +546,7 @@ $lang->resource->story->batchChangeModule = 'batchChangeModule';
$lang->resource->story->batchToTask = 'batchToTask';
$lang->resource->story->processStoryChange = 'processStoryChange';
$lang->resource->story->linkStories = 'linkStoriesAB';
$lang->resource->story->relieved = 'relievedSiblings';
$lang->story->methodOrder[5] = 'create';
$lang->story->methodOrder[10] = 'batchCreate';
@@ -575,6 +576,7 @@ $lang->story->methodOrder[120] = 'batchChangeModule';
$lang->story->methodOrder[125] = 'batchToTask';
$lang->story->methodOrder[130] = 'processStoryChange';
$lang->story->methodOrder[135] = 'linkStories';
$lang->story->methodOrder[140] = 'relieved';
/* Requirement. */
$lang->resource->requirement = new stdclass();
+4 -1
View File
@@ -266,7 +266,10 @@ class install extends control
$this->setting->setItem('system.common.safe.changeWeak', '1');
$this->setting->setItem('system.common.global.cron', 1);
if(strpos($this->app->getClientLang(), 'zh') === 0) $this->loadModel('api')->createDemoData($this->lang->api->zentaoAPI, 'http://' . $_SERVER['HTTP_HOST'] . $this->app->config->webRoot . 'api.php/v1', '16.0');
$httpType = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? 'https' : 'http';
if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') $httpType = 'https';
if(isset($_SERVER['REQUEST_SCHEME']) and strtolower($_SERVER['REQUEST_SCHEME']) == 'https') $httpType = 'https';
if(strpos($this->app->getClientLang(), 'zh') === 0) $this->loadModel('api')->createDemoData($this->lang->api->zentaoAPI, "{$httpType}://{$_SERVER['HTTP_HOST']}" . $this->app->config->webRoot . 'api.php/v1', '16.0');
return print(js::locate(inlink('step6'), 'parent'));
}
+7 -2
View File
@@ -818,8 +818,11 @@ class kanbanModel extends model
}
elseif($branchID)
{
$branchName = $this->branch->getById($branchID);
$branches = array($branchID => $branchName);
foreach(explode(',', $branchID) as $id)
{
$branchName = $this->branch->getById($id);
$branches[$id] = $branchName;
}
}
foreach($branches as $id => $name)
@@ -1511,6 +1514,8 @@ class kanbanModel extends model
$cardData['status'] = $object->status;
$cardData['left'] = $object->left;
$cardData['estStarted'] = $object->estStarted;
$cardData['mode'] = $object->mode;
if($object->mode == 'multi') $cardData['teamMembers'] = $object->teamMembers;
}
else
{
+8 -1
View File
@@ -114,7 +114,6 @@ class messageModel extends model
$this->loadModel('webhook')->send($objectType, $objectID, $actionType, $actionID, $actor);
}
}
if(isset($messageSetting['message']))
{
$actions = $messageSetting['message']['setting'];
@@ -201,6 +200,14 @@ class messageModel extends model
if(!empty($notifyPersons)) $toList = implode(',', $notifyPersons);
}
if(empty($toList) and $objectType == 'task' and $object->mode == 'multi')
{
$teamMembers = $this->loadModel('task')->getTeamMembers($object->id);
$toList = array_filter($teamMembers, function($account){
return $account != $this->app->user->account;
});
$toList = implode(',', $toList);
}
if($toList == 'closed') $toList = '';
if($objectType == 'feedback' and $object->status == 'replied') $toList = ',' . $object->openedBy . ',';
+1 -1
View File
@@ -42,7 +42,7 @@ $lang->misc->zentao->support['ask'] = "Official Answer";
$lang->misc->zentao->support['video'] = "Use Video";
$lang->misc->zentao->support['qqgroup'] = "Official QQ Group";
$lang->misc->zentao->cowin['reportbug'] = "Bug melden ";
$lang->misc->zentao->cowin['reportbug'] = "Report Bug";
$lang->misc->zentao->cowin['feedback'] = "Feedback";
$lang->misc->zentao->cowin['recommend'] = "More";
+1 -1
View File
@@ -42,7 +42,7 @@ $lang->misc->zentao->support['ask'] = "Official Answer";
$lang->misc->zentao->support['video'] = "Use Video";
$lang->misc->zentao->support['qqgroup'] = "Official QQ Group";
$lang->misc->zentao->cowin['reportbug'] = "Report Bug ";
$lang->misc->zentao->cowin['reportbug'] = "Report Bug";
$lang->misc->zentao->cowin['feedback'] = "Feedback";
$lang->misc->zentao->cowin['recommend'] = "More";
+1 -1
View File
@@ -42,7 +42,7 @@ $lang->misc->zentao->support['ask'] = "Official Answer";
$lang->misc->zentao->support['video'] = "Use Video";
$lang->misc->zentao->support['qqgroup'] = "Official QQ Group";
$lang->misc->zentao->cowin['reportbug'] = "Signaler un Bug";
$lang->misc->zentao->cowin['reportbug'] = "Report Bug";
$lang->misc->zentao->cowin['feedback'] = "Feedback";
$lang->misc->zentao->cowin['recommend'] = "Plus...";
+1 -1
View File
@@ -42,7 +42,7 @@ $lang->misc->zentao->support['ask'] = "官方问答";
$lang->misc->zentao->support['video'] = "使用视频";
$lang->misc->zentao->support['qqgroup'] = "官方QQ群";
$lang->misc->zentao->cowin['reportbug'] = "汇报Bug";
$lang->misc->zentao->cowin['reportbug'] = "反馈Bug";
$lang->misc->zentao->cowin['feedback'] = "反馈需求";
$lang->misc->zentao->cowin['recommend'] = "推荐给朋友";
+1 -1
View File
@@ -40,7 +40,7 @@ $lang->misc->zentao->support['ask'] = "官方問答";
$lang->misc->zentao->support['video'] = "使用視頻";
$lang->misc->zentao->support['qqgroup'] = "官方QQ群";
$lang->misc->zentao->cowin['reportbug'] = "彙報Bug";
$lang->misc->zentao->cowin['reportbug'] = "反饋Bug";
$lang->misc->zentao->cowin['feedback'] = "反饋需求";
$lang->misc->zentao->cowin['translate'] = "參與翻譯";
$lang->misc->zentao->cowin['recommend'] = "推薦給朋友";
+2 -2
View File
@@ -697,8 +697,8 @@ class mr extends control
$this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getForProducts(array($productID => $productID));
$this->config->bug->search['params']['module']['values'] = $modules;
$this->config->bug->search['params']['execution']['values'] = $this->product->getExecutionPairsByProduct($productID);
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, $branch = 'all', $params = '');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, $branch = 'all', $params = '');
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, $branch = 'all', $params = 'releasetag');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
unset($this->config->bug->search['fields']['product']);
if($product->type == 'normal')
+1 -4
View File
@@ -9,10 +9,7 @@ $config->my->taskCounts = 10;
$config->my->bugCounts = 10;
$config->my->storyCounts = 10;
$config->my->oaObjectType = 'attend,leave,makeup,overtime,lieu';
$config->my->reviewObjectType = 'story,case';
if($config->edition == 'biz') $config->my->reviewObjectType = 'story,case,feedback,attend,leave,makeup,overtime,lieu';
if($config->edition == 'max') $config->my->reviewObjectType = 'story,case,review,feedback,attend,leave,makeup,overtime,lieu';
$config->my->oaObjectType = 'attend,leave,makeup,overtime,lieu';
$config->mobile = new stdclass();
$config->mobile->todoBar = array('today', 'yesterday', 'thisWeek', 'lastWeek', 'all');
+9
View File
@@ -955,15 +955,24 @@ EOF;
$this->app->loadClass('pager', true);
$pager = pager::init($recTotal, $recPerPage, $pageID);
$typeList = array();
if($this->app->rawMethod == 'contribute')
{
$reviewList = $this->my->getReviewedList($browseType, $orderBy, $pager);
}
else
{
$this->lang->my->auditMenu->audit = $this->my->getReviewingTypeList();
$reviewList = $this->my->getReviewingList($browseType, $orderBy, $pager);
}
$this->view->flows = array();
if($this->config->edition == 'max')
{
$this->app->loadLang('approval');
$this->view->flows = $this->dao->select('module,name')->from(TABLE_WORKFLOW)->where('buildin')->eq(0)->fetchPairs('module', 'name');
}
$this->view->title = $this->lang->review->common;
$this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
$this->view->reviewList = $reviewList;
+2
View File
@@ -1 +1,3 @@
.tip {margin-top: 10px;}
.table-form>tbody>tr>th {white-space: nowrap; !important}
.table-form>tbody>tr>td {width: 75%; !important}
+140 -11
View File
@@ -640,7 +640,7 @@ class myModel extends model
$this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairs();
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getAllModulePairs();
$this->config->bug->search['params']['severity']['values'] = array(0 => '') + $this->lang->bug->severityList;
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($products);
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($products, 'all', 'releasetag');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
$this->loadModel('search')->setSearchParams($this->config->bug->search);
@@ -911,7 +911,7 @@ class myModel extends model
$this->config->ticket->search['params']['module']['values'] = array('' => '') + $this->loadModel('tree')->getAllModulePairs();
$grantProducts = $this->loadModel('feedback')->getGrantProducts();
$productIDlist = array_keys($grantProducts);
$this->config->ticket->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productIDlist);
$this->config->ticket->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productIDlist, 'all', 'releasetag');
$this->loadModel('search')->setSearchParams($this->config->ticket->search);
}
@@ -993,6 +993,34 @@ class myModel extends model
return $requirements;
}
/**
* Get reviewing type list for menu.
*
* @access public
* @return object
*/
public function getReviewingTypeList()
{
$typeList = array();
if($this->getReviewingStories('id_desc', true)) $typeList[] = 'story';
if($this->getReviewingCases('id_desc', true)) $typeList[] = 'testcase';
if($this->getReviewingApprovals('id_desc', true)) $typeList[] = 'project';
if($this->getReviewingFeedbacks('id_desc', true)) $typeList[] = 'feedback';
$typeList = array_merge($typeList, $this->getReviewingOA('status', true));
$typeList = array_merge($typeList, $this->getReviewingFlows('all', 'id_desc', true));
$flows = ($this->config->edition == 'open') ? array() : $this->dao->select('module,name')->from(TABLE_WORKFLOW)->where('module')->in($typeList)->andWhere('buildin')->eq(0)->fetchPairs('module', 'name');
$menu = new stdclass();
$menu->all = $this->lang->my->auditMenu->audit->all;
foreach($typeList as $type)
{
$this->app->loadLang($type);
$menu->$type = isset($this->lang->$type->common) ? $this->lang->$type->common : zget($flows, $type);
}
return $menu;
}
/**
* Get reviewing list for me.
*
@@ -1010,6 +1038,7 @@ class myModel extends model
if($browseType == 'all' or $browseType == 'project') $reviewList = array_merge($reviewList, $this->getReviewingApprovals());
if($browseType == 'all' or $browseType == 'feedback') $reviewList = array_merge($reviewList, $this->getReviewingFeedbacks());
if($browseType == 'all' or $browseType == 'oa') $reviewList = array_merge($reviewList, $this->getReviewingOA());
if($browseType == 'all' or !in_array($browseType, array('story', 'testcase', 'project', 'feedback', 'oa'))) $reviewList = array_merge($reviewList, $this->getReviewingFlows($browseType));
if(empty($reviewList)) return array();
@@ -1044,10 +1073,11 @@ class myModel extends model
* Get reviewing stories.
*
* @param string $orderBy
* @param bool $checkExists
* @access public
* @return array
*/
public function getReviewingStories($orderBy = 'id_desc')
public function getReviewingStories($orderBy = 'id_desc', $checkExists = false)
{
if(!common::hasPriv('story', 'review')) return array();
@@ -1066,6 +1096,7 @@ class myModel extends model
$stories = array();
while($data = $stmt->fetch())
{
if($checkExists) return true;
$story = new stdclass();
$story->id = $data->id;
$story->title = $data->title;
@@ -1084,10 +1115,11 @@ class myModel extends model
* Get reviewing cases.
*
* @param string $orderBy
* @param bool $checkExists
* @access public
* @return array
*/
public function getReviewingCases($orderBy = 'id_desc')
public function getReviewingCases($orderBy = 'id_desc', $checkExists = false)
{
if(!common::hasPriv('testcase', 'review')) return array();
@@ -1102,6 +1134,7 @@ class myModel extends model
$cases = array();
while($data = $stmt->fetch())
{
if($checkExists) return true;
$case = new stdclass();
$case->id = $data->id;
$case->title = $data->title;
@@ -1118,10 +1151,11 @@ class myModel extends model
* Get reviewing approvals.
*
* @param string $orderBy
* @param bool $checkExists
* @access public
* @return array
*/
public function getReviewingApprovals($orderBy = 'id_desc')
public function getReviewingApprovals($orderBy = 'id_desc', $checkExists = false)
{
if(!common::hasPriv('review', 'assess')) return array();
if($this->config->edition != 'max') return array();
@@ -1136,6 +1170,7 @@ class myModel extends model
foreach($projectReviews as $review)
{
if(!isset($pendingList[$review->id])) continue;
if($checkExists) return true;
$data = new stdclass();
$data->id = $review->id;
@@ -1149,13 +1184,80 @@ class myModel extends model
}
/**
* Get reviewing feedbacks.
* Get reviewing for flows setting.
*
* @param string $objectType
* @param string $orderBy
* @param bool $checkExists
* @access public
* @return array
*/
public function getReviewingFeedbacks($orderBy = 'id_desc')
public function getReviewingFlows($objectType = 'all', $orderBy = 'id_desc', $checkExists = false)
{
if($this->config->edition != 'max') return array();
$stmt = $this->dao->select('t2.objectType,t2.objectID')->from(TABLE_APPROVALNODE)->alias('t1')
->leftJoin(TABLE_APPROVALOBJECT)->alias('t2')
->on('t2.approval = t1.approval')
->where('t2.objectType')->ne('review')
->beginIF($objectType != 'all')->andWhere('t2.objectType')->eq($objectType)->fi()
->andWhere('t1.account')->eq($this->app->user->account)
->andWhere('t1.status')->eq('doing')
->query();
$objectIdList = array();
while($object = $stmt->fetch()) $objectIdList[$object->objectType][$object->objectID] = $object->objectID;
if($checkExists) return array_keys($objectIdList);
$flows = $this->dao->select('module,`table`,name,titleField')->from(TABLE_WORKFLOW)->where('module')->in(array_keys($objectIdList))->andWhere('buildin')->eq(0)->fetchAll('module');
$objectGroup = array();
foreach($objectIdList as $objectType => $idList)
{
$table = zget($this->config->objectTables, $objectType, '');
if(empty($table) and isset($flows[$objectType])) $table = $flows[$objectType]->table;
if(empty($table)) continue;
$objectGroup[$objectType] = $this->dao->select('*')->from($table)->where('id')->in($idList)->fetchAll('id');
}
$this->app->loadConfig('action');
$approvalList = array();
foreach($objectGroup as $objectType => $objects)
{
$title = '';
$titleFieldName = zget($this->config->action->objectNameFields, $objectType, '');
$openedDateField = 'openedDate';
if(in_array($objectType, array('product', 'productplan', 'release', 'build', 'testtask'))) $openedDateField = 'createdDate';
if(in_array($objectType, array('testsuite', 'caselib')))$openedDateField = 'addedDate';
if(empty($titleFieldName) and isset($flows[$objectType]))
{
if(!empty($flows[$objectType]->titleField)) $titleFieldName = $flows[$objectType]->titleField;
if(empty($flows[$objectType]->titleField)) $title = $flows[$objectType]->name;
$openedDateField = 'createdDate';
}
foreach($objects as $object)
{
$data = new stdclass();
$data->id = $object->id;
$data->title = (empty($titleFieldName) or !isset($object->$titleFieldName)) ? $title . " #{$object->id}" : $object->$titleFieldName;
$data->type = $objectType;
$data->time = $object->$openedDateField;
$data->status = (isset($object->status) and !isset($flows[$objectType])) ? $object->status : 'doing';
$approvalList[] = $data;
}
}
return $approvalList;
}
/**
* Get reviewing feedbacks.
*
* @param string $orderBy
* @param bool $checkExists
* @access public
* @return array
*/
public function getReviewingFeedbacks($orderBy = 'id_desc', $checkExists = false)
{
if(!common::hasPriv('feedback', 'review')) return array();
if($this->config->edition == 'open') return array();
@@ -1164,6 +1266,8 @@ class myModel extends model
$reviewList = array();
foreach($feedbacks as $feedback)
{
if($checkExists) return true;
$data = new stdclass();
$data->id = $feedback->id;
$data->title = $feedback->title;
@@ -1179,10 +1283,11 @@ class myModel extends model
* Get reviewing OA.
*
* @param string $orderBy
* @param bool $checkExists
* @access public
* @return array
*/
public function getReviewingOA($orderBy = 'status')
public function getReviewingOA($orderBy = 'status', $checkExists = false)
{
if($this->config->edition == 'open') return array();
@@ -1203,6 +1308,16 @@ class myModel extends model
if(common::hasPriv('makeup', 'review') and common::hasPriv('makeup', 'view')) $oa['makeup'] = $this->getReviewingMakeups($allDeptList, $managedDeptList, $orderBy);
if(common::hasPriv('lieu', 'review') and common::hasPriv('lieu', 'view')) $oa['lieu'] = $this->getReviewingLieus($allDeptList, $managedDeptList, $orderBy);
if($checkExists)
{
$typeList = array();
foreach($oa as $type => $reviewings)
{
if(!empty($reviewings)) $typeList[$type] = true;
}
return array_keys($typeList);
}
$reviewList = array();
foreach($oa as $type => $reviewings)
{
@@ -1251,19 +1366,19 @@ class myModel extends model
if(empty($actionField)) $actionField = 'date';
$orderBy = $actionField . '_' . $direction;
$condition = "action = 'reviewed'";
$condition = "(action = 'reviewed' or action = 'approvalreview')";
if($browseType == 'createdbyme')
{
$condition = "(objectType in('story','case','feedback') and action = 'submitreview') OR ";
$condition .= "(objectType = 'review' and action = 'opened') OR ";
$condition .= "(objectType = 'attend' and action = 'commited') OR ";
$condition .= "(action = 'approvalsubmit') OR ";
$condition .= "(objectType in('leave','makeup','overtime','lieu') and action = 'created')";
$condition = "($condition)";
}
$actions = $this->dao->select('objectType,objectID,actor,action,MAX(`date`) as `date`,extra')->from(TABLE_ACTION)
->where('actor')->eq($this->app->user->account)
->andWhere('objectType')->in($this->config->my->reviewObjectType)
->andWhere('vision')->eq($this->config->vision)
->andWhere($condition)
->groupBy('objectType,objectID')
@@ -1273,10 +1388,12 @@ class myModel extends model
$objectTypeList = array();
foreach($actions as $action) $objectTypeList[$action->objectType][] = $action->objectID;
$flows = ($this->config->edition == 'open') ? array() : $this->dao->select('module,`table`,name,titleField')->from(TABLE_WORKFLOW)->where('module')->in(array_keys($objectTypeList))->andWhere('buildin')->eq(0)->fetchAll('module');
$objectGroup = array();
foreach($objectTypeList as $objectType => $idList)
{
$table = zget($this->config->objectTables, $objectType, '');
if(empty($table) and isset($flows[$objectType])) $table = $flows[$objectType]->table;
if(empty($table)) continue;
$objectGroup[$objectType] = $this->dao->select('*')->from($table)->where('id')->in($idList)->fetchAll('id');
@@ -1290,6 +1407,7 @@ class myModel extends model
}
$users = $this->loadModel('user')->getPairs('noletter');
$this->app->loadConfig('action');
$reviewList = array();
foreach($actions as $action)
{
@@ -1302,7 +1420,7 @@ class myModel extends model
$review->type = $objectType;
$review->time = $action->date;
$review->result = strtolower($action->extra);
$review->status = $objectType == 'attend' ? $object->reviewStatus : $object->status;
$review->status = $objectType == 'attend' ? $object->reviewStatus : ((isset($object->status) and !isset($flows[$objectType])) ? $object->status : 'done');
if(strpos($review->result, ',') !== false) list($review->result) = explode(',', $review->result);
if($review->type == 'review') $review->type = 'project';
@@ -1320,6 +1438,17 @@ class myModel extends model
{
$review->title = sprintf($this->lang->my->auditField->oaTitle[$objectType], zget($users, $object->createdBy), $object->begin . ' ' . substr($object->start, 0, 5) . ' ~ ' . $object->end . ' ' . substr($object->finish, 0, 5));
}
else
{
$title = '';
$titleFieldName = zget($this->config->action->objectNameFields, $objectType, '');
if(empty($titleFieldName) and isset($flows[$objectType]))
{
if(!empty($flows[$objectType]->titleField)) $titleFieldName = $flows[$objectType]->titleField;
if(empty($flows[$objectType]->titleField)) $title = $flows[$objectType]->name;
}
$review->title = (empty($titleFieldName) or !isset($object->$titleFieldName)) ? $title . " #{$object->id}" : $object->$titleFieldName;
}
$reviewList[] = $review;
}
+12 -3
View File
@@ -55,11 +55,15 @@
$type = $review->type;
if($type == 'project') $type = 'review';
$typeName = $lang->{$review->type}->common;
$typeName = '';
if(isset($lang->{$review->type}->common)) $typeName = $lang->{$review->type}->common;
if($type == 'story') $typeName = $lang->my->auditMenu->audit->story;
if(isset($flows[$review->type])) $typeName = $flows[$review->type];
$statusList = $lang->$type->statusList;
$statusList = array();
if(isset($lang->$type->statusList)) $statusList = $lang->$type->statusList;
if($type == 'attend') $statusList = $lang->attend->reviewStatusList;
if(isset($flows[$review->type])) $statusList = $lang->approval->statusList;
?>
<tr>
<td class='c-id'><?php echo $review->id?></td>
@@ -83,7 +87,8 @@
<td class='c-time text-left'><?php echo $review->time?></td>
<?php if($rawMethod == 'contribute' and $browseType == 'reviewedbyme'):?>
<?php
$reviewResultList = zget($lang->$type, 'reviewResultList', array());
$reviewResultList = array();
if(isset($lang->$type))$reviewResultList = zget($lang->$type, 'reviewResultList', array());
if(strpos(",{$config->my->oaObjectType},", ",$type,") !== false) $reviewResultList = zget($lang->$type, 'reviewStatusList', array());
?>
<td class='c-status'><?php echo zget($reviewResultList, $review->result);?></td>
@@ -114,6 +119,10 @@
{
common::printLink($module, 'view', $params, $reviewIcon, '', "class='btn' data-toggle='modal' title='{$lang->review->common}'", true, true);
}
elseif(!in_array($module, array('story', 'testcase', 'feedback')))
{
common::printLink($module, 'approvalreview', $params, $reviewIcon, '', "class='btn' data-toggle='modal' title='{$lang->review->common}'", true, true);
}
else
{
common::printLink($module, $method, $params, $reviewIcon, '', "class='btn iframe' title='{$lang->review->common}'", true, true);
+52 -11
View File
@@ -257,7 +257,7 @@ class product extends control
$this->products = $this->product->getProducts($projectID, 'all', '', false);
$projectProducts = $this->product->getProducts($projectID);
$productPlans = $this->execution->getPlans($projectProducts, 'skipParent');
$productPlans = $this->execution->getPlans($projectProducts, 'skipParent', $projectID);
if($browseType == 'bybranch') $param = $branchID;
$stories = $this->story->getExecutionStories($projectID, $productID, $branchID, $sort, $browseType, $param, $storyType, '', $pager);
@@ -271,13 +271,31 @@ class product extends control
/* Display status of branch. */
$branchOption = array();
$branchTagOption = array();
if($product and $product->type != 'normal')
if(!$product and $isProjectStory)
{
$branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
foreach($branches as $branchInfo)
/* Get branch display under multiple products. */
$branchOptions = array();
foreach($projectProducts as $projectProduct)
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
if($projectProduct and $projectProduct->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($projectProduct->id, $projectID, 'all');
foreach($branches as $branchInfo) $branchOptions[$projectProduct->id][$branchInfo->id] = $branchInfo->name;
}
}
$this->view->branchOptions = $branchOptions;
}
else
{
if($product and $product->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
foreach($branches as $branchInfo)
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
}
}
@@ -338,7 +356,7 @@ class product extends control
$this->view->productName = $productName;
$this->view->moduleID = $moduleID;
$this->view->stories = $stories;
$this->view->plans = $this->loadModel('productplan')->getPairs($productID, ($branch === 'all' or empty($branch)) ? '' : $branch, '', true);
$this->view->plans = $this->loadModel('productplan')->getPairs($productID, ($branch === 'all' or empty($branch)) ? '' : $branch, 'unexpired', true);
$this->view->productPlans = isset($productPlans) ? array(0 => '') + $productPlans : array();
$this->view->summary = $this->product->summary($stories, $storyType);
$this->view->moduleTree = $moduleTree;
@@ -906,6 +924,22 @@ class product extends control
}
}
/**
* Ajax get product by id.
*
* @param int $productID
* @access public
* @return void
*/
public function ajaxGetProductById($productID)
{
$product = $this->product->getById($productID);
$product->branchSourceName = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
$product->branchName = $this->lang->product->branchName[$product->type];
echo json_encode($product);
}
/**
* AJAX: get projects of a product in html select.
*
@@ -1020,12 +1054,19 @@ class product extends control
public function ajaxGetPlans($productID, $branch = 0, $planID = 0, $fieldID = '', $needCreate = false, $expired = '', $param = '')
{
$param = strtolower($param);
$plans = $this->loadModel('productplan')->getPairs($productID, $branch, $expired, strpos($param, 'skipparent') !== false);
$field = $fieldID ? "plans[$fieldID]" : 'plan';
if(strpos($param, 'forstory') === false)
{
$plans = $this->loadModel('productplan')->getPairs($productID, $branch, $expired, strpos($param, 'skipparent') !== false);
}
else
{
$plans = $this->loadModel('productplan')->getPairsForStory($productID, $branch == '0' ? 'all' : $branch, $param);
}
$field = $fieldID !== '' ? "plans[$fieldID]" : 'plan';
$multiple = strpos($param, 'multiple') === false ? '' : 'multiple';
$output = html::select($field, $plans, $planID, "class='form-control chosen' $multiple");
if($branch == 0 and strpos($param, 'edit')) $output = html::select($field, $plans, $planID, "class='form-control chosen' multiple");
if($branch == 0 and strpos($param, 'edit') and (strpos($param, 'forstory') === false)) $output = html::select($field, $plans, $planID, "class='form-control chosen' multiple");
if(count($plans) == 1 and $needCreate and $needCreate !== 'false')
{
@@ -1351,7 +1392,7 @@ class product extends control
$this->view->title = $this->lang->product->line;
$this->view->position[] = $this->lang->product->line;
$this->view->programs = array('') + $this->loadModel('program')->getTopPairs();
$this->view->programs = array('') + $this->loadModel('program')->getTopPairs('', 'withDeleted');
$this->view->lines = $this->product->getLines();
$this->display();
}
+1
View File
@@ -357,6 +357,7 @@ js::set('vision', $this->config->vision);
<?php foreach($stories as $story):?>
<tr data-id='<?php echo $story->id?>' data-estimate='<?php echo $story->estimate?>' <?php if(!empty($story->children)) echo "data-children=" . count($story->children);?> data-cases='<?php echo zget($storyCases, $story->id, 0);?>'>
<?php $story->from = $from;?>
<?php if(!empty($branchOptions) and isset($branchOptions[$story->product])) $branchOption = $branchOptions[$story->product];?>
<?php if($this->app->getViewType() == 'xhtml'):?>
<?php
foreach($setting as $key => $value)
+1 -1
View File
@@ -30,7 +30,7 @@ $config->productplan->search['fields']['end'] = $lang->productplan->end;
$config->productplan->search['params']['id'] = array('operator' => '=', 'control' => 'input', 'values' => '');
$config->productplan->search['params']['title'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
$config->productplan->search['params']['branch'] = array('operator' => '=', 'control' => 'select', 'values' => '');
$config->productplan->search['params']['branch'] = array('operator' => 'include', 'control' => 'select', 'values' => '');
$config->productplan->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => array('' => '') + $lang->productplan->statusList);
$config->productplan->search['params']['begin'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
$config->productplan->search['params']['end'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');

Some files were not shown because too many files have changed in this diff Show More