Merge branch 'master' into zenops_46

This commit is contained in:
caoyanyi
2022-11-22 15:39:59 +08:00
180 changed files with 1118 additions and 602 deletions
+1 -1
View File
@@ -410,7 +410,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'));
+2 -2
View File
@@ -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`),
+2 -2
View File
@@ -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
View File
@@ -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":{}}');
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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 项目起止时间选择框,宽度不一致。前面窄后面的宽。
@@ -1,6 +1,7 @@
<?php
$lang->action->label->execution = "Kanban|execution|task|executionID=%s";
$lang->action->label->task = 'Task|task|view|taskID=%s';
$lang->action->label->module = 'Katalog|tree|browse|productid=%s&type=story&currentModuleID=0&branch=all';
/* Object type. */
$lang->action->objectTypes['execution'] = 'Project' . $lang->executionCommon;
@@ -1,6 +1,7 @@
<?php
$lang->action->label->execution = "Kanban|execution|task|executionID=%s";
$lang->action->label->task = 'Task|task|view|taskID=%s';
$lang->action->label->module = 'Catalog|tree|browse|productid=%s&type=story&currentModuleID=0&branch=all';
/* Object type. */
$lang->action->objectTypes['execution'] = 'Project' . $lang->executionCommon;
@@ -1,6 +1,7 @@
<?php
$lang->action->label->execution = "Kanban|execution|task|executionID=%s";
$lang->action->label->task = 'Task|task|view|taskID=%s';
$lang->action->label->module = 'Table des matières|tree|browse|productid=%s&type=story&currentModuleID=0&branch=all';
/* Object type. */
$lang->action->objectTypes['execution'] = 'Project' . $lang->executionCommon;
@@ -1,6 +1,7 @@
<?php
$lang->action->label->execution = "看板|execution|task|executionID=%s";
$lang->action->label->task = '任务|task|view|taskID=%s';
$lang->action->label->module = '目录|tree|browse|productid=%s&type=story&currentModuleID=0&branch=all';
/* Object type. */
$lang->action->objectTypes['execution'] = '项目' . $lang->executionCommon;
@@ -5,6 +5,7 @@ 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->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. */
@@ -39,6 +39,7 @@ 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%;}
@@ -203,7 +204,7 @@ js::set('URAndSR', $this->config->URAndSR);
<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>
+3 -1
View File
@@ -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']);
+8 -1
View File
@@ -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,10 +107,17 @@ class helper extends baseHelper
if($feature == $group or $feature == $module)
{
$canConfigFeature = 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;
}
}
}
}
return !$canConfigFeature or ($hasFeature && strpos(",$config->disabledFeatures,", ",{$feature},") === false);
}
}
+2 -2
View File
@@ -521,8 +521,8 @@ class baseHTML
/* If the link of the referer is not the link of the current page or the link of the index, the cookie and gobackLink will be updated. */
if(!preg_match("/(m=|\/)(index|search|$currentModule)(&f=|-)(index|buildquery|$currentMethod)(&|-|\.)?/", strtolower($refererLink)))
{
$gobackList[$tab] = $referer . "#app=$tab";
$gobackLink = $referer . "#app=$tab";
$gobackList[$tab] = $referer;
$gobackLink = $referer;
setcookie('goback', json_encode($gobackList), $config->cookieLife, $config->webRoot, '', $config->cookieSecure, false);
}
+1 -1
View File
@@ -223,7 +223,7 @@ class zfile
*
* @param string $patern
* @access public
* @return avoid
* @return void
*/
public function batchRemoveFile($patern)
{
+1 -1
View File
@@ -231,7 +231,7 @@ $lang->action->desc->suspend = '$date, 由 <strong>$actor</strong>
$lang->action->desc->resume = '$date, 由 <strong>$actor</strong> 恢复。' . "\n";
$lang->action->desc->reboot = '$date, 由 <strong>$actor</strong> 重启。' . "\n";
$lang->action->desc->destroy = '$date, 由 <strong>$actor</strong> 销毁。' . "\n";
$lang->action->desc->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";
/* 用来描述和父子任务相关的操作历史记录。*/
-10
View File
@@ -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();
+9 -1
View File
@@ -11,5 +11,13 @@ $(function()
{
$("input[name='" + name + "'][type=hidden]").val('0').attr('disabled', false);
}
})
});
$('input[name=allChecker]').change(function()
{
$(this).closest('tr').find("input[name^='module']").prop('checked', $(this).prop('checked')).change();
});
$('#allChecker').change(function()
{
$('input[name=allChecker]').prop('checked', $(this).prop('checked')).change();
});
})
+16 -20
View File
@@ -20,12 +20,8 @@
<table class='table table-condensed table-bordered active-disabled table-fixed'>
<thead class='text-center'>
<tr>
<th rowspan='2' class='w-120px'><?php echo $lang->admin->setModule->module;?></th>
<th colspan='2'><?php echo $lang->admin->setModule->optional;?></th>
</tr>
<tr>
<th><?php echo $lang->admin->setModule->opened;?></th>
<th><?php echo $lang->admin->setModule->closed;?></th>
<th class='w-200px'><?php echo $lang->admin->setModule->module;?></th>
<th><?php echo $lang->admin->setModule->optional;?></th>
</tr>
</thead>
<tbody>
@@ -41,26 +37,20 @@
<?php if($hasData):?>
<tr>
<td class='text-right'><?php echo $lang->admin->setModule->{$group};?></td>
<td>
<?php foreach($features as $feature):?>
<?php $code = $group. ucfirst($feature);?>
<?php if(strpos(",$disabledFeatures,", ",$code,") !== false) continue;?>
<?php if(strpos(",$closedFeatures,", ",$code,") !== false) continue;?>
<div class='group-item'>
<?php echo html::checkbox("module[{$code}]", array('1' => $lang->admin->setModule->{$feature}), '1', "data-code='{$code}'", 'inline');?>
<?php echo html::hidden("module[{$code}][]", '1', 'disabled');?>
<td class='text-middle text-right thWidth'>
<div class="checkbox-primary checkbox-inline checkbox-right check-all">
<input type='checkbox' id='allChecker<?php echo $group;?>' name='allChecker'>
<label class='text-right' for='allChecker<?php echo $group;?>'><?php echo $lang->admin->setModule->{$group};?></label>
</div>
<?php endForeach;?>
</td>
<td>
<?php foreach($features as $feature):?>
<?php $code = $group. ucfirst($feature);?>
<?php if(strpos(",$disabledFeatures,", ",$code,") !== false) continue;?>
<?php if(strpos(",$closedFeatures,", ",$code,") === false) continue;?>
<?php $value = strpos(",$closedFeatures,", ",$code,") === false ? '1' : '0';?>
<div class='group-item'>
<?php echo html::checkbox("module[{$code}]", array('1' => $lang->admin->setModule->{$feature}), '0', "data-code='{$code}'", 'inline');?>
<?php echo html::hidden("module[{$code}][]", '0');?>
<?php echo html::checkbox("module[{$code}]", array('1' => $lang->admin->setModule->{$feature}), $value, "data-code='{$code}'", 'inline');?>
<?php echo html::hidden("module[{$code}][]", $value, $value ? 'disabled' : '');?>
</div>
<?php endForeach;?>
</td>
@@ -68,7 +58,13 @@
<?php endif;?>
<?php endForeach;?>
<tr>
<td colspan='3' class='text-center'><?php echo html::submitButton();?></td>
<td class='text-middle text-right thWidth'>
<div class="checkbox-primary checkbox-inline checkbox-right check-all">
<input type='checkbox' id='allChecker'>
<label class='text-right' for='allChecker'><?php echo $lang->selectAll;?></label>
</div>
</td>
<td><?php echo html::submitButton();?></td>
</tr>
</tbody>
</table>
+4 -3
View File
@@ -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>');
+18 -4
View File
@@ -1244,8 +1244,12 @@ class bug extends control
$branchProduct = $product->type == 'normal' ? false : true;
/* Set plans. */
$plans = $this->loadModel('productplan')->getPairs($productID, $branch, '', true);
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;
@@ -2045,7 +2049,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']);
}
}
}
@@ -2354,6 +2362,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);
}
@@ -2426,6 +2436,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;
@@ -2433,8 +2449,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();
}
+14 -3
View File
@@ -588,12 +588,12 @@ function loadExecutionBuilds(executionID, num)
{
if(typeof(num) == 'undefined') num = '';
var branch = $('#branch' + num).val();
if(typeof(branch) == 'undefined') var branch = 0;
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=&param=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;
}
}
+2 -14
View File
@@ -2126,7 +2126,7 @@ class bugModel extends model
*/
public function getLinkedExecutionByIdList($buildIdList)
{
$builds = $this->dao->select('id,execution')->from(TABLE_BUILD)->where('id')->in($buildIdList)->fetchAll('id');
$builds = $this->dao->select('id,execution,builds')->from(TABLE_BUILD)->where('id')->in($buildIdList)->fetchAll('id');
$executionIdList = array();
$linkedBuildIdList = array();
@@ -3490,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);
+2 -2
View File
@@ -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}'");
+1 -1
View File
@@ -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')
+2
View File
@@ -422,6 +422,7 @@
<td><?php echo html::a($this->createLink('task', 'view', "taskID=$bug->toTask", '', true), "#$bug->toTask $bug->toTaskTitle", '', "class='iframe' data-width='80%'");?></td>
</tr>
<?php endif;?>
<?php if(helper::hasFeature('devops')):?>
<tr>
<th><?php echo $lang->bug->linkMR;?></th>
<td>
@@ -448,6 +449,7 @@
?>
</td>
</tr>
<?php endif;?>
</tbody>
</table>
</div>
+18 -21
View File
@@ -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');
@@ -172,7 +177,7 @@ class build extends control
{
$productGroups = $this->product->getProducts($build->project);
$branches = $this->loadModel('branch')->getList($build->product, $build->project, 'all');
$builds = $this->build->getBuildPairs($build->product, $build->branch, 'noempty,notrunk,separate,noproject', $build->project, 'project');
$builds = $this->build->getBuildPairs($build->product, $build->branch, 'noempty,notrunk,separate', $build->project, 'project', $build->builds, false);
}
$executions = $this->product->getExecutionPairsByProduct($build->product, $build->branch, 'id_desc', $this->session->project, 'stagefilter');
@@ -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');
@@ -453,7 +450,7 @@ class build extends control
}
if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$builds = $this->build->getBuildPairs($productID, $branch, $type, $projectID, 'project', $build);
$builds = $this->build->getBuildPairs($productID, $branch, $type, $projectID, 'project', $build, false);
if(strpos($extra, 'multiple') !== false) $varName .= '[]';
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName, $builds, $build, "class='form-control chosen' $extra"));
@@ -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;
+51 -1
View File
@@ -12,8 +12,58 @@ $().ready(function()
$.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();
$('#builds').attr('data-placeholder', multipleSelect).chosen();
});
});
$('input[name=isIntegrated]').change(function()
{
if($(this).val() == 'no')
{
$('#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());
}
});
}
+1 -1
View File
@@ -14,7 +14,7 @@ $().ready(function()
$.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();
$('#builds').attr('data-placeholder', multipleSelect).chosen();
});
}
});
+6 -1
View File
@@ -33,6 +33,8 @@ $lang->build->project = 'Project';
$lang->build->branch = 'Platform/Branch';
$lang->build->branchName = '%s';
$lang->build->execution = $lang->executionCommon;
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Linked Builds';
$lang->build->name = 'Name';
$lang->build->date = 'Datum';
@@ -66,10 +68,13 @@ $lang->build->createdBugs = ' %s Bugs wurden erstellt.';
$lang->build->placeholder = new stdclass();
$lang->build->placeholder->scmPath = ' Source code repository, z.B. Subversion/Git Pfad';
$lang->build->placeholder->filePath = ' Pfad zum Download für diese Build.';
$lang->build->placeholder->multipleSelect = "Support select multiple builds";
$lang->build->action = new stdclass();
$lang->build->action->buildopened = '$date, erstellt von <strong>$actor</strong>, Build <strong>$extra</strong>.' . "\n";
$lang->backhome = 'zurück';
$lang->build->featureBar['browse']['all'] = 'Build List';
$lang->build->isIntegrated = array();
$lang->build->isIntegrated['no'] = 'No';
$lang->build->isIntegrated['yes'] = 'Yes';
+6 -1
View File
@@ -33,6 +33,8 @@ $lang->build->project = 'Project';
$lang->build->branch = 'Platform/Branch';
$lang->build->branchName = '%s';
$lang->build->execution = $lang->executionCommon;
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Linked Builds';
$lang->build->name = 'Name';
$lang->build->date = 'Date';
@@ -66,10 +68,13 @@ $lang->build->createdBugs = ' Reported Bug %s';
$lang->build->placeholder = new stdclass();
$lang->build->placeholder->scmPath = ' Source code repository, e.g. Subversion/Git Library path';
$lang->build->placeholder->filePath = ' Download path for this Build.';
$lang->build->placeholder->multipleSelect = "Support select multiple builds";
$lang->build->action = new stdclass();
$lang->build->action->buildopened = '$date, created by <strong>$actor</strong>, Build <strong>$extra</strong>.' . "\n";
$lang->backhome = 'back';
$lang->build->featureBar['browse']['all'] = 'Build List';
$lang->build->isIntegrated = array();
$lang->build->isIntegrated['no'] = 'No';
$lang->build->isIntegrated['yes'] = 'Yes';
+6 -1
View File
@@ -33,6 +33,8 @@ $lang->build->project = 'Project';
$lang->build->branch = 'Plateforme/Branche';
$lang->build->branchName = '%s';
$lang->build->execution = $lang->executionCommon;
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Linked Builds';
$lang->build->name = 'Nom';
$lang->build->date = 'Date';
@@ -66,10 +68,13 @@ $lang->build->createdBugs = ' Bugs Signalés %s';
$lang->build->placeholder = new stdclass();
$lang->build->placeholder->scmPath = ' Répertoire des codes sources, ex: chemin de la bibliothèque Subversion / GitSource';
$lang->build->placeholder->filePath = ' Chemin de téléchargement pour ce Build.';
$lang->build->placeholder->multipleSelect = "Support select multiple builds";
$lang->build->action = new stdclass();
$lang->build->action->buildopened = '$date, Build <strong>$extra</strong> créé par <strong>$actor</strong>.' . "\n";
$lang->backhome = 'Retour';
$lang->build->featureBar['browse']['all'] = 'Build List';
$lang->build->isIntegrated = array();
$lang->build->isIntegrated['no'] = 'No';
$lang->build->isIntegrated['yes'] = 'Yes';
+7
View File
@@ -33,6 +33,8 @@ $lang->build->project = '所属项目';
$lang->build->branch = '平台/分支';
$lang->build->branchName = '所属%s';
$lang->build->execution = '所属' . $lang->executionCommon;
$lang->build->integrated = '集成版本';
$lang->build->singled = '单一版本';
$lang->build->builds = '关联版本';
$lang->build->name = '名称编号';
$lang->build->date = '打包日期';
@@ -66,8 +68,13 @@ $lang->build->createdBugs = ' 本次共产生 %s 个Bug';
$lang->build->placeholder = new stdclass();
$lang->build->placeholder->scmPath = ' 软件源代码库,如Subversion、Git库地址';
$lang->build->placeholder->filePath = ' 该版本软件包下载存储地址';
$lang->build->placeholder->multipleSelect = "版本支持多选";
$lang->build->action = new stdclass();
$lang->build->action->buildopened = '$date, 由 <strong>$actor</strong> 创建版本 <strong>$extra</strong>。' . "\n";
$lang->backhome = '返回';
$lang->build->isIntegrated = array();
$lang->build->isIntegrated['no'] = '否';
$lang->build->isIntegrated['yes'] = '是';
+64 -50
View File
@@ -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,7 +227,7 @@ 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)")
@@ -234,7 +235,7 @@ class buildModel extends model
->leftJoin(TABLE_PRODUCT)->alias('t5')->on('t1.product = t5.id')
->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(strpos($params, 'noproject') !== false)->andWhere('t1.project')->ne(0)->fi()
->beginIF($products)->andWhere('t1.product')->in($products)->fi()
->beginIF($objectType === 'execution' and $objectID)->andWhere('t1.execution')->eq($objectID)->fi()
->beginIF($objectType === 'project' and $objectID)->andWhere('t1.project')->eq($objectID)->fi()
@@ -243,8 +244,9 @@ class buildModel extends model
/* Set builds and filter done executions and terminate releases. */
$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,isIntegrated,uid')
->get();
if($this->post->isIntegrated == 'yes') $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;
}
/**
+12 -4
View File
@@ -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->integrated;?></th>
<td><?php echo html::radio('isIntegrated', $lang->build->isIntegrated, 'no');?></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 id='buildBox'><?php echo html::select('builds[]', array(), '', "class='form-control chosen' multiple data-placeholder='{$lang->build->placeholder->multipleSelect}'");?></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>
@@ -97,4 +104,5 @@
<?php js::set('projectID', $projectID);?>
<?php js::set('executionID', $executionID);?>
<?php js::set('currentTab', $this->app->tab);?>
<?php js::set('multipleSelect', $lang->build->placeholder->multipleSelect);?>
<?php include '../../common/view/footer.html.php';?>
+2 -1
View File
@@ -46,7 +46,7 @@
<?php if(!$build->execution):?>
<tr>
<th><?php echo $lang->build->builds;?></th>
<td id='buildBox'><?php echo html::select('builds[]', $builds, $build->builds, "class='form-control chosen' multiple $disabled");?></td>
<td id='buildBox'><?php echo html::select('builds[]', $builds, $build->builds, "class='form-control chosen' multiple $disabled data-placeholder='{$lang->build->placeholder->multipleSelect}'");?></td>
<td>
<?php if($disabled):?>
<?php echo $lang->build->notice->changeBuilds;?>
@@ -104,4 +104,5 @@
<?php js::set('builds', $build->builds)?>
<?php js::set('executionID', $build->execution)?>
<?php js::set('currentTab', $this->app->tab);?>
<?php js::set('multipleSelect', $lang->build->placeholder->multipleSelect);?>
<?php include '../../common/view/footer.html.php';?>
+6 -4
View File
@@ -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>
@@ -195,10 +196,11 @@ tbody tr td:first-child input {display: none;}
<tbody class='text-center'>
<?php foreach($bugs as $bug):?>
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bug->id", '', true);?>
<?php $unlinkClass = strpos(",$build->bugs,", ",$bug->id,") !== false ? '' : "disabled";?>
<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>
+2 -2
View File
@@ -261,12 +261,12 @@ $lang->waterfall->menu = new stdclass();
$lang->waterfall->menu->index = array('link' => "$lang->dashboard|project|index|project=%s");
$lang->waterfall->menu->execution = array('link' => "{$lang->stage->common}|project|execution|status=all&projectID=%s", 'subModule' => 'programplan,task');
$lang->waterfall->menu->storyGroup = array('link' => "{$lang->common->story}|projectstory|story|projectID=%s",'class' => 'dropdown dropdown-hover', 'exclude' => 'tree-browse,projectstory-track');
$lang->waterfall->menu->story = array('link' => "$lang->SRCommon|projectstory|story|projectID=%s", 'subModule' => 'projectstory,tree', 'alias' => 'story,track', 'exclude' => 'projectstory-track');
$lang->waterfall->menu->story = array('link' => "$lang->SRCommon|projectstory|story|projectID=%s", 'subModule' => 'projectstory,tree', 'alias' => 'story', 'exclude' => 'projectstory-track');
$lang->waterfall->menu->design = array('link' => "{$lang->design->common}|design|browse|project=%s");
$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");
+3 -1
View File
@@ -116,9 +116,11 @@ function renderSpanItem(item, $item)
function renderProductItem(item, $item)
{
var $title = $item.find('.title');
var isShadow = (typeof(item.shadow) != 'undefined' && item.shadow == '1') ? true : false;
if(!$title.length)
{
if(window.userPrivs.product)
if(window.userPrivs.product && !isShadow)
{
$title = $('<a class="title" />')
.attr('href', $.createLink('product', 'browse', 'productID=' + item._id));
+1
View File
@@ -76,6 +76,7 @@
<?php endif;?>
<?php $tab = '';?>
<?php if($action->objectType == 'meeting') $tab = $action->project ? "data-app='project'" : "data-app='my'";?>
<?php if($action->objectType == 'module' and $config->vision == 'lite') $tab = "data-app='project'";?>
<span class="label-name">
<?php
if(empty($action->objectName) and $action->objectID)
+3
View File
@@ -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;
+5
View File
@@ -76,6 +76,11 @@ class design extends control
$this->session->set('reviewList', $this->app->getURI(true), 'project');
/* Build the search form. */
$products = $this->product->getProductPairsByProject($projectID);
$productIdList = $productID ? $productID : array_keys($products);
$stories = $this->loadModel('story')->getProductStoryPairs($productIdList, 'all', 0, 'active', 'id_desc', 0, 'full', 'story', false);
$this->config->design->search['params']['story']['values'] = $stories;
$queryID = ($type == 'bySearch') ? (int)$param : 0;
$actionURL = $this->createLink('design', 'browse', "projectID=$projectID&productID=$productID&type=bySearch&queryID=myQueryID");
$this->design->buildSearchForm($queryID, $actionURL);
+2
View File
@@ -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>
+1 -1
View File
@@ -50,7 +50,7 @@
<?php if(!$design->deleted):?>
<?php
common::printIcon('design', 'assignTo', "designID=$design->id", $design, 'button', '', '', 'iframe showinonlybody', true);
common::printIcon('design', 'linkCommit', "designID=$design->id", $design, 'button', 'link', '', 'iframe showinonlybody', true, "id='linkCommit'");
if(helper::hasFeature('devops')) common::printIcon('design', 'linkCommit', "designID=$design->id", $design, 'button', 'link', '', 'iframe showinonlybody', true, "id='linkCommit'");
common::printIcon('design', 'edit', "designID=$design->id", $design, 'button', 'alter');
common::printIcon('design', 'delete', "designID=$design->id", $design, 'button', 'trash', 'hiddenwin');
?>
+7
View File
@@ -155,10 +155,17 @@ class doc extends control
/* Splice project name. */
foreach($executions as $executionID => $execution)
{
if($execution->multiple)
{
$executionPrefix = isset($projects[$execution->project]) ? $projects[$execution->project] . '/' : '';
$executions[$executionID] = $executionPrefix . $execution->name;
}
else
{
unset($executions[$executionID]);
}
}
/* Get the project that has permission to view. */
foreach($projects as $projectID => $project) if(!$this->app->user->admin and strpos(',' . $this->app->user->view->projects . ',', ',' . $projectID . ',') === false) unset($projects[$projectID]);
+1 -1
View File
@@ -91,7 +91,7 @@ class docModel extends model
$products = $this->loadModel('product')->getPairs();
$projects = $this->loadModel('project')->getPairsByProgram();
$executions = $this->loadModel('execution')->getPairs();
$executions = $this->loadModel('execution')->getPairs(0, 'all', 'multiple');
$waterfalls = array();
if(empty($objectID) and ($type == 'all' or $type == 'execution'))
{
+11 -2
View File
@@ -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;
@@ -1609,6 +1609,7 @@ 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 == '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')
@@ -3133,9 +3140,11 @@ class execution extends control
if(!empty($_POST))
{
$this->execution->manageMembers($executionID);
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
$this->loadModel('action')->create('team', $executionID, 'managedTeam');
$link = $this->session->teamList ? $this->session->teamList : $this->createLink('execution', 'team', "executionID=$executionID");
return print(js::locate($link, 'parent'));
return $this->send(array('message' => $this->lang->saveSuccess, 'result' => 'success', 'locate' => $link));
}
/* Load model. */
+2
View File
@@ -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;}
+2
View File
@@ -147,6 +147,8 @@ $lang->execution->consumed = 'consumed';
$lang->execution->left = 'Left';
$lang->execution->copyTeamTip = "copy Project/project team members";
$lang->execution->daysGreaterProject = 'Days cannot be greater than days of execution 『%s』';
$lang->execution->errorHours = 'Hours/Day cannot be greater than『24』';
$lang->execution->start = 'Start';
$lang->execution->activate = 'Aktivieren';
+2
View File
@@ -147,6 +147,8 @@ $lang->execution->consumed = 'Consumed';
$lang->execution->left = 'Left';
$lang->execution->copyTeamTip = "copy Project/project team members";
$lang->execution->daysGreaterProject = 'Days cannot be greater than days of execution 『%s』';
$lang->execution->errorHours = 'Hours/Day cannot be greater than『24』';
$lang->execution->start = 'Start';
$lang->execution->activate = 'Activate';
+2
View File
@@ -147,6 +147,8 @@ $lang->execution->consumed = 'consumed';
$lang->execution->left = 'Left';
$lang->execution->copyTeamTip = "copy Project/project team members";
$lang->execution->daysGreaterProject = 'Days cannot be greater than days of execution 『%s』';
$lang->execution->errorHours = 'Hours/Day cannot be greater than『24』';
$lang->execution->start = 'Démarrer';
$lang->execution->activate = 'Activer';
+2
View File
@@ -147,6 +147,8 @@ $lang->execution->consumed = '消耗';
$lang->execution->left = '剩余';
$lang->execution->copyTeamTip = "可以选择复制项目或{$lang->execution->common}团队的成员";
$lang->execution->daysGreaterProject = '可用工日不能大于执行的可用工日『%s』';
$lang->execution->errorHours = '可用工时/天不能大于『24』';
$lang->execution->start = "开始";
$lang->execution->activate = "激活";
+27 -5
View File
@@ -64,6 +64,7 @@ class executionModel extends model
public function setMenu($executionID, $buildID = 0, $extra = '')
{
$execution = $this->getByID($executionID);
if(!$execution) return;
if($execution->type == 'stage') unset($this->lang->execution->menu->settings['subMenu']->products);
@@ -565,6 +566,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 +578,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)
@@ -3157,6 +3161,23 @@ class executionModel extends model
$accounts = array_unique($accounts);
$limited = array_values($limited);
$oldJoin = $this->dao->select('`account`, `join`')->from(TABLE_TEAM)->where('root')->eq($executionID)->andWhere('type')->eq($executionType)->fetchPairs();
foreach($accounts as $key => $account)
{
if(empty($account)) continue;
if(!empty($execution->days) and (int)$days[$key] > $execution->days)
{
dao::$errors['message'][] = sprintf($this->lang->execution->daysGreaterProject, $execution->days);
return false;
}
if((float)$hours[$key] > 24)
{
dao::$errors['message'][] = $this->lang->execution->errorHours;
return false;
}
}
$this->dao->delete()->from(TABLE_TEAM)->where('root')->eq($executionID)->andWhere('type')->eq($executionType)->exec();
$executionMember = array();
@@ -4712,7 +4733,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 +4763,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 +4965,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 +5113,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 +5133,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 +5146,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' : '';
+2
View File
@@ -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);
}
?>
+2 -2
View File
@@ -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)'");?>
+2 -1
View File
@@ -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>
+1 -1
View File
@@ -31,7 +31,7 @@
</div>
</div>
<div id='mainContent' class='main-content'>
<form class='main-form' method='post' id='teamForm' target='hiddenwin'>
<form class='main-form form-ajax' method='post' id='teamForm'>
<table class='table table-form'>
<thead>
<tr class='text-center'>
+41 -5
View File
@@ -81,7 +81,7 @@
if($productID) common::printIcon('story', 'report', "productID=$productID&branchID=&storyType=$storyType&browseType=$type&moduleID=$param&chartType=pie&projectID=$execution->id", '', 'button', 'bar-chart muted');
common::printLink('story', 'export', "productID=$productID&orderBy=id_desc&executionID=$execution->id&browseType=$type&storyType=$storyType", "<i class='icon icon-export muted'></i> " . $lang->story->export, '', "class='btn btn-link export iframe'");
$canLinkStory = $execution->multiple;
$canLinkStory = ($execution->hasProduct or $execution->multiple);
if(common::canModify('execution', $execution))
{
$this->lang->story->create = $this->lang->execution->createStory;
@@ -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)
{
+1 -2
View File
@@ -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();
}
+3 -1
View File
@@ -527,7 +527,9 @@ class extensionModel extends model
$this->app->loadClass('pclzip', true);
$zip = new pclzip($packageFile);
$files = $zip->listContent();
$removePath = $files[0]['filename'];
$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';
+1 -1
View File
@@ -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>
-2
View File
@@ -238,7 +238,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';
@@ -250,7 +249,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';
+2 -1
View File
@@ -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);
+2 -2
View File
@@ -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);
+1 -2
View File
@@ -8,8 +8,7 @@
#mainContent tr th {background-color: rgb(241, 241, 241);}
#mainContent tr td {background-color: rgb(255, 255, 255); border-bottom: 1px solid rgb(238, 238, 238); border-right: 1px solid rgb(238, 238, 238);}
#useLight {background-color: #ddd!important; padding: 6px 85px;}
#useALM {background-color: #ddd!important; padding: 6px 85px;}
#useLight, #useALM {border: #93969b 1px solid; padding: 6px 85px;}
#mainContent .datatable {cursor: default;}
.container {padding-top: 20px;}
+1 -1
View File
@@ -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 = "&copy; 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 = "&copy; 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!";
+1 -1
View File
@@ -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 = "&copy; 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 = "&copy; 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!";
+1 -1
View File
@@ -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 = "&copy; 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 = "&copy; 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 !";
+1 -1
View File
@@ -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 = "&copy; 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 = "&copy; 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!";
+2 -2
View File
@@ -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 = "&copy; 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> QQ1492153927";
$lang->misc->copyright = "&copy; 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> QQ1492153927";
$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' => '');
+1 -1
View File
@@ -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 = "&copy; 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> QQ1492153927";
$lang->misc->copyright = "&copy; 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> QQ1492153927";
$lang->misc->checkTable = "檢查修復數據表";
$lang->misc->needRepair = "修復表";
$lang->misc->repairTable = "資料庫表可能因為斷電原因損壞,需要檢查修復!!";
+1 -1
View File
@@ -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. */
+25 -3
View File
@@ -32,7 +32,7 @@ class product extends control
$this->loadModel('user');
/* Get all products, if no, goto the create page. */
$this->products = $this->product->getPairs('nocode');
$this->products = $this->product->getPairs('nocode', 0, '', 'all');
$isAPI = ($this->app->viewType == 'json' or (defined('RUN_MODE') and RUN_MODE == 'api'));
if(empty($this->products) and strpos($this->config->product->skipRedirectMethod, ",$this->methodName,") === false and $this->app->getViewType() != 'mhtml' and !$isAPI) $this->locate($this->createLink('product', 'create'));
$this->view->products = $this->products;
@@ -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));
+1 -1
View File
@@ -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>');
+25 -3
View File
@@ -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.
*
@@ -2324,7 +2346,7 @@ class productModel extends model
{
parse_str($extra, $output);
$projectID = isset($output['projectID']) ? $output['projectID'] : 0;
$link = helper::createLink($module, $method, "productID=%s&branch=" . ($branch ? "%s" : '') . "&groupBy=&projectID=$projectID") . "#app=project";
$link = helper::createLink($module, $method, "productID=%s&branch=" . ($branch ? "%s" : 'all') . "&groupBy=&projectID=$projectID") . "#app=project";
}
elseif($module == 'testcase' and $method == 'browse')
{
+4 -2
View File
@@ -51,7 +51,9 @@
</th>
<?php endif;?>
<th class='table-nest-title text-left c-name' rowspan="2">
<?php if($config->systemMode == 'ALM'):?>
<a class='table-nest-toggle table-nest-toggle-global' data-expand-text='<?php echo $lang->expand; ?>' data-collapse-text='<?php echo $lang->collapse; ?>'></a>
<?php endif;?>
<?php common::printOrderLink('name', $orderBy, $vars, $lang->product->name);?>
</th>
<th class='c-PO' rowspan="2">
@@ -118,7 +120,7 @@
echo html::smallAvatar(array('avatar' => $usersAvatar[$programPM], 'account' => $programPM, 'name' => $userName), 'avatar-circle avatar-top avatar-' . zget($userIdPairs, $programPM));
$userID = isset($userIdPairs[$programPM]) ? $userIdPairs[$programPM] : '';
echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");
echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' class='iframe' data-width='600'");
}
?>
</td>
@@ -221,7 +223,7 @@
echo html::smallAvatar(array('avatar' => $usersAvatar[$product->PO], 'account' => $product->PO, 'name' => $userName), 'avatar-circle avatar-' . zget($userIdPairs, $product->PO));
$userID = isset($userIdPairs[$product->PO]) ? $userIdPairs[$product->PO] : '';
echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");
echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' class='iframe' data-width='600'");
}
?>
</td>
+1
View File
@@ -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%;}
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -74,7 +74,7 @@
<td class='text-left'>
<?php
$projectType = $project->model == 'scrum' ? 'sprint' : $project->model;
echo html::a($this->createLink('project', 'index', 'project=' . $project->id), "<i class='text-muted icon icon-{$projectType}'></i> " . $project->name, '', "title='{$project->name} ({$lang->project->{$project->model}})'");
echo html::a($this->createLink('project', 'index', 'project=' . $project->id), "<i class='text-muted icon icon-{$projectType}'></i> " . $project->name, '', "title='$project->name'");
?>
</td>
<?php if(strpos('all,undone', $status) !== false):?>
+22 -11
View File
@@ -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']))
{
+5 -1
View File
@@ -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'" : '' ;?>
+2 -2
View File
@@ -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>
+1 -1
View File
@@ -53,7 +53,7 @@ function processKanbanData(key, programsData)
/* unclosed products */
var productID = product.id;
var productItem = {id: 'product-' + productID, _id: productID, name: product.name};
var productItem = {id: 'product-' + productID, _id: productID, name: product.name, shadow: product.shadow};
items.unclosedProduct = [productItem];
/* plans */
+8 -3
View File
@@ -99,7 +99,7 @@ class programModel extends model
$productPrograms = $this->dao->select('id, name')->from(TABLE_PROJECT)->where('type')->eq('program')->andWhere('deleted')->eq('0')->fetchPairs();
/* Put products of current program first.*/
if(!empty($products) and $mode != 'assign' and $programID)
if(!empty($products) and isset($products[$programID]) and $mode != 'assign' and $programID)
{
$currentProgramProducts = $products[$programID];
unset($products[$programID]);
@@ -274,7 +274,7 @@ class programModel extends model
$involvedPrograms = $this->getInvolvedPrograms($this->app->user->account);
/* Get all products under programs. */
$productGroup = $this->dao->select('id, program, name')->from(TABLE_PRODUCT)
$productGroup = $this->dao->select('id, program, name, shadow')->from(TABLE_PRODUCT)
->where('deleted')->eq(0)
->andWhere('program')->in(array_keys($programs))
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->products)->fi()
@@ -285,7 +285,12 @@ class programModel extends model
$productPairs = array();
foreach($productGroup as $programID => $products)
{
foreach($products as $product) $productPairs[$product->id] = $product->id;
foreach($products as $product)
{
$productPairs[$product->id] = $product->id;
if($product->shadow) $product->name = $product->name . ' (' . $this->lang->project->common . ')';
}
}
/* Get all plans under products. */
+1 -1
View File
@@ -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 = '已分解任务,不可添加子阶段';
+1 -1
View File
@@ -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 = '已分解任務,不可添加子階段';
+5 -1
View File
@@ -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);
@@ -1085,12 +1086,15 @@ class programplanModel extends model
$this->lang->project->name = $this->lang->programplan->name;
$this->lang->project->code = $this->lang->execution->code;
$relationExecutionsID = $this->loadModel('execution')->getRelatedExecutions($planID);
$relationExecutionsID = !empty($relationExecutionsID) ? implode(',', array_keys($relationExecutionsID)) : '';
$this->dao->update(TABLE_PROJECT)->data($plan)
->autoCheck()
->batchCheck($this->config->programplan->edit->requiredFields, 'notempty')
->checkIF($plan->end != '0000-00-00', 'end', 'ge', $plan->begin)
->checkIF($plan->percent != false, 'percent', 'float')
->checkIF(!empty($plan->name), 'name', 'unique', "id != {$planID} and type in ('sprint','stage') and `project` = {$oldPlan->project} and `deleted` = '0'" . ($parentStage ? " and `parent` = {$oldPlan->parent}" : ''))
->checkIF(!empty($plan->name), 'name', 'unique', "id in ('{$relationExecutionsID}') and type in ('sprint','stage') and `project` = {$oldPlan->project} and `deleted` = '0'" . ($parentStage ? " and `parent` = {$oldPlan->parent}" : ''))
->checkIF(!empty($plan->code) and $setCode, 'code', 'unique', "id != $planID and type in ('sprint','stage','kanban') and `deleted` = '0'")
->where('id')->eq($planID)
->exec();
+11 -7
View File
@@ -541,6 +541,8 @@ class project extends control
}
$parent = isset($_POST['parent']) ? $_POST['parent'] : 0;
$systemMode = $this->loadModel('setting')->getItem('owner=system&module=common&section=global&key=mode');
if(!empty($systemMode) and $systemMode == 'light') $parent = 0;
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('project', 'browse', "programID=$parent&browseType=all", '', '', $projectID)));
}
}
@@ -2173,15 +2175,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));
$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 +2239,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 +2298,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'"));
+12
View File
@@ -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();
+5
View File
@@ -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)
+2 -2
View File
@@ -182,8 +182,8 @@ $lang->project->kanban = 'Kanban';
/* Project Kanban. */
$lang->project->projectTypeList = array();
$lang->project->projectTypeList[1] = 'Has Product';
$lang->project->projectTypeList[0] = 'No Product';
$lang->project->projectTypeList[1] = 'Product-based';
$lang->project->projectTypeList[0] = 'Non-product-based';
/* Project Kanban. */
$lang->project->typeList = array();
+2 -2
View File
@@ -182,8 +182,8 @@ $lang->project->kanban = 'Kanban';
/* Project Kanban. */
$lang->project->projectTypeList = array();
$lang->project->projectTypeList[1] = 'Has Product';
$lang->project->projectTypeList[0] = 'No Product';
$lang->project->projectTypeList[1] = 'Product-based';
$lang->project->projectTypeList[0] = 'Non-product-based';
/* Project Kanban. */
$lang->project->typeList = array();
+2 -2
View File
@@ -182,8 +182,8 @@ $lang->project->kanban = 'Kanban';
/* Project Kanban. */
$lang->project->projectTypeList = array();
$lang->project->projectTypeList[1] = 'Has Product';
$lang->project->projectTypeList[0] = 'No Product';
$lang->project->projectTypeList[1] = 'Product-based';
$lang->project->projectTypeList[0] = 'Non-product-based';
/* Project Kanban. */
$lang->project->typeList = array();

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