Merge branch 'zenops_46_tanghucheng' into zenops_46
This commit is contained in:
@@ -108,6 +108,7 @@ zentaoxx:
|
||||
sed -i "s/\$$super = \$$this->dao->select('admin')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch('admin');/\$$account = \$$this->dao->select('account')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch('account');\n\$$admins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\n\$$adminArray = explode(',', \$$admins);\n\$$super = in_array(\$$account, \$$adminArray) ? 'super' : '';/g" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i "/foreach(\$$users as \$$user)/i \$$admins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\$$adminArray = explode(',', \$$admins);" zentaoxx/extension/xuan/im/model/user.php
|
||||
sed -i "/if(\!isset(\$$user->signed)) \$$user->signed = 0;/a \$$user->admin = in_array(\$$user->account, \$$adminArray) ? 'super' : '';" zentaoxx/extension/xuan/im/model/user.php
|
||||
sed -i "/updateUser->ping/d" zentaoxx/extension/xuan/im/model/user.php
|
||||
sed -i "s/\$$user = \$$this->user->login(\$$account, \$$user->password);/\$$user = \$$this->user->login(\$$user);\n\$$url .= \$$this->config->requestType == 'GET' ? '\&' : '?';\n\$$url .= \"{\$$this->config->sessionVar}={\$$this->app->sessionID}\";\n/" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i "s/\$$file->fullURL/\$$file->webPath/" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i 's/XXBVERSION/$(XVERSION)/g' zentaoxx/config/ext/_0_xuanxuan.php
|
||||
|
||||
@@ -87,7 +87,7 @@ class taskEntry extends entry
|
||||
$task->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
|
||||
$task->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
|
||||
|
||||
$execution = $this->loadModel('project')->getByID($task->execution, 'execution');
|
||||
$execution = $this->loadModel('project')->getByID($task->execution, 'execution,sprint');
|
||||
$task->executionStatus = $execution->status;
|
||||
|
||||
return $this->send(200, $this->format($task, 'deadline:date,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,realStarted:time,finishedBy:user,finishedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,lastEditedBy:user,lastEditedDate:time,deleted:bool,mailto:userList'));
|
||||
|
||||
@@ -20,7 +20,32 @@ class tasksEntry extends entry
|
||||
*/
|
||||
public function get($executionID = 0)
|
||||
{
|
||||
if(!$executionID)
|
||||
/* Get tasks by search, search arguments available: pri, assignedTo, status, id, name. Pager arguments will be utilized as well. */
|
||||
if($this->param('search', 0) == 1) // TODO: document this api.
|
||||
{
|
||||
$this->loadModel('task');
|
||||
$searchParams = array();
|
||||
foreach(array('pri' => 'priList', 'assignedTo' => 'assignedToList', 'status' => 'statusList', 'id' => 'idList', 'name' => 'taskName') as $field => $condName)
|
||||
{
|
||||
if($this->param($field, false))
|
||||
{
|
||||
$searchParams[$condName] = $this->param($field);
|
||||
continue;
|
||||
}
|
||||
if($this->param($condName, false)) $searchParams[$condName] = $this->param($condName);
|
||||
}
|
||||
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = pager::init($this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
|
||||
$tasks = $this->task->getListByConds((object)$searchParams, $this->param('order', 'id_desc'), $pager);
|
||||
|
||||
$data = new stdclass();
|
||||
$data->status = 'success';
|
||||
$data->data = new stdclass();
|
||||
$data->data->tasks = array_values($tasks);
|
||||
$data->data->pager = (object)$pager;
|
||||
}
|
||||
elseif(!$executionID)
|
||||
{
|
||||
/* Get my tasks defaultly. */
|
||||
$control = $this->loadController('my', 'task');
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
|
||||
if(!function_exists('getWebRoot')){function getWebRoot(){}}
|
||||
|
||||
/* 基本设置。Basic settings. */
|
||||
$config->version = '18.0.beta1'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
|
||||
$config->version = '18.0.beta2'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
|
||||
$config->liteVersion = '1.2'; // 迅捷版版本。 The version of Lite.
|
||||
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
|
||||
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
$filter = new stdclass();
|
||||
$filter->rules = new stdclass();
|
||||
$filter->rules->md5 = '/^[a-z0-9]{32}$/';
|
||||
$filter->rules->base64 = '/^[a-zA-Z0-9\+\/\=]+$/';
|
||||
$filter->rules->base64 = '/^[a-zA-Z0-9\+\/\=\.]+$/';
|
||||
$filter->rules->checked = '/^[0-9,\-]+$/';
|
||||
$filter->rules->idList = '/^[0-9\|]+$/';
|
||||
$filter->rules->lang = '/^[a-zA-Z_\-]+$/';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -140,3 +140,9 @@ ALTER TABLE `zt_repofiles` ADD `oldPath` varchar(255) DEFAULT '' AFTER `path`;
|
||||
|
||||
ALTER TABLE `zt_testresult` ADD `ZTFResult` text NOT NULL;
|
||||
ALTER TABLE `zt_testresult` ADD `node` int(8) unsigned NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `zt_story` ADD COLUMN `twins` varchar(255) NOT NULL AFTER `linkRequirements`;
|
||||
ALTER TABLE `zt_productplan` MODIFY COLUMN `branch` varchar(255) NOT NULL DEFAULT '0' AFTER `product`;
|
||||
ALTER TABLE `zt_effort` ADD `extra` text COLLATE 'utf8_general_ci' NOT NULL AFTER `end`;
|
||||
ALTER TABLE `zt_build` MODIFY COLUMN `branch` varchar(255) NOT NULL DEFAULT '0' AFTER `product`;
|
||||
ALTER TABLE `zt_feedback` ADD COLUMN `activatedBy` varchar(30) NOT NULL AFTER `assignedDate`;
|
||||
ALTER TABLE `zt_feedback` ADD COLUMN `activatedDate` datetime NOT NULL AFTER `activatedBy`;
|
||||
|
||||
+9
-3
@@ -321,7 +321,7 @@ CREATE TABLE IF NOT EXISTS `zt_build` (
|
||||
`id` mediumint(8) unsigned NOT NULL auto_increment,
|
||||
`project` mediumint(8) unsigned NOT NULL,
|
||||
`product` mediumint(8) unsigned NOT NULL default '0',
|
||||
`branch` mediumint(8) unsigned NOT NULL default '0',
|
||||
`branch` varchar(255) NOT NULL DEFAULT '0',
|
||||
`execution` mediumint(8) unsigned NOT NULL default '0',
|
||||
`builds` varchar(255) NOT NULL,
|
||||
`name` char(150) NOT NULL,
|
||||
@@ -1129,7 +1129,7 @@ CREATE TABLE IF NOT EXISTS `zt_product` (
|
||||
CREATE TABLE IF NOT EXISTS `zt_productplan` (
|
||||
`id` mediumint(8) unsigned NOT NULL auto_increment,
|
||||
`product` mediumint(8) unsigned NOT NULL,
|
||||
`branch` mediumint(8) unsigned NOT NULL,
|
||||
`branch` varchar(255) NOT NULL DEFAULT '0',
|
||||
`parent` mediumint(9) NOT NULL DEFAULT '0',
|
||||
`title` varchar(90) NOT NULL,
|
||||
`status` enum('wait','doing','done','closed') NOT NULL default 'wait',
|
||||
@@ -1480,6 +1480,7 @@ CREATE TABLE IF NOT EXISTS `zt_story` (
|
||||
`childStories` varchar(255) NOT NULL,
|
||||
`linkStories` varchar(255) NOT NULL,
|
||||
`linkRequirements` varchar(255) NOT NULL,
|
||||
`twins` varchar(255) NOT NULL,
|
||||
`duplicateStory` mediumint(8) unsigned NOT NULL,
|
||||
`version` smallint(6) NOT NULL default '1',
|
||||
`feedbackBy` varchar(100) NOT NULL,
|
||||
@@ -6401,7 +6402,7 @@ CREATE TABLE IF NOT EXISTS `zt_im_message` (
|
||||
`user` varchar(30) NOT NULL DEFAULT '',
|
||||
`date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`index` int(11) unsigned NOT NULL DEFAULT 0,
|
||||
`type` enum('normal', 'broadcast', 'notify', 'bulletin') NOT NULL DEFAULT 'normal',
|
||||
`type` enum('normal','broadcast','notify','bulletin','botcommand') NOT NULL DEFAULT 'normal',
|
||||
`content` text NOT NULL DEFAULT '',
|
||||
`contentType` enum('text', 'plain', 'emotion', 'image', 'file', 'object', 'code') NOT NULL DEFAULT 'text',
|
||||
`data` text NOT NULL DEFAULT '',
|
||||
@@ -6555,6 +6556,7 @@ ALTER TABLE `zt_effort` CHANGE `begin` `begin` smallint(4) unsigned zerofill NOT
|
||||
ALTER TABLE `zt_effort` CHANGE `end` `end` smallint(4) unsigned zerofill NOT NULL AFTER `begin`;
|
||||
ALTER TABLE `zt_effort` ADD `deleted` enum('0','1') NOT NULL DEFAULT '0' AFTER `end`;
|
||||
ALTER TABLE `zt_effort` ADD `order` tinyint unsigned NOT NULL DEFAULT '0' AFTER `end`;
|
||||
ALTER TABLE `zt_effort` ADD `extra` text COLLATE 'utf8_general_ci' NULL AFTER `end`;
|
||||
ALTER TABLE `zt_effort` ADD INDEX `execution` (`execution`);
|
||||
ALTER TABLE `zt_effort` ADD INDEX `objectID` (`objectID`);
|
||||
ALTER TABLE `zt_effort` ADD INDEX `date` (`date`);
|
||||
@@ -7129,6 +7131,8 @@ CREATE TABLE IF NOT EXISTS `zt_feedback` (
|
||||
`editedDate` datetime NOT NULL,
|
||||
`assignedTo` varchar(255) NOT NULL,
|
||||
`assignedDate` datetime NOT NULL,
|
||||
`activatedBy` varchar(30) NOT NULL,
|
||||
`activatedDate` datetime NOT NULL,
|
||||
`feedbackBy` varchar(100) NOT NULL,
|
||||
`repeatFeedback` mediumint(8) NOT NULL DEFAULT 0,
|
||||
`mailto` varchar(255) NOT NULL,
|
||||
@@ -7179,6 +7183,7 @@ CREATE TABLE IF NOT EXISTS `zt_ticket` (
|
||||
key `product` (`product`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- DROP TABLE IF EXISTS `zt_ticketsource`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_ticketsource` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`ticketId` mediumint(8) unsigned NOT NULL,
|
||||
@@ -7190,6 +7195,7 @@ CREATE TABLE IF NOT EXISTS `zt_ticketsource` (
|
||||
key `ticketId` (`ticketId`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- DROP TABLE IF EXISTS `zt_ticketrelation`;
|
||||
CREATE TABLE IF NOT EXISTS `zt_ticketrelation` (
|
||||
`id` mediumint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`ticketId` mediumint unsigned NOT NULL,
|
||||
|
||||
+199
@@ -1,3 +1,202 @@
|
||||
2022-12-14 18.0.beta2
|
||||
完成的需求
|
||||
开源版:
|
||||
41067 初始化执行节点时可以安装单个服务
|
||||
41056 孪生需求编辑的时候一直显示解除的icon
|
||||
41054 需求批量关闭页面增加孪生需求标签
|
||||
41046 孪生需求关闭时,支持解除孪生关系
|
||||
41045 优化按计划导入时提示语
|
||||
41044 孪生需求不支持细分
|
||||
41043 变更页面支持解除孪生关系
|
||||
41042 孪生需求变更页面中同步孪生需求区块调整至影响范围
|
||||
41021 计划关联的bug列表字段顺序调整
|
||||
41020 计划关联的研发需求列表字段顺序调整
|
||||
41018 发布关联的遗留bug列表字段顺序调整
|
||||
41016 版本关联的解决的bug列表字段顺序调整
|
||||
41015 发布中关联的解决的bug列表字段顺序调整
|
||||
41014 版本中关联的研发需求列表字段顺序调整
|
||||
41013 发布中关联的研发需求列表字段顺序调整
|
||||
41011 产品发布列表部分字段列宽调整
|
||||
41008 优化执行节点的远程管理页面
|
||||
40984 需求变更时的确认按钮改为ok样式
|
||||
40887 创建任务页优化多人任务设置
|
||||
40874 未开始的任务支持切换单人或多人任务
|
||||
40862 父计划支持编辑分支
|
||||
40837 集成版本始终保留自身关联的需求和bug所对应的分支
|
||||
40717 测试单可以关联版本对应分支的用例
|
||||
40713 发布归属多个分支时,路线图中在不同分支重复展示
|
||||
40712 计划列表的”平台/分支“搜索条件关于默认为”包含“。
|
||||
40711 项目的需求列表中按计划导入需求时,修改提示语
|
||||
40710 发布的列表页中,版本后面展示所属分支
|
||||
40709 发布的详情页中,所属分支展示关联版本的分支的合集
|
||||
40700 执行中创建版本时,所属分支支持多选
|
||||
40691 执行的需求列表中按计划导入需求时,修改提示语
|
||||
40649 优化多分支产品创建计划的逻辑
|
||||
40648 版本列表中增加所属分支字段
|
||||
40646 项目的发布去掉分支字段
|
||||
40644 多分支产品修改计划的分支时,同步移除对应分支的bug
|
||||
40615 优化创建执行节点的交互
|
||||
40524 批量执行自动化用例
|
||||
40358 在宿主机列表添加初始化的引导
|
||||
40352 优化初始化宿主机的交互
|
||||
40350 优化创建宿主机的交互
|
||||
40132 需求详情页中用户需求部分交互优化
|
||||
39893 编辑执行节点
|
||||
39773 主干需求的计划只能选择一个
|
||||
39772 详情页面和编辑页面的孪生需求样式优化
|
||||
39766 项目页面优化分支关联样式
|
||||
39763 执行页面优化分支关联样式
|
||||
39699 多分支产品1.5级菜单选所有时,隐藏批量修改模块按钮
|
||||
39657 浏览创建镜像进度
|
||||
39656 取消下载镜像
|
||||
39653 优化下载镜像的交互
|
||||
39636 浏览镜像仓库
|
||||
39602 孪生需求进行提交评审、撤销评审、撤销变更时,其余孪生需求均同步
|
||||
39601 多分支需求批量修改计划时,只能修改至对应分支的计划
|
||||
39600 勾选软件需求后进行批量编辑时,过滤掉孪生需求
|
||||
39599 孪生需求进行批量评审时,其余孪生需求均同步评审结果
|
||||
39575 瀑布项目阶段列表中细分按钮置灰逻辑完善
|
||||
39573 孪生需求进行批量关闭时,其余孪生需求均同步关闭
|
||||
39570 孪生需求进行批量指派给时,其余孪生需求均同步修改
|
||||
39568 研发需求批量修改指派给时过滤已关闭的需求
|
||||
39566 有执行节点的宿主机不能删除
|
||||
39564 浏览宿主机详情
|
||||
39562 需求批量修改阶段时修改提示语
|
||||
39558 创建孪生需求时相同分支只能选一次
|
||||
39448 编辑和变更孪生需求时,同步需求内容
|
||||
39445 孪生需求激活时,状态同步
|
||||
39436 孪生需求关闭时,状态同步
|
||||
39435 孪生需求指派时,指派人同步
|
||||
39424 孪生需求的产品进行切换后,解除孪生关系
|
||||
39423 复制需求时不复制孪生关系
|
||||
39422 孪生需求的变更页面中“影响范围”展示所有相关需求的影响范围
|
||||
39421 修改子计划分支时,只能在父计划的分支内选择
|
||||
39416 变更和编辑孪生需求时可以解除孪生关系
|
||||
39353 编写更新镜像下载状态的接口
|
||||
39302 币种设置中“台元”调整为”台币“
|
||||
39269 根据提供的ostype文件表的结构维护操作系统
|
||||
39224 初始化宿主机
|
||||
39196 编辑和变更孪生需求时增加同步的提示信息
|
||||
39177 基于执行节点创建镜像
|
||||
39150 宿主机网络连通性检验常用端口
|
||||
39148 编写初始化宿主机脚本
|
||||
39145 从镜像创建执行节点
|
||||
39143 宿主机列表添加初始化按钮
|
||||
39142 调整添加和编辑执行节点页面控件
|
||||
39141 调整添加和编辑执行节点页面的样式
|
||||
39138 调整添加和编辑宿主机页面控件
|
||||
39085 下载镜像
|
||||
39084 调整添加和编辑宿主机表单样式
|
||||
39083 调整测试下二级导航栏
|
||||
38958 解除多分支需求的孪生关系后,需求不再同步
|
||||
38956 孪生需求评审时,评审的流程及状态同步
|
||||
38654 优化创建项目页产品和计划的选择样式
|
||||
38653 优化创建执行页产品和计划的选择样式
|
||||
38645 执行按计划关联需求时,只关联本执行所关联分支的激活需求
|
||||
38486 初始化执行节点
|
||||
38482 用例列表添加自动化测试设置
|
||||
38459 项目按计划关联需求时,只关联本项目所关联分支的激活需求
|
||||
38373 孪生需求详情页中展示其余孪生需求
|
||||
38233 创建执行时可关联计划的范围需根据分支过滤
|
||||
38232 创建项目时可关联计划的范围需根据分支过滤
|
||||
37968 版本多选分支后,关联需求和bug只能关联分支内的
|
||||
37966 项目中创建版本时,所属分支支持多选
|
||||
37958 产品计划看板中,属于多个分支的计划多次展示
|
||||
37957 计划多选分支后,关联需求和bug只能关联分支内的
|
||||
37955 创建计划时,所属分支支持多选
|
||||
37818 禅道向执行节点发送请求时带上token
|
||||
37618 浏览执行节点详情
|
||||
37614 查看自动化用例执行结果
|
||||
37611 执行自动化用例
|
||||
36993 通过NoVNC远程操控执行节点
|
||||
36991 实现删除执行节点的功能
|
||||
36987 实现重启执行节点的功能
|
||||
36986 实现恢复执行节点的功能
|
||||
36985 实现暂停执行节点的功能
|
||||
36980 实现基于宿主机添加执行节点的功能
|
||||
36978 在测试自动化下增加执行节点列表页面
|
||||
36965 实现删除宿主机的功能
|
||||
36963 实现编辑宿主机的功能
|
||||
34485 批量提用例页面自定义表单不选择分支时,所属模块展示“主干”的模块
|
||||
34484 批量提bug页面自定义表单不选择分支时,所属模块展示“主干”的模块
|
||||
31514 多分支产品维护模块时上级模块要跟随所属产品分支联动
|
||||
30874 创建需求时,所属分支可以多选
|
||||
企业版:
|
||||
40541 上传课程支持断点续传功能
|
||||
39945 课程中可以替换需要修正的视频
|
||||
39691 课程中可以上传新视频
|
||||
39652 视频无法播放时给出提示
|
||||
38978 课程上传组件支持批量上传功能
|
||||
36843 调整系统备份逻辑不备份学堂数据
|
||||
旗舰版:
|
||||
40764 我的地盘审批列表过滤掉无数据的对象标签
|
||||
39800 调整瀑布项目计划区块的阶段进度计算公式
|
||||
39308 对瀑布类型项目进行评审时填报的工时可以记录到日志中
|
||||
37519 地盘审批列表可以展示在工作流中配置的审批流
|
||||
34166 消息通知增加审批流相关的通知设置
|
||||
禅道客户端:
|
||||
37925 实现原小喧喧以一对一会话的形式展示
|
||||
37930 实现机器人会话消息显示顺序调整
|
||||
37960 实现机器人会话消息右键菜单操作
|
||||
37959 实现在消息记录窗口中查看小喧喧历史消息
|
||||
37948 实现机器人会话在最近会话列表的提醒展示
|
||||
38620 实现机器人会话指令机制
|
||||
38500 实现内置应用查看服务器基础信息demo指令设计
|
||||
38519 实现内置应用查看企业授权信息demo指令设计
|
||||
38526 实现内置应用查看人员信息demo指令设计
|
||||
38529 实现内置提示音开关demo指令设计
|
||||
38438 实现查询指令特殊情况下的默认回复
|
||||
39186 实现会话列表中会议中、连接会议图标的干扰
|
||||
38688 实现机器人会话自动识错功能
|
||||
38426 实现查询任务指令结果以详情形式展示
|
||||
38406 实现通过任务指派人过滤任务的指令格式设计
|
||||
38646 实现机器人会话指令与禅道协同的机制
|
||||
38497 实现机器人会话应用选择
|
||||
38432 实现对话机器人查询任务指令的全局设计
|
||||
38421 实现查询任务指令结果以列表展示
|
||||
38407 实现通过任务优先级过滤任务的指令格式设计
|
||||
38409 实现引导帮助指令设计
|
||||
39261 实现查询任务显示列表增加快速操作任务的按钮设计
|
||||
38959 实现机器人会话操作任务指令与禅道协同的机制
|
||||
38961 实现对话机器人操作任务指令的全局设计
|
||||
39021 实现对话机器人指令开始禅道任务的设计
|
||||
39026 实现对话机器人指令完成禅道任务的设计
|
||||
38970 实现对话机器人指令关闭禅道任务的设计
|
||||
39180 实现群管理应用中合并群组时可以通过关键字进行搜索
|
||||
39181 实现加载会话消息记录的功能
|
||||
39187 实现图片查看时工具栏的优化显示
|
||||
39182 实现xxb后台用户默认职位角色可以删除操作
|
||||
39184 优化图片另存为浮窗交互显示
|
||||
39183 删除解散后的讨论组的相关操作
|
||||
解决的bug:
|
||||
24883 同时打开多个页签情况下出现页签导航和实际功能混乱情况
|
||||
29140 wiki编辑章节可以选择自身,保存会出问题
|
||||
29143 k8s环境替换正式授权之后频繁出现获取uid失败的提示
|
||||
29423 透视表中的部分报表状态显示的是英文
|
||||
30275 在反馈的历史记录中点击转的任务会跳转到执行下
|
||||
30539 工作流导入日期显示1970-01-01
|
||||
30548 用例导入页面输入框与字段错位显示
|
||||
30685 通过上传导入图片的文档导出无反应
|
||||
30700 创建工单无法选择“所属模块”了
|
||||
27979 地盘会议列表中添加会议页面不选择所属项目和执行,会议列表中不显示无所属项目和执行的会议
|
||||
28014 禅道客户端聊天中从自己的会话无法查看聊天记录
|
||||
27983 用户名大小写不对,提示有问题
|
||||
27629 预览txt文件乱码
|
||||
27628 喧喧查看大图后复制和另存为看不清楚(Mac用户)
|
||||
26559 最小窗口时群成员管理列表样式错误
|
||||
28637 已撤回的文件在侧边栏的文件列表中还显示
|
||||
28540 某些窗口无法正常弹出
|
||||
28512 客户端登录账号后一两分钟就提示账号被禁用,但后台账号状态正常
|
||||
28394 客户端导出模板,导入样式显示有问题
|
||||
28095 LDAP密码有特殊字符无法登录
|
||||
25192 多人快速发送消息时会出现index相同的情况
|
||||
14863 使用第三方截图工具截图后,有时在喧喧输入框中粘贴不上
|
||||
29037 bug指派无法弹窗
|
||||
29029 回复消息最后一层信息没有居左对齐
|
||||
28905 聊天发送图片,图片形状编写失真
|
||||
28529 macos客户端页面渲染异常
|
||||
28297 禅道客户端更新工时弹窗出现遮挡
|
||||
|
||||
2022-11-16 18.0.beta1
|
||||
完成的需求
|
||||
开源版:
|
||||
|
||||
@@ -98,7 +98,7 @@ class baseEntry
|
||||
* Get request params.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $defaultValue
|
||||
* @param mixed $defaultValue
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -112,13 +112,18 @@ class baseEntry
|
||||
* 设置请求参数
|
||||
* Set request param.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param string|array $key if is array, set params by its key-value pairs.
|
||||
* @param mixed $value
|
||||
* @access public
|
||||
* @return mixed
|
||||
* @return void
|
||||
*/
|
||||
public function setParam($key, $value)
|
||||
public function setParam($key, $value = null)
|
||||
{
|
||||
if(is_array($key))
|
||||
{
|
||||
foreach($key as $k => $v) $_GET[$k] = $v;
|
||||
return;
|
||||
}
|
||||
$_GET[$key] = $value;
|
||||
}
|
||||
|
||||
|
||||
@@ -600,7 +600,6 @@ class baseControl
|
||||
|
||||
if(!empty($jsExtPath))
|
||||
{
|
||||
$realModulePath = realPath($modulePath);
|
||||
foreach($jsExtPath as $jsPath)
|
||||
{
|
||||
if(empty($jsPath)) continue;
|
||||
@@ -730,7 +729,7 @@ class baseControl
|
||||
chdir(dirname($viewFile));
|
||||
|
||||
/**
|
||||
* 使用extract安定ob方法渲染$viewFile里面的代码。
|
||||
* 使用extract和ob方法渲染$viewFile里面的代码。
|
||||
* Use extract and ob functions to eval the codes in $viewFile.
|
||||
*/
|
||||
extract((array)$this->view);
|
||||
|
||||
@@ -87,7 +87,7 @@ class baseHelper
|
||||
/* 生成url链接的开始部分。Set the begin parts of the link. */
|
||||
if($config->requestType == 'PATH_INFO') $link = $config->webRoot . $appName;
|
||||
if($config->requestType != 'PATH_INFO') $link = $config->webRoot . $appName . basename($_SERVER['SCRIPT_NAME']);
|
||||
if($config->requestType == 'PATH_INFO2') $link .= '/';
|
||||
if($config->requestType == 'PATH_INFO2') $link = '/';
|
||||
|
||||
/**
|
||||
* #1: RequestType为GET。When the requestType is GET.
|
||||
@@ -178,7 +178,7 @@ class baseHelper
|
||||
* Check in only body mode or not.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
* @return bool
|
||||
*/
|
||||
public static function inOnlyBodyMode()
|
||||
{
|
||||
@@ -464,7 +464,7 @@ class baseHelper
|
||||
|
||||
$agent = $_SERVER["HTTP_USER_AGENT"];
|
||||
|
||||
/* Chrome should checked before safari.*/
|
||||
/* Chrome should check before safari.*/
|
||||
if(strpos($agent, 'Firefox') !== false) $browser['name'] = "firefox";
|
||||
if(strpos($agent, 'Opera') !== false) $browser['name'] = 'opera';
|
||||
if(strpos($agent, 'Safari') !== false) $browser['name'] = 'safari';
|
||||
@@ -853,7 +853,7 @@ function a($var)
|
||||
* Judge the server ip is local or not.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
* @return bool
|
||||
*/
|
||||
function isLocalIP()
|
||||
{
|
||||
@@ -954,33 +954,42 @@ function htmlSpecialString($string, $flags = '', $encoding = 'UTF-8')
|
||||
return htmlspecialchars($string, $flags, $encoding);
|
||||
}
|
||||
|
||||
if (!function_exists('array_column'))
|
||||
if(!function_exists('array_column'))
|
||||
{
|
||||
function array_column(array $input, $columnKey, $indexKey = null)
|
||||
{
|
||||
$output = array();
|
||||
|
||||
foreach ($input as $row) {
|
||||
$key = $value = null;
|
||||
foreach($input as $row)
|
||||
{
|
||||
$key = $value = null;
|
||||
$keySet = $valueSet = false;
|
||||
|
||||
if (null !== $indexKey && array_key_exists($indexKey, $row)) {
|
||||
if(null !== $indexKey && array_key_exists($indexKey, $row))
|
||||
{
|
||||
$keySet = true;
|
||||
$key = (string) $row[$indexKey];
|
||||
$key = (string) $row[$indexKey];
|
||||
}
|
||||
|
||||
if (null === $columnKey) {
|
||||
if(null === $columnKey)
|
||||
{
|
||||
$valueSet = true;
|
||||
$value = $row;
|
||||
} elseif (\is_array($row) && \array_key_exists($columnKey, $row)) {
|
||||
$value = $row;
|
||||
}
|
||||
elseif(\is_array($row) && \array_key_exists($columnKey, $row))
|
||||
{
|
||||
$valueSet = true;
|
||||
$value = $row[$columnKey];
|
||||
$value = $row[$columnKey];
|
||||
}
|
||||
|
||||
if ($valueSet) {
|
||||
if ($keySet) {
|
||||
if($valueSet)
|
||||
{
|
||||
if($keySet)
|
||||
{
|
||||
$output[$key] = $value;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$output[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,8 +281,8 @@ class baseModel
|
||||
/* 设置扩展的名字和相应的文件。Set extenson name and extension file. */
|
||||
$moduleExtPath = $this->app->getModuleExtPath($this->appName, $moduleName, $type);
|
||||
if(!empty($moduleExtPath['site'])) $extensionFile = $moduleExtPath['site'] . 'class/' . $extensionName . '.class.php';
|
||||
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['custom'] . 'class/' . $extensionName . '.class.php';
|
||||
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['saas'] . 'class/' . $extensionName . '.class.php';
|
||||
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['custom'] . 'class/' . $extensionName . '.class.php';
|
||||
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['vision'] . 'class/' . $extensionName . '.class.php';
|
||||
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['xuan'] . 'class/' . $extensionName . '.class.php';
|
||||
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['common'] . 'class/' . $extensionName . '.class.php';
|
||||
|
||||
@@ -1719,7 +1719,7 @@ class baseRouter
|
||||
}
|
||||
|
||||
/* 1. 如果extensionLevel == 2,且扩展文件存在,返回该站点扩展文件。 If extensionLevel == 2 and site extensionFile exists, return it. */
|
||||
if($this->config->framework->extensionLevel == 2 and !empty( $moduleExtPaths['site']))
|
||||
if($this->config->framework->extensionLevel == 2 and !empty($moduleExtPaths['site']))
|
||||
{
|
||||
$this->extActionFile = $moduleExtPaths['site'] . $this->methodName . '.php';
|
||||
if(file_exists($this->extActionFile)) return true;
|
||||
@@ -1757,7 +1757,7 @@ class baseRouter
|
||||
if(empty($moduleExtPaths)) return false;
|
||||
|
||||
/* 如果extensionLevel == 2,且扩展文件存在,返回该站点扩展文件。If extensionLevel == 2 and site extensionFile exists, return it. */
|
||||
if($this->config->framework->extensionLevel == 2 and !empty( $moduleExtPaths['site']))
|
||||
if($this->config->framework->extensionLevel == 2 and !empty($moduleExtPaths['site']))
|
||||
{
|
||||
$locateFile = $moduleExtPaths['site'] . $this->methodName . '.302';
|
||||
if(file_exists($locateFile)) $this->sendAPI($locateFile);
|
||||
@@ -2497,9 +2497,8 @@ class baseRouter
|
||||
*
|
||||
* @param string $moduleName module name
|
||||
* @param string $appName app name
|
||||
* @param bool $exitIfNone exit or not
|
||||
* @access public
|
||||
* @return object|bool the config object or false.
|
||||
* @return void
|
||||
*/
|
||||
public function loadModuleConfig($moduleName, $appName = '')
|
||||
{
|
||||
@@ -2525,7 +2524,7 @@ class baseRouter
|
||||
if(!empty($extConfigPath['saas'])) $commonExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['saas'], '.php'));
|
||||
if(!empty($extConfigPath['custom'])) $commonExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['custom'], '.php'));
|
||||
}
|
||||
if($config->framework->extensionLevel == 2 and !empty($extConfigPath['site'])) $siteExtConfigFiles = helper::ls($extConfigPath['site'], '.php');
|
||||
if($config->framework->extensionLevel == 2 and !empty($extConfigPath['site'])) $siteExtConfigFiles = helper::ls($extConfigPath['site'], '.php');
|
||||
$extConfigFiles = array_merge($commonExtConfigFiles, $siteExtConfigFiles);
|
||||
|
||||
/* 将主配置文件和扩展配置文件合并在一起。Put the main config file and extension config files together. */
|
||||
@@ -2690,12 +2689,12 @@ class baseRouter
|
||||
if($this->config->framework->extensionLevel >= 1)
|
||||
{
|
||||
if(!empty($extLangPath['common'])) $commonExtLangFiles = helper::ls($extLangPath['common'] . $this->clientLang, '.php');
|
||||
if(!empty($extLangPath['xuan'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['xuan'] . $this->clientLang, '.php'));
|
||||
if(!empty($extLangPath['xuan'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['xuan'] . $this->clientLang, '.php'));
|
||||
if(!empty($extLangPath['vision'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['vision'] . $this->clientLang, '.php'));
|
||||
if(!empty($extLangPath['custom'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['custom'] . $this->clientLang, '.php'));
|
||||
if(!empty($extLangPath['saas'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['saas'] . $this->clientLang, '.php'));
|
||||
}
|
||||
if($this->config->framework->extensionLevel == 2 and !empty($extLangPath['site'])) $siteExtLangFiles = helper::ls($extLangPath['site'] . $this->clientLang, '.php');
|
||||
if($this->config->framework->extensionLevel == 2 and !empty($extLangPath['site'])) $siteExtLangFiles = helper::ls($extLangPath['site'] . $this->clientLang, '.php');
|
||||
$extLangFiles = array_merge($commonExtLangFiles, $siteExtLangFiles);
|
||||
}
|
||||
|
||||
|
||||
@@ -315,9 +315,8 @@ class router extends baseRouter
|
||||
*
|
||||
* @param string $moduleName module name
|
||||
* @param string $appName app name
|
||||
* @param bool $exitIfNone exit or not
|
||||
* @access public
|
||||
* @return object|bool the config object or false.
|
||||
* @return void
|
||||
*/
|
||||
public function loadModuleConfig($moduleName, $appName = '')
|
||||
{
|
||||
|
||||
@@ -130,7 +130,11 @@ class pager extends basePager
|
||||
}
|
||||
}
|
||||
|
||||
echo "<ul class='pager' $pageSizeOptions data-page-cookie='{$this->pageCookie}' data-ride='pager' data-rec-total='{$this->recTotal}' data-rec-per-page='{$this->recPerPage}' data-page='{$this->pageID}' data-link-creator='" . helper::createLink($this->moduleName, $this->methodName, $params) . "'></ul>";
|
||||
global $app, $lang;
|
||||
$appendApp = '';
|
||||
$moduleName = $this->moduleName;
|
||||
if(isset($lang->navGroup->{$moduleName}) and $lang->navGroup->{$moduleName} != $app->tab) $appendApp = "#app={$app->tab}";
|
||||
echo "<ul class='pager' $pageSizeOptions data-page-cookie='{$this->pageCookie}' data-ride='pager' data-rec-total='{$this->recTotal}' data-rec-per-page='{$this->recPerPage}' data-page='{$this->pageID}' data-link-creator='" . helper::createLink($this->moduleName, $this->methodName, $params) . $appendApp . "'></ul>";
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -63,7 +63,7 @@ $config->action->majorList['project'] = array('opened', 'edited');
|
||||
$config->action->majorList['execution'] = array('opened', 'edited');
|
||||
|
||||
$config->action->needGetProjectType = 'build,task,bug,case,testcase,caselib,testtask,testsuite,testreport,doc,issue,release,risk,design,opportunity,trainplan,gapanalysis,researchplan,researchreport,';
|
||||
$config->action->needGetRelateField = ',story,productplan,release,task,build,bug,testcase,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,kanbanlane,kanbancolumn,module,';
|
||||
$config->action->needGetRelateField = ',story,productplan,release,task,build,bug,testcase,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,kanbanlane,kanbancolumn,module,review,';
|
||||
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,gitea,gogs,sonarqube,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,execution,project,traincategory,apistruct,program,product,user,entry,repo,';
|
||||
$config->action->ignoreObjectType4Dynamic = 'kanbanregion,kanbanlane,kanbancolumn';
|
||||
|
||||
|
||||
@@ -231,6 +231,7 @@ $lang->action->desc->suspend = '$date, the ZenAgent Node is suspend
|
||||
$lang->action->desc->resume = '$date, the ZenAgent Node is resumed by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->reboot = '$date, the ZenAgent Node is reboot by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->destroy = '$date, the ZenAgent Node is destroyed by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->relieved = '$date, relieved by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by <strong>'. $lang->admin->system .'</strong>.' . "\n";
|
||||
$lang->action->desc->getvnc = '$date, Remote control <strong>$extra</strong> by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n";
|
||||
@@ -408,6 +409,8 @@ $lang->action->label->suspend = 'suspended';
|
||||
$lang->action->label->resume = 'resumed';
|
||||
$lang->action->label->reboot = 'reboot';
|
||||
$lang->action->label->destroy = 'destroyed';
|
||||
$lang->action->label->synctwins = 'synchronized changes';
|
||||
$lang->action->label->relieved = 'relieved';
|
||||
$lang->action->label->switchtolight = 'switch from ALM mode to light mode';
|
||||
$lang->action->label->linkedrepo = 'Linked Code Repo';
|
||||
$lang->action->label->unlinkedrepo = 'Unlinked Code Repo';
|
||||
|
||||
@@ -231,6 +231,7 @@ $lang->action->desc->suspend = '$date, the ZenAgent Node is suspend
|
||||
$lang->action->desc->resume = '$date, the ZenAgent Node is resumed by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->reboot = '$date, the ZenAgent Node is reboot by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->destroy = '$date, the ZenAgent Node is destroyed by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->relieved = '$date, relieved by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by <strong>'. $lang->admin->system .'</strong>.' . "\n";
|
||||
$lang->action->desc->getvnc = '$date, Remote control <strong>$extra</strong> by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n";
|
||||
@@ -408,6 +409,8 @@ $lang->action->label->suspend = 'suspended';
|
||||
$lang->action->label->resume = 'resumed';
|
||||
$lang->action->label->reboot = 'reboot';
|
||||
$lang->action->label->destroy = 'destroyed';
|
||||
$lang->action->label->synctwins = 'synchronized changes';
|
||||
$lang->action->label->relieved = 'relieved';
|
||||
$lang->action->label->switchtolight = 'switch from ALM mode to light mode';
|
||||
$lang->action->label->linkedrepo = 'Linked Code Repo';
|
||||
$lang->action->label->unlinkedrepo = 'Unlinked Code Repo';
|
||||
|
||||
@@ -231,6 +231,7 @@ $lang->action->desc->suspend = '$date, the ZenAgent Node is suspend
|
||||
$lang->action->desc->resume = '$date, the ZenAgent Node is resumed by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->reboot = '$date, the ZenAgent Node is reboot by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->destroy = '$date, the ZenAgent Node is destroyed by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->relieved = '$date, relieved by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by <strong>'. $lang->admin->system .'</strong>.' . "\n";
|
||||
$lang->action->desc->getvnc = '$date, Remote control <strong>$extra</strong> by <strong>$actor</strong> .' . "\n";
|
||||
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n";
|
||||
@@ -408,6 +409,8 @@ $lang->action->label->suspend = 'suspended';
|
||||
$lang->action->label->resume = 'resumed';
|
||||
$lang->action->label->reboot = 'reboot';
|
||||
$lang->action->label->destroy = 'destroyed';
|
||||
$lang->action->label->synctwins = 'synchronized changes';
|
||||
$lang->action->label->relieved = 'relieved';
|
||||
$lang->action->label->switchtolight = 'switch from ALM mode to light mode';
|
||||
$lang->action->label->linkedrepo = 'Linked Code Repo';
|
||||
$lang->action->label->unlinkedrepo = 'Unlinked Code Repo';
|
||||
|
||||
@@ -318,6 +318,7 @@ $lang->action->label->suspend = 'suspended';
|
||||
$lang->action->label->resume = 'resumed';
|
||||
$lang->action->label->reboot = 'reboot';
|
||||
$lang->action->label->destroy = 'destroyed';
|
||||
$lang->action->label->synctwins = 'synchronized changes';
|
||||
$lang->action->label->linkedrepo = 'Linked Code Repo';
|
||||
$lang->action->label->unlinkedrepo = 'Unlinked Code Repo';
|
||||
|
||||
|
||||
@@ -231,6 +231,7 @@ $lang->action->desc->suspend = '$date, 由 <strong>$actor</strong>
|
||||
$lang->action->desc->resume = '$date, 由 <strong>$actor</strong> 恢复。' . "\n";
|
||||
$lang->action->desc->reboot = '$date, 由 <strong>$actor</strong> 重启。' . "\n";
|
||||
$lang->action->desc->destroy = '$date, 由 <strong>$actor</strong> 销毁。' . "\n";
|
||||
$lang->action->desc->relieved = '$date, 由 <strong>$actor</strong> 解除孪生需求关系。' . "\n";
|
||||
$lang->action->desc->switchtolight = '$date, 由于 <strong>'. $lang->admin->system .'</strong> 从全生命周期管理模式切换为轻量管理模式,项目访问控制由项目集内公开调整为私有。' . "\n";
|
||||
$lang->action->desc->getvnc = '$date, <strong>$actor</strong>对执行节点 <strong>$extra</strong> 进行了远程操控。' . "\n";
|
||||
$lang->action->desc->unlinkproduct = '$date, 系统判断由于' . $lang->executionCommon . '所属项目与$extra取消关联,同步将' . $lang->executionCommon . '与$extra取消关联。' . "\n";
|
||||
@@ -409,6 +410,8 @@ $lang->action->label->resume = '恢复了';
|
||||
$lang->action->label->reboot = '重启了';
|
||||
$lang->action->label->destroy = '销毁了';
|
||||
$lang->action->label->getvnc = '远程操控';
|
||||
$lang->action->label->synctwins = '同步修改了';
|
||||
$lang->action->label->relieved = '解除了';
|
||||
$lang->action->label->switchtolight = '从全生命周期管理模式切换为轻量管理模式';
|
||||
$lang->action->label->linkedrepo = '关联代码库到';
|
||||
$lang->action->label->unlinkedrepo = '取消了项目与代码库的关联';
|
||||
|
||||
+26
-1
@@ -50,7 +50,7 @@ class actionModel extends model
|
||||
$action->extra = $extra;
|
||||
if(!defined('IN_UPGRADE')) $action->vision = $this->config->vision;
|
||||
|
||||
if($objectType == 'story' and strpos(',reviewpassed,reviewrejected,reviewclarified,reviewreverted,', ",$actionType,") !== false) $action->actor = $this->lang->action->system;
|
||||
if($objectType == 'story' and strpos(',reviewpassed,reviewrejected,reviewclarified,reviewreverted,synctwins,', ",$actionType,") !== false) $action->actor = $this->lang->action->system;
|
||||
|
||||
/* Use purifier to process comment. Fix bug #2683. */
|
||||
$action->comment = fixer::stripDataTags($comment);
|
||||
@@ -289,6 +289,15 @@ class actionModel extends model
|
||||
if(strpos(',deleted,', ",$actionType,") !== false) $module = $this->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($objectID)->fetch();
|
||||
if(!empty($module) and $module->type == 'story') $record['product'] = $module->root;
|
||||
break;
|
||||
case 'review':
|
||||
$result = $this->dao->select('*')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
|
||||
if($result)
|
||||
{
|
||||
$products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($result->project)->fetchPairs('product');
|
||||
$record['product'] = join(',', array_keys($products));
|
||||
$record['project'] = zget($result, 'project', 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$result = $this->dao->select('*')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
|
||||
$record['product'] = zget($result, 'product', '0');
|
||||
@@ -964,6 +973,17 @@ class actionModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
if($action->objectType == 'story' and $action->action == 'synctwins')
|
||||
{
|
||||
if(!empty($extra) and strpos($extra, '|') !== false)
|
||||
{
|
||||
list($operate, $storyID) = explode('|', $extra);
|
||||
$desc['operate'] = $this->lang->$objectType->{$desc['operate']};
|
||||
$link = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$storyID"), "#$storyID ") : "#$storyID";
|
||||
$actionDesc = str_replace(array('$extra', '$operate'), array($link, $desc['operate'][$operate]), $desc['main']);
|
||||
}
|
||||
}
|
||||
|
||||
if($action->objectType == 'module' and strpos(',created,moved,', $action->action) !== false)
|
||||
{
|
||||
$moduleNames = $this->loadModel('tree')->getOptionMenu($action->objectID, 'story', 0, 'all', '');
|
||||
@@ -1834,6 +1854,11 @@ class actionModel extends model
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($action->objectType == 'release')
|
||||
{
|
||||
$release = $this->dao->select('*')->from(TABLE_RELEASE)->where('id')->eq($action->objectID)->fetch();
|
||||
if($release->shadow) $this->dao->update(TABLE_BUILD)->set('deleted')->eq(0)->where('id')->eq($release->shadow)->exec();
|
||||
}
|
||||
|
||||
/* Update deleted field in object table. */
|
||||
$table = $this->config->objectTables[$action->objectType];
|
||||
|
||||
@@ -1951,6 +1951,11 @@ class block extends control
|
||||
$hasViewPriv['review'] = true;
|
||||
$count['review'] = count($reviews);
|
||||
$this->view->reviews = $reviews;
|
||||
if($this->config->edition == 'max')
|
||||
{
|
||||
$this->app->loadLang('approval');
|
||||
$this->view->flows = $this->dao->select('module,name')->from(TABLE_WORKFLOW)->where('buildin')->eq(0)->fetchPairs('module', 'name');
|
||||
}
|
||||
}
|
||||
|
||||
$this->view->selfCall = $this->selfCall;
|
||||
|
||||
@@ -29,13 +29,21 @@
|
||||
<?php foreach($reviews as $review):?>
|
||||
<?php
|
||||
$type = $review->type;
|
||||
if($type == 'project') $type = 'review';
|
||||
if($type == 'projectreview') $type = 'review';
|
||||
|
||||
$typeName = $lang->$type->common;
|
||||
$typeName = '';
|
||||
if(isset($lang->{$review->type}->common)) $typeName = $lang->{$review->type}->common;
|
||||
if($type == 'story') $typeName = $lang->my->auditMenu->audit->story;
|
||||
if($review->type == 'projectreview') $typeName = $lang->project->common;
|
||||
if(isset($flows[$review->type])) $typeName = $flows[$review->type];
|
||||
|
||||
$statusList = $lang->$type->statusList;
|
||||
$statusList = array();
|
||||
if(isset($lang->$type->statusList)) $statusList = $lang->$type->statusList;
|
||||
if($type == 'attend') $statusList = $lang->attend->reviewStatusList;
|
||||
if(!in_array($type, array('story', 'testcase', 'feedback', 'review')) and strpos(",{$config->my->oaObjectType},", ",$type,") === false)
|
||||
{
|
||||
$statusList = $lang->approval->nodeList;
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td class='c-id'><?php echo $review->id?></td>
|
||||
@@ -82,6 +90,10 @@
|
||||
{
|
||||
common::printLink($module, 'view', $params, $reviewIcon, '', "class='btn' data-toggle='modal' title='{$lang->review->common}'", true, true);
|
||||
}
|
||||
elseif(!in_array($module, array('story', 'testcase', 'feedback')))
|
||||
{
|
||||
common::printLink($module, 'approvalreview', $params, $reviewIcon, '', "class='btn' data-toggle='modal' title='{$lang->review->common}'", true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
common::printLink($module, $method, $params, $reviewIcon, '', "class='btn iframe' title='{$lang->review->common}'", true, true);
|
||||
|
||||
@@ -86,12 +86,12 @@
|
||||
minTimeGap = Math.min(minTimeGap, endDatetime - startDatetime);
|
||||
item.tasks = [];
|
||||
item.completeTasks = [];
|
||||
item.progress = 0;
|
||||
item.progress = Number.parseFloat(item.taskProgress.replace('%', ''), 10);
|
||||
plans.push(item);
|
||||
}
|
||||
else if(item.type === 'task')
|
||||
{
|
||||
item.progress = Number.parseInt(item.taskProgress.replace('%', ''), 10);
|
||||
item.progress = Number.parseFloat(item.taskProgress.replace('%', ''), 10);
|
||||
tasks.push(item);
|
||||
}
|
||||
});
|
||||
@@ -105,7 +105,6 @@
|
||||
plan = plansMap[plan.parent];
|
||||
if(typeof(plan) != 'object') return;
|
||||
}
|
||||
plan.progress += task.progress;
|
||||
if(task.progress === 100) plan.completeTasks.push(task);
|
||||
plan.tasks.push(task);
|
||||
});
|
||||
@@ -122,7 +121,6 @@
|
||||
/* Update gantt plans and bars */
|
||||
$.each(plans, function(index, plan)
|
||||
{
|
||||
plan.progress = !plan.tasks.length ? 0 : plan.progress / plan.tasks.length;
|
||||
var $plan = $('<div class="gantt-plan"></div>');
|
||||
$plan.append('<div class="strong" title="' + plan.name + '">' + plan.text + '</div>');
|
||||
$plans.append($plan);
|
||||
|
||||
@@ -257,18 +257,21 @@ class branch extends control
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $oldBranch
|
||||
* @param string $param
|
||||
* @param string $browseType
|
||||
* @param int $projectID
|
||||
* @param bool $withMainBranch
|
||||
* @param string $isTwins
|
||||
* @param string $fieldID
|
||||
* @param string $multiple
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetBranches($productID, $oldBranch = 0, $param = 'all', $projectID = 0, $withMainBranch = true)
|
||||
public function ajaxGetBranches($productID, $oldBranch = 0, $browseType = 'all', $projectID = 0, $withMainBranch = true, $isTwins = 'no', $fieldID = '0', $multiple = '')
|
||||
{
|
||||
$product = $this->loadModel('product')->getById($productID);
|
||||
if(empty($product) or $product->type == 'normal') return;
|
||||
|
||||
$branches = $this->loadModel('branch')->getList($productID, $projectID, $param, 'order', null, $withMainBranch);
|
||||
$branches = $this->loadModel('branch')->getList($productID, $projectID, $browseType, 'order', null, $withMainBranch);
|
||||
$branchTagOption = array();
|
||||
foreach($branches as $branchInfo)
|
||||
{
|
||||
@@ -280,7 +283,10 @@ class branch extends control
|
||||
$branchTagOption[$oldBranch] = $oldBranch == BRANCH_MAIN ? $branch : ($branch->name . ($branch->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : ''));
|
||||
}
|
||||
|
||||
return print(html::select('branch', $branchTagOption, $oldBranch, "class='form-control' onchange='loadBranch(this)' data-last='{$oldBranch}'"));
|
||||
$name = $multiple == 'multiple' ? 'branch[]' : 'branch';
|
||||
|
||||
if($isTwins == 'yes') return print(html::select("branches[$fieldID]", $branchTagOption, $oldBranch, "onchange='loadBranchRelation(this.value, $fieldID);' class='form-control chosen control-branch'"));
|
||||
return print(html::select($name, $branchTagOption, $oldBranch, "class='form-control' $multiple onchange='loadBranch(this)' data-last='{$oldBranch}'"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-10
@@ -488,7 +488,7 @@ class bug extends control
|
||||
$steps = $this->lang->bug->tplStep . $this->lang->bug->tplResult . $this->lang->bug->tplExpect;
|
||||
$os = '';
|
||||
$browser = '';
|
||||
$assignedTo = '';
|
||||
$assignedTo = isset($currentProduct->QD) ? $currentProduct->QD : '';
|
||||
$deadline = '';
|
||||
$mailto = '';
|
||||
$keywords = '';
|
||||
@@ -1802,7 +1802,7 @@ class bug extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
return print(js::closeModal('parent.parent'));
|
||||
return print(js::closeModal('parent.parent', 'this', "typeof(parent.parent.setTitleWidth) == 'function' ? parent.parent.setTitleWidth() : parent.parent.location.reload()"));
|
||||
}
|
||||
}
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api')
|
||||
@@ -1989,7 +1989,7 @@ class bug extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
|
||||
return print(js::closeModal('parent.parent', 'this', "typeof(parent.parent.setTitleWidth) == 'function' ? parent.parent.setTitleWidth() : parent.parent.location.reload()"));
|
||||
}
|
||||
}
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api')
|
||||
@@ -2351,21 +2351,23 @@ class bug extends control
|
||||
$this->config->bug->datatable->fieldList['module']['dataSource']['method'] = 'getAllModulePairs';
|
||||
$this->config->bug->datatable->fieldList['module']['dataSource']['params'] = 'bug';
|
||||
|
||||
$this->config->bug->datatable->fieldList['project']['dataSource'] = array('module' => 'project', 'method' => 'getPairsByIdList', 'params' => $executionID);
|
||||
$this->config->bug->datatable->fieldList['execution']['dataSource'] = array('module' => 'execution', 'method' => 'getPairs', 'params' => $executionID);
|
||||
$object = $this->dao->findById($executionID)->from(TABLE_EXECUTION)->fetch();
|
||||
$projectID = $object->type == 'project' ? $object->id : $object->parent;
|
||||
$this->config->bug->datatable->fieldList['project']['dataSource'] = array('module' => 'project', 'method' => 'getPairsByIdList', 'params' => $projectID);
|
||||
$this->config->bug->datatable->fieldList['execution']['dataSource'] = array('module' => 'execution', 'method' => 'getPairs', 'params' => $projectID);
|
||||
}
|
||||
|
||||
$this->transfer->export('bug');
|
||||
$this->fetch('file', 'export2' . $_POST['fileType'], $_POST);
|
||||
}
|
||||
$product = $this->loadModel('product')->getByID($productID);
|
||||
if($product->type == 'normal') $this->config->bug->exportFields = str_replace('branch,', '', $this->config->bug->exportFields);
|
||||
if(isset($product->type) and $product->type == 'normal') $this->config->bug->exportFields = str_replace('branch,', '', $this->config->bug->exportFields);
|
||||
|
||||
if($this->app->tab == 'project' or $this->app->tab == 'execution')
|
||||
{
|
||||
$execution = $this->loadModel('execution')->getByID($executionID);
|
||||
if(empty($execution->multiple)) $this->config->bug->exportFields = str_replace('execution,', '', $this->config->bug->exportFields);
|
||||
if($product->shadow) $this->config->bug->exportFields = str_replace('product,', '', $this->config->bug->exportFields);
|
||||
if(!empty($product->shadow)) $this->config->bug->exportFields = str_replace('product,', '', $this->config->bug->exportFields);
|
||||
}
|
||||
|
||||
$fileName = $this->lang->bug->common;
|
||||
@@ -2505,9 +2507,9 @@ class bug extends control
|
||||
|
||||
/**
|
||||
* Ajax get released builds.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int|string $branch
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int|string $branch
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
|
||||
@@ -57,4 +57,4 @@ html[lang='de'] #keywordsAddonLabel, .task {width: 73px;}
|
||||
#openedBuildLabel {display: inline; position: relative; width: 50%; left: 14%;}
|
||||
#bugTypeInputGroup > .table-col {width: 40% !important;}
|
||||
|
||||
.pri-text > .label-pri {padding: 1px 5px;}
|
||||
.pri-text > .label-pri {padding: 2px 6px;}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
$(function()
|
||||
{
|
||||
if($('#bugList thead th.c-title').width() < 150) $('#bugList thead th.c-title').width(150);
|
||||
setTitleWidth();
|
||||
|
||||
/* The display of the adjusting sidebarHeader is synchronized with the sidebar. */
|
||||
$(".sidebar-toggle").click(function()
|
||||
|
||||
+43
-14
@@ -24,9 +24,16 @@ if($('#openedBuild').length || $('#resolvedBuild').length || $('[name^=openedBui
|
||||
{
|
||||
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
|
||||
|
||||
$('#openedBuild, #resolvedBuild, [name^=openedBuilds]').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
|
||||
$('#openedBuild, #resolvedBuild, [name^=openedBuilds]').picker({optionRender: markReleasedBuilds});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark released builds.
|
||||
*
|
||||
* @param object $option
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function markReleasedBuilds($option)
|
||||
{
|
||||
var build = $option.attr('data-value');
|
||||
@@ -35,7 +42,7 @@ function markReleasedBuilds($option)
|
||||
if(!$option.find('.label-released').length)
|
||||
{
|
||||
var optionText = $option.find('.picker-option-text').html();
|
||||
$option.find('.picker-option-text').replaceWith("<p class='picker-option-text no-margin'><span class='label label-released label-primary label-outline'>" + releasedBuild + "</span> " + optionText + "</p>");
|
||||
$option.find('.picker-option-text').replaceWith("<p class='picker-option-text no-margin'>" + optionText + " <span class='label label-released label-primary label-outline'>" + released + "</span></p>");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,7 +180,7 @@ function loadAllBuilds(object)
|
||||
{
|
||||
oldResolvedBuild = $('#resolvedBuild').val() ? $('#resolvedBuild').val() : 0;
|
||||
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=0&index=0&type=all');
|
||||
$('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
|
||||
$('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -212,7 +219,7 @@ function loadAllExecutionBuilds(executionID, productID, buildBox)
|
||||
$('#pickerDropMenu-pk_openedBuild').remove();
|
||||
$('#openedBuild').next('.picker').remove();
|
||||
notice();
|
||||
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
|
||||
$("#openedBuild").picker({optionRender: markReleasedBuilds});
|
||||
})
|
||||
}
|
||||
if(page == 'edit')
|
||||
@@ -220,7 +227,7 @@ function loadAllExecutionBuilds(executionID, productID, buildBox)
|
||||
if(buildBox == 'openedBuildBox')
|
||||
{
|
||||
link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&needCreate=true&type=all');
|
||||
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
|
||||
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds})});
|
||||
}
|
||||
if(buildBox == 'resolvedBuildBox')
|
||||
{
|
||||
@@ -255,7 +262,7 @@ function loadAllProductBuilds(productID, buildBox)
|
||||
$('#pickerDropMenu-pk_openedBuild').remove();
|
||||
$('#openedBuild').next('.picker').remove();
|
||||
notice();
|
||||
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
|
||||
$("#openedBuild").picker({optionRender: markReleasedBuilds});
|
||||
})
|
||||
}
|
||||
if(page == 'edit')
|
||||
@@ -263,12 +270,17 @@ function loadAllProductBuilds(productID, buildBox)
|
||||
if(buildBox == 'openedBuildBox')
|
||||
{
|
||||
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&type=all');
|
||||
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
|
||||
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds})});
|
||||
}
|
||||
if(buildBox == 'resolvedBuildBox')
|
||||
{
|
||||
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch + '&index=0&type=all');
|
||||
$('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
|
||||
$('#resolvedBuildBox').load(link, function()
|
||||
{
|
||||
$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})
|
||||
var $pkResolvedBuild = $('#pk_resolvedBuild-search');
|
||||
$pkResolvedBuild.closest('.picker').css('width', $pkResolvedBuild.closest('td').width());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,12 +486,12 @@ function loadProductBuilds(productID)
|
||||
$('#pickerDropMenu-pk_openedBuild').remove();
|
||||
$('#openedBuild').next('.picker').remove();
|
||||
notice();
|
||||
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
|
||||
$("#openedBuild").picker({optionRender: markReleasedBuilds});
|
||||
})
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
|
||||
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds})});
|
||||
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
|
||||
$('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
|
||||
}
|
||||
@@ -632,13 +644,13 @@ function loadProjectBuilds(projectID)
|
||||
$('#pickerDropMenu-pk_openedBuild').remove();
|
||||
$('#openedBuild').next('.picker').remove();
|
||||
notice();
|
||||
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
|
||||
$("#openedBuild").picker({optionRender: markReleasedBuilds});
|
||||
})
|
||||
}
|
||||
else
|
||||
{
|
||||
var link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch);
|
||||
$('#openedBuildBox').load(link, function(){$(this).find('select').val(oldOpenedBuild).picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
|
||||
$('#openedBuildBox').load(link, function(){$(this).find('select').val(oldOpenedBuild).picker({optionRender: markReleasedBuilds})});
|
||||
|
||||
var oldResolvedBuild = $('#resolvedBuild').val() ? $('#resolvedBuild').val() : 0;
|
||||
var link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
|
||||
@@ -677,13 +689,13 @@ function loadExecutionBuilds(executionID, num)
|
||||
$('#pickerDropMenu-pk_openedBuild').remove();
|
||||
$('#openedBuild').next('.picker').remove();
|
||||
notice();
|
||||
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
|
||||
$("#openedBuild").picker({optionRender: markReleasedBuilds});
|
||||
})
|
||||
}
|
||||
else
|
||||
{
|
||||
link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&needCreate=false&type=normal&number=' + num);
|
||||
$('#openedBuildBox' + num).load(link, function(){$(this).find('select').val(oldOpenedBuild).picker({optionRender: markReleaseBuilds, dropWidth: 'auto'})});
|
||||
$('#openedBuildBox' + num).load(link, function(){$(this).find('select').val(oldOpenedBuild).picker({optionRender: markReleaseBuilds})});
|
||||
|
||||
oldResolvedBuild = $('#resolvedBuild').val() ? $('#resolvedBuild').val() : 0;
|
||||
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
|
||||
@@ -973,3 +985,20 @@ function setBranchRelated(branchID, productID, num)
|
||||
$.ajaxSettings.async = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set title field width.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setTitleWidth()
|
||||
{
|
||||
if(window.config.currentMethod != 'browse') return false;
|
||||
|
||||
if($('#bugList thead th.c-title').width() < 150) $('#bugList thead th.c-title').width(150);
|
||||
setTimeout(function()
|
||||
{
|
||||
if($('#bugList thead th.c-title').width() < 150) $('#bugList thead th.c-title').width(150);
|
||||
}, 400)
|
||||
}
|
||||
|
||||
@@ -12,9 +12,8 @@ $(function()
|
||||
confirmResult = confirm(confirmUnlinkBuild);
|
||||
if(!confirmResult)
|
||||
{
|
||||
$('#resolvedBuild').val(oldResolvedBuild);
|
||||
$('#resolvedBuild').trigger("chosen:updated");
|
||||
$('#resolvedBuild').chosen();
|
||||
var resolvedBuildPicker = $('#resolvedBuild').data('zui.picker');
|
||||
resolvedBuildPicker.setValue(oldResolvedBuild);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -40,6 +39,9 @@ $(function()
|
||||
var modalTrigger = new $.zui.ModalTrigger({type: 'iframe', width: '95%', url: link});
|
||||
modalTrigger.show();
|
||||
});
|
||||
|
||||
var $pkResolvedBuild = $('#pk_resolvedBuild-search');
|
||||
$pkResolvedBuild.closest('.picker').css('width', $pkResolvedBuild.closest('td').width() - $pkResolvedBuild.closest('td').find('.input-group-btn').width());
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
$lang->bug->common = 'Bug';
|
||||
$lang->bug->id = 'Bug编号';
|
||||
$lang->bug->product = '所属' . $lang->productCommon;
|
||||
$lang->bug->branch = '分支/平台';
|
||||
$lang->bug->branch = '平台/分支';
|
||||
$lang->bug->productplan = '所属' . '计划';
|
||||
$lang->bug->module = '所属模块';
|
||||
$lang->bug->moduleAB = '模块';
|
||||
|
||||
@@ -1855,7 +1855,7 @@ class bugModel extends model
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($excludeBugs)->andWhere('id')->notIN($excludeBugs)->fi()
|
||||
->beginIF(!empty($productID) and strpos($bugQuery, 'product') === false and strpos($bugQuery, '`product` IN') === false)->andWhere('product')->eq($productID)->fi()
|
||||
->beginIF(!empty($productID) and strpos($bugQuery, 'product') === false and strpos($bugQuery, '`product` IN') === false)->andWhere('branch')->eq($branchID)->fi()
|
||||
->beginIF(!empty($productID) and strpos($bugQuery, 'product') === false and strpos($bugQuery, '`product` IN') === false and $branchID != 'all')->andWhere('branch')->eq($branchID)->fi()
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
@@ -2319,7 +2319,7 @@ class bugModel extends model
|
||||
$products = $this->session->product;
|
||||
preg_match('/`product` IN \((?P<productIdList>.+)\)/', $this->reportCondition(), $matchs);
|
||||
if(!empty($matchs) and isset($matchs['productIdList'])) $products = str_replace('\'', '', $matchs['productIdList']);
|
||||
$builds = $this->loadModel('build')->getBuildPairs($products, $branch = 0, $params = 'hasDeleted');
|
||||
$builds = $this->loadModel('build')->getBuildPairs($products, $branch = 0, $params = 'hasdeleted');
|
||||
|
||||
/* Deal with the situation that a bug maybe associate more than one openedBuild. */
|
||||
foreach($datas as $buildIDList => $data)
|
||||
@@ -3023,6 +3023,8 @@ class bugModel extends model
|
||||
}
|
||||
|
||||
$allBranch = "`branch` = 'all'";
|
||||
$branch = trim($branch, ',');
|
||||
if(strpos($branch, ',') !== false) $branch = str_replace(',', "','", $branch);
|
||||
if($branch !== 'all' and strpos($bugQuery, '`branch` =') === false) $bugQuery .= " AND `branch` in('0','$branch')";
|
||||
if(strpos($bugQuery, $allBranch) !== false) $bugQuery = str_replace($allBranch, '1', $bugQuery);
|
||||
|
||||
|
||||
@@ -58,6 +58,6 @@
|
||||
</div>
|
||||
<?php
|
||||
js::set('productID', $bug->product);
|
||||
js::set('releasedBuild', $lang->build->releasedBuild);
|
||||
js::set('released', $lang->build->released);
|
||||
?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
include '../../common/view/header.html.php';
|
||||
js::set('requiredFields', $config->bug->create->requiredFields);
|
||||
js::set('productID', $productID);
|
||||
js::set('releasedBuild', $lang->build->releasedBuild);
|
||||
js::set('released', $lang->build->released);
|
||||
?>
|
||||
<?php
|
||||
$visibleFields = array();
|
||||
|
||||
@@ -328,7 +328,7 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow
|
||||
{
|
||||
$actionLink = $this->createLink('bug', 'batchResolve', "resolution=fixed&resolvedBuild=$key");
|
||||
echo "<li class='option' data-key='$key'>";
|
||||
echo html::a('javascript:;', (in_array($key, $releasedBuilds) ? "<span class='label label-primary label-outline'>{$lang->build->releasedBuild}</span> " : '') . $build, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#bugList')\"");
|
||||
echo html::a('javascript:;', $build . (in_array($key, $releasedBuilds) ? " <span class='label label-primary label-outline'>{$lang->build->released}</span> " : ''), '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#bugList')\"");
|
||||
echo "</li>";
|
||||
}
|
||||
echo "</ul>";
|
||||
|
||||
@@ -31,7 +31,7 @@ js::set('requiredFields', $config->bug->create->requiredFields);
|
||||
js::set('showFields', $showFields);
|
||||
js::set('projectExecutionPairs', $projectExecutionPairs);
|
||||
js::set('productID', $productID);
|
||||
js::set('releasedBuild', $lang->build->releasedBuild);
|
||||
js::set('released', $lang->build->released);
|
||||
if($this->app->tab == 'execution') js::set('objectID', zget($execution, 'id', ''));
|
||||
if($this->app->tab == 'project') js::set('objectID', $projectID);
|
||||
?>
|
||||
|
||||
@@ -31,7 +31,7 @@ js::set('bugBranch' , $bug->branch);
|
||||
js::set('isClosedBug' , $bug->status == 'closed');
|
||||
js::set('projectExecutionPairs' , $projectExecutionPairs);
|
||||
js::set('productID' , $product->id);
|
||||
js::set('releasedBuild' , $lang->build->releasedBuild);
|
||||
js::set('released' , $lang->build->released);
|
||||
if($this->app->tab == 'execution') js::set('objectID', $bug->execution);
|
||||
if($this->app->tab == 'project') js::set('objectID', $bug->project);
|
||||
?>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<?php
|
||||
js::set('page', 'resolve');
|
||||
js::set('productID', $bug->product);
|
||||
js::set('releasedBuild', $lang->build->releasedBuild);
|
||||
js::set('released', $lang->build->released);
|
||||
?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='center-block'>
|
||||
|
||||
+145
-12
@@ -144,6 +144,8 @@ class build extends control
|
||||
$changes = $this->build->update($buildID);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
$files = $this->loadModel('file')->saveUpload('build', $buildID);
|
||||
$change[$buildID] = $changes;
|
||||
$this->unlinkOldBranch($change);
|
||||
|
||||
if($changes or $files)
|
||||
{
|
||||
@@ -162,6 +164,7 @@ class build extends control
|
||||
$this->loadModel('execution');
|
||||
$this->loadModel('product');
|
||||
$build = $this->build->getById((int)$buildID);
|
||||
$oldBranch = array($buildID => $build->branch);
|
||||
|
||||
/* Set menu. */
|
||||
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($build->project);
|
||||
@@ -177,10 +180,11 @@ class build extends control
|
||||
{
|
||||
$productGroups = $this->product->getProducts($build->project);
|
||||
$branches = $this->loadModel('branch')->getList($build->product, $build->project, 'all');
|
||||
$builds = $this->build->getBuildPairs($build->product, $build->branch, 'noempty,notrunk,singled,separate', $build->project, 'project', $build->builds, false);
|
||||
$builds = $this->build->getBuildPairs($build->product, 'all', 'noempty,notrunk,singled,separate', $build->project, 'project', $build->builds, false);
|
||||
}
|
||||
|
||||
$executions = $this->product->getExecutionPairsByProduct($build->product, $build->branch, 'id_desc', $this->session->project, 'stagefilter');
|
||||
if($build->execution and !isset($executions[$build->execution])) $executions[$build->execution] = $this->loadModel('execution')->getById($build->execution)->name;
|
||||
|
||||
/* Get stories and bugs. */
|
||||
$orderBy = 'status_asc, stage_asc, id_desc';
|
||||
@@ -198,7 +202,10 @@ class build extends control
|
||||
{
|
||||
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
|
||||
}
|
||||
if(!isset($branchTagOption[$build->branch])) $branchTagOption[$build->branch] = $this->branch->getById($build->branch, 0, 'name');
|
||||
foreach(explode(',', $build->branch) as $buildBranch)
|
||||
{
|
||||
if(!isset($branchTagOption[$buildBranch])) $branchTagOption[$buildBranch] = $this->branch->getById($buildBranch, 0, 'name');
|
||||
}
|
||||
|
||||
foreach($productGroups as $product) $products[$product->id] = $product->name;
|
||||
|
||||
@@ -209,6 +216,7 @@ class build extends control
|
||||
$this->view->product = isset($productGroups[$build->product]) ? $productGroups[$build->product] : '';
|
||||
$this->view->branchTagOption = $branchTagOption;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->oldBranch = $oldBranch;
|
||||
$this->view->executions = $executions;
|
||||
$this->view->productGroups = $productGroups;
|
||||
$this->view->products = $products;
|
||||
@@ -279,6 +287,8 @@ class build extends control
|
||||
foreach($stages as $storyID => $stage) $stories[$storyID]->stage = $stage;
|
||||
|
||||
/* Set menu. */
|
||||
$objectType = 'execution';
|
||||
$objectID = $build->execution;
|
||||
if($this->app->tab == 'project')
|
||||
{
|
||||
$this->loadModel('project')->setMenu($build->project);
|
||||
@@ -305,6 +315,16 @@ class build extends control
|
||||
$this->view->generatedBugPager = $generatedBugPager;
|
||||
|
||||
$this->executeHooks($buildID);
|
||||
$branchName = '';
|
||||
if($build->productType != 'normal')
|
||||
{
|
||||
foreach(explode(',', $build->branch) as $buildBranch)
|
||||
{
|
||||
$branchName .= $this->loadModel('branch')->getById($buildBranch);
|
||||
$branchName .= ',';
|
||||
}
|
||||
$branchName = trim($branchName, ',');
|
||||
}
|
||||
|
||||
/* Assign. */
|
||||
$this->view->canBeChanged = common::canBeChanged('build', $build); // Determines whether an object is editable.
|
||||
@@ -320,7 +340,8 @@ class build extends control
|
||||
$this->view->bugs = $bugs;
|
||||
$this->view->type = $type;
|
||||
$this->view->bugPager = $bugPager;
|
||||
$this->view->branchName = $build->productType == 'normal' ? '' : $this->loadModel('branch')->getById($build->branch);
|
||||
$this->view->branchName = empty($branchName) ? $this->lang->branch->main : $branchName;
|
||||
$this->view->childBuilds = empty($build->builds) ? array() : $this->dao->select('id,name,bugs,stories')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchAll();
|
||||
|
||||
if($this->app->getViewType() == 'json')
|
||||
{
|
||||
@@ -413,7 +434,7 @@ class build extends control
|
||||
return print(html::select($varName, $builds, $build, "class='form-control'"));
|
||||
}
|
||||
|
||||
$builds = $this->build->getBuildPairs($productID, $branch, $type, 0, 'project', $build);
|
||||
$builds = $this->build->getBuildPairs($productID, $branch, $type, 0, 'project', $build, false);
|
||||
if(strpos($extra, 'multiple') !== false) $varName .= '[]';
|
||||
if($isJsonView) return print(json_encode($builds));
|
||||
return print(html::select($varName, $builds, $build, "class='form-control chosen' $extra"));
|
||||
@@ -624,8 +645,16 @@ class build extends control
|
||||
else
|
||||
{
|
||||
$branchPairs = $this->loadModel('branch')->getPairs($build->product, 'noempty');
|
||||
$branches = array('' => '') + array(BRANCH_MAIN => $this->lang->branch->main);
|
||||
if($build->branch) $branches += array($build->branch => $branchPairs[$build->branch]);
|
||||
$branchAll = sprintf($this->lang->build->branchAll, $this->lang->product->branchName[$product->type]);
|
||||
$branches = array('' => $branchAll) + array(BRANCH_MAIN => $this->lang->branch->main);
|
||||
if($build->branch)
|
||||
{
|
||||
foreach(explode(',', $build->branch) as $branchID)
|
||||
{
|
||||
if($branchID == '0') continue;
|
||||
$branches += array($branchID => $branchPairs[$branchID]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->config->product->search['fields']['branch'] = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
$this->config->product->search['params']['branch']['values'] = $branches;
|
||||
@@ -655,22 +684,82 @@ class build extends control
|
||||
/**
|
||||
* Unlink story
|
||||
*
|
||||
* @param int $buildID
|
||||
* @param int $storyID
|
||||
* @param string $confirm yes|no
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function unlinkStory($buildID, $storyID)
|
||||
public function unlinkStory($buildID, $storyID, $confirm = 'no')
|
||||
{
|
||||
$this->build->unlinkStory($buildID, $storyID);
|
||||
if($confirm == 'no')
|
||||
{
|
||||
return print(js::confirm($this->lang->build->confirmUnlinkStory, inlink('unlinkstory', "buildID=$buildID&storyID=$storyID&confirm=yes")));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->build->unlinkStory($buildID, $storyID);
|
||||
$this->loadModel('action')->create('build', $buildID, 'unlinkstory', '', $storyID);
|
||||
return print(js::reload('parent'));
|
||||
}
|
||||
}
|
||||
|
||||
return print(js::reload('parent'));
|
||||
/**
|
||||
* AJAX: Get unlinkBranch story and bug.
|
||||
*
|
||||
* @param int $buildID
|
||||
* @param int $newBranch
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetBranch($buildID, $newBranch)
|
||||
{
|
||||
$build = $this->build->getByID($buildID);
|
||||
$oldBranch = $build->branch;
|
||||
$buildStories = $build->allStories ? $this->loadModel('story')->getByList($build->allStories) : array();
|
||||
$buildBugs = $build->allBugs ? $this->loadModel('bug')->getByList($build->allBugs) : array();
|
||||
$branchPairs = $this->loadModel('branch')->getPairs($build->product);
|
||||
$typeName = $this->lang->product->branchName[$build->productType];
|
||||
|
||||
$removeBranches = '';
|
||||
foreach(explode(',', $oldBranch) as $oldBranchID)
|
||||
{
|
||||
if($oldBranchID and strpos(",$newBranch,", ",$oldBranchID,") === false) $removeBranches .= "{$branchPairs[$oldBranchID]},";
|
||||
}
|
||||
|
||||
$unlinkStoryCounts = 0;
|
||||
$unlinkBugCounts = 0;
|
||||
if($oldBranch)
|
||||
{
|
||||
foreach($buildStories as $storyID => $story)
|
||||
{
|
||||
if($story->branch and strpos(",$newBranch,", ",$story->branch,") === false) $unlinkStoryCounts ++;
|
||||
}
|
||||
|
||||
foreach($buildBugs as $bugID => $bug)
|
||||
{
|
||||
if($bug->branch and strpos(",$newBranch,", ",$bug->branch,") === false) $unlinkBugCounts ++;
|
||||
}
|
||||
}
|
||||
|
||||
if($unlinkStoryCounts and $unlinkBugCounts)
|
||||
{
|
||||
printf($this->lang->build->confirmChangeBuild, $typeName, trim($removeBranches, ','), $typeName, $unlinkStoryCounts, $unlinkBugCounts);
|
||||
}
|
||||
elseif($unlinkStoryCounts)
|
||||
{
|
||||
printf($this->lang->build->confirmRemoveStory, $typeName, trim($removeBranches, ','), $typeName, $unlinkStoryCounts);
|
||||
}
|
||||
elseif($unlinkBugCounts)
|
||||
{
|
||||
printf($this->lang->build->confirmRemoveBug, $typeName, trim($removeBranches, ','), $typeName, $unlinkBugCounts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch unlink story.
|
||||
*
|
||||
* @param string $confirm
|
||||
* @param int $buildID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
@@ -680,6 +769,45 @@ class build extends control
|
||||
return print(js::locate($this->createLink('build', 'view', "buildID=$buildID&type=story"), 'parent'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink story and bug when edit branch of build.
|
||||
* @param array $changes
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function unlinkOldBranch($changes)
|
||||
{
|
||||
foreach($changes as $buildID => $changes)
|
||||
{
|
||||
$oldBranch = '';
|
||||
$newBranch = '';
|
||||
foreach($changes as $changeId => $change)
|
||||
{
|
||||
if($change['field'] == 'branch')
|
||||
{
|
||||
$oldBranch = $change['old'];
|
||||
$newBranch = $change['new'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
$build = $this->build->getByID($buildID);
|
||||
$planStories = $this->loadModel('story')->getByList($build->allStories);
|
||||
$planBugs = $this->loadModel('bug')->getByList($build->allBugs);
|
||||
if($oldBranch)
|
||||
{
|
||||
foreach($planStories as $storyID => $story)
|
||||
{
|
||||
if($story->branch and strpos(",$newBranch,", ",$story->branch,") === false) $this->build->unlinkStory($buildID, $storyID);
|
||||
}
|
||||
|
||||
foreach($planBugs as $bugID => $bug)
|
||||
{
|
||||
if($bug->branch and strpos(",$newBranch,", ",$bug->branch,") === false) $this->build->unlinkBug($buildID, $bugID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Link bugs.
|
||||
*
|
||||
@@ -748,8 +876,13 @@ class build extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
$branchName = $this->loadModel('branch')->getById($build->branch);
|
||||
$branches = array('' => '', BRANCH_MAIN => $this->lang->branch->main, $build->branch => $branchName);
|
||||
$buildBranch = array();
|
||||
$branchList = $this->loadModel('branch')->getPairs($build->product, '', $build->execution);
|
||||
$branchAll = sprintf($this->lang->build->branchAll, $this->lang->product->branchName[$product->type]);
|
||||
$branches = array('' => $branchAll, BRANCH_MAIN => $this->lang->branch->main);
|
||||
if(strpos($build->branch, ',') !== false) $buildBranch = explode(',', $build->branch);
|
||||
foreach($buildBranch as $buildKey) $branches += array($buildKey => zget($branchList, $buildKey));
|
||||
|
||||
|
||||
$this->config->bug->search['fields']['branch'] = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
$this->config->bug->search['params']['branch']['values'] = $branches;
|
||||
|
||||
@@ -1,8 +1,27 @@
|
||||
.linkBox #queryBox .search-form .form-actions {padding-bottom: 5px;}
|
||||
.linkBox .table-header {padding: 8px 15px; border-bottom: 1px solid #cbd0db;}
|
||||
#unlinkStoryList, #unlinkBugList {border-top: 1px solid #cbd0db;}
|
||||
.page-title .dropdown-menu {top: 20px; left: 170px;}
|
||||
.page-title .dropdown-menu {top: 20px; left: 170px; max-height:300px; overflow:auto;}
|
||||
.page-title .text>a {font-weight: 700;}
|
||||
|
||||
.body-modal #mainContent {min-height: 200px;}
|
||||
td.article-content{overflow:auto !important;}
|
||||
td.c-build{white-space: nowrap; overflow:hidden;}
|
||||
th.c-user,td.c-user{text-align:left;}
|
||||
|
||||
#stories th, #stories td{padding-left:16px;padding-right:16px;}
|
||||
#stories .c-build{width:160px; text-align:left}
|
||||
#stories .c-estimate{width:90px; text-align:right}
|
||||
#stories .c-status{width:120px}
|
||||
#stories .c-stage{width:130px; text-align:left;}
|
||||
#bugs .c-status{width:100px;}
|
||||
#bugs .c-build{width:160px; text-align:left}
|
||||
#bugs .c-user{width:120px;}
|
||||
#bugs .c-date{width:130px;}
|
||||
#bugs .c-actions-1{width:60px;}
|
||||
#generatedBugs .c-id {width:60px;}
|
||||
#generatedBugs .c-severity {width:70px;}
|
||||
#generatedBugs .c-status {width:100px;}
|
||||
#generatedBugs .c-build {width:160px; text-align:left}
|
||||
#generatedBugs .c-user {width:100px;}
|
||||
#generatedBugs .c-date {width:120px;}
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
*/
|
||||
function loadBranches(productID)
|
||||
{
|
||||
if($('input[name=isIntegrated]:checked').val() == 'yes')
|
||||
{
|
||||
$('#branchBox').closest('tr').addClass('hidden');
|
||||
return false;
|
||||
}
|
||||
$('#branch').remove();
|
||||
$('#branch_chosen').remove();
|
||||
var oldBranch = 0;
|
||||
@@ -16,12 +21,17 @@ function loadBranches(productID)
|
||||
}
|
||||
|
||||
projectID = currentTab == 'execution' ? executionID : projectID;
|
||||
$.get(createLink('branch', 'ajaxGetBranches', 'productID=' + productID + '&oldBranch=0¶m=active&projectID=' + projectID), function(data)
|
||||
$.get(createLink('branch', 'ajaxGetBranches', 'productID=' + productID + '&oldBranch=0¶m=active&projectID=' + projectID + '&withMainBranch=true&isSiblings=no&fieldID=0&multiple=multiple'), function(data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
$('#product').closest('.input-group').append(data);
|
||||
$('#branchBox').append(data);
|
||||
$('#branch').chosen();
|
||||
$('#branchBox').closest('tr').removeClass('hidden');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#branchBox').closest('tr').addClass('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,18 +9,23 @@ $().ready(function()
|
||||
{
|
||||
var projectID = $('#project').val();
|
||||
var productID = $('#product').val();
|
||||
var branch = $('#branch').length > 0 ? $('#branch').val() : '';
|
||||
$.get(createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=builds&build=&branch=' + branch + '&index=&needCreate=&type=noempty,notrunk,separate,singled&extra=multiple'), function(data)
|
||||
$.get(createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=builds&build=&branch=all&index=&needCreate=&type=noempty,notrunk,separate,singled&extra=multiple'), function(data)
|
||||
{
|
||||
if(data) $('#buildBox').html(data);
|
||||
$('#builds').attr('data-placeholder', multipleSelect).chosen();
|
||||
});
|
||||
|
||||
$.get(createLink('product', 'ajaxGetProductById', 'produtID=' + productID), function(data)
|
||||
{
|
||||
$('#branchBox').closest('tr').find('th').text(data.branchName);
|
||||
}, 'json');
|
||||
});
|
||||
|
||||
$('input[name=isIntegrated]').change(function()
|
||||
{
|
||||
var projectID = $('#project').val();
|
||||
var executionID = $('#execution').val();
|
||||
|
||||
if($(this).val() == 'no')
|
||||
{
|
||||
$('#execution').closest('tr').show();
|
||||
@@ -31,7 +36,16 @@ $().ready(function()
|
||||
{
|
||||
$('#execution').closest('tr').hide();
|
||||
$('#buildBox').closest('tr').show();
|
||||
|
||||
$.ajaxSettings.async = false;
|
||||
loadProducts(projectID);
|
||||
var productID = $('#product').val();
|
||||
$.get(createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=builds&build=&branch=all&index=&needCreate=&type=noempty,notrunk,separate,singled&extra=multiple'), function(data)
|
||||
{
|
||||
if(data) $('#buildBox').html(data);
|
||||
$('#builds').attr('data-placeholder', multipleSelect).chosen();
|
||||
});
|
||||
$.ajaxSettings.async = true;
|
||||
}
|
||||
});
|
||||
$('#product').change();
|
||||
@@ -67,9 +81,16 @@ function loadProducts(executionID)
|
||||
|
||||
$('#productBox').append(data);
|
||||
$('#product').chosen();
|
||||
|
||||
$.get(createLink('product', 'ajaxGetProductById', 'produtID=' + $("#product").val()), function(data)
|
||||
{
|
||||
$('#branchBox').closest('tr').find('th').text(data.branchName);
|
||||
}, 'json');
|
||||
|
||||
loadBranches($("#product").val());
|
||||
}
|
||||
});
|
||||
|
||||
loadLastBuild();
|
||||
}
|
||||
|
||||
@@ -84,7 +105,7 @@ function loadLastBuild()
|
||||
var isIntegrated = $('input[name=isIntegrated]:checked').val();
|
||||
var projectID = $('#project').val();
|
||||
var executionID = $('#execution').val();
|
||||
if(isIntegrated == 'yes') executionID = 0;
|
||||
if(isIntegrated == 'yes') executionID = 0;
|
||||
$.get(createLink('build', 'ajaxGetLastBuild', 'projectID=' + projectID + '&executionID=' + executionID), function(data)
|
||||
{
|
||||
$('#lastBuildBox').html(data);
|
||||
|
||||
+22
-3
@@ -3,20 +3,39 @@ $().ready(function()
|
||||
var oldExecutionID = $('#execution').val();
|
||||
$(document).on('change', '#product, #branch', function()
|
||||
{
|
||||
var productID = $('#product').val();
|
||||
|
||||
if(executionID)
|
||||
{
|
||||
loadExecutions(oldExecutionID);
|
||||
}
|
||||
else
|
||||
{
|
||||
var productID = $('#product').val();
|
||||
var branch = $('#branch').val();
|
||||
$.get(createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=builds&build=&branch=' + branch + '&index=&needCreate=&type=noempty,notrunk,separate,singled&extra=multiple'), function(data)
|
||||
$.get(createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=builds&build=&branch=all&index=&needCreate=&type=noempty,notrunk,separate,singled&extra=multiple'), function(data)
|
||||
{
|
||||
if(data) $('#buildBox').html(data);
|
||||
$('#builds').attr('data-placeholder', multipleSelect).chosen();
|
||||
});
|
||||
}
|
||||
|
||||
var newBranch = $('#branch').val() ? $('#branch').val().toString() : '';
|
||||
$.get(createLink('build', 'ajaxGetBranch', 'buildID=' + buildID + '&newBranch=' + newBranch), function(unlinkBranch)
|
||||
{
|
||||
if(unlinkBranch != '')
|
||||
{
|
||||
var result = confirm(unlinkBranch) ? true : false;
|
||||
if(!result)
|
||||
{
|
||||
$('#branch').val(oldBranch[buildID].split(','));
|
||||
$('#branch').trigger("chosen:updated");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.get(createLink('product', 'ajaxGetProductById', 'produtID=' + productID), function(data)
|
||||
{
|
||||
$('#branchBox').closest('tr').find('th').text(data.branchName);
|
||||
}, 'json');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -31,15 +31,17 @@ $lang->build->id = 'ID';
|
||||
$lang->build->product = $lang->productCommon;
|
||||
$lang->build->project = 'Project';
|
||||
$lang->build->branch = 'Platform/Branch';
|
||||
$lang->build->branchAll = 'All associated %s';
|
||||
$lang->build->branchName = '%s';
|
||||
$lang->build->execution = $lang->executionCommon;
|
||||
$lang->build->integrated = 'Integrated';
|
||||
$lang->build->singled = 'Singled';
|
||||
$lang->build->builds = 'Included Builds';
|
||||
$lang->build->releasedBuild = 'Released Build';
|
||||
$lang->build->released = 'Released';
|
||||
$lang->build->name = 'Name';
|
||||
$lang->build->date = 'Datum';
|
||||
$lang->build->builder = 'Builder';
|
||||
$lang->build->url = 'URL';
|
||||
$lang->build->scmPath = 'SCM Pfad';
|
||||
$lang->build->filePath = 'Dateipfad';
|
||||
$lang->build->desc = 'Beschreibung';
|
||||
@@ -54,7 +56,8 @@ $lang->build->bugs = 'Gelöster Bug';
|
||||
$lang->build->generatedBugs = 'Left Bug';
|
||||
$lang->build->noProduct = " <span id='noProduct' style='color:red'>Dieses {$lang->executionCommon} ist nicht mit einem {$lang->productCommon} verknüpft, daher kann das Build nicht erstellt werden. Bitte erst <a href='%s' data-app='%s' data-toggle='modal' data-type='iframe'> {$lang->productCommon} verknüpfen.</a></span>";
|
||||
$lang->build->noBuild = 'Keine Builds. ';
|
||||
$lang->build->emptyExecution = $lang->executionCommon . 'should be not empty.';
|
||||
$lang->build->emptyExecution = $lang->executionCommon . 'should be not empty.';
|
||||
$lang->build->linkedBuild = 'Linked Build';
|
||||
|
||||
$lang->build->notice = new stdclass();
|
||||
$lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the version of the submitted test order has been linked, and its {$lang->productCommon} cannot be modified";
|
||||
@@ -63,6 +66,11 @@ $lang->build->notice->changeBuilds = "The version of the submitted test order
|
||||
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
|
||||
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
|
||||
|
||||
$lang->build->confirmChangeBuild = "After branch『%s』disassociation,under the %s have %s {$lang->SRCommon} and %s Bug will remove synchronization from version, whether to cancel?";
|
||||
$lang->build->confirmRemoveStory = "After branch『%s』disassociation,under the %s have %s {$lang->SRCommon} will remove synchronization from version, whether to cancel?";
|
||||
$lang->build->confirmRemoveBug = "After branch『%s』disassociation,under the %s have %s Bug will remove synchronization from version, whether to cancel?";
|
||||
$lang->build->confirmRemoveTips = "Are you sure to delete %s『%s』?";
|
||||
|
||||
$lang->build->finishStories = " %s {$lang->SRCommon} sind abgeschlossen.";
|
||||
$lang->build->resolvedBugs = ' %s Bugs sind gelöst.';
|
||||
$lang->build->createdBugs = ' %s Bugs wurden erstellt.';
|
||||
|
||||
@@ -31,15 +31,17 @@ $lang->build->id = 'ID';
|
||||
$lang->build->product = $lang->productCommon;
|
||||
$lang->build->project = 'Project';
|
||||
$lang->build->branch = 'Platform/Branch';
|
||||
$lang->build->branchAll = 'All associated %s';
|
||||
$lang->build->branchName = '%s';
|
||||
$lang->build->execution = $lang->executionCommon;
|
||||
$lang->build->integrated = 'Integrated';
|
||||
$lang->build->singled = 'Singled';
|
||||
$lang->build->builds = 'Included Builds';
|
||||
$lang->build->releasedBuild = 'Released Build';
|
||||
$lang->build->released = 'Released';
|
||||
$lang->build->name = 'Name';
|
||||
$lang->build->date = 'Date';
|
||||
$lang->build->builder = 'Builder';
|
||||
$lang->build->url = 'URL';
|
||||
$lang->build->scmPath = 'SCM Path';
|
||||
$lang->build->filePath = 'File Path';
|
||||
$lang->build->desc = 'Description';
|
||||
@@ -54,7 +56,8 @@ $lang->build->bugs = 'Resolved Bugs';
|
||||
$lang->build->generatedBugs = 'Reported Bugs';
|
||||
$lang->build->noProduct = " <span id='noProduct' style='color:red'>This {$lang->executionCommon} is not linked to {$lang->productCommon}, so the Build cannot be created. Please first <a href='%s' data-app='%s' data-toggle='modal' data-type='iframe'> link {$lang->productCommon}</a></span>";
|
||||
$lang->build->noBuild = 'No builds yet.';
|
||||
$lang->build->emptyExecution = $lang->executionCommon . 'should be not empty.';
|
||||
$lang->build->emptyExecution = $lang->executionCommon . 'should be not empty.';
|
||||
$lang->build->linkedBuild = 'Linked Build';
|
||||
|
||||
$lang->build->notice = new stdclass();
|
||||
$lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the version of the submitted test order has been linked, and its {$lang->productCommon} cannot be modified";
|
||||
@@ -63,6 +66,11 @@ $lang->build->notice->changeBuilds = "The version of the submitted test order
|
||||
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
|
||||
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
|
||||
|
||||
$lang->build->confirmChangeBuild = "After branch『%s』disassociation,under the %s have %s {$lang->SRCommon} and %s Bug will remove synchronization from version, whether to cancel?";
|
||||
$lang->build->confirmRemoveStory = "After branch『%s』disassociation,under the %s have %s {$lang->SRCommon} will remove synchronization from version, whether to cancel?";
|
||||
$lang->build->confirmRemoveBug = "After branch『%s』disassociation,under the %s have %s Bug will remove synchronization from version, whether to cancel?";
|
||||
$lang->build->confirmRemoveTips = "Are you sure to delete %s『%s』?";
|
||||
|
||||
$lang->build->finishStories = " Finished {$lang->SRCommon} %s";
|
||||
$lang->build->resolvedBugs = ' Resolved Bug %s';
|
||||
$lang->build->createdBugs = ' Reported Bug %s';
|
||||
|
||||
@@ -31,15 +31,17 @@ $lang->build->id = 'ID';
|
||||
$lang->build->product = $lang->productCommon;
|
||||
$lang->build->project = 'Project';
|
||||
$lang->build->branch = 'Plateforme/Branche';
|
||||
$lang->build->branchAll = 'All associated %s';
|
||||
$lang->build->branchName = '%s';
|
||||
$lang->build->execution = $lang->executionCommon;
|
||||
$lang->build->integrated = 'Integrated';
|
||||
$lang->build->singled = 'Singled';
|
||||
$lang->build->builds = 'Included Builds';
|
||||
$lang->build->releasedBuild = 'Released Build';
|
||||
$lang->build->released = 'Released';
|
||||
$lang->build->name = 'Nom';
|
||||
$lang->build->date = 'Date';
|
||||
$lang->build->builder = 'Builder';
|
||||
$lang->build->url = 'URL';
|
||||
$lang->build->scmPath = 'Chemin SCM';
|
||||
$lang->build->filePath = 'Chemin Fichier';
|
||||
$lang->build->desc = 'Description';
|
||||
@@ -54,7 +56,8 @@ $lang->build->bugs = 'Bugs Résolus';
|
||||
$lang->build->generatedBugs = 'Bugs signalés';
|
||||
$lang->build->noProduct = " <span id='noProduct' style='color:red'>Ce {$lang->executionCommon} n'est pas associé à un {$lang->productCommon}, le Build ne peut pas être créé. Commencez par <a href='%s' data-app='%s' data-toggle='modal' data-type='iframe'>rattacher le projet à un {$lang->productCommon}</a></span>";
|
||||
$lang->build->noBuild = 'Aucun builds.';
|
||||
$lang->build->emptyExecution = $lang->executionCommon . 'should be not empty.';
|
||||
$lang->build->emptyExecution = $lang->executionCommon . 'should be not empty.';
|
||||
$lang->build->linkedBuild = 'Linked Build';
|
||||
|
||||
$lang->build->notice = new stdclass();
|
||||
$lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the version of the submitted test order has been linked, and its {$lang->productCommon} cannot be modified";
|
||||
@@ -63,6 +66,11 @@ $lang->build->notice->changeBuilds = "The version of the submitted test order
|
||||
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
|
||||
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
|
||||
|
||||
$lang->build->confirmChangeBuild = "After branch『%s』disassociation,under the %s have %s {$lang->SRCommon} and %s Bug will remove synchronization from version, whether to cancel?";
|
||||
$lang->build->confirmRemoveStory = "After branch『%s』disassociation,under the %s have %s {$lang->SRCommon} will remove synchronization from version, whether to cancel?";
|
||||
$lang->build->confirmRemoveBug = "After branch『%s』disassociation,under the %s have %s Bug will remove synchronization from version, whether to cancel?";
|
||||
$lang->build->confirmRemoveTips = "Are you sure to delete %s『%s』?";
|
||||
|
||||
$lang->build->finishStories = " {$lang->SRCommon} Terminées %s";
|
||||
$lang->build->resolvedBugs = ' Bugs Résolus %s';
|
||||
$lang->build->createdBugs = ' Bugs Signalés %s';
|
||||
|
||||
@@ -31,15 +31,17 @@ $lang->build->id = 'ID';
|
||||
$lang->build->product = '所属' . $lang->productCommon;
|
||||
$lang->build->project = '所属项目';
|
||||
$lang->build->branch = '平台/分支';
|
||||
$lang->build->branchAll = '所有关联%s';
|
||||
$lang->build->branchName = '所属%s';
|
||||
$lang->build->execution = '所属' . $lang->executionCommon;
|
||||
$lang->build->integrated = '集成版本';
|
||||
$lang->build->singled = '单一版本';
|
||||
$lang->build->builds = '包含版本';
|
||||
$lang->build->releasedBuild = '发布版本';
|
||||
$lang->build->released = '发布';
|
||||
$lang->build->name = '名称编号';
|
||||
$lang->build->date = '打包日期';
|
||||
$lang->build->builder = '构建者';
|
||||
$lang->build->url = '地址';
|
||||
$lang->build->scmPath = '源代码地址';
|
||||
$lang->build->filePath = '下载地址';
|
||||
$lang->build->desc = '描述';
|
||||
@@ -54,7 +56,8 @@ $lang->build->bugs = '解决的Bug';
|
||||
$lang->build->generatedBugs = '产生的Bug';
|
||||
$lang->build->noProduct = " <span id='noProduct' style='color:red'>该{$lang->executionCommon}没有关联{$lang->productCommon},无法创建版本,请先<a href='%s' data-app='%s' data-toggle='modal' data-type='iframe'>关联{$lang->productCommon}</a></span>";
|
||||
$lang->build->noBuild = '暂时没有版本。';
|
||||
$lang->build->emptyExecution = $lang->executionCommon . '不能为空。';
|
||||
$lang->build->emptyExecution = $lang->executionCommon . '不能为空。';
|
||||
$lang->build->linkedBuild = '关联版本';
|
||||
|
||||
$lang->build->notice = new stdclass();
|
||||
$lang->build->notice->changeProduct = "已经关联{$lang->SRCommon}、Bug或提交测试单的版本,不能修改其所属{$lang->productCommon}";
|
||||
@@ -63,6 +66,11 @@ $lang->build->notice->changeBuilds = "提交测试单的版本,不能修改
|
||||
$lang->build->notice->autoRelation = "相关版本下完成的需求、解决的Bug、产生的Bug将会自动关联到项目版本中";
|
||||
$lang->build->notice->createTest = "该版本所属执行已删除,不能提交测试";
|
||||
|
||||
$lang->build->confirmChangeBuild = "%s『%s』解除关联后,%s下 %s个{$lang->SRCommon}和%s个Bug将同步从版本移除,是否解除?";
|
||||
$lang->build->confirmRemoveStory = "%s『%s』解除关联后,%s下 %s个{$lang->SRCommon}将同步从计划中移除,是否解除?";
|
||||
$lang->build->confirmRemoveBug = "%s『%s』解除关联后,%s下 %s个Bug将同步从计划中移除,是否解除?";
|
||||
$lang->build->confirmRemoveTips = "确认删除%s『%s』吗?";
|
||||
|
||||
$lang->build->finishStories = " 本次共完成 %s 个{$lang->SRCommon}";
|
||||
$lang->build->resolvedBugs = ' 本次共解决 %s 个Bug';
|
||||
$lang->build->createdBugs = ' 本次共产生 %s 个Bug';
|
||||
|
||||
@@ -31,6 +31,7 @@ $lang->build->id = 'ID';
|
||||
$lang->build->product = $lang->productCommon;
|
||||
$lang->build->project = '所屬項目';
|
||||
$lang->build->branch = '平台/分支';
|
||||
$lang->build->branchAll = '所有關聯%s';
|
||||
$lang->build->branchName = '所屬%s';
|
||||
$lang->build->execution = '所屬' . $lang->executionCommon;
|
||||
$lang->build->name = '名稱編號';
|
||||
|
||||
+88
-13
@@ -63,11 +63,10 @@ class buildModel extends model
|
||||
*/
|
||||
public function getProjectBuilds($projectID = 0, $type = 'all', $param = 0, $orderBy = 't1.date_desc,t1.id_desc', $pager = null)
|
||||
{
|
||||
return $this->dao->select('t1.*, t2.name as executionName, t2.id as executionID, t3.name as productName, t4.name as branchName')
|
||||
return $this->dao->select('t1.*, t2.name as executionName, t2.id as executionID, t2.deleted as executionDeleted, t3.name as productName')
|
||||
->from(TABLE_BUILD)->alias('t1')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id')
|
||||
->leftJoin(TABLE_BRANCH)->alias('t4')->on('t1.branch = t4.id')
|
||||
->where('t1.deleted')->eq(0)
|
||||
->andWhere('t1.project')->ne(0)
|
||||
->beginIF($projectID)->andWhere('t1.project')->eq((int)$projectID)->fi()
|
||||
@@ -129,11 +128,10 @@ class buildModel extends model
|
||||
*/
|
||||
public function getExecutionBuilds($executionID, $type = '', $param = '', $orderBy = 't1.date_desc,t1.id_desc', $pager = null)
|
||||
{
|
||||
return $this->dao->select('t1.*, t2.name as executionName, t3.name as productName, t4.name as branchName')
|
||||
return $this->dao->select('t1.*, t2.name as executionName, t3.name as productName')
|
||||
->from(TABLE_BUILD)->alias('t1')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id')
|
||||
->leftJoin(TABLE_BRANCH)->alias('t4')->on('t1.branch = t4.id')
|
||||
->where('t1.deleted')->eq(0)
|
||||
->beginIF($executionID)->andWhere('t1.execution')->eq((int)$executionID)->fi()
|
||||
->beginIF($type == 'product' and $param)->andWhere('t1.product')->eq($param)->fi()
|
||||
@@ -255,9 +253,11 @@ class buildModel extends model
|
||||
->beginIF($products)->andWhere('product')->in($products)->fi()
|
||||
->beginIF($objectType === 'execution' and $objectID)->andWhere('execution')->eq($objectID)->fi()
|
||||
->beginIF($objectType === 'project' and $objectID)->andWhere('project')->eq($objectID)->fi()
|
||||
->beginIF(strpos($params, 'hasdeleted') === false)->andWhere('deleted')->eq(0)->fi()
|
||||
->fetchPairs();
|
||||
}
|
||||
|
||||
$shadows = $this->dao->select('shadow')->from(TABLE_RELEASE)->where('product')->in($products)->fetchPairs('shadow', 'shadow');
|
||||
$branchs = strpos($params, 'separate') === false ? "0,$branch" : $branch;
|
||||
$allBuilds = $this->dao->select('t1.id, t1.name, t1.execution, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName, t5.type as productType')->from(TABLE_BUILD)->alias('t1')
|
||||
->beginIF($objectType === 'execution')->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')->fi()
|
||||
@@ -266,7 +266,8 @@ class buildModel extends model
|
||||
->leftJoin(TABLE_BRANCH)->alias('t4')->on('t1.branch = t4.id')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t5')->on('t1.product = t5.id')
|
||||
->where('1=1')
|
||||
->beginIF(strpos($params, 'hasDeleted') === false)->andWhere('t1.deleted')->eq(0)->fi()
|
||||
->andWhere('t1.id')->notIN($shadows)
|
||||
->beginIF(strpos($params, 'hasdeleted') === false)->andWhere('t1.deleted')->eq(0)->fi()
|
||||
->beginIF(strpos($params, 'hasproject') !== false)->andWhere('t1.project')->ne(0)->fi()
|
||||
->beginIF(strpos($params, 'singled') !== false)->andWhere('t1.execution')->ne(0)->fi()
|
||||
->beginIF($products)->andWhere('t1.product')->in($products)->fi()
|
||||
@@ -327,7 +328,7 @@ class buildModel extends model
|
||||
$releaseName = $release->name;
|
||||
$branchName = $release->branchName ? $release->branchName : $this->lang->branch->main;
|
||||
if($release->productType != 'normal') $releaseName = (strpos($params, 'withbranch') !== false ? $branchName . '/' : '') . $releaseName;
|
||||
if(strpos($params, 'releasetag') !== false) $releaseName = "[{$this->lang->build->releasedBuild}] " . $releaseName;
|
||||
if(strpos($params, 'releasetag') !== false) $releaseName = $releaseName . " [{$this->lang->build->released}]";
|
||||
$builds[$release->date][$release->shadow] = $releaseName;
|
||||
foreach(explode(',', trim($release->build, ',')) as $buildID)
|
||||
{
|
||||
@@ -382,21 +383,44 @@ class buildModel extends model
|
||||
->setDefault('product', 0)
|
||||
->setDefault('branch', 0)
|
||||
->setDefault('builds', '')
|
||||
->cleanInt('product,branch')
|
||||
->cleanInt('product')
|
||||
->add('createdBy', $this->app->user->account)
|
||||
->add('createdDate', helper::now())
|
||||
->stripTags($this->config->build->editor->create['id'], $this->config->allowedTags)
|
||||
->join('builds', ',')
|
||||
->join('branch', ',')
|
||||
->remove('resolvedBy,allchecker,files,labels,isIntegrated,uid')
|
||||
->get();
|
||||
|
||||
if($this->post->isIntegrated == 'yes') $build->execution = 0;
|
||||
if($this->post->isIntegrated == 'yes')
|
||||
{
|
||||
$build->execution = 0;
|
||||
$branchPairs = $this->dao->select('branch')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchPairs();
|
||||
$relationBranch = array();
|
||||
foreach($branchPairs as $branches)
|
||||
{
|
||||
foreach(explode(',', $branches) as $branch)
|
||||
{
|
||||
if(!isset($relationBranch[$branch])) $relationBranch[$branch] = $branch;
|
||||
}
|
||||
}
|
||||
$build->branch = implode(',', $relationBranch);
|
||||
}
|
||||
|
||||
$product = $this->loadModel('product')->getByID($build->product);
|
||||
if(!empty($product) and $product->type != 'normal' and $this->post->isIntegrated == 'no' and !isset($_POST['branch']))
|
||||
{
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
dao::$errors['branch'] = sprintf($this->lang->error->notempty, $this->lang->product->branch);
|
||||
}
|
||||
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$build = $this->loadModel('file')->processImgURL($build, $this->config->build->editor->create['id'], $this->post->uid);
|
||||
$this->dao->insert(TABLE_BUILD)->data($build)
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->build->create->requiredFields, 'notempty')
|
||||
->check('name', 'unique', "product = {$build->product} AND branch = {$build->branch} AND deleted = '0'")
|
||||
->check('name', 'unique', "product = {$build->product} AND branch = '{$build->branch}' AND deleted = '0'")
|
||||
->checkFlow()
|
||||
->exec();
|
||||
|
||||
@@ -426,17 +450,67 @@ class buildModel extends model
|
||||
->setIF(!isset($_POST['branch']), 'branch', $oldBuild->branch)
|
||||
->setDefault('product', $oldBuild->product)
|
||||
->setDefault('builds', '')
|
||||
->cleanInt('product,branch,execution')
|
||||
->cleanInt('product,execution')
|
||||
->join('builds', ',')
|
||||
->join('branch', ',')
|
||||
->remove('allchecker,resolvedBy,files,labels,uid')
|
||||
->get();
|
||||
|
||||
if(empty($oldBuild->execution))
|
||||
{
|
||||
$buildBranch = array();
|
||||
foreach(explode(',', trim($build->branch, ',')) as $branchID) $buildBranch[$branchID] = $branchID;
|
||||
|
||||
/* Get delete builds. */
|
||||
$deleteBuilds = array();
|
||||
foreach(explode(',', $oldBuild->builds) as $oldBuildID)
|
||||
{
|
||||
if(empty($oldBuildID)) continue;
|
||||
if(strpos(",$newBuilds,", ",$oldBuildID,") === false) $deleteBuilds[$oldBuildID] = $oldBuildID;
|
||||
}
|
||||
|
||||
/* Delete the branch when the branch of the deleted build has no linked stories. */
|
||||
$deleteBuildBranches = $this->dao->select('branch')->from(TABLE_BUILD)->where('id')->in($deleteBuilds)->fetchPairs();
|
||||
$linkedStoryBranches = $this->dao->select('branch')->from(TABLE_STORY)->where('id')->in($oldBuild->stories)->fetchPairs('branch');
|
||||
foreach($deleteBuildBranches as $deleteBuildBranch)
|
||||
{
|
||||
foreach(explode(',', $deleteBuildBranch) as $deleteBuildBranchID)
|
||||
{
|
||||
if(empty($deleteBuildBranchID) or isset($linkedStoryBranches[$deleteBuildBranchID])) continue;
|
||||
unset($buildBranch[$deleteBuildBranchID]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add branch of new builds. */
|
||||
$newBuilds = isset($build->builds) ? $build->builds : '';
|
||||
$newBuildBranches = $this->dao->select('branch')->from(TABLE_BUILD)->where('id')->in($newBuilds)->fetchPairs();
|
||||
foreach($newBuildBranches as $newBuildBranch)
|
||||
{
|
||||
foreach(explode(',', $newBuildBranch) as $newBuildBranchID)
|
||||
{
|
||||
if(empty($newBuildBranchID)) continue;
|
||||
if(!isset($buildBranch[$newBuildBranchID])) $buildBranch[$newBuildBranchID] = $newBuildBranchID;
|
||||
}
|
||||
}
|
||||
|
||||
$build->branch = implode(',', $buildBranch);
|
||||
}
|
||||
|
||||
$product = $this->loadModel('product')->getByID($build->product);
|
||||
if(!empty($product) and $product->type != 'normal' and !isset($_POST['branch']) and isset($_POST['product']))
|
||||
{
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
dao::$errors['branch'] = sprintf($this->lang->error->notempty, $this->lang->product->branch);
|
||||
}
|
||||
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$build = $this->loadModel('file')->processImgURL($build, $this->config->build->editor->edit['id'], $this->post->uid);
|
||||
$this->dao->update(TABLE_BUILD)->data($build)
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->build->edit->requiredFields, 'notempty')
|
||||
->where('id')->eq($buildID)
|
||||
->check('name', 'unique', "id != $buildID AND product = {$build->product} AND branch = {$build->branch} AND deleted = '0'")
|
||||
->check('name', 'unique', "id != $buildID AND product = {$build->product} AND branch = '{$build->branch}' AND deleted = '0'")
|
||||
->checkFlow()
|
||||
->exec();
|
||||
if(isset($build->branch) and $oldBuild->branch != $build->branch) $this->dao->update(TABLE_RELEASE)->set('branch')->eq($build->branch)->where('build')->eq($buildID)->exec();
|
||||
@@ -511,6 +585,7 @@ class buildModel extends model
|
||||
|
||||
$this->loadModel('action');
|
||||
foreach($this->post->stories as $storyID) $this->action->create('story', $storyID, 'linked2build', '', $buildID);
|
||||
$this->action->create('build', $buildID, 'linkstory', '', implode(',', $this->post->stories));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -628,8 +703,8 @@ class buildModel extends model
|
||||
{
|
||||
$build->allBugs = $build->bugs;
|
||||
$build->allStories = $build->stories;
|
||||
$childBuilds = $this->dao->select('bugs, stories')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchAll();
|
||||
|
||||
$childBuilds = $this->dao->select('id,name,bugs,stories')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchAll();
|
||||
foreach($childBuilds as $childBuild)
|
||||
{
|
||||
if($childBuild->bugs) $build->allBugs .= ",{$childBuild->bugs}";
|
||||
@@ -687,7 +762,7 @@ class buildModel extends model
|
||||
{
|
||||
$executionID = $tab == 'execution' ? $extraParams['executionID'] : $build->execution;
|
||||
$execution = $this->loadModel('execution')->getByID($executionID);
|
||||
$build->executionDeleted = $execution ? $execution->deleted : 0;
|
||||
$build->executionDeleted = $execution ? $execution->deleted : 0;
|
||||
|
||||
$testtaskApp = (!empty($execution->type) and $execution->type == 'kanban') ? 'data-app="qa"' : "data-app='{$tab}'";
|
||||
|
||||
|
||||
@@ -33,12 +33,6 @@
|
||||
<td>
|
||||
<div class='input-group' id='productBox'>
|
||||
<?php echo html::select('product', $products, empty($product) ? '' : $product->id, "onchange='loadBranches(this.value);' class='form-control chosen' required");?>
|
||||
<?php
|
||||
if(!empty($product) and $product->type != 'normal')
|
||||
{
|
||||
echo "<span class='input-group-addon fix-padding fix-border'></span>" . html::select('branch', $branches, key($product->branches), "class='form-control chosen'");
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</td>
|
||||
<?php else:?>
|
||||
@@ -50,6 +44,19 @@
|
||||
<?php endif;?>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class='<?php if((!empty($product) and $product->type == 'normal') or empty($product)) echo 'hidden'?>'>
|
||||
<?php
|
||||
if(empty($product)) $product = new stdclass();
|
||||
$productType = zget($product, 'type', 'normal');
|
||||
$productBranches = zget($product, 'branches', array());
|
||||
?>
|
||||
<th class='w-120px'><?php echo $productType == 'normal' ? '' : $lang->product->branchName[$productType]?></th>
|
||||
<td>
|
||||
<div class='input-group' id='branchBox'>
|
||||
<?php echo html::select('branch[]', $branches, key($productBranches), "class='form-control chosen' multiple required"); ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class='hide'>
|
||||
<th class='w-120px'><?php echo $lang->build->builds;?></th>
|
||||
<td id='buildBox'><?php echo html::select('builds[]', array(), '', "class='form-control chosen' multiple data-placeholder='{$lang->build->placeholder->multipleSelect}'");?></td>
|
||||
|
||||
@@ -32,16 +32,24 @@
|
||||
?>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('product', $products, $build->product, "onchange='loadBranches(this.value);' class='form-control chosen' $disabled required");?>
|
||||
<?php
|
||||
if($build->productType != 'normal')
|
||||
{
|
||||
echo "<span class='input-group-addon fix-padding fix-border'></span>" . html::select('branch', $branchTagOption, $build->branch, "class='form-control chosen' $disabled");
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</td>
|
||||
<td><?php if($disabled) echo $lang->build->notice->changeProduct;?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr class='<?php if((!empty($product) and $product->type == 'normal') or empty($product) or empty($build->execution)) echo 'hidden'?>'>
|
||||
<?php
|
||||
if(empty($product)) $product = new stdclass();
|
||||
$productType = zget($product, 'type', 'normal');
|
||||
$productBranches = zget($product, 'branches', array());
|
||||
?>
|
||||
<th class='w-120px'><?php echo $product->type == 'normal' ? '' : $lang->product->branchName[$product->type]?></th>
|
||||
<td>
|
||||
<div class='input-group' id='branchBox'>
|
||||
<?php echo html::select('branch[]', $branchTagOption, $build->branch, "class='form-control chosen' multiple required"); ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php $disabled = $testtaskID ? 'disabled' : '';?>
|
||||
<?php if(!$build->execution):?>
|
||||
<tr>
|
||||
@@ -101,7 +109,9 @@
|
||||
</div>
|
||||
<?php js::set('productGroups', $productGroups)?>
|
||||
<?php js::set('projectID', $build->project)?>
|
||||
<?php js::set('oldBranch', $oldBranch)?>
|
||||
<?php js::set('builds', $build->builds)?>
|
||||
<?php js::set('buildID', $build->id)?>
|
||||
<?php js::set('executionID', $build->execution)?>
|
||||
<?php js::set('currentTab', $this->app->tab);?>
|
||||
<?php js::set('multipleSelect', $lang->build->placeholder->multipleSelect);?>
|
||||
|
||||
@@ -88,18 +88,35 @@ tbody tr td:first-child input {display: none;}
|
||||
<?php endif;?>
|
||||
<?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?>
|
||||
</th>
|
||||
<th class='c-id' title=<?php echo $lang->pri;?>><?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
|
||||
<th class='text-left'><?php common::printOrderLink('title', $orderBy, $vars, $lang->story->title);?></th>
|
||||
<th class='c-user'><?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
|
||||
<th class='c-id text-right'><?php common::printOrderLink('estimate', $orderBy, $vars, $lang->story->estimateAB);?></th>
|
||||
<th class='c-pri' title=<?php echo $lang->pri;?>><?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
|
||||
<th class='c-status'><?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
|
||||
<th class='c-status'><?php common::printOrderLink('stage', $orderBy, $vars, $lang->story->stageAB);?></th>
|
||||
<?php if($childBuilds):?>
|
||||
<th class='c-build'><?php echo $lang->build->linkedBuild;?></th>
|
||||
<?php endif;?>
|
||||
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
|
||||
<th class='c-estimate'> <?php common::printOrderLink('estimate', $orderBy, $vars, $lang->story->estimateAB);?></th>
|
||||
<th class='c-stage'> <?php common::printOrderLink('stage', $orderBy, $vars, $lang->story->stageAB);?></th>
|
||||
<th class='c-actions-1'><?php echo $lang->actions?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class='text-center'>
|
||||
<?php foreach($stories as $storyID => $story):?>
|
||||
<?php $unlinkClass = strpos(",$build->stories,", ",$story->id,") !== false ? '' : "disabled";?>
|
||||
<?php
|
||||
$unlinkClass = strpos(",$build->allStories,", ",$story->id,") !== false ? '' : "disabled";
|
||||
$buildName = $build->name;
|
||||
if($unlinkClass == 'disabled')
|
||||
{
|
||||
foreach($childBuilds as $childBuild)
|
||||
{
|
||||
if(strpos(",$childBuild->stories,", ",$story->id,") !== false)
|
||||
{
|
||||
$buildName = $childBuild->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td class='c-id text-left'>
|
||||
<?php if($canBatchUnlink):?>
|
||||
@@ -108,11 +125,6 @@ tbody tr td:first-child input {display: none;}
|
||||
<?php printf('%03d', $story->id);?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if($story->pri):?>
|
||||
<span class='label-pri label-pri-<?php echo $story->pri;?>' title='<?php echo zget($lang->story->priList, $story->pri, $story->pri);?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri);?></span>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td class='text-left nobr' title='<?php echo $story->title?>'>
|
||||
<?php
|
||||
if($story->parent > 0) echo "<span class='label label-badge label-light'>{$lang->story->childrenAB}</span>";
|
||||
@@ -130,14 +142,20 @@ tbody tr td:first-child input {display: none;}
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td><?php echo zget($users, $story->openedBy);?></td>
|
||||
<td class='text-right' title="<?php echo $story->estimate . ' ' . $lang->hourCommon;?>"><?php echo $story->estimate . $config->hourUnit;?></td>
|
||||
<td>
|
||||
<span class='status-story status-<?php echo $story->status;?>'>
|
||||
<?php echo $this->processStatus('story', $story);?>
|
||||
</span>
|
||||
<?php if($story->pri):?>
|
||||
<span class='label-pri label-pri-<?php echo $story->pri;?>' title='<?php echo zget($lang->story->priList, $story->pri, $story->pri);?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri);?></span>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td><?php echo $lang->story->stageList[$story->stage];?></td>
|
||||
<td>
|
||||
<span class='status-story status-<?php echo $story->status;?>'><?php echo $this->processStatus('story', $story);?></span>
|
||||
</td>
|
||||
<?php if($childBuilds):?>
|
||||
<td class='c-build' title='<?php echo $buildName?>'><?php echo $buildName;?></td>
|
||||
<?php endif;?>
|
||||
<td class='c-user'><?php echo zget($users, $story->openedBy);?></td>
|
||||
<td class='c-estimate' title="<?php echo $story->estimate . ' ' . $lang->hourCommon;?>"><?php echo $story->estimate . $config->hourUnit;?></td>
|
||||
<td class='c-stage'><?php echo $lang->story->stageList[$story->stage];?></td>
|
||||
<td class='c-actions'>
|
||||
<?php
|
||||
if($canBeChanged and common::hasPriv($module, 'unlinkStory'))
|
||||
@@ -188,19 +206,36 @@ tbody tr td:first-child input {display: none;}
|
||||
<?php endif;?>
|
||||
<?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?>
|
||||
</th>
|
||||
<th class='text-left'> <?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
|
||||
<th class='c-status'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
|
||||
<th class='text-left'><?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
|
||||
<th class='c-status'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
|
||||
<?php if($childBuilds):?>
|
||||
<th class='c-build'><?php echo $lang->build->linkedBuild?></th>
|
||||
<?php endif;?>
|
||||
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
|
||||
<th class='c-date'> <?php common::printOrderLink('openedDate', $orderBy, $vars, $lang->bug->openedDateAB);?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('resolvedBy', $orderBy, $vars, $lang->bug->resolvedByAB);?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('resolvedBy', $orderBy, $vars, $lang->bug->resolvedBy);?></th>
|
||||
<th class='c-date'> <?php common::printOrderLink('resolvedDate', $orderBy, $vars, $lang->bug->resolvedDateAB);?></th>
|
||||
<th class='c-actions-1'><?php echo $lang->actions?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class='text-center'>
|
||||
<?php foreach($bugs as $bug):?>
|
||||
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bug->id", '', true);?>
|
||||
<?php $unlinkClass = strpos(",$build->bugs,", ",$bug->id,") !== false ? '' : "disabled";?>
|
||||
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bug->id", '', true);?>
|
||||
<?php
|
||||
$unlinkClass = strpos(",$build->allBugs,", ",$bug->id,") !== false ? '' : "disabled";
|
||||
$buildName = $build->name;
|
||||
if($unlinkClass == 'disabled')
|
||||
{
|
||||
foreach($childBuilds as $childBuild)
|
||||
{
|
||||
if(strpos(",$childBuild->bugs,", ",$bug->id,") !== false)
|
||||
{
|
||||
$buildName = $childBuild->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td class='c-id text-left'>
|
||||
<?php if($canBatchUnlink):?>
|
||||
@@ -216,10 +251,13 @@ tbody tr td:first-child input {display: none;}
|
||||
<?php echo $this->processStatus('bug', $bug);?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo zget($users, $bug->openedBy);?></td>
|
||||
<td><?php echo helper::isZeroDate($bug->openedDate) ? '' : substr($bug->openedDate, 5, 11);?></td>
|
||||
<td><?php echo zget($users, $bug->resolvedBy);?></td>
|
||||
<td><?php echo helper::isZeroDate($bug->resolvedDate) ? '' : substr($bug->resolvedDate, 5, 11);?></td>
|
||||
<?php if($childBuilds):?>
|
||||
<td class='c-build' title='<?php echo $buildName?>'><?php echo $buildName;?></td>
|
||||
<?php endif;?>
|
||||
<td class='c-user'><?php echo zget($users, $bug->openedBy);?></td>
|
||||
<td class='c-date'><?php echo helper::isZeroDate($bug->openedDate) ? '' : substr($bug->openedDate, 5, 11);?></td>
|
||||
<td class='c-user'><?php echo zget($users, $bug->resolvedBy);?></td>
|
||||
<td class='c-date'><?php echo helper::isZeroDate($bug->resolvedDate) ? '' : substr($bug->resolvedDate, 5, 11);?></td>
|
||||
<td class='c-actions'>
|
||||
<?php
|
||||
if($canBeChanged and common::hasPriv($module, 'unlinkBug'))
|
||||
@@ -257,13 +295,14 @@ tbody tr td:first-child input {display: none;}
|
||||
<?php $vars = "buildID={$build->id}&type=generatedBug&link=$link¶m=$param&orderBy=%s";?>
|
||||
<thead>
|
||||
<tr class='text-center'>
|
||||
<th class='c-id text-left'><?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
|
||||
<th class='c-status' title=<?php echo $lang->bug->severity;?>><?php common::printOrderLink('severity', $orderBy, $vars, $lang->bug->severityAB);?></th>
|
||||
<th class='text-left'><?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
|
||||
<th class='c-status'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
|
||||
<th class='c-id text-left'><?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
|
||||
<th class='text-left'><?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
|
||||
<th class='c-severity' title=<?php echo $lang->bug->severity;?>><?php common::printOrderLink('severity', $orderBy, $vars, $lang->bug->severityAB);?></th>
|
||||
<th class='c-status'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
|
||||
<th class='c-build'> <?php echo $lang->bug->openedBuild;?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
|
||||
<th class='c-date'> <?php common::printOrderLink('openedDate', $orderBy, $vars, $lang->bug->openedDateAB);?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('resolvedBy', $orderBy, $vars, $lang->bug->resolvedByAB);?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('resolvedBy', $orderBy, $vars, $lang->bug->resolvedBy);?></th>
|
||||
<th class='c-date'> <?php common::printOrderLink('resolvedDate', $orderBy, $vars, $lang->bug->resolvedDateAB);?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -283,6 +322,9 @@ tbody tr td:first-child input {display: none;}
|
||||
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bug->id", '', true);?>
|
||||
<tr>
|
||||
<td class='text-left'><?php printf('%03d', $bug->id);?></td>
|
||||
<td class='text-left nobr' title='<?php echo $bug->title?>'>
|
||||
<?php echo html::a($bugLink, $bug->title, '', isonlybody() ? "data-width='1000'" : "class='iframe' data-width='1000'");?>
|
||||
</td>
|
||||
<td class='c-severity'>
|
||||
<?php if($hasCustomSeverity):?>
|
||||
<span class='label-severity-custom' data-severity='<?php echo $bug->severity;?>' title='<?php echo zget($lang->bug->severityList, $bug->severity);?>'><?php echo zget($lang->bug->severityList, $bug->severity, $bug->severity);?></span>
|
||||
@@ -290,18 +332,20 @@ tbody tr td:first-child input {display: none;}
|
||||
<span class='label-severity' data-severity='<?php echo $bug->severity;?>' title='<?php echo zget($lang->bug->severityList, $bug->severity, $bug->severity);?>'></span>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td class='text-left nobr' title='<?php echo $bug->title?>'>
|
||||
<?php echo html::a($bugLink, $bug->title, '', isonlybody() ? "data-width='1000'" : "class='iframe' data-width='1000'");?>
|
||||
</td>
|
||||
<td>
|
||||
<span class='status-bug status-<?php echo $bug->status?>'>
|
||||
<?php echo $this->processStatus('bug', $bug);?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo zget($users, $bug->openedBy);?></td>
|
||||
<td><?php echo helper::isZeroDate($bug->openedDate) ? '' : substr($bug->openedDate, 5, 11);?></td>
|
||||
<td><?php echo zget($users, $bug->resolvedBy);?></td>
|
||||
<td><?php echo helper::isZeroDate($bug->resolvedDate) ? '' : substr($bug->resolvedDate, 5, 11);?></td>
|
||||
<?php
|
||||
$openedBuilds = '';
|
||||
foreach(explode(',', $bug->openedBuild) as $buildID) $openedBuilds .= ($buildID == 'trunk' ? 'Trunk' : zget($buildPairs, $buildID, '')) . ' ';
|
||||
?>
|
||||
<td class='c-build' title='<?php echo $openedBuilds;?>'><?php echo $openedBuilds;?></td>
|
||||
<td class='c-user'><?php echo zget($users, $bug->openedBy);?></td>
|
||||
<td class='c-date'><?php echo helper::isZeroDate($bug->openedDate) ? '' : substr($bug->openedDate, 5, 11);?></td>
|
||||
<td class='c-user'><?php echo zget($users, $bug->resolvedBy);?></td>
|
||||
<td class='c-date'><?php echo helper::isZeroDate($bug->resolvedDate) ? '' : substr($bug->resolvedDate, 5, 11);?></td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
|
||||
+36
-4
@@ -395,9 +395,9 @@ class commonModel extends model
|
||||
/**
|
||||
* Deny access.
|
||||
*
|
||||
* @param varchar $module
|
||||
* @param varchar $method
|
||||
* @param bool $reload
|
||||
* @param string $module
|
||||
* @param string $method
|
||||
* @param bool $reload
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -939,6 +939,38 @@ class commonModel extends model
|
||||
echo "<div class='btn-group header-btn'>" . $html . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the date to YYYY-mm-dd, format the datetime to YYYY-mm-dd HH:ii:ss.
|
||||
*
|
||||
* @param int $date
|
||||
* @param string $type date|datetime|''
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function formatDate($date, $type = '')
|
||||
{
|
||||
$datePattern = '\w{4}(\/|-)\w{1,2}(\/|-)\w{1,2}';
|
||||
$datetimePattern = $datePattern . ' \w{1,2}\:\w{1,2}\:\w{1,2}';
|
||||
|
||||
if(empty($type))
|
||||
{
|
||||
if(!preg_match("/$datePattern/", $date) and !preg_match("/$datetimePattern/", $date)) return $date;
|
||||
if(preg_match("/$datePattern/", $date) === 1) $type = 'date';
|
||||
if(preg_match("/$datetimePattern/", $date) === 1) $type = 'datetime';
|
||||
}
|
||||
|
||||
if(helper::isZeroDate($date))
|
||||
{
|
||||
if($type == 'date') return '0000-00-00';
|
||||
if($type == 'datetime') return '0000-00-00 00:00:00';
|
||||
}
|
||||
|
||||
if($type == 'date') $format = 'Y-m-d';
|
||||
if($type == 'datetime') $format = 'Y-m-d H:i:s';
|
||||
|
||||
return date($format, strtotime($date));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get main nav items list
|
||||
*
|
||||
@@ -2454,7 +2486,7 @@ EOD;
|
||||
}
|
||||
catch(EndResponseException $endResponseException)
|
||||
{
|
||||
echo $endResponseException->getContent();
|
||||
die($endResponseException->getContent());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,12 +41,13 @@ class convertModel extends model
|
||||
* Check database exits or not.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
* @return object|false
|
||||
*/
|
||||
public function dbExists($dbName = '')
|
||||
{
|
||||
$sql = "SHOW DATABASES like '{$dbName}'";
|
||||
return $this->dbh->query($sql)->fetch();
|
||||
$statement = $this->dbh->prepare('SHOW DATABASES like ?');
|
||||
$statement->execute([$dbName]);
|
||||
return $statement->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -371,10 +371,10 @@ class deptModel extends model
|
||||
/**
|
||||
* Get users of a deparment.
|
||||
*
|
||||
* @param varchar $browseType inside|outside|all
|
||||
* @param string $browseType inside|outside|all
|
||||
* @param int $deptID
|
||||
* @param object $pager
|
||||
* @param varchar $orderBy
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
<?php if(common::hasPriv('doc', 'collect')):?>
|
||||
<a data-url="<?php echo $this->createLink('doc', 'collect', "objectID=$doc->id&objectType=doc");?>" title="<?php echo $collectTitle;?>" class='btn btn-link ajaxCollect'><i class='icon <?php echo $star;?>'></i></a>
|
||||
<?php endif;?>
|
||||
<?php common::printLink('doc', 'edit', "docID=$doc->id&comment=false", "<i class='icon icon-edit'></i>", '', "title='{$lang->edit}' class='btn btn-link iframe'", true, true)?>
|
||||
<?php common::printLink('doc', 'edit', "docID=$doc->id&comment=false", "<i class='icon icon-edit'></i>", '', "title='{$lang->edit}' class='btn btn-link'", true, false)?>
|
||||
<?php common::printLink('doc', 'delete', "docID=$doc->id&confirm=no", "<i class='icon icon-trash'></i>", 'hiddenwin', "title='{$lang->delete}' class='btn btn-link'")?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
$(function()
|
||||
{
|
||||
var simplemde = new SimpleMDE({element: $("#markdownContent")[0],toolbar:false, status: false});
|
||||
simplemde.value(String(markdownText));
|
||||
//simplemde.value(String(markdownText));
|
||||
simplemde.togglePreview();
|
||||
|
||||
$('#content .CodeMirror .editor-preview a').attr('target', '_blank');
|
||||
|
||||
@@ -249,7 +249,7 @@ js::set('docID', $doc->id);
|
||||
$(function()
|
||||
{
|
||||
var simplemde = new SimpleMDE({element: $("#markdownContent")[0],toolbar:false, status: false});
|
||||
simplemde.value(String(markdownText));
|
||||
//simplemde.value(String(markdownText));
|
||||
simplemde.togglePreview();
|
||||
|
||||
$('#content .CodeMirror .editor-preview a').attr('target', '_blank');
|
||||
|
||||
@@ -898,7 +898,7 @@ class execution extends control
|
||||
$storyBugs = $this->loadModel('bug')->getStoryBugCounts($storyIdList, $executionID);
|
||||
$storyCases = $this->loadModel('testcase')->getStoryCaseCounts($storyIdList);
|
||||
|
||||
$plans = $this->execution->getPlans($products, 'skipParent|withMainPlan');
|
||||
$plans = $this->execution->getPlans($products, 'skipParent|withMainPlan|unexpired|noclosed', $executionID);
|
||||
$allPlans = array('' => '');
|
||||
if(!empty($plans))
|
||||
{
|
||||
@@ -934,6 +934,17 @@ class execution extends control
|
||||
$moduleTree = $this->tree->getProjectStoryTreeMenu($executionID, 0, array('treeModel', $createModuleLink));
|
||||
}
|
||||
|
||||
$executionProductList = $this->loadModel('product')->getProducts($executionID);
|
||||
$multiBranch = false;
|
||||
foreach($executionProductList as $executionProduct)
|
||||
{
|
||||
if($executionProduct->type != 'normal')
|
||||
{
|
||||
$multiBranch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Assign. */
|
||||
$this->view->title = $title;
|
||||
$this->view->position = $position;
|
||||
@@ -963,6 +974,7 @@ class execution extends control
|
||||
$this->view->canBeChanged = common::canModify('execution', $execution); // Determines whether an object is editable.
|
||||
$this->view->showBranch = $showBranch;
|
||||
$this->view->storyStages = $this->product->batchGetStoryStage($stories);
|
||||
$this->view->multiBranch = $multiBranch;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -1298,21 +1310,26 @@ class execution extends control
|
||||
/* Set execution builds. */
|
||||
$executionBuilds = array();
|
||||
$productList = $this->product->getProducts($executionID);
|
||||
$this->app->loadLang('branch');
|
||||
$showBranch = false;
|
||||
if(!empty($builds))
|
||||
{
|
||||
foreach($builds as $build) $executionBuilds[$build->product][] = $build;
|
||||
|
||||
/* Get branch name. */
|
||||
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($executionBuilds));
|
||||
foreach($builds as $build)
|
||||
{
|
||||
/* If product is normal, unset branch name. */
|
||||
if(isset($productList[$build->product]) and $productList[$build->product]->type == 'normal')
|
||||
$build->branchName = '';
|
||||
if(isset($branchGroups[$build->product]))
|
||||
{
|
||||
$build->branchName = '';
|
||||
$showBranch = true;
|
||||
$branchPairs = $branchGroups[$build->product];
|
||||
foreach(explode(',', trim($build->branch, ',')) as $branchID)
|
||||
{
|
||||
if(isset($branchPairs[$branchID])) $build->branchName .= "{$branchPairs[$branchID]},";
|
||||
}
|
||||
$build->branchName = trim($build->branchName, ',');
|
||||
}
|
||||
else
|
||||
{
|
||||
$build->branchName = isset($build->branchName) ? $build->branchName : $this->lang->branch->main;
|
||||
}
|
||||
$executionBuilds[$build->product][] = $build;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1328,6 +1345,7 @@ class execution extends control
|
||||
$this->view->product = $type == 'product' ? $param : 'all';
|
||||
$this->view->products = $products;
|
||||
$this->view->type = $type;
|
||||
$this->view->showBranch = $showBranch;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -1579,6 +1597,7 @@ class execution extends control
|
||||
|
||||
$execution = $this->commonAction($executionID);
|
||||
$executionID = $execution->id;
|
||||
$deptID = $this->app->user->admin ? 0 : $this->app->user->dept;
|
||||
|
||||
$title = $execution->name . $this->lang->colon . $this->lang->execution->team;
|
||||
$position[] = html::a($this->createLink('execution', 'browse', "executionID=$executionID"), $execution->name);
|
||||
@@ -1586,7 +1605,7 @@ class execution extends control
|
||||
|
||||
$this->view->title = $title;
|
||||
$this->view->position = $position;
|
||||
$this->view->deptUsers = $this->loadModel('dept')->getDeptUserPairs($this->app->user->dept, 'id');
|
||||
$this->view->deptUsers = $this->loadModel('dept')->getDeptUserPairs($deptID, 'id');
|
||||
$this->view->canBeChanged = common::canModify('execution', $execution); // Determines whether an object is editable.
|
||||
|
||||
$this->display();
|
||||
@@ -1645,7 +1664,20 @@ class execution extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
return print(js::confirm($this->lang->execution->importPlanStory, inlink('create', "projectID=$projectID&executionID=$executionID©ExecutionID=&planID=$planID&confirm=yes"), inlink('create', "projectID=$projectID&executionID=$executionID")));
|
||||
$executionProductList = $this->loadModel('product')->getProducts($executionID);
|
||||
$multiBranchProduct = false;
|
||||
foreach($executionProductList as $executionProduct)
|
||||
{
|
||||
if($executionProduct->type != 'normal')
|
||||
{
|
||||
$multiBranchProduct = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$importPlanStoryTips = $multiBranchProduct ? $this->lang->execution->importBranchPlanStory : $this->lang->execution->importPlanStory;
|
||||
|
||||
return print(js::confirm($importPlanStoryTips, inlink('create', "projectID=$projectID&executionID=$executionID©ExecutionID=&planID=$planID&confirm=yes"), inlink('create', "projectID=$projectID&executionID=$executionID")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1689,10 +1721,11 @@ class execution extends control
|
||||
$linkedBranches = array();
|
||||
foreach($products as $productIndex => $product)
|
||||
{
|
||||
$productPlans[$productIndex] = array();
|
||||
foreach($branches[$productIndex] as $branchID => $branch)
|
||||
{
|
||||
$linkedBranches[$productIndex][$branchID] = $branchID;
|
||||
$productPlans[$productIndex][$branchID] = isset($plans[$productIndex][$branchID]) ? $plans[$productIndex][$branchID] : array();
|
||||
$productPlans[$productIndex] += isset($plans[$productIndex][$branchID]) ? $plans[$productIndex][$branchID] : array();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1724,10 +1757,11 @@ class execution extends control
|
||||
$linkedBranches = array();
|
||||
foreach($products as $productIndex => $product)
|
||||
{
|
||||
$productPlans[$productIndex] = array();
|
||||
foreach($branches[$productIndex] as $branchID => $branch)
|
||||
{
|
||||
$linkedBranches[$productIndex][$branchID] = $branchID;
|
||||
$productPlans[$productIndex][$branchID] = isset($plans[$productIndex][$branchID]) ? $plans[$productIndex][$branchID] : array();
|
||||
$productPlans[$productIndex] += isset($plans[$productIndex][$branchID]) ? $plans[$productIndex][$branchID] : array();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1776,27 +1810,15 @@ class execution extends control
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('doc', 'objectLibs', "type=execution")));
|
||||
}
|
||||
|
||||
$planID = '';
|
||||
if(isset($_POST['plans']))
|
||||
{
|
||||
foreach($_POST['plans'] as $plans)
|
||||
{
|
||||
foreach($plans as $planID)
|
||||
{
|
||||
if(!empty($planID)) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($projectID) and $project->model == 'kanban')
|
||||
{
|
||||
$execution = $this->execution->getById($executionID);
|
||||
$this->loadModel('kanban')->createRDKanban($execution);
|
||||
}
|
||||
|
||||
if(!empty($planID))
|
||||
if(!empty($_POST['plans']))
|
||||
{
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('create', "projectID=$projectID&executionID=$executionID©ExecutionID=&planID=$planID&confirm=no")));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('create', "projectID=$projectID&executionID=$executionID©ExecutionID=&planID=1&confirm=no")));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1904,7 +1926,20 @@ class execution extends control
|
||||
}
|
||||
elseif(!empty($newPlans))
|
||||
{
|
||||
return print(js::confirm($this->lang->execution->importEditPlanStory, inlink('edit', "executionID=$executionID&action=edit&extra=&newPlans=$newPlans&confirm=yes"), inlink('view', "executionID=$executionID")));
|
||||
$executionProductList = $this->loadModel('product')->getProducts($executionID);
|
||||
$multiBranchProduct = false;
|
||||
foreach($executionProductList as $executionProduct)
|
||||
{
|
||||
if($executionProduct->type != 'normal')
|
||||
{
|
||||
$multiBranchProduct = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$importEditPlanStoryTips = $multiBranchProduct ? $this->lang->execution->importBranchEditPlanStory : $this->lang->execution->importEditPlanStory;
|
||||
|
||||
return print(js::confirm($importEditPlanStoryTips, inlink('edit', "executionID=$executionID&action=edit&extra=&newPlans=$newPlans&confirm=yes"), inlink('view', "executionID=$executionID")));
|
||||
}
|
||||
|
||||
/* Set menu. */
|
||||
@@ -2003,12 +2038,15 @@ class execution extends control
|
||||
foreach($linkedProducts as $productID => $linkedProduct)
|
||||
{
|
||||
if(!isset($allProducts[$productID])) $allProducts[$productID] = $linkedProduct->name;
|
||||
$productPlans[$productID] = array();
|
||||
|
||||
foreach($branches[$productID] as $branchID => $branch)
|
||||
{
|
||||
$productPlans[$productID] += isset($plans[$productID][$branchID]) ? $plans[$productID][$branchID] : array();
|
||||
|
||||
$linkedBranchList[$branchID] = $branchID;
|
||||
$linkedBranches[$productID][$branchID] = $branchID;
|
||||
$productPlans[$productID][$branchID] = isset($plans[$productID][$branchID]) ? $plans[$productID][$branchID] : array();
|
||||
if($branchID != BRANCH_MAIN and isset($plans[$productID][BRANCH_MAIN])) $productPlans[$productID][$branchID] += $plans[$productID][BRANCH_MAIN];
|
||||
if($branchID != BRANCH_MAIN and isset($plans[$productID][BRANCH_MAIN])) $productPlans[$productID] += $plans[$productID][BRANCH_MAIN];
|
||||
if(!empty($executionStories[$productID][$branchID]))
|
||||
{
|
||||
array_push($unmodifiableProducts, $productID);
|
||||
@@ -4121,9 +4159,11 @@ class execution extends control
|
||||
$count = 0;
|
||||
if(!empty($planStory))
|
||||
{
|
||||
$projectProducts = $this->loadModel('project')->getBranchesByProject($executionID);
|
||||
foreach($planStory as $id => $story)
|
||||
{
|
||||
if($story->status == 'draft' or $story->status == 'reviewing')
|
||||
$projectBranches = zget($projectProducts, $story->product, array());
|
||||
if($story->status != 'active' or (!empty($story->branch) and !empty($projectBranches) and !isset($projectBranches[$story->branch])))
|
||||
{
|
||||
$count++;
|
||||
unset($planStory[$id]);
|
||||
@@ -4155,8 +4195,28 @@ class execution extends control
|
||||
include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php';
|
||||
}
|
||||
|
||||
$haveDraft = sprintf($this->lang->execution->haveDraft, $count);
|
||||
if(!$execution->multiple) $haveDraft = str_replace($this->lang->executionCommon, $this->lang->projectCommon, $haveDraft);
|
||||
$multiBranchProduct = false;
|
||||
if($productID)
|
||||
{
|
||||
$product = $this->loadModel('product')->getByID($productID);
|
||||
if($product->type != 'normal') $multiBranchProduct = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$executionProductList = $this->loadModel('product')->getProducts($executionID);
|
||||
foreach($executionProductList as $executionProduct)
|
||||
{
|
||||
if($executionProduct->type != 'normal')
|
||||
{
|
||||
$multiBranchProduct = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$importPlanStoryTips = $multiBranchProduct ? $this->lang->execution->haveBranchDraft : $this->lang->execution->haveDraft;
|
||||
|
||||
$haveDraft = sprintf($importPlanStoryTips, $count);
|
||||
if(!$execution->multiple or $moduleName == 'projectstory') $haveDraft = str_replace($this->lang->executionCommon, $this->lang->projectCommon, $haveDraft);
|
||||
if($count != 0) echo js::alert($haveDraft) . js::locate($this->createLink($moduleName, $fromMethod, $param));
|
||||
return print(js::locate(helper::createLink($moduleName, $fromMethod, $param)));
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
|
||||
.chosen-container.chosen-highlight-selected .disabled-result.result-selected {background: none;}
|
||||
|
||||
#productsBox .row .col-sm-4 {padding-right: 13px;}
|
||||
#plansBox .row {display: inline-table; width: 102%;}
|
||||
#plansBox .row .col-sm-4 {display: inline-block; float: none; padding-right: 13px;}
|
||||
.productsBox .row .col-sm-4 {padding-right: 13px;}
|
||||
.plansBox .row {display: inline-table; width: 102%;}
|
||||
.plansBox .row .col-sm-4 {display: inline-block; float: none; padding-right: 13px;}
|
||||
|
||||
#dateRange {vertical-align: top; padding-top: 13px;}
|
||||
#dateRangeOption {vertical-align: top; padding-top: 13px;}
|
||||
@@ -31,4 +31,10 @@
|
||||
#endLabel {white-space: nowrap;}
|
||||
#copyProjectModal .projectSelect {display: inline-block; margin-left: 10px; width: 20%;}
|
||||
#copyProjectModal .titleBox{position: relative; bottom: 3px; display: inline-block;}
|
||||
a.chosen-single > div > b {top: -4px !important;}
|
||||
#copyProjectModal .projectSelect a.chosen-single > div > b {top: -4px !important;}
|
||||
|
||||
.productsBox a {border-radius: 2px !important;}
|
||||
.productsBox .required:after {right: -9.5px !important;}
|
||||
.productsBox .input-group-addon > div {display: inline-block !important;}
|
||||
.productsBox .required + .text-danger.help-text {position: relative; left: 10px;}
|
||||
.productsBox > #productNameLabel {padding-top: 8px;}
|
||||
|
||||
@@ -34,3 +34,4 @@ th.c-pri{width:50px;}
|
||||
.table td.c-estimate {padding-right: 12px;}
|
||||
.main-table tbody > tr.table-children > td:first-child::before {width: 3px;}
|
||||
.table-footer {z-index: 1;}
|
||||
#linkStoryByPlan .modal-header {padding: 20px 0 10px 0; border-bottom: 0px}
|
||||
@@ -113,6 +113,15 @@ function computeEndDate(delta)
|
||||
computeWorkDays();
|
||||
}
|
||||
|
||||
/* Auto compute the work days. */
|
||||
$(function()
|
||||
{
|
||||
$(".date").bind('dateSelected', function()
|
||||
{
|
||||
computeWorkDays(this.id);
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* Load branches.
|
||||
*
|
||||
@@ -122,118 +131,127 @@ function computeEndDate(delta)
|
||||
*/
|
||||
function loadBranches(product)
|
||||
{
|
||||
if($('#productsBox .input-group:last select:first').val() != 0)
|
||||
/* When selecting a product, delete a plan that is empty by default. */
|
||||
$("#planDefault").remove();
|
||||
|
||||
$(".productsBox select[name^='products']").each(function()
|
||||
{
|
||||
if(model !== 'waterfall')
|
||||
var $product = $(product);
|
||||
var productID = $(this).val();
|
||||
if($product.val() != 0 && $product.val() == $(this).val() && $product.attr('id') != $(this).attr('id') && !multiBranchProducts[$product.val()])
|
||||
{
|
||||
var length = $('#productsBox .input-group').size();
|
||||
$('#productsBox .row').append('<div class="col-sm-4">' + $('#productsBox .col-sm-4:last').html().replace('required', '') + '</div>');
|
||||
if($('#productsBox .input-group:last select').size() >= 2) $('#productsBox .input-group:last select:last').remove();
|
||||
$('#productsBox .input-group:last .chosen-container').remove();
|
||||
$('#productsBox .input-group:last select:first').attr('name', 'products[' + length + ']').attr('id', 'products' + length);
|
||||
$('#productsBox .input-group:last .chosen').chosen();
|
||||
bootbox.alert(errorSameProducts);
|
||||
$product.val(0);
|
||||
$product.trigger("chosen:updated");
|
||||
return false;
|
||||
}
|
||||
adjustProductBoxMargin();
|
||||
});
|
||||
|
||||
var $tableRow = $(product).closest('.table-row');
|
||||
var index = $tableRow.find('select:first').attr('id').replace('products' , '');
|
||||
var oldBranch = $(product).attr('data-branch') !== undefined ? $(product).attr('data-branch') : 0;
|
||||
if($(product).val() != 0)
|
||||
{
|
||||
$(product).closest('tr').find('.newProduct').addClass('hidden')
|
||||
}
|
||||
else
|
||||
{
|
||||
$(product).closest('tr').find('.newProduct').removeClass('hidden')
|
||||
}
|
||||
|
||||
var $inputgroup = $(product).closest('.input-group');
|
||||
if($inputgroup.find('select').size() >= 2) $inputgroup.removeClass('has-branch').find('select:last').remove();
|
||||
if($inputgroup.find('.chosen-container').size() >= 2) $inputgroup.find('.chosen-container:last').remove();
|
||||
if(!multiBranchProducts[$(product).val()])
|
||||
{
|
||||
$tableRow.find('.table-col:last select').val('').trigger('chosen:updated');
|
||||
$tableRow.find('.table-col:last').addClass('hidden');
|
||||
}
|
||||
|
||||
var projectID = $('#project').val();
|
||||
if(typeof(projectID) == 'undefined') projectID = 0;
|
||||
|
||||
var index = $inputgroup.find('select:first').attr('id').replace('products' , '');
|
||||
$.get(createLink('branch', 'ajaxGetBranches', "productID=" + $(product).val() + "&oldBranch=0¶m=active&projectID=" + projectID + "&withMainBranch=true"), function(data)
|
||||
$.get(createLink('branch', 'ajaxGetBranches', "productID=" + $(product).val() + "&oldBranch=" + oldBranch + "¶m=active&projectID=" + projectID + "&withMainBranch=true"), function(data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
$inputgroup.addClass('has-branch').append(data);
|
||||
$inputgroup.find('select:last').attr('name', 'branch[' + index + ']').attr('id', 'branch' + index).attr('onchange', "loadPlans('#products" + index + "', this.value)").chosen();
|
||||
$tableRow.find("select[name^='branch']").replaceWith(data);
|
||||
$tableRow.find('.table-col:last .chosen-container').remove();
|
||||
$tableRow.find('.table-col:last').removeClass('hidden');
|
||||
$tableRow.find("select[name^='branch']").attr('multiple', '').attr('name', 'branch[' + index + '][]').attr('id', 'branch' + index).attr('onchange', "loadPlans('#products" + index + "', this)").chosen();
|
||||
|
||||
$inputgroup.find('select:last').each(disableSelectedBranch);
|
||||
disableSelectedProduct();
|
||||
}
|
||||
|
||||
var branchID = $('#branch' + index).val();
|
||||
loadPlans(product, branchID);
|
||||
var branch = $('#branch' + index);
|
||||
loadPlans(product, branch);
|
||||
});
|
||||
|
||||
if(!multiBranchProducts[$(product).val()]) disableSelectedProduct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plans by product id.
|
||||
* Load plans.
|
||||
*
|
||||
* @param int $product
|
||||
* @param int $branchID
|
||||
* @param obj $product
|
||||
* @param obj $branchID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadPlans(product, branchID)
|
||||
function loadPlans(product, branch)
|
||||
{
|
||||
if($('#plansBox').size() == 0) return false;
|
||||
|
||||
var productID = $(product).val();
|
||||
var branchID = typeof(branchID) == 'undefined' ? 0 : branchID;
|
||||
var branchID = $(branch).val() == null ? 0 : '0,' + $(branch).val();
|
||||
var planID = $(product).attr('data-plan') !== undefined ? $(product).attr('data-plan') : 0;
|
||||
var index = $(product).attr('id').replace('products', '');
|
||||
|
||||
$.get(createLink('product', 'ajaxGetPlans', "productID=" + productID + '&branch=0,' + branchID + '&planID=0&fieldID&needCreate=&expired=noclosed,unexpired¶m=skipParent,multiple'), function(data)
|
||||
$.get(createLink('product', 'ajaxGetPlans', "productID=" + productID + '&branch=' + branchID + '&planID=' + planID + '&fieldID&needCreate=&expired=unexpired,noclosed¶m=skipParent,multiple'), function(data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
if($("div#plan" + index).size() == 0) $("#plansBox .row").append('<div class="col-sm-4" id="plan' + index + '"></div>');
|
||||
$("div#plan" + index).html(data).find('select').attr('name', 'plans[' + productID + '][' + branchID + '][]').attr('id', 'plans' + productID).chosen();
|
||||
|
||||
adjustPlanBoxMargin();
|
||||
$("div#plan" + index).find("select[name^='plans']").replaceWith(data);
|
||||
$("div#plan" + index).find('.chosen-container').remove();
|
||||
$("div#plan" + index).find('select').attr('name', 'plans[' + productID + ']' + '[]').attr('id', 'plans' + productID).chosen();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust product box margin.
|
||||
*
|
||||
* Add new line for link product.
|
||||
*
|
||||
* @param obj $obj
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function adjustProductBoxMargin()
|
||||
function addNewLine(obj)
|
||||
{
|
||||
var productRows = Math.ceil($('#productsBox > .row > .col-sm-4').length / 3);
|
||||
if(productRows > 1)
|
||||
var newLine = $(obj).closest('tr').clone();
|
||||
var index = 0;
|
||||
$(".productsBox select[name^='products']").each(function()
|
||||
{
|
||||
for(i = 1; i <= productRows - 1; i++)
|
||||
{
|
||||
$('#productsBox .col-sm-4:lt(' + (i * 3) + ')').css('margin-bottom', '10px');
|
||||
}
|
||||
}
|
||||
}
|
||||
var id = $(this).attr('id').replace('products' , '');
|
||||
|
||||
/**
|
||||
* Adjust plan box margin.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function adjustPlanBoxMargin()
|
||||
{
|
||||
var planRows = Math.ceil($('#plansBox > .row > .col-sm-4').length / 3);
|
||||
if(planRows > 1)
|
||||
{
|
||||
for(j = 1; j <= planRows - 1; j++)
|
||||
{
|
||||
$('#plansBox .col-sm-4:lt(' + (j * 3) + ')').css('margin-bottom', '10px');
|
||||
}
|
||||
}
|
||||
}
|
||||
id = parseInt(id);
|
||||
id ++;
|
||||
|
||||
/* Auto compute the work days. */
|
||||
$(function()
|
||||
{
|
||||
$(".date").bind('dateSelected', function()
|
||||
{
|
||||
computeWorkDays(this.id);
|
||||
index = id > index ? id : index;
|
||||
})
|
||||
});
|
||||
|
||||
newLine.find('.newProduct').remove();
|
||||
newLine.find('.addProduct').remove();
|
||||
newLine.addClass('newLine');
|
||||
newLine.find('th').html('');
|
||||
newLine.find('.removeLine').css('visibility', 'visible');
|
||||
newLine.find('.chosen-container').remove();
|
||||
newLine.find('.productsBox .table-col:last').addClass('hidden');
|
||||
newLine.find("select[name^='products']").attr('name', 'products[' + index + ']').attr('id', 'products' + index).val('').chosen();
|
||||
newLine.find("select[name^='plans']").attr('name', 'plans[' + index + '][' + 0 + '][]').chosen();
|
||||
newLine.find("div[id^='plan']").attr('id', 'plan' + index);
|
||||
|
||||
$(obj).closest('tr').after(newLine);
|
||||
var product = newLine.find("select[name^='products']");
|
||||
var branch = newLine.find("select[name^='branch']");
|
||||
loadPlans(product, branch);
|
||||
disableSelectedProduct();
|
||||
}
|
||||
|
||||
function removeLine(obj)
|
||||
{
|
||||
$(obj).closest('tr').remove();
|
||||
disableSelectedProduct();
|
||||
}
|
||||
|
||||
$(function()
|
||||
{
|
||||
@@ -247,9 +265,6 @@ $(function()
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
adjustProductBoxMargin();
|
||||
adjustPlanBoxMargin();
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -209,82 +209,84 @@ $lang->execution->burnByList['estimate'] = "View by plan hours";
|
||||
$lang->execution->burnByList['storyPoint'] = 'View by story point';
|
||||
|
||||
/* Method list. */
|
||||
$lang->execution->index = "Home";
|
||||
$lang->execution->task = 'Aufgaben';
|
||||
$lang->execution->groupTask = 'Nach Gruppen';
|
||||
$lang->execution->story = 'Storys';
|
||||
$lang->execution->qa = 'QA';
|
||||
$lang->execution->bug = 'Bugs';
|
||||
$lang->execution->testcase = 'Testcase List';
|
||||
$lang->execution->dynamic = 'Verlauf';
|
||||
$lang->execution->latestDynamic = 'Letzter Verlauf';
|
||||
$lang->execution->build = 'Builds';
|
||||
$lang->execution->testtask = 'Testaufgaben';
|
||||
$lang->execution->burn = 'Burndown';
|
||||
$lang->execution->computeBurn = 'Aktualisieren';
|
||||
$lang->execution->CFD = 'Cumulative Flow diagrams';
|
||||
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
|
||||
$lang->execution->burnData = 'Burndown Daten';
|
||||
$lang->execution->fixFirst = 'Bearbeite Mannstunden des ersten Tags';
|
||||
$lang->execution->team = 'Teammitglieder';
|
||||
$lang->execution->doc = 'Dok';
|
||||
$lang->execution->doclib = 'Dok Bibliothek';
|
||||
$lang->execution->manageProducts = 'Verküpfe ' . $lang->productCommon;
|
||||
$lang->execution->linkStory = 'Link Stories';
|
||||
$lang->execution->linkStoryByPlan = 'Verküpfe Story aus Plan';
|
||||
$lang->execution->linkPlan = 'Verküpfe Plan';
|
||||
$lang->execution->unlinkStoryTasks = 'Verknüpfung aufheben';
|
||||
$lang->execution->linkedProducts = 'Verküpfte Produkte';
|
||||
$lang->execution->unlinkedProducts = 'Produkt verknüpfung aufheben';
|
||||
$lang->execution->view = "Übersicht";
|
||||
$lang->execution->startAction = "Start Execution";
|
||||
$lang->execution->activateAction = "Activate Execution";
|
||||
$lang->execution->delayAction = "Delay Execution";
|
||||
$lang->execution->suspendAction = "Suspend Execution";
|
||||
$lang->execution->closeAction = "Close Execution";
|
||||
$lang->execution->testtaskAction = "Execution Request";
|
||||
$lang->execution->teamAction = "Execution Members";
|
||||
$lang->execution->kanbanAction = "Execution Kanban";
|
||||
$lang->execution->printKanbanAction = "Print Kanban";
|
||||
$lang->execution->treeAction = "Execution Tree View";
|
||||
$lang->execution->exportAction = "Export Execution";
|
||||
$lang->execution->computeBurnAction = "Compute Burn";
|
||||
$lang->execution->create = "Erstelle Projekt";
|
||||
$lang->execution->createExec = "Create Execution";
|
||||
$lang->execution->createAction = "Create {$lang->execution->common}";
|
||||
$lang->execution->copyExec = "Copy Execution";
|
||||
$lang->execution->copy = "Kopiere {$lang->executionCommon}";
|
||||
$lang->execution->delete = "Lösche";
|
||||
$lang->execution->deleteAB = "Lösche Execution";
|
||||
$lang->execution->browse = "Durchsuchen";
|
||||
$lang->execution->edit = "Bearbeiten";
|
||||
$lang->execution->editAction = "Edit Execution";
|
||||
$lang->execution->batchEdit = "Mehere bearbeiten";
|
||||
$lang->execution->batchEditAction = "Batch Edit";
|
||||
$lang->execution->manageMembers = 'Teams verwalten';
|
||||
$lang->execution->unlinkMember = 'Mitgliefer entfernen';
|
||||
$lang->execution->unlinkStory = 'Story entfernen';
|
||||
$lang->execution->unlinkStoryAB = 'Unlink';
|
||||
$lang->execution->batchUnlinkStory = 'Mehere Storys entfernen';
|
||||
$lang->execution->importTask = 'Importiere Aufgaben';
|
||||
$lang->execution->importPlanStories = 'Verknüpfe Story aus Plan';
|
||||
$lang->execution->importBug = 'Importiere Bugs';
|
||||
$lang->execution->tree = 'Baum';
|
||||
$lang->execution->treeTask = 'Aufgabe anzeigen';
|
||||
$lang->execution->treeStory = 'Story anzeigen';
|
||||
$lang->execution->treeViewTask = 'Tree View Task';
|
||||
$lang->execution->treeViewStory = 'Tree View Story';
|
||||
$lang->execution->storyKanban = 'Story Kanban';
|
||||
$lang->execution->storySort = 'Story sortieren';
|
||||
$lang->execution->importPlanStory = '' . $lang->executionCommon . ' wurde erstellt!\nMöchten Sie Storys aus dem Plan importieren?';
|
||||
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
|
||||
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
|
||||
$lang->execution->iteration = 'Iteration';
|
||||
$lang->execution->iterationInfo = '%s Iterationen';
|
||||
$lang->execution->viewAll = 'Alle anzeigen';
|
||||
$lang->execution->testreport = 'Test Report';
|
||||
$lang->execution->taskKanban = 'Task Kanban';
|
||||
$lang->execution->RDKanban = 'Research & Development Kanban';
|
||||
$lang->execution->index = "Home";
|
||||
$lang->execution->task = 'Aufgaben';
|
||||
$lang->execution->groupTask = 'Nach Gruppen';
|
||||
$lang->execution->story = 'Storys';
|
||||
$lang->execution->qa = 'QA';
|
||||
$lang->execution->bug = 'Bugs';
|
||||
$lang->execution->testcase = 'Testcase List';
|
||||
$lang->execution->dynamic = 'Verlauf';
|
||||
$lang->execution->latestDynamic = 'Letzter Verlauf';
|
||||
$lang->execution->build = 'Builds';
|
||||
$lang->execution->testtask = 'Testaufgaben';
|
||||
$lang->execution->burn = 'Burndown';
|
||||
$lang->execution->computeBurn = 'Aktualisieren';
|
||||
$lang->execution->CFD = 'Cumulative Flow diagrams';
|
||||
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
|
||||
$lang->execution->burnData = 'Burndown Daten';
|
||||
$lang->execution->fixFirst = 'Bearbeite Mannstunden des ersten Tags';
|
||||
$lang->execution->team = 'Teammitglieder';
|
||||
$lang->execution->doc = 'Dok';
|
||||
$lang->execution->doclib = 'Dok Bibliothek';
|
||||
$lang->execution->manageProducts = 'Verküpfe ' . $lang->productCommon;
|
||||
$lang->execution->linkStory = 'Link Stories';
|
||||
$lang->execution->linkStoryByPlan = 'Verküpfe Story aus Plan';
|
||||
$lang->execution->linkPlan = 'Verküpfe Plan';
|
||||
$lang->execution->unlinkStoryTasks = 'Verknüpfung aufheben';
|
||||
$lang->execution->linkedProducts = 'Verküpfte Produkte';
|
||||
$lang->execution->unlinkedProducts = 'Produkt verknüpfung aufheben';
|
||||
$lang->execution->view = "Übersicht";
|
||||
$lang->execution->startAction = "Start Execution";
|
||||
$lang->execution->activateAction = "Activate Execution";
|
||||
$lang->execution->delayAction = "Delay Execution";
|
||||
$lang->execution->suspendAction = "Suspend Execution";
|
||||
$lang->execution->closeAction = "Close Execution";
|
||||
$lang->execution->testtaskAction = "Execution Request";
|
||||
$lang->execution->teamAction = "Execution Members";
|
||||
$lang->execution->kanbanAction = "Execution Kanban";
|
||||
$lang->execution->printKanbanAction = "Print Kanban";
|
||||
$lang->execution->treeAction = "Execution Tree View";
|
||||
$lang->execution->exportAction = "Export Execution";
|
||||
$lang->execution->computeBurnAction = "Compute Burn";
|
||||
$lang->execution->create = "Erstelle Projekt";
|
||||
$lang->execution->createExec = "Create Execution";
|
||||
$lang->execution->createAction = "Create {$lang->execution->common}";
|
||||
$lang->execution->copyExec = "Copy Execution";
|
||||
$lang->execution->copy = "Kopiere {$lang->executionCommon}";
|
||||
$lang->execution->delete = "Lösche";
|
||||
$lang->execution->deleteAB = "Lösche Execution";
|
||||
$lang->execution->browse = "Durchsuchen";
|
||||
$lang->execution->edit = "Bearbeiten";
|
||||
$lang->execution->editAction = "Edit Execution";
|
||||
$lang->execution->batchEdit = "Mehere bearbeiten";
|
||||
$lang->execution->batchEditAction = "Batch Edit";
|
||||
$lang->execution->manageMembers = 'Teams verwalten';
|
||||
$lang->execution->unlinkMember = 'Mitgliefer entfernen';
|
||||
$lang->execution->unlinkStory = 'Story entfernen';
|
||||
$lang->execution->unlinkStoryAB = 'Unlink';
|
||||
$lang->execution->batchUnlinkStory = 'Mehere Storys entfernen';
|
||||
$lang->execution->importTask = 'Importiere Aufgaben';
|
||||
$lang->execution->importPlanStories = 'Verknüpfe Story aus Plan';
|
||||
$lang->execution->importBug = 'Importiere Bugs';
|
||||
$lang->execution->tree = 'Baum';
|
||||
$lang->execution->treeTask = 'Aufgabe anzeigen';
|
||||
$lang->execution->treeStory = 'Story anzeigen';
|
||||
$lang->execution->treeViewTask = 'Tree View Task';
|
||||
$lang->execution->treeViewStory = 'Tree View Story';
|
||||
$lang->execution->storyKanban = 'Story Kanban';
|
||||
$lang->execution->storySort = 'Story sortieren';
|
||||
$lang->execution->importPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
|
||||
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
|
||||
$lang->execution->importBranchPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
|
||||
$lang->execution->importBranchEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
|
||||
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
|
||||
$lang->execution->iteration = 'Iteration';
|
||||
$lang->execution->iterationInfo = '%s Iterationen';
|
||||
$lang->execution->viewAll = 'Alle anzeigen';
|
||||
$lang->execution->testreport = 'Test Report';
|
||||
$lang->execution->taskKanban = 'Task Kanban';
|
||||
$lang->execution->RDKanban = 'Research & Development Kanban';
|
||||
|
||||
/* Group browsing. */
|
||||
$lang->execution->allTasks = 'Alle';
|
||||
@@ -349,7 +351,8 @@ $lang->execution->howToUpdateBurn = "<a href='https://api.zentao.pm/goto.ph
|
||||
$lang->execution->whyNoStories = "Keine Story kann verknüpft werden. Bitte prüfen Sie ob ein Story mit {$lang->executionCommon} verknüpft ist {$lang->productCommon} und stellen Sie sicher das diese geprüft ist.";
|
||||
$lang->execution->projectNoStories = "No story can be linked. Please check whether there is any story in project and make sure it has been reviewed.";
|
||||
$lang->execution->productStories = "{$lang->executionCommon} verknüpfte Story ist ein Subset von {$lang->productCommon}, welche nur nach überprüfung verknüpft werden kann. Bitte <a href='%s'> Story verknüpfen</a>。";
|
||||
$lang->execution->haveDraft = "There are %s draft stories can't be linked.";
|
||||
$lang->execution->haveBranchDraft = "There are %s draft stories or not associated with this {$lang->executionCommon} can't be linked.";
|
||||
$lang->execution->haveDraft = "There are %s draft stories with this {$lang->executionCommon} can't be linked.";
|
||||
$lang->execution->doneExecutions = 'Erledigt';
|
||||
$lang->execution->selectDept = 'Abteilung wählen';
|
||||
$lang->execution->selectDeptTitle = 'Abteilung wählen';
|
||||
@@ -594,3 +597,6 @@ $lang->execution->gantt->exporting = 'Exporting...';
|
||||
$lang->execution->gantt->exportFail = 'Failed to export.';
|
||||
|
||||
$lang->execution->boardColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761');
|
||||
|
||||
$lang->execution->linkBranchStoryByPlanTips = "When a scheduled association requirement is executed, only the active requirements associated with the %s of this execution are imported.";
|
||||
$lang->execution->linkNormalStoryByPlanTips = "Only the active requirements are imported when the scheduled requirements are associated.";
|
||||
@@ -209,82 +209,84 @@ $lang->execution->burnByList['estimate'] = "View by plan hours";
|
||||
$lang->execution->burnByList['storyPoint'] = 'View by story point';
|
||||
|
||||
/* Method list. */
|
||||
$lang->execution->index = "{$lang->executionCommon} Home";
|
||||
$lang->execution->task = 'Task List';
|
||||
$lang->execution->groupTask = 'Group View';
|
||||
$lang->execution->story = 'Story List';
|
||||
$lang->execution->qa = 'QA';
|
||||
$lang->execution->bug = 'Bug List';
|
||||
$lang->execution->testcase = 'Testcase List';
|
||||
$lang->execution->dynamic = 'Dynamics';
|
||||
$lang->execution->latestDynamic = 'Dynamics';
|
||||
$lang->execution->build = 'Build List';
|
||||
$lang->execution->testtask = 'Request';
|
||||
$lang->execution->burn = 'Burndown';
|
||||
$lang->execution->computeBurn = 'Update';
|
||||
$lang->execution->CFD = 'Cumulative Flow diagrams';
|
||||
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
|
||||
$lang->execution->burnData = 'Burndown Data';
|
||||
$lang->execution->fixFirst = 'Edit 1st-Day Estimates';
|
||||
$lang->execution->team = 'Members';
|
||||
$lang->execution->doc = 'Document';
|
||||
$lang->execution->doclib = 'Docoment Library';
|
||||
$lang->execution->manageProducts = 'Linked ' . $lang->productCommon . 's';
|
||||
$lang->execution->linkStory = 'Link Stories';
|
||||
$lang->execution->linkStoryByPlan = 'Link Stories By Plan';
|
||||
$lang->execution->linkPlan = 'Linked Plan';
|
||||
$lang->execution->unlinkStoryTasks = 'Unlink';
|
||||
$lang->execution->linkedProducts = "Linked {$lang->productCommon}s";
|
||||
$lang->execution->unlinkedProducts = "Unlinked {$lang->productCommon}s";
|
||||
$lang->execution->view = "Execution Detail";
|
||||
$lang->execution->startAction = "Start Execution";
|
||||
$lang->execution->activateAction = "Activate Execution";
|
||||
$lang->execution->delayAction = "Delay Execution";
|
||||
$lang->execution->suspendAction = "Suspend Execution";
|
||||
$lang->execution->closeAction = "Close Execution";
|
||||
$lang->execution->testtaskAction = "Execution Request";
|
||||
$lang->execution->teamAction = "Execution Members";
|
||||
$lang->execution->kanbanAction = "Execution Kanban";
|
||||
$lang->execution->printKanbanAction = "Print Kanban";
|
||||
$lang->execution->treeAction = "Execution Tree View";
|
||||
$lang->execution->exportAction = "Export Execution";
|
||||
$lang->execution->computeBurnAction = "Update Burndown";
|
||||
$lang->execution->create = "Create {$lang->executionCommon}";
|
||||
$lang->execution->createExec = "Create {$lang->execution->common}";
|
||||
$lang->execution->createAction = "Create {$lang->execution->common}";
|
||||
$lang->execution->copyExec = "Copy {$lang->execution->common}";
|
||||
$lang->execution->copy = "Copy {$lang->executionCommon}";
|
||||
$lang->execution->delete = "Delete {$lang->executionCommon}";
|
||||
$lang->execution->deleteAB = "Delete Execution";
|
||||
$lang->execution->browse = "{$lang->executionCommon} List";
|
||||
$lang->execution->edit = "Edit {$lang->executionCommon}";
|
||||
$lang->execution->editAction = "Edit Execution";
|
||||
$lang->execution->batchEdit = "Edit";
|
||||
$lang->execution->batchEditAction = "Batch Edit";
|
||||
$lang->execution->manageMembers = 'Manage Team';
|
||||
$lang->execution->unlinkMember = 'Remove Member';
|
||||
$lang->execution->unlinkStory = 'Unlink Story';
|
||||
$lang->execution->unlinkStoryAB = 'Unlink';
|
||||
$lang->execution->batchUnlinkStory = 'Batch Unlink Stories';
|
||||
$lang->execution->importTask = 'Transfer Task';
|
||||
$lang->execution->importPlanStories = 'Link Stories By Plan';
|
||||
$lang->execution->importBug = 'Import Bug';
|
||||
$lang->execution->tree = 'Tree';
|
||||
$lang->execution->treeTask = 'Show Task Only';
|
||||
$lang->execution->treeStory = 'Show Story Only';
|
||||
$lang->execution->treeViewTask = 'Tree View Task';
|
||||
$lang->execution->treeViewStory = 'Tree View Story';
|
||||
$lang->execution->storyKanban = 'Story Kanban';
|
||||
$lang->execution->storySort = 'Rank Story';
|
||||
$lang->execution->importPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
|
||||
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
|
||||
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
|
||||
$lang->execution->iteration = 'Iterations';
|
||||
$lang->execution->iterationInfo = '%s Iterations';
|
||||
$lang->execution->viewAll = 'View All';
|
||||
$lang->execution->testreport = 'Test Report';
|
||||
$lang->execution->taskKanban = 'Task Kanban';
|
||||
$lang->execution->RDKanban = 'Research & Development Kanban';
|
||||
$lang->execution->index = "{$lang->executionCommon} Home";
|
||||
$lang->execution->task = 'Task List';
|
||||
$lang->execution->groupTask = 'Group View';
|
||||
$lang->execution->story = 'Story List';
|
||||
$lang->execution->qa = 'QA';
|
||||
$lang->execution->bug = 'Bug List';
|
||||
$lang->execution->testcase = 'Testcase List';
|
||||
$lang->execution->dynamic = 'Dynamics';
|
||||
$lang->execution->latestDynamic = 'Dynamics';
|
||||
$lang->execution->build = 'Build List';
|
||||
$lang->execution->testtask = 'Request';
|
||||
$lang->execution->burn = 'Burndown';
|
||||
$lang->execution->computeBurn = 'Update';
|
||||
$lang->execution->CFD = 'Cumulative Flow diagrams';
|
||||
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
|
||||
$lang->execution->burnData = 'Burndown Data';
|
||||
$lang->execution->fixFirst = 'Edit 1st-Day Estimates';
|
||||
$lang->execution->team = 'Members';
|
||||
$lang->execution->doc = 'Document';
|
||||
$lang->execution->doclib = 'Docoment Library';
|
||||
$lang->execution->manageProducts = 'Linked ' . $lang->productCommon . 's';
|
||||
$lang->execution->linkStory = 'Link Stories';
|
||||
$lang->execution->linkStoryByPlan = 'Link Stories By Plan';
|
||||
$lang->execution->linkPlan = 'Linked Plan';
|
||||
$lang->execution->unlinkStoryTasks = 'Unlink';
|
||||
$lang->execution->linkedProducts = "Linked {$lang->productCommon}s";
|
||||
$lang->execution->unlinkedProducts = "Unlinked {$lang->productCommon}s";
|
||||
$lang->execution->view = "Execution Detail";
|
||||
$lang->execution->startAction = "Start Execution";
|
||||
$lang->execution->activateAction = "Activate Execution";
|
||||
$lang->execution->delayAction = "Delay Execution";
|
||||
$lang->execution->suspendAction = "Suspend Execution";
|
||||
$lang->execution->closeAction = "Close Execution";
|
||||
$lang->execution->testtaskAction = "Execution Request";
|
||||
$lang->execution->teamAction = "Execution Members";
|
||||
$lang->execution->kanbanAction = "Execution Kanban";
|
||||
$lang->execution->printKanbanAction = "Print Kanban";
|
||||
$lang->execution->treeAction = "Execution Tree View";
|
||||
$lang->execution->exportAction = "Export Execution";
|
||||
$lang->execution->computeBurnAction = "Update Burndown";
|
||||
$lang->execution->create = "Create {$lang->executionCommon}";
|
||||
$lang->execution->createExec = "Create {$lang->execution->common}";
|
||||
$lang->execution->createAction = "Create {$lang->execution->common}";
|
||||
$lang->execution->copyExec = "Copy {$lang->execution->common}";
|
||||
$lang->execution->copy = "Copy {$lang->executionCommon}";
|
||||
$lang->execution->delete = "Delete {$lang->executionCommon}";
|
||||
$lang->execution->deleteAB = "Delete Execution";
|
||||
$lang->execution->browse = "{$lang->executionCommon} List";
|
||||
$lang->execution->edit = "Edit {$lang->executionCommon}";
|
||||
$lang->execution->editAction = "Edit Execution";
|
||||
$lang->execution->batchEdit = "Edit";
|
||||
$lang->execution->batchEditAction = "Batch Edit";
|
||||
$lang->execution->manageMembers = 'Manage Team';
|
||||
$lang->execution->unlinkMember = 'Remove Member';
|
||||
$lang->execution->unlinkStory = 'Unlink Story';
|
||||
$lang->execution->unlinkStoryAB = 'Unlink';
|
||||
$lang->execution->batchUnlinkStory = 'Batch Unlink Stories';
|
||||
$lang->execution->importTask = 'Transfer Task';
|
||||
$lang->execution->importPlanStories = 'Link Stories By Plan';
|
||||
$lang->execution->importBug = 'Import Bug';
|
||||
$lang->execution->tree = 'Tree';
|
||||
$lang->execution->treeTask = 'Show Task Only';
|
||||
$lang->execution->treeStory = 'Show Story Only';
|
||||
$lang->execution->treeViewTask = 'Tree View Task';
|
||||
$lang->execution->treeViewStory = 'Tree View Story';
|
||||
$lang->execution->storyKanban = 'Story Kanban';
|
||||
$lang->execution->storySort = 'Rank Story';
|
||||
$lang->execution->importPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
|
||||
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
|
||||
$lang->execution->importBranchPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
|
||||
$lang->execution->importBranchEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
|
||||
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
|
||||
$lang->execution->iteration = 'Iterations';
|
||||
$lang->execution->iterationInfo = '%s Iterations';
|
||||
$lang->execution->viewAll = 'View All';
|
||||
$lang->execution->testreport = 'Test Report';
|
||||
$lang->execution->taskKanban = 'Task Kanban';
|
||||
$lang->execution->RDKanban = 'Research & Development Kanban';
|
||||
|
||||
/* Group browsing. */
|
||||
$lang->execution->allTasks = 'All';
|
||||
@@ -349,7 +351,8 @@ $lang->execution->howToUpdateBurn = "<a href='https://api.zentao.pm/goto.ph
|
||||
$lang->execution->whyNoStories = "No story can be linked. Please check whether there is any story in {$lang->executionCommon} which is linked to {$lang->productCommon} and make sure it has been reviewed.";
|
||||
$lang->execution->projectNoStories = "No story can be linked. Please check whether there is any story in project and make sure it has been reviewed.";
|
||||
$lang->execution->productStories = "Stories linked to {$lang->executionCommon} are the subeset of stories linked to {$lang->productCommon}. Stories can only be linked after they pass the review. <a href='%s'> Link Stories</a> now.";
|
||||
$lang->execution->haveDraft = "%s stories in draft, so they can't be linked.";
|
||||
$lang->execution->haveBranchDraft = "There are %s draft stories or not associated with this {$lang->executionCommon} can't be linked.";
|
||||
$lang->execution->haveDraft = "There are %s draft stories with this {$lang->executionCommon} can't be linked.";
|
||||
$lang->execution->doneExecutions = 'Finished';
|
||||
$lang->execution->selectDept = 'Select Department';
|
||||
$lang->execution->selectDeptTitle = 'Select User';
|
||||
@@ -594,3 +597,6 @@ $lang->execution->gantt->exporting = 'Exporting...';
|
||||
$lang->execution->gantt->exportFail = 'Failed to export.';
|
||||
|
||||
$lang->execution->boardColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761');
|
||||
|
||||
$lang->execution->linkBranchStoryByPlanTips = "When a scheduled association requirement is executed, only the active requirements associated with the %s of this execution are imported.";
|
||||
$lang->execution->linkNormalStoryByPlanTips = "Only the active requirements are imported when the scheduled requirements are associated.";
|
||||
@@ -209,82 +209,84 @@ $lang->execution->burnByList['estimate'] = "View by plan hours";
|
||||
$lang->execution->burnByList['storyPoint'] = 'View by story point';
|
||||
|
||||
/* Method list. */
|
||||
$lang->execution->index = "Accueil {$lang->executionCommon}";
|
||||
$lang->execution->task = 'Liste Tâches';
|
||||
$lang->execution->groupTask = 'Vision Groupée';
|
||||
$lang->execution->story = 'Liste Stories';
|
||||
$lang->execution->qa = 'QA';
|
||||
$lang->execution->bug = 'Liste Bugs';
|
||||
$lang->execution->testcase = 'Testcase List';
|
||||
$lang->execution->dynamic = 'Historique';
|
||||
$lang->execution->latestDynamic = 'Historique';
|
||||
$lang->execution->build = 'Liste Builds';
|
||||
$lang->execution->testtask = 'Recette';
|
||||
$lang->execution->burn = ' Atterrissage';
|
||||
$lang->execution->computeBurn = 'Calculer';
|
||||
$lang->execution->CFD = 'Cumulative Flow diagrams';
|
||||
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
|
||||
$lang->execution->burnData = "Données d'atterrissage";
|
||||
$lang->execution->fixFirst = 'Fixer 1er-Jour Estimation';
|
||||
$lang->execution->team = 'Membres';
|
||||
$lang->execution->doc = 'Documents';
|
||||
$lang->execution->doclib = 'Répertoire de Documents';
|
||||
$lang->execution->manageProducts = 'Liaisons du ' . $lang->executionCommon . ' avec les ' . $lang->productCommon . 's';
|
||||
$lang->execution->linkStory = 'Stories liées';
|
||||
$lang->execution->linkStoryByPlan = 'Stories liées par Plan';
|
||||
$lang->execution->linkPlan = 'Plans liés';
|
||||
$lang->execution->unlinkStoryTasks = 'Dissocier';
|
||||
$lang->execution->linkedProducts = "{$lang->productCommon}s liés à ce {$lang->executionCommon}";
|
||||
$lang->execution->unlinkedProducts = "{$lang->productCommon}s dissociés de ce {$lang->executionCommon}";
|
||||
$lang->execution->view = "Détail du Execution";
|
||||
$lang->execution->startAction = "Start Execution";
|
||||
$lang->execution->activateAction = "Activer le Execution";
|
||||
$lang->execution->delayAction = "Ajourner le Execution";
|
||||
$lang->execution->suspendAction = "Suspendre le Execution";
|
||||
$lang->execution->closeAction = "Fermer le Execution";
|
||||
$lang->execution->testtaskAction = "Recettes du Execution";
|
||||
$lang->execution->teamAction = "Membres du Execution";
|
||||
$lang->execution->kanbanAction = "Kaban Execution";
|
||||
$lang->execution->printKanbanAction = "Imprimer le Kanban";
|
||||
$lang->execution->treeAction = "Arborescence Execution";
|
||||
$lang->execution->exportAction = "Exporter Execution";
|
||||
$lang->execution->computeBurnAction = "Calculer Atterrissage";
|
||||
$lang->execution->create = "Créer {$lang->executionCommon}";
|
||||
$lang->execution->createExec = "Create Execution";
|
||||
$lang->execution->createAction = "Create {$lang->execution->common}";
|
||||
$lang->execution->copyExec = "Copy Execution";
|
||||
$lang->execution->copy = "Copier {$lang->executionCommon}";
|
||||
$lang->execution->delete = "Supprimer {$lang->executionCommon}";
|
||||
$lang->execution->deleteAB = "Delete Execution";
|
||||
$lang->execution->browse = "Liste du {$lang->executionCommon}";
|
||||
$lang->execution->edit = "Editer {$lang->executionCommon}";
|
||||
$lang->execution->editAction = "Edit Execution";
|
||||
$lang->execution->batchEdit = "Edition par lot";
|
||||
$lang->execution->batchEditAction = "Batch Edit";
|
||||
$lang->execution->manageMembers = 'Organiser Equipe';
|
||||
$lang->execution->unlinkMember = 'Retirer le membre';
|
||||
$lang->execution->unlinkStory = 'Dissocier Story';
|
||||
$lang->execution->unlinkStoryAB = 'Dissocier';
|
||||
$lang->execution->batchUnlinkStory = 'Dissocier Stories par lot';
|
||||
$lang->execution->importTask = 'Transfert Tâche';
|
||||
$lang->execution->importPlanStories = 'Lier Stories Par Plan';
|
||||
$lang->execution->importBug = 'Importer Bug';
|
||||
$lang->execution->tree = 'Arboressence';
|
||||
$lang->execution->treeTask = 'Seulement les Tâches';
|
||||
$lang->execution->treeStory = 'Seulement les Stories';
|
||||
$lang->execution->treeViewTask = 'Seulement les Tâches';
|
||||
$lang->execution->treeViewStory = 'Seulement les Stories';
|
||||
$lang->execution->storyKanban = 'Story Kanban';
|
||||
$lang->execution->storySort = 'Rang Story';
|
||||
$lang->execution->importPlanStory = $lang->executionCommon . ' est créé!\nVoulez-vous importer des stories qui ont été ajoutées au Plan ?';
|
||||
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
|
||||
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
|
||||
$lang->execution->iteration = 'Itérations';
|
||||
$lang->execution->iterationInfo = '%s Itérations';
|
||||
$lang->execution->viewAll = 'Voir Tout';
|
||||
$lang->execution->testreport = 'Test Report';
|
||||
$lang->execution->taskKanban = 'Task Kanban';
|
||||
$lang->execution->RDKanban = 'Research & Development Kanban';
|
||||
$lang->execution->index = "{$lang->executionCommon} Home";
|
||||
$lang->execution->task = 'Task List';
|
||||
$lang->execution->groupTask = 'Group View';
|
||||
$lang->execution->story = 'Story List';
|
||||
$lang->execution->qa = 'QA';
|
||||
$lang->execution->bug = 'Bug List';
|
||||
$lang->execution->testcase = 'Testcase List';
|
||||
$lang->execution->dynamic = 'Dynamics';
|
||||
$lang->execution->latestDynamic = 'Dynamics';
|
||||
$lang->execution->build = 'Build List';
|
||||
$lang->execution->testtask = 'Request';
|
||||
$lang->execution->burn = 'Burndown';
|
||||
$lang->execution->computeBurn = 'Update';
|
||||
$lang->execution->CFD = 'Cumulative Flow diagrams';
|
||||
$lang->execution->computeCFD = 'Compute Cumulative Flow diagrams';
|
||||
$lang->execution->burnData = 'Burndown Data';
|
||||
$lang->execution->fixFirst = 'Edit 1st-Day Estimates';
|
||||
$lang->execution->team = 'Members';
|
||||
$lang->execution->doc = 'Document';
|
||||
$lang->execution->doclib = 'Docoment Library';
|
||||
$lang->execution->manageProducts = 'Linked ' . $lang->productCommon . 's';
|
||||
$lang->execution->linkStory = 'Link Stories';
|
||||
$lang->execution->linkStoryByPlan = 'Link Stories By Plan';
|
||||
$lang->execution->linkPlan = 'Linked Plan';
|
||||
$lang->execution->unlinkStoryTasks = 'Unlink';
|
||||
$lang->execution->linkedProducts = "Linked {$lang->productCommon}s";
|
||||
$lang->execution->unlinkedProducts = "Unlinked {$lang->productCommon}s";
|
||||
$lang->execution->view = "Execution Detail";
|
||||
$lang->execution->startAction = "Start Execution";
|
||||
$lang->execution->activateAction = "Activate Execution";
|
||||
$lang->execution->delayAction = "Delay Execution";
|
||||
$lang->execution->suspendAction = "Suspend Execution";
|
||||
$lang->execution->closeAction = "Close Execution";
|
||||
$lang->execution->testtaskAction = "Execution Request";
|
||||
$lang->execution->teamAction = "Execution Members";
|
||||
$lang->execution->kanbanAction = "Execution Kanban";
|
||||
$lang->execution->printKanbanAction = "Print Kanban";
|
||||
$lang->execution->treeAction = "Execution Tree View";
|
||||
$lang->execution->exportAction = "Export Execution";
|
||||
$lang->execution->computeBurnAction = "Update Burndown";
|
||||
$lang->execution->create = "Create {$lang->executionCommon}";
|
||||
$lang->execution->createExec = "Create {$lang->execution->common}";
|
||||
$lang->execution->createAction = "Create {$lang->execution->common}";
|
||||
$lang->execution->copyExec = "Copy {$lang->execution->common}";
|
||||
$lang->execution->copy = "Copy {$lang->executionCommon}";
|
||||
$lang->execution->delete = "Delete {$lang->executionCommon}";
|
||||
$lang->execution->deleteAB = "Delete Execution";
|
||||
$lang->execution->browse = "{$lang->executionCommon} List";
|
||||
$lang->execution->edit = "Edit {$lang->executionCommon}";
|
||||
$lang->execution->editAction = "Edit Execution";
|
||||
$lang->execution->batchEdit = "Edit";
|
||||
$lang->execution->batchEditAction = "Batch Edit";
|
||||
$lang->execution->manageMembers = 'Manage Team';
|
||||
$lang->execution->unlinkMember = 'Remove Member';
|
||||
$lang->execution->unlinkStory = 'Unlink Story';
|
||||
$lang->execution->unlinkStoryAB = 'Unlink';
|
||||
$lang->execution->batchUnlinkStory = 'Batch Unlink Stories';
|
||||
$lang->execution->importTask = 'Transfer Task';
|
||||
$lang->execution->importPlanStories = 'Link Stories By Plan';
|
||||
$lang->execution->importBug = 'Import Bug';
|
||||
$lang->execution->tree = 'Tree';
|
||||
$lang->execution->treeTask = 'Show Task Only';
|
||||
$lang->execution->treeStory = 'Show Story Only';
|
||||
$lang->execution->treeViewTask = 'Tree View Task';
|
||||
$lang->execution->treeViewStory = 'Tree View Story';
|
||||
$lang->execution->storyKanban = 'Story Kanban';
|
||||
$lang->execution->storySort = 'Rank Story';
|
||||
$lang->execution->importPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
|
||||
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
|
||||
$lang->execution->importBranchPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
|
||||
$lang->execution->importBranchEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? Only the activation stories of the branch associated with this ' .$lang->executionCommon. ' will be associated with the import';
|
||||
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
|
||||
$lang->execution->iteration = 'Iterations';
|
||||
$lang->execution->iterationInfo = '%s Iterations';
|
||||
$lang->execution->viewAll = 'View All';
|
||||
$lang->execution->testreport = 'Test Report';
|
||||
$lang->execution->taskKanban = 'Task Kanban';
|
||||
$lang->execution->RDKanban = 'Research & Development Kanban';
|
||||
|
||||
/* Group browsing. */
|
||||
$lang->execution->allTasks = 'Toutes';
|
||||
@@ -349,7 +351,8 @@ $lang->execution->howToUpdateBurn = "<a href='https://api.zentao.pm/goto.ph
|
||||
$lang->execution->whyNoStories = "Aucune story ne peut être associée. Vérifiez s'il existe des stories dans {$lang->executionCommon} qui sont associées à {$lang->productCommon} et vérifiez qu'elles ont bien été validées.";
|
||||
$lang->execution->projectNoStories = "No story can be linked. Please check whether there is any story in project and make sure it has been reviewed.";
|
||||
$lang->execution->productStories = "Les stories associées au {$lang->executionCommon} sont une portion des stories associées au {$lang->productCommon}. Les stories ne peuvent être associées à un {$lang->executionCommon} qu'après avoir été validées. <a href='%s'> Associer Stories</a> maintenant.";
|
||||
$lang->execution->haveDraft = "%s stories sont encore en conception, elles ne peuvent pas être associées au {$lang->executionCommon} actuellement.";
|
||||
$lang->execution->haveBranchDraft = "There are %s draft stories or not associated with this {$lang->executionCommon} can't be linked.";
|
||||
$lang->execution->haveDraft = "There are %s draft stories with this {$lang->executionCommon} can't be linked.";
|
||||
$lang->execution->doneExecutions = 'Terminé';
|
||||
$lang->execution->selectDept = 'Sélection Compartiment';
|
||||
$lang->execution->selectDeptTitle = 'Sélection Utilisateur';
|
||||
@@ -594,3 +597,6 @@ $lang->execution->gantt->exporting = 'Exporting...';
|
||||
$lang->execution->gantt->exportFail = 'Failed to export.';
|
||||
|
||||
$lang->execution->boardColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761');
|
||||
|
||||
$lang->execution->linkBranchStoryByPlanTips = "When a scheduled association requirement is executed, only the active requirements associated with the %s of this execution are imported.";
|
||||
$lang->execution->linkNormalStoryByPlanTips = "Only the active requirements are imported when the scheduled requirements are associated.";
|
||||
@@ -209,82 +209,84 @@ $lang->execution->burnByList['estimate'] = "按计划工时查看";
|
||||
$lang->execution->burnByList['storyPoint'] = '按故事点查看';
|
||||
|
||||
/* 方法列表。*/
|
||||
$lang->execution->index = "{$lang->execution->common}主页";
|
||||
$lang->execution->task = '任务列表';
|
||||
$lang->execution->groupTask = '分组浏览任务';
|
||||
$lang->execution->story = "{$lang->SRCommon}列表";
|
||||
$lang->execution->qa = '测试仪表盘';
|
||||
$lang->execution->bug = 'Bug列表';
|
||||
$lang->execution->testcase = '用例列表';
|
||||
$lang->execution->dynamic = '动态';
|
||||
$lang->execution->latestDynamic = '最新动态';
|
||||
$lang->execution->build = '所有版本';
|
||||
$lang->execution->testtask = '测试单';
|
||||
$lang->execution->burn = '燃尽图';
|
||||
$lang->execution->computeBurn = '更新燃尽图';
|
||||
$lang->execution->CFD = '累积流图';
|
||||
$lang->execution->computeCFD = '更新累积流图';
|
||||
$lang->execution->burnData = '燃尽图数据';
|
||||
$lang->execution->fixFirst = '修改首天工时';
|
||||
$lang->execution->team = '团队成员';
|
||||
$lang->execution->doc = '文档列表';
|
||||
$lang->execution->doclib = '文档库列表';
|
||||
$lang->execution->manageProducts = '关联' . $lang->productCommon;
|
||||
$lang->execution->linkStory = "关联{$lang->SRCommon}";
|
||||
$lang->execution->linkStoryByPlan = "按照计划关联";
|
||||
$lang->execution->linkPlan = "关联计划";
|
||||
$lang->execution->unlinkStoryTasks = "未关联{$lang->SRCommon}任务";
|
||||
$lang->execution->linkedProducts = '已关联';
|
||||
$lang->execution->unlinkedProducts = '未关联';
|
||||
$lang->execution->view = "{$lang->execution->common}概况";
|
||||
$lang->execution->startAction = "开始{$lang->execution->common}";
|
||||
$lang->execution->activateAction = "激活{$lang->execution->common}";
|
||||
$lang->execution->delayAction = "延期{$lang->execution->common}";
|
||||
$lang->execution->suspendAction = "挂起{$lang->execution->common}";
|
||||
$lang->execution->closeAction = "关闭{$lang->execution->common}";
|
||||
$lang->execution->testtaskAction = "{$lang->execution->common}测试单";
|
||||
$lang->execution->teamAction = "{$lang->execution->common}团队";
|
||||
$lang->execution->kanbanAction = "{$lang->execution->common}看板";
|
||||
$lang->execution->printKanbanAction = "打印看板";
|
||||
$lang->execution->treeAction = "{$lang->execution->common}树状图";
|
||||
$lang->execution->exportAction = "导出{$lang->execution->common}";
|
||||
$lang->execution->computeBurnAction = "计算燃尽图";
|
||||
$lang->execution->create = "添加{$lang->executionCommon}";
|
||||
$lang->execution->createExec = "添加{$lang->execution->common}";
|
||||
$lang->execution->createAction = "添加{$lang->execution->common}";
|
||||
$lang->execution->copyExec = "复制{$lang->execution->common}";
|
||||
$lang->execution->copy = "复制{$lang->executionCommon}";
|
||||
$lang->execution->delete = "删除{$lang->executionCommon}";
|
||||
$lang->execution->deleteAB = "删除{$lang->execution->common}";
|
||||
$lang->execution->browse = "浏览{$lang->execution->common}";
|
||||
$lang->execution->edit = "设置{$lang->executionCommon}";
|
||||
$lang->execution->editAction = "编辑{$lang->execution->common}";
|
||||
$lang->execution->batchEdit = "编辑";
|
||||
$lang->execution->batchEditAction = "批量编辑";
|
||||
$lang->execution->manageMembers = '团队管理';
|
||||
$lang->execution->unlinkMember = '移除成员';
|
||||
$lang->execution->unlinkStory = "移除{$lang->SRCommon}";
|
||||
$lang->execution->unlinkStoryAB = "移除{$lang->SRCommon}";
|
||||
$lang->execution->batchUnlinkStory = "批量移除{$lang->SRCommon}";
|
||||
$lang->execution->importTask = '转入任务';
|
||||
$lang->execution->importPlanStories = "按计划关联{$lang->SRCommon}";
|
||||
$lang->execution->importBug = '导入Bug';
|
||||
$lang->execution->tree = '树状图';
|
||||
$lang->execution->treeTask = '只看任务';
|
||||
$lang->execution->treeStory = "只看{$lang->SRCommon}";
|
||||
$lang->execution->treeViewTask = '树状图查看任务';
|
||||
$lang->execution->treeViewStory = "树状图查看{$lang->SRCommon}";
|
||||
$lang->execution->storyKanban = "{$lang->SRCommon}看板";
|
||||
$lang->execution->storySort = "{$lang->SRCommon}排序";
|
||||
$lang->execution->importPlanStory = '创建' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将自动过滤掉草稿状态的' . $lang->SRCommon . '。';
|
||||
$lang->execution->importEditPlanStory = '编辑' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将自动过滤掉草稿状态的' . $lang->SRCommon . '。';
|
||||
$lang->execution->needLinkProducts = '该执行还未关联任何产品,相关功能无法使用,请先关联产品后再试。';
|
||||
$lang->execution->iteration = '版本迭代';
|
||||
$lang->execution->iterationInfo = '迭代%s次';
|
||||
$lang->execution->viewAll = '查看所有';
|
||||
$lang->execution->testreport = '测试报告';
|
||||
$lang->execution->taskKanban = '任务看板';
|
||||
$lang->execution->RDKanban = '研发看板';
|
||||
$lang->execution->index = "{$lang->execution->common}主页";
|
||||
$lang->execution->task = '任务列表';
|
||||
$lang->execution->groupTask = '分组浏览任务';
|
||||
$lang->execution->story = "{$lang->SRCommon}列表";
|
||||
$lang->execution->qa = '测试仪表盘';
|
||||
$lang->execution->bug = 'Bug列表';
|
||||
$lang->execution->testcase = '用例列表';
|
||||
$lang->execution->dynamic = '动态';
|
||||
$lang->execution->latestDynamic = '最新动态';
|
||||
$lang->execution->build = '所有版本';
|
||||
$lang->execution->testtask = '测试单';
|
||||
$lang->execution->burn = '燃尽图';
|
||||
$lang->execution->computeBurn = '更新燃尽图';
|
||||
$lang->execution->CFD = '累积流图';
|
||||
$lang->execution->computeCFD = '更新累积流图';
|
||||
$lang->execution->burnData = '燃尽图数据';
|
||||
$lang->execution->fixFirst = '修改首天工时';
|
||||
$lang->execution->team = '团队成员';
|
||||
$lang->execution->doc = '文档列表';
|
||||
$lang->execution->doclib = '文档库列表';
|
||||
$lang->execution->manageProducts = '关联' . $lang->productCommon;
|
||||
$lang->execution->linkStory = "关联{$lang->SRCommon}";
|
||||
$lang->execution->linkStoryByPlan = "按照计划关联";
|
||||
$lang->execution->linkPlan = "关联计划";
|
||||
$lang->execution->unlinkStoryTasks = "未关联{$lang->SRCommon}任务";
|
||||
$lang->execution->linkedProducts = '已关联';
|
||||
$lang->execution->unlinkedProducts = '未关联';
|
||||
$lang->execution->view = "{$lang->execution->common}概况";
|
||||
$lang->execution->startAction = "开始{$lang->execution->common}";
|
||||
$lang->execution->activateAction = "激活{$lang->execution->common}";
|
||||
$lang->execution->delayAction = "延期{$lang->execution->common}";
|
||||
$lang->execution->suspendAction = "挂起{$lang->execution->common}";
|
||||
$lang->execution->closeAction = "关闭{$lang->execution->common}";
|
||||
$lang->execution->testtaskAction = "{$lang->execution->common}测试单";
|
||||
$lang->execution->teamAction = "{$lang->execution->common}团队";
|
||||
$lang->execution->kanbanAction = "{$lang->execution->common}看板";
|
||||
$lang->execution->printKanbanAction = "打印看板";
|
||||
$lang->execution->treeAction = "{$lang->execution->common}树状图";
|
||||
$lang->execution->exportAction = "导出{$lang->execution->common}";
|
||||
$lang->execution->computeBurnAction = "计算燃尽图";
|
||||
$lang->execution->create = "添加{$lang->executionCommon}";
|
||||
$lang->execution->createExec = "添加{$lang->execution->common}";
|
||||
$lang->execution->createAction = "添加{$lang->execution->common}";
|
||||
$lang->execution->copyExec = "复制{$lang->execution->common}";
|
||||
$lang->execution->copy = "复制{$lang->executionCommon}";
|
||||
$lang->execution->delete = "删除{$lang->executionCommon}";
|
||||
$lang->execution->deleteAB = "删除{$lang->execution->common}";
|
||||
$lang->execution->browse = "浏览{$lang->execution->common}";
|
||||
$lang->execution->edit = "设置{$lang->executionCommon}";
|
||||
$lang->execution->editAction = "编辑{$lang->execution->common}";
|
||||
$lang->execution->batchEdit = "编辑";
|
||||
$lang->execution->batchEditAction = "批量编辑";
|
||||
$lang->execution->manageMembers = '团队管理';
|
||||
$lang->execution->unlinkMember = '移除成员';
|
||||
$lang->execution->unlinkStory = "移除{$lang->SRCommon}";
|
||||
$lang->execution->unlinkStoryAB = "移除{$lang->SRCommon}";
|
||||
$lang->execution->batchUnlinkStory = "批量移除{$lang->SRCommon}";
|
||||
$lang->execution->importTask = '转入任务';
|
||||
$lang->execution->importPlanStories = "按计划关联{$lang->SRCommon}";
|
||||
$lang->execution->importBug = '导入Bug';
|
||||
$lang->execution->tree = '树状图';
|
||||
$lang->execution->treeTask = '只看任务';
|
||||
$lang->execution->treeStory = "只看{$lang->SRCommon}";
|
||||
$lang->execution->treeViewTask = '树状图查看任务';
|
||||
$lang->execution->treeViewStory = "树状图查看{$lang->SRCommon}";
|
||||
$lang->execution->storyKanban = "{$lang->SRCommon}看板";
|
||||
$lang->execution->storySort = "{$lang->SRCommon}排序";
|
||||
$lang->execution->importPlanStory = '创建' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将自动过滤掉草稿状态的' . $lang->SRCommon . '。';
|
||||
$lang->execution->importEditPlanStory = '编辑' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将自动过滤掉草稿状态的' . $lang->SRCommon . '。';
|
||||
$lang->execution->importBranchPlanStory = '创建' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将只关联本' . $lang->executionCommon . '所关联分支的激活需求。';
|
||||
$lang->execution->importBranchEditPlanStory = '编辑' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '?导入时将只关联本' . $lang->executionCommon . '所关联分支的激活需求。';
|
||||
$lang->execution->needLinkProducts = '该执行还未关联任何产品,相关功能无法使用,请先关联产品后再试。';
|
||||
$lang->execution->iteration = '版本迭代';
|
||||
$lang->execution->iterationInfo = '迭代%s次';
|
||||
$lang->execution->viewAll = '查看所有';
|
||||
$lang->execution->testreport = '测试报告';
|
||||
$lang->execution->taskKanban = '任务看板';
|
||||
$lang->execution->RDKanban = '研发看板';
|
||||
|
||||
/* 分组浏览。*/
|
||||
$lang->execution->allTasks = '所有';
|
||||
@@ -349,7 +351,8 @@ $lang->execution->howToUpdateBurn = "<a href='https://api.zentao.net/goto.p
|
||||
$lang->execution->whyNoStories = "看起来没有{$lang->SRCommon}可以关联。请检查下{$lang->executionCommon}关联的{$lang->productCommon}中有没有{$lang->SRCommon},而且要确保它们已经审核通过。";
|
||||
$lang->execution->projectNoStories = "看起来没有{$lang->SRCommon}可以关联。请检查下项目中有没有{$lang->SRCommon},而且要确保它们已经审核通过。";
|
||||
$lang->execution->productStories = "{$lang->executionCommon}关联的{$lang->SRCommon}是{$lang->productCommon}{$lang->SRCommon}的子集,并且只有评审通过的{$lang->SRCommon}才能关联。请<a href='%s'>关联{$lang->SRCommon}</a>。";
|
||||
$lang->execution->haveDraft = "有%s条草稿状态的{$lang->SRCommon}无法关联到该{$lang->executionCommon}";
|
||||
$lang->execution->haveBranchDraft = "导入完成!有%s条非激活状态或不是{$lang->executionCommon}关联分支的{$lang->SRCommon}无法导入";
|
||||
$lang->execution->haveDraft = "导入完成!有%s条非激活状态的{$lang->SRCommon}无法导入";
|
||||
$lang->execution->doneExecutions = '已结束';
|
||||
$lang->execution->selectDept = '选择部门';
|
||||
$lang->execution->selectDeptTitle = '选择一个部门的成员';
|
||||
@@ -594,3 +597,6 @@ $lang->execution->gantt->exporting = '正在导出……';
|
||||
$lang->execution->gantt->exportFail = '导出失败。';
|
||||
|
||||
$lang->execution->boardColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761');
|
||||
|
||||
$lang->execution->linkBranchStoryByPlanTips = "执行按计划关联需求时,只导入本执行所关联%s的激活状态的需求。";
|
||||
$lang->execution->linkNormalStoryByPlanTips = "执行按计划关联需求时,只导入激活状态的需求。";
|
||||
+85
-26
@@ -332,6 +332,20 @@ class executionModel extends model
|
||||
$this->checkBeginAndEndDate($_POST['project'], $_POST['begin'], $_POST['end']);
|
||||
if(dao::isError()) return false;
|
||||
|
||||
if($_POST['products'])
|
||||
{
|
||||
$this->app->loadLang('project');
|
||||
$multipleProducts = $this->loadModel('product')->getMultiBranchPairs();
|
||||
foreach($_POST['products'] as $index => $productID)
|
||||
{
|
||||
if(isset($multipleProducts[$productID]) and empty($_POST['branch'][$index]))
|
||||
{
|
||||
dao::$errors[] = $this->lang->project->emptyBranch;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine whether to add a sprint or a stage according to the model of the execution. */
|
||||
$project = $this->loadModel('project')->getByID($_POST['project']);
|
||||
$type = 'sprint';
|
||||
@@ -514,6 +528,20 @@ class executionModel extends model
|
||||
return false;
|
||||
}
|
||||
|
||||
if($_POST['products'])
|
||||
{
|
||||
$this->app->loadLang('project');
|
||||
$multipleProducts = $this->loadModel('product')->getMultiBranchPairs();
|
||||
foreach($_POST['products'] as $index => $productID)
|
||||
{
|
||||
if(isset($multipleProducts[$productID]) and empty($_POST['branch'][$index]))
|
||||
{
|
||||
dao::$errors[] = $this->lang->project->emptyBranch;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the data from the post. */
|
||||
$execution = fixer::input('post')
|
||||
->add('id', $executionID)
|
||||
@@ -2288,7 +2316,7 @@ class executionModel extends model
|
||||
$planPairs = array('' => '');
|
||||
foreach($products as $productID => $product)
|
||||
{
|
||||
$plans = $this->productplan->getBranchPlanPairs($productID, array(BRANCH_MAIN) + $product->branches, true);
|
||||
$plans = $this->productplan->getBranchPlanPairs($productID, array(BRANCH_MAIN) + $product->branches, 'unexpired', true);
|
||||
foreach($plans as $plan) $planPairs += $plan;
|
||||
}
|
||||
$this->config->product->search['params']['plan']['values'] = $planPairs;
|
||||
@@ -2370,23 +2398,28 @@ class executionModel extends model
|
||||
$oldPlan = 0;
|
||||
$branch = isset($branches[$i]) ? $branches[$i] : 0;
|
||||
|
||||
if(isset($existedProducts[$productID][$branch])) continue;
|
||||
if(!is_array($branch)) $branch = array($branch);
|
||||
|
||||
if(isset($oldProducts[$productID][$branch]))
|
||||
foreach($branch as $branchID)
|
||||
{
|
||||
$oldProduct = $oldProducts[$productID][$branch];
|
||||
if($this->app->rawMethod != 'edit') $oldPlan = $oldProduct->plan;
|
||||
}
|
||||
if(isset($existedProducts[$productID][$branchID])) continue;
|
||||
|
||||
$data = new stdclass();
|
||||
$data->project = $executionID;
|
||||
$data->product = $productID;
|
||||
$data->branch = $branch;
|
||||
$data->plan = isset($plans[$productID][$branch]) ? implode(',', $plans[$productID][$branch]) : $oldPlan;
|
||||
$data->plan = trim($data->plan, ',');
|
||||
$data->plan = empty($data->plan) ? 0 : ",$data->plan,";
|
||||
$this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec();
|
||||
$existedProducts[$productID][$branch] = true;
|
||||
if(isset($oldProducts[$productID][$branchID]))
|
||||
{
|
||||
$oldProduct = $oldProducts[$productID][$branchID];
|
||||
if($this->app->rawMethod != 'edit') $oldPlan = $oldProduct->plan;
|
||||
}
|
||||
|
||||
$data = new stdclass();
|
||||
$data->project = $executionID;
|
||||
$data->product = $productID;
|
||||
$data->branch = $branchID;
|
||||
$data->plan = isset($plans[$productID]) ? implode(',', $plans[$productID]) : $oldPlan;
|
||||
$data->plan = trim($data->plan, ',');
|
||||
$data->plan = empty($data->plan) ? 0 : ",$data->plan,";
|
||||
$this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec();
|
||||
$existedProducts[$productID][$branchID] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$oldProductKeys = array_keys($oldProducts);
|
||||
@@ -2882,19 +2915,21 @@ class executionModel extends model
|
||||
*/
|
||||
public function linkStories($executionID)
|
||||
{
|
||||
$plans = $this->dao->select('plan')->from(TABLE_PROJECTPRODUCT)
|
||||
$plans = $this->dao->select('product, plan')->from(TABLE_PROJECTPRODUCT)
|
||||
->where('project')->eq($executionID)
|
||||
->fetchPairs('plan');
|
||||
->fetchPairs('product', 'plan');
|
||||
|
||||
$planStories = array();
|
||||
$planProducts = array();
|
||||
$this->loadModel('story');
|
||||
if(!empty($plans))
|
||||
{
|
||||
foreach($plans as $planIdList)
|
||||
$executionProducts = $this->loadModel('project')->getBranchesByProject($executionID);
|
||||
foreach($plans as $productID => $planIdList)
|
||||
{
|
||||
if(empty($planIdList)) continue;
|
||||
$planIdList = explode(',', $planIdList);
|
||||
$executionBranches = zget($executionProducts, $productID, array());
|
||||
foreach($planIdList as $planID)
|
||||
{
|
||||
$planStory = $this->story->getPlanStories($planID);
|
||||
@@ -2902,7 +2937,7 @@ class executionModel extends model
|
||||
{
|
||||
foreach($planStory as $id => $story)
|
||||
{
|
||||
if($story->status == 'draft' or $story->status == 'reviewing')
|
||||
if($story->status != 'active' or (!empty($story->branch) and !empty($executionBranches) and !isset($executionBranches[$story->branch])))
|
||||
{
|
||||
unset($planStory[$id]);
|
||||
continue;
|
||||
@@ -4618,22 +4653,45 @@ class executionModel extends model
|
||||
{
|
||||
$this->loadModel('productplan');
|
||||
|
||||
$date = date('Y-m-d');
|
||||
|
||||
$param = strtolower($param);
|
||||
$branchIdList = strpos($param, 'withmainplan') !== false ? array(BRANCH_MAIN => BRANCH_MAIN) : array();
|
||||
$branchGroups = $this->getBranchByProduct(array_keys($products), $executionID, 'noclosed');
|
||||
foreach($branchGroups as $branches)
|
||||
{
|
||||
foreach($branches as $branchID => $branchName) $branchIdList[$branchID] = $branchID;
|
||||
foreach($branches as $branchID => $branchName) $branchIdList[] = $branchID;
|
||||
}
|
||||
|
||||
$plans = $this->dao->select('id,title,product,parent,begin,end')->from(TABLE_PRODUCTPLAN)
|
||||
->where('product')->in(array_keys($products))
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('branch')->in($branchIdList)->fi()
|
||||
->orderBy('begin desc')
|
||||
$branchQuery = '(';
|
||||
if(!empty($branchIdList))
|
||||
{
|
||||
$branchCount = count($branchIdList);
|
||||
foreach($branchIdList as $index => $branchID)
|
||||
{
|
||||
$branchQuery .= "FIND_IN_SET('$branchID', branch)";
|
||||
if($index < $branchCount - 1) $branchQuery .= ' OR ';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$branchQuery .= "FIND_IN_SET('0', branch)";
|
||||
}
|
||||
|
||||
$branchQuery .= ')';
|
||||
|
||||
$plans = $this->dao->select('t1.id,t1.title,t1.product,t1.parent,t1.begin,t1.end,t1.branch,t2.type as productType')->from(TABLE_PRODUCTPLAN)->alias('t1')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t2.id=t1.product')
|
||||
->where('t1.product')->in(array_keys($products))
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->andWhere($branchQuery)
|
||||
->beginIF(strpos($param, 'unexpired') !== false)->andWhere('t1.end')->ge($date)->fi()
|
||||
->beginIF(strpos($param, 'noclosed') !== false)->andWhere('t1.status')->ne('closed')->fi()
|
||||
->orderBy('t1.begin desc')
|
||||
->fetchAll('id');
|
||||
|
||||
$plans = $this->productplan->reorder4Children($plans);
|
||||
$plans = $this->productplan->relationBranch($plans);
|
||||
$productPlans = array();
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
@@ -4641,6 +4699,7 @@ class executionModel extends model
|
||||
if($plan->parent > 0 and isset($plans[$plan->parent])) $plan->title = $plans[$plan->parent]->title . ' /' . $plan->title;
|
||||
$productPlans[$plan->product][$plan->id] = $plan->title . " [{$plan->begin} ~ {$plan->end}]";
|
||||
if($plan->begin == '2030-01-01' and $plan->end == '2030-01-01') $productPlans[$plan->product][$plan->id] = $plan->title . ' ' . $this->lang->productplan->future;
|
||||
if($plan->productType != 'normal') $productPlans[$plan->product][$plan->id] = $productPlans[$plan->product][$plan->id] . ' / ' . ($plan->branchName ? $plan->branchName : $this->lang->branch->main);
|
||||
}
|
||||
|
||||
return $productPlans;
|
||||
@@ -5202,7 +5261,7 @@ class executionModel extends model
|
||||
$_POST['status'] = $project->status;
|
||||
$_POST['acl'] = 'open';
|
||||
|
||||
if(!empty($_POST['code'])) $_POST['code'] = $project->code;
|
||||
if(!isset($this->config->setCode) or $this->config->setCode == 1) $_POST['code'] = $project->code;
|
||||
|
||||
$projectProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchAll();
|
||||
foreach($projectProducts as $projectProduct)
|
||||
|
||||
@@ -49,10 +49,12 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="c-id-sm"><?php echo $lang->build->id;?></th>
|
||||
<th class="c-name w-200px text-left <?php echo $hidden;?>"><?php echo $lang->build->product;?></th>
|
||||
<th class="c-name w-150px text-left <?php echo $hidden;?>"><?php echo $lang->build->product;?></th>
|
||||
<?php if($showBranch):?>
|
||||
<th class="c-name w-150px text-left <?php echo $hidden;?>"><?php echo $lang->build->branch;?></th>
|
||||
<?php endif;?>
|
||||
<th class="c-name text-left"><?php echo $lang->build->name;?></th>
|
||||
<th class="c-url"><?php echo $lang->build->scmPath;?></th>
|
||||
<th class="c-url"><?php echo $lang->build->filePath;?></th>
|
||||
<th class="c-url w-200px text-left"><?php echo $lang->build->url;?></th>
|
||||
<th class="c-date"><?php echo $lang->build->date;?></th>
|
||||
<th class="c-user"><?php echo $lang->build->builder;?></th>
|
||||
<th class="c-actions-5"><?php echo $lang->actions;?></th>
|
||||
@@ -64,12 +66,30 @@
|
||||
<tr data-id="<?php echo $productID;?>">
|
||||
<td class="c-id-sm text-muted"><?php echo html::a(helper::createLink('build', 'view', "buildID=$build->id"), sprintf('%03d', $build->id));?></td>
|
||||
<td class="c-name text-left <?php echo $hidden;?>" title='<?php echo $build->productName;?>'><?php echo $build->productName;?></td>
|
||||
<td class="c-name">
|
||||
<?php if($build->branchName) echo "<span class='label label-outline label-badge'>{$build->branchName}</span>"?>
|
||||
<?php echo html::a($this->createLink('build', 'view', "build=$build->id"), $build->name);?>
|
||||
<?php if($showBranch):?>
|
||||
<td class="c-name text-left <?php echo $hidden;?>" title='<?php echo $build->branchName;?>'><?php echo $build->branchName;?></td>
|
||||
<?php endif;?>
|
||||
<td class="c-name"><?php echo html::a($this->createLink('build', 'view', "build=$build->id"), $build->name);?></td>
|
||||
<td class="c-url text-left">
|
||||
<?php
|
||||
if($build->scmPath)
|
||||
{
|
||||
$colorStyle = strpos($build->scmPath, 'http') === 0 ? "style='color:#2463c7;'" : '';
|
||||
echo "<div><i class='icon icon-file-code' $colorStyle title='{$lang->build->scmPath}'></i> ";
|
||||
echo "<span title='{$build->scmPath}'>";
|
||||
echo $colorStyle ? html::a($build->scmPath, $build->scmPath, '_blank', $colorStyle) : $build->scmPath;
|
||||
echo '</span></div>';
|
||||
}
|
||||
if($build->filePath)
|
||||
{
|
||||
$colorStyle = strpos($build->filePath, 'http') === 0 ? "style='color:#2463c7;'" : '';
|
||||
echo "<div><i class='icon icon-download' $colorStyle title='{$lang->build->filePath}'></i> ";
|
||||
echo "<span title='{$build->filePath}'>";
|
||||
echo $colorStyle ? html::a($build->filePath, $build->filePath, '_blank', $colorStyle) : $build->filePath;
|
||||
echo '</span></div>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="c-url" title="<?php echo $build->scmPath?>"><?php echo strpos($build->scmPath, 'http') === 0 ? html::a($build->scmPath) : $build->scmPath;?></td>
|
||||
<td class="c-url" title="<?php echo $build->filePath?>"><?php echo strpos($build->filePath, 'http') === 0 ? html::a($build->filePath) : $build->filePath;?></td>
|
||||
<td class="c-date"><?php echo $build->date?></td>
|
||||
<td class="c-user em"><?php echo zget($users, $build->builder);?></td>
|
||||
<td class="c-actions"><?php echo $this->build->buildOperateMenu($build, 'browse', "executionID={$execution->id}&productID={$productID}");?></td>
|
||||
|
||||
@@ -130,62 +130,81 @@
|
||||
<?php $this->printExtendFields('', 'table', 'columns=3');?>
|
||||
<?php $hidden = 'hide'?>
|
||||
<?php if(!empty($project->hasProduct)) $hidden = ''?>
|
||||
<?php if($products):?>
|
||||
<?php $i = 0;?>
|
||||
<?php foreach($products as $product):?>
|
||||
<tr class="<?php echo $hidden;?>">
|
||||
<th><?php echo $lang->execution->manageProducts;?></th>
|
||||
<td class='text-left' id='productsBox' colspan="3">
|
||||
<th><?php if($i == 0) echo $lang->project->manageProductPlan;?></th>
|
||||
<td class='text-left productsBox' colspan="3">
|
||||
<div class='row'>
|
||||
<?php $i = 0;?>
|
||||
<?php $class = $division ? '' : 'disabled';?>
|
||||
<?php foreach($products as $product):?>
|
||||
<?php $hasBranch = ($product->type != 'normal' and isset($branchGroups[$product->id]));?>
|
||||
<?php foreach($linkedBranches[$product->id] as $branchID => $branch):?>
|
||||
<div class='col-sm-4'>
|
||||
<div class="input-group<?php if($hasBranch) echo ' has-branch';?>">
|
||||
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' $class onchange='loadBranches(this)' data-last='" . $product->id . "'");?>
|
||||
<?php if($class) echo html::hidden("products[$i]", $product->id);?>
|
||||
<span class='input-group-addon fix-border'></span>
|
||||
<?php if($hasBranch) echo html::select("branch[$i]", $branchGroups[$product->id], $branchID, "class='form-control chosen' onchange=\"loadPlans('#products{$i}', this.value)\"");?>
|
||||
<div class="col-sm-6">
|
||||
<div class='table-row'>
|
||||
<div class='table-col'>
|
||||
<?php $hasBranch = $product->type != 'normal' and isset($branchGroups[$product->id]);?>
|
||||
<div class='input-group <?php if($hasBranch) echo ' has-branch';?>'>
|
||||
<span class='input-group-addon'><?php echo $lang->product->common;?></span>
|
||||
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='" . $product->type . "'");?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-col <?php if(!$hasBranch) echo 'hidden';?>'>
|
||||
<div class='input-group required'>
|
||||
<span class='input-group-addon fix-border'><?php echo $lang->project->branch;?></span>
|
||||
<?php $branchIdList = isset($product->branches) ? join(',', $product->branches) : '';?>
|
||||
<?php echo html::select("branch[$i][]", isset($branchGroups[$product->id]) ? $branchGroups[$product->id] : array(), $branchIdList, "class='form-control chosen' multiple onchange=\"loadPlans('#products{$i}', this)\"");?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php $i++;?>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
<?php if((isset($project->model) and $project->model == 'scrum') or empty($products)):?>
|
||||
<div class='col-sm-4'>
|
||||
<div class="input-group">
|
||||
<?php echo html::select("products[$i]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
|
||||
<span class='input-group-addon fix-border'></span>
|
||||
<div class="col-sm-6">
|
||||
<div class='input-group' <?php echo "id='plan$i'";?>>
|
||||
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
|
||||
<?php echo html::select("plans[$product->id][]", isset($productPlans[$product->id]) ? $productPlans[$product->id] : array(), isset($product->plans) ? $product->plans : '', "class='form-control chosen' multiple");?>
|
||||
<div class='input-group-btn'>
|
||||
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
|
||||
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' <?php if($i == 0) echo "style='visibility: hidden'";?>><i class='icon-close'></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php $hidden = 'hide'?>
|
||||
<?php if(isset($project->model) and !empty($project->hasProduct) and $project->model == 'scrum') $hidden = '';?>
|
||||
<tr class="<?php echo $hidden?>">
|
||||
<th><?php echo $lang->execution->linkPlan;?></th>
|
||||
<td colspan="3" id="plansBox">
|
||||
<?php $i ++;?>
|
||||
<?php endforeach;?>
|
||||
<?php else:?>
|
||||
<tr class='<?php echo $hidden;?>'>
|
||||
<th id='productTitle'><?php echo $lang->project->manageProductPlan;?></th>
|
||||
<td class='text-left productsBox' colspan='3'>
|
||||
<div class='row'>
|
||||
<?php if(isset($plan) && !empty($plan->begin)):?>
|
||||
<div class="col-sm-4" id="plan0"><?php echo html::select("plans[{$plan->product}][{$plan->branch}][]", $productPlan, $plan->id, "class='form-control chosen' multiple");?></div>
|
||||
<?php js::set('currentPlanID', $plan->id)?>
|
||||
<?php elseif($copyExecutionID):?>
|
||||
<?php $i = 0;?>
|
||||
<?php foreach($products as $product):?>
|
||||
<?php foreach($linkedBranches[$product->id] as $branchID => $branch):?>
|
||||
<?php $plans = isset($productPlans[$product->id][$branchID]) ? $productPlans[$product->id][$branchID] : array();?>
|
||||
<div class="col-sm-4" id="plan<?php echo $i;?>"><?php echo html::select("plans[{$product->id}][$branchID][]", $plans, $branches[$product->id][$branchID]->plan, "class='form-control chosen' multiple");?></div>
|
||||
<?php $i++;?>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
<?php else:?>
|
||||
<div class="col-sm-4" id="plan0"><?php echo html::select("plans[][][]", $productPlan, '', "class='form-control chosen' multiple");?></div>
|
||||
<?php js::set('currentPlanID', '')?>
|
||||
<?php endif;?>
|
||||
<div class="col-sm-6">
|
||||
<div class='table-row'>
|
||||
<div class='table-col'>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon'><?php echo $lang->product->common;?></span>
|
||||
<?php echo html::select("products[0]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-col hidden'>
|
||||
<div class='input-group required'>
|
||||
<span class='input-group-addon fix-border'><?php echo $lang->project->branch;?></span>
|
||||
<?php echo html::select("branch", '', '', "class='form-control chosen' multiple");?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class='input-group' id='plan0'>
|
||||
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
|
||||
<?php echo html::select("plans[][]", $productPlan, '', "class='form-control chosen' multiple");?>
|
||||
<div class='input-group-btn'>
|
||||
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
|
||||
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' style='visibility: hidden'><i class='icon-close'></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->teamname;?></th>
|
||||
<td><?php echo html::input('team', $team, "class='form-control'");?></td>
|
||||
|
||||
@@ -141,56 +141,81 @@
|
||||
<?php if(!in_array($execution->attribute, array('request', 'design', 'review'))): ?>
|
||||
<?php $hidden = 'hide'?>
|
||||
<?php if(!empty($project->hasProduct)) $hidden = ''?>
|
||||
<?php if($linkedProducts):?>
|
||||
<?php $i = 0;?>
|
||||
<?php foreach($linkedProducts as $product):?>
|
||||
<tr class="<?php echo $hidden;?>">
|
||||
<th><?php echo $lang->execution->manageProducts;?></th>
|
||||
<td class='text-left' id='productsBox' colspan="2">
|
||||
<?php $class = ($execution->grade == 2 or $execution->type == 'stage') ? "disabled" : '';?>
|
||||
<th><?php if($i == 0) echo $lang->project->manageProductPlan;?></th>
|
||||
<td class='text-left productsBox' colspan="3">
|
||||
<div class='row'>
|
||||
<?php $i = 0;?>
|
||||
<?php foreach($linkedProducts as $product):?>
|
||||
<?php $hasBranch = $product->type != 'normal' and isset($branchGroups[$product->id]);?>
|
||||
<?php foreach($linkedBranches[$product->id] as $branchID => $branch):?>
|
||||
<div class='col-sm-4'>
|
||||
<div class="input-group<?php if($hasBranch) echo ' has-branch';?>">
|
||||
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' $class onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='". $product->type ."' data-lastBranch='" . $branchID . "'");?>
|
||||
<span class='input-group-addon fix-border'></span>
|
||||
<?php if($hasBranch) echo html::select("branch[$i]", $branchGroups[$product->id], $branchID, "class='form-control chosen' $class onchange=\"loadPlans('#products{$i}', this.value)\" data-last='" . $branchID . "'");?>
|
||||
<div class="col-sm-6">
|
||||
<div class='table-row'>
|
||||
<div class='table-col'>
|
||||
<?php $hasBranch = $product->type != 'normal' and isset($branchGroups[$product->id]);?>
|
||||
<div class='input-group <?php if($hasBranch) echo ' has-branch';?>'>
|
||||
<span class='input-group-addon'><?php echo $lang->product->common;?></span>
|
||||
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='" . $product->type . "'");?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-col <?php if(!$hasBranch) echo 'hidden';?>'>
|
||||
<div class='input-group required'>
|
||||
<span class='input-group-addon fix-border'><?php echo $lang->product->branchName['branch'];?></span>
|
||||
<?php $branchIdList = join(',', $product->branches);?>
|
||||
<?php echo html::select("branch[$i][]", isset($branchGroups[$product->id]) ? $branchGroups[$product->id] : array(), $branchIdList, "class='form-control chosen' multiple onchange=\"loadPlans('#products{$i}', this)\"");?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php $i++; ?>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
<?php if($execution->type != 'stage'):?>
|
||||
<div class='col-sm-4'>
|
||||
<div class="input-group">
|
||||
<?php echo html::select("products[$i]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
|
||||
<span class='input-group-addon fix-border'></span>
|
||||
<div class="col-sm-6">
|
||||
<div class='input-group' <?php echo "id='plan$i'";?>>
|
||||
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
|
||||
<?php echo html::select("plans[$product->id][]", isset($productPlans[$product->id]) ? $productPlans[$product->id] : array(), $product->plans, "class='form-control chosen' multiple");?>
|
||||
<div class='input-group-btn'>
|
||||
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
|
||||
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' <?php if($i == 0) echo "style='visibility: hidden'";?>><i class='icon-close'></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if(isset($project->model) and $project->model == 'scrum') $hidden = '';?>
|
||||
<tr class="<?php echo $hidden?>">
|
||||
<th><?php echo $lang->execution->linkPlan;?></th>
|
||||
<td id="plansBox" colspan="2">
|
||||
<?php $i ++;?>
|
||||
<?php endforeach;?>
|
||||
<?php else:?>
|
||||
<tr class='<?php echo $hidden;?>'>
|
||||
<th id='productTitle'><?php echo $lang->project->manageProductPlan;?></th>
|
||||
<td class='text-left productsBox' colspan='3'>
|
||||
<div class='row'>
|
||||
<?php $i = 0;?>
|
||||
<?php if(empty($linkedProducts)):?>
|
||||
<div class="col-sm-4" id="plan0"><?php echo html::select("plans[][][]", $productPlans, '', "class='form-control chosen' multiple");?></div>
|
||||
<?php else:?>
|
||||
<?php foreach($linkedProducts as $product):?>
|
||||
<?php foreach($linkedBranches[$product->id] as $branchID => $branch):?>
|
||||
<?php $plans = isset($productPlans[$product->id][$branchID]) ? $productPlans[$product->id][$branchID] : array();?>
|
||||
<div class="col-sm-4" id="plan<?php echo $i;?>"><?php echo html::select("plans[{$product->id}][{$branchID}][]", $plans, $branches[$product->id][$branchID]->plan, "class='form-control chosen' multiple");?></div>
|
||||
<?php $i++;?>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
<div class="col-sm-6">
|
||||
<div class='table-row'>
|
||||
<div class='table-col'>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon'><?php echo $lang->product->common;?></span>
|
||||
<?php echo html::select("products[0]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-col hidden'>
|
||||
<div class='input-group required'>
|
||||
<span class='input-group-addon fix-border'><?php echo $lang->product->branchName['branch'];?></span>
|
||||
<?php echo html::select("branch", '', '', "class='form-control chosen' multiple");?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class='input-group' id='plan0'>
|
||||
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
|
||||
<?php echo html::select("plans[][]", '', '', "class='form-control chosen' multiple");?>
|
||||
<div class='input-group-btn'>
|
||||
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
|
||||
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' style='visibility: hidden'><i class='icon-close'></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<?php echo html::hidden("products[]", key($linkedProducts));?>
|
||||
<?php endif; ?>
|
||||
@@ -232,5 +257,6 @@
|
||||
<?php js::set('confirmSync', $lang->execution->confirmSync);?>
|
||||
<?php js::set('allProducts', $allProducts);?>
|
||||
<?php js::set('branchGroups', $branchGroups);?>
|
||||
<?php js::set('projectID', $execution->project);?>
|
||||
<?php js::set('unLinkProductTip', $lang->project->unLinkProductTip);?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -402,13 +402,17 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="icon icon-close"></i></button>
|
||||
<?php $linkStoryByPlanTips = $execution->multiple ? $lang->execution->linkStoryByPlanTips : str_replace($lang->executionCommon, $lang->projectCommon, $lang->execution->linkStoryByPlanTips);?>
|
||||
<?php
|
||||
$linkStoryByPlanTips = $multiBranch ? sprintf($lang->execution->linkBranchStoryByPlanTips, $lang->project->branch) : $lang->execution->linkNormalStoryByPlanTips;
|
||||
$linkStoryByPlanTips = $execution->multiple ? $linkStoryByPlanTips : str_replace($lang->executionCommon, $lang->projectCommon, $linkStoryByPlanTips);
|
||||
?>
|
||||
<h4 class="modal-title"><?php echo $lang->execution->linkStoryByPlan;?></h4><?php echo '(' . $linkStoryByPlanTips . ')';?>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('plan', $allPlans, '', "class='form-control chosen' id='plan'");?>
|
||||
<span class='input-group-btn'><?php echo html::commonButton($lang->execution->linkStory, "id='toTaskButton'", 'btn btn-primary');?></span>
|
||||
<?php $disabled = empty(array_filter($allPlans)) ? 'disabled' : ''?>
|
||||
<span class='input-group-btn'><?php echo html::commonButton($lang->execution->linkStory, "id='toTaskButton'", 'btn btn-primary ' . $disabled);?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -131,7 +131,7 @@ class file extends control
|
||||
{
|
||||
echo(js::alert($this->lang->file->accessDenied));
|
||||
if(isonlybody()) return print(js::reload('parent.parent'));
|
||||
return print(js::locate(helper::createLink('my', 'index')));
|
||||
return print(js::locate(helper::createLink('my', 'index'), 'parent.parent'));
|
||||
}
|
||||
|
||||
/* Judge the mode, down or open. */
|
||||
|
||||
@@ -547,6 +547,7 @@ $lang->resource->story->batchChangeModule = 'batchChangeModule';
|
||||
$lang->resource->story->batchToTask = 'batchToTask';
|
||||
$lang->resource->story->processStoryChange = 'processStoryChange';
|
||||
$lang->resource->story->linkStories = 'linkStoriesAB';
|
||||
$lang->resource->story->relieved = 'relievedTwins';
|
||||
|
||||
$lang->story->methodOrder[5] = 'create';
|
||||
$lang->story->methodOrder[10] = 'batchCreate';
|
||||
@@ -576,6 +577,7 @@ $lang->story->methodOrder[120] = 'batchChangeModule';
|
||||
$lang->story->methodOrder[125] = 'batchToTask';
|
||||
$lang->story->methodOrder[130] = 'processStoryChange';
|
||||
$lang->story->methodOrder[135] = 'linkStories';
|
||||
$lang->story->methodOrder[140] = 'relieved';
|
||||
|
||||
/* Requirement. */
|
||||
$lang->resource->requirement = new stdclass();
|
||||
|
||||
@@ -250,8 +250,8 @@ class holidayModel extends model
|
||||
/**
|
||||
* Get diff days.
|
||||
*
|
||||
* @param varchar $begin
|
||||
* @param varchar $end
|
||||
* @param string $begin
|
||||
* @param string $end
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -49,7 +49,8 @@ body.menu-hide {padding-left: 0;}
|
||||
.menu-hide #apps {left: 40px;}
|
||||
.app-container.loading:before {background-color: rgba(0,0,0,.1);}
|
||||
.app-container.loading:before, .app-container.loading::after {transition-delay: 3s;}
|
||||
.app-container.loading.open-from-hidden {transition: 0s;}
|
||||
.app-container.loading.open-from-hidden {transition-delay: 0s;}
|
||||
.app-container.loading.open-from-hidden > iframe {opacity: 0;}
|
||||
|
||||
#appsBar {position: fixed; left: 96px; bottom: 0; right: 0; height: 40px; z-index: 1012; background: #fff; border-top: 1px solid #eff1f7;}
|
||||
.menu-hide #appsBar {left: 40px;}
|
||||
|
||||
@@ -268,10 +268,10 @@
|
||||
var isSameUrl = iframe && url && iframe.contentWindow.location.href.endsWith(url);
|
||||
if (url && (!isSameUrl || forceReload !== false))
|
||||
{
|
||||
app.$app.toggleClass('open-from-hidden', app.$app.is(':hidden'))
|
||||
app.$app.toggleClass('open-from-hidden', app.zIndex < openedAppZIndex)
|
||||
reloadApp(appCode, url, true);
|
||||
}
|
||||
app.zIndex = openedAppZIndex++;
|
||||
app.zIndex = ++openedAppZIndex;
|
||||
app.$app.show().css('z-index', app.zIndex);
|
||||
|
||||
/* Update task bar */
|
||||
@@ -464,7 +464,7 @@
|
||||
|
||||
if(!notTriggerEvent) app.$app.trigger('reloadapp', app);
|
||||
|
||||
if(!isSameUrl) app.$app.addClass('loading');
|
||||
if(!isSameUrl || app.zIndex < openedAppZIndex) app.$app.addClass('loading');
|
||||
if(app._loadTimer) clearTimeout(app._loadTimer);
|
||||
app._loadTimer = setTimeout(function()
|
||||
{
|
||||
|
||||
@@ -818,8 +818,11 @@ class kanbanModel extends model
|
||||
}
|
||||
elseif($branchID)
|
||||
{
|
||||
$branchName = $this->branch->getById($branchID);
|
||||
$branches = array($branchID => $branchName);
|
||||
foreach(explode(',', $branchID) as $id)
|
||||
{
|
||||
$branchName = $this->branch->getById($id);
|
||||
$branches[$id] = $branchName;
|
||||
}
|
||||
}
|
||||
|
||||
foreach($branches as $id => $name)
|
||||
|
||||
@@ -103,6 +103,7 @@ $lang->misc->feature->themeDesc = '<p>ZenTao 15.0+ a new "Youth Blue" theme
|
||||
$lang->misc->feature->visionsDesc = "<p>The concept of interface has been added since 16.5. Users can deal with R&D affairs in <span style='color: #0c60e1'>[Full Feature Interface]</span> and daily office affairs in <span style='color: #0c60e1'>[Operation Management Interface]</span>.</p><p>You can view the current interface on the avatar, and click the name of the interface to view and switch other interfaces.</p>";
|
||||
$lang->misc->feature->visionsImage = 'theme/default/images/main/visions_en.png';
|
||||
|
||||
$lang->misc->releaseDate['18.0.beta2'] = '2022-12-14';
|
||||
$lang->misc->releaseDate['18.0.beta1'] = '2022-11-16';
|
||||
$lang->misc->releaseDate['17.8'] = '2022-11-02';
|
||||
$lang->misc->releaseDate['17.7'] = '2022-10-19';
|
||||
@@ -193,6 +194,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['18.0.beta2'][] = array('title' => "We have optimized the product with multi-branches/multi-platforms. It's supported to create siblings stories. It's possible for Plan, Build, and Release to link requirements or bugs beyond their parent branch. 5 BI big screens are newly added. ZenTao Client has implemented the robot chatting mechanism.", 'desc' => '');
|
||||
$lang->misc->feature->all['18.0.beta1'][] = array('title' => "Multiple core processes in ZenTao are improved: A project without any product linked in is able to be created, as well as creating projects without sprints/iterations linked in; projects are able to link products beyond the father program; switch easily between ZenTao Lite mode and Full Lifecycle Management mode.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.8'][] = array('title' => "We have optimized the color of status in lists, as well as the dashboard color. At the same time, the page of the task effort has been improved.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.7'][] = array('title' => "The table is optimized in the transition version. At the same time, we have added the new feature of Work Order and get the Feedback features improved as well. Fix bugs.", 'desc' => '');
|
||||
|
||||
@@ -103,6 +103,7 @@ $lang->misc->feature->themeDesc = '<p>ZenTao 15.0+ a new "Youth Blue" theme
|
||||
$lang->misc->feature->visionsDesc = "<p>The concept of interface has been added since 16.5. Users can deal with R&D affairs in <span style='color: #0c60e1'>[Full Feature Interface]</span> and daily office affairs in <span style='color: #0c60e1'>[Operation Management Interface]</span>.</p><p>You can view the current interface on the avatar, and click the name of the interface to view and switch other interfaces.</p>";
|
||||
$lang->misc->feature->visionsImage = 'theme/default/images/main/visions_en.png';
|
||||
|
||||
$lang->misc->releaseDate['18.0.beta2'] = '2022-12-14';
|
||||
$lang->misc->releaseDate['18.0.beta1'] = '2022-11-16';
|
||||
$lang->misc->releaseDate['17.8'] = '2022-11-02';
|
||||
$lang->misc->releaseDate['17.7'] = '2022-10-19';
|
||||
@@ -193,6 +194,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['18.0.beta2'][] = array('title' => "We have optimized the product with multi-branches/multi-platforms. It's supported to create siblings stories. It's possible for Plan, Build, and Release to link requirements or bugs beyond their parent branch. 5 BI big screens are newly added. ZenTao Client has implemented the robot chatting mechanism.", 'desc' => '');
|
||||
$lang->misc->feature->all['18.0.beta1'][] = array('title' => "Multiple core processes in ZenTao are improved: A project without any product linked in is able to be created, as well as creating projects without sprints/iterations linked in; projects are able to link products beyond the father program; switch easily between ZenTao Lite mode and Full Lifecycle Management mode.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.8'][] = array('title' => "We have optimized the color of status in lists, as well as the dashboard color. At the same time, the page of the task effort has been improved.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.7'][] = array('title' => "The table is optimized in the transition version. At the same time, we have added the new feature of Work Order and get the Feedback features improved as well. Fix bugs.", 'desc' => '');
|
||||
|
||||
@@ -103,6 +103,7 @@ $lang->misc->feature->themeDesc = '<p>ZenTao 15.0+ a new "Youth Blue" theme
|
||||
$lang->misc->feature->visionsDesc = "<p>The concept of interface has been added since 16.5. Users can deal with R&D affairs in <span style='color: #0c60e1'>[Full Feature Interface]</span> and daily office affairs in <span style='color: #0c60e1'>[Operation Management Interface]</span>.</p><p>You can view the current interface on the avatar, and click the name of the interface to view and switch other interfaces.</p>";
|
||||
$lang->misc->feature->visionsImage = 'theme/default/images/main/visions_en.png';
|
||||
|
||||
$lang->misc->releaseDate['18.0.beta2'] = '2022-12-14';
|
||||
$lang->misc->releaseDate['18.0.beta1'] = '2022-11-16';
|
||||
$lang->misc->releaseDate['17.8'] = '2022-11-02';
|
||||
$lang->misc->releaseDate['17.7'] = '2022-10-19';
|
||||
@@ -193,6 +194,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['18.0.beta2'][] = array('title' => "We have optimized the product with multi-branches/multi-platforms. It's supported to create siblings stories. It's possible for Plan, Build, and Release to link requirements or bugs beyond their parent branch. 5 BI big screens are newly added. ZenTao Client has implemented the robot chatting mechanism.", 'desc' => '');
|
||||
$lang->misc->feature->all['18.0.beta1'][] = array('title' => "Multiple core processes in ZenTao are improved: A project without any product linked in is able to be created, as well as creating projects without sprints/iterations linked in; projects are able to link products beyond the father program; switch easily between ZenTao Lite mode and Full Lifecycle Management mode.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.8'][] = array('title' => "We have optimized the color of status in lists, as well as the dashboard color. At the same time, the page of the task effort has been improved.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.7'][] = array('title' => "The table is optimized in the transition version. At the same time, we have added the new feature of Work Order and get the Feedback features improved as well. Fix bugs.", 'desc' => '');
|
||||
|
||||
@@ -103,6 +103,7 @@ $lang->misc->feature->themeDesc = "<p>禅道15系列上线了全新的“
|
||||
$lang->misc->feature->visionsDesc = "<p>从16.5开始增加了界面概念,用户可以在<span style='color:#0c60e1'>[研发综合界面]</span>中处理研发事务、在<span style='color:#0c60e1'>[运营管理界面]</span>处理日常办公事务。</p><p>在头像右侧即可查看当前所处界面,点击当前界面名称可查看和切换其他的界面。</p>";
|
||||
$lang->misc->feature->visionsImage = 'theme/default/images/main/visions.png';
|
||||
|
||||
$lang->misc->releaseDate['18.0.beta2'] = '2022-12-14';
|
||||
$lang->misc->releaseDate['18.0.beta1'] = '2022-11-16';
|
||||
$lang->misc->releaseDate['17.8'] = '2022-11-02';
|
||||
$lang->misc->releaseDate['17.7'] = '2022-10-19';
|
||||
@@ -193,6 +194,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['18.0.beta2'][] = array('title' => '优化多分支/多平台产品,支持创建孪生需求,计划、版本、发布支持跨分支关联需求和bug,新增5个BI大屏,并且禅道客户端实现了机器人会话机制。', 'desc' => '');
|
||||
$lang->misc->feature->all['18.0.beta1'][] = array('title' => '主要对禅道多项核心流程进行改进,新增项目型项目、无迭代项目;支持项目跨项目集关联产品;支持轻量管理模式和全生命周期管理模式进行切换。', 'desc' => '');
|
||||
$lang->misc->feature->all['17.8'][] = array('title' => '列表状态颜色、仪表盘颜色的改版和任务日志页面的优化。', 'desc' => '');
|
||||
$lang->misc->feature->all['17.7'][] = array('title' => '过渡版本表格优化完成。新增工单功能,优化了反馈功能。修复Bug。', 'desc' => '');
|
||||
@@ -330,7 +332,7 @@ $lang->misc->feature->all['8.2.stable'][] = array('title'=>'导出自定义', 'd
|
||||
$lang->misc->feature->all['8.2.stable'][] = array('title'=>"{$lang->SRCommon}、任务、Bug、用例组合检索功能", 'desc' => "<p>在{$lang->SRCommon}、任务、Bug、用例列表页面,可以实现模块和标签的组合检索。</p>");
|
||||
$lang->misc->feature->all['8.2.stable'][] = array('title'=>'增加新手教程', 'desc' => '<p>增加新手教程,方便新用户了解禅道使用。</p>');
|
||||
|
||||
$lang->misc->feature->all['7.4.beta'][] = array('title'=>'产品实现分支功能', 'desc' => "<p>产品增加分支/平台类型,相应的{$lang->SRCommon}、计划、Bug、用例、模块等都增加分支。</p>");
|
||||
$lang->misc->feature->all['7.4.beta'][] = array('title'=>'产品实现分支功能', 'desc' => "<p>产品增加平台/分支类型,相应的{$lang->SRCommon}、计划、Bug、用例、模块等都增加分支。</p>");
|
||||
$lang->misc->feature->all['7.4.beta'][] = array('title'=>'调整发布模块', 'desc' => '<p>发布增加停止维护操作,当发布停止维护时,创建Bug将不显示这个发布。</p><p>发布中遗留的bug改为手工关联。</p>');
|
||||
$lang->misc->feature->all['7.4.beta'][] = array('title'=>"调整{$lang->SRCommon}和Bug的创建页面", 'desc' => '');
|
||||
|
||||
|
||||
@@ -9,10 +9,7 @@ $config->my->taskCounts = 10;
|
||||
$config->my->bugCounts = 10;
|
||||
$config->my->storyCounts = 10;
|
||||
|
||||
$config->my->oaObjectType = 'attend,leave,makeup,overtime,lieu';
|
||||
$config->my->reviewObjectType = 'story,case';
|
||||
if($config->edition == 'biz') $config->my->reviewObjectType = 'story,case,feedback,attend,leave,makeup,overtime,lieu';
|
||||
if($config->edition == 'max') $config->my->reviewObjectType = 'story,case,review,feedback,attend,leave,makeup,overtime,lieu';
|
||||
$config->my->oaObjectType = 'attend,leave,makeup,overtime,lieu';
|
||||
|
||||
$config->mobile = new stdclass();
|
||||
$config->mobile->todoBar = array('today', 'yesterday', 'thisWeek', 'lastWeek', 'all');
|
||||
|
||||
@@ -955,15 +955,27 @@ EOF;
|
||||
$this->app->loadClass('pager', true);
|
||||
$pager = pager::init($recTotal, $recPerPage, $pageID);
|
||||
|
||||
$typeList = array();
|
||||
if($this->app->rawMethod == 'contribute')
|
||||
{
|
||||
$reviewList = $this->my->getReviewedList($browseType, $orderBy, $pager);
|
||||
}
|
||||
else
|
||||
{
|
||||
$typeList = $this->my->getReviewingTypeList();
|
||||
if(!isset($typeList->$browseType)) $browseType = 'all';
|
||||
|
||||
$this->lang->my->auditMenu->audit = $typeList;
|
||||
$reviewList = $this->my->getReviewingList($browseType, $orderBy, $pager);
|
||||
}
|
||||
|
||||
$this->view->flows = array();
|
||||
if($this->config->edition == 'max')
|
||||
{
|
||||
$this->app->loadLang('approval');
|
||||
$this->view->flows = $this->dao->select('module,name')->from(TABLE_WORKFLOW)->where('buildin')->eq(0)->fetchPairs('module', 'name');
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->review->common;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
|
||||
$this->view->reviewList = $reviewList;
|
||||
|
||||
+138
-11
@@ -993,6 +993,34 @@ class myModel extends model
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reviewing type list for menu.
|
||||
*
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function getReviewingTypeList()
|
||||
{
|
||||
$typeList = array();
|
||||
if($this->getReviewingStories('id_desc', true)) $typeList[] = 'story';
|
||||
if($this->getReviewingCases('id_desc', true)) $typeList[] = 'testcase';
|
||||
if($this->getReviewingApprovals('id_desc', true)) $typeList[] = 'project';
|
||||
if($this->getReviewingFeedbacks('id_desc', true)) $typeList[] = 'feedback';
|
||||
if($this->getReviewingOA('status', true)) $typeList[] = 'oa';
|
||||
$typeList = array_merge($typeList, $this->getReviewingFlows('all', 'id_desc', true));
|
||||
|
||||
$flows = ($this->config->edition == 'open') ? array() : $this->dao->select('module,name')->from(TABLE_WORKFLOW)->where('module')->in($typeList)->andWhere('buildin')->eq(0)->fetchPairs('module', 'name');
|
||||
$menu = new stdclass();
|
||||
$menu->all = $this->lang->my->auditMenu->audit->all;
|
||||
foreach($typeList as $type)
|
||||
{
|
||||
$this->app->loadLang($type);
|
||||
$menu->$type = isset($this->lang->$type->common) ? $this->lang->$type->common : zget($flows, $type);
|
||||
}
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reviewing list for me.
|
||||
*
|
||||
@@ -1010,6 +1038,7 @@ class myModel extends model
|
||||
if($browseType == 'all' or $browseType == 'project') $reviewList = array_merge($reviewList, $this->getReviewingApprovals());
|
||||
if($browseType == 'all' or $browseType == 'feedback') $reviewList = array_merge($reviewList, $this->getReviewingFeedbacks());
|
||||
if($browseType == 'all' or $browseType == 'oa') $reviewList = array_merge($reviewList, $this->getReviewingOA());
|
||||
if($browseType == 'all' or !in_array($browseType, array('story', 'testcase', 'feedback', 'oa'))) $reviewList = array_merge($reviewList, $this->getReviewingFlows($browseType));
|
||||
|
||||
if(empty($reviewList)) return array();
|
||||
|
||||
@@ -1044,10 +1073,11 @@ class myModel extends model
|
||||
* Get reviewing stories.
|
||||
*
|
||||
* @param string $orderBy
|
||||
* @param bool $checkExists
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getReviewingStories($orderBy = 'id_desc')
|
||||
public function getReviewingStories($orderBy = 'id_desc', $checkExists = false)
|
||||
{
|
||||
if(!common::hasPriv('story', 'review')) return array();
|
||||
|
||||
@@ -1066,6 +1096,7 @@ class myModel extends model
|
||||
$stories = array();
|
||||
while($data = $stmt->fetch())
|
||||
{
|
||||
if($checkExists) return true;
|
||||
$story = new stdclass();
|
||||
$story->id = $data->id;
|
||||
$story->title = $data->title;
|
||||
@@ -1084,10 +1115,11 @@ class myModel extends model
|
||||
* Get reviewing cases.
|
||||
*
|
||||
* @param string $orderBy
|
||||
* @param bool $checkExists
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getReviewingCases($orderBy = 'id_desc')
|
||||
public function getReviewingCases($orderBy = 'id_desc', $checkExists = false)
|
||||
{
|
||||
if(!common::hasPriv('testcase', 'review')) return array();
|
||||
|
||||
@@ -1102,6 +1134,7 @@ class myModel extends model
|
||||
$cases = array();
|
||||
while($data = $stmt->fetch())
|
||||
{
|
||||
if($checkExists) return true;
|
||||
$case = new stdclass();
|
||||
$case->id = $data->id;
|
||||
$case->title = $data->title;
|
||||
@@ -1118,10 +1151,11 @@ class myModel extends model
|
||||
* Get reviewing approvals.
|
||||
*
|
||||
* @param string $orderBy
|
||||
* @param bool $checkExists
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getReviewingApprovals($orderBy = 'id_desc')
|
||||
public function getReviewingApprovals($orderBy = 'id_desc', $checkExists = false)
|
||||
{
|
||||
if(!common::hasPriv('review', 'assess')) return array();
|
||||
if($this->config->edition != 'max') return array();
|
||||
@@ -1136,11 +1170,12 @@ class myModel extends model
|
||||
foreach($projectReviews as $review)
|
||||
{
|
||||
if(!isset($pendingList[$review->id])) continue;
|
||||
if($checkExists) return true;
|
||||
|
||||
$data = new stdclass();
|
||||
$data->id = $review->id;
|
||||
$data->title = $review->title;
|
||||
$data->type = 'project';
|
||||
$data->type = 'projectreview';
|
||||
$data->time = $review->createdDate;
|
||||
$data->status = $review->status;
|
||||
$reviewList[] = $data;
|
||||
@@ -1149,13 +1184,80 @@ class myModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reviewing feedbacks.
|
||||
* Get reviewing for flows setting.
|
||||
*
|
||||
* @param string $objectType
|
||||
* @param string $orderBy
|
||||
* @param bool $checkExists
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getReviewingFeedbacks($orderBy = 'id_desc')
|
||||
public function getReviewingFlows($objectType = 'all', $orderBy = 'id_desc', $checkExists = false)
|
||||
{
|
||||
if($this->config->edition != 'max') return array();
|
||||
|
||||
$stmt = $this->dao->select('t2.objectType,t2.objectID')->from(TABLE_APPROVALNODE)->alias('t1')
|
||||
->leftJoin(TABLE_APPROVALOBJECT)->alias('t2')
|
||||
->on('t2.approval = t1.approval')
|
||||
->where('t2.objectType')->ne('review')
|
||||
->beginIF($objectType != 'all')->andWhere('t2.objectType')->eq($objectType)->fi()
|
||||
->andWhere('t1.account')->eq($this->app->user->account)
|
||||
->andWhere('t1.status')->eq('doing')
|
||||
->query();
|
||||
$objectIdList = array();
|
||||
while($object = $stmt->fetch()) $objectIdList[$object->objectType][$object->objectID] = $object->objectID;
|
||||
if($checkExists) return array_keys($objectIdList);
|
||||
|
||||
$flows = $this->dao->select('module,`table`,name,titleField')->from(TABLE_WORKFLOW)->where('module')->in(array_keys($objectIdList))->andWhere('buildin')->eq(0)->fetchAll('module');
|
||||
$objectGroup = array();
|
||||
foreach($objectIdList as $objectType => $idList)
|
||||
{
|
||||
$table = zget($this->config->objectTables, $objectType, '');
|
||||
if(empty($table) and isset($flows[$objectType])) $table = $flows[$objectType]->table;
|
||||
if(empty($table)) continue;
|
||||
|
||||
$objectGroup[$objectType] = $this->dao->select('*')->from($table)->where('id')->in($idList)->fetchAll('id');
|
||||
}
|
||||
|
||||
$this->app->loadConfig('action');
|
||||
$approvalList = array();
|
||||
foreach($objectGroup as $objectType => $objects)
|
||||
{
|
||||
$title = '';
|
||||
$titleFieldName = zget($this->config->action->objectNameFields, $objectType, '');
|
||||
$openedDateField = 'openedDate';
|
||||
if(in_array($objectType, array('product', 'productplan', 'release', 'build', 'testtask'))) $openedDateField = 'createdDate';
|
||||
if(in_array($objectType, array('testsuite', 'caselib')))$openedDateField = 'addedDate';
|
||||
if(empty($titleFieldName) and isset($flows[$objectType]))
|
||||
{
|
||||
if(!empty($flows[$objectType]->titleField)) $titleFieldName = $flows[$objectType]->titleField;
|
||||
if(empty($flows[$objectType]->titleField)) $title = $flows[$objectType]->name;
|
||||
$openedDateField = 'createdDate';
|
||||
}
|
||||
|
||||
foreach($objects as $object)
|
||||
{
|
||||
$data = new stdclass();
|
||||
$data->id = $object->id;
|
||||
$data->title = (empty($titleFieldName) or !isset($object->$titleFieldName)) ? $title . " #{$object->id}" : $object->$titleFieldName;
|
||||
$data->type = $objectType;
|
||||
$data->time = $object->$openedDateField;
|
||||
$data->status = 'doing';
|
||||
$approvalList[] = $data;
|
||||
}
|
||||
}
|
||||
return $approvalList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reviewing feedbacks.
|
||||
*
|
||||
* @param string $orderBy
|
||||
* @param bool $checkExists
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getReviewingFeedbacks($orderBy = 'id_desc', $checkExists = false)
|
||||
{
|
||||
if(!common::hasPriv('feedback', 'review')) return array();
|
||||
if($this->config->edition == 'open') return array();
|
||||
@@ -1164,6 +1266,8 @@ class myModel extends model
|
||||
$reviewList = array();
|
||||
foreach($feedbacks as $feedback)
|
||||
{
|
||||
if($checkExists) return true;
|
||||
|
||||
$data = new stdclass();
|
||||
$data->id = $feedback->id;
|
||||
$data->title = $feedback->title;
|
||||
@@ -1179,10 +1283,11 @@ class myModel extends model
|
||||
* Get reviewing OA.
|
||||
*
|
||||
* @param string $orderBy
|
||||
* @param bool $checkExists
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getReviewingOA($orderBy = 'status')
|
||||
public function getReviewingOA($orderBy = 'status', $checkExists = false)
|
||||
{
|
||||
if($this->config->edition == 'open') return array();
|
||||
|
||||
@@ -1203,6 +1308,14 @@ class myModel extends model
|
||||
if(common::hasPriv('makeup', 'review') and common::hasPriv('makeup', 'view')) $oa['makeup'] = $this->getReviewingMakeups($allDeptList, $managedDeptList, $orderBy);
|
||||
if(common::hasPriv('lieu', 'review') and common::hasPriv('lieu', 'view')) $oa['lieu'] = $this->getReviewingLieus($allDeptList, $managedDeptList, $orderBy);
|
||||
|
||||
if($checkExists)
|
||||
{
|
||||
foreach($oa as $type => $reviewings)
|
||||
{
|
||||
if(!empty($reviewings)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
$reviewList = array();
|
||||
foreach($oa as $type => $reviewings)
|
||||
{
|
||||
@@ -1251,19 +1364,19 @@ class myModel extends model
|
||||
if(empty($actionField)) $actionField = 'date';
|
||||
$orderBy = $actionField . '_' . $direction;
|
||||
|
||||
$condition = "action = 'reviewed'";
|
||||
$condition = "(action = 'reviewed' or action = 'approvalreview')";
|
||||
if($browseType == 'createdbyme')
|
||||
{
|
||||
$condition = "(objectType in('story','case','feedback') and action = 'submitreview') OR ";
|
||||
$condition .= "(objectType = 'review' and action = 'opened') OR ";
|
||||
$condition .= "(objectType = 'attend' and action = 'commited') OR ";
|
||||
$condition .= "(action = 'approvalsubmit') OR ";
|
||||
$condition .= "(objectType in('leave','makeup','overtime','lieu') and action = 'created')";
|
||||
$condition = "($condition)";
|
||||
}
|
||||
|
||||
$actions = $this->dao->select('objectType,objectID,actor,action,MAX(`date`) as `date`,extra')->from(TABLE_ACTION)
|
||||
->where('actor')->eq($this->app->user->account)
|
||||
->andWhere('objectType')->in($this->config->my->reviewObjectType)
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->andWhere($condition)
|
||||
->groupBy('objectType,objectID')
|
||||
@@ -1273,10 +1386,12 @@ class myModel extends model
|
||||
$objectTypeList = array();
|
||||
foreach($actions as $action) $objectTypeList[$action->objectType][] = $action->objectID;
|
||||
|
||||
$flows = ($this->config->edition == 'open') ? array() : $this->dao->select('module,`table`,name,titleField')->from(TABLE_WORKFLOW)->where('module')->in(array_keys($objectTypeList))->andWhere('buildin')->eq(0)->fetchAll('module');
|
||||
$objectGroup = array();
|
||||
foreach($objectTypeList as $objectType => $idList)
|
||||
{
|
||||
$table = zget($this->config->objectTables, $objectType, '');
|
||||
if(empty($table) and isset($flows[$objectType])) $table = $flows[$objectType]->table;
|
||||
if(empty($table)) continue;
|
||||
|
||||
$objectGroup[$objectType] = $this->dao->select('*')->from($table)->where('id')->in($idList)->fetchAll('id');
|
||||
@@ -1290,6 +1405,7 @@ class myModel extends model
|
||||
}
|
||||
$users = $this->loadModel('user')->getPairs('noletter');
|
||||
|
||||
$this->app->loadConfig('action');
|
||||
$reviewList = array();
|
||||
foreach($actions as $action)
|
||||
{
|
||||
@@ -1302,10 +1418,10 @@ class myModel extends model
|
||||
$review->type = $objectType;
|
||||
$review->time = $action->date;
|
||||
$review->result = strtolower($action->extra);
|
||||
$review->status = $objectType == 'attend' ? $object->reviewStatus : $object->status;
|
||||
$review->status = $objectType == 'attend' ? $object->reviewStatus : ((isset($object->status) and !isset($flows[$objectType])) ? $object->status : 'done');
|
||||
if(strpos($review->result, ',') !== false) list($review->result) = explode(',', $review->result);
|
||||
|
||||
if($review->type == 'review') $review->type = 'project';
|
||||
if($review->type == 'review') $review->type = 'projectreview';
|
||||
if($review->type == 'case') $review->type = 'testcase';
|
||||
$review->title = '';
|
||||
if(isset($object->title))
|
||||
@@ -1320,6 +1436,17 @@ class myModel extends model
|
||||
{
|
||||
$review->title = sprintf($this->lang->my->auditField->oaTitle[$objectType], zget($users, $object->createdBy), $object->begin . ' ' . substr($object->start, 0, 5) . ' ~ ' . $object->end . ' ' . substr($object->finish, 0, 5));
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = '';
|
||||
$titleFieldName = zget($this->config->action->objectNameFields, $objectType, '');
|
||||
if(empty($titleFieldName) and isset($flows[$objectType]))
|
||||
{
|
||||
if(!empty($flows[$objectType]->titleField)) $titleFieldName = $flows[$objectType]->titleField;
|
||||
if(empty($flows[$objectType]->titleField)) $title = $flows[$objectType]->name;
|
||||
}
|
||||
$review->title = (empty($titleFieldName) or !isset($object->$titleFieldName)) ? $title . " #{$object->id}" : $object->$titleFieldName;
|
||||
}
|
||||
|
||||
$reviewList[] = $review;
|
||||
}
|
||||
|
||||
@@ -53,13 +53,22 @@
|
||||
<?php foreach($reviewList as $review):?>
|
||||
<?php
|
||||
$type = $review->type;
|
||||
if($type == 'project') $type = 'review';
|
||||
if($type == 'projectreview') $type = 'review';
|
||||
|
||||
$typeName = $lang->{$review->type}->common;
|
||||
$typeName = '';
|
||||
if(isset($lang->{$review->type}->common)) $typeName = $lang->{$review->type}->common;
|
||||
if($type == 'story') $typeName = $lang->my->auditMenu->audit->story;
|
||||
if($review->type == 'projectreview') $typeName = $lang->project->common;
|
||||
if(isset($flows[$review->type])) $typeName = $flows[$review->type];
|
||||
|
||||
$statusList = $lang->$type->statusList;
|
||||
$statusList = array();
|
||||
if(isset($lang->$type->statusList)) $statusList = $lang->$type->statusList;
|
||||
if($type == 'attend') $statusList = $lang->attend->reviewStatusList;
|
||||
if(!in_array($type, array('story', 'testcase', 'feedback', 'review')) and strpos(",{$config->my->oaObjectType},", ",$type,") === false)
|
||||
{
|
||||
if($rawMethod == 'audit') $statusList = $lang->approval->nodeList;
|
||||
if(isset($flows[$review->type])) $statusList = $rawMethod == 'audit' ? $lang->approval->nodeList : $lang->approval->statusList;
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td class='c-id'><?php echo $review->id?></td>
|
||||
@@ -83,7 +92,8 @@
|
||||
<td class='c-time text-left'><?php echo $review->time?></td>
|
||||
<?php if($rawMethod == 'contribute' and $browseType == 'reviewedbyme'):?>
|
||||
<?php
|
||||
$reviewResultList = zget($lang->$type, 'reviewResultList', array());
|
||||
$reviewResultList = array();
|
||||
if(isset($lang->$type))$reviewResultList = zget($lang->$type, 'reviewResultList', array());
|
||||
if(strpos(",{$config->my->oaObjectType},", ",$type,") !== false) $reviewResultList = zget($lang->$type, 'reviewStatusList', array());
|
||||
?>
|
||||
<td class='c-status'><?php echo zget($reviewResultList, $review->result);?></td>
|
||||
@@ -114,6 +124,10 @@
|
||||
{
|
||||
common::printLink($module, 'view', $params, $reviewIcon, '', "class='btn' data-toggle='modal' title='{$lang->review->common}'", true, true);
|
||||
}
|
||||
elseif(!in_array($module, array('story', 'testcase', 'feedback')))
|
||||
{
|
||||
common::printLink($module, 'approvalreview', $params, $reviewIcon, '', "class='btn' data-toggle='modal' title='{$lang->review->common}'", true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
common::printLink($module, $method, $params, $reviewIcon, '', "class='btn iframe' title='{$lang->review->common}'", true, true);
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<tbody>
|
||||
<?php foreach($stories as $story):?>
|
||||
<?php
|
||||
$storyLink = $this->createLink('story', 'view', "id=$story->id");
|
||||
$storyLink = $this->createLink('story', 'view', "id=$story->id&version=0¶m=0&storyType=requirement");
|
||||
$canBeChanged = common::canBeChanged('story', $story);
|
||||
$spanClass = $canBatchAction ? 'c-span' : '';
|
||||
?>
|
||||
|
||||
@@ -249,7 +249,7 @@ class product extends control
|
||||
$showBranch = $this->loadModel('branch')->showBranch($productID);
|
||||
|
||||
/* Get stories. */
|
||||
if($isProjectStory)
|
||||
if($isProjectStory and $storyType == 'story')
|
||||
{
|
||||
$showBranch = $this->loadModel('branch')->showBranch($productID, 0, $projectID);
|
||||
|
||||
@@ -257,7 +257,7 @@ class product extends control
|
||||
|
||||
$this->products = $this->product->getProducts($projectID, 'all', '', false);
|
||||
$projectProducts = $this->product->getProducts($projectID);
|
||||
$productPlans = $this->execution->getPlans($projectProducts, 'skipParent');
|
||||
$productPlans = $this->execution->getPlans($projectProducts, 'skipParent,unexpired,noclosed', $projectID);
|
||||
|
||||
if($browseType == 'bybranch') $param = $branchID;
|
||||
$stories = $this->story->getExecutionStories($projectID, $productID, $branchID, $sort, $browseType, $param, $storyType, '', $pager);
|
||||
@@ -274,6 +274,7 @@ class product extends control
|
||||
if(!$product and $isProjectStory)
|
||||
{
|
||||
/* Get branch display under multiple products. */
|
||||
$branchOptions = array();
|
||||
foreach($projectProducts as $projectProduct)
|
||||
{
|
||||
if($projectProduct and $projectProduct->type != 'normal')
|
||||
@@ -355,7 +356,7 @@ class product extends control
|
||||
$this->view->productName = $productName;
|
||||
$this->view->moduleID = $moduleID;
|
||||
$this->view->stories = $stories;
|
||||
$this->view->plans = $this->loadModel('productplan')->getPairs($productID, ($branch === 'all' or empty($branch)) ? '' : $branch, '', true);
|
||||
$this->view->plans = $this->loadModel('productplan')->getPairs($productID, ($branch === 'all' or empty($branch)) ? '' : $branch, 'unexpired,noclosed', true);
|
||||
$this->view->productPlans = isset($productPlans) ? array(0 => '') + $productPlans : array();
|
||||
$this->view->summary = $this->product->summary($stories, $storyType);
|
||||
$this->view->moduleTree = $moduleTree;
|
||||
@@ -923,6 +924,22 @@ class product extends control
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax get product by id.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetProductById($productID)
|
||||
{
|
||||
$product = $this->product->getById($productID);
|
||||
|
||||
$product->branchSourceName = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
$product->branchName = $this->lang->product->branchName[$product->type];
|
||||
echo json_encode($product);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: get projects of a product in html select.
|
||||
*
|
||||
@@ -1037,12 +1054,19 @@ class product extends control
|
||||
public function ajaxGetPlans($productID, $branch = 0, $planID = 0, $fieldID = '', $needCreate = false, $expired = '', $param = '')
|
||||
{
|
||||
$param = strtolower($param);
|
||||
$plans = $this->loadModel('productplan')->getPairs($productID, $branch, $expired, strpos($param, 'skipparent') !== false);
|
||||
$field = $fieldID ? "plans[$fieldID]" : 'plan';
|
||||
if(strpos($param, 'forstory') === false)
|
||||
{
|
||||
$plans = $this->loadModel('productplan')->getPairs($productID, empty($branch) ? 'all' : $branch, $expired, strpos($param, 'skipparent') !== false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$plans = $this->loadModel('productplan')->getPairsForStory($productID, $branch == '0' ? 'all' : $branch, $param);
|
||||
}
|
||||
$field = $fieldID !== '' ? "plans[$fieldID]" : 'plan';
|
||||
$multiple = strpos($param, 'multiple') === false ? '' : 'multiple';
|
||||
$output = html::select($field, $plans, $planID, "class='form-control chosen' $multiple");
|
||||
|
||||
if($branch == 0 and strpos($param, 'edit')) $output = html::select($field, $plans, $planID, "class='form-control chosen' multiple");
|
||||
if($branch == 0 and strpos($param, 'edit') and (strpos($param, 'forstory') === false)) $output = html::select($field, $plans, $planID, "class='form-control chosen' multiple");
|
||||
|
||||
if(count($plans) == 1 and $needCreate and $needCreate !== 'false')
|
||||
{
|
||||
|
||||
@@ -41,3 +41,4 @@ a.removeModule:hover {color: red;}
|
||||
#productStoryForm tbody tr td .label {max-width: 100px; text-overflow: unset;}
|
||||
.c-span {margin-left: 19px;}
|
||||
.btn-toolbar #query span.text{overflow: hidden; width: 52px; vertical-align: middle; margin-right: 1px;}
|
||||
#linkStoryByPlan .modal-header {padding: 20px 0 10px 0; border-bottom: 0px}
|
||||
@@ -8,3 +8,4 @@
|
||||
.release-line > li:nth-child(even) > a {padding-bottom: 38px;}
|
||||
.release-link-line {pointer-events: none; background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+YAAADiCAMAAAD0xy2eAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAABOUExURUdwTOXl5eXl5ebm5ufn5+rq6u7u7unp6eXl5f///+Xl5eXl5efn5+Xl5eXl5eXl5ebm5uXl5eXl5ebm5ubm5ubm5uXl5ebm5uXl5eXl5Uh6G7kAAAAZdFJOUwDuuVQtFQwg1gXH+Dpzoq1CmIV7aEuOX+MTWsN0AAAGrUlEQVQYGe3ACbaYOHRF0SuQkETfw5v/RPNdLpMZZKWez5buVQBcu8zmJACO1WOwcAqAZ7kx66MAeNa+ZncnAI51t1kvAK7F/hEAAAAAAACA/xP93gmAZ6tZOKsAODb2ZuUSAM/aYtZEAXCsTsFs7gTAse4eigD4lqMAAAAAAMD/D09/CYBrvVl/CYBjdXrN+lUAHOumYNavAuBYNwWzTQA866ZwCYBvnQAAAAD8V7RHEgDParHhzgLg2NqYDXMUAMfiPJg1qwA4lu/BbBMAz7rjvQTAtyoAAOBG1wmAb1O4swB4NptZcwmAY3EbzN4pCYBfaSpmwywAnl2NNQLgW44CAABuZAHwLQ1lSgLg2BjMhuUSAL9q25jZu2cB8CsfxcweAfBsnYcsAL51AgAAboxL2wmAZ5vZMF9VANxKZ29mYRsFwK98FDN7swA4Fvc3VAHwLQsAALgxlSMKgGeNmZU9CoBb9dqCmb33KABu1XV7zSwJgGfjPQsAALixHlEAXJvN3u3qBMCtdXvNbGjOLABuxaO3H1EAHEvPUgQAANwYlycLgGe7mZX76gTAq3wuwcyGZsoC4FUd997MLgHwLLVbJwB/j7UTANeyDf2+dgLgVuwHMxv6fa0C4FR37b39WATAse66+0kA/h45CYBvjZX5yQLg1xLsR1imsQqATzVOy2s/kgA4lp+tEYC/R9rOsRMAx1r7UebjygLgU57mMtgvswC4VeNzN++hT0oC4FDVZ7ehLPe55ioAPu3BfhseAXCqi+2xNa9d+rTnFTsB8KLqH7Xq09iPoTTzngXApXNrSrBfRn1i7ATAlS5e5570KWbD2y/b8XQC4NJSgv2W9RljrgLgR5fH9tznqk8ws1D6ZTs6AXCp6d/B/lH1Oc52jakKgBcpj+156FPtt1B6AXCp27elKcHMgj5d6Zdtn55rzALgRcpRn2x/vPrUMaYqAP9hVZ8a1/Y87rnpG32y/Qhv38y7ALiU+xIG+6Xok5r5Ps52jbkTABe6PF5Pq89ofxR9upg7AXAiXc+0b0tT3kaf0cyGtzTLdgqAS2N5B/tHo09ctn162jGmKgAedDmu7Xnp09ofjT5dTFUAnEjtedzz0pd30+cxs/D2zXy3AuBSW4L9tumzzvdxtmvMnQC40OXxes5Vn8n+2PTpkgC4EZ9p35amvMOuz2QWSr/M9zQKgEtTsH/t+qzH2a4xVQFwoaY4Xs+0r/rs9lsopwC4tO7b0pcwmJ367KVftn16rjEJgBddTvrM9sejT46pCoATKY7tedxz06/6zGYWSr9sexQAl+4S7LdLn3Z6rpirAHiR4tieR9ansX+E0o8C4NJzz015BzMb9bmX7TjbMXcC4EaXx06fYv8aogC4NLbnvi19CZb06Usz38dzjVkA/Kj6X8H+SPpUAfAjxfWZ9rnp36pPCKWZ7+m5ogC4VAf7o+rTCYAjKa7PdM9Nr0+1UJr5ntoxC4BLebB/BQFwKsX1me6lb/RJ89HGKgB+jfZLae5zFACX0nk3xX5pBMCvGttjnvRJWQB8myw0e5sFwK0p2C+h2aMAOJXbvQlm1gqAZ/k6sgD8PfpmXzsB8KuzX8rWZgFwKrV3P9iPIgB+1fFoQi8AziV9qgA4d4bljALg2GY/3vnJAuBVfubXfryrAPgVzyVYFgDfogD8Per8JAHwbDWzfh+rAHiVpmYws7CcWQC8qtddzOwWAM/yuawCAABu9HPbCYBj2cyG5swC4FacevtR9lEA3ErPEswWAfCsrncrAADgxraPAuBZN5i921oFwK31fs0szG0nAG7FvZhZLwCe5ak/BAAA3FizAPj2WjmyAPjVzcHMyhEFwK16zcHMyiQAftVrCzYLgGt1jQIAAG7MRxYAz7KZ9VMWALfqNQcz66ckAG7VdhnM7BYAx2q7DKcA+NZ1AgAAXtSyjQLg2WVm7x4FwK94v2ZWpiwAfo1bMLNJAByr1zyMAuBbJwAA4EYsUxYAzw4za55OANyq1zKYDctVBcCt7mnMLIwC4Fg+ytAJgG9ZAADAjWuPAuBaY9afSQD8GrdgNixXFQC3atuYWbirAPiVpmJFAHyLqwAAgBtjEgDX6jssVxUAv9IymIU7CoBfaSpm1p9JAPwat2A2C4BntW1WAQAAAPiPyGVKAuDZYTYslwD4VdvGzN49C4Bf6Shm1kQBcGydhyEJgGvdJQAA4EZOAuDbMiyrAHi2mNl7ZAHwKx2vmTVXFQC/1mUw6wXAszSVQwCcqwIAAG4cSQBcW4ckAK7lU/8D/a9fSZZlwxkAAAAASUVORK5CYII="); height: 196px; position: absolute; left: 10px; right: 100px; top: 97px; background-size: 100% 100%; background-repeat: no-repeat;}
|
||||
.release-line li .title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
|
||||
.branch-nav .nav li { max-width: 200px; white-space: nowrap; overflow: hidden; }
|
||||
|
||||
@@ -1578,10 +1578,16 @@ class productModel extends model
|
||||
if($plan->parent > 0 and isset($parents[$plan->parent])) $plan->title = $parents[$plan->parent] . ' / ' . $plan->title;
|
||||
|
||||
$year = substr($plan->end, 0, 4);
|
||||
$roadmap[$year][$plan->branch][] = $plan;
|
||||
$branchIdList = explode(',', trim($plan->branch, ','));
|
||||
$branchIdList = array_unique($branchIdList);
|
||||
foreach($branchIdList as $branchID)
|
||||
{
|
||||
if($branchID === '') continue;
|
||||
$roadmap[$year][$branchID][] = $plan;
|
||||
}
|
||||
$total++;
|
||||
|
||||
if($count > 0 and $total >= $count) return $this->processRoadmap($roadmap);
|
||||
if($count > 0 and $total >= $count) return $this->processRoadmap($roadmap, $branch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1595,14 +1601,20 @@ class productModel extends model
|
||||
foreach($releases as $release)
|
||||
{
|
||||
$year = substr($release->date, 0, 4);
|
||||
$roadmap[$year][$release->branch][] = $release;
|
||||
$branchIdList = explode(',', trim($release->branch, ','));
|
||||
$branchIdList = array_unique($branchIdList);
|
||||
foreach($branchIdList as $branchID)
|
||||
{
|
||||
if($branchID === '') continue;
|
||||
$roadmap[$year][$branchID][] = $release;
|
||||
}
|
||||
$total++;
|
||||
|
||||
if($count > 0 and $total >= $count) return $this->processRoadmap($roadmap);
|
||||
if($count > 0 and $total >= $count) return $this->processRoadmap($roadmap, $branch);
|
||||
}
|
||||
}
|
||||
|
||||
if($count > 0) return $this->processRoadmap($roadmap);
|
||||
if($count > 0) return $this->processRoadmap($roadmap, $branch);
|
||||
|
||||
$groupRoadmap = array();
|
||||
foreach($roadmap as $year => $branchRoadmaps)
|
||||
@@ -1643,16 +1655,18 @@ class productModel extends model
|
||||
* Process roadmap.
|
||||
*
|
||||
* @param array $roadmap
|
||||
* @param int $branch
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function processRoadmap($roadmapGroups)
|
||||
public function processRoadmap($roadmapGroups, $branch)
|
||||
{
|
||||
$newRoadmap = array();
|
||||
foreach($roadmapGroups as $year => $branchRoadmaps)
|
||||
{
|
||||
foreach($branchRoadmaps as $branch => $roadmaps)
|
||||
foreach($branchRoadmaps as $branchID => $roadmaps)
|
||||
{
|
||||
if($branch != $branchID) continue;
|
||||
foreach($roadmaps as $roadmap) $newRoadmap[] = $roadmap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,7 +620,11 @@ js::set('vision', $this->config->vision);
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="icon icon-close"></i></button>
|
||||
<h4 class="modal-title"><?php echo $lang->execution->linkStoryByPlan;?></h4><?php echo '(' . $lang->project->linkStoryByPlanTips . ')';?>
|
||||
<h4 class="modal-title">
|
||||
<?php
|
||||
$linkStoryByPlanTips = $product->type == 'normal' ? $lang->project->linkNormalStoryByPlanTips : sprintf($lang->project->linkBranchStoryByPlanTips, $lang->product->branchName[$product->type]);
|
||||
echo $lang->execution->linkStoryByPlan;?></h4><?php echo '(' . $linkStoryByPlanTips . ')';
|
||||
?>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class='input-group'>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<ul class="nav nav-secondary inline-block">
|
||||
<li class="nav-heading"><?php echo zget($lang->product->branchName, $product->type);?></li>
|
||||
<?php foreach($branches as $branchKey => $branchName):?>
|
||||
<li <?php if($branchKey == 0) echo "class='active'";?>><a data-target="#tabContent<?php echo $branchKey;?>" data-toggle="tab"><?php echo $branchName;?></a></li>
|
||||
<li title="<?php echo $branchName;?>" <?php if($branchKey == 0) echo "class='active'";?>><a data-target="#tabContent<?php echo $branchKey;?>" data-toggle="tab"><?php echo $branchName;?></a></li>
|
||||
<?php endforeach;?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -30,7 +30,7 @@ $config->productplan->search['fields']['end'] = $lang->productplan->end;
|
||||
|
||||
$config->productplan->search['params']['id'] = array('operator' => '=', 'control' => 'input', 'values' => '');
|
||||
$config->productplan->search['params']['title'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
|
||||
$config->productplan->search['params']['branch'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
$config->productplan->search['params']['branch'] = array('operator' => 'include', 'control' => 'select', 'values' => '');
|
||||
$config->productplan->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => array('' => '') + $lang->productplan->statusList);
|
||||
$config->productplan->search['params']['begin'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
|
||||
$config->productplan->search['params']['end'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
|
||||
|
||||
+142
-38
@@ -84,7 +84,7 @@ class productplan extends control
|
||||
}
|
||||
|
||||
$this->commonAction($productID, $branchID);
|
||||
$lastPlan = $this->productplan->getLast($productID, $branchID, $parent);
|
||||
$lastPlan = $this->productplan->getLast($productID, '', $parent);
|
||||
$product = $this->loadModel('product')->getById($productID);
|
||||
|
||||
if($lastPlan)
|
||||
@@ -117,7 +117,7 @@ class productplan extends control
|
||||
$this->view->branches = $branchPairs;
|
||||
$this->view->defaultBranch = $defaultBranch;
|
||||
$this->view->parent = $parent;
|
||||
$this->view->parentPlanPairs = $this->productplan->getTopPlanPairs($productID, $branchID, 'done,closed');
|
||||
$this->view->parentPlanPairs = $this->productplan->getTopPlanPairs($productID, 'done,closed');
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ class productplan extends control
|
||||
$changes = $this->productplan->update($planID);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
$change[$planID] = $changes;
|
||||
$this->syncStory($change);
|
||||
$this->unlinkOldBranch($change);
|
||||
if($changes)
|
||||
{
|
||||
$actionID = $this->loadModel('action')->create('productplan', $planID, 'edited');
|
||||
@@ -151,11 +151,19 @@ class productplan extends control
|
||||
$oldBranch = array($planID => $plan->branch);
|
||||
|
||||
/* Get the parent plan pair exclusion itself. */
|
||||
$parentPlanPairs = $this->productplan->getTopPlanPairs($plan->product, $plan->branch);
|
||||
$parentPlanPairs = $this->productplan->getTopPlanPairs($plan->product);
|
||||
unset($parentPlanPairs[$planID]);
|
||||
$this->view->parentPlanPairs = $parentPlanPairs;
|
||||
|
||||
$this->commonAction($plan->product, $plan->branch);
|
||||
|
||||
if($plan->parent > 0)
|
||||
{
|
||||
$parentPlan = $this->productplan->getByID($plan->parent);
|
||||
$branchPairs = array();
|
||||
foreach(explode(',', $parentPlan->branch) as $parentBranchID) $branchPairs[$parentBranchID] = $this->view->branchTagOption[$parentBranchID];
|
||||
$this->view->branchTagOption = $branchPairs;
|
||||
}
|
||||
$this->view->title = $this->view->product->name . $this->lang->colon . $this->lang->productplan->edit;
|
||||
$this->view->position[] = $this->lang->productplan->edit;
|
||||
$this->view->productID = $plan->product;
|
||||
@@ -178,7 +186,7 @@ class productplan extends control
|
||||
if(!empty($_POST['title']))
|
||||
{
|
||||
$changes = $this->productplan->batchUpdate($productID);
|
||||
$this->syncStory($changes);
|
||||
$this->unlinkOldBranch($changes);
|
||||
$this->loadModel('action');
|
||||
foreach($changes as $planID => $change)
|
||||
{
|
||||
@@ -194,15 +202,21 @@ class productplan extends control
|
||||
|
||||
$this->commonAction($productID, $branch);
|
||||
|
||||
$plans = $this->productplan->getByIDList($this->post->planIDList);
|
||||
$oldBranch = array();
|
||||
$plans = $this->productplan->getByIDList($this->post->planIDList);
|
||||
$oldBranch = array();
|
||||
$parentIdList = array();
|
||||
|
||||
foreach($plans as $plan) $oldBranch[$plan->id] = $plan->branch;
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
$oldBranch[$plan->id] = $plan->branch;
|
||||
$parentIdList[$plan->parent] = $plan->parent;
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->productplan->batchEdit;
|
||||
$this->view->plans = $plans;
|
||||
$this->view->oldBranch = $oldBranch;
|
||||
$this->view->product = $this->loadModel('product')->getById($productID);;
|
||||
$this->view->title = $this->lang->productplan->batchEdit;
|
||||
$this->view->plans = $plans;
|
||||
$this->view->oldBranch = $oldBranch;
|
||||
$this->view->product = $this->loadModel('product')->getById($productID);;
|
||||
$this->view->parentList = $this->productplan->getByIDList($parentIdList);
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -447,8 +461,6 @@ class productplan extends control
|
||||
if($plan->parent > 0) $this->view->parentPlan = $this->productplan->getById($plan->parent);
|
||||
if($plan->parent == '-1') $this->view->childrenPlans = $this->productplan->getChildren($plan->id);
|
||||
|
||||
if($plan->branch > 0) $this->view->branchStatus = $this->loadModel('branch')->getById($plan->branch, $plan->product, 'status');
|
||||
|
||||
$storyIdList = array();
|
||||
$modulePairs = $this->loadModel('tree')->getOptionMenu($plan->product, 'story', 0, 'all');
|
||||
foreach($planStories as $story)
|
||||
@@ -593,7 +605,7 @@ class productplan extends control
|
||||
*/
|
||||
public function ajaxGetProductplans($productID, $branch = 0, $number = '', $expired = '')
|
||||
{
|
||||
$plans = $this->productplan->getPairs($productID, $branch, $expired, true);
|
||||
$plans = $this->productplan->getPairs($productID, empty($branch) ? '' : $branch, $expired, true);
|
||||
$planName = $number === '' ? 'plan' : "plan[$number]";
|
||||
$plans = empty($plans) ? array('' => '') : $plans;
|
||||
echo html::select($planName, $plans, '', "class='form-control'");
|
||||
@@ -675,7 +687,7 @@ class productplan extends control
|
||||
$this->config->product->search['style'] = 'simple';
|
||||
$this->config->product->search['params']['product']['values'] = $products + array('all' => $this->lang->product->allProductsOfProject);
|
||||
$this->config->product->search['params']['plan']['values'] = $this->productplan->getPairsForStory($plan->product, $plan->branch, 'skipParent|withMainPlan');
|
||||
$this->config->product->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($plan->product, 'story', 0, $plan->branch);
|
||||
$this->config->product->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($plan->product, 'story', 0, 'all');
|
||||
$storyStatusList = $this->lang->story->statusList;
|
||||
unset($storyStatusList['closed']);
|
||||
$this->config->product->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => $storyStatusList);
|
||||
@@ -687,8 +699,9 @@ class productplan extends control
|
||||
else
|
||||
{
|
||||
$this->config->product->search['fields']['branch'] = $this->lang->product->branch;
|
||||
$branchName = $this->loadModel('branch')->getById($plan->branch);
|
||||
$branches = array('' => '', BRANCH_MAIN => $this->lang->branch->main, $plan->branch => $branchName);
|
||||
|
||||
$branchPairs = $this->dao->select('id, name')->from(TABLE_BRANCH)->where('id')->in($plan->branch)->fetchPairs();
|
||||
$branches = array('' => '', BRANCH_MAIN => $this->lang->branch->main) + $branchPairs;
|
||||
$this->config->product->search['params']['branch']['values'] = $branches;
|
||||
}
|
||||
$this->loadModel('search')->setSearchParams($this->config->product->search);
|
||||
@@ -809,9 +822,12 @@ class productplan extends control
|
||||
$this->config->bug->search['style'] = 'simple';
|
||||
$this->config->bug->search['params']['plan']['values'] = $this->productplan->getPairsForStory($productID, $plan->branch, 'skipParent|withMainPlan');
|
||||
$this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($plan->product, $plan->branch);
|
||||
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, $branch = 'all', $params = '');
|
||||
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->build->getBuildPairs($productID, $branch = 'all', $params = '');
|
||||
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($plan->product, 'bug', 0, 'all');
|
||||
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, $branch = 'all', $params = 'releasetag');
|
||||
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
|
||||
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($plan->product, 'bug', 0, $plan->branch);
|
||||
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($plan->product, 'bug', 0, 'all');
|
||||
$this->config->bug->search['params']['project']['values'] = $this->product->getProjectPairsByProduct($productID, $plan->branch);
|
||||
|
||||
unset($this->config->bug->search['fields']['product']);
|
||||
@@ -823,8 +839,9 @@ class productplan extends control
|
||||
else
|
||||
{
|
||||
$this->config->bug->search['fields']['branch'] = $this->lang->product->branch;
|
||||
$branchName = $this->loadModel('branch')->getById($plan->branch);
|
||||
$branches = array('' => '', BRANCH_MAIN => $this->lang->branch->main, $plan->branch => $branchName);
|
||||
|
||||
$branchPairs = $this->dao->select('id, name')->from(TABLE_BRANCH)->where('id')->in($plan->branch)->fetchPairs();
|
||||
$branches = array('' => '', BRANCH_MAIN => $this->lang->branch->main) + $branchPairs;
|
||||
$this->config->bug->search['params']['branch']['values'] = $branches;
|
||||
}
|
||||
$this->loadModel('search')->setSearchParams($this->config->bug->search);
|
||||
@@ -891,13 +908,13 @@ class productplan extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize story when edit plan.
|
||||
* Unlink story and bug when edit branch of plan.
|
||||
* @param int $planID
|
||||
* @param int $oldBranch
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function syncStory($changes)
|
||||
protected function unlinkOldBranch($changes)
|
||||
{
|
||||
foreach($changes as $planID => $changes)
|
||||
{
|
||||
@@ -913,38 +930,71 @@ class productplan extends control
|
||||
}
|
||||
}
|
||||
$planStories = $this->loadModel('story')->getPlanStories($planID, 'all');
|
||||
$planBugs = $this->loadModel('bug')->getPlanBugs($planID, 'all');
|
||||
if($oldBranch)
|
||||
{
|
||||
foreach($planStories as $storyID => $story)
|
||||
{
|
||||
if($story->branch and $story->branch != $newBranch) $this->productplan->unlinkStory($storyID, $planID);
|
||||
if($story->branch and strpos(",$newBranch,", ",$story->branch,") === false) $this->productplan->unlinkStory($storyID, $planID);
|
||||
}
|
||||
|
||||
foreach($planBugs as $bugID => $bug)
|
||||
{
|
||||
if($bug->branch and strpos(",$newBranch,", ",$bug->branch,") === false) $this->productplan->unlinkBug($bugID, $planID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Get conflict story.
|
||||
* AJAX: Get conflict story and bug.
|
||||
*
|
||||
* @param int $planID
|
||||
* @param int $branch
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetConflictStory($planID, $newBranch)
|
||||
public function ajaxGetConflict($planID, $newBranch)
|
||||
{
|
||||
$plan = $this->productplan->getByID($planID);
|
||||
$oldBranch = $plan->branch;
|
||||
$planStories = $this->loadModel('story')->getPlanStories($planID, 'all');
|
||||
$conflictStoryIdList = '';
|
||||
$plan = $this->productplan->getByID($planID);
|
||||
$oldBranch = $plan->branch;
|
||||
$planStories = $this->loadModel('story')->getPlanStories($planID, 'all');
|
||||
$planBugs = $this->loadModel('bug')->getPlanBugs($planID, 'all');
|
||||
$branchPairs = $this->loadModel('branch')->getPairs($plan->product);
|
||||
|
||||
$removeBranches = '';
|
||||
foreach(explode(',', $oldBranch) as $oldBranchID)
|
||||
{
|
||||
if($oldBranchID and strpos(",$newBranch,", ",$oldBranchID,") === false) $removeBranches .= "{$branchPairs[$oldBranchID]},";
|
||||
}
|
||||
|
||||
$conflictStoryCounts = 0;
|
||||
$conflictBugCounts = 0;
|
||||
if($oldBranch)
|
||||
{
|
||||
foreach($planStories as $storyID => $story)
|
||||
{
|
||||
if($story->branch and $story->branch != $newBranch) $conflictStoryIdList .= '[' . $storyID . ']';
|
||||
if($story->branch and strpos(",$newBranch,", ",$story->branch,") === false) $conflictStoryCounts ++;
|
||||
}
|
||||
|
||||
foreach($planBugs as $bugID => $bug)
|
||||
{
|
||||
if($bug->branch and strpos(",$newBranch,", ",$bug->branch,") === false) $conflictBugCounts ++;
|
||||
}
|
||||
}
|
||||
if($conflictStoryIdList != '') printf($this->lang->story->confirmChangePlan, $conflictStoryIdList);
|
||||
|
||||
if($conflictStoryCounts and $conflictBugCounts)
|
||||
{
|
||||
printf($this->lang->productplan->confirmChangePlan, trim($removeBranches, ','), $conflictStoryCounts, $conflictBugCounts);
|
||||
}
|
||||
elseif($conflictStoryCounts)
|
||||
{
|
||||
printf($this->lang->productplan->confirmRemoveStory, trim($removeBranches, ','), $conflictStoryCounts);
|
||||
}
|
||||
elseif($conflictBugCounts)
|
||||
{
|
||||
printf($this->lang->productplan->confirmRemoveBug, trim($removeBranches, ','), $conflictBugCounts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -963,16 +1013,70 @@ class productplan extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Get top plan.
|
||||
* AJAX: Get parent branches.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $branch
|
||||
* @param int $parentID
|
||||
* @param string $currentBranches
|
||||
* @access public
|
||||
* @return object
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetTopPlan($productID, $branch = 0)
|
||||
public function ajaxGetParentBranches($productID = 0, $parentID = 0, $currentBranches = '')
|
||||
{
|
||||
$parentPlanPairs = $this->productplan->getTopPlanPairs($productID, $branch);
|
||||
return print(html::select('parent', array('0' => '') + $parentPlanPairs, '', 'class="form-control"'));
|
||||
$branchPairs = $this->loadModel('branch')->getPairs($productID, 'active');
|
||||
if(!empty($parentID))
|
||||
{
|
||||
$parentBranches = array();
|
||||
$parentPlan = $this->productplan->getByID($parentID);
|
||||
foreach(explode(',', $parentPlan->branch) as $parentBranchID)
|
||||
{
|
||||
if(!isset($branchPairs[$parentBranchID])) continue;
|
||||
$parentBranches[$parentBranchID] = $branchPairs[$parentBranchID];
|
||||
if(!empty($currentBranches) and strpos(",$currentBranches,", ",$parentBranchID,") === false) $currentBranches = str_replace(",$parentBranchID,", ',', $currentBranches);
|
||||
}
|
||||
}
|
||||
return print(html::select('branch[]', empty($parentID) ? $branchPairs : $parentBranches, trim($currentBranches, ','), "class='form-control chosen' multiple"));
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Get diff branches tips.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $parentID
|
||||
* @param string $branches
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetDiffBranchesTip($productID = 0, $parentID = 0, $branches = '')
|
||||
{
|
||||
if(empty($parentID) or empty($productID)) return;
|
||||
|
||||
/* If it has children, return. */
|
||||
$parentBranch = $this->productplan->getByID($parentID);
|
||||
if($parentBranch->parent == '-1') return;
|
||||
|
||||
/* Find diff branches between parent plan and child plan. */
|
||||
$diffBranches = array();
|
||||
$diffBranchesTip = '';
|
||||
$product = $this->loadModel('product')->getByID($productID);
|
||||
$branchPairs = $this->loadModel('branch')->getPairs($productID);
|
||||
foreach(explode(',', $parentBranch->branch) as $parentBranchID)
|
||||
{
|
||||
if(empty($parentBranchID)) continue;
|
||||
if(strpos(",$branches,", ",$parentBranchID,") === false)
|
||||
{
|
||||
$diffBranches[$parentBranchID] = $parentBranchID;
|
||||
$diffBranchesTip .= "{$branchPairs[$parentBranchID]},";
|
||||
}
|
||||
}
|
||||
if(empty($diffBranchesTip)) return;
|
||||
|
||||
/* Find stories and bugs in diff branches. */
|
||||
$unlinkStories = $this->dao->select('*')->from(TABLE_STORY)->where('branch')->in($diffBranches)->andWhere("CONCAT(',', plan, ',')")->like("%,{$parentID},%")->fetchAll('id');
|
||||
$unlinkBugs = $this->dao->select('*')->from(TABLE_BUG)->where('branch')->in($diffBranches)->andWhere('plan')->eq($parentID)->fetchAll('id');
|
||||
if(empty($unlinkStories) and empty($unlinkBugs)) return;
|
||||
|
||||
$this->lang->productplan->diffBranchesTip = str_replace('@branch@', $this->lang->product->branchName[$product->type], $this->lang->productplan->diffBranchesTip);
|
||||
printf($this->lang->productplan->diffBranchesTip, trim($diffBranchesTip, ','));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.table td.content div {height: 25px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; float: left; max-width: calc(100% - 20px);}
|
||||
.table td.content .more {position: absolute; right: 16px;}
|
||||
.table td.content .more .icon {color: #838a9d;}
|
||||
td.c-branch {overflow: hidden; text-align: left !important; text-overflow: ellipsis; white-space: nowrap;}
|
||||
td.c-branch {overflow: hidden; text-align: left !important; 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;}
|
||||
@@ -17,11 +17,12 @@ td.c-branch {overflow: hidden; text-align: left !important; text-overflow: ellip
|
||||
@-moz-document url-prefix() {.main-table tbody > tr.table-children > td:first-child::before {width: 4px;};}
|
||||
|
||||
.c-title {width: 160px;}
|
||||
.c-branch {width: 100px;}
|
||||
.c-branch {width: 130px;}
|
||||
.c-story, .c-status {width: 80px;}
|
||||
.c-execution {width: 60px !important;}
|
||||
.c-bug, .c-hour {width: 60px;}
|
||||
.c-desc {width: 160px;}
|
||||
.c-desc {width: 140px;}
|
||||
.c-date {width: 90px;}
|
||||
|
||||
.plan-name {position: relative; display: flex; align-items: center;}
|
||||
.plan-name > span {flex: none;}
|
||||
|
||||
@@ -33,3 +33,6 @@ ol, ul {padding-left: 20px;}
|
||||
#mainMenu .btn-toolbar .page-title .text {max-width: 434px; overflow: hidden; white-space:nowrap; margin-right: 6px;}
|
||||
#actionsBox a:last-of-type + .divider {display: none;}
|
||||
#actionsBox div.divider:first-child {display: none;}
|
||||
|
||||
#bugs th.c-pri, #bugs th.c-actions {width:70px !important;}
|
||||
#bugs th.c-status, #bugs th.c-user {width:120px !important;}
|
||||
|
||||
@@ -24,17 +24,17 @@ function changeDate(planID)
|
||||
* Get conflict stories.
|
||||
*
|
||||
* @param int $planID
|
||||
* @param int $branch
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function getConflictStories(planID, branch)
|
||||
function getConflictStories(planID)
|
||||
{
|
||||
$.get(createLink('productplan', 'ajaxGetConflictStory', 'planID=' + planID + '&newBranch=' + branch), function(conflictStories)
|
||||
var newBranch = $('#branch' + planID).val() ? $('#branch' + planID).val().toString() : '';
|
||||
$.get(createLink('productplan', 'ajaxGetConflict', 'planID=' + planID + '&newBranch=' + newBranch), function(conflictStories)
|
||||
{
|
||||
if(conflictStories != '' && !confirm(conflictStories))
|
||||
{
|
||||
$('#branch' + planID).val(oldBranch[planID]);
|
||||
$('#branch' + planID).val(oldBranch[planID].split(','));
|
||||
$('#branch' + planID).trigger("chosen:updated");
|
||||
}
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user