Merge branch 'master' of https://github.com/easysoft/zentaopms
This commit is contained in:
@@ -79,6 +79,8 @@ zentaoxx:
|
||||
sed -i 's/sys_user/zt_user/' zentaoxx/db/*.sql
|
||||
sed -i 's/sys_file/zt_file/' zentaoxx/db/*.sql
|
||||
sed -i '/sys_entry/d' zentaoxx/db/*.sql
|
||||
mkdir zentaoxx/tools; cp tools/cn2tw.php zentaoxx/tools; cd zentaoxx/tools; php cn2tw.php
|
||||
rm -rf zentaopms/tools
|
||||
zip -rqm -9 zentaoxx.$(VERSION).zip zentaoxx/*
|
||||
rm -rf xuan.zip xuan zentaoxx
|
||||
package:
|
||||
@@ -92,7 +94,8 @@ package:
|
||||
if [ ! -d "zentaopms/config/ext" ]; then mkdir zentaopms/config/ext; fi
|
||||
for module in `ls zentaopms/module/`; do if [ ! -d "zentaopms/module/$$module/ext" ]; then mkdir zentaopms/module/$$module/ext; fi done
|
||||
find zentaopms/ -name ext |xargs chmod -R 777
|
||||
tools/cn2tw.php
|
||||
mkdir zentaopms/tools; cp tools/cn2tw.php zentaopms/tools; cd zentaopms/tools; php cn2tw.php
|
||||
rm -rf zentaopms/tools
|
||||
pms:
|
||||
make common
|
||||
make zentaoxx
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
update `zt_build` set `deleted`='1' where `project`='0' and `id` in (select `build` from `zt_release` where `deleted`='1');
|
||||
ALTER TABLE `zt_productplan` ADD `parent` mediumint(9) NOT NULL DEFAULT '0' AFTER `branch`;
|
||||
@@ -901,7 +901,7 @@ class block extends control
|
||||
$tasks = $this->dao->select("project, count(id) as totalTasks, count(status in ('wait','doing','pause') or null) as undoneTasks, count(finishedDate like '{$yesterday}%' or null) as yesterdayFinished, sum(if(status != 'cancel', estimate, 0)) as totalEstimate, sum(consumed) as totalConsumed, sum(if(status != 'cancel' and status != 'closed', `left`, 0)) as totalLeft")->from(TABLE_TASK)
|
||||
->where('project')->in($projectIdList)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('parent')->lt(1)
|
||||
->andWhere('parent')->ge(0)
|
||||
->groupBy('project')
|
||||
->fetchAll('project');
|
||||
foreach($tasks as $projectID => $task)
|
||||
|
||||
@@ -295,7 +295,7 @@ js::set('confirmDeleteTemplate', $lang->bug->confirmDeleteTemplate);
|
||||
<tr>
|
||||
<td colspan="3" class="text-center form-actions">
|
||||
<?php echo html::submitButton();?>
|
||||
<?php echo html::backButton();?>
|
||||
<?php if($caseID == 0) echo html::backButton();?>
|
||||
<?php echo html::hidden('case', (int)$caseID) . html::hidden('caseVersion', (int)$version);?>
|
||||
<?php echo html::hidden('result', (int)$runID) . html::hidden('testtask', (int)$testtask);?>
|
||||
</td>
|
||||
|
||||
@@ -274,7 +274,7 @@ class buildModel extends model
|
||||
{
|
||||
foreach($data->bugs as $key => $bugID)
|
||||
{
|
||||
if(isset($_POST['resolvedBy'][$key]))$resolvedPairs[$bugID] = $data->resolvedBy[$key];
|
||||
if(isset($_POST['resolvedBy'][$bugID])) $resolvedPairs[$bugID] = $data->resolvedBy[$bugID];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ $lang->ipLimited = "<html><head><meta http-equiv='Content-Type' content='t
|
||||
$lang->unfold = '+';
|
||||
$lang->fold = '-';
|
||||
$lang->homepage = 'Set Home';
|
||||
$lang->tutorial = 'Tutorial';
|
||||
$lang->noviceTutorial = 'Novice Tutorial';
|
||||
$lang->changeLog = 'Change Log';
|
||||
$lang->manual = 'Manual';
|
||||
$lang->manualUrl = 'https://www.zentao.pm/book/zentaomanual/zentao-installation-11.html';
|
||||
|
||||
@@ -80,7 +80,7 @@ $lang->ipLimited = "<html><head><meta http-equiv='Content-Type' content='t
|
||||
$lang->unfold = '+';
|
||||
$lang->fold = '-';
|
||||
$lang->homepage = '设为模块首页';
|
||||
$lang->tutorial = '新手教程';
|
||||
$lang->noviceTutorial = '新手教程';
|
||||
$lang->changeLog = '修改日志';
|
||||
$lang->manual = '手册';
|
||||
$lang->manualUrl = 'https://www.zentao.net/book/zentaopmshelp.html?fullScreen=zentao';
|
||||
|
||||
@@ -167,7 +167,7 @@ class commonModel extends model
|
||||
if($this->loadModel('user')->isLogon() or ($this->app->company->guest and $this->app->user->account == 'guest'))
|
||||
{
|
||||
if(stripos($method, 'ajax') !== false) return true;
|
||||
if($module == 'misc' and $method == 'downloadClient') return true;
|
||||
if($module == 'misc' and $method == 'downloadclient') return true;
|
||||
if($module == 'block' and $method == 'main') return true;
|
||||
if($module == 'misc' and $method == 'changelog') return true;
|
||||
if($module == 'tutorial') return true;
|
||||
@@ -315,7 +315,7 @@ class commonModel extends model
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo "<a data-toggle='dropdown'>" . $lang->help . "</a>";
|
||||
echo "<ul class='dropdown-menu pull-left'>";
|
||||
if($config->global->flow == 'full' && !commonModel::isTutorialMode() and $app->user->account != 'guest') echo '<li>' . html::a(helper::createLink('tutorial', 'start'), $lang->tutorial, '', "class='iframe' data-class-name='modal-inverse' data-width='800' data-headerless='true' data-backdrop='true' data-keyboard='true'") . "</li>";
|
||||
if($config->global->flow == 'full' && !commonModel::isTutorialMode() and $app->user->account != 'guest') echo '<li>' . html::a(helper::createLink('tutorial', 'start'), $lang->noviceTutorial, '', "class='iframe' data-class-name='modal-inverse' data-width='800' data-headerless='true' data-backdrop='true' data-keyboard='true'") . "</li>";
|
||||
echo '<li>' . html::a($lang->manualUrl, $lang->manual, '_blank', "class='open-help-tab'") . '</li>';
|
||||
echo '<li>' . html::a(helper::createLink('misc', 'changeLog'), $lang->changeLog, '', "class='iframe' data-width='800' data-headerless='true' data-backdrop='true' data-keyboard='true'") . '</li>';
|
||||
echo "</ul></li>\n";
|
||||
|
||||
@@ -31,8 +31,9 @@ class custom extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function set($module = 'story', $field = 'priList', $lang = 'zh_cn')
|
||||
public function set($module = 'story', $field = 'priList', $lang = '')
|
||||
{
|
||||
if(empty($lang)) $lang = $this->app->getClientLang();
|
||||
if($module == 'user' and $field == 'priList') $field = 'roleList';
|
||||
if($module == 'block' and $field == 'priList')$field = 'closed';
|
||||
$currentLang = $this->app->getClientLang();
|
||||
@@ -159,7 +160,7 @@ class custom extends control
|
||||
}
|
||||
}
|
||||
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
$this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'reload'));
|
||||
$this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('custom', 'set', "module=$module&field=$field&lang=" . str_replace('-', '_', $lang))));
|
||||
}
|
||||
|
||||
/* Check whether the current language has been customized. */
|
||||
|
||||
@@ -796,6 +796,7 @@ class doc extends control
|
||||
}
|
||||
elseif($from == 'project')
|
||||
{
|
||||
$this->lang->modulePageActions = common::hasPriv('doc', 'createLib') ? html::a(helper::createLink('doc', 'createLib', "from=project&projectID=$objectID"), "<i class='icon icon-folder-plus'></i> " . $this->lang->doc->createLib, '', "class='btn btn-secondary iframe'") : '';
|
||||
$this->lang->doc->menu = $this->lang->project->menu;
|
||||
$this->lang->doc->menuOrder = $this->lang->project->menuOrder;
|
||||
$this->project->setMenu($this->project->getPairs('nocode'), $objectID);
|
||||
|
||||
@@ -324,7 +324,7 @@ class gitModel extends model
|
||||
list($hash, $account, $date) = $log;
|
||||
|
||||
$account = preg_replace('/^Author:/', '', $account);
|
||||
$account = trim(preg_replace('/<[\w\-\.]+@([\w\-]+\.)+\w+>/', '', $account));
|
||||
$account = trim(preg_replace('/<[\w\-\.]+@[\w\-]+>/', '', $account));
|
||||
$date = trim(preg_replace('/^Date:/', '', $date));
|
||||
|
||||
$count = count($log);
|
||||
|
||||
@@ -59,16 +59,15 @@ class misc extends control
|
||||
/**
|
||||
* Check current version is latest or not.
|
||||
*
|
||||
* @param string $sn
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function checkUpdate()
|
||||
public function checkUpdate($sn)
|
||||
{
|
||||
$note = isset($_GET['note']) ? $_GET['note'] : '';
|
||||
$browser = isset($_GET['browser']) ? $_GET['browser'] : '';
|
||||
|
||||
$this->view->note = urldecode(helper::safe64Decode($note));
|
||||
$this->view->browser = $browser;
|
||||
session_write_close();
|
||||
$link = $this->lang->misc->api . "/updater-isLatest-{$this->config->version}-{$sn}.html?lang=" . str_replace('-', '_', $this->app->getClientLang());
|
||||
$this->view->note = file_get_contents($link);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php error_reporting(0);?>
|
||||
<html xmlns='http://www.w3.org/1999/xhtml'>
|
||||
<head><meta http-equiv='Content-Type' content='text/html; charset=utf-8' /></head>
|
||||
<body <?php if($browser != 'opera') echo "bgcolor='transparent'";?> style='color:white; font-size:13px; text-align:center'>
|
||||
<body <?php if(strpos($this->server->http_user_agen, 'opera') === false) echo "bgcolor='transparent'";?> style='color:white; font-size:13px; text-align:center'>
|
||||
<?php if($note):?>
|
||||
<?php echo $note;?>
|
||||
<script>window.parent.document.getElementById('updater').className=''</script>
|
||||
|
||||
@@ -622,6 +622,18 @@ class productModel extends model
|
||||
$roadmap = array();
|
||||
$total = 0;
|
||||
|
||||
$parents = array();
|
||||
foreach($plans as $planID => $plan)
|
||||
{
|
||||
if($plan->parent == '-1')
|
||||
{
|
||||
$parents[$planID] = $plan->title;
|
||||
unset($plans[$planID]);
|
||||
}
|
||||
|
||||
if($plan->parent > 0 and isset($parents[$plan->parent])) $plan->title = $parents[$plan->parent] . ' / ' . $plan->title;
|
||||
}
|
||||
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
if(($plan->end != '0000-00-00' and strtotime($plan->end) - time() <= 0) or $plan->end == '2030-01-01') continue;
|
||||
|
||||
@@ -42,7 +42,7 @@ class productplan extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function create($product = '', $branch = 0)
|
||||
public function create($product = '', $branch = 0, $parent = 0)
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -54,7 +54,7 @@ class productplan extends control
|
||||
}
|
||||
|
||||
$this->commonAction($product, $branch);
|
||||
$lastPlan = $this->productplan->getLast($product);
|
||||
$lastPlan = $this->productplan->getLast($product, $branch, $parent);
|
||||
if($lastPlan)
|
||||
{
|
||||
$timestamp = strtotime($lastPlan->end);
|
||||
@@ -65,11 +65,15 @@ class productplan extends control
|
||||
$begin = date('Y-m-d', strtotime("+$delta days", $timestamp));
|
||||
}
|
||||
$this->view->begin = $lastPlan ? $begin : '';
|
||||
if($parent) $this->view->parentPlan = $this->productplan->getById($parent);
|
||||
|
||||
$this->view->title = $this->view->product->name . $this->lang->colon . $this->lang->productplan->create;
|
||||
$this->view->lastPlan = $lastPlan;
|
||||
$this->view->title = $this->view->product->name . $this->lang->colon . $this->lang->productplan->create;
|
||||
$this->view->position[] = $this->lang->productplan->common;
|
||||
$this->view->position[] = $this->lang->productplan->create;
|
||||
|
||||
$this->view->lastPlan = $lastPlan;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->parent = $parent;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -206,6 +210,7 @@ class productplan extends control
|
||||
$this->view->title = $products[$productID] . $this->lang->colon . $this->lang->productplan->browse;
|
||||
$this->view->position[] = $this->lang->productplan->browse;
|
||||
$this->view->productID = $productID;
|
||||
$this->view->branch = $branch;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->plans = $this->productplan->getList($productID, $branch, $browseType, $pager, $sort);
|
||||
@@ -265,6 +270,9 @@ class productplan extends control
|
||||
$orderBy = str_replace('id', 'order', $orderBy);
|
||||
}
|
||||
|
||||
if($plan->parent > 0) $this->view->parentPlan = $this->productplan->getById($plan->parent);
|
||||
if($plan->parent == '-1') $this->view->childrenPlans = $this->productplan->getChildren($plan->id);
|
||||
|
||||
$this->loadModel('datatable');
|
||||
$this->view->modulePairs = $this->loadModel('tree')->getOptionMenu($plan->product, 'story');
|
||||
$this->view->title = "PLAN #$plan->id $plan->title/" . $products[$plan->product];
|
||||
|
||||
@@ -1 +1,13 @@
|
||||
.table td.content { overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
|
||||
|
||||
.table-children {border-left: 2px solid #cbd0db; border-right: 2px solid #cbd0db;}
|
||||
.table tbody > tr.table-children.table-child-top {border-top: 2px solid #cbd0db;}
|
||||
.table tbody > tr.table-children.table-child-bottom {border-bottom: 2px solid #cbd0db;}
|
||||
.table td.has-child > a {max-width: 90%; max-width: calc(100% - 30px); display: inline-block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
|
||||
.table td.has-child > .task-toggle {color: #838a9d; position: relative; top: 1px;}
|
||||
.table td.has-child > .task-toggle:hover {color: #006af1; cursor: pointer;}
|
||||
.table td.has-child > .task-toggle > .icon {font-size: 16px; display: inline-block; transition: transform .2s; -ms-transform:rotate(-90deg); -moz-transform:rotate(-90deg); -o-transform:rotate(-90deg); -webkit-transform:rotate(-90deg); transform: rotate(-90deg);}
|
||||
.table td.has-child > .task-toggle > .icon:before {text-align: left;}
|
||||
.table td.has-child > .task-toggle.collapsed > .icon {-ms-transform:rotate(90deg); -moz-transform:rotate(90deg); -o-transform:rotate(90deg); -webkit-transform:rotate(90deg); transform: rotate(90deg);}
|
||||
.main-table tbody > tr.table-children > td:first-child::before {width: 3px;}
|
||||
@-moz-document url-prefix() {.main-table tbody > tr.table-children > td:first-child::before {width: 4px;}}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
$(document).on('click', '.task-toggle', function(e)
|
||||
{
|
||||
var $toggle = $(this);
|
||||
var id = $(this).data('id');
|
||||
var isCollapsed = $toggle.toggleClass('collapsed').hasClass('collapsed');
|
||||
$toggle.closest('[data-ride="table"]').find('tr.parent-' + id).toggle(!isCollapsed);
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
@@ -27,6 +27,7 @@ $lang->productplan->batchUnlinkStory = "Batch Unlink";
|
||||
$lang->productplan->linkedStories = 'Linked Story';
|
||||
$lang->productplan->unlinkedStories = 'Unlinked Story';
|
||||
$lang->productplan->updateOrder = 'Sort';
|
||||
$lang->productplan->createChildren = "Create subplans";
|
||||
|
||||
$lang->productplan->linkBug = "Link Bug";
|
||||
$lang->productplan->unlinkBug = "Unlink Bug";
|
||||
@@ -54,6 +55,8 @@ $lang->productplan->stories = 'Stories';
|
||||
$lang->productplan->bugs = 'Bugs';
|
||||
$lang->productplan->hour = 'Hour';
|
||||
$lang->productplan->project = $lang->projectCommon;
|
||||
$lang->productplan->parent = "Father plan";
|
||||
$lang->productplan->children= "Sub plan";
|
||||
|
||||
$lang->productplan->endList[7] = '1 Week';
|
||||
$lang->productplan->endList[14] = '2 Weeks';
|
||||
|
||||
@@ -27,6 +27,7 @@ $lang->productplan->batchUnlinkStory = "批量移除需求";
|
||||
$lang->productplan->linkedStories = '需求';
|
||||
$lang->productplan->unlinkedStories = '未关联需求';
|
||||
$lang->productplan->updateOrder = '排序';
|
||||
$lang->productplan->createChildren = "创建子计划";
|
||||
|
||||
$lang->productplan->linkBug = "关联Bug";
|
||||
$lang->productplan->unlinkBug = "移除Bug";
|
||||
@@ -54,6 +55,8 @@ $lang->productplan->stories = '需求数';
|
||||
$lang->productplan->bugs = 'Bug数';
|
||||
$lang->productplan->hour = '工时';
|
||||
$lang->productplan->project = $lang->projectCommon;
|
||||
$lang->productplan->parent = "父计划";
|
||||
$lang->productplan->children= "子计划";
|
||||
|
||||
$lang->productplan->endList[7] = '一星期';
|
||||
$lang->productplan->endList[14] = '两星期';
|
||||
|
||||
+162
-35
@@ -47,14 +47,18 @@ class productplanModel extends model
|
||||
* Get last plan.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $branch
|
||||
* @param int $parent
|
||||
* @access public
|
||||
* @return void
|
||||
* @return object
|
||||
*/
|
||||
public function getLast($productID, $branch = 0)
|
||||
public function getLast($productID, $branch = 0, $parent = 0)
|
||||
{
|
||||
return $this->dao->select('*')->from(TABLE_PRODUCTPLAN)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('product')->eq($productID)
|
||||
->beginIF($parent <= 0)->andWhere('parent')->le((int)$parent)->fi()
|
||||
->beginIF($parent > 0)->andWhere('parent')->eq((int)$parent)->fi()
|
||||
->andWhere('product')->eq((int)$productID)
|
||||
->andWhere('end')->ne('2030-01-01')
|
||||
->beginIF($branch)->andWhere('branch')->eq($branch)->fi()
|
||||
->orderBy('end desc')
|
||||
@@ -75,8 +79,8 @@ class productplanModel extends model
|
||||
*/
|
||||
public function getList($product = 0, $branch = 0, $browseType = 'all', $pager = null, $orderBy = 'begin_desc')
|
||||
{
|
||||
$date = date('Y-m-d');
|
||||
$productPlans = $this->dao->select('t1.*,t2.project')->from(TABLE_PRODUCTPLAN)->alias('t1')
|
||||
$date = date('Y-m-d');
|
||||
$plans = $this->dao->select('t1.*,t2.project')->from(TABLE_PRODUCTPLAN)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t2.plan = t1.id and t2.product = ' . $product)
|
||||
->where('t1.product')->eq($product)
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
@@ -87,21 +91,64 @@ class productplanModel extends model
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
|
||||
if(!empty($productPlans))
|
||||
if(!empty($plans))
|
||||
{
|
||||
foreach($productPlans as $productPlan)
|
||||
$plans = $this->reorder4Children($plans);
|
||||
$planIdList = array_keys($plans);
|
||||
|
||||
$product = $this->loadModel('product')->getById($product);
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
$stories = $this->dao->select('id,estimate')->from(TABLE_STORY)
|
||||
->where("CONCAT(',', plan, ',')")->like("%,{$productPlan->id},%")
|
||||
$storyGroups = $this->dao->select('id,plan,estimate')->from(TABLE_STORY)
|
||||
->where("plan")->in($planIdList)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchPairs('id', 'estimate');
|
||||
$productPlan->stories = count($stories);
|
||||
$productPlan->bugs = $this->dao->select()->from(TABLE_BUG)->where("plan")->eq($productPlan->id)->andWhere('deleted')->eq(0)->count();
|
||||
$productPlan->hour = array_sum($stories);
|
||||
$productPlan->projectID = $productPlan->project;
|
||||
->fetchGroup('plan', 'id');
|
||||
}
|
||||
|
||||
$bugs = $this->dao->select('*')->from(TABLE_BUG)->where("plan")->in($planIdList)->andWhere('deleted')->eq(0)->fetchGroup('plan', 'id');
|
||||
$parentStories = $parentBugs = $parentHour = array();
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
$stories = zget($storyGroups, $plan->id, array());
|
||||
$storyPairs = array();
|
||||
foreach($stories as $story) $storyPairs[$story->id] = $story->estimate;
|
||||
}
|
||||
else
|
||||
{
|
||||
$storyPairs = $this->dao->select('id,estimate')->from(TABLE_STORY)
|
||||
->where("CONCAT(',', plan, ',')")->like("%,{$plan->id},%")
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchPairs('id', 'estimate');
|
||||
}
|
||||
$plan->stories = count($storyPairs);
|
||||
$plan->bugs = isset($bugs[$plan->id]) ? count($bugs[$plan->id]) : 0;
|
||||
$plan->hour = array_sum($storyPairs);
|
||||
$plan->projectID = $plan->project;
|
||||
|
||||
if(!isset($parentStories[$plan->parent])) $parentStories[$plan->parent] = 0;
|
||||
if(!isset($parentBugs[$plan->parent])) $parentBugs[$plan->parent] = 0;
|
||||
if(!isset($parentHour[$plan->parent])) $parentHour[$plan->parent] = 0;
|
||||
|
||||
$parentStories[$plan->parent] += $plan->stories;
|
||||
$parentBugs[$plan->parent] += $plan->bugs;
|
||||
$parentHour[$plan->parent] += $plan->hour;
|
||||
}
|
||||
|
||||
unset($parentStories[0]);
|
||||
unset($parentBugs[0]);
|
||||
unset($parentHour[0]);
|
||||
foreach($parentStories as $parentID => $count)
|
||||
{
|
||||
if(!isset($plans[$parentID])) continue;
|
||||
$plan = $plans[$parentID];
|
||||
$plan->stories += $count;
|
||||
$plan->bugs += $parentBugs[$parentID];
|
||||
$plan->hour += $parentHour[$parentID];
|
||||
}
|
||||
}
|
||||
return $productPlans;
|
||||
return $plans;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,17 +163,17 @@ class productplanModel extends model
|
||||
public function getPairs($product = 0, $branch = 0, $expired = '')
|
||||
{
|
||||
$date = date('Y-m-d');
|
||||
$plans = $this->dao->select('id,CONCAT(title, " [", begin, " ~ ", end, "]") as title')->from(TABLE_PRODUCTPLAN)
|
||||
$plans = $this->dao->select('id,title,parent,begin,end')->from(TABLE_PRODUCTPLAN)
|
||||
->where('product')->in($product)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($branch)->andWhere("branch")->in("0,$branch")->fi()
|
||||
->beginIF($expired == 'unexpired')->andWhere('end')->ge($date)->fi()
|
||||
->orderBy('begin desc')
|
||||
->fetchPairs();
|
||||
->fetchAll('id');
|
||||
|
||||
if($expired == 'unexpired')
|
||||
{
|
||||
$plans += $this->dao->select('id,CONCAT(title, " [", begin, " ~ ", end, "]") as title')->from(TABLE_PRODUCTPLAN)
|
||||
$plans += $this->dao->select('id,title,parent,begin,end')->from(TABLE_PRODUCTPLAN)
|
||||
->where('product')->in($product)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('end')->lt($date)
|
||||
@@ -134,14 +181,25 @@ class productplanModel extends model
|
||||
->beginIF($plans)->andWhere("id")->notIN(array_keys($plans))->fi()
|
||||
->orderBy('begin desc')
|
||||
->limit(5)
|
||||
->fetchPairs();
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
foreach($plans as $key => $value)
|
||||
$plans = $this->reorder4Children($plans);
|
||||
$planPairs = array();
|
||||
$parent = 0;
|
||||
$parentTitle = '';
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
$plans[$key] = str_replace('[2030-01-01 ~ 2030-01-01]', '[' . $this->lang->productplan->future . ']', $value);
|
||||
if($plan->parent == '-1')
|
||||
{
|
||||
$parent = $plan->id;
|
||||
$parentTitle = $plan->title;
|
||||
}
|
||||
if($plan->parent > 0 and $plan->parent == $parent) $plan->title = $parentTitle . ' /' . $plan->title;
|
||||
$planPairs[$plan->id] = $plan->title . " [{$plan->begin} ~ {$plan->end}]";
|
||||
if($plan->begin == '2030-01-01' and $plan->end == '2030-01-01') $planPairs[$plan->id] = $plan->title . ' ' . $this->lang->productplan->future;
|
||||
}
|
||||
return array('' => '') + $this->processFuture($plans);
|
||||
return array('' => '') + $planPairs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,27 +213,43 @@ class productplanModel extends model
|
||||
public function getPairsForStory($product = 0, $branch = 0)
|
||||
{
|
||||
$date = date('Y-m-d');
|
||||
$plans = $this->dao->select('id, CONCAT(title, " [", begin, " ~ ", end, "]") AS title')->from(TABLE_PRODUCTPLAN)
|
||||
$plans = $this->dao->select('id,title,parent,begin,end')->from(TABLE_PRODUCTPLAN)
|
||||
->where('product')->in($product)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('end')->ge($date)
|
||||
->beginIF($branch)->andWhere("branch")->in("0,$branch")->fi()
|
||||
->orderBy('begin desc')
|
||||
->fetchPairs();
|
||||
->fetchAll('id');
|
||||
|
||||
if(!$plans)
|
||||
{
|
||||
$plans = $this->dao->select('id, CONCAT(title, " [", begin, " ~ ", end, "]") AS title')->from(TABLE_PRODUCTPLAN)
|
||||
$plans = $this->dao->select('id,title,parent,begin,end')->from(TABLE_PRODUCTPLAN)
|
||||
->where('product')->in($product)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('end')->lt($date)
|
||||
->beginIF($branch)->andWhere("branch")->in("0,$branch")->fi()
|
||||
->orderBy('begin desc')
|
||||
->limit(5)
|
||||
->fetchPairs();
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
return array('' => '') + $this->processFuture($plans);
|
||||
$plans = $this->reorder4Children($plans);
|
||||
$planPairs = array();
|
||||
$parent = 0;
|
||||
$parentTitle = '';
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
if($plan->parent == '-1')
|
||||
{
|
||||
$parent = $plan->id;
|
||||
$parentTitle = $plan->title;
|
||||
}
|
||||
if($plan->parent > 0 and $plan->parent == $parent) $plan->title = $parentTitle . ' /' . $plan->title;
|
||||
$planPairs[$plan->id] = $plan->title . " [{$plan->begin} ~ {$plan->end}]";
|
||||
if($plan->begin == '2030-01-01' and $plan->end == '2030-01-01') $planPairs[$plan->id] = $plan->title . ' ' . $this->lang->productplan->future;
|
||||
}
|
||||
|
||||
return array('' => '') + $planPairs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,10 +261,39 @@ class productplanModel extends model
|
||||
*/
|
||||
public function getForProducts($products)
|
||||
{
|
||||
return array('' => '') + $this->dao->select('id,title')->from(TABLE_PRODUCTPLAN)
|
||||
$plans = $this->dao->select('id,title,parent,begin,end')->from(TABLE_PRODUCTPLAN)
|
||||
->where('product')->in(array_keys($products))
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy('begin desc')->fetchPairs();
|
||||
->orderBy('begin desc')
|
||||
->fetchAll('id');
|
||||
|
||||
$plans = $this->reorder4Children($plans);
|
||||
$planPairs = array();
|
||||
$parent = 0;
|
||||
$parentTitle = '';
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
if($plan->parent == '-1')
|
||||
{
|
||||
$parent = $plan->id;
|
||||
$parentTitle = $plan->title;
|
||||
}
|
||||
if($plan->parent > 0 and $plan->parent == $parent) $plan->title = $parentTitle . ' /' . $plan->title;
|
||||
$planPairs[$plan->id] = $plan->title;
|
||||
}
|
||||
return array('' => '') + $planPairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Children plan.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getChildren($planID)
|
||||
{
|
||||
return $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('parent')->eq((int)$planID)->andWhere('deleted')->eq('0')->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,6 +331,7 @@ class productplanModel extends model
|
||||
$planID = $this->dao->lastInsertID();
|
||||
$this->file->updateObjectID($this->post->uid, $planID, 'plan');
|
||||
$this->loadModel('score')->create('productplan', 'create', $planID);
|
||||
if(!empty($plan->parent)) $this->dao->update(TABLE_PRODUCTPLAN)->set('parent')->eq('-1')->where('id')->eq($plan->parent)->andWhere('parent')->eq('0')->exec();
|
||||
return $planID;
|
||||
}
|
||||
}
|
||||
@@ -425,18 +529,41 @@ class productplanModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* Process future of plans.
|
||||
*
|
||||
* @param array $plans
|
||||
* Reorder for children plans.
|
||||
*
|
||||
* @param array $plans
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function processFuture($plans)
|
||||
public function reorder4Children($plans)
|
||||
{
|
||||
foreach($plans as $key => $value)
|
||||
/* Get children and unset. */
|
||||
$childrenPlans = array();
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
$plans[$key] = str_replace('[2030-01-01 ~ 2030-01-01]', '[' . $this->lang->productplan->future . ']', $value);
|
||||
if($plan->parent > 0)
|
||||
{
|
||||
$childrenPlans[$plan->parent][$plan->id] = $plan;
|
||||
if(isset($plans[$plan->parent])) unset($plans[$plan->id]);
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($childrenPlans))
|
||||
{
|
||||
/* Append to parent plan. */
|
||||
$reorderedPlans = array();
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
$reorderedPlans[$plan->id] = $plan;
|
||||
if(isset($childrenPlans[$plan->id]))
|
||||
{
|
||||
$plan->children = count($childrenPlans[$plan->id]);
|
||||
foreach($childrenPlans[$plan->id] as $childrenPlan) $reorderedPlans[$childrenPlan->id] = $childrenPlan;
|
||||
}
|
||||
}
|
||||
$plans = $reorderedPlans;
|
||||
}
|
||||
|
||||
return $plans;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,14 +63,33 @@
|
||||
<th class='w-60px'> <?php echo $lang->productplan->hour;?></th>
|
||||
<th class='w-60px'> <?php echo $lang->productplan->project;?></th>
|
||||
<th> <?php echo $lang->productplan->desc;?></th>
|
||||
<th class='c-actions-5 text-center'><?php echo $lang->actions;?></th>
|
||||
<th class='c-actions-6 text-center'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $this->loadModel('file');?>
|
||||
<?php foreach($plans as $plan):?>
|
||||
<?php $plan = $this->file->replaceImgURL($plan, 'desc');?>
|
||||
<tr>
|
||||
<?php
|
||||
$plan = $this->file->replaceImgURL($plan, 'desc');
|
||||
if($plan->parent == '-1')
|
||||
{
|
||||
$parent = $plan->id;
|
||||
$children = $plan->children;
|
||||
}
|
||||
if($plan->parent == 0) $parent = 0;
|
||||
if(!empty($parent) and $plan->parent > 0 and $plan->parent != $parent) $parent = 0;
|
||||
if($plan->parent <= 0) $i = 0;
|
||||
|
||||
$class = '';
|
||||
if(!empty($parent) and $plan->parent == $parent)
|
||||
{
|
||||
$class = "table-children parent-{$parent}";
|
||||
$class .= $i == 0 ? ' table-child-top' : '';
|
||||
$class .= ($i + 1 == $children) ? ' table-child-bottom' : '';
|
||||
$i++;
|
||||
}
|
||||
?>
|
||||
<tr class='<?php echo $class;?>'>
|
||||
<td class='cell-id'>
|
||||
<?php if(common::hasPriv('productplan', 'batchEdit')):?>
|
||||
<?php echo html::checkbox('planIDList', array($plan->id => '')) . html::a(helper::createLink('productplan', 'view', "planID=$plan->id"), sprintf('%03d', $plan->id));?>
|
||||
@@ -78,7 +97,12 @@
|
||||
<?php echo sprintf('%03d', $plan->id);?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td class='text-left' title="<?php echo $plan->title?>"><?php echo html::a(inlink('view', "id=$plan->id"), $plan->title);?></td>
|
||||
<td class='text-left<?php if($plan->parent == '-1') echo ' has-child';?>' title="<?php echo $plan->title?>">
|
||||
<?php
|
||||
echo html::a(inlink('view', "id=$plan->id"), $plan->title);
|
||||
if($plan->parent == '-1') echo '<a class="task-toggle" data-id="' . $plan->id . '"><i class="icon icon-angle-double-right"></i></a>';
|
||||
?>
|
||||
</td>
|
||||
<?php if($this->session->currentProductType != 'normal'):?>
|
||||
<td><?php echo $branches[$plan->branch];?></td>
|
||||
<?php endif;?>
|
||||
@@ -95,6 +119,11 @@
|
||||
if(common::hasPriv('productplan', 'linkStory')) echo html::a(inlink('view', "planID=$plan->id&type=story&orderBy=id_desc&link=true"), '<i class="icon-link"></i>', '', "class='btn' title='{$lang->productplan->linkStory}'");
|
||||
if(common::hasPriv('productplan', 'linkBug') and $config->global->flow != 'onlyStory') echo html::a(inlink('view', "planID=$plan->id&type=bug&orderBy=id_desc&link=true"), '<i class="icon-bug"></i>', '', "class='btn' title='{$lang->productplan->linkBug}'");
|
||||
common::printIcon('productplan', 'edit', "planID=$plan->id", $plan, 'list');
|
||||
if(common::hasPriv('productplan', 'create'))
|
||||
{
|
||||
if($plan->parent > '0') echo "<button type='button' class='disabled btn'><i class='disabled icon-treemap-alt' title='{$this->lang->productplan->children}'></i></button>";
|
||||
if($plan->parent <= '0') echo html::a($this->createLink('productplan', 'create', "product=$productID&branch=$branch&parent={$plan->id}"), "<i class='icon-treemap-alt'></i>", '', "class='btn' title='{$this->lang->productplan->children}'");
|
||||
}
|
||||
|
||||
if(common::hasPriv('productplan', 'delete', $plan))
|
||||
{
|
||||
|
||||
@@ -17,11 +17,17 @@
|
||||
<div id='mainContent'class='main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2> <?php echo $lang->productplan->create;?></h2>
|
||||
<h2> <?php echo $parent ? $lang->productplan->createChildren : $lang->productplan->create;?></h2>
|
||||
</div>
|
||||
<form class='load-indicator main-form form-ajax' method='post' target='hiddenwin' id='dataform'>
|
||||
<table class='table table-form'>
|
||||
<tbody>
|
||||
<?php if($parent):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->parent;?></th>
|
||||
<td class='muted'><?php echo $parentPlan->title;?></td><td></td><td></td>
|
||||
</tr>
|
||||
<?php else:?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->product;?></th>
|
||||
<td class='muted'><?php echo $product->name;?></td><td></td><td></td>
|
||||
@@ -32,6 +38,7 @@
|
||||
<td><?php echo html::select('branch', $branches, $branch, "class='form-control chosen'");?></td><td></td><td></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->title;?></th>
|
||||
<td><?php echo html::input('title', '', "class='form-control' autocomplete='off' required");?></td>
|
||||
@@ -61,6 +68,8 @@
|
||||
<?php echo html::submitButton();?>
|
||||
<?php echo html::backButton();?>
|
||||
<?php echo html::hidden('product', $product->id);?>
|
||||
<?php if($parent) echo html::hidden('branch', $parentPlan->branch);?>
|
||||
<?php echo html::hidden('parent', $parent);?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
{
|
||||
echo html::a(inlink('view', "planID=$plan->id&type=bug&orderBy=id_desc&link=true"), '<i class="icon-bug"></i> ' . $lang->productplan->linkBug, '', "class='btn btn-link'");
|
||||
}
|
||||
if(common::hasPriv('productplan', 'create') and $plan->parent <= '0') echo html::a($this->createLink('productplan', 'create', "product={$plan->product}&branch={$plan->branch}&parent={$plan->id}"), "<i class='icon-treemap-alt'></i>", '', "class='btn btn-link' title='{$this->lang->productplan->children}'");
|
||||
common::printIcon('productplan', 'edit', "planID=$plan->id", $plan);
|
||||
common::printIcon('productplan', 'delete', "planID=$plan->id", $plan, 'button', '', 'hiddenwin');
|
||||
}
|
||||
@@ -416,6 +417,12 @@
|
||||
<th class='w-80px strong'><?php echo $lang->productplan->title;?></th>
|
||||
<td><?php echo $plan->title;?></td>
|
||||
</tr>
|
||||
<?php if($plan->parent > 0):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->parent;?></th>
|
||||
<td><?php echo html::a(inlink('view', "planID={$parentPlan->id}"), "#{$parentPlan->id} " . $parentPlan->title);?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<?php if($product->type != 'normal'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->branch;?></th>
|
||||
@@ -430,6 +437,16 @@
|
||||
<th><?php echo $lang->productplan->end;?></th>
|
||||
<td><?php echo $plan->end == '2030-01-01' ? $lang->productplan->future : $plan->end;?></td>
|
||||
</tr>
|
||||
<?php if($plan->parent == '-1'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->children;?></th>
|
||||
<td>
|
||||
<?php foreach($childrenPlans as $childrenPlan):?>
|
||||
<?php echo html::a(inlink('view', "planID={$childrenPlan->id}"), "#{$childrenPlan->id} " . $childrenPlan->title) . '<br />';?>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->desc;?></th>
|
||||
<td><?php echo $plan->desc;?></td>
|
||||
|
||||
@@ -1000,6 +1000,8 @@ class project extends control
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$projectID = $copyProjectID == '' ? $this->project->create() : $this->project->create($copyProjectID);
|
||||
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$this->project->updateProducts($projectID);
|
||||
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
@@ -1056,6 +1058,8 @@ class project extends control
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$changes = $this->project->update($projectID);
|
||||
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$this->project->updateProducts($projectID);
|
||||
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
if($action == 'undelete')
|
||||
@@ -1718,7 +1722,7 @@ class project extends control
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->project->manageMembers($projectID);
|
||||
$this->locate($this->createLink('project', 'team', "projectID=$projectID"));
|
||||
die(js::locate($this->createLink('project', 'team', "projectID=$projectID"), 'parent'));
|
||||
}
|
||||
|
||||
/* Load model. */
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.chosen-container-single .chosen-single > span{max-width:100%;}
|
||||
@@ -1599,6 +1599,7 @@ class projectModel extends model
|
||||
|
||||
$planStories = array();
|
||||
$planProducts = array();
|
||||
$count = 0;
|
||||
if(!empty($plans))
|
||||
{
|
||||
foreach($plans as $planID => $productID)
|
||||
@@ -1606,7 +1607,6 @@ class projectModel extends model
|
||||
$planStory = $this->loadModel('story')->getPlanStories($planID);
|
||||
if(!empty($planStory))
|
||||
{
|
||||
$count = 0;
|
||||
foreach($planStory as $id => $story)
|
||||
{
|
||||
if($story->status == 'draft')
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<form class='main-form' method='post' id='teamForm'>
|
||||
<form class='main-form' method='post' id='teamForm' target='hiddenwin'>
|
||||
<table class='table table-form'>
|
||||
<thead>
|
||||
<tr class='text-center'>
|
||||
|
||||
@@ -191,6 +191,10 @@ class release extends control
|
||||
{
|
||||
$this->release->delete(TABLE_RELEASE, $releaseID);
|
||||
|
||||
$release = $this->dao->select('*')->from(TABLE_RELEASE)->where('id')->eq((int)$releaseID)->fetch();
|
||||
$build = $this->dao->select('*')->from(TABLE_BUILD)->where('id')->eq((int)$release->build)->fetch();
|
||||
if(empty($build->project)) $this->loadModel('build')->delete(TABLE_BUILD, $build->id);
|
||||
|
||||
/* if ajax request, send result. */
|
||||
if($this->server->ajax)
|
||||
{
|
||||
@@ -203,6 +207,8 @@ class release extends control
|
||||
{
|
||||
$response['result'] = 'success';
|
||||
$response['message'] = '';
|
||||
$release = $this->release->getById($releaseID);
|
||||
$this->dao->update(TABLE_BUILD)->set('deleted')->eq(1)->where('id')->eq($release->build)->andWhere('name')->eq($release->name)->exec();
|
||||
}
|
||||
$this->send($response);
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
<td><?php echo html::a(helper::createLink('release', 'view', "releaseID=$release->id"), sprintf('%03d', $release->id));?></td>
|
||||
<td>
|
||||
<?php
|
||||
$releaseName = $release->marker ? "<icon class='icon-flag'></icon>" . $release->name : $release->name;
|
||||
echo html::a(inlink('view', "release=$release->id"), $releaseName);
|
||||
$flagIcon = $release->marker ? "<icon class='icon icon-flag-alt'></icon> " : '';
|
||||
echo $flagIcon . html::a(inlink('view', "release=$release->id"), $release->name);
|
||||
?>
|
||||
</td>
|
||||
<td title='<?php echo $release->buildName?>'><?php echo html::a($this->createLink('build', 'view', "buildID=$release->buildID"), $release->buildName);?></td>
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
<div class='divider'></div>
|
||||
<div class='page-title'>
|
||||
<span class='label label-id'><?php echo $release->id;?></span>
|
||||
<?php $releaseName = $release->marker ? "<icon class='icon-flag'></icon>" . $release->name : $release->name;?>
|
||||
<span class='text' title='<?php echo $release->name;?>'><?php echo $releaseName;?></span>
|
||||
<?php $flagIcon = $release->marker ? "<icon class='icon icon-flag-alt'></icon> " : '';?>
|
||||
<span class='text' title='<?php echo $release->name;?>'><?php echo $flagIcon . $release->name;?></span>
|
||||
<?php if($release->deleted):?>
|
||||
<span class='label label-danger'><?php echo $lang->release->deleted;?></span>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -59,7 +59,7 @@ $lang->report->product = $lang->productCommon;
|
||||
$lang->report->user = 'Name';
|
||||
$lang->report->bugTotal = 'Bug';
|
||||
$lang->report->task = 'Task';
|
||||
$lang->report->estimate = 'Est.(h)';
|
||||
$lang->report->estimate = 'Estimates';
|
||||
$lang->report->consumed = 'Cost';
|
||||
$lang->report->remain = 'Left';
|
||||
$lang->report->deviation = 'Deviation';
|
||||
|
||||
@@ -30,8 +30,8 @@ $lang->sso->bindTypeList['bind'] = 'Bind to existing User';
|
||||
$lang->sso->bindTypeList['add'] = 'Add User';
|
||||
|
||||
$lang->sso->help = <<<EOD
|
||||
<p>1. Interface address is required. If use PATH_INFO, it is http://YOUR RANGER ADDRESS/sys/sso-check.html If GET, it is http://YOUR RANGER ADDRESS/sys/index.php?m=sso&f=check</p>
|
||||
<p>2. Code and Key must be the same as set in Ranger.</p>
|
||||
<p>1. Zdoo address is required. If use PATH_INFO, it is http://YOUR ZDOO ADDRESS/sys/sso-check.html If GET, it is http://YOUR ZDOO ADDRESS/sys/index.php?m=sso&f=check</p>
|
||||
<p>2. CAlias and Key must be the same as set in Zdoo.</p>
|
||||
EOD;
|
||||
$lang->sso->bindNotice = 'User that is just added has no privilege. You have to ask ZenTao Admin to grant permissions to the User.';
|
||||
$lang->sso->bindNoPassword = 'Password should not be empty.';
|
||||
|
||||
@@ -234,7 +234,7 @@ $lang->story->report->charts['storysPerPlan'] = 'by Plan';
|
||||
$lang->story->report->charts['storysPerStatus'] = 'by Status';
|
||||
$lang->story->report->charts['storysPerStage'] = 'by Phase';
|
||||
$lang->story->report->charts['storysPerPri'] = 'by Priority';
|
||||
$lang->story->report->charts['storysPerEstimate'] = 'by Hour';
|
||||
$lang->story->report->charts['storysPerEstimate'] = 'by Estimate';
|
||||
$lang->story->report->charts['storysPerOpenedBy'] = 'by CreatedBy';
|
||||
$lang->story->report->charts['storysPerAssignedTo'] = 'by Assignee';
|
||||
$lang->story->report->charts['storysPerClosedReason'] = 'by Closed Reason';
|
||||
@@ -269,7 +269,7 @@ $lang->story->report->storysPerPri->item = 'Priority';
|
||||
$lang->story->report->storysPerOpenedBy->item = 'Account';
|
||||
$lang->story->report->storysPerAssignedTo->item = 'User';
|
||||
$lang->story->report->storysPerClosedReason->item = 'Reason';
|
||||
$lang->story->report->storysPerEstimate->item = 'Hour';
|
||||
$lang->story->report->storysPerEstimate->item = 'Estimates';
|
||||
$lang->story->report->storysPerChange->item = 'Change';
|
||||
|
||||
$lang->story->report->storysPerProduct->graph = new stdclass();
|
||||
@@ -295,7 +295,7 @@ $lang->story->report->storysPerPri->graph->xAxisName = 'Priority';
|
||||
$lang->story->report->storysPerOpenedBy->graph->xAxisName = 'Created By';
|
||||
$lang->story->report->storysPerAssignedTo->graph->xAxisName = 'Assigned To';
|
||||
$lang->story->report->storysPerClosedReason->graph->xAxisName = 'Close Reason';
|
||||
$lang->story->report->storysPerEstimate->graph->xAxisName = 'Hour ';
|
||||
$lang->story->report->storysPerEstimate->graph->xAxisName = 'Estimates ';
|
||||
$lang->story->report->storysPerChange->graph->xAxisName = 'Change';
|
||||
|
||||
$lang->story->placeholder = new stdclass();
|
||||
|
||||
@@ -22,8 +22,8 @@ $lang->task->delete = "Delete";
|
||||
$lang->task->deleted = "Deleted";
|
||||
$lang->task->delayed = 'Delayed';
|
||||
$lang->task->view = "Overview";
|
||||
$lang->task->logEfforts = "Hour";
|
||||
$lang->task->record = "Est";
|
||||
$lang->task->logEfforts = "Effort";
|
||||
$lang->task->record = "Estimates";
|
||||
$lang->task->start = "Start";
|
||||
$lang->task->restart = "Continue";
|
||||
$lang->task->finish = "Finish";
|
||||
@@ -38,7 +38,7 @@ $lang->task->case = 'Linked Case';
|
||||
$lang->task->confirmStoryChange = "Confirm Change";
|
||||
$lang->task->progress = 'Progress';
|
||||
$lang->task->progressTips = 'Cost/(Cost+Left)';
|
||||
$lang->task->copy = 'Duplicate Task';
|
||||
$lang->task->copy = 'Duplicated Task';
|
||||
$lang->task->waitTask = 'Wait Task';
|
||||
|
||||
$lang->task->common = 'Task';
|
||||
@@ -62,7 +62,7 @@ $lang->task->consumed = 'Cost';
|
||||
$lang->task->myConsumed = 'My Cost';
|
||||
$lang->task->consumedAB = 'Cost';
|
||||
$lang->task->hour = 'Hour';
|
||||
$lang->task->consumedThisTime = 'Hour';
|
||||
$lang->task->consumedThisTime = 'Cost';
|
||||
$lang->task->leftThisTime = 'Left';
|
||||
$lang->task->datePlan = 'Plan';
|
||||
$lang->task->estStarted = 'Plan Start';
|
||||
|
||||
+11
-1
@@ -428,6 +428,12 @@ class taskModel extends model
|
||||
|
||||
if($status == 'doing')
|
||||
{
|
||||
if($parentTask->assignedTo == 'closed')
|
||||
{
|
||||
$task->assignedTo = $childTask->assignedTo;
|
||||
$task->assignedDate = $now;
|
||||
}
|
||||
|
||||
$task->finishedBy = '';
|
||||
$task->finishedDate = '';
|
||||
$task->closedBy = '';
|
||||
@@ -661,7 +667,11 @@ class taskModel extends model
|
||||
{
|
||||
foreach($teams as $member) $this->dao->insert(TABLE_TEAM)->data($member)->autoCheck()->exec();
|
||||
$task = $this->computeHours4Multiple($oldTask, $task);
|
||||
if($task->status == 'wait') $task->assignedTo = key($teams);
|
||||
if($task->status == 'wait')
|
||||
{
|
||||
reset($teams);
|
||||
$task->assignedTo = key($teams);
|
||||
}
|
||||
}
|
||||
|
||||
$this->dao->update(TABLE_TASK)->data($task)
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
<?php if($hasCustomPri):?>
|
||||
<?php echo html::select('pri', (array)$priList, $pri, "class='form-control'");?>
|
||||
<?php else: ?>
|
||||
<?php ksort($priList);?>
|
||||
<div class="input-group-btn pri-selector" data-type="pri">
|
||||
<button type="button" class="btn dropdown-toggle br-0" data-toggle="dropdown">
|
||||
<span class="pri-text"><span class="label-pri label-pri-<?php echo empty($pri) ? '0' : $pri?>" title="<?php echo $pri?>"><?php echo $pri?></span></span> <span class="caret"></span>
|
||||
|
||||
@@ -90,15 +90,12 @@
|
||||
}
|
||||
}
|
||||
$priList = $lang->testcase->priList;
|
||||
if(end($priList))
|
||||
{
|
||||
unset($priList[0]);
|
||||
$priList[0] = '';
|
||||
}
|
||||
if(end($priList)) unset($priList[0]);
|
||||
?>
|
||||
<?php if($hasCustomPri):?>
|
||||
<?php echo html::select('pri', (array)$priList, $pri, "class='form-control'");?>
|
||||
<?php else: ?>
|
||||
<?php ksort($priList);?>
|
||||
<div class="input-group-btn pri-selector" data-type="pri">
|
||||
<button type="button" class="btn dropdown-toggle br-0" data-toggle="dropdown">
|
||||
<span class="pri-text"><span class="label-pri label-pri-<?php echo empty($pri) ? '0' : $pri?>" title="<?php echo $pri?>"><?php echo $pri?></span></span> <span class="caret"></span>
|
||||
|
||||
@@ -23,20 +23,12 @@
|
||||
|
||||
if($hasGroupPriv and $config->global->flow != 'onlyTest')
|
||||
{
|
||||
echo "<div class='btn-group'>";
|
||||
$active = $browseType == 'group' ? 'btn-active-text' : '';
|
||||
$groupBy = isset($groupBy) ? $groupBy : '';
|
||||
$current = zget($lang->testcase->groups, isset($groupBy) ? $groupBy : '', '');
|
||||
if(empty($current)) $current = $lang->testcase->groups[''];
|
||||
echo html::a('javascript:;', "<span class='text'>{$current} <span class='caret'></span></span>", '', "class='btn btn-link $active' data-toggle='dropdown'");
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
foreach ($lang->testcase->groups as $key => $value)
|
||||
{
|
||||
if($key == '') continue;
|
||||
echo '<li' . ($key == $groupBy ? " class='active'" : '') . '>';
|
||||
echo html::a($this->inlink('groupCase', "taskID=$taskID&groupBy=$key"), $value);
|
||||
}
|
||||
echo '</ul></div>';
|
||||
$groupBy = isset($groupBy) ? $groupBy : '';
|
||||
$active = !empty($groupBy) ? 'btn-active-text' : '';
|
||||
|
||||
echo "<div id='groupTab' class='btn-group'>";
|
||||
echo html::a($this->createLink('testtask', 'groupCase', "taskID=$taskID&groupBy=story"), "<span class='text'>{$lang->testcase->groupByStories}</span>", '', "class='btn btn-link $active'");
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
if($this->methodName == 'cases') echo "<a class='btn btn-link querybox-toggle' id='bysearchTab'><i class='icon icon-search muted'></i>{$lang->testcase->bySearch}</a>";
|
||||
|
||||
@@ -444,7 +444,11 @@ class treeModel extends model
|
||||
->orderBy('grade desc, type, `order`')
|
||||
->get();
|
||||
$stmt = $this->dbh->query($query);
|
||||
while($module = $stmt->fetch()) $this->buildTree($treeMenu, $module, 'task', $userFunc, $extra);
|
||||
while($module = $stmt->fetch())
|
||||
{
|
||||
if(!$manage and !isset($projectModules[$module->id])) continue;
|
||||
$this->buildTree($treeMenu, $module, 'task', $userFunc, $extra);
|
||||
}
|
||||
if(isset($treeMenu[0]) and $branch) $treeMenu[0] = "<li><a>$branchName</a><ul>{$treeMenu[0]}</ul></li>";
|
||||
$tree .= isset($treeMenu[0]) ? $treeMenu[0] : '';
|
||||
}
|
||||
@@ -510,10 +514,10 @@ class treeModel extends model
|
||||
->orderBy('grade desc, type, `order`')
|
||||
->get();
|
||||
$stmt = $this->dbh->query($query);
|
||||
if($branch == 0) $productTree = $this->getDataStructure($stmt, 'task');
|
||||
if($branch == 0) $productTree = $this->getDataStructure($stmt, 'task', $projectModules);
|
||||
if($branch != 0)
|
||||
{
|
||||
$children = $this->getDataStructure($stmt, 'task');
|
||||
$children = $this->getDataStructure($stmt, 'task', $projectModules);
|
||||
if($children) $branchTrees[] = array('name' => $branchName, 'root' => $id, 'type' => 'branch', 'actions' => false, 'children' => $children);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ class upgradeModel extends model
|
||||
public function execute($fromVersion)
|
||||
{
|
||||
set_time_limit(0);
|
||||
$executeXuanxuan = false;
|
||||
switch($fromVersion)
|
||||
{
|
||||
case '0_3beta':
|
||||
@@ -322,6 +323,7 @@ class upgradeModel extends model
|
||||
$this->saveLogs('Execute 10_1');
|
||||
$xuanxuanSql = $this->app->getAppRoot() . 'db' . DS . 'xuanxuan.sql';
|
||||
$this->execSQL($xuanxuanSql);
|
||||
$executeXuanxuan = true;
|
||||
case '10_2': $this->saveLogs('Execute 10_2');
|
||||
case '10_3': $this->saveLogs('Execute 10_3');
|
||||
case '10_3_1':
|
||||
@@ -339,10 +341,13 @@ class upgradeModel extends model
|
||||
$this->execSQL($this->getUpgradeFile('10.5.1'));
|
||||
case '10_6':
|
||||
$this->saveLogs('Execute 10_6');
|
||||
$xuanxuanSql = $this->app->getAppRoot() . 'db' . DS . 'upgradexuanxuan2.1.0.sql';
|
||||
$this->execSQL($xuanxuanSql);
|
||||
$xuanxuanSql = $this->app->getAppRoot() . 'db' . DS . 'upgradexuanxuan2.2.0.sql';
|
||||
$this->execSQL($xuanxuanSql);
|
||||
if(!$executeXuanxuan)
|
||||
{
|
||||
$xuanxuanSql = $this->app->getAppRoot() . 'db' . DS . 'upgradexuanxuan2.1.0.sql';
|
||||
$this->execSQL($xuanxuanSql);
|
||||
$xuanxuanSql = $this->app->getAppRoot() . 'db' . DS . 'upgradexuanxuan2.2.0.sql';
|
||||
$this->execSQL($xuanxuanSql);
|
||||
}
|
||||
$this->initXuanxuan();
|
||||
case '11_0': $this->saveLogs('Execute 11_0');
|
||||
case '11_1':
|
||||
@@ -350,8 +355,11 @@ class upgradeModel extends model
|
||||
$this->execSQL($this->getUpgradeFile('11.1'));
|
||||
if(!isset($this->config->isINT) or !($this->config->isINT))
|
||||
{
|
||||
$xuanxuanSql = $this->app->getAppRoot() . 'db' . DS . 'upgradexuanxuan2.3.0.sql';
|
||||
$this->execSQL($xuanxuanSql);
|
||||
if(!$executeXuanxuan)
|
||||
{
|
||||
$xuanxuanSql = $this->app->getAppRoot() . 'db' . DS . 'upgradexuanxuan2.3.0.sql';
|
||||
$this->execSQL($xuanxuanSql);
|
||||
}
|
||||
$this->dao->update(TABLE_CONFIG)->set('value')->eq('off')->where('`key`')->eq('isHttps')->andWhere('`section`')->eq('xuanxuan')->andWhere('`value`')->eq('0')->exec();
|
||||
$this->dao->update(TABLE_CONFIG)->set('value')->eq('on')->where('`key`')->eq('isHttps')->andWhere('`section`')->eq('xuanxuan')->andWhere('`value`')->eq('1')->exec();
|
||||
}
|
||||
|
||||
@@ -42,8 +42,7 @@
|
||||
<script>
|
||||
<?php
|
||||
foreach($needProcess as $processKey => $value) echo 'var ' . $processKey . "Finish = false;\n";
|
||||
$needUpdateFile = strpos($config->installedVersion, 'pro') === false ? version_compare($config->installedVersion, '8.3', '<') : version_compare($config->installedVersion, 'pro5.4', '<');
|
||||
if($needUpdateFile):?>
|
||||
if(isset($needProcess['updateFile'])):?>
|
||||
$(function()
|
||||
{
|
||||
$('a#tohome').closest('.alert').hide();
|
||||
|
||||
@@ -82,8 +82,7 @@ if(empty($config->notMd5Pwd))js::import($jsRoot . 'md5.js');
|
||||
<div class="table-col text-middle text-center">
|
||||
<div id="poweredby">
|
||||
<?php if($config->checkVersion):?>
|
||||
<?php $siteURL = 'https://api.zentao.net';?>
|
||||
<iframe id='updater' frameborder='0' width='100%' height='45' scrolling='no' allowtransparency='true' src="<?php echo $siteURL;?>/updater-isLatest-<?php echo $config->version;?>-<?php echo $s;?>.html?lang=<?php echo str_replace('-', '_', $this->app->getClientLang())?>"></iframe>
|
||||
<iframe id='updater' class='hidden' frameborder='0' width='100%' height='45' scrolling='no' allowtransparency='true' src="<?php echo $this->createLink('misc', 'checkUpdate', "sn=$s");?>"></iframe>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+27
-9
@@ -3,16 +3,34 @@
|
||||
$langType = 'zh-tw';
|
||||
$langDesc = 'zh-tw';
|
||||
if(empty($langType)) die('lang') . "\n";
|
||||
foreach(glob('../module/*') as $moduleName)
|
||||
foreach(array('../module/') as $subModuleRoot)
|
||||
{
|
||||
$moduleLangPath = realpath($moduleName) . '/lang/';
|
||||
$defaultLangFile = $moduleLangPath . 'zh-cn.php';
|
||||
$targetLangFile = $moduleLangPath . $langType . '.php';
|
||||
if(!file_exists($defaultLangFile)) continue;
|
||||
foreach(glob($subModuleRoot . '*') as $moduleName)
|
||||
{
|
||||
$realModulePath = realpath($moduleName);
|
||||
$moduleLangPath = $realModulePath . '/lang/';
|
||||
$defaultLangFile = $moduleLangPath . 'zh-cn.php';
|
||||
$targetLangFile = $moduleLangPath . $langType . '.php';
|
||||
if(file_exists($defaultLangFile))
|
||||
{
|
||||
system("cconv -f utf-8 -t UTF8-TW $defaultLangFile > $targetLangFile");
|
||||
$defaultLang = file_get_contents($targetLangFile);
|
||||
$targetLang = str_replace('zh-cn', $langDesc, $defaultLang);
|
||||
file_put_contents($targetLangFile, $targetLang);
|
||||
}
|
||||
|
||||
system("cconv -f utf-8 -t UTF8-TW $defaultLangFile > $targetLangFile");
|
||||
$defaultLang = file_get_contents($targetLangFile);
|
||||
$targetLang = str_replace('zh-cn', $langDesc, $defaultLang);
|
||||
file_put_contents($targetLangFile, $targetLang);
|
||||
$extModuleLangPath = $realModulePath . '/ext/lang/zh-cn/*.php';
|
||||
foreach(glob($extModuleLangPath) as $extModuleLang)
|
||||
{
|
||||
$fileName = basename($extModuleLang);
|
||||
if(!is_dir("{$realModulePath}/ext/lang/{$langType}/")) `mkdir -p {$realModulePath}/ext/lang/{$langType}/`;
|
||||
$targetLangFile = $realModulePath . "/ext/lang/{$langType}/" . $fileName;
|
||||
|
||||
system("cconv -f utf-8 -t UTF8-TW $extModuleLang > $targetLangFile");
|
||||
$defaultLang = file_get_contents($targetLangFile);
|
||||
$targetLang = str_replace('zh-cn', $langDesc, $defaultLang);
|
||||
file_put_contents($targetLangFile, $targetLang);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -302,6 +302,10 @@ function ajaxDelete(url, replaceID, notice)
|
||||
if($('#' + replaceID).find('table.datatable').length) $('#' + replaceID).find('table.datatable').datatable();
|
||||
});
|
||||
}
|
||||
else if(data.result == 'fail' && typeof(data.message) == 'string')
|
||||
{
|
||||
bootbox.alert(data.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+4
-4
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@ $lang->chat->common = 'Xuanxuan';
|
||||
$lang->chat->turnon = 'On';
|
||||
$lang->chat->help = 'Help';
|
||||
$lang->chat->settings = 'Settings';
|
||||
$lang->chat->xxdServer = 'Zentao Server';
|
||||
$lang->chat->xxdServer = 'ZenTao Server';
|
||||
$lang->chat->downloadXXD = 'Download XXD';
|
||||
$lang->chat->zentaoIntegrate = 'Zentao Integrated';
|
||||
$lang->chat->zentaoClient = 'ZenTao Client is added!';
|
||||
@@ -16,9 +16,9 @@ $lang->chat->turnonList[1] = 'Enable';
|
||||
$lang->chat->turnonList[0] = 'Disable';
|
||||
|
||||
$lang->chat->info = "ZenTao client is powered by <a href='https://xuan.im/' target='_blank'>Xuan</a>, a secure and open source Instant Messenger by Nature Easy Soft. It is a self-hosted and cross-platform tool with numerous plug-ins and robust features. In Xuan, you can code your own plug-ins. Click <a href='https://xuan.im/' target='_blank'>HERE</a> for more.";
|
||||
$lang->chat->xxClientConfirm = 'Click the lower right icon to download new zentao client!';
|
||||
$lang->chat->xxServerConfirm = 'Go to Admin-Integrate-Xuanxuan download new zentao client server!';
|
||||
$lang->chat->xxClientConfirm = 'Click Download ZenTao Client at the right bottom to download it!';
|
||||
$lang->chat->xxServerConfirm = 'Go to Admin-Integrate-ZT Client to download the ZenTao Client Server!';
|
||||
|
||||
$lang->chat->xxdServerTip = 'XXD server address contains protocol and host and port,such as http://192.168.1.35 or http://pms.zentao.com. that can not be 127.0.0.1.';
|
||||
$lang->chat->xxdServerTip = 'XXD server address contains protocol, host and port,such as http://192.168.1.35 or http://pms.zentao.com. It should not be 127.0.0.1.';
|
||||
$lang->chat->xxdServerEmpty = 'XXD server address is empty.';
|
||||
$lang->chat->xxdServerError = 'XXD server address can not be 127.0.0.1.';
|
||||
$lang->chat->xxdServerError = 'XXD server address should not be 127.0.0.1.';
|
||||
|
||||
@@ -5,5 +5,5 @@ $lang->admin->menu->sso['link'] = 'Integrate|admin|xuanxuan';
|
||||
if(!isset($lang->admin->menu->sso['alias'])) $lang->admin->menu->sso['alias'] = '';
|
||||
$lang->admin->menu->sso['alias'] .= ',sso';
|
||||
|
||||
$lang->admin->subMenu->sso->xuanxuan = 'Xuanxuan|admin|xuanxuan';
|
||||
$lang->admin->subMenu->sso->xuanxuan = 'ZT Client|admin|xuanxuan';
|
||||
$lang->admin->subMenuOrder->sso[4] = 'xuanxuan';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
$lang->message->typeList['xuanxuan'] = 'Client';
|
||||
|
||||
$lang->message->sender = 'ZentaoPMS';
|
||||
$lang->message->sender = 'ZenTao';
|
||||
|
||||
Reference in New Issue
Block a user