Merge branch 'master' into 'Fixbug'

# Conflicts:
#   module/kanban/js/view.js
This commit is contained in:
孙广明
2022-01-27 03:02:56 +00:00
58 changed files with 2214 additions and 213 deletions
+1 -1
View File
@@ -1 +1 @@
16.2
16.3
+1 -1
View File
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
if(!function_exists('getWebRoot')){function getWebRoot(){}}
/* 基本设置。Basic settings. */
$config->version = '16.2'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->version = '16.3'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
$config->timezone = 'Asia/Shanghai'; // 时区设置。 The time zone setting, for more see http://www.php.net/manual/en/timezones.php.
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,5 +1,6 @@
ALTER TABLE `zt_kanbanspace` ADD `type` varchar(50) NOT NULL AFTER `name`;
UPDATE `zt_kanbanspace` SET `type` = 'cooperation', `whitelist` = '' WHERE `type` = '';
UPDATE `zt_kanbanspace` SET `type` = 'cooperation' WHERE `type` = '';
UPDATE `zt_kanban` SET `team` = CONCAT(team, ',', whitelist) where `whitelist` != '';
ALTER TABLE `zt_kanban` ADD `object` varchar(255) NOT NULL AFTER `displayCards`;
ALTER TABLE `zt_kanban` ADD `performable` enum ('0', '1') NOT NULL DEFAULT '0' AFTER `archived`;
+6
View File
@@ -629,6 +629,8 @@ CREATE TABLE IF NOT EXISTS `zt_job` (
`server` mediumint(8) unsigned NOT NULL,
`pipeline` varchar(500) NOT NULL,
`triggerType` varchar(255) NOT NULL,
`sonarqubeServer` mediumint(8) unsigned NOT NULL,
`projectKey` varchar(255) NOT NULL,
`svnDir` varchar(255) NOT NULL,
`atDay` varchar(255) DEFAULT NULL,
`atTime` varchar(10) DEFAULT NULL,
@@ -676,9 +678,11 @@ CREATE TABLE `zt_kanban` (
`acl` char(30) NOT NULL DEFAULT 'open',
`whitelist` text NOT NULL,
`archived` enum('0', '1') NOT NULL DEFAULT '0',
`performable` enum ('0', '1') NOT NULL DEFAULT '0',
`status` enum('active','closed') NOT NULL default 'active',
`order` mediumint(8) NOT NULL DEFAULT '0',
`displayCards` smallint(6) NOT NULL default '0',
`fluidBoard` enum('0','1') NOT NULL DEFAULT '0',
`object` varchar(255) NOT NULL,
`createdBy` char(30) NOT NULL,
`createdDate` datetime NOT NULL,
@@ -712,6 +716,7 @@ CREATE TABLE `zt_kanbancard` (
`fromID` mediumint(8) unsigned NOT NULL,
`fromType` varchar(30) NOT NULL,
`name` varchar(255) NOT NULL,
`status` varchar(30) NOT NULL,
`pri` mediumint(8) unsigned NOT NULL,
`assignedTo` text NOT NULL,
`desc` text NOT NULL,
@@ -1025,6 +1030,7 @@ CREATE TABLE IF NOT EXISTS `zt_project` (
`whitelist` text NOT NULL,
`order` mediumint(8) unsigned NOT NULL,
`displayCards` smallint(6) NOT NULL default '0',
`fluidBoard` enum('0','1') NOT NULL DEFAULT '0',
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `parent` (`parent`),
+59
View File
@@ -1,3 +1,62 @@
2022-01-26 16.3
完成的需求
29706 研发看板相关操作支持平滑刷新方式呈现
30102 我的空间调整为私人空间
30103 空间检索标签增加新的空间类型和看板维度的标签
30197 数据归并页面中产品线列表增加滚动条功能
29490 实现列的拖动排序功能
30125 泳道组中创建卡片时可以选择所属泳道
30126 泳道组中支持批量创建卡片
30131 通用看板支持列宽度设置功能
30132 任务看板支持列宽度设置功能
30133 执行看板支持列宽度设置功能
30134 通用看板支持导入功能设置
30137 通用看板列中支持导入产品计划
30138 实现产品计划卡片在看板中的展示方式
30139 通用看板列中支持导入产品发布
30140 实现产品发布卡片在看板中的展示方式
30141 通用看板列中支持导入项目版本
30142 实现版本卡片在看板中的展示方式
30147 通用看板列中支持导入项目执行
30149 实现执行卡片在看板中的展示方式
30156 通用看板列中支持转入卡片
30167 通用看板支持完成功能设置
30170 在看板中实现卡片完成状态的展示方式
30171 卡片的设置菜单中增加完成/激活卡片操作
29861 在禅道SonarQube项目列表页面中添加执行SonarQube按钮
29860 实现禅道中删除SonarQube项目的功能
29858 实现禅道中SonarQube项目列表页面的搜索功能
29857 实现禅道SonarQube项目列表页面返回功能
29856 实现禅道中SonarQube项目列表页面
29850 在禅道SonarQube服务器列表页面添加SonarQube项目入口
29848 实现禅道中删除SonarQube服务器功能
29847 实现禅道中添加SonarQube服务器功能
29846 实现禅道中SonarQube服务器列表页面
29844 在禅道中添加管理SonarQube服务器的入口
29227 在禅道版本库列表中添加执行SonarQube按钮
29226 实现在禅道中编辑SonarQube服务器的功能
26572 实现禅道中配置SonarQube构建任务的功能
30314 实现在禅道中检查禅道用户是否与GitLab用户绑定的功能
30312 实现禅道中删除GitLab合并请求权限与GitLab保持一致的功能
30311 实现禅道中编辑GitLab合并请求权限与GitLab保持一致的功能
30302 实现在禅道中创建合并请求服务器权限控制功能
30301 实现在禅道中创建合并请求项目权限控制功能
30228 实现禅道中GitLab合并请求数据按权限展示的功能
30227 创建禅道GitLab服务器时需验证Token是否具有GitLab管理员权限
30226 使用禅道所绑定的GitLab用户进行合并请求的创建和审批操作
30099 实现禅道中编辑GitLab群组权限与GitLab保持一致的功能
30098 实现禅道中删除GitLab群组权限与GitLab保持一致的功能
30097 实现禅道中GitLab群组的可见权限功能
30096 实现禅道中标签保护管理权限与GitLab权限保持一致的功能
30095 实现禅道中删除GitLab项目权限与GitLab保持一致的功能
30094 实现禅道中分支保护管理权限与GitLab权限保持一致的功能
30093 实现禅道中编辑GitLab项目权限与GitLab保持一致的功能
30092 实现禅道中GitLab项目的可见权限功能
26573 实现在禅道中查看Sonar代码检查结果的功能
修复的BUG
19014 有时登录后 session 失效登出的问题
19015 在未打开客户端集成时,不展示右下角的聊天入口
2022-01-17 16.2
28397 选择项目管理方式弹窗中增加专业研发看板
28398 实现专业研发看板项目的创建功能
+1 -1
View File
@@ -956,7 +956,7 @@ class bugModel extends model
{
$this->loadModel('kanban');
if(!isset($output['toColID'])) $this->kanban->updateLane($oldBug->execution, 'bug', $bugID);
if(isset($output['toColID'])) $this->kanban->moveCard($bugID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
if(isset($output['toColID'])) $this->kanban->moveCard($bugID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID'], $oldBug->execution);
}
return common::createChanges($oldBug, $bug);
}
+7 -5
View File
@@ -67,9 +67,9 @@ class buildModel extends model
->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.project')->eq((int)$projectID)
->andWhere('t1.deleted')->eq(0)
->where('t1.deleted')->eq(0)
->andWhere('t1.project')->ne(0)
->beginIF($projectID)->andWhere('t1.project')->eq((int)$projectID)->fi()
->beginIF($type == 'product' and $param)->andWhere('t1.product')->eq($param)->fi()
->beginIF($type == 'bysearch')->andWhere($param)->fi()
->orderBy($orderBy)
@@ -121,21 +121,23 @@ class buildModel extends model
* @param string $type all|product|bysearch
* @param int|string $param productID|buildQuery
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
public function getExecutionBuilds($executionID, $type = '', $param = '', $orderBy = 't1.date_desc,t1.id_desc')
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')
->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.execution')->eq((int)$executionID)
->andWhere('t1.deleted')->eq(0)
->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()
->beginIF($type == 'bysearch')->andWhere($param)->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
}
+4 -3
View File
@@ -3610,17 +3610,18 @@ class execution extends control
* @param string $enterTime
* @param string $browseType
* @param string $groupBy
* @param string $from execution|RD
* @access public
* @return void
* @return array
*/
public function ajaxUpdateKanban($executionID = 0, $enterTime = '', $browseType = '', $groupBy = '')
public function ajaxUpdateKanban($executionID = 0, $enterTime = '', $browseType = '', $groupBy = '', $from = 'execution')
{
$enterTime = date('Y-m-d H:i:s', $enterTime);
$lastEditedTime = $this->dao->select("max(lastEditedTime) as lastEditedTime")->from(TABLE_KANBANLANE)->where('execution')->eq($executionID)->fetch('lastEditedTime');
if($lastEditedTime > $enterTime or $groupBy != 'default')
{
$kanbanGroup = $this->loadModel('kanban')->getExecutionKanban($executionID, $browseType, $groupBy);
$kanbanGroup = $from == 'execution' ? $this->loadModel('kanban')->getExecutionKanban($executionID, $browseType, $groupBy) : $this->loadModel('kanban')->getRDKanban($executionID, $browseType, 'id_asc', 0, $groupBy);
die(json_encode($kanbanGroup));
}
else
+1 -1
View File
@@ -95,7 +95,7 @@
.kanban-card > .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
.kanban-card > .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
#kanban .kanban-card[data-scale-size="4"] {padding: 8px;}
#kanban .kanban-card[data-scale-size="4"] {padding: 8px !important; min-height: 47px !important; height: 47px !important;}
#kanban .kanban-card[data-scale-size="3"] {padding: 3px 4px;}
#kanban .kanban-card[data-scale-size="3"] > .title {white-space: normal; max-height: 100%;}
#kanban .kanban-card[data-scale-size="2"] {padding: 3px 4px; overflow: hidden;}
+21
View File
@@ -1294,6 +1294,27 @@ $(function()
if(sortType == 'lane') $cards.show();
}
});
/* Ajax update kanban. */
if(groupBy == 'default')
{
var lastUpdateData;
setInterval(function()
{
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD'), function(data)
{
if(data && lastUpdateData !== data)
{
lastUpdateData = data;
kanbanData = $.parseJSON(data);
for(var region in kanbanData)
{
updateRegion(region, kanbanData[region]);
}
}
});
}, 10000);
}
});
/** Calculate column height */
+2 -1
View File
@@ -41,6 +41,7 @@ js::set('laneCount', $laneCount);
js::set('userList', $userList);
js::set('noAssigned', $lang->kanbancard->noAssigned);
js::set('users', $users);
js::set('entertime', time());
js::set('displayCards', $execution->displayCards);
js::set('fluidBoard', $execution->fluidBoard);
js::set('colorListLang', $lang->kanbancard->colorList);
@@ -136,7 +137,7 @@ js::set('hasTaskButton', $hasTaskButton);
if(common::hasPriv('execution', 'delete')) $kanbanActions .= '<li>' . html::a(helper::createLink('execution', 'delete', "executionID=$execution->id"), '<i class="icon icon-trash"></i>' . $lang->delete, 'hiddenwin', "class='btn btn-link text-left'") . '</li>';
if($kanbanActions)
{
$actions .= ((common::hasPriv('kanban', 'createRegion') or common::hasPriv('kanban', 'setLaneHeight')) and (common::hasPriv('execution', 'edit') or common::hasPriv('execution', 'delete') or !empty($executionActions))) ? "<div class='divider'></div>" . $kanbanActions : $kanbanActions;
$actions .= ((common::hasPriv('kanban', 'createRegion') or common::hasPriv('kanban', 'setLaneHeight') or common::hasPriv('kanban', 'setColumnWidth')) and (common::hasPriv('execution', 'edit') or common::hasPriv('execution', 'delete') or !empty($executionActions))) ? "<div class='divider'></div>" . $kanbanActions : $kanbanActions;
}
$actions .= "</ul>";
}
+1 -1
View File
@@ -65,7 +65,7 @@
$width = $this->app->getClientLang() == 'en' ? '70%' : '60%';
echo '<li>' .html::a($this->createLink('kanban', 'setLaneHeight', "executionID=$executionID&from=execution", '', true), "<i class='icon icon-size-height'></i> " . $lang->kanban->laneHeight, '', "class='iframe btn btn-link' title='{$lang->kanban->laneHeight}' data-width=$width") . '</li>';
}
if(common::hasPriv('kanban', 'setColumnWidth')) echo '<li>' .html::a($this->createLink('kanban', 'setColumnWidth', "executionID=$executionID&from=execution", '', true), "<i class='icon icon-size-width'></i> " . $lang->kanban->columnWidth, '', "class='iframe btn btn-link' title='{$lang->kanban->laneHeight}' data-width=30%") . '</li>';
if(common::hasPriv('kanban', 'setColumnWidth')) echo '<li>' .html::a($this->createLink('kanban', 'setColumnWidth', "executionID=$executionID&from=execution", '', true), "<i class='icon icon-size-width'></i> " . $lang->kanban->columnWidth, '', "class='iframe btn btn-link' title='{$lang->kanban->columnWidth}' data-width=30%") . '</li>';
if(common::hasPriv('execution', 'printKanban')) echo '<li>' .html::a($this->createLink('execution', 'printKanban', "executionID=$executionID"), "<i class='icon icon-printer muted'></i> " . $lang->execution->printKanban, '', "class='iframe btn btn-link' id='printKanban' title='{$lang->execution->printKanban}' data-width='500'") . '</li>';
echo '<li>' .html::a('javascript:fullScreen()', "<i class='icon icon-fullscreen muted'></i> " . $lang->execution->fullScreen, '', "class='btn btn-link' title='{$lang->execution->fullScreen}' data-width='500'") . '</li>';
echo '</ul></div>';
+5 -5
View File
@@ -314,15 +314,15 @@ class gitlab extends control
}
$groups = $this->gitlab->apiGetGroups($gitlabID, $orderBy);
$adminGroups = $this->gitlab->apiGetGroups($gitlabID, $orderBy, $this->config->gitlab->accessLevel['owner']);
$adminGroups = $this->gitlab->apiGetGroups($gitlabID, $orderBy, 'owner');
$adminGropuIDList = array();
foreach($adminGroups as $group) $adminGropuIDList[] = $group->id;
$adminGroupIDList = array();
foreach($adminGroups as $group) $adminGroupIDList[] = $group->id;
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->browseGroup;
$this->view->gitlabID = $gitlabID;
$this->view->gitlabGroupList = $groups;
$this->view->adminGropuIDList = $adminGropuIDList;
$this->view->adminGroupIDList = $adminGroupIDList;
$this->view->orderBy = $orderBy;
$this->display();
}
@@ -656,7 +656,7 @@ class gitlab extends control
/* Get group id list by gitlab user that the user is maintainer. */
$groupIDList = array(0 => 0);
$groups = $this->gitlab->apiGetGroups($gitlabID, 'name_asc', $this->config->gitlab->accessLevel['maintainer']);
$groups = $this->gitlab->apiGetGroups($gitlabID, 'name_asc', 'maintainer');
foreach($groups as $group) $groupIDList[] = $group->id;
foreach($result['projects'] as $key => $project)
+28 -12
View File
@@ -61,15 +61,24 @@ class gitlabModel extends model
/**
* Get gitlab api base url by gitlab id.
*
* @param int $id
* @param int $gitlabID
* @param bool $sudo
* @access public
* @return string
*/
public function getApiRoot($id)
public function getApiRoot($gitlabID, $sudo = true)
{
$gitlab = $this->getByID($id);
$gitlab = $this->getByID($gitlabID);
if(!$gitlab) return '';
return rtrim($gitlab->url, '/') . '/api/v4%s' . "?private_token={$gitlab->token}";
$sudoParam = '';
if($sudo == true and !$this->app->user->admin)
{
$openID = $this->getUserIDByZentaoAccount($gitlabID, $this->app->user->account);
if($openID) $sudoParam = "&sudo={$openID}";
}
return rtrim($gitlab->url, '/') . '/api/v4%s' . "?private_token={$gitlab->token}" . $sudoParam;
}
/**
@@ -592,11 +601,18 @@ class gitlabModel extends model
* @access public
* @return object
*/
public function apiGetGroups($gitlabID, $orderBy, $minAccessLevel = 0)
public function apiGetGroups($gitlabID, $orderBy, $minRole = '')
{
$apiRoot = $this->getApiRoot($gitlabID);
$url = sprintf($apiRoot, "/groups");
if($minAccessLevel > 0) $url .= "&min_access_level=$minAccessLevel";
if($minRole == 'owner')
{
$url .= '&owned=true';
}
elseif(!empty($minRole))
{
$url .= "&min_access_level=$this->config->gitlab->accessLevel[$minRole]";
}
list($order, $sort) = explode('_', $orderBy);
@@ -1088,7 +1104,7 @@ class gitlabModel extends model
*/
public function apiGetHooks($gitlabID, $projectID)
{
$apiRoot = $this->getApiRoot($gitlabID);
$apiRoot = $this->getApiRoot($gitlabID, false);
$apiPath = "/projects/{$projectID}/hooks";
$url = sprintf($apiRoot, $apiPath);
@@ -1107,7 +1123,7 @@ class gitlabModel extends model
*/
public function apiGetHook($gitlabID, $projectID, $hookID)
{
$apiRoot = $this->getApiRoot($gitlabID);
$apiRoot = $this->getApiRoot($gitlabID, false);
$apiPath = "/projects/$projectID/hooks/$hookID)";
$url = sprintf($apiRoot, $apiPath);
@@ -1133,7 +1149,7 @@ class gitlabModel extends model
foreach($hook as $index => $item) $newHook->$index= $item;
$apiRoot = $this->getApiRoot($gitlabID);
$apiRoot = $this->getApiRoot($gitlabID, false);
$url = sprintf($apiRoot, "/projects/{$projectID}/hooks");
return json_decode(commonModel::http($url, $newHook));
@@ -1151,7 +1167,7 @@ class gitlabModel extends model
*/
public function apiDeleteHook($gitlabID, $projectID, $hookID)
{
$apiRoot = $this->getApiRoot($gitlabID);
$apiRoot = $this->getApiRoot($gitlabID, false);
$url = sprintf($apiRoot, "/projects/{$projectID}/hooks/{$hookID}");
return json_decode(commonModel::http($url, null, array(CURLOPT_CUSTOMREQUEST => 'delete')));
@@ -1210,7 +1226,7 @@ class gitlabModel extends model
*/
public function apiUpdateHook($gitlabID, $projectID, $hookID, $hook)
{
$apiRoot = $this->getApiRoot($gitlabID);
$apiRoot = $this->getApiRoot($gitlabID, false);
if(!isset($hook->url)) return false;
@@ -2777,7 +2793,7 @@ class gitlabModel extends model
{
if(empty($groupIDList))
{
$groups = $this->apiGetGroups($gitlabID, 'name_asc', $accessLevel);
$groups = $this->apiGetGroups($gitlabID, 'name_asc', $maxRole);
foreach($groups as $group) $groupIDList[] = $group->id;
}
+2
View File
@@ -59,6 +59,8 @@
<?php else:?>
<?php echo '<span class="text-red">' . $lang->gitlab->bindedError . '</span>';?>
<?php endif;?>
<?php else:?>
<?php echo $lang->gitlab->notBind;?>
<?php endif;?>
</td>
</tr>
+1 -1
View File
@@ -55,7 +55,7 @@
<td class='text' title='<?php echo substr($gitlabGroup->created_at, 0, 10);?>'><?php echo substr($gitlabGroup->created_at, 0, 10);?></td>
<td class='c-actions text-left'>
<?php
$adminClass = ($app->user->admin or in_array($gitlabGroup->id, $adminGropuIDList)) ? '' : 'disabled';
$adminClass = ($app->user->admin or in_array($gitlabGroup->id, $adminGroupIDList)) ? '' : 'disabled';
common::printLink('gitlab', 'manageGroupMembers', "gitlabID=$gitlabID&groupID=$gitlabGroup->id", "<i class='icon icon-team'></i> ", '',"title='{$lang->gitlab->group->manageMembers}' class='btn btn-primary'");
common::printLink('gitlab', 'editGroup', "gitlabID=$gitlabID&groupID=$gitlabGroup->id", "<i class='icon icon-edit'></i> ", '', "title='{$lang->gitlab->group->edit}' class='btn btn-primary {$adminClass}'");
if(common::hasPriv('gitlab', 'delete')) echo html::a($this->createLink('gitlab', 'deleteGroup', "gitlabID=$gitlabID&groupID=$gitlabGroup->id"), '<i class="icon-trash"></i>', 'hiddenwin', "title='{$lang->gitlab->deleteGroup}' class='btn {$adminClass}'");
-2
View File
@@ -669,8 +669,6 @@ $lang->resource->kanban->assigntoCard = 'assigntoCard';
//$lang->resource->kanban->copyCard = 'copyCard';
$lang->resource->kanban->deleteCard = 'deleteCard';
$lang->resource->kanban->moveCard = 'moveCard';
$lang->resource->kanban->finishCard = 'finishCard';
$lang->resource->kanban->activateCard = 'activateCard';
$lang->resource->kanban->setCardColor = 'setCardColor';
$lang->resource->kanban->laneMove = 'laneMove';
$lang->resource->kanban->viewArchivedColumn = 'viewArchivedColumn';
+2
View File
@@ -21,6 +21,8 @@ class jobModel extends model
public function getByID($id)
{
$job = $this->dao->select('*')->from(TABLE_JOB)->where('id')->eq($id)->fetch();
if(empty($job)) return new stdClass();
if(strtolower($job->engine) == 'gitlab')
{
$pipeline = json_decode($job->pipeline);
+29 -19
View File
@@ -168,7 +168,7 @@ class kanban extends control
unset($this->lang->kanbanspace->featureBar['involved']);
$space = $this->kanban->getSpaceById($spaceID);
$spaceUsers = $spaceID == 0 ? ',' : trim($space->owner) . ',' . trim($space->team) . ',' . trim($space->whitelist);
$spaceUsers = $spaceID == 0 ? ',' : trim($space->owner) . ',' . trim($space->team);
$users = $this->loadModel('user')->getPairs('noclosed|nodeleted', '', 0, $spaceUsers);
$this->view->users = $users;
@@ -204,11 +204,11 @@ class kanban extends control
$kanban = $this->kanban->getByID($kanbanID);
$space = $this->kanban->getSpaceById($kanban->space);
$spaceUsers = trim($space->owner) . ',' . trim($space->team) . ',' . trim($space->whitelist);
$spaceUsers = trim($space->owner) . ',' . trim($space->team);
$users = $this->loadModel('user')->getPairs('noclosed|nodeleted', '', 0, $spaceUsers);
$this->view->users = $users;
$this->view->spacePairs = array(0 => '') + $this->kanban->getSpacePairs($space->type);
$this->view->spacePairs = array(0 => '') + array($kanban->space => $space->name) + $this->kanban->getSpacePairs($space->type);
$this->view->kanban = $kanban;
$this->view->type = $space->type;
@@ -801,7 +801,11 @@ class kanban extends control
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $backLink));
}
$users = $this->loadModel('user')->getPairs('noclosed|nodeleted');
$kanban = $this->kanban->getByID($kanbanID);
$space = $this->kanban->getSpaceById($kanban->space);
$spaceUsers = $kanban->space == 0 ? ',' : trim($space->owner) . ',' . trim($space->team);
$users = $this->loadModel('user')->getPairs('noclosed|nodeleted', '', 0, $spaceUsers);
$lanePairs = $this->kanban->getLanePairsByGroup($groupID);
$lanePairs['ditto'] = $this->lang->kanbancard->ditto;
@@ -941,7 +945,7 @@ class kanban extends control
* @access public
* @return void
*/
public function moveCard($cardID, $fromColID, $toColID, $fromLaneID, $toLaneID, $kanbanID)
public function moveCard($cardID, $fromColID, $toColID, $fromLaneID, $toLaneID, $kanbanID = 0)
{
$this->kanban->moveCard($cardID, $fromColID, $toColID, $fromLaneID, $toLaneID, $kanbanID);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
@@ -963,7 +967,7 @@ class kanban extends control
* @access public
* @return void
*/
public function importCard($kanbanID = 0, $regionID = 0, $groupID = 0, $columnID = 0, $selectedKanbanID = 0, $recTotal = 0, $recPerPage = 30, $pageID = 1)
public function importCard($kanbanID = 0, $regionID = 0, $groupID = 0, $columnID = 0, $selectedKanbanID = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
/* Load pager. */
$this->app->loadClass('pager', $static = true);
@@ -1016,7 +1020,7 @@ class kanban extends control
* @access public
* @return void
*/
public function importPlan($kanbanID = 0, $regionID = 0, $groupID = 0, $columnID = 0, $selectedProductID = 0, $recTotal = 0, $recPerPage = 30, $pageID = 1)
public function importPlan($kanbanID = 0, $regionID = 0, $groupID = 0, $columnID = 0, $selectedProductID = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
if($_POST)
{
@@ -1068,7 +1072,7 @@ class kanban extends control
* @access public
* @return void
*/
public function importRelease($kanbanID = 0, $regionID = 0, $groupID = 0, $columnID = 0, $selectedProductID = 0, $recTotal = 0, $recPerPage = 30, $pageID = 1)
public function importRelease($kanbanID = 0, $regionID = 0, $groupID = 0, $columnID = 0, $selectedProductID = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
if($_POST)
{
@@ -1090,10 +1094,7 @@ class kanban extends control
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$productPairs = $this->product->getPairs();
$selectedProductID = empty($selectedProductID) ? key($productPairs) : $selectedProductID;
$this->view->products = $productPairs;
$this->view->products = array($this->lang->kanban->allProducts) + $this->product->getPairs();
$this->view->selectedProductID = $selectedProductID;
$this->view->lanePairs = $this->kanban->getLanePairsByGroup($groupID);
$this->view->releases2Imported = $this->release->getList($selectedProductID, 'all', 'all', 't1.date_desc', $pager);
@@ -1120,7 +1121,7 @@ class kanban extends control
* @access public
* @return void
*/
public function importBuild($kanbanID = 0, $regionID = 0, $groupID = 0, $columnID = 0, $selectedProjectID = 0, $recTotal = 0, $recPerPage = 30, $pageID = 1)
public function importBuild($kanbanID = 0, $regionID = 0, $groupID = 0, $columnID = 0, $selectedProjectID = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
if($_POST)
{
@@ -1135,20 +1136,29 @@ class kanban extends control
return print(js::locate($this->createLink('kanban', 'view', "kanbanID=$kanbanID"), 'parent.parent'));
}
$this->loadModel('project');
$this->loadModel('build');
/* Load pager. */
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$projectPairs = $this->project->getPairsByProgram();
$selectedProjectID = empty($selectedProjectID) ? key($projectPairs) : $selectedProjectID;
$builds2Imported = array();
$projects = array($this->lang->kanban->allProjects);
if($this->config->systemMode == 'classic')
{
$projects += $this->loadModel('execution')->getPairs();
$builds2Imported = $this->build->getExecutionBuilds($selectedProjectID, '', '', 't1.date_desc,t1.id_desc', $pager);
}
else
{
$projects += $this->loadModel('project')->getPairsByProgram('', 'all', false, 'order_asc', 'kanban');
$builds2Imported = $this->build->getProjectBuilds($selectedProjectID, 'all', 0, 't1.date_desc,t1.id_desc', $pager);
}
$this->view->projects = $projectPairs;
$this->view->projects = $projects;
$this->view->selectedProjectID = $selectedProjectID;
$this->view->builds2Imported = $builds2Imported;
$this->view->lanePairs = $this->kanban->getLanePairsByGroup($groupID);
$this->view->builds2Imported = $this->build->getProjectBuilds($selectedProjectID, 'all', 0, 't1.date_desc,t1.id_desc', $pager);;
$this->view->users = $this->loadModel('user')->getPairs('noletter|nodeleted');
$this->view->pager = $pager;
$this->view->kanbanID = $kanbanID;
@@ -1173,7 +1183,7 @@ class kanban extends control
* @access public
* @return void
*/
public function importExecution($kanbanID = 0, $regionID = 0, $groupID = 0, $columnID = 0, $selectedProjectID = 0, $recTotal = 0, $recPerPage = 30, $pageID = 1)
public function importExecution($kanbanID = 0, $regionID = 0, $groupID = 0, $columnID = 0, $selectedProjectID = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
if($_POST)
{
+2
View File
@@ -3,3 +3,5 @@
.checked > .icon {display: inline-block;}
.p-10px {padding: 10px}
#kanbanActionMenu li a {text-align: left}
.importModal {min-height: 300px;}
+3 -2
View File
@@ -58,7 +58,7 @@
.region .kanban-lane-items {overflow: overlay !important; padding-bottom: 10px;}
.region .kanban-item {position: relative}
.region .kanban-item > .kanban-card > .title {line-height: 18px;}
.region .kanban-item > .kanban-card > .title {display: block; line-height: 18px;}
.region .kanban-item > .kanban-card > .title:hover {color: #2272eb}
.region .kanban-item > .kanban-card > .info {margin-top: 4px; position: relative;}
.region .kanban-item > .kanban-card > .info > .pri {height: 14px; border-width: 1px; font-size: 12px; line-height: 12px; min-width: 14px; padding: 0 1px;}
@@ -103,11 +103,12 @@
.kanban-card .header .executionName {display: flex; width: 100%; float: left;}
.kanban-card .header .executionName .title {padding-right: 0px; margin-right: 5px; overflow: hidden; white-space: nowrap;}
.kanban-card .header .executionName > span {flex: none;}
.execInfo, .releaseInfo, .productplanInfo {margin-top: 23px;}
.execInfo, .releaseInfo, .productplanInfo {margin-top: 22px;}
.label-wait {background: #EFEFEF !important; color: #838A9D;}
.label-doing {background: #f8d2d2 !important; color: #e64b4c;}
.label-suspended {background: #fff3d9 !important; color: #ff9800;}
.label-future {background: #EFEFEF !important; color: #838A9D; border-radius: 9px}
.label-done {background: #dfe9d8 !important; color: #429b16;}
.label-closed, .label-terminate {background: #e5e5e5 !important; color: #b8b8b8;}
.label-deleted {background: #ff5d5d !important; color: #fff;}
.label-normal {background: #e1e8d9 !important; color: #9abe76;}
+17
View File
@@ -68,3 +68,20 @@ function setTargetLane(targetLaneID)
{
$('#targetLane').val(targetLaneID);
}
/**
* Jump to the view page.
*
* @param string $module
* @param int $objectID
* @access public
* @return void
*/
function locateView(module, objectID)
{
var dataApp = 'kanban';
if(module == 'productplan' || module == 'release') dataApp = 'product';
if(module == 'execution') dataApp = 'execution';
if(module == 'build') dataApp = 'project';
parent.$.apps.open(createLink(module, 'view', 'objectID=' + objectID), dataApp);
}
+16 -13
View File
@@ -332,7 +332,9 @@ function renderKanbanItem(item, $item)
$title.text(item.name).css('color', '');
$item.children('.label').hide();
}
if(printMoreBtn)
var $actions = $item.children('.actions');
if(printMoreBtn && !$actions.length)
{
$(
[
@@ -438,9 +440,10 @@ function renderExecutionItem(item, $item)
var $title = $titleBox.children('.title');
if(!$title.length)
{
var icon = mode == 'new' ? 'run' : 'project';
var viewMethod = item.execType == 'kanban' ? 'kanban' : 'view';
if(privs.includes('viewExecution') && item.deleted == '0') $title = $('<a class="title"><i class="icon icon-run"></i>' + item.name + '</a>').appendTo($titleBox).attr('href', createLink('execution', viewMethod, 'executionID=' + item.fromID));
if(!privs.includes('viewExecution') || item.deleted == '1') $title = $('<div class="title"><i class="icon icon-run"></i>' + item.name + '</div>').appendTo($titleBox);
if(privs.includes('viewExecution') && item.deleted == '0') $title = $('<a class="title"><i class="icon icon-' + icon + '"></i>' + item.name + '</a>').appendTo($titleBox).attr('href', createLink('execution', viewMethod, 'executionID=' + item.fromID));
if(!privs.includes('viewExecution') || item.deleted == '1') $title = $('<div class="title"><i class="icon icon-' + icon + '"></i>' + item.name + '</div>').appendTo($titleBox);
}
$title.attr('title', item.name);
@@ -511,7 +514,7 @@ function renderReleaseItem(item, $item)
var $title = $item.children('.releaseTitle');
if(!$title.length)
{
if(privs.includes('viewRelease') && item.deleted == '0') $title = $('<a class="releaseTitle"><i class="icon icon-publish"></i>' + item.name + '</a>').appendTo($item).attr('href', createLink('release', 'view', 'releaseID=' + item.fromID));
if(privs.includes('viewRelease') && item.deleted == '0') $title = $('<a class="releaseTitle title"><i class="icon icon-publish"></i>' + item.name + '</a>').appendTo($item).attr('href', createLink('release', 'view', 'releaseID=' + item.fromID));
if(!privs.includes('viewRelease') || item.deleted == '1') $title = $('<div class="releaseTitle"><i class="icon icon-publish"></i>' + item.name + '</div>').appendTo($item);
}
$title.attr('title', item.name);
@@ -570,7 +573,7 @@ function renderProductplanItem(item, $item)
var $title = $item.children('.productplanTitle');
if(!$title.length)
{
if(privs.includes('viewPlan') && item.deleted == '0') $title = $('<a class="productplanTitle"><i class="icon icon-delay"></i>' + item.title + '</a>').appendTo($item).attr('href', createLink('productplan', 'view', 'productplanID=' + item.fromID));
if(privs.includes('viewPlan') && item.deleted == '0') $title = $('<a class="productplanTitle title"><i class="icon icon-delay"></i>' + item.title + '</a>').appendTo($item).attr('href', createLink('productplan', 'view', 'productplanID=' + item.fromID));
if(!privs.includes('viewPlan') || item.deleted == '1') $title = $('<div class="productplanTitle"><i class="icon icon-delay"></i>' + item.title + '</div>').appendTo($item);
}
$title.attr('title', item.title);
@@ -600,7 +603,7 @@ function renderProductplanItem(item, $item)
var begin = $.zui.createDate(item.begin);
var end = $.zui.createDate(item.end);
var today = new Date();
var labelType = end.toLocaleDateString() == today.toLocaleDateString() ? 'danger' : 'wait';
var labelType = (item.begin <= $.zui.formatDate(today, 'yyyy-MM-dd') && item.end >= $.zui.formatDate(today, 'yyyy-MM-dd')) ? 'danger' : 'wait';
var labelTitle = $.zui.formatDate(begin, 'MM-dd') + ' ' + productplanLang.to + ' ' + $.zui.formatDate(end, 'MM-dd');
if((item.begin == '2030-01-01' || item.end == '2030-01-01'))
@@ -638,7 +641,7 @@ function renderBuildItem(item, $item)
var $title = $item.children('.buildTitle');
if(!$title.length)
{
if(privs.includes('viewBuild') && item.deleted == '0') $title = $('<a class="buildTitle"><i class="icon icon-ver"></i>' + item.name + '</a>').appendTo($item).attr('href', createLink('build', 'view', 'buildID=' + item.fromID));
if(privs.includes('viewBuild') && item.deleted == '0') $title = $('<a class="buildTitle" data-app="project"><i class="icon icon-ver"></i>' + item.name + '</a>').appendTo($item).attr('href', createLink('build', 'view', 'buildID=' + item.fromID));
if(!privs.includes('viewBuild') || item.deleted == '1') $title = $('<div class="buildTitle"><i class="icon icon-ver"></i>' + item.name + '</div>').appendTo($item);
}
$title.attr('title', item.name);
@@ -1082,9 +1085,9 @@ function createCardMenu(options)
var items = [];
if(privs.includes('editCard')) items.push({label: kanbanLang.editCard, icon: 'edit', url: createLink('kanban', 'editCard', 'cardID=' + card.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
if(kanban.performable == 1)
if(privs.includes('performable') && kanban.performable == 1)
{
if(privs.includes('activateCard') && card.status != 'doing')
if(card.status != 'doing')
{
items.push({label: kanbanLang.activateCard, icon: 'magic', onClick: function(){activateCard(card.id, card.kanban, card.region);}});
}
@@ -1311,10 +1314,10 @@ $(function()
var columnID = $(this).closest('.kanban-col').data('id');
/* The submenu of import. */
var importPlanLink = kanban.object.indexOf('plans') != -1 ? "<li><a class='iframe' data-toggle='modal' data-width='80%' href='" + createLink('kanban', 'importPlan', 'kanbanID=' + kanban.id + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID) + "'>" + kanbanLang.importPlan + '</a></li>' : '';
var importReleaseLink = kanban.object.indexOf('releases') != -1 ? "<li><a class='iframe' data-toggle='modal' data-width='80%' href='" + createLink('kanban', 'importRelease', 'kanbanID=' + kanban.id + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID) + "'>" + kanbanLang.importRelease + '</a></li>' : '';
var importExecutionLink = kanban.object.indexOf('executions') != -1 ? "<li><a class='iframe' data-toggle='modal' data-width='80%' href='" + createLink('kanban', 'importExecution', 'kanbanID=' + kanban.id + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID) + "'>" + kanbanLang.importExecution + '</a></li>' : '';
var importBuildLink = kanban.object.indexOf('builds') != -1 ? "<li><a class='iframe' data-toggle='modal' data-width='80%' href='" + createLink('kanban', 'importBuild', 'kanbanID=' + kanban.id + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID) + "'>" + kanbanLang.importBuild + '</a></li>' : '';
var importPlanLink = kanban.object.indexOf('plans') != -1 ? "<li><a class='iframe' data-toggle='modal'' href='" + createLink('kanban', 'importPlan', 'kanbanID=' + kanban.id + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID) + "'>" + kanbanLang.importPlan + '</a></li>' : '';
var importReleaseLink = kanban.object.indexOf('releases') != -1 ? "<li><a class='iframe' data-toggle='modal'' href='" + createLink('kanban', 'importRelease', 'kanbanID=' + kanban.id + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID) + "'>" + kanbanLang.importRelease + '</a></li>' : '';
var importExecutionLink = kanban.object.indexOf('executions') != -1 ? "<li><a class='iframe' data-toggle='modal' href='" + createLink('kanban', 'importExecution', 'kanbanID=' + kanban.id + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID) + "'>" + kanbanLang.importExecution + '</a></li>' : '';
var importBuildLink = kanban.object.indexOf('builds') != -1 ? "<li><a class='iframe' data-toggle='modal' href='" + createLink('kanban', 'importBuild', 'kanbanID=' + kanban.id + '&regionID=' + regionID + '&groupID=' + groupID + '&columnID=' + columnID) + "'>" + kanbanLang.importBuild + '</a></li>' : '';
var importSubmenu = '<ul class="dropdown-menu">' + importPlanLink + importReleaseLink + importExecutionLink + importBuildLink +'</ul>';
$('.import').parent().append(importSubmenu);
+4 -4
View File
@@ -20,8 +20,8 @@ $lang->kanban->editLane = 'Edit Lane';
$lang->kanban->sortLane = 'Sort Lane';
$lang->kanban->laneHeight = 'Lane Height';
$lang->kanban->setLaneHeight = 'Set Lane Height';
$lang->kanban->columnWidth = 'Column Height';
$lang->kanban->setColumnWidth = 'Set Column Height';
$lang->kanban->columnWidth = 'Column Width';
$lang->kanban->setColumnWidth = 'Set Column Width';
$lang->kanban->deleteLane = 'Delete Lane';
$lang->kanban->createColumn = 'Create Column';
$lang->kanban->editColumn = 'Edit Column';
@@ -74,7 +74,7 @@ $lang->kanban->importRelease = 'Release';
$lang->kanban->importExecution = $lang->execution->common;
$lang->kanban->importBuild = 'Build';
$lang->kanban->allKanban = 'All Kanban';
$lang->kanban->allProjects = 'All Projects';
$lang->kanban->allProjects = 'All ' . ($this->config->systemMode == 'classic' ? $lang->executionCommon : 'Projects');
$lang->kanban->allProducts = 'All Products';
/* Fields. */
@@ -107,7 +107,7 @@ $lang->kanban->cardCountTip = 'Please enter the number of cards';
$lang->kanban->selectedKanban = 'Please select Kanban';
$lang->kanban->selectedProduct = 'Please select Product';
$lang->kanban->selectedProject = 'Please select Project';
$lang->kanban->selectedProject = 'Please select ' . ($this->config->systemMode == 'classic' ? $lang->executionCommon : 'Project');
$lang->kanban->selectedLane = 'Target Lane';
$lang->kanban->aclGroup['open'] = 'Open';
+2 -2
View File
@@ -74,7 +74,7 @@ $lang->kanban->importRelease = '发布';
$lang->kanban->importExecution = $lang->execution->common;
$lang->kanban->importBuild = '版本';
$lang->kanban->allKanban = '所有看板';
$lang->kanban->allProjects = '所有项目';
$lang->kanban->allProjects = '所有' . ($this->config->systemMode == 'classic' ? $lang->executionCommon : '项目');
$lang->kanban->allProducts = '所有产品';
/* Fields. */
@@ -107,7 +107,7 @@ $lang->kanban->cardCountTip = '请输入卡片数量';
$lang->kanban->selectedKanban = '请选择看板';
$lang->kanban->selectedProduct = '请选择产品';
$lang->kanban->selectedProject = '请选择项目';
$lang->kanban->selectedProject = '请选择' . ($this->config->systemMode == 'classic' ? $lang->executionCommon : '项目');
$lang->kanban->selectedLane = '目标泳道';
$lang->kanban->aclGroup['open'] = '公开';
+28 -14
View File
@@ -1036,7 +1036,7 @@ class kanbanModel extends model
->andWhere('type')->eq('common')
->fetchAll();
$actions = array('editCard', 'finishCard', 'activateCard', 'archiveCard', 'deleteCard', 'moveCard', 'setCardColor', 'viewCard', 'sortCard', 'viewExecution', 'viewPlan', 'viewRelease', 'viewBuild');
$actions = array('editCard', 'performable', 'archiveCard', 'deleteCard', 'moveCard', 'setCardColor', 'viewCard', 'sortCard', 'viewExecution', 'viewPlan', 'viewRelease', 'viewBuild');
$cardGroup = array();
foreach($cellList as $cell)
{
@@ -1677,7 +1677,7 @@ class kanbanModel extends model
foreach($objects as $objectID => $object)
{
$remove = true;
if($param == 'public') continue;
if($objectType == 'kanbanspace' and $object->type == 'public') continue;
if($object->owner == $account) $remove = false;
if(strpos(",{$object->team},", ",$account,") !== false) $remove = false;
@@ -2807,11 +2807,11 @@ class kanbanModel extends model
/**
* Set column width.
*
* @param int $kanbanID
* @param string $from
*
* @param int $kanbanID
* @param string $from
* @access public
* @return bool|void
* @return bool|void
*/
public function setColumnWidth($kanbanID, $from = 'kanban')
{
@@ -2830,6 +2830,9 @@ class kanbanModel extends model
*/
public function setHeaderActions($kanban)
{
$btnColor = '';
if($this->app->cookie->theme == 'blue') $btnColor = 'style="color:#000000"';
$printSetHeightBtn = false;
if(common::hasPriv('kanban', 'setLaneHeight'))
{
@@ -2845,17 +2848,18 @@ class kanbanModel extends model
$actions = '';
$actions .= "<div class='btn-group'>";
$actions .= "<a href='javascript:fullScreen();' id='fullScreenBtn' class='btn btn-link'><i class='icon icon-fullscreen'></i> {$this->lang->kanban->fullScreen}</a>";
$actions .= "<a href='javascript:fullScreen();' id='fullScreenBtn' $btnColor class='btn btn-link'><i class='icon icon-fullscreen'></i> {$this->lang->kanban->fullScreen}</a>";
$printSettingBtn = (common::hasPriv('kanban', 'createRegion') or $printSetHeightBtn or common::hasPriv('kanban', 'performable') or common::hasPriv('kanban', 'edit') or common::hasPriv('kanban', 'close') or common::hasPriv('kanban', 'enableArchived') or common::hasPriv('kanban', 'delete'));
if($printSettingBtn)
{
$actions .= "<a data-toggle='dropdown' class='btn btn-link dropdown-toggle setting' type='button'>" . '<i class="icon icon-cog-outline"></i> ' . $this->lang->kanban->setting . '</a>';
$actions .= "<a data-toggle='dropdown' $btnColor class='btn btn-link dropdown-toggle setting' type='button'>" . '<i class="icon icon-cog-outline"></i> ' . $this->lang->kanban->setting . '</a>';
$actions .= "<ul id='kanbanActionMenu' class='dropdown-menu text-left'>";
if(common::hasPriv('kanban', 'createRegion')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'createRegion', "kanbanID=$kanban->id", '', true), '<i class="icon icon-plus"></i>' . $this->lang->kanban->createRegion, '', "class='iframe btn btn-link'") . '</li>';
if(common::hasPriv('kanban', 'import')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'import', "kanbanID=$kanban->id", '', true), '<i class="icon icon-import"></i>' . $this->lang->kanban->import, '', "class='iframe btn btn-link'") . '</li>';
if(common::hasPriv('kanban', 'enableArchived')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'enableArchived', "kanbanID=$kanban->id", '', true), '<i class="icon icon-card-archive"></i>' . $this->lang->kanban->archived, '', "class='iframe btn btn-link'") . '</li>';
$importWidth = $this->app->getClientLang() == 'en' ? '70%' : '50%';
if(common::hasPriv('kanban', 'import')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'import', "kanbanID=$kanban->id", '', true), '<i class="icon icon-import"></i>' . $this->lang->kanban->import, '', "class='iframe btn btn-link' data-width=$importWidth") . '</li>';
if(common::hasPriv('kanban', 'enableArchived')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'enableArchived', "kanbanID=$kanban->id", '', true), '<i class="icon icon-card-archive"></i>' . $this->lang->kanban->archived, '', "class='iframe btn btn-link' data-width=20%") . '</li>';
if($printSetHeightBtn)
{
$width = $this->app->getClientLang() == 'en' ? '70%' : '60%';
@@ -2863,7 +2867,7 @@ class kanbanModel extends model
}
if(common::hasPriv('kanban', 'setColumnWidth')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'setColumnWidth', "kanbanID=$kanban->id", '', true), '<i class="icon icon-size-width"></i>' . $this->lang->kanban->columnWidth, '', "class='iframe btn btn-link' data-width=30%") . '</li>';
if(common::hasPriv('kanban', 'performable')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'performable', "kanbanID=$kanban->id", '', true), '<i class="icon icon-checked"></i>' . $this->lang->kanban->doneFunction, '', "class='iframe btn btn-link'") . '</li>';
if(common::hasPriv('kanban', 'performable')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'performable', "kanbanID=$kanban->id", '', true), '<i class="icon icon-checked"></i>' . $this->lang->kanban->doneFunction, '', "class='iframe btn btn-link' data-width=20%") . '</li>';
$kanbanActions = '';
$attr = $kanban->status == 'closed' ? "disabled='disabled'" : '';
@@ -2872,7 +2876,7 @@ class kanbanModel extends model
if(common::hasPriv('kanban', 'delete')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'delete', "kanbanID=$kanban->id"), '<i class="icon icon-trash"></i>' . $this->lang->kanban->delete, 'hiddenwin', "class='btn btn-link'") . '</li>';
if($kanbanActions)
{
$actions .= ((common::hasPriv('kanban', 'createRegion') or $printSetHeight or common::hasPriv('kanban', 'performable')) and (common::hasPriv('kanban', 'edit') or common::hasPriv('kanban', 'close') or common::hasPriv('kanban', 'enableArchived') or common::hasPriv('kanban', 'delete'))) ? "<div class='divider'></div>" . $kanbanActions : $kanbanActions;
$actions .= ((common::hasPriv('kanban', 'createRegion') or $printSetHeightBtn or common::hasPriv('kanban', 'performable') or common::hasPriv('kanban', 'setColumnWidth')) and (common::hasPriv('kanban', 'edit') or common::hasPriv('kanban', 'close') or common::hasPriv('kanban', 'enableArchived') or common::hasPriv('kanban', 'delete'))) ? "<li class='divider'></li>" . $kanbanActions : $kanbanActions;
}
$actions .= "</ul>";
}
@@ -2943,12 +2947,14 @@ class kanbanModel extends model
* @access public
* @return void
*/
public function moveCard($cardID, $fromColID, $toColID, $fromLaneID, $toLaneID, $kanbanID)
public function moveCard($cardID, $fromColID, $toColID, $fromLaneID, $toLaneID, $kanbanID = 0)
{
$fromCellCards = $this->dao->select('cards')->from(TABLE_KANBANCELL)->where('lane')->eq($fromLaneID)->andWhere('`column`')->eq($fromColID)->fetch('cards');
$toCell = $this->dao->select('*')->from(TABLE_KANBANCELL)->where('lane')->eq($toLaneID)->andWhere('`column`')->eq($toColID)->fetch();
$toCellCards = $this->dao->select('cards')->from(TABLE_KANBANCELL)->where('lane')->eq($toLaneID)->andWhere('`column`')->eq($toColID)->fetch('cards');
$kanbanID = $kanbanID == 0 ? $toCell->kanban : $kanbanID;
if(!$toCell) $this->addKanbanCell($kanbanID, $toLaneID, $toColID, 'common');
$fromCardList = str_replace(",$cardID,", ',', $fromCellCards);
@@ -3048,7 +3054,15 @@ class kanbanModel extends model
foreach($parentCells as $cell)
{
$this->dao->update(TABLE_KANBANCELL)->set('cards')->eq($cell->cards)
$cards = $this->dao->select('cards')->from(TABLE_KANBANCELL)
->where('lane')->eq($cell->lane)
->andWhere('`column`')->eq($columnID)
->andWhere('type')->eq('common')
->fetch('cards');
$cards = $cards ? $cards . ltrim($cell->cards, ',') : $cell->cards;
$this->dao->update(TABLE_KANBANCELL)->set('cards')->eq($cards)
->where('lane')->eq($cell->lane)
->andWhere('`column`')->eq($columnID)
->andWhere('type')->eq('common')
+1 -1
View File
@@ -19,7 +19,7 @@
<form class='main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
<table class='table table-form'>
<tr>
<th><?php echo $lang->kanban->archive;?></th>
<th class='w-70px'><?php echo $lang->kanban->archive;?></th>
<td><?php echo nl2br(html::radio('archived', $lang->kanban->archiveList, $kanban->archived));?></td>
</tr>
<tr>
+16 -13
View File
@@ -19,17 +19,16 @@
<div id='mainContent' class='main-content importModal'>
<div class='center-block'>
<div class='main-header'>
<h2><?php echo $lang->kanban->importBuild;?></h2>
<h2><?php echo $lang->kanban->importAB . $lang->kanban->importBuild;?></h2>
</div>
</div>
<div class='table-row p-10px'>
<div class='table-col w-150px text-center'><h4><?php echo $lang->kanban->selectedProject;?></h4></div>
<div class='table-col'><?php echo html::select('project', $projects, $selectedProjectID, "onchange='reloadObjectList(this.value)' class='form-control chosen' data-drop_direction='down'");?></div>
</div>
<div class='table-row p-10px'>
<div class='table-col w-150px text-center'><h4><?php echo $lang->kanban->selectedLane;?></h4></div>
<div class='table-col'><?php echo html::select('lane', $lanePairs, '', "onchange='setTargetLane(this.value)' class='form-control chosen' data-drop_direction='down'");?></div>
<div class='input-group space'>
<span class='input-group-addon'><?php echo $lang->kanban->selectedProject;?></span>
<?php echo html::select('project', $projects, $selectedProjectID, "onchange='reloadObjectList(this.value)' class='form-control chosen' data-drop_direction='down'");?>
<span class='input-group-addon'><?php echo $lang->kanban->selectedLane;?></span>
<?php echo html::select('lane', $lanePairs, '', "onchange='setTargetLane(this.value)' class='form-control chosen' data-drop_direction='down'");?>
</div>
<?php if($builds2Imported):?>
<form class='main-table' method='post' data-ride='table' target='hiddenwin' id='importBuildForm'>
<table class='table table-fixed' id='buildList'>
<thead>
@@ -42,7 +41,7 @@
</th>
<th class='c-name'><?php echo $lang->build->product;?></th>
<th class='c-name'><?php echo $lang->build->name;?></th>
<th class='c-name'><?php echo $lang->executionCommon;?></th>
<th class='c-name'><?php echo $lang->execution->common;?></th>
<th class='c-date'><?php echo $lang->build->date;?></th>
<th class='c-user'><?php echo $lang->build->builder;?></th>
</tr>
@@ -59,7 +58,9 @@
</td>
<td title='<?php echo $build->productName;?>'><?php echo $build->productName;?></td>
<?php if(common::hasPriv('build', 'view')):?>
<td title='<?php echo $build->name;?>'><?php common::printLink('build', 'view', "buildID=$build->id", $build->name, '', "class='iframe'", true, true);?></td>
<td title='<?php echo $build->name;?>'>
<a href='javascript:void(0);' onclick="locateView('build', <?php echo $build->id;?>)"><?php echo $build->name;?></a>
</td>
<?php else:?>
<td title='<?php echo $build->name;?>'><?php echo $build->name;?></td>
<?php endif;?>
@@ -71,13 +72,15 @@
<tr><?php echo html::hidden('targetLane', key($lanePairs));?></tr>
</tbody>
</table>
<?php if($builds2Imported):?>
<div class='table-footer'>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar show-always"><?php echo html::submitButton($lang->kanban->importBuild, '', 'btn btn-default');?></div>
<div class="table-actions btn-toolbar show-always"><?php echo html::submitButton($lang->kanban->importAB, '', 'btn btn-default');?></div>
<?php $pager->show('right', 'pagerjs');?>
</div>
<?php endif;?>
</form>
<?php else:?>
<div class='table-empty-tip'><?php echo $lang->noData;?></div>
<?php endif;?>
</div>
<style>#project_chosen {width: 45% !important}</style>
<?php include '../../common/view/footer.lite.html.php';?>
+10 -9
View File
@@ -22,14 +22,13 @@
<h2><?php echo $lang->kanban->importCard;?></h2>
</div>
</div>
<div class='table-row p-10px'>
<div class='table-col w-150px text-center'><h4><?php echo $lang->kanban->selectedKanban;?></h4></div>
<div class='table-col'><?php echo html::select('kanban', $kanbanPairs, $selectedKanbanID, "onchange='reloadObjectList(this.value)' class='form-control chosen' data-drop_direction='down'");?></div>
</div>
<div class='table-row p-10px'>
<div class='table-col w-150px text-center'><h4><?php echo $lang->kanban->selectedLane;?></h4></div>
<div class='table-col'><?php echo html::select('lane', $lanePairs, '', "onchange='setTargetLane(this.value)' class='form-control chosen' data-drop_direction='down'");?></div>
<div class='input-group space'>
<span class='input-group-addon'><?php echo $lang->kanban->selectedKanban;?></span>
<?php echo html::select('kanban', $kanbanPairs, $selectedKanbanID, "onchange='reloadObjectList(this.value)' class='form-control chosen' data-drop_direction='down'");?>
<span class='input-group-addon'><?php echo $lang->kanban->selectedLane;?></span>
<?php echo html::select('lane', $lanePairs, '', "onchange='setTargetLane(this.value)' class='form-control chosen' data-drop_direction='down'");?>
</div>
<?php if($cards2Imported):?>
<form class='main-table' method='post' data-ride='table' target='hiddenwin' id='importCardForm'>
<table class='table table-fixed' id='cardList'>
<thead>
@@ -71,13 +70,15 @@
<tr><?php echo html::hidden('targetLane', key($lanePairs));?></tr>
</tbody>
</table>
<?php if($cards2Imported):?>
<div class='table-footer'>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar show-always"><?php echo html::submitButton($lang->kanban->importCard, '', 'btn btn-default');?></div>
<?php $pager->show('right', 'pagerjs');?>
</div>
<?php endif;?>
</form>
<?php else:?>
<div class='table-empty-tip'><?php echo $lang->noData;?></div>
<?php endif;?>
</div>
<style>#kanban_chosen {width: 45% !important}</style>
<?php include '../../common/view/footer.lite.html.php';?>
+21 -12
View File
@@ -19,17 +19,18 @@
<div id='mainContent' class='main-content importModal'>
<div class='center-block'>
<div class='main-header'>
<h2><?php echo $lang->kanban->importExecution;?></h2>
<h2><?php echo $lang->kanban->importAB . $lang->kanban->importExecution;?></h2>
</div>
</div>
<div class='table-row p-10px'>
<div class='table-col w-150px text-center'><h4><?php echo $lang->kanban->selectedProject;?></h4></div>
<div class='table-col'><?php echo html::select('project', $projects, $selectedProjectID, "onchange='reloadObjectList(this.value)' class='form-control chosen' data-drop_direction='down'");?></div>
</div>
<div class='table-row p-10px'>
<div class='table-col w-150px text-center'><h4><?php echo $lang->kanban->selectedLane;?></h4></div>
<div class='table-col'><?php echo html::select('lane', $lanePairs, '', "onchange='setTargetLane(this.value)' class='form-control chosen' data-drop_direction='down'");?></div>
<div class='input-group space'>
<?php if($config->systemMode == 'new'):?>
<span class='input-group-addon'><?php echo $lang->kanban->selectedProject;?></span>
<?php echo html::select('project', $projects, $selectedProjectID, "onchange='reloadObjectList(this.value)' class='form-control chosen' data-drop_direction='down'");?>
<?php endif;?>
<span class='input-group-addon'><?php echo $lang->kanban->selectedLane;?></span>
<?php echo html::select('lane', $lanePairs, '', "onchange='setTargetLane(this.value)' class='form-control chosen' data-drop_direction='down'");?>
</div>
<?php if($executions2Imported):?>
<form class='main-table' method='post' data-ride='table' target='hiddenwin' id='importExecutionForm'>
<table class='table table-fixed' id='executionList'>
<thead>
@@ -60,7 +61,9 @@
<?php printf('%03d', $execution->id);?>
</td>
<?php if(common::hasPriv('execution', 'view')):?>
<td title='<?php echo $execution->name;?>'><?php common::printLink('execution', 'view', "executionID=$execution->id", $execution->name, '', "class='iframe'", true, true);?></td>
<td title='<?php echo $execution->name;?>'>
<a href='javascript:void(0);' onclick="locateView('execution', <?php echo $execution->id;?>)"><?php echo $execution->name;?></a>
</td>
<?php else:?>
<td title='<?php echo $execution->name;?>'><?php echo $execution->name;?></td>
<?php endif;?>
@@ -75,13 +78,19 @@
<tr><?php echo html::hidden('targetLane', key($lanePairs));?></tr>
</tbody>
</table>
<?php if($executions2Imported):?>
<div class='table-footer'>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar show-always"><?php echo html::submitButton($lang->kanban->importExecution, '', 'btn btn-default');?></div>
<div class="table-actions btn-toolbar show-always"><?php echo html::submitButton($lang->kanban->importAB, '', 'btn btn-default');?></div>
<?php $pager->show('right', 'pagerjs');?>
</div>
<?php endif;?>
</form>
<?php else:?>
<div class='table-empty-tip'><?php echo $lang->noData;?></div>
<?php endif;?>
</div>
<?php if($config->systemMode == 'classic'):?>
<style>.input-group {width: 45% !important}</style>
<?php else:?>
<style>#project_chosen {width: 45% !important}</style>
<?php endif;?>
<?php include '../../common/view/footer.lite.html.php';?>
+15 -12
View File
@@ -19,17 +19,16 @@
<div id='mainContent' class='main-content importModal'>
<div class='center-block'>
<div class='main-header'>
<h2><?php echo $lang->kanban->importPlan;?></h2>
<h2><?php echo $lang->kanban->importAB . $lang->kanban->importPlan;?></h2>
</div>
</div>
<div class='table-row p-10px'>
<div class='table-col w-150px text-center'><h4><?php echo $lang->kanban->selectedProduct;?></h4></div>
<div class='table-col'><?php echo html::select('product', $products, $selectedProductID, "onchange='reloadObjectList(this.value)' class='form-control chosen' data-drop_direction='down'");?></div>
</div>
<div class='table-row p-10px'>
<div class='table-col w-150px text-center'><h4><?php echo $lang->kanban->selectedLane;?></h4></div>
<div class='table-col'><?php echo html::select('lane', $lanePairs, '', "onchange='setTargetLane(this.value)' class='form-control chosen' data-drop_direction='down'");?></div>
<div class='input-group space'>
<span class='input-group-addon'><?php echo $lang->kanban->selectedProduct;?></span>
<?php echo html::select('product', $products, $selectedProductID, "onchange='reloadObjectList(this.value)' class='form-control chosen' data-drop_direction='down'");?>
<span class='input-group-addon'><?php echo $lang->kanban->selectedLane;?></span>
<?php echo html::select('lane', $lanePairs, '', "onchange='setTargetLane(this.value)' class='form-control chosen' data-drop_direction='down'");?>
</div>
<?php if($plans2Imported):?>
<form class='main-table' method='post' data-ride='table' target='hiddenwin' id='importPlanForm'>
<table class='table table-fixed' id='planList'>
<thead>
@@ -60,7 +59,9 @@
<?php printf('%03d', $plan->id);?>
</td>
<?php if(common::hasPriv('productplan', 'view')):?>
<td title='<?php echo $plan->title;?>'><?php common::printLink('productplan', 'view', "planID=$plan->id", $plan->title, '', "class='iframe'", true, true);?></td>
<td title='<?php echo $plan->title;?>'>
<a href='javascript:void(0);' onclick="locateView('productplan', <?php echo $plan->id;?>)"><?php echo $plan->title;?></a>
</td>
<?php else:?>
<td title='<?php echo $plan->title;?>'><?php echo $plan->title;?></td>
<?php endif;?>
@@ -75,13 +76,15 @@
<tr><?php echo html::hidden('targetLane', key($lanePairs));?></tr>
</tbody>
</table>
<?php if($plans2Imported):?>
<div class='table-footer'>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar show-always"><?php echo html::submitButton($lang->kanban->importPlan, '', 'btn btn-default');?></div>
<div class="table-actions btn-toolbar show-always"><?php echo html::submitButton($lang->kanban->importAB, '', 'btn btn-default');?></div>
<?php $pager->show('right', 'pagerjs');?>
</div>
<?php endif;?>
</form>
<?php else:?>
<div class='table-empty-tip'><?php echo $lang->noData;?></div>
<?php endif;?>
</div>
<style>#product_chosen {width: 45% !important}</style>
<?php include '../../common/view/footer.lite.html.php';?>
+19 -12
View File
@@ -19,17 +19,16 @@
<div id='mainContent' class='main-content importModal'>
<div class='center-block'>
<div class='main-header'>
<h2><?php echo $lang->kanban->importRelease;?></h2>
<h2><?php echo $lang->kanban->importAB . $lang->kanban->importRelease;?></h2>
</div>
</div>
<div class='table-row p-10px'>
<div class='table-col w-150px text-center'><h4><?php echo $lang->kanban->selectedProduct;?></h4></div>
<div class='table-col'><?php echo html::select('product', $products, $selectedProductID, "onchange='reloadObjectList(this.value)' class='form-control chosen' data-drop_direction='down'");?></div>
</div>
<div class='table-row p-10px'>
<div class='table-col w-150px text-center'><h4><?php echo $lang->kanban->selectedLane;?></h4></div>
<div class='table-col'><?php echo html::select('lane', $lanePairs, '', "onchange='setTargetLane(this.value)' class='form-control chosen' data-drop_direction='down'");?></div>
<div class='input-group space'>
<span class='input-group-addon'><?php echo $lang->kanban->selectedProduct;?></span>
<?php echo html::select('product', $products, $selectedProductID, "onchange='reloadObjectList(this.value)' class='form-control chosen' data-drop_direction='down'");?>
<span class='input-group-addon'><?php echo $lang->kanban->selectedLane;?></span>
<?php echo html::select('lane', $lanePairs, '', "onchange='setTargetLane(this.value)' class='form-control chosen' data-drop_direction='down'");?>
</div>
<?php if($releases2Imported):?>
<form class='main-table' method='post' data-ride='table' target='hiddenwin' id='importReleaseForm'>
<table class='table table-fixed' id='releaseList'>
<thead>
@@ -41,7 +40,9 @@
<?php echo $lang->idAB;?>
</th>
<th class='c-name'><?php echo $lang->release->name;?></th>
<?php if($config->systemMode == 'new'):?>
<th class='c-name'><?php echo $lang->release->project;?></th>
<?php endif;?>
<th class='c-name'><?php echo $lang->release->build;?></th>
<th class='c-date'><?php echo $lang->release->date;?></th>
</tr>
@@ -57,11 +58,15 @@
<?php printf('%03d', $release->id);?>
</td>
<?php if(common::hasPriv('release', 'view')):?>
<td title='<?php echo $release->name;?>'><?php common::printLink('release', 'view', "releaseID=$release->id", $release->name, '', "class='iframe'", true, true);?></td>
<td title='<?php echo $release->name;?>'>
<a href='javascript:void(0);' onclick="locateView('release', <?php echo $release->id;?>)"><?php echo $release->name;?></a>
</td>
<?php else:?>
<td title='<?php echo $release->name;?>'><?php echo $release->name;?></td>
<?php endif;?>
<?php if($config->systemMode == 'new'):?>
<td title='<?php echo $release->projectName;?>'><?php echo $release->projectName;?></td>
<?php endif;?>
<td title='<?php echo $release->buildName;?>'><?php echo $release->buildName;?></td>
<td title='<?php echo $release->date;?>'><?php echo $release->date;?></td>
</tr>
@@ -69,13 +74,15 @@
<tr><?php echo html::hidden('targetLane', key($lanePairs));?></tr>
</tbody>
</table>
<?php if($releases2Imported):?>
<div class='table-footer'>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar show-always"><?php echo html::submitButton($lang->kanban->importRelease, '', 'btn btn-default');?></div>
<div class="table-actions btn-toolbar show-always"><?php echo html::submitButton($lang->kanban->importAB, '', 'btn btn-default');?></div>
<?php $pager->show('right', 'pagerjs');?>
</div>
<?php endif;?>
</form>
<?php else:?>
<div class='table-empty-tip'><?php echo $lang->noData;?></div>
<?php endif;?>
</div>
<style>#product_chosen {width: 45% !important}</style>
<?php include '../../common/view/footer.lite.html.php';?>
+1 -1
View File
@@ -19,7 +19,7 @@
<form class='main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
<table class='table table-form'>
<tr>
<th class='w-110px'><?php echo $lang->kanban->doneFunction;?></th>
<th class='w-70px text-left'><?php echo $lang->kanban->doneFunction;?></th>
<td><?php echo nl2br(html::radio('performable', $lang->kanban->enableFinished, $kanban->performable));?></td>
</tr>
<tr>
+2 -1
View File
@@ -11,6 +11,7 @@
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php $width = $this->app->getClientLang() == 'en' ? 'w-120px' : 'w-80px';?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
@@ -19,7 +20,7 @@
<form class='main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
<table class='table table-form'>
<tr>
<th><?php echo $lang->kanban->columnWidth;?></th>
<th class='<?php echo $width;?>'><?php echo $lang->kanban->columnWidth;?></th>
<td><?php echo nl2br(html::radio('fluidBoard', $lang->kanbancolumn->fluidBoardList, $kanban->fluidBoard));?></td>
</tr>
<tr>
@@ -11,6 +11,9 @@
*/
?>
<?php include '../../common/view/header.html.php';?>
<style>
.table-form>tbody>tr>th {width: 90px;}
</style>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
+1
View File
@@ -38,6 +38,7 @@ js::set('colorListLang', $lang->kanbancard->colorList);
js::set('colorList', $this->config->kanban->cardColorList);
js::set('displayCards', $kanban->displayCards);
js::set('fluidBoard', $kanban->fluidBoard);
js::set('mode', $config->systemMode);
js::set('priv',
array(
+2
View File
@@ -94,6 +94,7 @@ $lang->misc->feature->downloadFile = 'Download introduction';
$lang->misc->feature->tutorialDesc = '<p>ZenTao 15.0 has new functions, and you know how to use it through the "<strong>Tutorial</strong>".</p><p>Click your [<span style="color: #0c60e1">Avatar-Theme-Young Blue</span>] to set it.</p>';
$lang->misc->feature->themeDesc = '<p>ZenTao 15.0+ a new "Youth Blue" theme, the pages are more beautiful and the experience is more friendly.</p><p>Click your [<span style="color: #0c60e1">Avatar-Theme-Young Blue</span>] to set it.</p>';
$lang->misc->releaseDate['16.3'] = '2022-01-26';
$lang->misc->releaseDate['16.2'] = '2022-01-17';
$lang->misc->releaseDate['16.1'] = '2022-01-11';
$lang->misc->releaseDate['16.0'] = '2021-12-24';
@@ -166,6 +167,7 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
$lang->misc->feature->all['16.3'][] = array('title' => 'Kanban adds related plan/release/version/iteration functions, and the detail experience is optimized, fix bugs.', 'desc' => '');
$lang->misc->feature->all['16.2'][] = array('title' => 'Add kanban model project, fix bugs.', 'desc' => '');
$lang->misc->feature->all['16.1'][] = array('title' => 'Plan to add status management and Kanban view, upgrade process optimization, fix bugs.', 'desc' => '');
$lang->misc->feature->all['16.0'][] = array('title' => 'New general board, improve branch management, fix bugs.', 'desc' => '');
+2
View File
@@ -94,6 +94,7 @@ $lang->misc->feature->downloadFile = '下载新版本功能介绍文档';
$lang->misc->feature->tutorialDesc = "<p>禅道15系列新增了多项功能,您可以通过“<strong>新手引导教程</strong>”快速了解禅道的基本使用方法。</p><p>通过鼠标经过 [<span style='color: #0c60e1'>头像-新手引导</span>],点击新手引导,即可进入新手引导教程。</p>";
$lang->misc->feature->themeDesc = "<p>禅道15系列上线了全新的“青春蓝”主题,页面呈现更加美观,体验更加友好。</p><p>通过鼠标经过 [<span style='color: #0c60e1'>头像-主题-青春蓝</span>],点击青春蓝,即可设置成功。</p>";
$lang->misc->releaseDate['16.3'] = '2022-01-26';
$lang->misc->releaseDate['16.2'] = '2022-01-17';
$lang->misc->releaseDate['16.1'] = '2022-01-11';
$lang->misc->releaseDate['16.0'] = '2021-12-24';
@@ -166,6 +167,7 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
$lang->misc->feature->all['16.3'][] = array('title' => '看板增加关联计划/发布/版本/迭代功能,细节体验优化。', 'desc' => '');
$lang->misc->feature->all['16.2'][] = array('title' => '新增专业研发看板,可以创建看板模型项目,修复Bug。', 'desc' => '');
$lang->misc->feature->all['16.1'][] = array('title' => '计划增加状态管理和看板视图,升级流程优化,修复Bug。', 'desc' => '');
$lang->misc->feature->all['16.0'][] = array('title' => '新增通用看板,完善分支管理,修复Bug。', 'desc' => '');
+10 -2
View File
@@ -247,6 +247,13 @@ class mr extends control
$sourceBranch = $this->gitlab->apiGetSingleBranch($MR->gitlabID, $MR->sourceProject, $MR->sourceBranch);
$targetBranch = $this->gitlab->apiGetSingleBranch($MR->gitlabID, $MR->targetProject, $MR->targetBranch);
$projectOwner = true;
if(isset($MR->gitlabID) and !$this->app->user->admin)
{
$openID = $this->gitlab->getUserIDByZentaoAccount($MR->gitlabID, $this->app->user->account);
if(!$projectOwner and isset($sourceProject->owner->id) and $sourceProject->owner->id == $openID) $projectOwner = true;
}
$this->view->sourceProjectName = $sourceProject->name_with_namespace;
$this->view->targetProjectName = $targetProject->name_with_namespace;
$this->view->sourceProjectURL = isset($sourceBranch->web_url) ? $sourceBranch->web_url : '';
@@ -260,8 +267,9 @@ class mr extends control
$this->app->loadLang('productplan');
$product = $this->mr->getMRProduct($MR);
$this->view->compile = $this->loadModel('compile')->getById($MR->compileID);
$this->view->compileJob = $MR->jobID ? $this->job->getById($MR->jobID) : false;
$this->view->compile = $this->loadModel('compile')->getById($MR->compileID);
$this->view->compileJob = $MR->jobID ? $this->job->getById($MR->jobID) : false;
$this->view->projectOwner = $projectOwner;
$this->view->title = $this->lang->mr->view;
$this->view->MR = $MR;
+2 -2
View File
@@ -57,7 +57,7 @@ class mrModel extends model
foreach($filterProjects as $gitlabID => $projects)
{
$projectIDList = array_keys($projects);
if(!empty($projectIDList)) $filterProjectSql .= "(gitlabID = {$gitlabID} and sourceProject ".helper::dbIN($projectIDList).") or ";
if(!empty($projectIDList)) $filterProjectSql .= "(gitlabID = {$gitlabID} and sourceProject " . helper::dbIN($projectIDList) . ") or ";
}
if($filterProjectSql) $filterProjectSql = '(' . substr($filterProjectSql, 0, -3) . ')'; // Remove last or.
@@ -164,7 +164,7 @@ class mrModel extends model
if(!empty($pipeline->queue))
{
$compile = $this->loadModel('compile')->getByQueue($pipeline->queue);
$MR->compileID = $compile->id;
$MR->compileID = $compile->id;
$MR->compileStatus = $compile->status;
}
}
+4 -2
View File
@@ -64,11 +64,13 @@
</thead>
<tbody>
<?php foreach($MRList as $MR):?>
<?php $sourceProject = isset($projects[$MR->gitlabID][$MR->sourceProject]) ? $projects[$MR->gitlabID][$MR->sourceProject]->name_with_namespace . ':' . $MR->sourceBranch : $MR->sourceProject . ':' . $MR->sourceBranch; ?>
<?php $targetProject = isset($projects[$MR->gitlabID][$MR->targetProject]) ? $projects[$MR->gitlabID][$MR->targetProject]->name_with_namespace . ':' . $MR->targetBranch : $MR->targetProject . ':' . $MR->targetBranch; ?>
<tr>
<td class='text'><?php echo $MR->id;?></td>
<td class='text'><?php echo html::a(inlink('view', "mr={$MR->id}"), $MR->title);?></td>
<td class='text' title='<?php echo $projects[$MR->gitlabID][$MR->sourceProject]->name_with_namespace . ':' . $MR->sourceBranch;?>'><?php echo $projects[$MR->gitlabID][$MR->sourceProject]->name_with_namespace . ':' . $MR->sourceBranch;?></td>
<td class='text' title='<?php echo $projects[$MR->gitlabID][$MR->targetProject]->name_with_namespace . ':' . $MR->targetBranch;?>'><?php echo $projects[$MR->gitlabID][$MR->targetProject]->name_with_namespace . ':' . $MR->targetBranch;?></td>
<td class='text' title='<?php echo $sourceProject;?>'><?php echo $sourceProject;?></td>
<td class='text' title='<?php echo $targetProject;?>'><?php echo $targetProject;?></td>
<?php if($MR->status == 'closed'):?>
<td class='text'><?php echo zget($lang->mr->statusList, $MR->status);?></td>
<?php else:?>
+3 -3
View File
@@ -119,7 +119,7 @@
<?php common::printIcon('mr', 'edit', "mr=$MR->id", $MR, 'button', 'edit');?>
<?php endif;?>
<?php if($MR->synced and $rawMR->state == 'closed') common::printIcon('mr', 'reopen', "mr=$MR->id", $MR, 'button', 'restart', 'hiddenwin', 'mergeButton'); ?>
<?php common::printIcon('mr', 'delete', "mr=$MR->id", $MR, 'button', 'trash', 'hiddenwin');?>
<?php if($projectOwner) common::printIcon('mr', 'delete', "mr=$MR->id", $MR, 'button', 'trash', 'hiddenwin');?>
</div>
</div>
</div>
@@ -139,9 +139,9 @@
</tr>
<tr>
<th><?php echo $lang->compile->atTime;?></th>
<td><?php echo $compileJob ? $compileJob->lastExec : $lang->mr->compileUnexecuted;?></td>
<td><?php echo $compile->createdDate;?></td>
</tr>
<?php if($compileJob):?>
<?php if($compileJob and !empty($compileJob->id)):?>
<tr>
<th><?php echo $lang->compile->result;?></th>
<td>
+3 -1
View File
@@ -480,10 +480,11 @@ class projectModel extends model
* @param status $status all|wait|doing|suspended|closed|noclosed
* @param bool $isQueryAll
* @param string $orderBy
* @param string $excludedModel
* @access public
* @return object
*/
public function getPairsByProgram($programID = '', $status = 'all', $isQueryAll = false, $orderBy = 'order_asc')
public function getPairsByProgram($programID = '', $status = 'all', $isQueryAll = false, $orderBy = 'order_asc', $excludedModel = '')
{
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getProjectPairs();
return $this->dao->select('id, name')->from(TABLE_PROJECT)
@@ -491,6 +492,7 @@ class projectModel extends model
->andWhere('deleted')->eq(0)
->beginIF($programID !== '')->andWhere('parent')->eq($programID)->fi()
->beginIF($status != 'all' && $status != 'noclosed')->andWhere('status')->eq($status)->fi()
->beginIF($excludedModel)->andWhere('model')->ne($excludedModel)->fi()
->beginIF($status == 'noclosed')->andWhere('status')->ne('closed')->fi()
->beginIF(!$this->app->user->admin and !$isQueryAll)->andWhere('id')->in($this->app->user->view->projects)->fi()
->orderBy($orderBy)
+2 -2
View File
@@ -58,10 +58,10 @@ class releaseModel extends model
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
->leftJoin(TABLE_BUILD)->alias('t3')->on('t1.build = t3.id')
->leftJoin(TABLE_PROJECT)->alias('t4')->on('t1.project = t4.id')
->where('t1.product')->eq((int)$productID)
->where('t1.deleted')->eq(0)
->beginIF($productID)->andWhere('t1.product')->eq((int)$productID)->fi()
->beginIF($branch !== 'all')->andWhere('t1.branch')->eq($branch)->fi()
->beginIF($type != 'all')->andWhere('t1.status')->eq($type)->fi()
->andWhere('t1.deleted')->eq(0)
->orderBy($orderBy)
->page($pager)
->fetchAll();
+8 -8
View File
@@ -44,14 +44,14 @@ $lang->sonarqube->projectKey = 'Project Key';
$lang->sonarqube->projectName = 'Project Name';
$lang->sonarqube->projectlastAnalysis = 'Last analysis time';
$lang->sonarqube->reprot = new stdclass();
$lang->sonarqube->reprot->bugs = 'Bugs';
$lang->sonarqube->reprot->vulnerabilities = 'Vulnerabilities';
$lang->sonarqube->reprot->security_hotspots_reviewed = 'Hotspots Reviewed';
$lang->sonarqube->reprot->code_smells = 'Code Smells';
$lang->sonarqube->reprot->coverage = 'Coverage';
$lang->sonarqube->reprot->duplicated_lines_density = 'Duplications';
$lang->sonarqube->reprot->ncloc = 'Lines';
$lang->sonarqube->report = new stdclass();
$lang->sonarqube->report->bugs = 'Bugs';
$lang->sonarqube->report->vulnerabilities = 'Vulnerabilities';
$lang->sonarqube->report->security_hotspots_reviewed = 'Hotspots Reviewed';
$lang->sonarqube->report->code_smells = 'Code Smells';
$lang->sonarqube->report->coverage = 'Coverage';
$lang->sonarqube->report->duplicated_lines_density = 'Duplications';
$lang->sonarqube->report->ncloc = 'Lines';
$lang->sonarqube->qualitygateList = array();
$lang->sonarqube->qualitygateList['OK'] = 'Passed';
-1
View File
@@ -26,7 +26,6 @@ $lang->sonarqube->private = 'MD5验证';
$lang->sonarqube->createServer = '添加SonarQube服务器';
$lang->sonarqube->editServer = '修改SonarQube服务器';
$lang->sonarqube->desc = '描述';
$lang->sonarqube->createSuccess = "创建成功";
$lang->sonarqube->placeholder = new stdclass;
+1 -1
View File
@@ -1,7 +1,7 @@
$(document).ready(function()
{
removeDitto();//Remove 'ditto' in first row.
if($('#batchCreateForm table thead tr th.c-title').width() < 150) $('#batchCreateForm table thead tr th.c-title').width('150');
if($('#batchCreateForm table thead tr th.c-title').width() < 170) $('#batchCreateForm table thead tr th.c-title').width('170');
$(document).keydown(function(event)
{
+7 -1
View File
@@ -1668,7 +1668,13 @@ class treeModel extends model
{
$this->dao->update(TABLE_MODULE)->set('root')->eq($module->root)->where('id')->in($childs)->exec();
$this->dao->update(TABLE_MODULE)->set('branch')->eq($module->branch)->where('id')->in($childs)->exec();
if($self->type == 'doc') $this->dao->update(TABLE_DOC)->set('`lib`')->eq($module->root)->where('module')->eq($moduleID)->exec();
if($self->type == 'doc')
{
$this->dao->update(TABLE_DOC)->set('`lib`')->eq($module->root)
->where('module')->eq($moduleID)
->orWhere('module')->in($childs)
->exec();
}
}
$this->fixModulePath(isset($module->root) ? $module->root : $self->root, $self->type);
if(isset($module->root) and $module->root != $self->root) $this->changeRoot($moduleID, $self->root, $module->root, $self->type);
+29 -27
View File
@@ -158,6 +158,7 @@ class tutorialModel extends model
$project->whitelist = '';
$project->budget = 0;
$project->displayCards = 0;
$project->fluidBoard = 0;
$project->deleted = '0';
return $project;
@@ -268,33 +269,34 @@ class tutorialModel extends model
public function getExecution()
{
$execution = new stdclass();
$execution->id = 3;
$execution->project = 2;
$execution->type = 'sprint';
$execution->name = 'Test execution';
$execution->code = 'test';
$execution->lifetime = '';
$execution->begin = date('Y-m-d', strtotime('-7 days'));
$execution->end = date('Y-m-d', strtotime('+7 days'));
$execution->days = 10;
$execution->status = 'wait';
$execution->pri = '1';
$execution->desc = '';
$execution->goal = '';
$execution->acl = 'open';
$execution->parent = 2;
$execution->path = ',2,3,';
$execution->grade = 1;
$execution->PM = $this->app->user->account;
$execution->PO = $this->app->user->account;
$execution->QD = $this->app->user->account;
$execution->RD = $this->app->user->account;
$execution->deleted = '0';
$execution->totalConsumed = 0;
$execution->totalLeft = 0;
$execution->totalHours = 0;
$execution->totalEstimate = 0;
$execution->displayCards = 0;
$execution->id = 3;
$execution->project = 2;
$execution->type = 'sprint';
$execution->name = 'Test execution';
$execution->code = 'test';
$execution->lifetime = '';
$execution->begin = date('Y-m-d', strtotime('-7 days'));
$execution->end = date('Y-m-d', strtotime('+7 days'));
$execution->days = 10;
$execution->status = 'wait';
$execution->pri = '1';
$execution->desc = '';
$execution->goal = '';
$execution->acl = 'open';
$execution->parent = 2;
$execution->path = ',2,3,';
$execution->grade = 1;
$execution->PM = $this->app->user->account;
$execution->PO = $this->app->user->account;
$execution->QD = $this->app->user->account;
$execution->RD = $this->app->user->account;
$execution->deleted = '0';
$execution->totalConsumed = 0;
$execution->totalLeft = 0;
$execution->totalHours = 0;
$execution->totalEstimate = 0;
$execution->displayCards = 0;
$execution->fluidBoard = 0;
return $execution;
}
+1
View File
@@ -150,3 +150,4 @@ $lang->upgrade->fromVersions['15_7_1'] = '15.7.1';
$lang->upgrade->fromVersions['16_0_beta1'] = '16.0.beta1';
$lang->upgrade->fromVersions['16_0'] = '16.0';
$lang->upgrade->fromVersions['16_1'] = '16.1';
$lang->upgrade->fromVersions['16_2'] = '16.2';
+26 -3
View File
@@ -753,7 +753,8 @@ class upgradeModel extends model
case '16_2':
$this->saveLogs('Execute 16_2');
$this->execSQL($this->getUpgradeFile('16.2'));
$this->addSpaceTeam();
$this->updateSpaceTeam();
$this->updateDocField();
$this->appendExec('16_2');
}
@@ -964,6 +965,7 @@ class upgradeModel extends model
case '16_0_beta1': $confirmContent .= file_get_contents($this->getUpgradeFile('16.0.beta1'));
case '16_0': $confirmContent .= file_get_contents($this->getUpgradeFile('16.0'));
case '16_1': $confirmContent .= file_get_contents($this->getUpgradeFile('16.1'));
case '16_2': $confirmContent .= file_get_contents($this->getUpgradeFile('16.2'));
}
return str_replace('zt_', $this->config->db->prefix, $confirmContent);
}
@@ -5458,8 +5460,8 @@ class upgradeModel extends model
*/
public function updateSpaceTeam()
{
$kanbanUsers = $this->dao->select("space, CONCAT(owner, ',', team) as users") ->from(TABLE_KANBAN)->fetchAll('space');
$spaceUsers = $this->dao->select("id, CONCAT(owner, ',', team) as users")->from(TABLE_KANBANSPACE)->fetchAll('id');
$kanbanUsers = $this->dao->select("space, CONCAT(owner, ',', team, ',', whitelist) as users") ->from(TABLE_KANBAN)->fetchAll('space');
$spaceUsers = $this->dao->select("id, CONCAT(owner, ',', team, ',', whitelist) as users")->from(TABLE_KANBANSPACE)->fetchAll('id');
foreach($kanbanUsers as $spaceID => $kanban)
{
@@ -5473,6 +5475,8 @@ class upgradeModel extends model
$this->dao->update(TABLE_KANBANSPACE)->set('`team`')->eq($team)->where('id')->eq($spaceID)->exec();
}
$this->dao->update(TABLE_KANBANSPACE)->set('`whitelist`')->eq('')->exec();
$this->dao->update(TABLE_KANBAN)->set('`whitelist`')->eq('')->exec();
}
/**
@@ -5580,4 +5584,23 @@ class upgradeModel extends model
return true;
}
/**
* Document library for updating documents.
*
* @access public
* @return bool
*/
public function updateDocField()
{
$hasModuleDocs = $this->dao->select('*')->from(TABLE_DOC)->where('module')->ne(0)->fetchAll('id');
$docModules = $this->dao->select('*')->from(TABLE_MODULE)->where('type')->eq('doc')->fetchAll('id');
foreach($hasModuleDocs as $doc)
{
$libID = isset($docModules[$doc->module]->root) ? $docModules[$doc->module]->root : 0;
if(!$libID or $libID == $doc->lib) continue;
$this->dao->update(TABLE_DOC)->set('lib')->eq($libID)->where('id')->eq($doc->id)->exec();
}
return true;
}
}
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=测试productModel->getLatestProject();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->product = $tester->loadModel('product');
}
public function testGetLatestProject($productID)
{
$project = $this->product->getLatestProject($productID);
if($project == false) return '没有数据';
return $project;
}
}
$z = new Tester('admin');
r($z->testGetLatestProject(25)) && p('id') && e('315'); // 测试产品25关联的最后一个未关闭的项目,按begin字段排序
r($z->testGetLatestProject(38)) && p('id') && e('688'); // 测试产品38关联的最后一个未关闭的项目,按begin字段排序
r($z->testGetLatestProject(101)) && p() && e('没有数据'); // 传入不存在的产品
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env php
<?php include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=productModel->getProjectListByProduct();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->product = $tester->loadModel('product');
}
public function getAllProjectsByProduct($productID)
{
$projects = $this->product->getProjectListByProduct($productID, 'all');
if($projects == array()) return '没有数据';
return $projects;
}
public function getProjectsByStatus($productID, $status)
{
$projects = $this->product->getProjectListByProduct($productID, $browseType);
if($projects == array()) return '没有数据';
return $projects;
}
}
$tester = new Tester('admin');
r($tester->getAllProjectsByProduct(1)) && p('21:name') && e('项目11'); // 返回产品1关联的项目11名字
r($tester->getAllProjectsByProduct(1)) && p('11:name') && e('项目1'); // 返回产品1关联的项目21名字
r($tester->getAllProjectsByProduct(101)) && p() && e('没有数据'); // 传入不存在的产品
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
/**
title=productModel->getProjectPairsByProduct();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->product = $tester->loadModel('product');
}
public function getProjectPairsByProductID($productID)
{
$projects = $this->product->getProjectPairsByProduct($productID, 0, 0);
if($projects == array()) return '没有数据';
return $projects;
}
public function getAppendProject($projectID)
{
$project = $this->product->getProjectPairsByProduct(10086, 0, $projectID);
if($project == array()) return '没有数据';
return $project;
}
}
$tester = new Tester('admin');
r($tester->getProjectPairsByProductID(1)) && p('11') && e('项目1'); // 返回产品1关联的项目11名字
r($tester->getProjectPairsByProductID(1)) && p('21') && e('项目11'); // 返回产品1关联的项目21名字
r($tester->getProjectPairsByProductID(101)) && p() && e('没有数据'); // 传入不存在的产品
r($tester->getAppendProject(15)) && p('15') && e('项目5'); // 返回id为15的项目名
r($tester->getAppendProject(701)) && p() && e('没有数据'); // 传入不存在的项目id
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env php
<?php
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
su('admin');
/**
title=测试productModel->isClickable();
cid=1
pid=1
*/
class Tester
{
public function __construct($user)
{
global $tester;
su($user);
$this->product = $tester->loadModel('product');
}
public function testIsClickable($productID, $status)
{
$product = $this->product->getById($productID);
$isClick = $this->product->isClickable($product, $status);
return $isClick == false ? 'false' : 'true';
}
}
$adminTester = new Tester('admin');
r($adminTester->testIsClickable(2, 'close')) && p() && e('true'); // status为normal,action为close
r($adminTester->testIsClickable(75, 'close')) && p() && e('false'); // status为close,action为close
r($adminTester->testIsClickable(2, 'start')) && p() && e('true'); // status为normal,action为start
r($adminTester->testIsClickable(75, 'start')) && p() && e('true'); // status为close,action为start
File diff suppressed because one or more lines are too long
@@ -30,15 +30,19 @@ $(document).on('showapp', function(e, app)
<?php
$this->loadModel('im');
$xuanConfig = new stdclass();
$token = $this->im->userGetAuthToken($this->app->user->id, 'zentaoweb');
$clientUrl = isset($this->config->webClientUrl) ? $this->config->webClientUrl : 'data/xuanxuan/web/';
if(isset($this->config->xuanxuan->turnon) && $this->config->xuanxuan->turnon)
{
$xuanConfig = new stdclass();
$token = $this->im->userGetAuthToken($this->app->user->id, 'zentaoweb');
$clientUrl = isset($this->config->webClientUrl) ? $this->config->webClientUrl : 'data/xuanxuan/web/';
$backendUrl = $this->im->getServer('zentao');
$xuanConfig->clientUrl = $clientUrl;
$xuanConfig->server = $this->im->getServer('zentao');
$xuanConfig->account = $this->app->user->account;
$xuanConfig->authKey = $token->token;
$xuanConfig->debug = $this->config->debug;
$xuanConfig->clientUrl = $clientUrl;
$xuanConfig->server = parse_url($backendUrl, PHP_URL_HOST);
$xuanConfig->account = $this->app->user->account;
$xuanConfig->authKey = $token->token;
$xuanConfig->debug = $this->config->debug;
}
?>
<?php if(isset($xuanConfig)): ?>
<style>