Merge branch 'zentaopms_239' of https://gitlab.zcorp.cc/easycorp/zentaopms into 239
This commit is contained in:
@@ -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'));
|
||||
|
||||
|
||||
@@ -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}'"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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¶m=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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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, ',');
|
||||
|
||||
@@ -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')
|
||||
{
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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]);?>
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user