Merge branch 'master' into master_oss_wangjianhua
This commit is contained in:
@@ -408,8 +408,12 @@ class userEntry extends entry
|
||||
$this->setPost('gender', $gender);
|
||||
|
||||
$password = $this->request('password', zget($_POST, 'password', ''));
|
||||
$this->setPost('password1', md5($password));
|
||||
$this->setPost('password2', md5($password));
|
||||
if($password)
|
||||
{
|
||||
$this->setPost('password1', md5($password));
|
||||
$this->setPost('password2', md5($password));
|
||||
$this->setPost('passwordStrength', 2);
|
||||
}
|
||||
$this->setPost('verifyPassword', md5($this->app->user->password . $this->app->session->rand));
|
||||
|
||||
$control = $this->loadController('user', 'edit');
|
||||
|
||||
@@ -403,7 +403,7 @@ $config->pipelineTypeList = array('gitlab', 'gogs', 'gitea', 'jenkins', 'sonarqu
|
||||
|
||||
/* Program privs.*/
|
||||
$config->programPriv = new stdclass();
|
||||
$config->programPriv->noSprint = array('task', 'story', 'tree', 'project', 'execution', 'build', 'bug', 'testcase', 'testreport', 'doc', 'repo', 'stakeholder');
|
||||
$config->programPriv->noSprint = array('task', 'story', 'tree', 'project', 'execution', 'build', 'bug', 'testcase', 'testreport', 'doc', 'repo', 'stakeholder', 'projectrelease', 'requirement');
|
||||
$config->programPriv->scrum = array('story', 'requirement', 'productplan', 'tree', 'projectplan', 'projectstory', 'projectrelease', 'project', 'execution', 'build', 'bug', 'testcase', 'testreport', 'doc', 'repo', 'meeting', 'stakeholder', 'testtask');
|
||||
$config->programPriv->waterfall = array_merge($config->programPriv->scrum, array('task', 'workestimation', 'durationestimation', 'budget', 'programplan', 'review', 'reviewissue', 'weekly', 'cm', 'milestone', 'design', 'issue', 'risk', 'opportunity', 'measrecord', 'auditplan', 'trainplan', 'gapanalysis', 'pssp', 'researchplan', 'researchreport'));
|
||||
|
||||
|
||||
@@ -1489,7 +1489,7 @@ CREATE TABLE `zt_kanban` (
|
||||
`showWIP` enum('0','1') NOT NULL DEFAULT '1',
|
||||
`fluidBoard` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`colWidth` smallint(4) NOT NULL DEFAULT '264',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '180',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '200',
|
||||
`maxColWidth` smallint(4) NOT NULL DEFAULT '384',
|
||||
`object` varchar(255) NOT NULL,
|
||||
`alignment` varchar(10) NOT NULL DEFAULT 'center',
|
||||
@@ -2187,7 +2187,7 @@ CREATE TABLE `zt_project` (
|
||||
`displayCards` smallint(6) NOT NULL DEFAULT '0',
|
||||
`fluidBoard` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`colWidth` smallint(4) NOT NULL DEFAULT '264',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '180',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '200',
|
||||
`maxColWidth` smallint(4) NOT NULL DEFAULT '384',
|
||||
`deleted` enum('0','1') NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
|
||||
@@ -1489,7 +1489,7 @@ CREATE TABLE `zt_kanban` (
|
||||
`showWIP` enum('0','1') NOT NULL DEFAULT '1',
|
||||
`fluidBoard` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`colWidth` smallint(4) NOT NULL DEFAULT '264',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '180',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '200',
|
||||
`maxColWidth` smallint(4) NOT NULL DEFAULT '384',
|
||||
`object` varchar(255) NOT NULL,
|
||||
`alignment` varchar(10) NOT NULL DEFAULT 'center',
|
||||
@@ -2187,7 +2187,7 @@ CREATE TABLE `zt_project` (
|
||||
`displayCards` smallint(6) NOT NULL DEFAULT '0',
|
||||
`fluidBoard` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`colWidth` smallint(4) NOT NULL DEFAULT '264',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '180',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '200',
|
||||
`maxColWidth` smallint(4) NOT NULL DEFAULT '384',
|
||||
`deleted` enum('0','1') NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
|
||||
@@ -1232,6 +1232,8 @@ CREATE TABLE `zt_im_chat` (
|
||||
`pinnedMessages` text NOT NULL,
|
||||
`mergedChats` text NOT NULL DEFAULT '',
|
||||
`adminInvite` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`avatar` text NOT NULL DEFAULT '',
|
||||
`archiveDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `gid` (`gid`),
|
||||
KEY `name` (`name`),
|
||||
@@ -1490,7 +1492,7 @@ CREATE TABLE `zt_kanban` (
|
||||
`showWIP` enum('0','1') NOT NULL DEFAULT '1',
|
||||
`fluidBoard` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`colWidth` smallint(4) NOT NULL DEFAULT '264',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '180',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '200',
|
||||
`maxColWidth` smallint(4) NOT NULL DEFAULT '384',
|
||||
`object` varchar(255) NOT NULL,
|
||||
`alignment` varchar(10) NOT NULL DEFAULT 'center',
|
||||
@@ -2192,7 +2194,7 @@ CREATE TABLE `zt_project` (
|
||||
`fluidBoard` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`multiple` enum('0', '1') NOT NULL DEFAULT '1',
|
||||
`colWidth` smallint(4) NOT NULL DEFAULT '264',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '180',
|
||||
`minColWidth` smallint(4) NOT NULL DEFAULT '200',
|
||||
`maxColWidth` smallint(4) NOT NULL DEFAULT '384',
|
||||
`deleted` enum('0','1') NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
@@ -2278,6 +2280,7 @@ CREATE TABLE `zt_release` (
|
||||
`project` varchar(255) NOT NULL,
|
||||
`product` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`branch` varchar(255) NOT NULL,
|
||||
`shadow` mediumint(8) unsigned NOT NULL default '0',
|
||||
`build` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL DEFAULT '',
|
||||
`marker` enum('0','1') NOT NULL DEFAULT '0',
|
||||
+2
-2
@@ -62,10 +62,10 @@ CREATE TABLE `zt_ticketrelation` (
|
||||
|
||||
ALTER TABLE `zt_product` ADD `ticket` varchar(30) NOT NULL AFTER `feedback`;
|
||||
ALTER TABLE `zt_kanban` ADD `colWidth` smallint(4) NOT NULL DEFAULT '264' AFTER `fluidBoard`;
|
||||
ALTER TABLE `zt_kanban` ADD `minColWidth` smallint(4) NOT NULL DEFAULT '180' AFTER `colWidth`;
|
||||
ALTER TABLE `zt_kanban` ADD `minColWidth` smallint(4) NOT NULL DEFAULT '200' AFTER `colWidth`;
|
||||
ALTER TABLE `zt_kanban` ADD `maxColWidth` smallint(4) NOT NULL DEFAULT '384' AFTER `minColWidth`;
|
||||
ALTER TABLE `zt_project` ADD `colWidth` smallint(4) NOT NULL DEFAULT '264' AFTER `fluidBoard`;
|
||||
ALTER TABLE `zt_project` ADD `minColWidth` smallint(4) NOT NULL DEFAULT '180' AFTER `colWidth`;
|
||||
ALTER TABLE `zt_project` ADD `minColWidth` smallint(4) NOT NULL DEFAULT '200' AFTER `colWidth`;
|
||||
ALTER TABLE `zt_project` ADD `maxColWidth` smallint(4) NOT NULL DEFAULT '384' AFTER `minColWidth`;
|
||||
|
||||
REPLACE INTO `zt_config` (`owner`, `module`, `section`, `key`, `value`) VALUES ('system', 'common', 'global', 'syncProduct', '{"feedback":{},"ticket":{}}');
|
||||
|
||||
@@ -5,6 +5,7 @@ ALTER TABLE `zt_repo` ADD `projects` varchar(255) NOT NULL AFTER `product`;
|
||||
ALTER TABLE `zt_release` CHANGE `project` `project` varchar(255) NOT NULL;
|
||||
ALTER TABLE `zt_release` CHANGE `branch` `branch` varchar(255) NOT NULL;
|
||||
ALTER TABLE `zt_release` CHANGE `build` `build` varchar(255) NOT NULL;
|
||||
ALTER TABLE `zt_release` ADD `shadow` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `branch`;
|
||||
|
||||
CREATE OR REPLACE VIEW `ztv_normalproduct` AS SELECT * FROM `zt_product` WHERE `shadow` = 0;
|
||||
|
||||
|
||||
+2
-2
@@ -1285,6 +1285,7 @@ CREATE TABLE IF NOT EXISTS `zt_release` (
|
||||
`project` varchar(255) NOT NULL,
|
||||
`product` mediumint(8) unsigned NOT NULL default '0',
|
||||
`branch` varchar(255) NOT NULL default '0',
|
||||
`shadow` mediumint(8) unsigned NOT NULL default '0',
|
||||
`build` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL default '',
|
||||
`marker` enum('0','1') NOT NULL default '0',
|
||||
@@ -6407,8 +6408,7 @@ CREATE TABLE IF NOT EXISTS `zt_im_message` (
|
||||
KEY `mgid` (`gid`),
|
||||
KEY `mcgid` (`cgid`),
|
||||
KEY `muser` (`user`),
|
||||
KEY `mtype` (`type`),
|
||||
UNIQUE `unique_msg`(`index`, `cgid`)
|
||||
KEY `mtype` (`type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- DROP TABLE IF EXISTS `zt_im_message_backup`;
|
||||
|
||||
+53
-53
@@ -39,14 +39,14 @@
|
||||
39090 创建不启用迭代的项目时,项目起止日期自动同步到隐藏迭代的起止日期
|
||||
38949 产品看板中增加显示非当前项目集的项目信息的开关功能
|
||||
38948 项目集看板中增加显示非当前项目集的项目信息的开关功能
|
||||
38934 单迭代无产品项目的研发需求增加报表功能
|
||||
38931 单迭代无产品项目的权限去掉计划和会议相关的权限
|
||||
38928 单迭代无产品项目的版本关联需求和bug时搜索条件去掉所属计划
|
||||
38927 单迭代无产品项目增加发布功能
|
||||
38925 单迭代无产品项目的研发需求相关页面去掉计划信息
|
||||
38924 单迭代无产品项目研发需求看板中去掉关联研发需求的按钮
|
||||
38922 单迭代无产品项目中研发需求列表增加细分按钮
|
||||
38921 单迭代无产品项目增加用户需求功能
|
||||
38934 单迭代项目型项目的研发需求增加报表功能
|
||||
38931 单迭代项目型项目的权限去掉计划和会议相关的权限
|
||||
38928 单迭代项目型项目的版本关联需求和bug时搜索条件去掉所属计划
|
||||
38927 单迭代项目型项目增加发布功能
|
||||
38925 单迭代项目型项目的研发需求相关页面去掉计划信息
|
||||
38924 单迭代项目型项目研发需求看板中去掉关联研发需求的按钮
|
||||
38922 单迭代项目型项目中研发需求列表增加细分按钮
|
||||
38921 单迭代项目型项目增加用户需求功能
|
||||
38920 将地盘待处理中的评审功能与地盘审批功能进行合并
|
||||
38918 无迭代项目的任务列表中,导出数据的字段中所属执行调整为所属项目
|
||||
38917 无迭代项目的任务列表中,导出模板的字段中所属执行调整为所属项目
|
||||
@@ -106,7 +106,7 @@
|
||||
38349 从综合模式切到迅捷模式时,敏捷项目根据是否存在机会数据来判断是否开启机会功能
|
||||
38347 从综合模式切到迅捷模式时,敏捷项目根据是否存在风险数据来判断是否开启风险功能
|
||||
38345 从综合模式切到迅捷模式时,敏捷项目根据是否存在问题数据来判断是否开启问题功能
|
||||
38324 项目管理员权限分组中无产品项目的权限特殊处理
|
||||
38324 项目管理员权限分组中项目型项目的权限特殊处理
|
||||
38281 实现从15版本经典模式直接升级到18本版迅捷模式
|
||||
38234 综合模式下如果没有项目集数据,切换迅捷模式时可以不用选择默认项目集
|
||||
38231 执行创建阶段类型为需求、设计、总结评审的瀑布项目阶段时,隐藏关联计划
|
||||
@@ -255,9 +255,9 @@
|
||||
37731 编辑执行时可以取消已关联的产品
|
||||
37730 项目的产品列表中可以取消已关联的产品
|
||||
37729 后台自定义的流程中,去掉组合方式之间的减号
|
||||
37675 无产品项目复制模块可以复制产品和无产品项目的模块
|
||||
37674 项目概况中展示产品型项目和无产品项目的标签
|
||||
37673 无产品项目研发需求隐藏移除按钮
|
||||
37675 项目型项目复制模块可以复制产品和项目型项目的模块
|
||||
37674 项目概况中展示产品型项目和项目型项目的标签
|
||||
37673 项目型项目研发需求隐藏移除按钮
|
||||
37660 创建产品页面所属项目集为空时,不显示产品线字段
|
||||
37658 产品调整所属项目集时,可以任意选择一个项目集
|
||||
37657 项目调整所属项目集时,可以任意选择一个项目集
|
||||
@@ -268,44 +268,44 @@
|
||||
37612 新用户安装禅道18版本迅捷模式后关闭瀑布项目功能
|
||||
37603 从综合模式切到迅捷模式时,根据是否存在瀑布项目数据来判断是否开启瀑布项目功能
|
||||
37596 从综合模式切到迅捷模式时,访问权限是项目集内公开的项目统一调整为私有
|
||||
37572 无产品项目项目复制
|
||||
37553 无产品项目的权限通过项目维护
|
||||
37552 无产品项目的视野权限在产品中进行过滤,通过项目维护
|
||||
37551 无产品项目恢复时同步恢复影子产品
|
||||
37549 测试模块测试单功能展示产品和无产品项目的信息
|
||||
37546 测试模块用例功能统计产品和无产品项目的信息
|
||||
37544 测试模块bug功能统计产品和无产品项目的信息
|
||||
37572 项目型项目项目复制
|
||||
37553 项目型项目的权限通过项目维护
|
||||
37552 项目型项目的视野权限在产品中进行过滤,通过项目维护
|
||||
37551 项目型项目恢复时同步恢复影子产品
|
||||
37549 测试模块测试单功能展示产品和项目型项目的信息
|
||||
37546 测试模块用例功能统计产品和项目型项目的信息
|
||||
37544 测试模块bug功能统计产品和项目型项目的信息
|
||||
37542 实现从12版本升级到18版本综合模式的手工归并数据功能
|
||||
37541 无产品项目在测试区块仪表盘的所属产品展示为无产品项目名
|
||||
37541 项目型项目在测试区块仪表盘的所属产品展示为项目型项目名
|
||||
37540 地盘动态不展示影子产品的动态
|
||||
37539 无产品项目在地盘贡献的产品名称下展示为无产品项目名
|
||||
37538 无产品项目在地盘待处理的产品名称下展示为无产品项目名
|
||||
37537 无产品项目在地盘日志的所属产品展示为无产品项目名
|
||||
37534 无产品项目在地盘区块的产品名称下展示为无产品项目名
|
||||
37533 反馈不支持无产品项目
|
||||
37532 组织中无产品项目的所属产品展示为项目名
|
||||
37531 统计产品和测试菜单下的列表,无产品项目进行特殊处理
|
||||
37539 项目型项目在地盘贡献的产品名称下展示为项目型项目名
|
||||
37538 项目型项目在地盘待处理的产品名称下展示为项目型项目名
|
||||
37537 项目型项目在地盘日志的所属产品展示为项目型项目名
|
||||
37534 项目型项目在地盘区块的产品名称下展示为项目型项目名
|
||||
37533 反馈不支持项目型项目
|
||||
37532 组织中项目型项目的所属产品展示为项目名
|
||||
37531 统计产品和测试菜单下的列表,项目型项目进行特殊处理
|
||||
37530 资产库导入需求不展示无产品的产品名称
|
||||
37529 通用看板导入发布与导入计划的产品中增加无产品项目的层级,展示无产品项目名
|
||||
37529 通用看板导入发布与导入计划的产品中增加项目型项目的层级,展示项目型项目名
|
||||
37528 从12版本升级到18版本的综合模式时,增加自动或手工归并数据的功能
|
||||
37527 从12版本升级到18版本的迅捷模式时,增加自动或手工归并数据的功能
|
||||
37525 从综合模式切换为迅捷模式时可以选择一个项目集作为默认项目集
|
||||
37517 创建看板项目时可以设置是否启用迭代功能
|
||||
37504 迅捷模式下默认创建一个隐藏的项目集,关联所有产品和项目数据
|
||||
37462 无产品项目仪表盘隐藏所属产品字段
|
||||
37461 无产品项目执行的任务导入bug隐藏搜索的所属产品字段
|
||||
37460 无产品项目执行的日志导出数据隐藏所属产品
|
||||
37458 无产品项目中测试单功能隐藏产品信息
|
||||
37457 无产品项目中用例功能隐藏产品信息
|
||||
37456 无产品项目中bug功能隐藏产品信息
|
||||
37455 无产品项目中研发需求和用户需求列表导出和导入功能隐藏产品信息
|
||||
37454 无产品项目中研发需求和用户需求列表增加维护模块按钮
|
||||
37453 无产品项目中研发需求和用户需求列表隐藏所属产品信息
|
||||
37452 无产品项目执行的看板新建隐藏产品与计划
|
||||
37462 项目型项目仪表盘隐藏所属产品字段
|
||||
37461 项目型项目执行的任务导入bug隐藏搜索的所属产品字段
|
||||
37460 项目型项目执行的日志导出数据隐藏所属产品
|
||||
37458 项目型项目中测试单功能隐藏产品信息
|
||||
37457 项目型项目中用例功能隐藏产品信息
|
||||
37456 项目型项目中bug功能隐藏产品信息
|
||||
37455 项目型项目中研发需求和用户需求列表导出和导入功能隐藏产品信息
|
||||
37454 项目型项目中研发需求和用户需求列表增加维护模块按钮
|
||||
37453 项目型项目中研发需求和用户需求列表隐藏所属产品信息
|
||||
37452 项目型项目执行的看板新建隐藏产品与计划
|
||||
37451 看板项目的设置隐藏产品与计划字段
|
||||
37450 无产品项目中研发需求隐藏所属产品信息
|
||||
37449 无产品项目中增加用户需求模块
|
||||
37448 无产品项目中二级菜单研发需求改为需求,包含研发需求和用户需求
|
||||
37450 项目型项目中研发需求隐藏所属产品信息
|
||||
37449 项目型项目中增加用户需求模块
|
||||
37448 项目型项目中二级菜单研发需求改为需求,包含研发需求和用户需求
|
||||
37447 瀑布项目的报告隐藏产品
|
||||
37445 瀑布项目的估算的阶段隐藏产品
|
||||
37444 瀑布项目的评审隐藏产品
|
||||
@@ -315,15 +315,15 @@
|
||||
37438 敏捷、瀑布项目的设置隐藏产品与计划字段
|
||||
37437 敏捷、瀑布、看板项目的版本隐藏产品字段
|
||||
37424 项目模块中执行的相关页面隐藏“所属产品”字段
|
||||
37422 项目列表页导出列表中增加“项目类型”,无产品项目的所属产品为“”
|
||||
37422 项目列表页导出列表中增加“项目类型”,项目型项目的所属产品为“”
|
||||
37421 项目列表搜索项增加“项目类型”
|
||||
37420 创建项目选择“项目类型”,可以创建产品型项目或无产品项目
|
||||
37420 创建项目选择“项目类型”,可以创建产品型项目或项目型项目
|
||||
37346 项目列表页增加字段“项目类型”
|
||||
37336 迅捷模式中隐藏产品线的相关功能
|
||||
37333 无产品项目的需求列表中增加批量创建功能
|
||||
37332 无产品项目的需求列表中取消关联研发需求功能
|
||||
37331 敏捷无产品项目中增加计划功能
|
||||
37328 无产品项目中发布隐藏产品信息
|
||||
37333 项目型项目的需求列表中增加批量创建功能
|
||||
37332 项目型项目的需求列表中取消关联研发需求功能
|
||||
37331 敏捷项目型项目中增加计划功能
|
||||
37328 项目型项目中发布隐藏产品信息
|
||||
37308 实现从15版本经典模式升级到18本版迅捷模式
|
||||
37292 实现从12版本升级到18版本迅捷模式的手工归并数据功能
|
||||
37291 12版本升级到18版本时,提供综合模式和迅捷模式的介绍和选择
|
||||
@@ -334,9 +334,9 @@
|
||||
37272 从综合模式切换到迅捷模式时增加功能影响的提示信息
|
||||
37270 迅捷模式和综合模式的切换不做次数限制
|
||||
37268 调整后台自定义模式中的名称
|
||||
38176 无产品项目下可以设置与代码库的关联关系
|
||||
37635 在无产品项目下可以创建代码库
|
||||
37465 在无产品项目下可以提交评审问题
|
||||
38176 项目型项目下可以设置与代码库的关联关系
|
||||
37635 在项目型项目下可以创建代码库
|
||||
37465 在项目型项目下可以提交评审问题
|
||||
37464 代码库可以关联项目
|
||||
36616 实现版本升级后原存档讨论组逻辑处理
|
||||
36543 实现群主取消归档讨论组相关提醒及操作
|
||||
@@ -362,11 +362,11 @@
|
||||
29702 批量编辑产品,自定义表单项显示产品线
|
||||
29650 新建项目时,关联产品下拉列表显示了非所选项目集下的产品
|
||||
29628 Bug默认指派人没指派给产品测试负责人
|
||||
29549 无产品项目和无产品迭代文档下搜索条件“所属产品”未隐藏掉
|
||||
29549 项目型项目和无产品迭代文档下搜索条件“所属产品”未隐藏掉
|
||||
29535 执行中转入任务后F12有报错信息
|
||||
29508 地盘--待处理中Bug列表错乱
|
||||
29499 项目概况页面所属项目集代码报错
|
||||
29452 无产品项目下批量编辑和批量指派给下拉数据与单个指派下拉数据范围不一致
|
||||
29452 项目型项目下批量编辑和批量指派给下拉数据与单个指派下拉数据范围不一致
|
||||
27994 禅道系统使用时切换页面会突然登录超时退出
|
||||
28255 无产品权限人员编辑代码库显示项目不正确
|
||||
27516 可合并讨论组的列表中列出了已经被合并的群
|
||||
@@ -4783,7 +4783,7 @@
|
||||
1734 权限--按模块分配权限,提示文案里,control 能否改为 Ctrl。shift 改为 Shift。
|
||||
1733 用户列表页,点击用户真实姓名,跳转的页面,测试--负责的版本。表头字段没显示完整,没加title。样式也要调整一下,排序按钮太靠边框。
|
||||
1731 动态--搜索,对象类型里的 build 能否改为中文。
|
||||
1729 权限--视图维护,产品和项目不显示填写框。(无产品项目)
|
||||
1729 权限--视图维护,产品和项目不显示填写框。(项目型项目)
|
||||
1727 部门折叠展开按钮的显示位置要调整。
|
||||
1724 统计,测试,Bug创建表,选择产品和项目时,刷新选择框,显示的样式不对。
|
||||
1722 项目起止时间选择框,宽度不一致。前面窄后面的宽。
|
||||
|
||||
@@ -4,7 +4,8 @@ class myExecution extends execution
|
||||
{
|
||||
public function create($projectID = '', $executionID = 0, $copyExecutionID = '', $planID = 0, $confirm = 'no', $productID = 0, $extra = '')
|
||||
{
|
||||
$this->config->execution->create->requiredFields = 'name,code,begin,end';
|
||||
$this->config->execution->create->requiredFields = 'name,code,begin,end';
|
||||
$this->loadModel('project')->setMenu($projectID);
|
||||
parent::create($projectID, $executionID, $copyExecutionID, $planID, $confirm, $productID, $extra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
<?php echo html::hidden("RD", '');?>
|
||||
<?php echo html::hidden("type", 'kanban');?>
|
||||
<?php echo html::hidden("vision", 'lite');?>
|
||||
<?php echo html::hidden('project', $projectID);?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -90,6 +90,7 @@ class product extends control
|
||||
$product = $this->product->getById($productID);
|
||||
|
||||
/* Get stories. */
|
||||
if($browseType == 'reviewing') $browseType = 'reviewingstory';
|
||||
$stories = $this->product->getStories($productID, $branchID, $browseType, $queryID, $moduleID, $storyType, $sort, $pager);
|
||||
|
||||
/* Display status of branch. */
|
||||
|
||||
@@ -20,22 +20,26 @@ body {margin-bottom: 25px;}
|
||||
.assignedTo{border-radius: 4px !important;}
|
||||
#productStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
|
||||
</style>
|
||||
<?php js::set('browseType', $browseType);?>
|
||||
<?php js::set('productID', $productID);?>
|
||||
<?php js::set('projectID', $projectID);?>
|
||||
<?php js::set('branch', $branch);?>
|
||||
<?php js::set('rawModule', $this->app->rawModule);?>
|
||||
<?php js::set('productType', $this->app->tab == 'product' ? $product->type : '');?>
|
||||
<?php
|
||||
$unfoldStories = isset($config->product->browse->unfoldStories) ? json_decode($config->product->browse->unfoldStories, true) : array();
|
||||
$unfoldStories = zget($unfoldStories, $productID, array());
|
||||
$lang->story->createCommon = $storyType == 'story' ? $lang->story->createStory : $lang->story->createRequirement;
|
||||
$unfoldStories = isset($config->product->browse->unfoldStories) ? json_decode($config->product->browse->unfoldStories, true) : array();
|
||||
$unfoldStories = zget($unfoldStories, $productID, array());
|
||||
$isProjectStory = $this->app->rawModule == 'projectstory';
|
||||
$projectHasProduct = $isProjectStory && !empty($project->hasProduct);
|
||||
$projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
js::set('unfoldStories', $unfoldStories);
|
||||
js::set('unfoldAll', $lang->execution->treeLevel['all']);
|
||||
js::set('foldAll', $lang->execution->treeLevel['root']);
|
||||
js::set('storyType', $storyType);
|
||||
$lang->story->createCommon = $storyType == 'story' ? $lang->story->createStory : $lang->story->createRequirement;
|
||||
$isProjectStory = $this->app->rawModule == 'projectstory';
|
||||
$projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
js::set('browseType', $browseType);
|
||||
js::set('productID', $productID);
|
||||
js::set('projectID', $projectID);
|
||||
js::set('branch', $branch);
|
||||
js::set('rawModule', $this->app->rawModule);
|
||||
js::set('productType', $this->app->tab == 'product' ? $product->type : '');
|
||||
js::set('projectHasProduct', $projectHasProduct);
|
||||
js::set('URAndSR', $this->config->URAndSR);
|
||||
js::set('vision', $this->config->vision);
|
||||
?>
|
||||
<style>
|
||||
.btn-group .icon-close:before {font-size: 5px; vertical-align: 25%;}
|
||||
@@ -200,7 +204,7 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $storyType == 'story' ? $lang->story->noStory : $lang->story->noRequirement;?></span>
|
||||
<?php if(common::canModify('product', $product) and common::hasPriv('story', 'create')):?>
|
||||
<?php echo html::a($this->createLink('story', 'create', "productID={$productID}&branch={$branch}&moduleID={$moduleID}&storyID=0&projectID=$projectID&bugID=0&planID=0&todoID=0&extra=&type=$storyType"), "<i class='icon icon-plus'></i> " . $lang->story->createCommon, '', "class='btn btn-info' data-app='$from'");?>
|
||||
<?php echo html::a($this->createLink('story', 'create', "productID={$productID}&branch={$branch}&moduleID={$moduleID}&storyID=0&projectID=$projectID&bugID=0&planID=0&todoID=0&extra=&type=$storyType"), "<i class='icon icon-plus'></i> " . $lang->story->create, '', "class='btn btn-info' data-app='$from'");?>
|
||||
<?php endif;?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
<?php
|
||||
$config->project->list->exportFields = 'id,code,name,status,budget,PM,desc';
|
||||
$config->project->list->exportFields = 'id,code,name,status,PM,desc';
|
||||
$config->project->datatable->defaultField = array('id', 'name', 'status', 'PM', 'begin', 'end', 'progress', 'actions');
|
||||
unset($config->project->datatable->fieldList['budget']);
|
||||
|
||||
@@ -96,7 +96,7 @@ class helper extends baseHelper
|
||||
}
|
||||
else
|
||||
{
|
||||
if($feature == 'product' or $feature == 'scrum' or $feature == 'waterfall') return strpos(",$config->disabledFeatures,", ",{$feature},") === false;
|
||||
if($feature == 'scrum' or $feature == 'waterfall') return strpos(",$config->disabledFeatures,", ",{$feature},") === false;
|
||||
|
||||
$hasFeature = false;
|
||||
$canConfigFeature = false;
|
||||
@@ -107,7 +107,14 @@ class helper extends baseHelper
|
||||
if($feature == $group or $feature == $module)
|
||||
{
|
||||
$canConfigFeature = true;
|
||||
if(helper::hasFeature("{$group}_{$module}")) $hasFeature = true;
|
||||
if($group == 'scrum' or $group == 'waterfall')
|
||||
{
|
||||
if(helper::hasFeature("{$group}") and helper::hasFeature("{$group}_{$module}")) $hasFeature = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(helper::hasFeature("{$group}_{$module}")) $hasFeature = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ class router extends baseRouter
|
||||
|
||||
$hourKey = $planKey = $URSR = $URAndSR = 0;
|
||||
|
||||
$mode = 'new';
|
||||
$mode = 'ALM';
|
||||
$score = '0';
|
||||
$projectKey = ITERATION_KEY;
|
||||
$disabledFeatures = '';
|
||||
@@ -200,7 +200,7 @@ class router extends baseRouter
|
||||
}
|
||||
|
||||
/* Lite Version is compatible with classic modes */
|
||||
if($config->vision == 'lite') $mode = 'new';
|
||||
if($config->vision == 'lite') $mode = 'ALM';
|
||||
|
||||
/* Record system mode. */
|
||||
$config->systemMode = $mode;
|
||||
|
||||
@@ -223,7 +223,7 @@ class zfile
|
||||
*
|
||||
* @param string $patern
|
||||
* @access public
|
||||
* @return avoid
|
||||
* @return void
|
||||
*/
|
||||
public function batchRemoveFile($patern)
|
||||
{
|
||||
|
||||
@@ -224,7 +224,7 @@ $lang->action->desc->reopen = '$date, 由 <strong>$actor</strong>
|
||||
$lang->action->desc->merged = '$date, 由 <strong>$actor</strong> 合并。' . "\n";
|
||||
$lang->action->desc->submitreview = '$date, 由 <strong>$actor</strong> 提交评审。' . "\n";
|
||||
$lang->action->desc->ganttmove = '$date, 由 <strong>$actor</strong> 排序。' . "\n";
|
||||
$lang->action->desc->switchtolight = '$date, 由 <strong>'. $lang->admin->system .'</strong> 从全生命周期管理模式切换为轻量管理模式。' . "\n";
|
||||
$lang->action->desc->switchtolight = '$date, 由于 <strong>'. $lang->admin->system .'</strong> 从全生命周期管理模式切换为轻量管理模式,项目访问控制由项目集内公开调整为私有。' . "\n";
|
||||
$lang->action->desc->unlinkproduct = '$date, 系统判断由于迭代所属项目与$extra取消关联,同步将迭代与$extra取消关联。' . "\n";
|
||||
|
||||
/* 用来描述和父子任务相关的操作历史记录。*/
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
<?php
|
||||
$config->url = new stdclass();
|
||||
$config->url->community = 'https://www.zentao.net';
|
||||
$config->url->ask = 'https://www.zentao.net/ask-browse.html';
|
||||
$config->url->document = 'https://www.zentao.net/help-book-zentaopmshelp.html';
|
||||
$config->url->feedback = 'https://www.zentao.net/forum-board-1074.html';
|
||||
$config->url->faq = 'https://www.zentao.net/ask-faq.html';
|
||||
$config->url->extension = 'https://www.zentao.net/extension-browse.html';
|
||||
$config->url->donation = 'https://www.zentao.net/help-donation.html';
|
||||
$config->url->service = 'https://www.cnezsoft.com/article-browse-1078.html';
|
||||
|
||||
$config->admin->apiRoot = 'https://www.zentao.net';
|
||||
|
||||
$config->admin->log = new stdclass();
|
||||
|
||||
@@ -337,11 +337,12 @@ class backup extends control
|
||||
{
|
||||
$this->app->loadLang('extension');
|
||||
|
||||
$search = dirname($this->app->getBasePath()) . DS;
|
||||
$search = $this->app->getBasePath();
|
||||
$pos = strpos($statusFile, $search);
|
||||
if($pos !== false) $statusFile = substr_replace($statusFile, '', $pos, strlen($search));
|
||||
$okFile = $statusFile;
|
||||
if($pos !== false) $okFile = substr_replace($statusFile, '', $pos, strlen($search));
|
||||
|
||||
$this->view->error = sprintf($this->lang->extension->noticeOkFile, $statusFile, $statusFile);
|
||||
$this->view->error = sprintf($this->lang->extension->noticeOkFile, $okFile, $statusFile);
|
||||
return print($this->display());
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
{
|
||||
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.text + '">' + plan.text + '</div>');
|
||||
$plan.append('<div class="strong" title="' + plan.name + '">' + plan.text + '</div>');
|
||||
$plans.append($plan);
|
||||
|
||||
var $bar = $('<div class="gantt-bar"></div>');
|
||||
|
||||
+19
-5
@@ -1243,8 +1243,12 @@ class bug extends control
|
||||
$branchProduct = $product->type == 'normal' ? false : true;
|
||||
|
||||
/* Set plans. */
|
||||
$plans = $this->loadModel('productplan')->getPairs($productID, $branch, '', true);
|
||||
$plans = array('' => '', 'ditto' => $this->lang->bug->ditto) + $plans;
|
||||
foreach($bugs as $bug)
|
||||
{
|
||||
$plans = $this->loadModel('productplan')->getPairs($productID, $bug->branch, '', true);
|
||||
$plans = array('' => '', 'ditto' => $this->lang->bug->ditto) + $plans;
|
||||
$bug->plans = $plans;
|
||||
}
|
||||
|
||||
/* Set branches and modules. */
|
||||
$branches = 0;
|
||||
@@ -2044,7 +2048,11 @@ class bug extends control
|
||||
if(!$project->hasProduct)
|
||||
{
|
||||
unset($this->config->bug->search['fields']['product']);
|
||||
if($project->model != 'scrum') unset($this->config->bug->search['fields']['plan']);
|
||||
if(!$project->multiple)
|
||||
{
|
||||
unset($this->config->bug->search['fields']['execution']);
|
||||
unset($this->config->bug->search['fields']['plan']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2353,6 +2361,8 @@ class bug extends control
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -2425,6 +2435,12 @@ class bug extends control
|
||||
$products = array();
|
||||
if(!empty($extra)) $products = $this->product->getProducts($extra, 'all', 'program desc, line desc, ');
|
||||
|
||||
if($this->config->systemMode == 'ALM')
|
||||
{
|
||||
$this->view->programs = $this->loadModel('program')->getPairs(true);
|
||||
$this->view->lines = $this->product->getLinePairs();
|
||||
}
|
||||
|
||||
$this->view->link = $this->product->getProductLink($module, $method, $extra);
|
||||
$this->view->productID = $productID;
|
||||
$this->view->module = $module;
|
||||
@@ -2432,8 +2448,6 @@ class bug extends control
|
||||
$this->view->extra = $extra;
|
||||
$this->view->products = $products;
|
||||
$this->view->projectID = $this->session->project;
|
||||
$this->view->programs = $this->loadModel('program')->getPairs(true);
|
||||
$this->view->lines = $this->product->getLinePairs();
|
||||
$this->display();
|
||||
}
|
||||
|
||||
|
||||
+15
-4
@@ -587,13 +587,13 @@ function loadProjectBuilds(projectID)
|
||||
function loadExecutionBuilds(executionID, num)
|
||||
{
|
||||
if(typeof(num) == 'undefined') num = '';
|
||||
var branch = $('#branch' + num).val();
|
||||
|
||||
if(typeof(branch) == 'undefined') var branch = 0;
|
||||
|
||||
var branch = $('#branch' + num).val();
|
||||
var oldOpenedBuild = $('#openedBuild' + num).val() ? $('#openedBuild' + num).val() : 0;
|
||||
var productID = $('#product' + num).val();
|
||||
|
||||
if(typeof(branch) == 'undefined') var branch = 0;
|
||||
if(typeof(productID) == 'undefined') var productID = 0;
|
||||
|
||||
if(page == 'create')
|
||||
{
|
||||
link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + "&branch=" + branch + "&index=0&needCreate=true");
|
||||
@@ -882,9 +882,20 @@ function setBranchRelated(branchID, productID, num)
|
||||
{
|
||||
planID = $('#plans' + num).val();
|
||||
planLink = createLink('product', 'ajaxGetPlans', 'productID=' + productID + '&branch=' + branchID + '&planID=' + planID + '&fieldID=' + num + '&needCreate=false&expired=¶m=skipParent');
|
||||
$.ajaxSettings.async = false;
|
||||
$('#plans' + num).parent('td').load(planLink, function()
|
||||
{
|
||||
$('#plans' + num).chosen();
|
||||
var firstBugID = $('.table-form tbody').first('tr').find('input[id^=bugIDList]').val();
|
||||
if(num == firstBugID)
|
||||
{
|
||||
$('#plans' + firstBugID).find('option').each(function()
|
||||
{
|
||||
if($(this).val() == 'ditto') $(this).remove();
|
||||
$('#plans' + firstBugID).trigger('chosen:updated');
|
||||
});
|
||||
}
|
||||
});
|
||||
$.ajaxSettings.async = true;
|
||||
}
|
||||
}
|
||||
|
||||
+53
-42
@@ -1972,24 +1972,17 @@ class bugModel extends model
|
||||
/**
|
||||
* Get product left bugs.
|
||||
*
|
||||
* @param int $build
|
||||
* @param int $productID
|
||||
* @param int $branch
|
||||
* @param string $linkedBugs
|
||||
* @param object $pager
|
||||
* @param int|string $buildIdList
|
||||
* @param int $productID
|
||||
* @param int $branch
|
||||
* @param string $linkedBugs
|
||||
* @param object $pager
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getProductLeftBugs($build, $productID, $branch = '', $linkedBugs = '', $pager = null)
|
||||
public function getProductLeftBugs($buildIdList, $productID, $branch = '', $linkedBugs = '', $pager = null)
|
||||
{
|
||||
$builds = $this->dao->select('*')->from(TABLE_BUILD)->where('id')->in($build)->fetchAll('id');
|
||||
|
||||
$executionIdList = array();
|
||||
foreach($builds as $build)
|
||||
{
|
||||
if(empty($build->execution)) continue;
|
||||
$executionIdList[$build->execution] = $build->execution;
|
||||
}
|
||||
$executionIdList = $this->getLinkedExecutionByIdList($buildIdList);
|
||||
if(empty($executionIdList)) return array();
|
||||
|
||||
$executions = $this->dao->select('*')->from(TABLE_EXECUTION)->where('id')->in($executionIdList)->fetchAll();
|
||||
@@ -2088,28 +2081,26 @@ class bugModel extends model
|
||||
/**
|
||||
* Get bugs according to buildID and productID.
|
||||
*
|
||||
* @param int $buildID
|
||||
* @param int $productID
|
||||
* @param string $branch
|
||||
* @param string $linkedBugs
|
||||
* @param object $pager
|
||||
* @param int|string $buildIdList
|
||||
* @param int $productID
|
||||
* @param string $branch
|
||||
* @param string $linkedBugs
|
||||
* @param object $pager
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getReleaseBugs($buildID, $productID, $branch = 0, $linkedBugs = '', $pager = null)
|
||||
public function getReleaseBugs($buildIdList, $productID, $branch = 0, $linkedBugs = '', $pager = null)
|
||||
{
|
||||
$executions = $this->dao->select('t1.id,t1.begin')->from(TABLE_EXECUTION)->alias('t1')
|
||||
->leftJoin(TABLE_BUILD)->alias('t2')->on('t1.id = t2.execution')
|
||||
->where('t2.id')->in($buildID)
|
||||
->fetchAll('id');
|
||||
if(empty($executions)) return array();
|
||||
$executionIdList = $this->getLinkedExecutionByIdList($buildIdList);
|
||||
if(empty($executionIdList)) return array();
|
||||
|
||||
$condition = 'execution NOT ' . helper::dbIN(array_keys($executions));
|
||||
$minBegin = '';
|
||||
$executions = $this->dao->select('id,type,begin')->from(TABLE_EXECUTION)->where('id')->in($executionIdList)->fetchAll('id');
|
||||
$condition = 'execution NOT ' . helper::dbIN($executionIdList);
|
||||
$minBegin = '';
|
||||
foreach($executions as $execution)
|
||||
{
|
||||
if(empty($minBegin) or $minBegin > $execution->begin) $minBegin = $execution->begin;
|
||||
$condition .= " OR (execution = '{$execution->id}' AND openedDate < '{$execution->begin}')";
|
||||
$condition .= " OR (`execution` = '{$execution->id}' AND openedDate < '{$execution->begin}')";
|
||||
}
|
||||
|
||||
$bugs = $this->dao->select('*')->from(TABLE_BUG)
|
||||
@@ -2122,10 +2113,42 @@ class bugModel extends model
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy('openedDate ASC')
|
||||
->page($pager)
|
||||
->fetchAll();
|
||||
->fetchAll('id');
|
||||
return $bugs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get linked execution by build id list.
|
||||
*
|
||||
* @param string $buildIdList
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getLinkedExecutionByIdList($buildIdList)
|
||||
{
|
||||
$builds = $this->dao->select('id,execution')->from(TABLE_BUILD)->where('id')->in($buildIdList)->fetchAll('id');
|
||||
|
||||
$executionIdList = array();
|
||||
$linkedBuildIdList = array();
|
||||
foreach($builds as $build)
|
||||
{
|
||||
if($build->builds) $linkedBuildIdList = array_merge($linkedBuildIdList, explode(',', $build->builds));
|
||||
|
||||
if(empty($build->execution)) continue;
|
||||
$executionIdList[$build->execution] = $build->execution;
|
||||
}
|
||||
if($linkedBuildIdList)
|
||||
{
|
||||
$linkedBuilds = $this->dao->select('*')->from(TABLE_BUILD)->where('id')->in(array_unique($linkedBuildIdList))->fetchAll('id');
|
||||
foreach($linkedBuilds as $build)
|
||||
{
|
||||
if(empty($build->execution)) continue;
|
||||
$executionIdList[$build->execution] = $build->execution;
|
||||
}
|
||||
}
|
||||
return $executionIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bugs of a story.
|
||||
*
|
||||
@@ -3467,19 +3490,7 @@ class bugModel extends model
|
||||
echo helper::isZeroDate($bug->openedDate) ? '' : substr($bug->openedDate, 5, 11);
|
||||
break;
|
||||
case 'openedBuild':
|
||||
$builds = array_flip($builds);
|
||||
foreach(explode(',', $bug->openedBuild) as $build)
|
||||
{
|
||||
$buildID = zget($builds, $build, '');
|
||||
if($buildID == 'trunk')
|
||||
{
|
||||
echo $build . ' ';
|
||||
}
|
||||
elseif($buildID and common::hasPriv('build', 'view'))
|
||||
{
|
||||
echo html::a(helper::createLink('build', 'view', "buildID=$buildID"), $build, '', "title='$bug->openedBuild'") . ' ';
|
||||
}
|
||||
}
|
||||
echo $bug->openedBuild;
|
||||
break;
|
||||
case 'assignedTo':
|
||||
$this->printAssignedHtml($bug, $users);
|
||||
|
||||
@@ -22,8 +22,8 @@ $productsHtml = count($products) > 1 ? html::a($linkHtml, $this->lang->bug->al
|
||||
foreach($products as $product)
|
||||
{
|
||||
$selected = $product->id == $productID ? 'selected' : '';
|
||||
$productName = $product->program ? zget($programs, $product->program, '') . '/' : '';
|
||||
$productName .= $product->line ? zget($lines, $product->line, '') . '/' . $product->name : $product->name;
|
||||
$productName = ($product->program and $this->config->systemMode == 'ALM') ? zget($programs, $product->program, '') . '/' : '';
|
||||
$productName .= ($this->config->systemMode == 'ALM' and $product->line) ? zget($lines, $product->line, '') . '/' . $product->name : $product->name;
|
||||
$objectID = ($product->type != 'platform' && $module == 'branch' && $method == 'manage') ? $productID : $product->id;
|
||||
$linkHtml = $this->product->setParamsForLink($module, $link, $projectID, $product->id);
|
||||
$productsHtml .= html::a($linkHtml, $productName, '', "class='text-primary $selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='{$this->app->tab}'");
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
</td>
|
||||
<?php endif;?>
|
||||
<td><?php echo html::select("modules[$bugID]", isset($modules[$bug->product][$bug->branch]) ? $modules[$bug->product][$bug->branch] : array(0 => '/'), $bug->module, "class='form-control picker-select' data-drop-width='auto'");?></td>
|
||||
<td class='<?php echo zget($visibleFields, 'productplan', ' hidden')?>' style='overflow:visible'><?php echo html::select("plans[$bugID]", $plans, $bug->plan, "class='form-control picker-select' data-drop-width='auto'");?></td>
|
||||
<td class='<?php echo zget($visibleFields, 'productplan', ' hidden')?>' style='overflow:visible'><?php echo html::select("plans[$bugID]", $bug->plans, $bug->plan, "class='form-control picker-select' data-drop-width='auto'");?></td>
|
||||
<?php
|
||||
$assignedToList = array();
|
||||
if($app->tab == 'project' or $app->tab == 'execution')
|
||||
|
||||
+16
-19
@@ -54,7 +54,7 @@ class build extends control
|
||||
|
||||
if(defined('TUTORIAL')) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true)); // Fix bug #21095.
|
||||
|
||||
$buildID = $this->build->create($executionID, $projectID);
|
||||
$buildID = $this->build->create();
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
$this->loadModel('action')->create('build', $buildID, 'opened');
|
||||
|
||||
@@ -72,6 +72,8 @@ class build extends control
|
||||
if($this->app->tab == 'project')
|
||||
{
|
||||
$this->project->setMenu($projectID);
|
||||
$executions = $this->execution->getPairs($projectID, 'all', 'stagefilter');
|
||||
$executionID = empty($executionID) ? key($executions) : $executionID;
|
||||
$productGroups = $this->product->getProducts($projectID);
|
||||
$branchGroups = $this->project->getBranchesByProject($projectID);
|
||||
$this->session->set('project', $projectID);
|
||||
@@ -79,6 +81,7 @@ class build extends control
|
||||
elseif($this->app->tab == 'execution')
|
||||
{
|
||||
$execution = $this->execution->getByID($executionID);
|
||||
$executions = $this->execution->getPairs($execution->project);
|
||||
$projectID = $execution->project;
|
||||
$productGroups = $this->product->getProducts($executionID);
|
||||
$branchGroups = $this->project->getBranchesByProject($executionID);
|
||||
@@ -89,6 +92,7 @@ class build extends control
|
||||
{
|
||||
$execution = $this->execution->getByID($executionID);
|
||||
$projectID = $execution ? $execution->project : 0;
|
||||
$executions = $this->execution->getPairs($projectID);
|
||||
$productGroups = $this->product->getProducts($executionID);
|
||||
$branchGroups = $this->project->getBranchesByProject($executionID);
|
||||
}
|
||||
@@ -119,6 +123,7 @@ class build extends control
|
||||
$this->view->executionID = $executionID;
|
||||
$this->view->products = $products;
|
||||
$this->view->projectID = $projectID;
|
||||
$this->view->executions = $executions;
|
||||
$this->view->lastBuild = $this->build->getLast($executionID, $projectID);
|
||||
$this->view->productGroups = $productGroups;
|
||||
$this->view->users = $this->user->getPairs('nodeleted|noclosed');
|
||||
@@ -255,7 +260,7 @@ class build extends control
|
||||
|
||||
$bugPager = new pager($type == 'bug' ? $recTotal : 0, $recPerPage, $type == 'bug' ? $pageID : 1);
|
||||
$bugs = $this->dao->select('*')->from(TABLE_BUG)
|
||||
->where('id')->in($build->bugs)
|
||||
->where('id')->in($build->allBugs)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($type == 'bug')->orderBy($sort)->fi()
|
||||
->page($bugPager)
|
||||
@@ -264,7 +269,7 @@ class build extends control
|
||||
/* Get stories and stages. */
|
||||
$storyPager = new pager($type == 'story' ? $recTotal : 0, $recPerPage, $type == 'story' ? $pageID : 1);
|
||||
$stories = $this->dao->select("*, IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder")->from(TABLE_STORY)
|
||||
->where('id')->in($build->stories)
|
||||
->where('id')->in($build->allStories)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($type == 'story')->orderBy($sort)->fi()
|
||||
->page($storyPager)
|
||||
@@ -277,10 +282,14 @@ class build extends control
|
||||
if($this->app->tab == 'project')
|
||||
{
|
||||
$this->loadModel('project')->setMenu($build->project);
|
||||
$objectType = 'project';
|
||||
$objectID = $build->project;
|
||||
}
|
||||
elseif($this->app->tab == 'execution')
|
||||
{
|
||||
$this->loadModel('execution')->setMenu($build->execution);
|
||||
$objectType = 'execution';
|
||||
$objectID = $build->execution;
|
||||
}
|
||||
|
||||
$executions = $this->loadModel('execution')->getPairs($this->session->project, 'all', 'empty');
|
||||
@@ -297,18 +306,6 @@ class build extends control
|
||||
|
||||
$this->executeHooks($buildID);
|
||||
|
||||
if($this->app->tab == 'execution')
|
||||
{
|
||||
$objectType = 'execution';
|
||||
$objectID = $build->execution;
|
||||
}
|
||||
else
|
||||
{
|
||||
$objectType = 'project';
|
||||
$objectID = $build->project;
|
||||
}
|
||||
|
||||
|
||||
/* Assign. */
|
||||
$this->view->canBeChanged = common::canBeChanged('build', $build); // Determines whether an object is editable.
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
@@ -611,11 +608,11 @@ class build extends control
|
||||
$executionID = $build->execution ? $build->execution : $build->project;
|
||||
if($browseType == 'bySearch')
|
||||
{
|
||||
$allStories = $this->story->getBySearch($build->product, $build->branch, $queryID, 'id', $executionID, 'story', $build->stories, $pager);
|
||||
$allStories = $this->story->getBySearch($build->product, $build->branch, $queryID, 'id', $executionID, 'story', $build->allStories, $pager);
|
||||
}
|
||||
else
|
||||
{
|
||||
$allStories = $this->story->getExecutionStories($executionID, $build->product, 0, 't1.`order`_desc', 'byBranch', $build->branch, 'story', $build->stories, $pager);
|
||||
$allStories = $this->story->getExecutionStories($executionID, $build->product, 0, 't1.`order`_desc', 'byBranch', $build->branch, 'story', $build->allStories, $pager);
|
||||
}
|
||||
|
||||
$this->view->allStories = $allStories;
|
||||
@@ -735,11 +732,11 @@ class build extends control
|
||||
$executionID = $build->execution ? $build->execution : $build->project;
|
||||
if($browseType == 'bySearch')
|
||||
{
|
||||
$allBugs = $this->bug->getBySearch($build->product, $build->branch, $queryID, 'id_desc', $build->bugs, $pager, $build->project);
|
||||
$allBugs = $this->bug->getBySearch($build->product, $build->branch, $queryID, 'id_desc', $build->allBugs, $pager, $build->project);
|
||||
}
|
||||
else
|
||||
{
|
||||
$allBugs = $this->bug->getExecutionBugs($executionID, 0, 'all', $buildID, 'noclosed', 0, 'status_desc,id_desc', $build->bugs, $pager);
|
||||
$allBugs = $this->bug->getExecutionBugs($executionID, 0, 'all', $buildID, 'noclosed', 0, 'status_desc,id_desc', $build->allBugs, $pager);
|
||||
}
|
||||
|
||||
$this->view->allBugs = $allBugs;
|
||||
|
||||
@@ -8,12 +8,62 @@ $().ready(function()
|
||||
$(document).on('change', '#product, #branch', function()
|
||||
{
|
||||
var productID = $('#product').val();
|
||||
var branch = $('#branch').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,noproject&extra=multiple'), function(data)
|
||||
{
|
||||
if(data) $('#buildBox').html(data);
|
||||
$('#builds').chosen();
|
||||
});
|
||||
});
|
||||
|
||||
$('input[name=type]').change(function()
|
||||
{
|
||||
if($(this).val() == 'execution')
|
||||
{
|
||||
$('#execution').closest('tr').show();
|
||||
$('#buildBox').closest('tr').hide();
|
||||
loadProducts($('#execution').val());
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#execution').closest('tr').hide();
|
||||
$('#buildBox').closest('tr').show();
|
||||
loadProducts($('#project').val());
|
||||
}
|
||||
});
|
||||
$('#product').change();
|
||||
});
|
||||
|
||||
/**
|
||||
* Load products.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadProducts(executionID)
|
||||
{
|
||||
$('#product').remove();
|
||||
$('#product_chosen').remove();
|
||||
$('#branch').remove();
|
||||
$('#branch_chosen').remove();
|
||||
$('#noProduct').remove();
|
||||
$.get(createLink('product', 'ajaxGetProducts', 'executionID=' + executionID), function(data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
if(data.indexOf("required") != -1)
|
||||
{
|
||||
$('#productBox').addClass('required');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#productBox').removeClass('required');
|
||||
}
|
||||
|
||||
$('#productBox').append(data);
|
||||
$('#product').chosen();
|
||||
loadBranches($("#product").val());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ $lang->build->project = 'Project';
|
||||
$lang->build->branch = 'Platform/Branch';
|
||||
$lang->build->branchName = '%s';
|
||||
$lang->build->execution = $lang->executionCommon;
|
||||
$lang->build->type = 'Type';
|
||||
$lang->build->builds = 'Linked Builds';
|
||||
$lang->build->name = 'Name';
|
||||
$lang->build->date = 'Datum';
|
||||
@@ -73,3 +74,7 @@ $lang->build->action->buildopened = '$date, erstellt von <strong>$actor</strong>
|
||||
$lang->backhome = 'zurück';
|
||||
|
||||
$lang->build->featureBar['browse']['all'] = 'Build List';
|
||||
|
||||
$lang->build->typeList = array();
|
||||
$lang->build->typeList['execution'] = "{$lang->executionCommon}版本";
|
||||
$lang->build->typeList['project'] = '项目版本';
|
||||
|
||||
@@ -34,6 +34,7 @@ $lang->build->branch = 'Platform/Branch';
|
||||
$lang->build->branchName = '%s';
|
||||
$lang->build->execution = $lang->executionCommon;
|
||||
$lang->build->builds = 'Linked Builds';
|
||||
$lang->build->type = 'Type';
|
||||
$lang->build->name = 'Name';
|
||||
$lang->build->date = 'Date';
|
||||
$lang->build->builder = 'Builder';
|
||||
@@ -73,3 +74,7 @@ $lang->build->action->buildopened = '$date, created by <strong>$actor</strong>,
|
||||
$lang->backhome = 'back';
|
||||
|
||||
$lang->build->featureBar['browse']['all'] = 'Build List';
|
||||
|
||||
$lang->build->typeList = array();
|
||||
$lang->build->typeList['execution'] = "{$lang->executionCommon}版本";
|
||||
$lang->build->typeList['project'] = '项目版本';
|
||||
|
||||
@@ -33,6 +33,7 @@ $lang->build->project = 'Project';
|
||||
$lang->build->branch = 'Plateforme/Branche';
|
||||
$lang->build->branchName = '%s';
|
||||
$lang->build->execution = $lang->executionCommon;
|
||||
$lang->build->type = 'Type';
|
||||
$lang->build->builds = 'Linked Builds';
|
||||
$lang->build->name = 'Nom';
|
||||
$lang->build->date = 'Date';
|
||||
@@ -73,3 +74,7 @@ $lang->build->action->buildopened = '$date, Build <strong>$extra</strong> créé
|
||||
$lang->backhome = 'Retour';
|
||||
|
||||
$lang->build->featureBar['browse']['all'] = 'Build List';
|
||||
|
||||
$lang->build->typeList = array();
|
||||
$lang->build->typeList['execution'] = "{$lang->executionCommon}版本";
|
||||
$lang->build->typeList['project'] = '项目版本';
|
||||
|
||||
@@ -33,6 +33,7 @@ $lang->build->project = '所属项目';
|
||||
$lang->build->branch = '平台/分支';
|
||||
$lang->build->branchName = '所属%s';
|
||||
$lang->build->execution = '所属' . $lang->executionCommon;
|
||||
$lang->build->type = '版本类型';
|
||||
$lang->build->builds = '关联版本';
|
||||
$lang->build->name = '名称编号';
|
||||
$lang->build->date = '打包日期';
|
||||
@@ -71,3 +72,7 @@ $lang->build->action = new stdclass();
|
||||
$lang->build->action->buildopened = '$date, 由 <strong>$actor</strong> 创建版本 <strong>$extra</strong>。' . "\n";
|
||||
|
||||
$lang->backhome = '返回';
|
||||
|
||||
$lang->build->typeList = array();
|
||||
$lang->build->typeList['execution'] = "{$lang->executionCommon}版本";
|
||||
$lang->build->typeList['project'] = '项目版本';
|
||||
|
||||
+65
-51
@@ -31,6 +31,7 @@ class buildModel extends model
|
||||
->fetch();
|
||||
if(!$build) return false;
|
||||
|
||||
$build = $this->linkChildBuilds($build);
|
||||
$build = $this->loadModel('file')->replaceImgURL($build, 'desc');
|
||||
$build->files = $this->file->getByObject('build', $buildID);
|
||||
if($setImgSize) $build->desc = $this->file->setImgSize($build->desc);
|
||||
@@ -226,13 +227,13 @@ class buildModel extends model
|
||||
}
|
||||
|
||||
$branchs = strpos($params, 'separate') === false ? "0,$branch" : $branch;
|
||||
$allBuilds = $this->dao->select('t1.id, t1.name, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName, t5.type as productType')->from(TABLE_BUILD)->alias('t1')
|
||||
$allBuilds = $this->dao->select('t1.id, t1.name, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName, t5.type as productType')->from(TABLE_BUILD)->alias('t1')
|
||||
->beginIF($objectType === 'execution')->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')->fi()
|
||||
->beginIF($objectType === 'project')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')->fi()
|
||||
->leftJoin(TABLE_RELEASE)->alias('t3')->on("FIND_IN_SET(t1.id,t3.build)")
|
||||
->leftJoin(TABLE_BRANCH)->alias('t4')->on('t1.branch = t4.id')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t5')->on('t1.product = t5.id')
|
||||
->where(1)->eq(1)
|
||||
->where('1=1')
|
||||
->beginIF(strpos($params, 'hasDeleted') === false)->andWhere('t1.deleted')->eq(0)->fi()
|
||||
->beginIF(strpos($params, 'noproject') !== false)->andWhere('t1.execution')->ne(0)->fi()
|
||||
->beginIF($products)->andWhere('t1.product')->in($products)->fi()
|
||||
@@ -242,9 +243,10 @@ class buildModel extends model
|
||||
->orderBy('t1.date desc, t1.id desc')->fetchAll('id');
|
||||
|
||||
/* Set builds and filter done executions and terminate releases. */
|
||||
$builds = array();
|
||||
$builds = array();
|
||||
$buildIdList = array();
|
||||
$this->app->loadLang('branch');
|
||||
foreach($allBuilds as $key => $build)
|
||||
foreach($allBuilds as $id => $build)
|
||||
{
|
||||
if(empty($build->releaseID) and (strpos($params, 'nodone') !== false) and ($build->objectStatus === 'done')) continue;
|
||||
if((strpos($params, 'noterminate') !== false) and ($build->releaseStatus === 'terminate')) continue;
|
||||
@@ -252,32 +254,58 @@ class buildModel extends model
|
||||
if($build->deleted == 1) $build->name .= ' (' . $this->lang->build->deleted . ')';
|
||||
$branchName = $build->branchName ? $build->branchName : $this->lang->branch->main;
|
||||
|
||||
$builds[$key] = $build->name;
|
||||
if(strpos($params, 'withbranch') !== false and $build->productType != 'normal') $builds[$key] = $branchName . '/' . $builds[$key];
|
||||
$buildName = $build->name;
|
||||
if(strpos($params, 'withbranch') !== false and $build->productType != 'normal') $buildName = $branchName . '/' . $buildName;
|
||||
|
||||
$buildIdList[$id] = $id;
|
||||
$builds[$build->date][$id] = $buildName;
|
||||
}
|
||||
|
||||
if(!$builds) return $sysBuilds + $selectedBuilds;
|
||||
if(empty($builds)) return $sysBuilds + $selectedBuilds;
|
||||
|
||||
/* if the build has been released and replace is true, replace build name with release name. */
|
||||
if($replace)
|
||||
{
|
||||
$releases = $this->dao->select('build, name')->from(TABLE_RELEASE)
|
||||
->where('build')->in(array_keys($builds))
|
||||
->andWhere('product')->in($products)
|
||||
->beginIF($branch !== 'all')->andWhere('branch')->in("$branchs")->fi()
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchPairs();
|
||||
foreach($releases as $buildID => $releaseName)
|
||||
$releases = $this->dao->select('t1.id,t1.shadow,t1.product,t1.branch,t1.build,t1.name,t1.date,t3.name as branchName,t4.type as productType')->from(TABLE_RELEASE)->alias('t1')
|
||||
->leftJoin(TABLE_BUILD)->alias('t2')->on('FIND_IN_SET(t2.id, t1.build)')
|
||||
->leftJoin(TABLE_BRANCH)->alias('t3')->on('FIND_IN_SET(t3.id, t1.branch)')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t4')->on('t1.product=t4.id')
|
||||
->where('t2.id')->in($buildIdList)
|
||||
->andWhere('t1.product')->in($products)
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->andWhere('t1.shadow')->ne(0)
|
||||
->fetchAll('id');
|
||||
foreach($releases as $release)
|
||||
{
|
||||
$branchName = $allBuilds[$buildID]->branchName ? $allBuilds[$buildID]->branchName : $this->lang->branch->main;
|
||||
if($allBuilds[$buildID]->productType != 'normal')
|
||||
if($branch !== 'all')
|
||||
{
|
||||
$builds[$buildID] = (strpos($params, 'withbranch') !== false ? $branchName . '/' : '') . $releaseName;
|
||||
$inBranch = false;
|
||||
foreach(explode(',', trim($release->branch, ',')) as $branchID)
|
||||
{
|
||||
if($branchID === '') continue;
|
||||
if(strpos(",{$branchs},", ",{$branchID},") !== false) $inBranch = true;
|
||||
}
|
||||
if(!$inBranch) continue;
|
||||
}
|
||||
|
||||
$releaseName = $release->name;
|
||||
$branchName = $release->branchName ? $release->branchName : $this->lang->branch->main;
|
||||
if($release->productType != 'normal') $releaseName = (strpos($params, 'withbranch') !== false ? $branchName . '/' : '') . $releaseName;
|
||||
$builds[$release->date][$release->shadow] = $releaseName;
|
||||
foreach(explode(',', trim($release->build, ',')) as $buildID)
|
||||
{
|
||||
if(!isset($allBuilds[$buildID])) continue;
|
||||
$build = $allBuilds[$buildID];
|
||||
unset($builds[$build->date][$buildID]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sysBuilds + $builds + $selectedBuilds;
|
||||
krsort($builds);
|
||||
$buildPairs = array();
|
||||
foreach($builds as $date => $childBuilds) $buildPairs += $childBuilds;
|
||||
|
||||
return $sysBuilds + $buildPairs + $selectedBuilds;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,42 +330,31 @@ class buildModel extends model
|
||||
/**
|
||||
* Create a build
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function create($executionID = 0, $projectID = 0)
|
||||
public function create()
|
||||
{
|
||||
$build = new stdclass();
|
||||
$build->stories = '';
|
||||
$build->bugs = '';
|
||||
|
||||
if($projectID && !$executionID)
|
||||
{
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if(!$project->multiple) $executionID = $this->dao->select('id')->from(TABLE_EXECUTION)->where('project')->eq($projectID)->fetch('id');
|
||||
}
|
||||
else if($executionID && !$projectID)
|
||||
{
|
||||
$execution = $this->loadModel('execution')->getByID($executionID);
|
||||
$projectID = $execution->project;
|
||||
}
|
||||
|
||||
$build = fixer::input('post')
|
||||
->setDefault('project', $projectID)
|
||||
->setDefault('project', 0)
|
||||
->setDefault('execution', 0)
|
||||
->setDefault('product', 0)
|
||||
->setDefault('branch', 0)
|
||||
->setDefault('builds', '')
|
||||
->cleanInt('product,branch')
|
||||
->add('execution', $executionID)
|
||||
->add('createdBy', $this->app->user->account)
|
||||
->add('createdDate', helper::now())
|
||||
->stripTags($this->config->build->editor->create['id'], $this->config->allowedTags)
|
||||
->join('builds', ',')
|
||||
->remove('resolvedBy,allchecker,files,labels,uid')
|
||||
->remove('resolvedBy,allchecker,files,labels,type,uid')
|
||||
->get();
|
||||
|
||||
if($this->post->type == 'project') $build->execution = 0;
|
||||
|
||||
$build = $this->loadModel('file')->processImgURL($build, $this->config->build->editor->create['id'], $this->post->uid);
|
||||
$this->dao->insert(TABLE_BUILD)->data($build)
|
||||
->autoCheck()
|
||||
@@ -349,7 +366,6 @@ class buildModel extends model
|
||||
if(!dao::isError())
|
||||
{
|
||||
$buildID = $this->dao->lastInsertID();
|
||||
$this->linkChildBuilds($buildID, $build->builds);
|
||||
$this->file->updateObjectID($this->post->uid, $buildID, 'build');
|
||||
$this->file->saveUpload('build', $buildID);
|
||||
$this->loadModel('score')->create('build', 'create', $buildID);
|
||||
@@ -389,8 +405,6 @@ class buildModel extends model
|
||||
if(isset($build->branch) and $oldBuild->branch != $build->branch) $this->dao->update(TABLE_RELEASE)->set('branch')->eq($build->branch)->where('build')->eq($buildID)->exec();
|
||||
if(!dao::isError())
|
||||
{
|
||||
$addBuilds = array_diff(explode(',', $build->builds), explode(',', $oldBuild->builds));
|
||||
if($addBuilds) $this->linkChildBuilds($buildID, $addBuilds);
|
||||
$this->file->updateObjectID($this->post->uid, $buildID, 'build');
|
||||
return common::createChanges($oldBuild, $build);
|
||||
}
|
||||
@@ -569,28 +583,28 @@ class buildModel extends model
|
||||
/**
|
||||
* Bugs and stories associated with child builds.
|
||||
*
|
||||
* @param int $buildID
|
||||
* @param string $childBuildIDList
|
||||
* @param object $build
|
||||
* @access public
|
||||
* @return void
|
||||
* @return object
|
||||
*/
|
||||
public function linkChildBuilds($buildID, $childBuildIDList)
|
||||
public function linkChildBuilds($build)
|
||||
{
|
||||
$build = $this->dao->select('bugs, stories')->from(TABLE_BUILD)->where('id')->eq($buildID)->fetch();
|
||||
$childBuilds = $this->dao->select('bugs, stories')->from(TABLE_BUILD)->where('id')->in($childBuildIDList)->fetchAll();
|
||||
$build->allBugs = $build->bugs;
|
||||
$build->allStories = $build->stories;
|
||||
$childBuilds = $this->dao->select('bugs, stories')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchAll();
|
||||
|
||||
foreach($childBuilds as $childBuild)
|
||||
{
|
||||
if($childBuild->bugs) $build->bugs .= ",{$childBuild->bugs}";
|
||||
if($childBuild->stories) $build->stories .= ",{$childBuild->stories}";
|
||||
if($childBuild->bugs) $build->allBugs .= ",{$childBuild->bugs}";
|
||||
if($childBuild->stories) $build->allStories .= ",{$childBuild->stories}";
|
||||
}
|
||||
|
||||
$build->bugs = explode(',', $build->bugs);
|
||||
$build->bugs = join(',', array_unique(array_filter($build->bugs)));
|
||||
$build->stories = explode(',', $build->stories);
|
||||
$build->stories = join(',', array_unique(array_filter($build->stories)));
|
||||
$build->allBugs = explode(',', $build->allBugs);
|
||||
$build->allBugs = join(',', array_unique(array_filter($build->allBugs)));
|
||||
$build->allStories = explode(',', $build->allStories);
|
||||
$build->allStories = join(',', array_unique(array_filter($build->allStories)));
|
||||
|
||||
$this->dao->update(TABLE_BUILD)->data($build)->where('id')->eq($buildID)->exec();
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
</div>
|
||||
<form class='load-indicator main-form form-ajax' id='dataform' method='post' enctype='multipart/form-data'>
|
||||
<table class='table table-form'>
|
||||
<tr class="<?php echo ($app->tab == 'project' and !empty($multipleProject)) ? '' : 'hidden';?>">
|
||||
<th><?php echo $lang->build->type;?></th>
|
||||
<td><?php echo html::radio('type', $lang->build->typeList, 'execution');?></td>
|
||||
</tr>
|
||||
<tr class="<?php echo !empty($multipleProject) ? '' : 'hidden';?>">
|
||||
<th><?php echo $lang->executionCommon;?></th>
|
||||
<td><?php echo html::select('execution', $executions, $executionID, "onchange='loadProducts(this.value);' class='form-control chosen' required");?></td>
|
||||
</tr>
|
||||
<tr class="<?php echo $hidden;?>">
|
||||
<th><?php echo $lang->build->product;?></th>
|
||||
<?php if(!empty($products)):?>
|
||||
@@ -42,13 +50,11 @@
|
||||
<?php endif;?>
|
||||
<td></td>
|
||||
</tr>
|
||||
<?php if($app->tab == 'project' && !empty($multipleProject)):?>
|
||||
<tr>
|
||||
<tr class='hide'>
|
||||
<th><?php echo $lang->build->builds;?></th>
|
||||
<td id='buildBox'><?php echo html::select('builds[]', array(), '', "class='form-control chosen' multiple");?></td>
|
||||
<td><?php echo $lang->build->notice->autoRelation;?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->build->name;?></th>
|
||||
<td><?php echo html::input('name', '', "class='form-control' required");?></td>
|
||||
@@ -86,6 +92,7 @@
|
||||
<tr>
|
||||
<td colspan="3" class="text-center form-actions">
|
||||
<?php echo html::submitButton();?>
|
||||
<?php echo html::hidden('project', $projectID);?>
|
||||
<?php echo html::backButton();?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -95,10 +95,11 @@ tbody tr td:first-child input {display: none;}
|
||||
</thead>
|
||||
<tbody class='text-center'>
|
||||
<?php foreach($stories as $storyID => $story):?>
|
||||
<?php $unlinkClass = strpos(",$build->stories,", ",$story->id,") !== false ? '' : "disabled";?>
|
||||
<tr>
|
||||
<td class='c-id text-left'>
|
||||
<?php if($canBatchUnlink):?>
|
||||
<?php echo html::checkbox('unlinkStories', array($story->id => sprintf('%03d', $story->id)));?>
|
||||
<?php echo html::checkbox('unlinkStories', array($story->id => sprintf('%03d', $story->id)), '', $unlinkClass);?>
|
||||
<?php else:?>
|
||||
<?php printf('%03d', $story->id);?>
|
||||
<?php endif;?>
|
||||
@@ -138,7 +139,7 @@ tbody tr td:first-child input {display: none;}
|
||||
if($canBeChanged and common::hasPriv($module, 'unlinkStory'))
|
||||
{
|
||||
$unlinkURL = $this->createLink($module, 'unlinkStory', "buildID=$build->id&story=$story->id");
|
||||
echo html::a($unlinkURL, '<i class="icon-unlink"></i>', 'hiddenwin', "class='btn' title='{$lang->build->unlinkStory}'");
|
||||
echo html::a($unlinkURL, '<i class="icon-unlink"></i>', 'hiddenwin', "class='btn' title='{$lang->build->unlinkStory}' $unlinkClass");
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
@@ -194,11 +195,12 @@ tbody tr td:first-child input {display: none;}
|
||||
</thead>
|
||||
<tbody class='text-center'>
|
||||
<?php foreach($bugs as $bug):?>
|
||||
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bug->id", '', true);?>
|
||||
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bug->id", '', true);?>
|
||||
<?php $unlinkClass = strpos(",$build->bugs,", ",$bug->id,") !== false ? '' : "disabled";?>
|
||||
<tr>
|
||||
<td class='c-id text-left'>
|
||||
<?php if($canBatchUnlink):?>
|
||||
<?php echo html::checkbox('unlinkBugs', array($bug->id => sprintf('%03d', $bug->id)));?>
|
||||
<?php echo html::checkbox('unlinkBugs', array($bug->id => sprintf('%03d', $bug->id)), '', $unlinkClass);?>
|
||||
<?php else:?>
|
||||
<?php printf('%03d', $bug->id);?>
|
||||
<?php endif;?>
|
||||
@@ -219,7 +221,7 @@ tbody tr td:first-child input {display: none;}
|
||||
if($canBeChanged and common::hasPriv($module, 'unlinkBug'))
|
||||
{
|
||||
$unlinkURL = $this->createLink($module, 'unlinkBug', "buildID=$build->id&bug=$bug->id");
|
||||
echo html::a("###", '<i class="icon-unlink"></i>', '', "onclick='ajaxDelete(\"$unlinkURL\", \"bugList\", confirmUnlinkBug)' class='btn' title='{$lang->build->unlinkBug}'");
|
||||
echo html::a("###", '<i class="icon-unlink"></i>', '', (!$unlinkClass ? "onclick='ajaxDelete(\"$unlinkURL\", \"bugList\", confirmUnlinkBug)'" : '') . "class='btn' title='{$lang->build->unlinkBug}' $unlinkClass");
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
|
||||
@@ -266,7 +266,7 @@ $lang->waterfall->menu->design = array('link' => "{$lang->design->common}|de
|
||||
$lang->waterfall->menu->qa = array('link' => "{$lang->qa->common}|project|bug|projectID=%s", 'subModule' => 'testcase,testtask,bug,testreport', 'alias' => 'bug,testtask,testcase,testreport');
|
||||
$lang->waterfall->menu->doc = array('link' => "{$lang->doc->common}|doc|tableContents|type=project&objectID=%s");
|
||||
$lang->waterfall->menu->devops = array('link' => "{$lang->repo->common}|repo|browse|repoID=0&branchID=&objectID=%s", 'subModule' => 'repo');
|
||||
$lang->waterfall->menu->build = array('link' => "{$lang->build->common}|project|build|project=%s");
|
||||
$lang->waterfall->menu->build = array('link' => "{$lang->build->common}|project|build|project=%s", 'subModule' => 'projectbuild');
|
||||
$lang->waterfall->menu->release = array('link' => "{$lang->release->common}|projectrelease|browse|project=%s", 'subModule' => 'projectrelease');
|
||||
$lang->waterfall->menu->dynamic = array('link' => "$lang->dynamic|project|dynamic|project=%s");
|
||||
|
||||
@@ -343,7 +343,7 @@ $lang->execution->menu->view = array('link' => "$lang->view|execution|grouptas
|
||||
if($config->edition != 'open') $lang->execution->menu->view = array('link' => "$lang->view|execution|gantt|executionID=%s", 'alias' => 'grouptask,tree,taskeffort,gantt,calendar,relation,maintainrelation');
|
||||
|
||||
$lang->execution->menu->storyGroup = array('link' => "{$lang->common->story}|execution|story|executionID=%s",'class' => 'dropdown dropdown-hover', 'subModule' => 'story', 'alias' => 'batchcreate,storykanban');
|
||||
$lang->execution->menu->story = array('link' => "$lang->SRCommon|execution|story|executionID=%s", 'subModule' => 'story,execution', 'alias' => 'storykanban,linkstory');
|
||||
$lang->execution->menu->story = array('link' => "$lang->SRCommon|execution|story|executionID=%s", 'subModule' => 'story', 'alias' => 'storykanban,linkstory');
|
||||
$lang->execution->menu->qa = array('link' => "{$lang->qa->common}|execution|bug|executionID=%s", 'subModule' => 'bug,testcase,testtask,testreport', 'alias' => 'qa,bug,testcase,testtask,testreport');
|
||||
$lang->execution->menu->devops = array('link' => "{$lang->repo->common}|repo|browse|repoID=0&branchID=&objectID=%s", 'subModule' => 'repo');
|
||||
$lang->execution->menu->doc = array('link' => "{$lang->doc->common}|doc|tableContents|type=execution&objectID=%s", 'subModule' => 'doc');
|
||||
|
||||
@@ -106,6 +106,7 @@ class datatable extends control
|
||||
|
||||
if(!$project->multiple) unset($cols['execution']);
|
||||
if(!$project->hasProduct and $project->model != 'scrum') unset($cols['plan']);
|
||||
if(!$project->hasProduct) unset($cols['branch']);
|
||||
}
|
||||
|
||||
if($moduleName == 'execution' and $method == 'bug')
|
||||
@@ -113,12 +114,14 @@ class datatable extends control
|
||||
$execution = $this->loadModel('execution')->getByID($this->session->execution);
|
||||
$project = $this->loadModel('project')->getByID($execution->project);
|
||||
if(!$project->hasProduct and $project->model != 'scrum') unset($cols['plan']);
|
||||
if(!$project->hasProduct) unset($cols['branch']);
|
||||
}
|
||||
|
||||
if($moduleName == 'execution' and $method == 'story')
|
||||
{
|
||||
$execution = $this->loadModel('execution')->getByID($this->session->execution);
|
||||
if(!$execution->hasProduct and !$execution->multiple) unset($cols['plan']);
|
||||
if(!$execution->hasProduct) unset($cols['branch']);
|
||||
}
|
||||
|
||||
$this->view->cols = $cols;
|
||||
|
||||
@@ -115,6 +115,9 @@ class design extends control
|
||||
$pager = pager::init(0, $recPerPage, $pageID);
|
||||
$designs = $this->design->getList($projectID, $productID, $type, $queryID, $orderBy, $pager);
|
||||
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
$this->view->hiddenProduct = $project->hasProduct ? false : true;
|
||||
|
||||
$this->view->title = $this->lang->design->common . $this->lang->colon . $this->lang->design->browse;
|
||||
$this->view->position[] = $this->lang->design->browse;
|
||||
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
<?php $vars = "projectID=$projectID&productID=$productID&type=$type¶m=$param&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}";?>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-left w-60px"> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
|
||||
<th class="text-left"> <?php common::printOrderLink('name', $orderBy, $vars, $lang->design->name);?></th>
|
||||
<th class="text-left w-150px"> <?php common::printOrderLink('product', $orderBy, $vars, $lang->design->product);?></th>
|
||||
<th class="text-left w-60px"> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
|
||||
<th class="text-left"> <?php common::printOrderLink('name', $orderBy, $vars, $lang->design->name);?></th>
|
||||
<th class="text-left w-150px <?php echo $hiddenProduct ? 'hidden' : '';?>"><?php common::printOrderLink('product', $orderBy, $vars, $lang->design->product);?></th>
|
||||
<th class="text-left w-100px"> <?php common::printOrderLink('type', $orderBy, $vars, $lang->design->type);?></th>
|
||||
<th class="c-assignedTo w-120px"><?php common::printOrderLink('assignedTo', $orderBy, $vars, $lang->design->assignedTo);?></th>
|
||||
<th class="text-left w-120px"> <?php common::printOrderLink('createdBy', $orderBy, $vars, $lang->design->createdByAB);?></th>
|
||||
@@ -47,7 +47,7 @@
|
||||
<tr>
|
||||
<td calss="c-id"> <?php printf('%03d', $design->id);?></td>
|
||||
<td class="c-name" title="<?php echo $design->name;?>"><?php echo common::hasPriv('design', 'view') ? html::a($this->createLink('design', 'view', "id={$design->id}"), $design->name) : $design->name;?></td>
|
||||
<td class="c-product"> <?php echo zget($products, $design->product);?></td>
|
||||
<td class="c-product <?php echo $hiddenProduct ? 'hidden' : '';?>"><?php echo zget($products, $design->product);?></td>
|
||||
<td class="c-type"> <?php echo zget($lang->design->typeList, $design->type);?></td>
|
||||
<td class="c-assignedTo"> <?php echo $this->design->printAssignedHtml($design, $users);?></td>
|
||||
<td class="c-createdBy"> <?php echo zget($users, $design->createdBy);?></td>
|
||||
@@ -55,9 +55,9 @@
|
||||
<td class='c-actions text-center'>
|
||||
<?php
|
||||
$vars = "design={$design->id}";
|
||||
common::printIcon('design', 'edit', $vars, $design, 'list', 'alter');
|
||||
common::printIcon('design', 'viewCommit', $vars, $design, 'list', 'list-alt', '', 'iframe showinonlybody', true);
|
||||
common::printIcon('design', 'delete', $vars, $design, 'list', 'trash', 'hiddenwin');
|
||||
common::printIcon('design', 'edit', $vars, $design, 'list', 'alter');
|
||||
if(helper::hasFeature('devops')) common::printIcon('design', 'viewCommit', $vars, $design, 'list', 'list-alt', '', 'iframe showinonlybody', true);
|
||||
common::printIcon('design', 'delete', $vars, $design, 'list', 'trash', 'hiddenwin');
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -74,7 +74,9 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<div class='table-footer'>
|
||||
<?php if(!empty($revisions)):?>
|
||||
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
|
||||
<?php endif;?>
|
||||
<div class="table-actions btn-toolbar">
|
||||
<?php echo html::submitButton('', '', 'btn btn-primary')?>
|
||||
</div>
|
||||
|
||||
@@ -250,7 +250,7 @@ class execution extends control
|
||||
$this->view->moduleTree = $this->tree->getTaskTreeMenu($executionID, $productID, $startModuleID = 0, array('treeModel', 'createTaskLink'), $extra);
|
||||
$this->view->memberPairs = $memberPairs;
|
||||
$this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products));
|
||||
$this->view->setModule = true;
|
||||
$this->view->setModule = !$execution->multiple ? false : true;
|
||||
$this->view->canBeChanged = common::canModify('execution', $execution); // Determines whether an object is editable.
|
||||
$this->view->showBranch = $showBranch;
|
||||
$this->view->projectName = $this->loadModel('project')->getById($execution->project)->name . ' / ' . $execution->name;
|
||||
@@ -1608,7 +1608,8 @@ class execution extends control
|
||||
*/
|
||||
public function create($projectID = '', $executionID = 0, $copyExecutionID = '', $planID = 0, $confirm = 'no', $productID = 0, $extra = '')
|
||||
{
|
||||
if($this->app->tab == 'doc') unset($this->lang->doc->menu->execution['subMenu']);
|
||||
if($this->app->tab == 'doc') unset($this->lang->doc->menu->execution['subMenu']);
|
||||
if($this->app->tab == 'project') $this->project->setMenu($projectID);
|
||||
|
||||
$project = $this->project->getByID($projectID);
|
||||
if(!empty($project) and $project->model == 'kanban')
|
||||
@@ -2680,6 +2681,12 @@ class execution extends control
|
||||
$projects = $this->project->getPairsByProgram('', 'noclosed');
|
||||
$executions = $this->execution->getStatData(0, 'all', 0, 0, false, '', 'id_desc');
|
||||
|
||||
foreach($executions as $execution)
|
||||
{
|
||||
$execution->name = htmlspecialchars_decode($execution->name);
|
||||
$execution->team = htmlspecialchars_decode($execution->team);
|
||||
}
|
||||
|
||||
$teams = $this->dao->select('root,account')->from(TABLE_TEAM)
|
||||
->where('root')->in($this->app->user->view->sprints)
|
||||
->andWhere('type')->eq('execution')
|
||||
|
||||
@@ -42,3 +42,5 @@ canvas {height: 28px;}
|
||||
.table thead .c-estimate.text-right,
|
||||
.table thead .c-consumed.text-right,
|
||||
.table thead .c-left.text-right {padding-right: 8px;}
|
||||
#executionsForm td.c-name {padding-right: 5px;}
|
||||
#executionsForm td.c-name.delay {padding-right: 55px;}
|
||||
|
||||
@@ -12,6 +12,8 @@ $(function()
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
if($('#executionList thead th.c-name').width() < 260) $('#executionList thead th.c-name').width(260);
|
||||
|
||||
$('#executionTableList').on('sort.sortable', function(e, data)
|
||||
{
|
||||
var list = '';
|
||||
|
||||
@@ -565,6 +565,9 @@ class executionModel extends model
|
||||
if($oldExecution->type == 'stage' and $field == 'name') $this->lang->project->name = str_replace($this->lang->executionCommon, $this->lang->project->stage, $this->lang->project->name);
|
||||
}
|
||||
|
||||
$relationExecutionsID = $this->getRelatedExecutions($executionID);
|
||||
$relationExecutionsID = !empty($relationExecutionsID) ? implode(',', array_keys($relationExecutionsID)) : '';
|
||||
|
||||
/* Update data. */
|
||||
$this->lang->error->unique = $this->lang->error->repeat;
|
||||
$executionProject = isset($execution->project) ? $execution->project : '0';
|
||||
@@ -574,7 +577,7 @@ class executionModel extends model
|
||||
->checkIF($execution->begin != '', 'begin', 'date')
|
||||
->checkIF($execution->end != '', 'end', 'date')
|
||||
->checkIF($execution->end != '', 'end', 'ge', $execution->begin)
|
||||
->checkIF(!empty($execution->name), 'name', 'unique', "id != $executionID and type in ('sprint','stage', 'kanban') and `project` = $executionProject and `deleted` = '0'")
|
||||
->checkIF(!empty($execution->name), 'name', 'unique', "id in ('$relationExecutionsID') and type in ('sprint','stage', 'kanban') and `project` = $executionProject and `deleted` = '0'")
|
||||
->checkIF(!empty($execution->code), 'code', 'unique', "id != $executionID and type in ('sprint','stage', 'kanban') and `deleted` = '0'")
|
||||
->checkFlow()
|
||||
->where('id')->eq($executionID)
|
||||
@@ -4712,7 +4715,7 @@ class executionModel extends model
|
||||
echo "<span class='project-type-label label label-outline $spanClass'>{$this->lang->execution->typeList[$execution->type]}</span> ";
|
||||
if(empty($execution->children))
|
||||
{
|
||||
echo html::a(helper::createLink('execution', 'view', "executionID=$execution->id"), $execution->name, '', 'class="text-ellipsis"');
|
||||
echo html::a(helper::createLink('execution', 'view', "executionID=$execution->id"), $execution->name, '', "class='text-ellipsis' title='{$execution->name}'");
|
||||
if(!helper::isZeroDate($execution->end))
|
||||
{
|
||||
if($execution->status != 'closed')
|
||||
@@ -4742,7 +4745,7 @@ class executionModel extends model
|
||||
echo "<td class='hours text-right' title='{$execution->hours->totalLeft}{$this->lang->execution->workHour}'>" . $execution->hours->totalLeft . $this->lang->execution->workHourUnit . '</td>';
|
||||
echo '<td>' . html::ring($execution->hours->progress) . '</td>';
|
||||
echo "<td id='spark-{$execution->id}' class='sparkline text-left no-padding' values='$burns'></td>";
|
||||
echo '<td class="c-actions">';
|
||||
echo '<td class="c-actions text-center">';
|
||||
common::printIcon('execution', 'start', "executionID={$execution->id}", $execution, 'list', '', '', 'iframe', true);
|
||||
$class = !empty($execution->children) ? 'disabled' : '';
|
||||
common::printIcon('task', 'create', "executionID={$execution->id}", '', 'list', '', '', $class, false, "data-app='execution'");
|
||||
@@ -4944,6 +4947,7 @@ class executionModel extends model
|
||||
{
|
||||
$title = " title='{$execution->name}'";
|
||||
if(!empty($execution->children)) $class .= ' has-child';
|
||||
if(isset($execution->delay)) $class .= ' delay';
|
||||
}
|
||||
|
||||
if($id == 'teamCount')
|
||||
@@ -5091,7 +5095,7 @@ class executionModel extends model
|
||||
$this->config->execution->all->search['actionURL'] = $actionURL;
|
||||
|
||||
$projectPairs = array(0 => '');
|
||||
$projectPairs += $this->loadModel('project')->getPairsByProgram();
|
||||
$projectPairs += $this->loadModel('project')->getPairsByProgram('', 'all', false, 'order_asc', '', '', 'multiple');
|
||||
$this->config->execution->all->search['params']['project']['values'] = $projectPairs + array('all' => $this->lang->execution->allProject);
|
||||
|
||||
$this->loadModel('search')->setSearchParams($this->config->execution->all->search);
|
||||
@@ -5111,7 +5115,6 @@ class executionModel extends model
|
||||
$_POST = array();
|
||||
$_POST['project'] = $projectID;
|
||||
$_POST['name'] = $project->name;
|
||||
$_POST['code'] = $project->code;
|
||||
$_POST['begin'] = $project->begin;
|
||||
$_POST['end'] = $project->end;
|
||||
$_POST['status'] = 'wait';
|
||||
@@ -5125,6 +5128,7 @@ class executionModel extends model
|
||||
$_POST['RD'] = '';
|
||||
$_POST['multiple'] = '0';
|
||||
$_POST['hasProduct'] = $project->hasProduct;
|
||||
if($project->code) $_POST['code'] = $project->code;
|
||||
|
||||
$projectProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchAll();
|
||||
foreach($projectProducts as $projectProduct)
|
||||
|
||||
@@ -82,6 +82,7 @@ foreach($executions as $projectID => $projectExecutions)
|
||||
$isKanbanMethod = ((in_array($method, $config->execution->kanbanMethod) and $module == 'execution') or (strpos(',create,edit,', ",$method,") !== false and $module == 'build'));
|
||||
if(isset($execution->type) and $execution->type == 'kanban' and !$isKanbanMethod) $executionLink = $kanbanLink;
|
||||
if(isset($execution->type) and $execution->type != 'kanban' and strpos(',kanban,cfd,', ",$method,") !== false) $executionLink = $taskLink;
|
||||
if(isset($execution->type) and $execution->type == 'stage' and in_array($module, array('issue', 'risk', 'opportunity', 'pssp', 'auditplan', 'meeting'))) $executionLink = $taskLink;
|
||||
|
||||
if($execution->id == $executionID) $currentExecution = $execution;
|
||||
$selected = $execution->id == $executionID ? 'selected' : '';
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
foreach($setting as $value)
|
||||
{
|
||||
if(!$project->hasProduct and $project->model != 'scrum' and $value->id == 'plan') continue;
|
||||
if(!$project->hasProduct and $value->id == 'branch') continue;
|
||||
if($value->show)
|
||||
{
|
||||
if(common::checkNotCN() and $value->id == 'severity') $value->name = $lang->bug->severity;
|
||||
@@ -154,6 +155,7 @@
|
||||
<?php foreach($setting as $value)
|
||||
{
|
||||
if(!$project->hasProduct and $project->model != 'scrum' and $value->id == 'plan') continue;
|
||||
if(!$project->hasProduct and $value->id == 'branch') continue;
|
||||
$this->bug->printCell($value, $bug, $users, $builds, $branchOption, $modulePairs, $executions, $plans, $stories, $tasks, $useDatatable ? 'datatable' : 'table', $projectPairs);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
<?php if($isStage):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->stage->percent;?></th>
|
||||
<td>
|
||||
<td class='required'>
|
||||
<div class='input-group'>
|
||||
<?php echo html::input('percent', '', "class='form-control'");?>
|
||||
<span class='input-group-addon'>%</span>
|
||||
@@ -150,7 +150,7 @@
|
||||
<?php $i++;?>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
<?php if($division):?>
|
||||
<?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)'");?>
|
||||
|
||||
@@ -110,7 +110,8 @@
|
||||
<?php else:?>
|
||||
<div class="table-empty-tip">
|
||||
<?php $emptyTips = ($app->rawModule == 'execution' and !$project->hasProduct) ? 'projectNoStories' : 'whyNoStories';?>
|
||||
<p><span class="text-muted"><?php echo $lang->{$app->rawModule}->{$emptyTips};?></p>
|
||||
<?php $app->loadLang('projectstory');?>
|
||||
<p><span class="text-muted"><?php echo $project->multiple ? $lang->{$app->rawModule}->{$emptyTips} : $lang->projectstory->whyNoStories;?></p>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</form>
|
||||
|
||||
@@ -184,9 +184,6 @@
|
||||
</div>
|
||||
<div class="main-col">
|
||||
<div id='queryBox' data-module='executionStory' class='cell <?php if($type =='bysearch') echo 'show';?>'></div>
|
||||
<div class="table-header fixed-right">
|
||||
<nav class="btn-toolbar pull-right setting"></nav>
|
||||
</div>
|
||||
<?php if(empty($stories)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
@@ -217,6 +214,9 @@
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<div class="table-header fixed-right">
|
||||
<nav class="btn-toolbar pull-right setting"></nav>
|
||||
</div>
|
||||
<form class='main-table table-story skip-iframe-modal' method='post' id='executionStoryForm'>
|
||||
<?php
|
||||
$datatableId = $this->moduleName . ucfirst($this->methodName);
|
||||
@@ -243,7 +243,9 @@
|
||||
$canBatchChangeStage = common::hasPriv('story', 'batchChangeStage');
|
||||
$canBatchUnlink = common::hasPriv('execution', 'batchUnlinkStory');
|
||||
$canBatchToTask = common::hasPriv('story', 'batchToTask', $checkObject);
|
||||
$canBatchAction = ($canBeChanged and ($canBatchEdit or $canBatchClose or $canBatchChangeStage or $canBatchUnlink or $canBatchToTask));
|
||||
$canBatchAssignTo = common::hasPriv($storyType, 'batchAssignTo');
|
||||
|
||||
$canBatchAction = ($canBeChanged and ($canBatchEdit or $canBatchClose or $canBatchChangeStage or $canBatchUnlink or $canBatchToTask or $canBatchAssignTo));
|
||||
?>
|
||||
<?php if(!$useDatatable) echo '<div class="table-responsive">';?>
|
||||
<table class='table tablesorter has-sort-head<?php if($useDatatable) echo ' datatable';?>' id='storyList' data-fixed-left-width='<?php echo $widths['leftWidth']?>' data-fixed-right-width='<?php echo $widths['rightWidth']?>'>
|
||||
@@ -252,6 +254,7 @@
|
||||
<?php
|
||||
foreach($setting as $key => $value)
|
||||
{
|
||||
if(!$execution->hasProduct and $value->id == 'branch') continue;
|
||||
if(!$execution->hasProduct and !$execution->multiple and $value->id == 'plan') continue;
|
||||
if(!$execution->hasProduct and !$execution->multiple and $value->id == 'stage') continue;
|
||||
if(!$execution->hasProduct and !$execution->multiple and $storyType == 'requirement' and $value->id == 'taskCount') continue;
|
||||
@@ -272,6 +275,7 @@
|
||||
<tr id="story<?php echo $story->id;?>" data-id='<?php echo $story->id;?>' data-order='<?php echo $story->order ?>' data-estimate='<?php echo $story->estimate?>' data-cases='<?php echo zget($storyCases, $story->id, 0)?>'>
|
||||
<?php foreach($setting as $key => $value)
|
||||
{
|
||||
if(!$execution->hasProduct and $value->id == 'branch') continue;
|
||||
if(!$execution->hasProduct and !$execution->multiple and $value->id == 'plan') continue;
|
||||
if(!$execution->hasProduct and !$execution->multiple and $value->id == 'stage') continue;
|
||||
if(!$execution->hasProduct and !$execution->multiple and $storyType == 'requirement' and $value->id == 'taskCount') continue;
|
||||
@@ -288,6 +292,7 @@
|
||||
<tr class='table-children<?php echo $class;?> parent-<?php echo $story->id;?>' data-id='<?php echo $child->id?>' data-status='<?php echo $child->status?>' data-estimate='<?php echo $child->estimate?>' data-cases='<?php echo zget($storyCases, $story->id, 0);?>'>
|
||||
<?php foreach($setting as $key => $value)
|
||||
{
|
||||
if(!$execution->hasProduct and $value->id == 'branch') continue;
|
||||
if(!$execution->hasProduct and !$execution->multiple and $value->id == 'plan') continue;
|
||||
if(!$execution->hasProduct and !$execution->multiple and $value->id == 'stage') continue;
|
||||
if(!$execution->hasProduct and !$execution->multiple and $storyType == 'requirement' and $value->id == 'taskCount') continue;
|
||||
@@ -321,6 +326,37 @@
|
||||
</ul>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
|
||||
<?php if($canBatchAssignTo):?>
|
||||
<div class="btn-group dropup">
|
||||
<button data-toggle="dropdown" type="button" class="btn assignedTo"><?php echo $lang->story->assignedTo;?> <span class="caret"></span></button>
|
||||
<?php
|
||||
$withSearch = count($users) > 10;
|
||||
$actionLink = $this->createLink('story', 'batchAssignTo', "storyType=$storyType");
|
||||
echo html::select('assignedTo', $users, '', 'class="hidden"');
|
||||
?>
|
||||
<div class="dropdown-menu search-list<?php if($withSearch) echo ' search-box-sink';?>" data-ride="searchList">
|
||||
<?php if($withSearch):?>
|
||||
<?php $usersPinYin = common::convert2Pinyin($users);?>
|
||||
<div class="input-control search-box has-icon-left has-icon-right search-example">
|
||||
<input id="userSearchBox" type="search" autocomplete="off" class="form-control search-input">
|
||||
<label for="userSearchBox" class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label>
|
||||
<a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div class="list-group">
|
||||
<?php foreach ($users as $key => $value):?>
|
||||
<?php
|
||||
if(empty($key) or $key == 'closed') continue;
|
||||
$searchKey = $withSearch ? ('data-key="' . zget($usersPinYin, $value, '') . " @$key\"") : "data-key='@$key'";
|
||||
echo html::a("javascript:$(\"#assignedTo\").val(\"$key\");setFormAction(\"$actionLink\", \"hiddenwin\", \"#storyList\")", $value, '', $searchKey);
|
||||
?>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
|
||||
<?php
|
||||
if($canBatchClose)
|
||||
{
|
||||
|
||||
@@ -145,7 +145,6 @@ class extension extends control
|
||||
$this->view->upgrade = $upgrade;
|
||||
$this->view->title = $installTitle . $extension;
|
||||
|
||||
|
||||
$statusFile = $this->loadModel('common')->checkSafeFile();
|
||||
if($statusFile)
|
||||
{
|
||||
@@ -186,7 +185,7 @@ class extension extends control
|
||||
$incompatible = $condition->zentao['incompatible'];
|
||||
if($this->extension->checkVersion($incompatible))
|
||||
{
|
||||
$this->view->error = sprintf($this->lang->extension->errorIncompatible);
|
||||
$this->view->error = $this->lang->extension->errorIncompatible;
|
||||
return $this->display();
|
||||
}
|
||||
|
||||
@@ -220,7 +219,7 @@ class extension extends control
|
||||
$noDepends = false;
|
||||
if(isset($installedExts[$code]))
|
||||
{
|
||||
if($this->extension->compare4Limit($installedExts[$code]->version, $limit, 'noBetween'))$noDepends = true;
|
||||
if($this->extension->compare4Limit($installedExts[$code]->version, $limit, 'noBetween')) $noDepends = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -235,7 +234,7 @@ class extension extends control
|
||||
if(!empty($limit['max'])) $extVersion .= ' <=v' . $limit['max'];
|
||||
$extVersion .=')';
|
||||
}
|
||||
if($noDepends)$dependsExt .= $code . $extVersion . ' ' . html::a(inlink('obtain', 'type=bycode¶m=' . helper::safe64Encode($code)), $this->lang->extension->installExt, '_blank') . '<br />';
|
||||
if($noDepends) $dependsExt .= $code . $extVersion . ' ' . html::a(inlink('obtain', 'type=bycode¶m=' . helper::safe64Encode($code)), $this->lang->extension->installExt, '_blank') . '<br />';
|
||||
}
|
||||
|
||||
if($noDepends)
|
||||
|
||||
@@ -525,9 +525,11 @@ class extensionModel extends model
|
||||
/* Extract files. */
|
||||
$packageFile = $this->getPackageFile($extension);
|
||||
$this->app->loadClass('pclzip', true);
|
||||
$zip = new pclzip($packageFile);
|
||||
$files = $zip->listContent();
|
||||
$removePath = $files[0]['filename'];
|
||||
$zip = new pclzip($packageFile);
|
||||
$files = $zip->listContent();
|
||||
$pathinfo = pathinfo($files[0]['filename']);
|
||||
$removePath = isset($pathinfo['dirname']) && $pathinfo['dirname'] != '.' ? $pathinfo['dirname'] : $pathinfo['basename'];
|
||||
|
||||
if($zip->extract(PCLZIP_OPT_PATH, $extensionPath, PCLZIP_OPT_REMOVE_PATH, $removePath) == 0)
|
||||
{
|
||||
$return->result = 'fail';
|
||||
@@ -548,7 +550,7 @@ class extensionModel extends model
|
||||
{
|
||||
$appRoot = $this->app->getAppRoot();
|
||||
$extensionDir = "ext/$extension/";
|
||||
$paths = scandir($extensionDir);
|
||||
$paths = scandir($extensionDir);
|
||||
$copiedFiles = array();
|
||||
|
||||
foreach($paths as $path)
|
||||
|
||||
@@ -3,7 +3,7 @@ $maxUploadSize = strtoupper(ini_get('upload_max_filesize'));
|
||||
js::set('dangerExtensions', ',' . $this->config->file->dangers . ',');
|
||||
js::set('maxUploadSize', $maxUploadSize);
|
||||
?>
|
||||
<div class="file-input-list" data-append-way="before" data-provide="fileInputList" data-each-file-max-size="<?php echo $maxUploadSize; ?>" data-file-size-error="<?php echo sprintf($lang->file->errorFileSize, $maxUploadSize); ?>">
|
||||
<div class="file-input-list" data-append-way="before" data-filedName="<?php echo $filesName;?>" data-provide="fileInputList" data-each-file-max-size="<?php echo $maxUploadSize; ?>" data-file-size-error="<?php echo sprintf($lang->file->errorFileSize, $maxUploadSize); ?>">
|
||||
<div class="file-input">
|
||||
<div class="file-input-edit input-group">
|
||||
<div class="input-group-cell"><i class="icon icon-paper-clip text-muted"></i></div>
|
||||
|
||||
@@ -237,7 +237,6 @@ $lang->project->methodOrder[190] = 'manageRepo';
|
||||
|
||||
$lang->resource->projectbuild = new stdclass();
|
||||
$lang->resource->projectbuild->browse = 'browse';
|
||||
$lang->resource->projectbuild->create = 'create';
|
||||
$lang->resource->projectbuild->edit = 'edit';
|
||||
$lang->resource->projectbuild->view = 'view';
|
||||
$lang->resource->projectbuild->delete = 'delete';
|
||||
@@ -249,7 +248,6 @@ $lang->resource->projectbuild->unlinkBug = 'unlinkBug';
|
||||
$lang->resource->projectbuild->batchUnlinkBug = 'batchUnlinkBug';
|
||||
|
||||
$lang->projectbuild->methodOrder[5] = 'browse';
|
||||
$lang->projectbuild->methodOrder[10] = 'create';
|
||||
$lang->projectbuild->methodOrder[15] = 'edit';
|
||||
$lang->projectbuild->methodOrder[20] = 'view';
|
||||
$lang->projectbuild->methodOrder[25] = 'delete';
|
||||
|
||||
@@ -198,12 +198,13 @@ class holidayModel extends model
|
||||
{
|
||||
if(empty($begin) or empty($end) or $begin == '0000-00-00' or $end == '0000-00-00') return array();
|
||||
|
||||
$this->app->loadConfig('execution');
|
||||
$actualDays = array();
|
||||
$currentDay = $begin;
|
||||
|
||||
$holidays = $this->getHolidays($begin, $end);
|
||||
$workingDays = $this->getWorkingDays($begin, $end);
|
||||
$weekend = isset($this->config->project->weekend) ? $this->config->project->weekend : 2;
|
||||
$weekend = isset($this->config->execution->weekend) ? $this->config->execution->weekend : 2;
|
||||
|
||||
$holidaysFlip = array_flip($holidays);
|
||||
$workingDaysFlip = array_flip($workingDays);
|
||||
|
||||
@@ -564,7 +564,7 @@
|
||||
/* The magic number "111" is the space between dropdown trigger
|
||||
btn and the bottom of screen */
|
||||
var listStyle = {maxHeight: 'initial', top: moreMenuHeight > 111 ? 111 - moreMenuHeight : ''};
|
||||
if($list[0].getBoundingClientRect)
|
||||
if($list[0] && $list[0].getBoundingClientRect)
|
||||
{
|
||||
var btnBounding = $list.prev('a')[0].getBoundingClientRect();
|
||||
if(btnBounding.height)
|
||||
@@ -803,7 +803,7 @@ $(function()
|
||||
{
|
||||
var val = $searchQuery.val();
|
||||
var searchType = changeSearchObject();
|
||||
if(val !== null && val !== "")
|
||||
if(val)
|
||||
{
|
||||
var isQuickGo = !reg.test(val);
|
||||
$dropmenu.toggleClass('show-quick-go', isQuickGo);
|
||||
|
||||
@@ -59,7 +59,7 @@ $lang->misc->zentao->others['meshiot' ] = "<img src='{$config->webRoot}theme/def
|
||||
|
||||
$lang->misc->mobile = "Mobiler Zugriff";
|
||||
$lang->misc->noGDLib = "Bitte benutzen Sie den Browser Ihres Telefons um die Seite <strong>%s</strong> aufzurufen";
|
||||
$lang->misc->copyright = "© 2009 - 2018 <a href='http://easysoft.ltd' target='_blank'>Nature Easy Soft Network Technology Co,LTD</a> Email <a href='mailto:Max@easysoft.ltd'>Max@easysoft.ltd</a>";
|
||||
$lang->misc->copyright = "© 2009 - " . date('Y') . " <a href='https://easysoft.ltd' target='_blank'>Nature Easy Soft Network Technology Co,LTD</a> Email <a href='mailto:Max@easysoft.ltd'>Max@easysoft.ltd</a>";
|
||||
$lang->misc->checkTable = "Prüfe Datentabellen";
|
||||
$lang->misc->needRepair = "Repariere Datentabellen";
|
||||
$lang->misc->repairTable = "Datenbank íst beschädigt. Bitte brüfen und reparieren!";
|
||||
|
||||
@@ -59,7 +59,7 @@ $lang->misc->zentao->others['meshiot' ] = "<img src='{$config->webRoot}theme/def
|
||||
|
||||
$lang->misc->mobile = "Mobile Access";
|
||||
$lang->misc->noGDLib = "Please visit <strong>%s</strong> in the browser of your phone.";
|
||||
$lang->misc->copyright = "© 2009 - 2019 <a href='https://easycorp.ltd/' target='_blank'>EasyCorp</a> Email <a href='mailto:Renee@easycorp.ltd'>Renee@easycorp.ltd</a>";
|
||||
$lang->misc->copyright = "© 2009 - " . date('Y') . " <a href='https://easycorp.ltd/' target='_blank'>EasyCorp</a> Email <a href='mailto:Renee@easycorp.ltd'>Renee@easycorp.ltd</a>";
|
||||
$lang->misc->checkTable = "Check Data Table";
|
||||
$lang->misc->needRepair = "Repair Table";
|
||||
$lang->misc->repairTable = "Database table might be damaged due to power outage. Please check and repair!";
|
||||
|
||||
@@ -59,7 +59,7 @@ $lang->misc->zentao->others['meshiot' ] = "<img src='{$config->webRoot}theme/def
|
||||
|
||||
$lang->misc->mobile = "Accès Mobile";
|
||||
$lang->misc->noGDLib = "SVP visitez <strong>%s</strong> via le navigateur de votre smartphone.";
|
||||
$lang->misc->copyright = "© 2009 - 2019 <a href='http://easysoft.ltd' target='_blank'>Nature Easy Soft</a> Email <a href='mailto:Renee@easysoft.ltd'>Renee@easysoft.ltd</a>";
|
||||
$lang->misc->copyright = "© 2009 - " . date('Y') . " <a href='https://easysoft.ltd' target='_blank'>Nature Easy Soft</a> Email <a href='mailto:Renee@easysoft.ltd'>Renee@easysoft.ltd</a>";
|
||||
$lang->misc->checkTable = "Vérifiez les Données de la Table";
|
||||
$lang->misc->needRepair = "Réparer la Table";
|
||||
$lang->misc->repairTable = "La Base de Données est peut-être endommagée. Elle a besoin d'être vérifiée et éventuellement réparée !";
|
||||
|
||||
@@ -59,7 +59,7 @@ $lang->misc->zentao->others['meshiot' ] = "<img src='{$config->webRoot}theme/def
|
||||
|
||||
$lang->misc->mobile = "Mobile Access";
|
||||
$lang->misc->noGDLib = "Please visit <strong>%s</strong> in the browser of your phone.";
|
||||
$lang->misc->copyright = "© 2009 - 2019 <a href='http://easysoft.ltd' target='_blank'>Nature Easy Soft</a> Email <a href='mailto:Renee@easysoft.ltd'>Renee@easysoft.ltd</a>";
|
||||
$lang->misc->copyright = "© 2009 - " . date('Y') . " <a href='https://easysoft.ltd' target='_blank'>Nature Easy Soft</a> Email <a href='mailto:Renee@easysoft.ltd'>Renee@easysoft.ltd</a>";
|
||||
$lang->misc->checkTable = "Check Data Table";
|
||||
$lang->misc->needRepair = "Repair Table";
|
||||
$lang->misc->repairTable = "Database table might be damaged due to power outage. Vui lòng check and repair!";
|
||||
|
||||
@@ -59,7 +59,7 @@ $lang->misc->zentao->others['meshiot' ] = "<img src='{$config->webRoot}theme/def
|
||||
|
||||
$lang->misc->mobile = "手机访问";
|
||||
$lang->misc->noGDLib = "请用手机浏览器访问:<strong>%s</strong>";
|
||||
$lang->misc->copyright = "© 2009 - 2018 <a href='http://www.cnezsoft.com' target='_blank'>青岛易软天创网络科技有限公司</a> 电话:4006-8899-23 Email:<a href='mailto:co@zentao.net'>co@zentao.net</a> QQ:1492153927";
|
||||
$lang->misc->copyright = "© 2009 - " . date('Y') . " <a href='https://www.easycorp.cn' target='_blank'>青岛易软天创网络科技有限公司</a> 电话:4006-8899-23 Email:<a href='mailto:co@zentao.net'>co@zentao.net</a> QQ:1492153927";
|
||||
$lang->misc->checkTable = "检查修复数据表";
|
||||
$lang->misc->needRepair = "修复表";
|
||||
$lang->misc->repairTable = "数据库表可能因为断电原因损坏,需要检查修复!!";
|
||||
@@ -193,7 +193,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.beta1'][] = array('title' => '主要对禅道多项核心流程进行改进,新增无产品项目、无迭代项目;支持项目跨项目集关联产品;支持轻量管理模式和全生命周期管理模式进行切换。', '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' => '');
|
||||
$lang->misc->feature->all['17.6.2'][] = array('title' => '禅道更新叶兰绿、禅道蓝、青春蓝三大主题。实现附件批量上传功能。修复Bug。', 'desc' => '');
|
||||
|
||||
@@ -59,7 +59,7 @@ $lang->misc->zentao->others['meshiot' ] = "<img src='{$config->webRoot}theme/def
|
||||
|
||||
$lang->misc->mobile = "手機訪問";
|
||||
$lang->misc->noGDLib = "請用手機瀏覽器訪問:<strong>%s</strong>";
|
||||
$lang->misc->copyright = "© 2009 - 2018 <a href='http://www.cnezsoft.com' target='_blank'>青島易軟天創網絡科技有限公司</a> 電話:4006-8899-23 Email:<a href='mailto:co@zentao.net'>co@zentao.net</a> QQ:1492153927";
|
||||
$lang->misc->copyright = "© 2009 - " . date('Y') . " <a href='https://www.easycorp.cn' target='_blank'>青島易軟天創網絡科技有限公司</a> 電話:4006-8899-23 Email:<a href='mailto:co@zentao.net'>co@zentao.net</a> QQ:1492153927";
|
||||
$lang->misc->checkTable = "檢查修復數據表";
|
||||
$lang->misc->needRepair = "修復表";
|
||||
$lang->misc->repairTable = "資料庫表可能因為斷電原因損壞,需要檢查修復!!";
|
||||
|
||||
@@ -127,7 +127,7 @@ class my extends control
|
||||
$storyCount = $assignedToStoryCount + $reviewByStoryCount;
|
||||
|
||||
$requirementCount = 0;
|
||||
$isOpenedURAndSR = $this->config->URAndSR;
|
||||
$isOpenedURAndSR = $this->config->URAndSR ? 1 : 0;
|
||||
if($isOpenedURAndSR)
|
||||
{
|
||||
/* Get the number of requirements assigned to me. */
|
||||
|
||||
@@ -880,6 +880,27 @@ class product extends control
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax get products.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetProducts($executionID)
|
||||
{
|
||||
$this->loadModel('build');
|
||||
$products = $this->product->getProductPairsByProject($executionID);
|
||||
if(empty($products))
|
||||
{
|
||||
return printf($this->lang->build->noProduct, $this->createLink('execution', 'manageproducts', "executionID=$executionID&from=buildCreate", '', 'true'), 'project');
|
||||
}
|
||||
else
|
||||
{
|
||||
return print(html::select('product', $products, empty($product) ? '' : $product->id, "onchange='loadBranches(this.value);' class='form-control chosen' required data-toggle='modal' data-type='iframe'"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: get projects of a product in html select.
|
||||
*
|
||||
@@ -924,10 +945,11 @@ class product extends control
|
||||
* @param string $number
|
||||
* @param int $executionID
|
||||
* @param string $from showImport
|
||||
* @param string mode
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetExecutions($productID, $projectID = 0, $branch = 0, $number = '', $executionID = 0, $from = '')
|
||||
public function ajaxGetExecutions($productID, $projectID = 0, $branch = 0, $number = '', $executionID = 0, $from = '', $mode = '')
|
||||
{
|
||||
if($this->app->tab == 'execution' and $this->session->execution)
|
||||
{
|
||||
@@ -935,7 +957,7 @@ class product extends control
|
||||
if($execution->type == 'kanban') $projectID = $execution->project;
|
||||
}
|
||||
|
||||
$mode = ($from == 'bugToTask' or empty($this->config->CRExecution)) ? 'noclosed' : '';
|
||||
$mode .= ($from == 'bugToTask' or empty($this->config->CRExecution)) ? 'noclosed' : '';
|
||||
$mode .= !$projectID ? ',multiple' : '';
|
||||
$executions = $from == 'showImport' ? $this->product->getAllExecutionPairsByProduct($productID, $branch, $projectID) : $this->product->getExecutionPairsByProduct($productID, $branch, 'id_desc', $projectID, $mode);
|
||||
if($this->app->getViewType() == 'json') return print(json_encode($executions));
|
||||
|
||||
@@ -5,7 +5,7 @@ $(function()
|
||||
$('#navbar .nav li').removeClass('active');
|
||||
$("#navbar .nav li[data-id=" + storyType + ']').addClass('active');
|
||||
|
||||
if(rawModule == 'projectstory' && !projectHasProduct && URAndSR)
|
||||
if(vision != 'lite' && rawModule == 'projectstory' && !projectHasProduct && URAndSR)
|
||||
{
|
||||
$('#navbar .nav>li[data-id=story]').addClass('active');
|
||||
$('#navbar .nav>li[data-id=story]>a').html($('.active [data-id=' + storyType + ']').text() + '<span class="caret"></span>');
|
||||
|
||||
@@ -124,7 +124,7 @@ class productModel extends model
|
||||
if($isQaModule) $moduleName = 'bug';
|
||||
if($isFeedbackModel) $moduleName = 'feedback';
|
||||
$dropMenuLink = helper::createLink($moduleName, 'ajaxGetDropMenu', "objectID=$productID&module=$currentModule&method=$currentMethod&extra=$extra");
|
||||
$output = "<div class='btn-group angle-btn'><div class='btn-group'><button data-toggle='dropdown' type='button' class='btn btn-limit' id='currentItem' title='{$currentProduct->name}'><span class='text'>{$currentProduct->name}</span> <span class='caret'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
|
||||
$output = "<div class='btn-group angle-btn'><div class='btn-group'><button data-toggle='dropdown' type='button' class='btn btn-limit' id='currentItem' title='{$currentProduct->name}' style='width: 90%'><span class='text'>{$currentProduct->name}</span> <span class='caret'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
|
||||
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
|
||||
$output .= "</div></div>";
|
||||
if($isMobile) $output = "<a id='currentItem' href=\"javascript:showSearchMenu('product', '$productID', '$currentModule', '$currentMethod', '$extra')\"><span class='text'>{$currentProduct->name}</span> <span class='icon-caret-down'></span></a><div id='currentItemDropMenu' class='hidden affix enter-from-bottom layer'></div>";
|
||||
@@ -140,7 +140,7 @@ class productModel extends model
|
||||
if(!$isMobile)
|
||||
{
|
||||
$dropMenuLink = helper::createLink('branch', 'ajaxGetDropMenu', "objectID=$productID&branch=$branch&module=$currentModule&method=$currentMethod&extra=$extra");
|
||||
$output .= "<div class='btn-group'><button id='currentBranch' data-toggle='dropdown' type='button' class='btn btn-limit'>{$branchName} <span class='caret'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
|
||||
$output .= "<div class='btn-group'><button id='currentBranch' data-toggle='dropdown' type='button' class='btn btn-limit' title='{$branchName}' style='width: 90%'>{$branchName} <span class='caret'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
|
||||
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
|
||||
$output .= "</div></div>";
|
||||
}
|
||||
@@ -1228,6 +1228,28 @@ class productModel extends model
|
||||
$this->loadModel('search')->setSearchParams($this->config->product->all->search);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project pairs by product.
|
||||
*
|
||||
* @param array $productIDList
|
||||
* @param int $branch
|
||||
* @param int $appendProject
|
||||
* @param string $status all|closed|unclosed
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getProjectPairsByProductIDList($productIDList, $branch = 0, $appendProject = 0, $status = '')
|
||||
{
|
||||
$projectParis = array();
|
||||
foreach($productIDList as $productID)
|
||||
{
|
||||
$projects = $this->getProjectPairsByProduct($productID, $branch, $appendProject, $status);
|
||||
$projectParis = $projectParis + $projects;
|
||||
}
|
||||
|
||||
return $projectParis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project pairs by product.
|
||||
*
|
||||
|
||||
@@ -38,6 +38,7 @@ js::set('unfoldStories', $unfoldStories);
|
||||
js::set('unfoldAll', $lang->execution->treeLevel['all']);
|
||||
js::set('foldAll', $lang->execution->treeLevel['root']);
|
||||
js::set('storyType', $storyType);
|
||||
js::set('vision', $this->config->vision);
|
||||
?>
|
||||
<style>
|
||||
.btn-group .icon-close:before {font-size: 5px; vertical-align: 25%;}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<div id='mainContent' class="main-row">
|
||||
<div class="col-12 main-col">
|
||||
<div class="row">
|
||||
<?php $isRoadmap = common::hasPriv('product', 'roadmap');?>
|
||||
<?php $isRoadmap = (common::hasPriv('product', 'roadmap') and helper::hasFeature('product_roadmap'));?>
|
||||
<?php if($isRoadmap):?>
|
||||
<div class="col-sm-6">
|
||||
<div class="panel block-release">
|
||||
|
||||
@@ -247,7 +247,7 @@ class productplanModel extends model
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t3.id=t1.product')
|
||||
->where('t1.product')->in($product)
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->beginIF($branch !== '')->andWhere('t1.branch')->in($branch)->fi()
|
||||
->beginIF($branch !== '' and $branch != 'all')->andWhere('t1.branch')->in("0,$branch")->fi()
|
||||
->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')
|
||||
@@ -255,6 +255,8 @@ class productplanModel extends model
|
||||
|
||||
$plans = $this->reorder4Children($plans);
|
||||
$planPairs = array();
|
||||
$mainPlan = array();
|
||||
$this->app->loadLang('bug');
|
||||
$this->app->loadLang('branch');
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
@@ -263,8 +265,14 @@ class productplanModel extends model
|
||||
$planPairs[$plan->id] = $plan->title . " [{$plan->begin} ~ {$plan->end}]";
|
||||
if($plan->begin == $this->config->productplan->future and $plan->end == $this->config->productplan->future) $planPairs[$plan->id] = $plan->title . ' ' . $this->lang->productplan->future;
|
||||
if($plan->productType != 'normal') $planPairs[$plan->id] = ($plan->branchName ? $plan->branchName : $this->lang->branch->main) . ' / ' . $planPairs[$plan->id];
|
||||
if(empty($plan->branchName))
|
||||
{
|
||||
$mainPlan = $planPairs[$plan->id];
|
||||
unset($planPairs[$plan->id]);
|
||||
}
|
||||
}
|
||||
return array('' => '') + $planPairs;
|
||||
array_splice($planPairs, 0, 0, $mainPlan);
|
||||
return array('' => '', 'ditto' => $this->lang->bug->ditto) + $planPairs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -531,22 +539,21 @@ class productplanModel extends model
|
||||
->get();
|
||||
|
||||
$parentPlan = $this->getByID($plan->parent);
|
||||
|
||||
$futureTime = $this->config->productplan->future;
|
||||
|
||||
if($plan->parent > 0)
|
||||
{
|
||||
if($parentPlan->begin !== $this->config->productplan->future)
|
||||
if($parentPlan->begin !== $futureTime)
|
||||
{
|
||||
if($plan->begin < $parentPlan->begin) dao::$errors['begin'] = sprintf($this->lang->productplan->beginLetterParent, $parentPlan->begin);
|
||||
}
|
||||
if($parentPlan->end !== $this->config->productplan->future)
|
||||
if($parentPlan->end !== $futureTime)
|
||||
{
|
||||
if($plan->end !== $this->config->productplan->future and $plan->end > $parentPlan->end) dao::$errors['end'] = sprintf($this->lang->productplan->endGreaterParent, $parentPlan->end);
|
||||
if($plan->end !== $futureTime and $plan->end > $parentPlan->end) dao::$errors['end'] = sprintf($this->lang->productplan->endGreaterParent, $parentPlan->end);
|
||||
}
|
||||
}
|
||||
elseif($oldPlan->parent == -1 and $plan->begin != $this->config->productplan->future)
|
||||
elseif($oldPlan->parent == -1 and ($plan->begin != $futureTime or $plan->end != $futureTime))
|
||||
{
|
||||
$plan->parent = -1;
|
||||
$childPlans = $this->getChildren($planID);
|
||||
$minBegin = $plan->begin;
|
||||
$maxEnd = $plan->end;
|
||||
@@ -556,8 +563,8 @@ class productplanModel extends model
|
||||
if($childPlan->begin < $minBegin) $minBegin = $childPlan->begin;
|
||||
if($childPlan->end > $maxEnd) $maxEnd = $childPlan->end;
|
||||
}
|
||||
if($minBegin < $plan->begin and $minBegin != $this->config->productplan->future) dao::$errors['begin'] = sprintf($this->lang->productplan->beginGreaterChildTip, $oldPlan->title, $plan->begin, $minBegin);
|
||||
if($maxEnd > $plan->end and $maxEnd != $this->config->productplan->future) dao::$errors['end'] = sprintf($this->lang->productplan->endLetterChildTip, $oldPlan->title, $plan->end, $maxEnd);
|
||||
if($minBegin < $plan->begin and $minBegin != $futureTime) dao::$errors['begin'] = sprintf($this->lang->productplan->beginGreaterChildTip, $oldPlan->title, $plan->begin, $minBegin);
|
||||
if($maxEnd > $plan->end and $maxEnd != $futureTime) dao::$errors['end'] = sprintf($this->lang->productplan->endLetterChildTip, $oldPlan->title, $plan->end, $maxEnd);
|
||||
}
|
||||
|
||||
if(dao::isError()) return false;
|
||||
@@ -647,7 +654,11 @@ class productplanModel extends model
|
||||
$childStatus = $this->dao->select('status')->from(TABLE_PRODUCTPLAN)->where('parent')->eq($parentID)->andWhere('deleted')->eq(0)->fetchPairs();
|
||||
|
||||
/* If the subplan is empty, update the plan. */
|
||||
if(empty($childStatus)) $this->dao->update(TABLE_PRODUCTPLAN)->set('parent')->eq(0)->where('id')->eq($parentID)->exec();
|
||||
if(empty($childStatus))
|
||||
{
|
||||
$this->dao->update(TABLE_PRODUCTPLAN)->set('parent')->eq(0)->set('status')->eq('wait')->where('id')->eq($parentID)->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
if(count($childStatus) == 1 and isset($childStatus['wait']))
|
||||
{
|
||||
|
||||
@@ -41,10 +41,14 @@
|
||||
<th><?php echo $lang->productplan->title;?></th>
|
||||
<td><?php echo html::input('title', $plan->title, "class='form-control' required");?></td><td></td><td></td>
|
||||
</tr>
|
||||
<tr <?php echo $plan->parent == '-1' ? "class='hidden'": '';?>>
|
||||
<?php if($plan->parent == '-1'):?>
|
||||
<?php echo html::hidden('parent', $plan->parent);?>
|
||||
<?php else:?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->parent;?></th>
|
||||
<td><?php echo html::select('parent', array('0' => '') + $parentPlanPairs, $plan->parent, "class='form-control chosen'");?>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->productplan->status;?></th>
|
||||
<?php $disabled = $plan->parent == -1 ? "disabled='disabled'" : '' ;?>
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
<td class='text-left nobr' title='<?php echo $story->title?>'>
|
||||
<?php
|
||||
if($story->parent > 0) echo "<span class='label label-badge label-light' title={$lang->story->children}>{$lang->story->childrenAB}</span>";
|
||||
echo html::a($viewLink , $story->title, '', "style='color: $story->color'");
|
||||
echo html::a($viewLink , $story->title, '', "style='color: $story->color' data-app={$this->app->tab}");
|
||||
?>
|
||||
</td>
|
||||
<td><?php echo zget($users, $story->openedBy);?></td>
|
||||
@@ -464,7 +464,7 @@
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td><span class='<?php echo $bug->pri ? "label-pri label-pri-{$bug->pri}" : "";?>' title='<?php echo zget($lang->bug->priList, $bug->pri);?>'><?php echo zget($lang->bug->priList, $bug->pri);?></span></td>
|
||||
<td class='text-left nobr' title='<?php echo $bug->title?>'><?php echo html::a($this->createLink('bug', 'view', "bugID=$bug->id"), $bug->title, '', 'data-app="product"');?></td>
|
||||
<td class='text-left nobr' title='<?php echo $bug->title?>'><?php echo html::a($this->createLink('bug', 'view', "bugID=$bug->id"), $bug->title, '', "data-app={$this->app->tab}");?></td>
|
||||
<td><?php echo zget($users, $bug->openedBy);?></td>
|
||||
<td><?php echo zget($users, $bug->assignedTo);?></td>
|
||||
<td>
|
||||
|
||||
@@ -88,7 +88,6 @@ class programModel extends model
|
||||
$dao = $this->dao->select('id, name, program')->from(TABLE_PRODUCT)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->beginIF($programID !== '')->andWhere('program')->eq($programID)->fi()
|
||||
->beginIF($shadow !== 'all')->andWhere('shadow')->eq((int)$shadow)->fi()
|
||||
->beginIF($mode == 'assign')->andWhere('program')->eq($programID)->fi()
|
||||
->beginIF(strpos($status, 'noclosed') !== false)->andWhere('status')->ne('closed')->fi()
|
||||
|
||||
@@ -102,7 +102,7 @@ $lang->programplan->ganttCustom['delay'] = '是否延期';
|
||||
$lang->programplan->ganttCustom['delayDays'] = '延期天数';
|
||||
|
||||
$lang->programplan->error = new stdclass();
|
||||
$lang->programplan->error->percentNumber = '"工作量比例"必须为数字';
|
||||
$lang->programplan->error->percentNumber = '"工作量占比"必须为数字';
|
||||
$lang->programplan->error->planFinishSmall = '"计划完成时间"必须大于"计划开始时间"';
|
||||
$lang->programplan->error->percentOver = '工作量占比累计不应当超过100%';
|
||||
$lang->programplan->error->createdTask = '已分解任务,不可添加子阶段';
|
||||
|
||||
@@ -72,7 +72,7 @@ $lang->programplan->stageCustom->date = '顯示日期';
|
||||
$lang->programplan->stageCustom->task = '顯示任務';
|
||||
|
||||
$lang->programplan->error = new stdclass();
|
||||
$lang->programplan->error->percentNumber = '"工作量比例"必須為數字';
|
||||
$lang->programplan->error->percentNumber = '"工作量占比"必須為數字';
|
||||
$lang->programplan->error->planFinishSmall = '"計劃完成時間"必須大於"計劃開始時間"';
|
||||
$lang->programplan->error->percentOver = '工作量占比累計不應當超過100%';
|
||||
$lang->programplan->error->createdTask = '已分解任務,不可添加子階段';
|
||||
|
||||
@@ -187,6 +187,7 @@ class programplanModel extends model
|
||||
$data->id = $plan->id;
|
||||
$data->type = 'plan';
|
||||
$data->text = empty($plan->milestone) ? $plan->name : $plan->name . $isMilestone ;
|
||||
$data->name = $plan->name;
|
||||
$data->percent = $plan->percent;
|
||||
$data->attribute = zget($this->lang->stage->typeList, $plan->attribute);
|
||||
$data->milestone = zget($this->lang->programplan->milestoneList, $plan->milestone);
|
||||
|
||||
@@ -2173,15 +2173,15 @@ class project extends control
|
||||
if($executionID) $this->execution->updateProducts($executionID);
|
||||
}
|
||||
|
||||
$oldProducts = array_keys($oldProducts);
|
||||
$newProducts = $this->product->getProducts($projectID);
|
||||
$newProducts = array_keys($newProducts);
|
||||
$diffProducts = array_merge(array_diff($oldProducts, $newProducts), array_diff($newProducts, $oldProducts));
|
||||
$newProducts = $this->product->getProducts($projectID);
|
||||
$oldProductIDs = array_keys($oldProducts);
|
||||
$newProductIDs = array_keys($newProducts);
|
||||
$diffProducts = array_merge(array_diff($oldProductIDs, $newProductIDs), array_diff($newProductIDs, $oldProductIDs));
|
||||
if($diffProducts) $this->loadModel('action')->create('project', $projectID, 'Managed', '', !empty($_POST['products']) ? join(',', $_POST['products']) : '');
|
||||
|
||||
if($project->multiple)
|
||||
{
|
||||
$unlinkedProducts = array_diff($oldProducts, $newProducts);
|
||||
$unlinkedProducts = array_diff($oldProductIDs, $newProductIDs);
|
||||
if(!empty($unlinkedProducts))
|
||||
{
|
||||
$unlinkedProductPairs = array();
|
||||
@@ -2237,13 +2237,14 @@ class project extends control
|
||||
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal|noclosed');
|
||||
if($this->config->systemMode == 'ALM')
|
||||
{
|
||||
$topProgramID = $this->program->getTopByPath($project->path);
|
||||
$productsGroupByProgram = $this->product->getProductsGroupByProgram();
|
||||
|
||||
$currentProducts = array();
|
||||
$otherProducts = array();
|
||||
foreach($productsGroupByProgram as $programID => $programProducts)
|
||||
{
|
||||
if($programID != $project->parent)
|
||||
if($programID != $topProgramID)
|
||||
{
|
||||
foreach($programProducts as $productID => $productName)
|
||||
{
|
||||
@@ -2295,12 +2296,13 @@ class project extends control
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param int $executionID
|
||||
* @param string $mode
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetExecutions($projectID, $executionID = 0)
|
||||
public function ajaxGetExecutions($projectID, $executionID = 0, $mode = '')
|
||||
{
|
||||
$executions = array('' => '') + $this->loadModel('execution')->getPairs($projectID, 'all');
|
||||
$executions = array('' => '') + $this->loadModel('execution')->getPairs($projectID, 'all', $mode);
|
||||
|
||||
if($this->app->getViewType() == 'json') return print(json_encode($executionList));
|
||||
return print(html::select('execution', $executions, $executionID, "class='form-control'"));
|
||||
|
||||
@@ -5,6 +5,18 @@ $(function()
|
||||
const hasProduct = $('[name=hasProduct]:checked').val();
|
||||
|
||||
$('#productTitle, #linkPlan').closest('tr').toggle(hasProduct == 1);
|
||||
|
||||
if(hasProduct == 0) $('.division').addClass('hide');
|
||||
|
||||
if(hasProduct == 1)
|
||||
{
|
||||
var chosenProducts = 0;
|
||||
$("#productsBox select[name^='products']").each(function()
|
||||
{
|
||||
if($(this).val() > 0) chosenProducts ++;
|
||||
});
|
||||
if(chosenProducts > 1) $('.division').removeClass('hide');
|
||||
}
|
||||
});
|
||||
|
||||
$('[name=hasProduct]').change();
|
||||
@@ -160,13 +172,12 @@ function setParentProgram(parentProgram)
|
||||
var selectedProduct = $(this).find('[name^=products]').val();
|
||||
var selectedBranch = $(this).find('[name^=branch]').val();
|
||||
var selectedPlan = $('#plan' + index ).find('[name^=plans]').val();
|
||||
var newProductHtml = $(this).find('span.input-group-addon');
|
||||
|
||||
$(this).html(productSelectHtml);
|
||||
$(this).append(newProductHtml);
|
||||
$(this).find('[name^=products]').attr('name', 'products[' + index + ']').attr('id', 'products' + index).attr('data-branch', selectedBranch).attr('data-plan', selectedPlan);
|
||||
$(this).find('[name^=products]').val(selectedProduct).chosen().change();
|
||||
});
|
||||
$('#productsBox .row .col-sm-4:last').find('.input-group').append($('#productsBox .addProduct .input-group:first .input-group-addon').prop('outerHTML'));
|
||||
}
|
||||
|
||||
if(parentProgram != 0)
|
||||
|
||||
@@ -116,6 +116,11 @@ $(function()
|
||||
return (checkedTotal ? checkedSummary : pageSummary).replace('%total%', $rows.length).replace('%wait%', checkedWait).replace('%doing%', checkedDoing);
|
||||
}
|
||||
})
|
||||
|
||||
if(project.division && project.hasProduct && $('#executionList thead th.table-nest-title').width() < 240)
|
||||
{
|
||||
$('#executionList thead th.table-nest-title').width(240)
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener('scroll', this.handleScroll)
|
||||
|
||||
@@ -183,7 +183,7 @@ $lang->project->kanban = '看板';
|
||||
/* Project Kanban. */
|
||||
$lang->project->projectTypeList = array();
|
||||
$lang->project->projectTypeList[1] = '产品型项目';
|
||||
$lang->project->projectTypeList[0] = '无产品项目';
|
||||
$lang->project->projectTypeList[0] = '项目型项目';
|
||||
|
||||
/* Project Kanban. */
|
||||
$lang->project->typeList = array();
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
<?php
|
||||
class projectModel extends model
|
||||
{
|
||||
/**
|
||||
* Check the privilege.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function checkPriv($projectID)
|
||||
{
|
||||
if(empty($projectID)) return false;
|
||||
|
||||
/* If is admin, return true. */
|
||||
if($this->app->user->admin) return true;
|
||||
return (strpos(",{$this->app->user->view->projects},", ",{$projectID},") !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Multiple linked products for project.
|
||||
*
|
||||
@@ -3003,7 +3019,7 @@ class projectModel extends model
|
||||
$menu .= "<div class='btn-group'>";
|
||||
$menu .= "<button type='button' class='btn dropdown-toggle' data-toggle='context-dropdown' title='{$this->lang->more}'><i class='icon-ellipsis-v'></i></button>";
|
||||
$menu .= "<ul class='dropdown-menu pull-right text-center' role='menu'>";
|
||||
$menu .= $this->buildMenu($moduleName, 'manageProducts', $params . "&from={$this->app->tab}", $project, 'browse', 'link', '', 'btn-action', '', '', $this->lang->project->manageProducts);
|
||||
if($project->hasProduct) $menu .= $this->buildMenu($moduleName, 'manageProducts', $params . "&from={$this->app->tab}", $project, 'browse', 'link', '', 'btn-action', '', '', $this->lang->project->manageProducts);
|
||||
$menu .= $this->buildMenu('project', 'whitelist', "$params&module=project&from=$from", $project, 'browse', 'shield-check', '', 'btn-action', '', $dataApp);
|
||||
$menu .= $this->buildMenu($moduleName, "delete", $params, $project, 'browse', 'trash', 'hiddenwin', 'btn-action');
|
||||
$menu .= "</ul>";
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#swapper li {padding-top: 0; padding-bottom: 0;}
|
||||
#swapper .tree li>.list-toggle {top: -1px;}
|
||||
|
||||
#closed {width: 90px; height: 25px; line-height: 25px; background-color: #ddd; color: #3c495c; text-align: center; margin-left: 15px; border-radius: 2px;}
|
||||
#dropMenu div#closed {width: 90px; height: 25px; line-height: 25px; background-color: #ddd; color: #3c495c; text-align: center; margin-left: 15px; border-radius: 2px;}
|
||||
#gray-line {width:230px; height: 1px; margin-left: 10px; margin-bottom:2px; background-color: #ddd;}
|
||||
</style>
|
||||
<?php
|
||||
@@ -53,10 +53,11 @@ foreach($projects as $programID => $programProjects)
|
||||
}
|
||||
$projectsPinYin = common::convert2Pinyin($projectNames);
|
||||
|
||||
$myProjectsHtml = $config->systemMode == 'ALM' ? '<ul class="tree tree-angles" data-ride="tree">' : '<ul class="noProgram">';
|
||||
$normalProjectsHtml = $config->systemMode == 'ALM' ? '<ul class="tree tree-angles" data-ride="tree">' : '<ul class="noProgram">';
|
||||
$closedProjectsHtml = $config->systemMode == 'ALM' ? '<ul class="tree tree-angles" data-ride="tree">' : '<ul class="noProgram">';
|
||||
$myProjectsHtml = $config->systemMode == 'ALM' ? '<ul class="tree tree-angles" data-ride="tree">' : '<ul class="tree noProgram">';
|
||||
$normalProjectsHtml = $config->systemMode == 'ALM' ? '<ul class="tree tree-angles" data-ride="tree">' : '<ul class="tree noProgram">';
|
||||
$closedProjectsHtml = $config->systemMode == 'ALM' ? '<ul class="tree tree-angles" data-ride="tree">' : '<ul class="tree noProgram">';
|
||||
|
||||
$indexLink = helper::createLink('project', 'index', "projectID=%s");
|
||||
foreach($projects as $programID => $programProjects)
|
||||
{
|
||||
/* Add the program name before project. */
|
||||
@@ -77,15 +78,36 @@ foreach($projects as $programID => $programProjects)
|
||||
|
||||
if($project->model != 'waterfall' and (in_array($module, $config->waterfallModules) or $method == 'track'))
|
||||
{
|
||||
$link = helper::createLink('project', 'index', "projectID=%s");
|
||||
$link = $indexLink;
|
||||
}
|
||||
elseif($project->model == 'scrum' and
|
||||
(
|
||||
(in_array($module, array('issue', 'risk', 'meeting')) and !helper::hasFeature("scrum_{$module}")) or
|
||||
($module == 'report' and $method == 'projectsummary' and !helper::hasFeature("scrum_measrecord"))
|
||||
))
|
||||
{
|
||||
$link = $indexLink;
|
||||
}
|
||||
elseif($project->model == 'waterfall' and
|
||||
(
|
||||
(in_array($module, array('issue', 'risk', 'opportunity', 'measrecord', 'auditplan', 'meeting')) and !helper::hasFeature("waterfall_{$module}")) or
|
||||
($module == 'pssp' and !helper::hasFeature("waterfall_process")) or
|
||||
($module == 'report' and $method == 'projectsummary' and !helper::hasFeature("scrum_measrecord"))
|
||||
))
|
||||
{
|
||||
$link = $indexLink;
|
||||
}
|
||||
elseif($project->model == 'kanban' and (($module == 'project' and !in_array($method, array('build', 'view', 'manageproducts', 'team', 'whitelist', 'managemembers', 'addwhitelist'))) or $module != 'project'))
|
||||
{
|
||||
$link = helper::createLink('project', 'index', "projectID=%s");
|
||||
$link = $indexLink;
|
||||
}
|
||||
elseif(empty($project->hasProduct) and $module == 'project' and $method == 'manageproducts')
|
||||
{
|
||||
$link = $indexLink;
|
||||
}
|
||||
elseif(empty($project->multiple))
|
||||
{
|
||||
$link = helper::createLink('project', 'index', "projectID=%s");
|
||||
$link = $indexLink;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -122,7 +144,7 @@ foreach($projects as $programID => $programProjects)
|
||||
}
|
||||
|
||||
/* If the project is the last one in the program, print the closed label. */
|
||||
if(isset($programs[$programID]) and !isset($programProjects[$index + 1]))
|
||||
if($config->systemMode == 'ALM' and isset($programs[$programID]) and !isset($programProjects[$index + 1]))
|
||||
{
|
||||
if($projectCounts[$programID]['myProject']) $myProjectsHtml .= '</ul></li>';
|
||||
if($projectCounts[$programID]['others']) $normalProjectsHtml .= '</ul></li>';
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
foreach($setting as $key => $value)
|
||||
{
|
||||
if(!$project->hasProduct and $project->model != 'scrum' and $value->id == 'plan') continue;
|
||||
if(!$project->hasProduct and $value->id == 'branch') continue;
|
||||
|
||||
if($value->show)
|
||||
{
|
||||
@@ -119,6 +120,7 @@
|
||||
<?php foreach($setting as $value)
|
||||
{
|
||||
if(!$project->hasProduct and $project->model != 'scrum' and $value->id == 'plan') continue;
|
||||
if(!$project->hasProduct and $value->id == 'branch') continue;
|
||||
$this->bug->printCell($value, $bug, $users, $builds, $branchOption, $modulePairs, $executions, $plans, $stories, $tasks, $useDatatable ? 'datatable' : 'table', $projectPairs);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<a class="btn btn-link querybox-toggle" id="bysearchTab"><i class="icon icon-search muted"></i> <?php echo $lang->execution->byQuery;?></a>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-right">
|
||||
<?php if(common::canModify('project', $project)) common::printLink('projectbuild', 'create', "projectID=$projectID", "<i class='icon icon-plus'></i> " . $lang->build->create, '', "class='btn btn-primary' id='createBuild'");?>
|
||||
<?php if(common::canModify('project', $project)) common::printLink('build', 'create', "executionID=&productID=&projectID=$projectID", "<i class='icon icon-plus'></i> " . $lang->build->create, '', "class='btn btn-primary' id='createBuild'");?>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mainContent">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php js::set('projectID', $projectID);?>
|
||||
<?php js::set('project', $project);?>
|
||||
<?php js::set('edit', $lang->edit);?>
|
||||
<?php js::set('selectAll', $lang->selectAll);?>
|
||||
<?php js::set('checkedExecutions', $lang->execution->checkedExecutions);?>
|
||||
@@ -87,15 +88,15 @@
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</th>
|
||||
<?php if($project->division and $project->hasProduct) echo "<th class='text-left c-product'>{$lang->project->product}</th>";?>
|
||||
<?php if($project->division and $project->hasProduct) echo "<th class='text-left w-100px'>{$lang->project->product}</th>";?>
|
||||
<th class='c-status text-center'><?php echo $lang->project->status;?></th>
|
||||
<th class='c-user'><?php echo $lang->execution->owner;?></th>
|
||||
<th class='w-50px'><?php echo $lang->execution->owner;?></th>
|
||||
<th class='c-date'><?php echo $lang->programplan->begin;?></th>
|
||||
<th class='c-date'><?php echo $lang->programplan->end;?></th>
|
||||
<th class='c-hours text-right'><?php echo $lang->task->estimateAB;?></th>
|
||||
<th class='c-hours text-right'><?php echo $lang->task->consumedAB;?></th>
|
||||
<th class='c-hours text-right'><?php echo $lang->task->leftAB;?> </th>
|
||||
<th class='c-hours'><?php echo $lang->project->progress;?></th>
|
||||
<th class='w-50px text-right'><?php echo $lang->task->estimateAB;?></th>
|
||||
<th class='w-50px text-right'><?php echo $lang->task->consumedAB;?></th>
|
||||
<th class='w-50px text-right'><?php echo $lang->task->leftAB;?> </th>
|
||||
<th class='w-50px'><?php echo $lang->project->progress;?></th>
|
||||
<th class='c-progress'><?php echo $lang->execution->burn;?> </th>
|
||||
<th class='text-center c-actions-6'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
|
||||
@@ -157,12 +157,12 @@ class projectrelease extends control
|
||||
$this->loadModel('story');
|
||||
$this->loadModel('bug');
|
||||
$this->loadModel('build');
|
||||
$this->app->loadConfig('release');
|
||||
$this->loadModel('release');
|
||||
$this->config->projectrelease->create = $this->config->release->create;
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$changes = $this->projectrelease->update($releaseID);
|
||||
$changes = $this->release->update($releaseID);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
$files = $this->loadModel('file')->saveUpload('release', $releaseID);
|
||||
if($changes or $files)
|
||||
@@ -367,9 +367,10 @@ class projectrelease extends control
|
||||
|
||||
$release = $this->dao->select('*')->from(TABLE_RELEASE)->where('id')->eq((int)$releaseID)->fetch();
|
||||
$builds = $this->dao->select('*')->from(TABLE_BUILD)->where('id')->in($release->build)->fetchAll('id');
|
||||
$this->loadModel('build')->delete(TABLE_BUILD, $release->shadow);
|
||||
foreach($builds as $build)
|
||||
{
|
||||
if(empty($build->execution) and empty($build->builds) and $build->createdDate == $release->createdDate) $this->build->delete(TABLE_BUILD, $build->id);
|
||||
if(empty($build->execution) and $build->createdDate == $release->createdDate) $this->build->delete(TABLE_BUILD, $build->id);
|
||||
}
|
||||
|
||||
$message = $this->executeHooks($releaseID);
|
||||
@@ -571,11 +572,8 @@ class projectrelease extends control
|
||||
$this->loadModel('search')->setSearchParams($this->config->product->search);
|
||||
|
||||
$executionIdList = array();
|
||||
foreach($builds as $build)
|
||||
{
|
||||
if(empty($build->execution)) continue;
|
||||
$executionIdList[$build->execution] = $build->execution;
|
||||
}
|
||||
foreach($builds as $build) $executionIdList[] = empty($build->execution) ? $build->project : $build->execution;
|
||||
$executionIdList = array_unique($executionIdList);
|
||||
|
||||
$allStories = array();
|
||||
if($browseType == 'bySearch')
|
||||
|
||||
@@ -77,6 +77,7 @@ class projectreleaseModel extends model
|
||||
$builds = $this->dao->select("id,project,product,execution,name,scmPath,filePath")->from(TABLE_BUILD)->where('id')->in(array_unique($buildIdList))->fetchAll('id');
|
||||
foreach($releases as $release)
|
||||
{
|
||||
$release->buildInfos = array();
|
||||
foreach(explode(',', $release->build) as $buildID)
|
||||
{
|
||||
if(empty($buildID)) continue;
|
||||
@@ -113,53 +114,18 @@ class projectreleaseModel extends model
|
||||
*/
|
||||
public function getReleasedBuilds($projectID)
|
||||
{
|
||||
$releases = $this->dao->select('build')->from(TABLE_RELEASE)
|
||||
$releases = $this->dao->select('shadow,build')->from(TABLE_RELEASE)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere("FIND_IN_SET($projectID, project)")
|
||||
->fetchAll();
|
||||
|
||||
$buildIdList = array();
|
||||
foreach($releases as $release) $buildIdList = array_merge($buildIdList, explode(',', trim($release->build, ',')));
|
||||
return $buildIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a release.
|
||||
*
|
||||
* @param int $releaseID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function update($releaseID)
|
||||
{
|
||||
/* Init vars. */
|
||||
$releaseID = (int)$releaseID;
|
||||
$oldRelease = $this->dao->select('*')->from(TABLE_RELEASE)->where('id')->eq($releaseID)->fetch();
|
||||
|
||||
/* Check build if build is required. */
|
||||
if(strpos($this->config->release->edit->requiredFields, 'build') !== false and $this->post->build == false) return dao::$errors['build'] = sprintf($this->lang->error->notempty, $this->lang->release->build);
|
||||
|
||||
$release = fixer::input('post')->stripTags($this->config->release->editor->edit['id'], $this->config->allowedTags)
|
||||
->setDefault('mailto', '')
|
||||
->join('build', ',')
|
||||
->join('mailto', ',')
|
||||
->setIF(!$this->post->marker, 'marker', 0)
|
||||
->cleanInt('product')
|
||||
->remove('files,labels,allchecker,uid')
|
||||
->get();
|
||||
|
||||
$release = $this->loadModel('file')->processImgURL($release, $this->config->release->editor->edit['id'], $this->post->uid);
|
||||
$this->dao->update(TABLE_RELEASE)->data($release)
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->release->edit->requiredFields, 'notempty')
|
||||
->check('name', 'unique', "id != '$releaseID' AND product = '{$oldRelease->product}' AND branch = '{$oldRelease->branch}' AND deleted = '0'")
|
||||
->where('id')->eq((int)$releaseID)
|
||||
->exec();
|
||||
if(!dao::isError())
|
||||
foreach($releases as $release)
|
||||
{
|
||||
$this->file->updateObjectID($this->post->uid, $releaseID, 'release');
|
||||
return common::createChanges($oldRelease, $release);
|
||||
$buildIdList = array_merge($buildIdList, explode(',', trim($release->build, ',')));
|
||||
$buildIdList[] = $release->shadow;
|
||||
}
|
||||
return $buildIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,11 +67,12 @@
|
||||
<?php
|
||||
$i = 0;
|
||||
$buildCount = count($release->buildInfos);
|
||||
$rowspan = $buildCount > 1 ? "rowspan='$buildCount'" : '';
|
||||
if($buildCount == 0) $release->buildInfos = array('');
|
||||
foreach($release->buildInfos as $buildID => $build):
|
||||
?>
|
||||
<?php if($i == 0):?>
|
||||
<?php $rowspan = $buildCount > 1 ? "rowspan='$buildCount'" : '';?>
|
||||
<tr data-type='<?php echo $release->status;?>'>
|
||||
<?php if($i == 0):?>
|
||||
<td <?php echo $rowspan?>><?php echo html::a(inlink('view', "releaseID=$release->id"), sprintf('%03d', $release->id));?></td>
|
||||
<td <?php echo $rowspan?>>
|
||||
<?php
|
||||
@@ -82,7 +83,9 @@
|
||||
<?php if($project->hasProduct):?>
|
||||
<td <?php echo $rowspan?> title='<?php echo $release->productName?>'><?php echo $release->productName?></td>
|
||||
<?php endif;?>
|
||||
<td class='c-build' title='<?php echo $build->name;?>'><?php echo html::a($this->createLink($build->execution ? 'build' : 'projectbuild', 'view', "buildID=$buildID"), $build->name, '', "data-app='project'");?></td>
|
||||
<?php endif;?>
|
||||
<td class='c-build'><?php if($buildCount) echo html::a($this->createLink($build->execution ? 'build' : 'projectbuild', 'view', "buildID=$buildID"), $build->name, '', "data-app='project' title='<?php echo $build->name;?>'");?></td>
|
||||
<?php if($i == 0):?>
|
||||
<?php $status = $this->processStatus('release', $release);?>
|
||||
<td <?php echo $rowspan?> class='c-status text-center' title='<?php echo $status;?>'>
|
||||
<span class="status-release status-<?php echo $release->status?>"><?php echo $status;?></span>
|
||||
@@ -90,12 +93,8 @@
|
||||
<td <?php echo $rowspan?> class='text-center'><?php echo $release->date;?></td>
|
||||
<?php foreach($extendFields as $extendField) echo "<td $rowspan>" . $this->loadModel('flow')->getFieldValue($extendField, $release) . "</td>";?>
|
||||
<td <?php echo $rowspan?> class='c-actions'><?php echo $this->projectrelease->buildOperateMenu($release, 'browse');?></td>
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
<?php else:?>
|
||||
<tr>
|
||||
<td class='c-build' title='<?php echo $build->name;?>'><?php echo html::a($this->createLink($build->execution ? 'build' : 'projectbuild', 'view', "buildID=$buildID"), $build->name, '', "data-app='project'");?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<?php $i++; ?>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
|
||||
@@ -26,13 +26,18 @@
|
||||
<th><?php echo $lang->release->name;?></th>
|
||||
<td><?php echo html::input('name', '', "class='form-control' required");?></td>
|
||||
<td>
|
||||
<?php if(!$product->shadow):?>
|
||||
<div id='markerBox' class='checkbox-primary'>
|
||||
<input id='marker' name='marker' value='1' type='checkbox' />
|
||||
<label for='marker'><?php echo $lang->release->marker;?></label>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php if($lastRelease) echo '(' . $lang->release->last . ': ' . $lastRelease->name . ')';?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if($product->shadow):?>
|
||||
<?php echo html::hidden('product', $product->id);?>
|
||||
<?php else:?>
|
||||
<tr>
|
||||
<th><?php echo $lang->release->product;?></th>
|
||||
<td>
|
||||
@@ -43,12 +48,11 @@
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->release->build;?></th>
|
||||
<td id='buildBox'><?php echo html::select('build[]', $builds, '', "class='form-control chosen' multiple");?></td>
|
||||
<td>
|
||||
<icon class='icon icon-help' data-toggle='popover' data-trigger='focus hover' data-placement='right' data-tip-class='text-muted popover-sm' data-content="<?php echo $lang->release->tips;?>"></icon>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->release->date;?></th>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->release->build;?></th>
|
||||
<td><?php echo html::select('build[]', $builds, $release->build, "class='form-control chosen' multiple required"); ?></td><td></td>
|
||||
<td><?php echo html::select('build[]', $builds, $release->build, "class='form-control chosen' multiple"); ?></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->release->date;?></th>
|
||||
|
||||
@@ -40,7 +40,7 @@ class projectStory extends control
|
||||
if($projectID)
|
||||
{
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if(!$project->hasProduct) $productID = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetch('product');
|
||||
if(!$project->hasProduct) $productID = $this->loadModel('product')->getShadowProductByProject($projectID)->id;
|
||||
}
|
||||
|
||||
$this->products = $this->loadModel('product')->getProductPairsByProject($projectID);
|
||||
|
||||
@@ -3,7 +3,7 @@ $config->release = new stdclass();
|
||||
$config->release->create = new stdclass();
|
||||
$config->release->edit = new stdclass();
|
||||
$config->release->create->requiredFields = 'name,date';
|
||||
$config->release->edit->requiredFields = 'name,build,date';
|
||||
$config->release->edit->requiredFields = 'name,date';
|
||||
|
||||
$config->release->editor = new stdclass();
|
||||
$config->release->editor->create = array('id' => 'desc', 'tools' => 'simpleTools');
|
||||
|
||||
@@ -302,7 +302,11 @@ class release extends control
|
||||
|
||||
$release = $this->dao->select('*')->from(TABLE_RELEASE)->where('id')->eq((int)$releaseID)->fetch();
|
||||
$build = $this->dao->select('*')->from(TABLE_BUILD)->where('id')->eq((int)$release->build)->fetch();
|
||||
if(empty($build->execution)) $this->loadModel('build')->delete(TABLE_BUILD, $build->id);
|
||||
$this->loadModel('build')->delete(TABLE_BUILD, $release->shadow);
|
||||
foreach($builds as $build)
|
||||
{
|
||||
if(empty($build->execution) and $build->createdDate == $release->createdDate) $this->build->delete(TABLE_BUILD, $build->id);
|
||||
}
|
||||
|
||||
$message = $this->executeHooks($releaseID);
|
||||
if($message) $response['message'] = $message;
|
||||
@@ -320,7 +324,6 @@ class release extends control
|
||||
$response['result'] = 'success';
|
||||
$response['message'] = '';
|
||||
$release = $this->release->getById($releaseID);
|
||||
$this->dao->update(TABLE_BUILD)->set('deleted')->eq(1)->where('id')->eq($release->build)->andWhere('name')->eq($release->name)->exec();
|
||||
}
|
||||
|
||||
return $this->send($response);
|
||||
@@ -525,7 +528,7 @@ class release extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
$allStories = $this->story->getExecutionStories($executionIdList, $build->product, 0, 't1.`order`_desc', 'byBranch', $release->branch, 'story', $release->stories, $pager);
|
||||
$allStories = $this->story->getExecutionStories($executionIdList, $release->product, 0, 't1.`order`_desc', 'byBranch', $release->branch, 'story', $release->stories, $pager);
|
||||
}
|
||||
|
||||
$this->view->allStories = $allStories;
|
||||
|
||||
@@ -30,7 +30,6 @@ $lang->release->confirmUnlinkBug = "Möchten Sie diesen Bug löschen?";
|
||||
$lang->release->existBuild = '『Build』『%s』 existiert bereits. Sie können den 『name』 ändern oder ein anderes 『build』 wählen.';
|
||||
$lang->release->noRelease = 'Keine Releases. ';
|
||||
$lang->release->errorDate = 'The release date should not be greater than today.';
|
||||
$lang->release->tips = 'If no build is selected for a release, a build with the same name as the release is created by default.';
|
||||
|
||||
$lang->release->basicInfo = 'Basis Info';
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ $lang->release->confirmUnlinkBug = "Do you want to remove this bug?";
|
||||
$lang->release->existBuild = '『Build』『%s』existed. You could change『name』or choose a『build』.';
|
||||
$lang->release->noRelease = 'No releases yet.';
|
||||
$lang->release->errorDate = 'The release date should not be greater than today.';
|
||||
$lang->release->tips = 'If no build is selected for a release, a build with the same name as the release is created by default.';
|
||||
|
||||
$lang->release->basicInfo = 'Basic Info';
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ $lang->release->confirmUnlinkBug = "Voulez-vous retirer ce bug de la release ?
|
||||
$lang->release->existBuild = '『Build』『%s』existant. Vous pouvez changer『name』ou choisir un『build』.';
|
||||
$lang->release->noRelease = 'Pas de release à ce jour.';
|
||||
$lang->release->errorDate = "La date de release ne doit pas être supérieure à aujourd'hui.";
|
||||
$lang->release->tips = 'If no build is selected for a release, a build with the same name as the release is created by default.';
|
||||
|
||||
$lang->release->basicInfo = 'Infos de Base';
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ $lang->release->confirmUnlinkBug = "您确认移除该Bug吗?";
|
||||
$lang->release->existBuild = '『版本』已经有『%s』这条记录了。您可以更改『发布名称』或者选择一个『版本』。';
|
||||
$lang->release->noRelease = '暂时没有发布。';
|
||||
$lang->release->errorDate = '发布日期不能大于今天。';
|
||||
$lang->release->tips = '如果发布未选择任何版本,系统会默认创建一个和该发布同名的版本。';
|
||||
|
||||
$lang->release->basicInfo = '基本信息';
|
||||
|
||||
|
||||
+49
-50
@@ -66,7 +66,7 @@ class releaseModel extends model
|
||||
->page($pager)
|
||||
->fetchAll();
|
||||
|
||||
$builds = $this->dao->select("t1.id, t1.name, t1.execution, IF(t2.name IS NOT NULL, t2.name, '') AS projectName, IF(t3.name IS NOT NULL, t3.name, '{$this->lang->trunk}') AS branchName")
|
||||
$builds = $this->dao->select("t1.id, t1.name, t1.project, t1.execution, IF(t2.name IS NOT NULL, t2.name, '') AS projectName, IF(t3.name IS NOT NULL, t3.name, '{$this->lang->trunk}') AS branchName")
|
||||
->from(TABLE_BUILD)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
|
||||
->leftJoin(TABLE_BRANCH)->alias('t3')->on('t1.branch = t3.id')
|
||||
@@ -116,19 +116,30 @@ class releaseModel extends model
|
||||
*/
|
||||
public function getReleasedBuilds($productID, $branch = 'all')
|
||||
{
|
||||
$builds = $this->dao->select('build')->from(TABLE_RELEASE)
|
||||
$releases = $this->dao->select('branch,shadow,build')->from(TABLE_RELEASE)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('product')->eq($productID)
|
||||
->beginIF($branch !== 'all')->andWhere('branch')->eq($branch)->fi()
|
||||
->fetchPairs('build');
|
||||
->fetchAll();
|
||||
|
||||
$buildIDList = array();
|
||||
foreach($builds as $build)
|
||||
$buildIdList = array();
|
||||
foreach($releases as $release)
|
||||
{
|
||||
$build = explode(',', $build);
|
||||
$buildIDList = array_merge($buildIDList, $build);
|
||||
if($branch != 'all')
|
||||
{
|
||||
$inBranch = false;
|
||||
foreach(explode(',', trim($release->branch, ',')) as $branchID)
|
||||
{
|
||||
if(empty($branchID)) continue;
|
||||
if(strpos(",{$branch},", ",{$branchID},") !== false) $inBranch = true;
|
||||
}
|
||||
if(!$inBranch) continue;
|
||||
}
|
||||
|
||||
$builds = explode(',', $release->build);
|
||||
$buildIdList = array_merge($buildIdList, $builds);
|
||||
$buildIdList[] = $release->shadow;
|
||||
}
|
||||
return $buildIDList;
|
||||
return $buildIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,6 +182,7 @@ class releaseModel extends model
|
||||
->setIF($projectID, 'project', $projectID)
|
||||
->setIF($this->post->build == false, 'build', 0)
|
||||
->setDefault('stories', '')
|
||||
->setDefault('bugs', '')
|
||||
->setDefault('createdBy', $this->app->user->account)
|
||||
->setDefault('createdDate', helper::now())
|
||||
->join('build', ',')
|
||||
@@ -181,50 +193,25 @@ class releaseModel extends model
|
||||
->remove('allchecker,files,labels,uid,sync')
|
||||
->get();
|
||||
|
||||
/* Auto create build when release is not link build. */
|
||||
if(empty($release->build) and $release->name)
|
||||
/* Auto create shadow build. */
|
||||
if($release->name)
|
||||
{
|
||||
$build = $this->dao->select('*')->from(TABLE_BUILD)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere('name')->eq($release->name)
|
||||
->andWhere('product')->eq($productID)
|
||||
->andWhere('branch')->eq($branch)
|
||||
->fetch();
|
||||
if($build)
|
||||
{
|
||||
return dao::$errors['build'] = sprintf($this->lang->release->existBuild, $release->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
$build = new stdclass();
|
||||
$build->project = $projectID;
|
||||
$build->product = (int)$productID;
|
||||
$build->branch = (int)$branch;
|
||||
$build->name = $release->name;
|
||||
$build->date = $release->date;
|
||||
$build->builder = $this->app->user->account;
|
||||
$build->desc = $release->desc;
|
||||
$build->execution = 0;
|
||||
$build->createdBy = $this->app->user->account;
|
||||
$build->createdDate = helper::now();
|
||||
$shadowBuild = new stdclass();
|
||||
$shadowBuild->product = $release->product;
|
||||
$shadowBuild->builds = $release->build;
|
||||
$shadowBuild->name = $release->name;
|
||||
$shadowBuild->date = $release->date;
|
||||
$shadowBuild->createdBy = $this->app->user->account;
|
||||
$shadowBuild->createdDate = helper::now();
|
||||
$this->dao->insert(TABLE_BUILD)->data($shadowBuild)->exec();
|
||||
|
||||
$build = $this->loadModel('file')->processImgURL($build, $this->config->release->editor->create['id']);
|
||||
$this->app->loadLang('build');
|
||||
$this->dao->insert(TABLE_BUILD)->data($build)
|
||||
->autoCheck()
|
||||
->check('name', 'unique', "product = {$productID} AND branch = {$branch} AND deleted = '0'")
|
||||
->batchCheck($this->config->release->create->requiredFields, 'notempty')
|
||||
->exec();
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$buildID = $this->dao->lastInsertID();
|
||||
$release->build = $buildID;
|
||||
}
|
||||
if(dao::isError()) return false;
|
||||
$release->shadow = $this->dao->lastInsertID();
|
||||
}
|
||||
|
||||
if($release->build)
|
||||
{
|
||||
$builds = $this->dao->select('project, branch, stories, bugs')->from(TABLE_BUILD)->where('id')->in($release->build)->fetchAll();
|
||||
$builds = $this->dao->select('id,project,branch,stories,bugs')->from(TABLE_BUILD)->where('id')->in($release->build)->fetchAll('id');
|
||||
foreach($builds as $build)
|
||||
{
|
||||
$branches[$build->branch] = $build->branch;
|
||||
@@ -238,11 +225,17 @@ class releaseModel extends model
|
||||
if($build->bugs) $release->bugs .= ',' . $build->bugs;
|
||||
}
|
||||
}
|
||||
if($this->post->sync == 'true' and $release->bugs)
|
||||
{
|
||||
$releaseBugs = $this->loadModel('bug')->getReleaseBugs(array_keys($builds), $release->product, $release->branch);
|
||||
$release->bugs = join(',', array_intersect(explode(',', $release->bugs), array_keys($releaseBugs)));
|
||||
}
|
||||
|
||||
$release->build = ',' . trim($release->build, ',') . ',';
|
||||
$release->branch = ',' . trim(implode(',', $branches), ',') . ',';
|
||||
$release->project = ',' . trim(implode(',', $projects), ',') . ',';
|
||||
}
|
||||
|
||||
$release = $this->loadModel('file')->processImgURL($release, $this->config->release->editor->create['id'], $this->post->uid);
|
||||
$this->dao->insert(TABLE_RELEASE)->data($release)
|
||||
->autoCheck()
|
||||
@@ -252,7 +245,7 @@ class releaseModel extends model
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
if(!empty($buildID)) $this->dao->delete()->from(TABLE_BUILD)->where('id')->eq($buildID)->exec();
|
||||
if(!empty($release->shadow)) $this->dao->delete()->from(TABLE_BUILD)->where('id')->eq($release->shadow)->exec();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -260,7 +253,7 @@ class releaseModel extends model
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
if(!empty($buildID)) $this->dao->delete()->from(TABLE_BUILD)->where('id')->eq($buildID)->exec();
|
||||
if(!empty($release->shadow)) $this->dao->delete()->from(TABLE_BUILD)->where('id')->eq($release->shadow)->exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -304,7 +297,7 @@ class releaseModel extends model
|
||||
$oldRelease = $this->getById($releaseID);
|
||||
|
||||
$release = fixer::input('post')->stripTags($this->config->release->editor->edit['id'], $this->config->allowedTags)
|
||||
->add('id', $releaseID)
|
||||
->setDefault('build', '')
|
||||
->setDefault('mailto', '')
|
||||
->setDefault('deleteFiles', array())
|
||||
->join('build', ',')
|
||||
@@ -339,6 +332,12 @@ class releaseModel extends model
|
||||
->exec();
|
||||
if(!dao::isError())
|
||||
{
|
||||
$shadowBuild = array();
|
||||
if($release->name != $oldRelease->name) $shadowBuild['name'] = $release->name;
|
||||
if($release->build != $oldRelease->build) $shadowBuild['builds'] = $release->build;
|
||||
if($release->date != $oldRelease->date) $shadowBuild['date'] = $release->date;
|
||||
if($shadowBuild) $this->dao->update(TABLE_BUILD)->data($shadowBuild)->where('id')->eq($oldRelease->shadow)->exec();
|
||||
|
||||
$this->file->processFile4Object('release', $oldRelease, $release);
|
||||
return common::createChanges($oldRelease, $release);
|
||||
}
|
||||
|
||||
@@ -63,15 +63,21 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$this->loadModel('project');
|
||||
$this->loadModel('execution');
|
||||
?>
|
||||
<?php foreach($releases as $release):?>
|
||||
<?php $canBeChanged = common::canBeChanged('release', $release);?>
|
||||
<?php $buildCount = count($release->builds);?>
|
||||
<?php $buildCount = count($release->builds);?>
|
||||
<?php $rowspan = $buildCount > 1 ? "rowspan='{$buildCount}'" : '';?>
|
||||
<?php $i = 1;?>
|
||||
<?php if($buildCount == 0) $release->builds = array('');?>
|
||||
<?php foreach($release->builds as $build):?>
|
||||
<tr data-type='<?php echo $release->status;?>'>
|
||||
<?php if($i == 1):?>
|
||||
<td rowspan="<?php echo $buildCount;?>"><?php echo html::a(inlink('view', "releaseID=$release->id"), sprintf('%03d', $release->id));?></td>
|
||||
<td rowspan="<?php echo $buildCount;?>">
|
||||
<td <?php echo $rowspan?>><?php echo html::a(inlink('view', "releaseID=$release->id"), sprintf('%03d', $release->id));?></td>
|
||||
<td <?php echo $rowspan?>>
|
||||
<?php
|
||||
$flagIcon = $release->marker ? "<icon class='icon icon-flag red' title='{$lang->release->marker}'></icon> " : '';
|
||||
echo html::a(inlink('view', "release=$release->id"), $release->name, '', "title='$release->name'") . $flagIcon;
|
||||
@@ -79,20 +85,28 @@
|
||||
</td>
|
||||
<?php endif;?>
|
||||
<td>
|
||||
<?php if($buildCount):?>
|
||||
<?php if($product->type != 'normal'):?>
|
||||
<span class='label label-outline label-badge'><?php echo $build->branchName;?></span>
|
||||
<?php endif;?>
|
||||
<?php echo html::a($this->createLink($build->execution ? 'build' : 'projectbuild', 'view', "buildID=$build->id"), $build->name);?>
|
||||
<?php
|
||||
$moduleName = $build->execution ? 'build' : 'projectbuild';
|
||||
$canClickable = false;
|
||||
if($moduleName == 'projectbuild' and $this->project->checkPriv($build->project)) $canClickable = true;
|
||||
if($moduleName == 'build' and $this->execution->checkPriv($build->execution)) $canClickable = true;
|
||||
echo $canClickable ? html::a($this->createLink($moduleName, 'view', "buildID=$build->id"), $build->name, '', "data-app='project'") : $build->name;
|
||||
?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td><?php echo $build->projectName;?></td>
|
||||
<td><?php if($buildCount) echo $build->projectName;?></td>
|
||||
<?php if($i == 1):?>
|
||||
<?php $status = $this->processStatus('release', $release);?>
|
||||
<td class='c-status text-center' title='<?php echo $status;?>' rowspan="<?php echo $buildCount;?>">
|
||||
<td class='c-status text-center' title='<?php echo $status;?>' <?php echo $rowspan?>>
|
||||
<span class="status-release status-<?php echo $release->status?>"><?php echo $status;?></span>
|
||||
</td>
|
||||
<td class='text-center' rowspan="<?php echo $buildCount;?>"><?php echo $release->date;?></td>
|
||||
<?php foreach($extendFields as $extendField) echo "<td rowspan='{$buildCount}'>" . $this->loadModel('flow')->getFieldValue($extendField, $release) . "</td>";?>
|
||||
<td class='c-actions' rowspan="<?php echo $buildCount;?>"><?php echo $this->release->buildOperateMenu($release, 'browse');?></td>
|
||||
<td class='text-center' <?php echo $rowspan?>><?php echo $release->date;?></td>
|
||||
<?php foreach($extendFields as $extendField) echo "<td $rowspan>" . $this->loadModel('flow')->getFieldValue($extendField, $release) . "</td>";?>
|
||||
<td class='c-actions' <?php echo $rowspan?>><?php echo $this->release->buildOperateMenu($release, 'browse');?></td>
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
<?php $i++;?>
|
||||
|
||||
@@ -36,9 +36,7 @@
|
||||
<tr>
|
||||
<th><?php echo $lang->release->build;?></th>
|
||||
<td><?php echo html::select('build[]', $builds, '', "class='form-control chosen' multiple");?></td>
|
||||
<td>
|
||||
<icon class='icon icon-help' data-toggle='popover' data-trigger='focus hover' data-placement='right' data-tip-class='text-muted popover-sm' data-content="<?php echo $lang->release->tips;?>"></icon>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->release->date;?></th>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->release->build;?></th>
|
||||
<td><?php echo html::select('build[]', $builds, $release->build, "class='form-control chosen' required multiple"); ?></td>
|
||||
<td><?php echo html::select('build[]', $builds, $release->build, "class='form-control chosen' multiple"); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->release->date;?></th>
|
||||
|
||||
@@ -356,7 +356,12 @@
|
||||
$buildHtml = array();
|
||||
foreach($release->builds as $build)
|
||||
{
|
||||
$buildHtml[] = html::a($this->createLink($build->execution ? 'build' : 'projectbuild', 'view', "buildID=$build->id"), $build->name, '', "data-app='project'");
|
||||
$moduleName = $build->execution ? 'build' : 'projectbuild';
|
||||
$canClickable = false;
|
||||
if($moduleName == 'projectbuild' and $this->loadModel('project')->checkPriv($build->project)) $canClickable = true;
|
||||
if($moduleName == 'build' and $this->loadModel('execution')->checkPriv($build->execution)) $canClickable = true;
|
||||
|
||||
$buildHtml[] = $canClickable ? html::a($this->createLink($moduleName, 'view', "buildID=$build->id"), $build->name, '', "data-app='project'") : $build->name;
|
||||
}
|
||||
echo join($lang->comma, $buildHtml);
|
||||
?>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user