Merge branch 'zentaopms_239' of https://gitlab.zcorp.cc/easycorp/zentaopms into 239

This commit is contained in:
Yagami
2022-10-19 15:36:28 +08:00
20 changed files with 169 additions and 104 deletions
+1
View File
@@ -394,6 +394,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->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'));
+1 -1
View File
@@ -280,7 +280,7 @@ class branch extends control
$branchTagOption[$oldBranch] = $oldBranch == BRANCH_MAIN ? $branch : ($branch->name . ($branch->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : ''));
}
return print(html::select('branch', $branchTagOption, $oldBranch, "class='form-control' onchange='loadBranch(this)'"));
return print(html::select('branch', $branchTagOption, $oldBranch, "class='form-control' onchange='loadBranch(this)' data-last='{$oldBranch}'"));
}
/**
+5 -1
View File
@@ -166,11 +166,15 @@ $lang->product->menu->project = array('link' => "{$lang->project->common}|pr
$lang->product->menu->release = array('link' => "{$lang->release->common}|release|browse|productID=%s", 'subModule' => 'release');
$lang->product->menu->roadmap = array('link' => "{$lang->roadmap}|product|roadmap|productID=%s");
$lang->product->menu->requirement = array('link' => "$lang->URCommon|product|browse|productID=%s&branch=&browseType=unclosed&param=0&storyType=requirement", 'alias' => 'batchedit', 'subModule' => 'story');
$lang->product->menu->track = array('link' => "{$lang->track}|product|track|productID=%s");
$lang->product->menu->doc = array('link' => "{$lang->doc->common}|doc|tableContents|type=product&objectID=%s", 'subModule' => 'doc');
$lang->product->menu->dynamic = array('link' => "{$lang->dynamic}|product|dynamic|productID=%s");
$lang->product->menu->settings = array('link' => "{$lang->settings}|product|view|productID=%s", 'subModule' => 'tree,branch', 'alias' => 'edit,whitelist,addwhitelist');
if(strpos(",$config->disabledFeatures,", ',track,') === false)
{
$lang->product->menu->track = array('link' => "{$lang->track}|product|track|productID=%s");
}
/* Product menu order. */
$lang->product->menuOrder[5] = 'dashboard';
$lang->product->menuOrder[10] = 'story';
+7 -10
View File
@@ -2424,12 +2424,6 @@ EOD;
if(isset($this->app->user))
{
if($this->app->tab == 'project')
{
$projectPrivs = $this->loadModel('project')->processProjectPrivs();
if(isset($projectPrivs->$module->$method)) return true;
}
$this->app->user = $this->session->user;
if(!commonModel::hasPriv($module, $method))
{
@@ -2619,8 +2613,8 @@ EOD;
foreach($programRights as $programRight) $programRightGroup[strtolower($programRight->module)][strtolower($programRight->method)] = 1;
/* Reset priv by program privway. */
$rights = $this->app->user->rights['rights'];
$this->app->user = clone $_SESSION['user'];
$rights = $this->app->user->rights['rights'];
if($this->app->user->account == $program->openedBy or $this->app->user->account == $program->PM) $program->auth = 'extend';
@@ -2628,12 +2622,14 @@ EOD;
if($program->auth == 'reset')
{
/* If priv way is reset, unset common program priv, and cover by program priv. */
$projectPrivs = $this->loadModel('project')->processProjectPrivs();
foreach($rights as $module => $methods)
$projectPrivs = $this->loadModel('project')->processProjectPrivs($program->multiple ? $program->model : 'noSprint');
foreach($projectPrivs as $module => $methods)
{
foreach($methods as $method)
{
if(isset($projectPrivs->$module->$method)) unset($rights[$module][$method]);
$module = strtolower($module);
$method = strtolower($method);
if(isset($rights[$module][$method])) unset($rights[$module][$method]);
}
}
@@ -2646,6 +2642,7 @@ EOD;
if(isset($projectRights['index']) and !isset($recomputedRights['project']['index'])) $recomputedRights['project']['index'] = 1;
$this->app->user->rights['rights'] = $recomputedRights;
$this->session->set('user', $this->app->user);
}
}
+1 -1
View File
@@ -917,7 +917,7 @@ class customModel extends model
$function = 'has' . ucfirst($feature) . 'Data';
if(!$this->$function()) $disabledFeatures .= "$feature,";
}
$disabledFeatures .= 'scrumMeasrecord,';
$disabledFeatures .= 'scrumMeasrecord,track';
}
$disabledFeatures = rtrim($disabledFeatures, ',');
+7 -4
View File
@@ -130,10 +130,13 @@ body {margin-bottom: 25px;}
<button class="btn btn-link" data-toggle="dropdown"><i class="icon icon-import muted"></i> <span class="text"><?php echo $lang->import;?></span> <span class="caret"></span></button>
<ul class="dropdown-menu pull-right" id='importActionMenu'>
<?php
$class = common::hasPriv('execution', 'importTask') ? '' : "class=disabled";
$misc = common::hasPriv('execution', 'importTask') ? "class='import'" : "class=disabled";
$link = common::hasPriv('execution', 'importTask') ? $this->createLink('execution', 'importTask', "execution=$execution->id") : '#';
echo "<li $class>" . html::a($link, $lang->execution->importTask, '', $misc) . "</li>";
if($execution->multiple)
{
$class = common::hasPriv('execution', 'importTask') ? '' : "class=disabled";
$misc = common::hasPriv('execution', 'importTask') ? "class='import'" : "class=disabled";
$link = common::hasPriv('execution', 'importTask') ? $this->createLink('execution', 'importTask', "execution=$execution->id") : '#';
echo "<li $class>" . html::a($link, $lang->execution->importTask, '', $misc) . "</li>";
}
if($execution->lifetime != 'ops')
{
+2
View File
@@ -1887,6 +1887,7 @@ $lang->dev->methodOrder[20] = 'translate';
global $config;
$hasWaterfall = strpos(",$config->disabledFeatures,", ',waterfall,') === false || (defined('IN_UPGRADE') && IN_UPGRADE);
$hasTrack = strpos(",$config->disabledFeatures,", ',track,') === false || (defined('IN_UPGRADE') && IN_UPGRADE);
$isURSR = $config->URAndSR || (defined('IN_UPGRADE') && IN_UPGRADE);
$hasProgram = $config->systemMode == 'new' || (defined('IN_UPGRADE') && IN_UPGRADE);
if(!$hasWaterfall)
@@ -1906,5 +1907,6 @@ if(!$isURSR)
unset($lang->resource->story->linkStory);
unset($lang->resource->requirement);
}
if(!$hasTrack) unset($lang->resource->product->track);
include (dirname(__FILE__) . '/changelog.php');
+3 -5
View File
@@ -76,16 +76,15 @@ class programModel extends model
if($programID)
{
$program = $this->getByID($programID);
$path = explode(',', $program->path);
$path = array_filter($path);
$path = array_filter(explode(',', $program->path));
$programID = current($path);
}
/* When mode equals assign and programID equals 0, you can query the standalone product. */
if(!empty($append) and is_array($append)) $append = implode(',', $append);
$views = empty($append) ? $this->app->user->view->products : $this->app->user->view->products . ",$append";
$views = empty($append) ? $this->app->user->view->products : $this->app->user->view->products . ",$append";
$products = $this->dao->select('*')->from(TABLE_PRODUCT)
return $this->dao->select('*')->from(TABLE_PRODUCT)
->where('deleted')->eq(0)
->andWhere('vision')->eq($this->config->vision)
->beginIF($shadow !== 'all')->andWhere('shadow')->eq((int)$shadow)->fi()
@@ -93,7 +92,6 @@ class programModel extends model
->beginIF(strpos($status, 'noclosed') !== false)->andWhere('status')->ne('closed')->fi()
->beginIF(!$this->app->user->admin)->andWhere('id')->in($views)->fi()
->fetchPairs('id', 'name');
return $products;
}
/**
+15 -11
View File
@@ -165,7 +165,7 @@ $config->project->search['fields']['lastEditedDate'] = $lang->project->lastEdite
$config->project->search['fields']['closedDate'] = $lang->project->closedDate;
$config->project->search['params']['name'] = array('operator' => 'include', 'control' => 'input' , 'values' => '');
$config->project->search['params']['code'] = array('operator' => '=', 'control' => 'input' , 'values' => '');
$config->project->search['params']['code'] = array('operator' => '=' , 'control' => 'input' , 'values' => '');
$config->project->search['params']['id'] = array('operator' => '=' , 'control' => 'input' , 'values' => '');
$config->project->search['params']['model'] = array('operator' => '=' , 'control' => 'select', 'values' => $lang->project->modelList);
$config->project->search['params']['hasProduct'] = array('operator' => '=' , 'control' => 'select', 'values' => array('' => '') + $lang->project->projectTypeList);
@@ -183,15 +183,19 @@ $config->project->search['params']['closedBy'] = array('operator' => '='
$config->project->search['params']['lastEditedDate'] = array('operator' => '=' , 'control' => 'input' , 'values' => '', 'class' => 'date');
$config->project->search['params']['closedDate'] = array('operator' => '=' , 'control' => 'input' , 'values' => '', 'class' => 'date');
$config->project->includedPriv['project'] = array('edit', 'group', 'createGroup', 'managePriv', 'manageMembers', 'manageGroupMember', 'copyGroup', 'editGroup', 'start', 'suspend', 'close', 'activate', 'delete', 'view', 'whitelist', 'addWhitelist', 'unbindWhitelist', 'manageProducts', 'dynamic', 'build', 'bug', 'testcase', 'testtask', 'testreport', 'execution', 'team', 'unlinkMember');
$config->project->includedPriv['execution'] = array('create', 'start', 'delete', 'calendar', 'effortCalendar', 'effort', 'taskEffort', 'computeTaskEffort', 'deleterelation', 'maintainrelation', 'relation', 'gantt');
$config->project->noSprintPriv['project'] = array('edit', 'group', 'createGroup', 'managePriv', 'manageMembers', 'manageGroupMember', 'copyGroup', 'editGroup', 'start', 'suspend', 'close', 'activate', 'delete', 'view', 'whitelist', 'addWhitelist', 'unbindWhitelist', 'manageProducts', 'dynamic', 'build', 'bug', 'testcase', 'testtask', 'testreport', 'team', 'unlinkMember');
$config->project->noSprintPriv['execution'] = array('task', 'grouptask', 'importplanstories', 'importBug', 'story', 'burn', 'computeBurn', 'fixFirst', 'burnData', 'linkStory', 'unlinkStory', 'batchUnlinkStory', 'updateOrder', 'taskKanban', 'printKanban', 'tree', 'treeTask', 'treeStory', 'storyKanban', 'storySort', 'storyEstimate', 'executionkanban', 'kanban', 'setKanban', 'storyView', 'calendar', 'effortCalendar', 'effort', 'taskEffort', 'computeTaskEffort', 'deleterelation', 'maintainrelation', 'relation', 'gantt', 'ganttsetting', 'ganttEdit');
$config->project->noSprintPriv['story'] = array('create', 'batchCreate', 'edit', 'export', 'delete', 'view', 'change', 'review', 'batchReview', 'recall', 'close', 'batchClose', 'batchChangePlan', 'batchChangeStage', 'assignTo', 'batchAssignTo', 'activate', 'zeroCase', 'batchEdit', 'import', 'showImport', 'exportTemplate', 'importToLib', 'batchImportToLib', 'relation', 'browse');
$config->project->noSprintPriv['bug'] = array('create', 'confirmBug', 'view', 'edit', 'assignTo', 'batchAssignTo', 'resolve', 'activate', 'close', 'export', 'confirmStoryChange', 'delete', 'linkBugs', 'import', 'showImport', 'exportTemplate');
$config->project->noSprintPriv['testcase'] = array('groupCase', 'create', 'batchCreate', 'createBug', 'view', 'edit', 'delete', 'export', 'confirmChange', 'confirmStoryChange', 'batchEdit', 'batchDelete', 'linkCases', 'bugs', 'review', 'batchReview', 'batchConfirmStoryChange', 'importFromLib', 'batchCaseTypeChange', 'exportTemplate', 'import', 'showImport', 'confirmLibcaseChange', 'ignoreLibcaseChange', 'submit');
$config->project->noSprintPriv['testtask'] = array('create', 'cases', 'groupCase', 'edit', 'delete', 'batchAssign', 'linkcase', 'unlinkcase', 'runcase', 'results', 'batchUnlinkCases', 'report', 'browseUnits', 'unitCases', 'importUnitResult', 'batchRun', 'runDeployCase', 'deployCaseResults');
$config->project->noSprintPriv['doc'] = array('createLib', 'editLib', 'deleteLib', 'create', 'edit', 'delete', 'deleteFile', 'allLibs', 'objectLibs', 'collect', 'tableContents', 'showFiles', 'diff', 'manageBook', 'importToPracticeLib', 'importToComponentLib');
$config->project->noSprintPriv['repo'] = array('create', 'showSyncCommit', 'browse', 'view', 'diff', 'log', 'revision', 'blame', 'download', 'apiGetRepoByUrl', 'review', 'addBug', 'editBug', 'deleteBug', 'addComment', 'editComment', 'deleteComment');
$config->project->noSprintPriv['testreport'] = array('create', 'view', 'delete', 'edit', 'export');
$config->project->noSprintPriv['auditplan'] = array('browse', 'create', 'edit', 'batchCreate', 'batchCheck', 'check', 'nc', 'result', 'assignTo');
$config->project->includedPriv = $config->project->noSprintPriv;
$config->project->includedPriv['project'][] = 'execution';
$config->project->includedPriv['task'] = array('create');
$config->project->includedPriv['story'] = array('create', 'batchCreate', 'edit', 'export', 'delete', 'view', 'change', 'review', 'batchReview', 'recall', 'close', 'batchClose', 'batchChangePlan', 'batchChangeStage', 'assignTo', 'batchAssignTo', 'activate', 'zeroCase', 'batchEdit', 'import', 'showImport', 'exportTemplate', 'importToLib', 'batchImportToLib', 'relation', 'browse');
$config->project->includedPriv['bug'] = array('create', 'confirmBug', 'view', 'edit', 'assignTo', 'batchAssignTo', 'resolve', 'activate', 'close', 'export', 'confirmStoryChange', 'delete', 'linkBugs', 'import', 'showImport', 'exportTemplate');
$config->project->includedPriv['testcase'] = array('groupCase', 'create', 'batchCreate', 'createBug', 'view', 'edit', 'delete', 'export', 'confirmChange', 'confirmStoryChange', 'batchEdit', 'batchDelete', 'linkCases', 'bugs', 'review', 'batchReview', 'batchConfirmStoryChange', 'importFromLib', 'batchCaseTypeChange', 'exportTemplate', 'import', 'showImport', 'confirmLibcaseChange', 'ignoreLibcaseChange', 'submit');
$config->project->includedPriv['testtask'] = array('create', 'cases', 'groupCase', 'edit', 'delete', 'batchAssign', 'linkcase', 'unlinkcase', 'runcase', 'results', 'batchUnlinkCases', 'report', 'browseUnits', 'unitCases', 'importUnitResult', 'batchRun', 'runDeployCase', 'deployCaseResults');
$config->project->includedPriv['doc'] = array('createLib', 'editLib', 'deleteLib', 'create', 'edit', 'delete', 'deleteFile', 'allLibs', 'objectLibs', 'collect', 'tableContents', 'showFiles', 'diff', 'manageBook', 'importToPracticeLib', 'importToComponentLib');
$config->project->includedPriv['repo'] = array('create', 'showSyncCommit', 'browse', 'view', 'diff', 'log', 'revision', 'blame', 'download', 'apiGetRepoByUrl', 'review', 'addBug', 'editBug', 'deleteBug', 'addComment', 'editComment', 'deleteComment');
$config->project->includedPriv['testreport'] = array('create', 'view', 'delete', 'edit', 'export');
$config->project->includedPriv['auditplan'] = array('browse', 'create', 'edit', 'batchCreate', 'batchCheck', 'check', 'nc', 'result', 'assignTo');
$config->project->includedPriv['execution'] = array('create', 'start', 'delete', 'calendar', 'effortCalendar', 'effort', 'taskEffort', 'computeTaskEffort', 'deleterelation', 'maintainrelation', 'relation', 'gantt');
if($config->edition != 'max') $config->project->includedPriv['stakeholder'] = array('browse', 'create', 'batchCreate', 'edit', 'delete', 'view', 'communicate', 'expect', 'expectation', 'deleteExpect', 'createExpect', 'editExpect', 'viewExpect');
+18 -27
View File
@@ -280,7 +280,7 @@ class project extends control
$data['selectedProgramPath'] = explode(',', $selectedProgram->path);
}
$allProducts = array(0 => '') + $this->program->getProductPairs($selectedProgramID, 'assign', 'noclosed');
$allProducts = array(0 => '') + $this->program->getProductPairs(0, 'all', 'noclosed');
$data['allProducts'] = html::select("products[0]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");
$data['plans'] = html::select('plans[][][]', '', '', 'class=\'form-control chosen\' multiple');
@@ -540,25 +540,24 @@ class project extends control
}
}
if($this->app->tab == 'program' and $programID) $this->loadModel('program')->setMenu($programID);
if($this->app->tab == 'doc') unset($this->lang->doc->menu->project['subMenu']);
if($this->app->tab == 'program' and $programID) $this->loadModel('program')->setMenu($programID);
if($this->app->tab == 'product' and !empty($output['productID'])) $this->loadModel('product')->setMenu($output['productID']);
if($this->app->tab == 'doc') unset($this->lang->doc->menu->project['subMenu']);
$this->session->set('projectModel', $model);
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
parse_str($extra, $output);
$name = '';
$code = '';
$team = '';
$whitelist = '';
$acl = 'private';
$auth = 'extend';
$hasProduct = 1;
$name = '';
$code = '';
$team = '';
$whitelist = '';
$acl = 'private';
$auth = 'extend';
$hasProduct = 1;
$shadow = 0;
$products = array();
$productPlans = array();
$shadow = 0;
$parentProgram = $this->loadModel('program')->getByID($programID);
if($copyProjectID)
@@ -567,12 +566,12 @@ class project extends control
$name = $copyProject->name;
$code = $copyProject->code;
$team = $copyProject->team;
$whitelist = $copyProject->whitelist;
$acl = $copyProject->acl;
$auth = $copyProject->auth;
$whitelist = $copyProject->whitelist;
$hasProduct = $copyProject->hasProduct;
$programID = $copyProject->parent;
$model = $copyProject->model;
$hasProduct = $copyProject->hasProduct;
$products = $this->product->getProducts($copyProjectID);
if(!$copyProject->hasProduct) $shadow = 1;
@@ -598,14 +597,13 @@ class project extends control
$this->config->executionCommonList[$this->app->getClientLang()][0] :
$this->config->executionCommonList[$this->app->getClientLang()][1];
$this->view->title = $this->lang->project->create;
$this->view->title = $this->lang->project->create;
$this->view->gobackLink = (isset($output['from']) and $output['from'] == 'global') ? $this->createLink('project', 'browse') : '';
$this->view->pmUsers = $this->loadModel('user')->getPairs('noclosed|nodeleted|pmfirst');
$this->view->users = $this->user->getPairs('noclosed|nodeleted');
$this->view->copyProjects = $this->project->getPairsByModel($model);
$this->view->products = $products;
$this->view->allProducts = array('0' => '') + $this->program->getProductPairs($programID, 'assign', 'noclosed', '', $shadow);
$this->view->allProducts = array('0' => '') + $this->program->getProductPairs(0, 'all', 'noclosed', '', $shadow);
$this->view->productPlans = array('0' => '') + $productPlans;
$this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products), 'noclosed');
$this->view->programID = $programID;
@@ -713,7 +711,7 @@ class project extends control
$productPlans = array(0 => '');
$branches = $this->project->getBranchesByProject($projectID);
$linkedProductIdList = empty($branches) ? '' : array_keys($branches);
$allProducts = $this->program->getProductPairs($project->parent, 'assign', 'noclosed', $linkedProductIdList);
$allProducts = $this->program->getProductPairs(0, 'all', 'noclosed', $linkedProductIdList);
$linkedProducts = $this->loadModel('product')->getProducts($projectID, 'all', '', true, $linkedProductIdList);
$parentProject = $this->program->getByID($project->parent);
$plans = $this->productplan->getGroupByProduct(array_keys($linkedProducts), 'skipParent|unexpired');
@@ -1562,17 +1560,10 @@ class project extends control
}
if($project->model == 'scrum') unset($this->lang->resource->projectstory->track);
if(!$project->multiple)
{
unset($this->lang->resource->project->execution);
unset($this->lang->resource->execution->create);
unset($this->lang->resource->execution->start);
unset($this->lang->resource->execution->delete);
unset($this->lang->resource->meeting);
}
if(!$project->multiple) $this->config->project->includedPriv = $this->config->project->noSprintPriv;
$this->view->project = $project;
$this->lang->resource = $this->project->processProjectPrivs($project->model);
$this->lang->resource = $this->project->processProjectPrivs($project->multiple ? $project->model : 'noSprint');
}
$this->display();
+50 -21
View File
@@ -66,37 +66,66 @@ $(function()
adjustProductBoxMargin();
adjustPlanBoxMargin();
/* If the story of the product which linked the execution under the project, you don't allow to remove the product. */
$("#productsBox select[name^='products']").each(function()
$(document).on('change', '[name*=products]', function()
{
var isExistedProduct = $.inArray($(this).attr('data-last'), unmodifiableProducts);
var productType = $(this).attr('data-type');
if(isExistedProduct != -1 && productType == 'normal')
{
$(this).prop('disabled', true).trigger("chosen:updated");
$(this).siblings('div').find('span').attr('title', tip);
}
});
var current = $(this).val();
var last = $(this).attr('data-last');
var lastBranch = $(this).attr('data-lastBranch');
$("#productsBox select[name^='branch']").each(function()
{
var branchID = $(this).attr('data-last');
var isExistedBranch = $.inArray(branchID, unmodifiableBranches);
if(isExistedBranch != -1)
$(this).attr('data-last', current);
var $branch = $(this).closest('.has-branch').find("[name^='branch']");
if($branch !== undefined)
{
var $product = $(this).closest('.has-branch').find("[name^='products']");
if($.inArray($product.val(), unmodifiableProducts) != -1)
var branchID = $branch.val();
$(this).attr('data-lastBranch', branchID);
}
else
{
$(this).removeAttr('data-lastBranch');
}
if(current != last && $.inArray(last, unmodifiableProducts) != -1)
{
if(lastBranch)
{
if((branchID == 0 && unmodifiableMainBranches[$product.val()]) || branchID != 0)
if($.inArray(lastBranch, unmodifiableBranches) != -1)
{
$(this).prop('disabled', true).trigger("chosen:updated");
$product.prop('disabled', true).trigger("chosen:updated");
$product.siblings('div').find('span').attr('title', tip);
if((lastBranch == 0 && unmodifiableMainBranches[last]) || lastBranch != 0)
{
bootbox.alert(unLinkProductTip.replace("%s", allProducts[last]));
}
}
}
else
{
bootbox.alert(unLinkProductTip.replace("%s", allProducts[last]));
}
}
});
$(document).on('change', '[name*=branch]', function()
{
var current = $(this).val();
var last = $(this).attr('data-last');
$(this).attr('data-last', current);
var $product = $(this).closest('.has-branch').find("[name^='products']");
$product.attr('data-lastBranch', current);
if($.inArray(last, unmodifiableBranches) != -1)
{
var productID = $product.val();
if($.inArray(productID, unmodifiableProducts) != -1)
{
if((last == 0 && unmodifiableMainBranches[productID]) || last != 0)
{
bootbox.alert(unLinkProductTip.replace("%s", branchGroups[productID][last]));
}
}
}
})
/* If end is longtime, set the default date to today */
var today = $.zui.formatDate(new Date(), 'yyyy-MM-dd');
if($('#end').val() == longTime) $('#end').val(today).datetimepicker('update').val(longTime);
+23
View File
@@ -10,6 +10,29 @@ $(function()
{
var $cb = $(this);
$cb.closest('.product').toggleClass('checked', $cb.prop('checked'));
var productID = String($cb.val());
if($.inArray(productID, unmodifiableProducts) != -1)
{
var $branch = $cb.closest('.product').find('[name^=branch]');
if($branch)
{
var branchID = String($branch.val());
console.log(productID);
console.log(unmodifiableMainBranches);
console.log($.inArray(productID, unmodifiableMainBranches));
if((branchID == BRANCH_MAIN && unmodifiableMainBranches[productID]) || (branchID != BRANCH_MAIN && $.inArray(branchID, unmodifiableBranches) != -1))
{
bootbox.alert(unLinkProductTip.replace("%s", branchGroups[productID][branchID]));
}
}
else
{
bootbox.alert(unLinkProductTip.replace("%s", allProducts[productID]));
}
}
});
$("select[id^=branch]").change(function()
+1
View File
@@ -211,6 +211,7 @@ $lang->project->noDevStage = 'There is no R&D stage under this proje
$lang->project->budgetOverrun = "The project's budget exceeds the remaining budget of the parent program:";
$lang->project->disabledInputTip = 'Please cancel %s first';
$lang->project->linkRepoFailed = 'Failed to link projects and code repositories.';
$lang->project->unLinkProductTip = 'Are you sure you want to unlink %s? (Does not affect linked requirements)';
$lang->project->tenThousand = '';
$lang->project->hundredMillion = 'Hundred Million';
+1
View File
@@ -211,6 +211,7 @@ $lang->project->noDevStage = 'There is no R&D stage under this proje
$lang->project->budgetOverrun = "The project's budget exceeds the remaining budget of the parent program:";
$lang->project->disabledInputTip = 'Please cancel %s first';
$lang->project->linkRepoFailed = 'Failed to link projects and code repositories.';
$lang->project->unLinkProductTip = 'Are you sure you want to unlink %s? (Does not affect linked requirements)';
$lang->project->tenThousand = 'Ten Thousand';
$lang->project->hundredMillion = 'Hundred Million';
+1
View File
@@ -210,6 +210,7 @@ $lang->project->noDevStage = "Il n'y a pas de phase R&D dans ce proj
$lang->project->budgetOverrun = "Le budget du projet a dépassé le budget restant du programme parent:";
$lang->project->disabledInputTip = 'Please cancel %s first';
$lang->project->linkRepoFailed = 'Failed to link projects and code repositories.';
$lang->project->unLinkProductTip = 'Are you sure you want to unlink %s? (Does not affect linked requirements)';
$lang->project->tenThousand = '';
$lang->project->hundredMillion = 'Hundred Million';
+1
View File
@@ -211,6 +211,7 @@ $lang->project->noDevStage = '该项目下没有研发类型的阶
$lang->project->budgetOverrun = '项目的预算超出了父项目集的剩余预算:';
$lang->project->disabledInputTip = '请先取消%s';
$lang->project->linkRepoFailed = '关联代码库失败';
$lang->project->unLinkProductTip = "您确认要取消与%s的关联关系吗?(不影响已关联的需求)";
$lang->project->tenThousand = '万';
$lang->project->hundredMillion = '亿';
+15 -12
View File
@@ -930,21 +930,22 @@ class projectModel extends model
{
$this->app->loadLang('group');
$privs = clone $this->lang->resource;
foreach($privs as $module => $methods)
$privs = new stdclass();
$resource = $this->lang->resource;
foreach($resource as $module => $methods)
{
if(!in_array($module, $this->config->programPriv->$model))
if(!$methods) continue;
if(!in_array($module, $this->config->programPriv->$model)) continue;
foreach($methods as $method => $label)
{
unset($privs->$module);
}
elseif($methods)
{
foreach($methods as $method => $label)
{
if(isset($this->config->project->includedPriv[$module]) and !in_array($method, $this->config->project->includedPriv[$module])) unset($privs->$module->$method);
}
if(isset($this->config->project->includedPriv[$module]) and !in_array($method, $this->config->project->includedPriv[$module])) continue;
if(!isset($privs->$module)) $privs->$module = new stdclass();
$privs->$module->$method = $label;
}
}
return $privs;
}
@@ -1511,7 +1512,7 @@ class projectModel extends model
->checkIF($project->begin != '', 'begin', 'date')
->checkIF($project->end != '', 'end', 'date')
->checkIF($project->end != '', 'end', 'gt', $project->begin)
->checkIF(!empty($project->name), 'name', 'unique', "id != $projectID and `type` = 'project' and `parent` = $project->parent and `model` = '{$project->model}' and `deleted` = '0'")
->checkIF(!empty($project->name), 'name', 'unique', "id != $projectID and `type` = 'project' and `parent` = '$project->parent' and `model` = '{$project->model}' and `deleted` = '0'")
->checkIF(!empty($project->code), 'code', 'unique', "id != $projectID and `type` = 'project' and `model` = '{$project->model}' and `deleted` = '0'")
->checkFlow()
->where('id')->eq($projectID)
@@ -2771,6 +2772,8 @@ class projectModel extends model
$this->lang->project->menu = $this->lang->$navGroup->menu;
$this->lang->project->menuOrder = $this->lang->$navGroup->menuOrder;
$this->lang->project->dividerMenu = $this->lang->$navGroup->dividerMenu;
$this->loadModel('common')->resetProjectPriv($projectID);
}
/**
+4 -1
View File
@@ -37,6 +37,9 @@
<?php js::set('beginLetterParent', $lang->project->beginLetterParent);?>
<?php js::set('endGreaterParent', $lang->project->endGreaterParent);?>
<?php js::set('ignore', $lang->project->ignore);?>
<?php js::set('allProducts', $allProducts);?>
<?php js::set('branchGroups', $branchGroups);?>
<?php js::set('unLinkProductTip', $lang->project->unLinkProductTip);?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
@@ -152,7 +155,7 @@
<?php foreach($linkedBranches[$product->id] as $branchID => $branch):?>
<div class='col-sm-4' style="padding-right: 6px;">
<div class="input-group<?php if($hasBranch) echo ' has-branch';?>">
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='" . $product->type . "'");?>
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='" . $product->type . "' data-lastBranch='" . $branchID . "'");?>
<span class='input-group-addon fix-border'></span>
<?php if($hasBranch) echo html::select("branch[$i]", $branchGroups[$product->id], $branchID, "class='form-control chosen' onchange=\"loadPlans('#products{$i}', this.value)\" data-last='" . $branchID . "'");?>
</div>
+10 -10
View File
@@ -11,6 +11,13 @@
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php js::set('unmodifiableProducts', $unmodifiableProducts);?>
<?php js::set('unmodifiableBranches', $unmodifiableBranches);?>
<?php js::set('unmodifiableMainBranches', $unmodifiableMainBranches);?>
<?php js::set('allProducts', $allProducts);?>
<?php js::set('branchGroups', $branchGroups);?>
<?php js::set('BRANCH_MAIN', BRANCH_MAIN);?>
<?php js::set('unLinkProductTip', $lang->project->unLinkProductTip);?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<span class='btn btn-link btn-active-text'><span class='text'><?php echo $lang->project->manageProducts;?></span></span>
@@ -26,22 +33,15 @@
<?php foreach($allProducts as $productID => $productName):?>
<?php if(isset($linkedProducts[$productID])):?>
<?php foreach($linkedBranches[$productID] as $branchID):?>
<?php $isDisabled = '';?>
<?php if($branchID == BRANCH_MAIN and isset($unmodifiableMainBranches[$productID])) $isDisabled = "disabled='disabled'";?>
<?php if($branchID != BRANCH_MAIN and in_array($productID, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches)) $isDisabled = "disabled='disabled'";?>
<?php if(empty($project->multiple)) $isDisabled = '';?>
<?php $title = (in_array($productID, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches)) ? $lang->project->notAllowRemoveProducts : $productName;?>
<?php $checked = 'checked';?>
<div class='col-sm-4'>
<div class='product <?php echo $checked . (isset($allBranches[$productID]) ? ' has-branch' : '')?>'>
<div class="checkbox-primary" title='<?php echo $title;?>'>
<?php echo "<input type='checkbox' name='products[$i]' value='$productID' $checked id='products{$productID}' $isDisabled>";?>
<div class='product checked <?php echo isset($allBranches[$productID]) ? ' has-branch' : ''?>'>
<div class="checkbox-primary" title='<?php echo $productName;?>'>
<?php echo "<input type='checkbox' name='products[$i]' value='$productID' checked id='products{$productID}'>";?>
<label class='text-ellipsis checkbox-inline' for='<?php echo 'products' . $productID;?>' title='<?php echo $productName;?>'><?php echo $productName;?></label>
</div>
<?php if(isset($allBranches[$productID][$branchID])) echo html::select("branch[$i]", $allBranches[$productID], $branchID, "class='form-control chosen' data-drop_direction='down' disabled='disabled'");?>
</div>
</div>
<?php if(!empty($isDisabled)) echo html::hidden("products[$i]", $productID);?>
<?php echo html::hidden("branch[$i]", $branchID);?>
<?php if(!isset($branchGroups[$productID])) unset($allProducts[$productID]);?>
<?php if(isset($branchGroups[$productID][$branchID])) unset($branchGroups[$productID][$branchID]);?>
+3
View File
@@ -2020,6 +2020,9 @@ class task extends control
}
}
$execution = $this->loadModel('execution')->getByID($executionID);
if(!$execution->multiple) unset($this->lang->task->report->charts['tasksPerExecution']);
$executions = $this->execution->getPairs();
$this->execution->setMenu($executionID);