* Refactor repo pages.
This commit is contained in:
@@ -478,3 +478,6 @@ $config->featureGroup->other = array('devops', 'kanban');
|
||||
|
||||
$config->bi = new stdclass();
|
||||
$config->bi->pickerHeight = 150;
|
||||
|
||||
$config->hasDropmenuApps = array('program', 'project', 'product', 'execution', 'qa', 'admin');
|
||||
$config->excludeDropmenuList = array('program-browse', 'product-all', 'product-index', 'execution-all', 'project-browse', 'product-batchedit', 'admin-index', 'product-create', 'project-create', 'execution-create', 'program-create');
|
||||
@@ -498,6 +498,8 @@ $lang->pager->totalCount = "Total: <strong>{recTotal}</strong> items";
|
||||
$lang->pager->pageSize = "<strong>{recPerPage}</strong> per page";
|
||||
$lang->pager->itemsRange = "From <strong>{start}</strong> to <strong>{end}</strong>";
|
||||
$lang->pager->pageOfTotal = "Page <strong>{page}</strong> of <strong>{totalPage}</strong>";
|
||||
$lang->pager->totalCountAB = "Total: {recTotal} items";
|
||||
$lang->pager->pageSizeAB = "{recPerPage} per page";
|
||||
|
||||
$lang->colorPicker = new stdclass();
|
||||
$lang->colorPicker->errorTip = 'Not a valid color value';
|
||||
|
||||
@@ -512,6 +512,8 @@ $lang->pager->totalCount = "Total: <strong>{recTotal}</strong> items";
|
||||
$lang->pager->pageSize = "<strong>{recPerPage}</strong> per page";
|
||||
$lang->pager->itemsRange = "From <strong>{start}</strong> to <strong>{end}</strong>";
|
||||
$lang->pager->pageOfTotal = "Page <strong>{page}</strong> of <strong>{totalPage}</strong>";
|
||||
$lang->pager->totalCountAB = "Total: {recTotal} items";
|
||||
$lang->pager->pageSizeAB = "{recPerPage} per page";
|
||||
|
||||
$lang->colorPicker = new stdclass();
|
||||
$lang->colorPicker->errorTip = 'Not a valid color value';
|
||||
|
||||
@@ -498,6 +498,8 @@ $lang->pager->totalCount = "Total: <strong>{recTotal}</strong> lignes";
|
||||
$lang->pager->pageSize = "<strong>{recPerPage}</strong> par page";
|
||||
$lang->pager->itemsRange = "De <strong>{start}</strong> à <strong>{end}</strong>";
|
||||
$lang->pager->pageOfTotal = "Page <strong>{page}</strong> sur <strong>{totalPage}</strong>";
|
||||
$lang->pager->totalCountAB = "Total: {recTotal} lignes";
|
||||
$lang->pager->pageSizeAB = "{recPerPage} par page";
|
||||
|
||||
$lang->colorPicker = new stdclass();
|
||||
$lang->colorPicker->errorTip = "Ce n'est pas une valeur de couleur valide";
|
||||
|
||||
@@ -512,6 +512,8 @@ $lang->pager->totalCount = '共 <strong>{recTotal}</strong> 项';
|
||||
$lang->pager->pageSize = '每页 <strong>{recPerPage}</strong> 项';
|
||||
$lang->pager->itemsRange = '第 <strong>{start}</strong> ~ <strong>{end}</strong> 项';
|
||||
$lang->pager->pageOfTotal = '第 <strong>{page}</strong>/<strong>{totalPage}</strong> 页';
|
||||
$lang->pager->totalCountAB = '共 {recTotal} 项';
|
||||
$lang->pager->pageSizeAB = '每页 {recPerPage} 项';
|
||||
|
||||
$lang->colorPicker = new stdclass();
|
||||
$lang->colorPicker->errorTip = '不是有效的颜色值';
|
||||
|
||||
+18
-2
@@ -1,4 +1,6 @@
|
||||
<?php
|
||||
global $lang;
|
||||
|
||||
$config->program = new stdclass();
|
||||
$config->program->suffix['c'] = "cpp";
|
||||
$config->program->suffix['cpp'] = "cpp";
|
||||
@@ -66,8 +68,9 @@ $config->repo->gitlab->apiPath = "%s/api/v4/projects/%s/repository/";
|
||||
$config->repo->gitea = new stdclass;
|
||||
$config->repo->gitea->apiPath = "%s/api/v1/repos/%s/";
|
||||
|
||||
$config->repo->gitServiceList = array('gitlab', 'gitea', 'gogs');
|
||||
$config->repo->gitTypeList = array('Gitlab', 'Gitea', 'Gogs', 'Git');
|
||||
$config->repo->gitServiceList = array('gitlab', 'gitea', 'gogs');
|
||||
$config->repo->gitServiceTypeList = array('Gitlab', 'Gitea', 'Gogs');
|
||||
$config->repo->gitTypeList = array('Gitlab', 'Gitea', 'Gogs', 'Git');
|
||||
|
||||
$config->repo->rules['module']['task'] = 'Task';
|
||||
$config->repo->rules['module']['bug'] = 'Bug';
|
||||
@@ -151,3 +154,16 @@ $config->repo->fileExt["vb"] = array('.vb');
|
||||
$config->repo->fileExt["verilog"] = array('.v', '.vh');
|
||||
$config->repo->fileExt["xml"] = array('.xml', '.dtd', '.ascx', '.csproj', '.config', '.wxi', '.wxl', '.wxs', '.xaml', '.svg', '.svgz', '.opf', '.xsl');
|
||||
$config->repo->fileExt["yaml"] = array('.yaml', '.yml');
|
||||
|
||||
$config->repo->search['module'] = 'repo';
|
||||
$config->repo->search['fields']['name'] = $lang->repo->name;
|
||||
$config->repo->search['fields']['id'] = $lang->repo->id;
|
||||
$config->repo->search['fields']['product'] = $lang->repo->product;
|
||||
$config->repo->search['fields']['projects'] = $lang->repo->projects;
|
||||
$config->repo->search['fields']['SCM'] = $lang->repo->SCM;
|
||||
$config->repo->search['fields']['desc'] = $lang->repo->desc;
|
||||
|
||||
$config->repo->search['params']['name'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
|
||||
$config->repo->search['params']['product'] = array('operator' => 'include', 'control' => 'select', 'values' => '');
|
||||
$config->repo->search['params']['projects'] = array('operator' => 'include', 'control' => 'select', 'values' => '');
|
||||
$config->repo->search['params']['SCM'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->repo->scmList);
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
global $lang, $app;
|
||||
$app->loadLang('sonarqube');
|
||||
|
||||
$config->repo->dtable = new stdclass();
|
||||
|
||||
$config->repo->dtable->fieldList['name']['name'] = 'name';
|
||||
$config->repo->dtable->fieldList['name']['title'] = $lang->repo->name;
|
||||
$config->repo->dtable->fieldList['name']['type'] = 'title';
|
||||
$config->repo->dtable->fieldList['name']['width'] = '0.2';
|
||||
|
||||
$config->repo->dtable->fieldList['product']['name'] = 'productNames';
|
||||
$config->repo->dtable->fieldList['product']['title'] = $lang->repo->product;
|
||||
$config->repo->dtable->fieldList['product']['type'] = 'text';
|
||||
$config->repo->dtable->fieldList['product']['sortType'] = true;
|
||||
$config->repo->dtable->fieldList['product']['width'] = '136';
|
||||
|
||||
$config->repo->dtable->fieldList['project']['name'] = 'projectNames';
|
||||
$config->repo->dtable->fieldList['project']['title'] = $lang->repo->projects;
|
||||
$config->repo->dtable->fieldList['project']['type'] = 'text';
|
||||
$config->repo->dtable->fieldList['project']['sortType'] = true;
|
||||
$config->repo->dtable->fieldList['project']['width'] = '136';
|
||||
|
||||
$config->repo->dtable->fieldList['scm']['name'] = 'SCM';
|
||||
$config->repo->dtable->fieldList['scm']['title'] = $lang->repo->type;
|
||||
$config->repo->dtable->fieldList['scm']['type'] = 'scm';
|
||||
$config->repo->dtable->fieldList['scm']['map'] = $lang->repo->scmList;
|
||||
$config->repo->dtable->fieldList['scm']['group'] = 1;
|
||||
|
||||
$config->repo->dtable->fieldList['path']['name'] = 'codePath';
|
||||
$config->repo->dtable->fieldList['path']['title'] = $lang->repo->path;
|
||||
$config->repo->dtable->fieldList['path']['type'] = 'text';
|
||||
$config->repo->dtable->fieldList['path']['width'] = '260';
|
||||
$config->repo->dtable->fieldList['path']['group'] = 1;
|
||||
|
||||
$config->repo->dtable->fieldList['lastSubmit']['name'] = 'lastSubmitTime';
|
||||
$config->repo->dtable->fieldList['lastSubmit']['title'] = $lang->repo->lastSubmitTime;
|
||||
$config->repo->dtable->fieldList['lastSubmit']['type'] = 'datetime';
|
||||
$config->repo->dtable->fieldList['lastSubmit']['width'] = '128';
|
||||
|
||||
$config->repo->dtable->fieldList['job']['name'] = 'job';
|
||||
$config->repo->dtable->fieldList['job']['hidden'] = true;
|
||||
|
||||
$config->repo->dtable->fieldList['actions']['name'] = 'actions';
|
||||
$config->repo->dtable->fieldList['actions']['title'] = $lang->actions;
|
||||
$config->repo->dtable->fieldList['actions']['type'] = 'actions';
|
||||
$config->repo->dtable->fieldList['actions']['width'] = '132';
|
||||
$config->repo->dtable->fieldList['actions']['menu'] = array('execJob', 'reportView', 'edit', 'delete');
|
||||
|
||||
$config->repo->dtable->fieldList['actions']['list']['edit']['icon'] = 'edit';
|
||||
$config->repo->dtable->fieldList['actions']['list']['edit']['hint'] = $lang->repo->edit;
|
||||
|
||||
$config->repo->dtable->fieldList['actions']['list']['execJob']['icon'] = 'sonarqube';
|
||||
$config->repo->dtable->fieldList['actions']['list']['execJob']['hint'] = $lang->sonarqube->execJob;
|
||||
$config->repo->dtable->fieldList['actions']['list']['execJob']['url'] = helper::createLink('sonarqube', 'execJob', "jobID={jobID}");
|
||||
$config->repo->dtable->fieldList['actions']['list']['execJob']['data-toggle'] = 'modal';
|
||||
|
||||
$config->repo->dtable->fieldList['actions']['list']['reportView']['icon'] = 'audit';
|
||||
$config->repo->dtable->fieldList['actions']['list']['reportView']['hint'] = $lang->sonarqube->reportView;
|
||||
$config->repo->dtable->fieldList['actions']['list']['reportView']['url'] = helper::createLink('sonarqube', 'reportView', "jobID={jobID}");
|
||||
$config->repo->dtable->fieldList['actions']['list']['reportView']['data-toggle'] = 'modal';
|
||||
|
||||
$config->repo->dtable->fieldList['actions']['list']['delete']['icon'] = 'trash';
|
||||
$config->repo->dtable->fieldList['actions']['list']['delete']['hint'] = $lang->repo->delete;
|
||||
$config->repo->dtable->fieldList['actions']['list']['delete']['data-toggle'] = 'modal';
|
||||
|
||||
$config->repo->repoDtable = new stdclass();
|
||||
|
||||
$config->repo->repoDtable->fieldList['name']['name'] = 'name';
|
||||
$config->repo->repoDtable->fieldList['name']['title'] = $lang->repo->name;
|
||||
$config->repo->repoDtable->fieldList['name']['minWidth'] = '160';
|
||||
$config->repo->repoDtable->fieldList['name']['sortType'] = false;
|
||||
$config->repo->repoDtable->fieldList['name']['type'] = 'shortTitle';
|
||||
$config->repo->repoDtable->fieldList['name']['fixed'] = false;
|
||||
$config->repo->repoDtable->fieldList['name']['hint'] = true;
|
||||
$config->repo->repoDtable->fieldList['name']['checkbox'] = false;
|
||||
|
||||
$config->repo->repoDtable->fieldList['revision']['name'] = 'revision';
|
||||
$config->repo->repoDtable->fieldList['revision']['title'] = $lang->repo->revisions;
|
||||
$config->repo->repoDtable->fieldList['revision']['sortType'] = false;
|
||||
$config->repo->repoDtable->fieldList['revision']['width'] = '90';
|
||||
$config->repo->repoDtable->fieldList['revision']['hint'] = true;
|
||||
|
||||
$config->repo->repoDtable->fieldList['time']['name'] = 'date';
|
||||
$config->repo->repoDtable->fieldList['time']['title'] = $lang->repo->time;
|
||||
$config->repo->repoDtable->fieldList['time']['sortType'] = false;
|
||||
$config->repo->repoDtable->fieldList['time']['type'] = 'date';
|
||||
$config->repo->repoDtable->fieldList['time']['hint'] = true;
|
||||
|
||||
$config->repo->repoDtable->fieldList['committer']['name'] = 'account';
|
||||
$config->repo->repoDtable->fieldList['committer']['title'] = $lang->repo->committer;
|
||||
$config->repo->repoDtable->fieldList['committer']['sortType'] = false;
|
||||
$config->repo->repoDtable->fieldList['committer']['type'] = 'user';
|
||||
$config->repo->repoDtable->fieldList['committer']['hint'] = true;
|
||||
|
||||
$config->repo->repoDtable->fieldList['comment']['name'] = 'originalComment';
|
||||
$config->repo->repoDtable->fieldList['comment']['title'] = $lang->repo->comment;
|
||||
$config->repo->repoDtable->fieldList['comment']['sortType'] = false;
|
||||
$config->repo->repoDtable->fieldList['comment']['type'] = 'text';
|
||||
$config->repo->repoDtable->fieldList['comment']['hint'] = true;
|
||||
|
||||
$config->repo->commentDtable = new stdclass();
|
||||
|
||||
$config->repo->commentDtable->fieldList['id']['title'] = '';
|
||||
$config->repo->commentDtable->fieldList['id']['name'] = '';
|
||||
$config->repo->commentDtable->fieldList['id']['type'] = 'checkID';
|
||||
$config->repo->commentDtable->fieldList['id']['fixed'] = false;
|
||||
$config->repo->commentDtable->fieldList['id']['sortType'] = false;
|
||||
$config->repo->commentDtable->fieldList['id']['checkbox'] = true;
|
||||
$config->repo->commentDtable->fieldList['id']['width'] = '25';
|
||||
|
||||
$config->repo->commentDtable->fieldList['revision']['name'] = 'revision';
|
||||
$config->repo->commentDtable->fieldList['revision']['title'] = $lang->repo->revisions;
|
||||
$config->repo->commentDtable->fieldList['revision']['sortType'] = false;
|
||||
$config->repo->commentDtable->fieldList['revision']['type'] = 'title';
|
||||
$config->repo->commentDtable->fieldList['revision']['fixed'] = false;
|
||||
$config->repo->commentDtable->fieldList['revision']['width'] = '100';
|
||||
$config->repo->commentDtable->fieldList['revision']['hint'] = true;
|
||||
|
||||
$config->repo->commentDtable->fieldList['commit']['name'] = 'commit';
|
||||
$config->repo->commentDtable->fieldList['commit']['title'] = $lang->repo->commit;
|
||||
$config->repo->commentDtable->fieldList['commit']['sortType'] = false;
|
||||
$config->repo->commentDtable->fieldList['commit']['width'] = '40';
|
||||
$config->repo->commentDtable->fieldList ['commit']['hint'] = true;
|
||||
|
||||
$config->repo->commentDtable->fieldList['time'] = $config->repo->repoDtable->fieldList['time'];
|
||||
$config->repo->commentDtable->fieldList['committer'] = $config->repo->repoDtable->fieldList['committer'];
|
||||
$config->repo->commentDtable->fieldList['comment'] = $config->repo->repoDtable->fieldList['comment'];
|
||||
|
||||
$config->repo->commentDtable->fieldList['comment']['name'] = 'originalComment';
|
||||
$config->repo->commentDtable->fieldList['committer']['name'] = 'committer';
|
||||
|
||||
$config->repo->logDtable = new stdclass();
|
||||
|
||||
$config->repo->logDtable->fieldList['id']['hidden'] = true;
|
||||
|
||||
$config->repo->logDtable->fieldList['revision']['type'] = 'revision';
|
||||
$config->repo->logDtable->fieldList['revision']['width'] = '100';
|
||||
$config->repo->logDtable->fieldList['revision']['checkbox'] = true;
|
||||
$config->repo->logDtable->fieldList['revision']['nestedToggle'] = false;
|
||||
|
||||
$config->repo->logDtable->fieldList['commit']['type'] = 'number';
|
||||
$config->repo->logDtable->fieldList['commit']['width'] = '50';
|
||||
$config->repo->logDtable->fieldList['commit']['sortType'] = false;
|
||||
|
||||
$config->repo->logDtable->fieldList['date']['name'] = 'time';
|
||||
$config->repo->logDtable->fieldList['date']['type'] = 'datetime';
|
||||
$config->repo->logDtable->fieldList['date']['sortType'] = false;
|
||||
|
||||
$config->repo->logDtable->fieldList['committer']['name'] = 'committer';
|
||||
|
||||
$config->repo->logDtable->fieldList['comment']['type'] = 'html';
|
||||
$config->repo->logDtable->fieldList['comment']['width'] = '600';
|
||||
|
||||
$config->repo->blameDtable = new stdclass();
|
||||
|
||||
$config->repo->blameDtable->fieldList['revision']['type'] = 'revision';
|
||||
$config->repo->blameDtable->fieldList['revision']['width'] = '120';
|
||||
|
||||
$config->repo->blameDtable->fieldList['commit']['type'] = 'number';
|
||||
$config->repo->blameDtable->fieldList['commit']['sortType'] = false;
|
||||
$config->repo->blameDtable->fieldList['commit']['width'] = '80';
|
||||
|
||||
$config->repo->blameDtable->fieldList['committer']['name'] = 'committer';
|
||||
$config->repo->blameDtable->fieldList['committer']['width'] = '150';
|
||||
|
||||
$config->repo->blameDtable->fieldList['line']['type'] = 'number';
|
||||
$config->repo->blameDtable->fieldList['line']['sortType'] = false;
|
||||
$config->repo->blameDtable->fieldList['line']['width'] = '80';
|
||||
|
||||
$config->repo->blameDtable->fieldList['content']['title'] = $lang->repo->code;
|
||||
$config->repo->blameDtable->fieldList['content']['type'] = 'html';
|
||||
$config->repo->blameDtable->fieldList['content']['width'] = '700';
|
||||
|
||||
$app->loadLang('task');
|
||||
$app->loadModuleConfig('task');
|
||||
|
||||
$config->repo->taskDtable = new stdclass();
|
||||
$config->repo->taskDtable->fieldList = array();
|
||||
$config->repo->taskDtable->fieldList['id']['name'] = 'id';
|
||||
$config->repo->taskDtable->fieldList['id']['title'] = $lang->idAB;
|
||||
$config->repo->taskDtable->fieldList['id']['type'] = 'id';
|
||||
$config->repo->taskDtable->fieldList['id']['checkbox'] = true;
|
||||
|
||||
$config->repo->taskDtable->fieldList['pri']['title'] = $lang->priAB;
|
||||
$config->repo->taskDtable->fieldList['pri']['type'] = 'pri';
|
||||
$config->repo->taskDtable->fieldList['pri']['sortType'] = true;
|
||||
$config->repo->taskDtable->fieldList['pri']['show'] = true;
|
||||
$config->repo->taskDtable->fieldList['pri']['group'] = 1;
|
||||
$config->repo->taskDtable->fieldList['pri']['fixed'] = 'left';
|
||||
|
||||
$config->repo->taskDtable->fieldList ['name']['flex'] = 1;
|
||||
$config->repo->taskDtable->fieldList ['name']['nestedToggle'] = false;
|
||||
$config->repo->taskDtable->fieldList ['name']['sortType'] = true;
|
||||
$config->repo->taskDtable->fieldList ['name']['required'] = true;
|
||||
$config->repo->taskDtable->fieldList['name']['data-size'] = 'lg';
|
||||
$config->repo->taskDtable->fieldList['name']['data-toggle'] = 'modal';
|
||||
$config->repo->taskDtable->fieldList ['name']['fixed'] = 'left';
|
||||
$config->repo->taskDtable->fieldList ['name']['type'] = 'nestedTitle';
|
||||
$config->repo->taskDtable->fieldList ['name']['link'] = array('module' => 'task', 'method' => 'view', 'params' => 'taskID={id}');
|
||||
$config->repo->taskDtable->fieldList['name']['title'] = $lang->task->name;
|
||||
|
||||
$config->repo->taskDtable->fieldList['finishedBy']['title'] = $lang->task->finishedByAB;
|
||||
$config->repo->taskDtable->fieldList['finishedBy']['type'] = 'user';
|
||||
$config->repo->taskDtable->fieldList['finishedBy']['sortType'] = true;
|
||||
$config->repo->taskDtable->fieldList['finishedBy']['show'] = true;
|
||||
$config->repo->taskDtable->fieldList['finishedBy']['group'] = 4;
|
||||
|
||||
$config->repo->taskDtable->fieldList['assignedTo']['type'] = 'assign';
|
||||
$config->repo->taskDtable->fieldList['assignedTo']['sortType'] = true;
|
||||
$config->repo->taskDtable->fieldList['assignedTo']['show'] = true;
|
||||
$config->repo->taskDtable->fieldList['assignedTo']['group'] = 3;
|
||||
$config->repo->taskDtable->fieldList['assignedTo']['currentUser'] = $app->user->account;
|
||||
$config->repo->taskDtable->fieldList['assignedTo']['title'] = $lang->task->assignedTo;
|
||||
$config->repo->taskDtable->fieldList['assignedTo']['assignLink'] = array('module' => 'task', 'method' => 'assignTo', 'params' => 'executionID={execution}&taskID={id}');
|
||||
|
||||
$config->repo->taskDtable->fieldList['status']['title'] = $lang->statusAB;
|
||||
$config->repo->taskDtable->fieldList['status']['type'] = 'status';
|
||||
$config->repo->taskDtable->fieldList['status']['statusMap'] = $lang->task->statusList;
|
||||
$config->repo->taskDtable->fieldList['status']['sortType'] = true;
|
||||
$config->repo->taskDtable->fieldList['status']['show'] = true;
|
||||
$config->repo->taskDtable->fieldList['status']['group'] = 1;
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
$config->repo->form = new stdclass();
|
||||
|
||||
$config->repo->form->create = array();
|
||||
$config->repo->form->create['product'] = array('required' => true, 'type' => 'array');
|
||||
$config->repo->form->create['projects'] = array('required' => false, 'type' => 'array', 'default' => array());
|
||||
$config->repo->form->create['SCM'] = array('required' => true, 'type' => 'string', 'filter' => 'trim');
|
||||
$config->repo->form->create['serviceHost'] = array('required' => true, 'type' => 'int');
|
||||
$config->repo->form->create['serviceProject'] = array('required' => false, 'type' => 'string', 'default' => '');
|
||||
$config->repo->form->create['name'] = array('required' => true, 'type' => 'string', 'filter' => 'trim');
|
||||
$config->repo->form->create['path'] = array('required' => false, 'type' => 'string', 'default' => '');
|
||||
$config->repo->form->create['encoding'] = array('required' => true, 'type' => 'string');
|
||||
$config->repo->form->create['client'] = array('required' => false, 'type' => 'string', 'default' => '');
|
||||
$config->repo->form->create['account'] = array('required' => false, 'type' => 'string', 'default' => '');
|
||||
$config->repo->form->create['password'] = array('required' => false, 'type' => 'string', 'default' => '');
|
||||
$config->repo->form->create['encrypt'] = array('required' => false, 'type' => 'string', 'default' => '');
|
||||
$config->repo->form->create['desc'] = array('required' => false, 'type' => 'string', 'default' => '');
|
||||
+219
-264
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
.m-repo-ajaxgeteditorcontent {overflow: hidden;}
|
||||
#log .tip-circular {background: #2e7fff; border-radius: 10px; padding: 0px 7px;}
|
||||
#log {margin-top: 8px; display: none; padding: 5px; justify-content: space-between; height: 25px; line-height: 20px; background: #efefef;}
|
||||
#log .history {margin-left: 5px; max-width: 90%;}
|
||||
#log .action-btn .btn {border: none; background: none;}
|
||||
#related {display: none; margin-top: 2px; background: #fff; height: 0px;}
|
||||
|
||||
#relationTabs .nav > li > a {padding: 8px 1px; display: flex; white-space: pre;}
|
||||
#relationTabs .nav-tabs > li > a > span {margin-right: 5px;}
|
||||
#relationTabs .tab-pane {display: none;}
|
||||
#relationTabs {background: #FFFFFF;}
|
||||
#relationTabs .tab-pane.active {display: block;}
|
||||
#relationTabs .tab-nav-item {max-width: none !important;}
|
||||
#relationTabs .tab-nav-item .icon {line-height: inherit;}
|
||||
#relationTabs {overflow: hidden; padding-bottom: 10px; position: relative; height: 100%;}
|
||||
#relationTabs > .nav-tabs {position: absolute; display: flex;}
|
||||
#relationTabs .tab-nav-link .title {max-width: 300px; display: inline-block; white-space: nowrap; width: 100%; overflow: hidden; text-overflow: ellipsis; padding: 0 5px;}
|
||||
#relationTabs{width: 100%}
|
||||
#relationTabs .nav-tabs > li > a.active > span {background: #E6F0FF;color: #2e7fff;}
|
||||
#relationTabs .nav-tabs > li > a > i, #relationTabs .nav-tabs > li > a > span {background: #EDEEF2; font-weight: normal; padding: 1px 5px;}
|
||||
#relationTabs .nav-tabs > li > a > span > i {margin-right: 8px;}
|
||||
#relationTabs .nav-tabs > li > .unlinks {padding-left: 0;color: #169}
|
||||
#relationTabs .nav-tabs > li > .unlinks:hover {text-decoration: underline;color: #C61A1A;}
|
||||
#relationTabs .nav-tabs > li > .unlinks > i {background: none;padding: 0;}
|
||||
#relationTabs .nav-tabs>.nav-item>a.active:after{border: none;}
|
||||
#relationTabs .tab-content{margin-top: 40px;}
|
||||
#related .content, #related .btn {background-color: #F4F5F7; border: none;}
|
||||
#related .btn.pull-right {margin-right: 0;z-index: 1;}
|
||||
#related .btn.pull-left {z-index: 1;}
|
||||
#related .nav-tabs > li > a.active:before {background: none; height: 0;}
|
||||
#related .table-empty-tip {padding: 35px 10px;}
|
||||
.table-empty-tip {padding: 80px 10px;text-align: center;background: #fff;}
|
||||
.repoCode .binary a .icon-download {font-size: 50px;}
|
||||
.repoCode .binary, .repoCode .image {text-align: center;}
|
||||
.repoCode .binary a {margin: 100px 0px; display: block;}
|
||||
.repoCode .image {margin-top: 10px;}
|
||||
#codeContainer{height: 100%;}
|
||||
#related .nav-item {gap: 0;}
|
||||
.nav-tabs>li>a.active {font-weight: 700;color: #313c52!important}
|
||||
@@ -0,0 +1 @@
|
||||
#featureBar .nav .btn>.icon {color: #ffffff;}
|
||||
@@ -0,0 +1,7 @@
|
||||
.repo-downloadCode{margin: 8px 10px 8px 0;}
|
||||
.repo-select{margin-right: 10px;}
|
||||
.repo-comment{width: 100%; display: block; word-break: keep-all; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;}
|
||||
.dtable-cell-html{width: 100%;}
|
||||
.container .sidebar{width: 550px;}
|
||||
#actionBar .dropdown-menu {margin-top: 10px; padding: 10px;}
|
||||
#actionBar>.dropdown {position: absolute!important;}
|
||||
@@ -0,0 +1,53 @@
|
||||
#fileTabs .nav-tabs {overflow: hidden;position: absolute; height: 40px;background: #efefef;}
|
||||
#fileTabs .nav-tabs > li.nav-item > a {z-index: 1; background: none; padding: 1.7rem; cursor: pointer !important; margin-left: -25px; margin-top: 12px;}
|
||||
#fileTabs .nav-tabs > li > a::after {content: ''; position: absolute; top: 2px; left: 10px; width: 85%; right: 6px; bottom: 0; background: #f8f8f8; border: none; border-radius: 10px 10px 0 0; transform: perspective(0.5rem) rotateX(2deg); z-index: -1;}
|
||||
#fileTabs .nav-tabs > li > a.active span {font-weight: 700; color: #2b80ff!important;}
|
||||
#fileTabs .nav-tabs > li > a.active::after {background: #fff;}
|
||||
#fileTabs > .nav-tabs {overflow: hidden; padding-bottom: 10px; position: relative; height: 40px; background: #efefef;}
|
||||
#fileTabs > .nav-tabs {position: absolute; display: flex; padding-left: 25px;}
|
||||
#fileTabs .monaco-close{margin-right: 18px;}
|
||||
#fileTabs .nav-tabs > li > a > span{margin-left: 18px;font-weight: 700;color: #313c52!important;}
|
||||
#related .btn-right, #related .btn-left {padding-top: 9px;}
|
||||
#log .action-btn {margin-top: -7px;}
|
||||
.repoCode .btn.btn-right, .repoCode .btn.btn-left {margin-right: 0; padding: 6px 6px;}
|
||||
#related .btn-right, #related .btn-left {padding-top: 9px;}
|
||||
.btn-left, .btn-right {display: none;}
|
||||
#linkObject{display: none;}
|
||||
#related .btn-right, #related .btn-left {padding-top: 9px;}
|
||||
#monacoTree .tree-item-content span {cursor: pointer;}
|
||||
.directory {background-image:url('theme/default/images/repo/dir.png');}
|
||||
.file {background-image:url('theme/default/images/repo/txt.png');}
|
||||
.mini-icon {display: inline-block; height: 16px; width: 16px; background-color: transparent; background-position: 0 0; background-repeat: no-repeat; vertical-align: text-bottom; margin-right: 5px;}
|
||||
#monacoTree .tree-item-content {cursor: pointer;}
|
||||
.sync-content {margin: 10px}
|
||||
.sync-main-content {padding: 20px;background-color: #fff;border-radius: 4px;}
|
||||
.sync-line {border-top: 1px solid #e4e4e4; margin: 10px 0;}
|
||||
.sync-main-content div {width: 100%;}
|
||||
.sync-main-content h3 {font-size: 16px; font-weight: 700;}
|
||||
.sync-main-content p {color: #313c52;}
|
||||
.sync-main-content .alert > [class*="icon-"] {font-size: 42px;opacity: 0.8;}
|
||||
.repo-linkstory-title {background-color: #e6f0ff; color: #2e7fff; padding: 12px 6px 12px;}
|
||||
#repoBranchDropMenu .dropmenu-btn {justify-content: space-between; width: 100%;}
|
||||
#monacoTabs .nav > li > a {padding: 8px 10px; display: flex; white-space: pre;}
|
||||
#monacoTabs .nav-tabs > li > a > span {margin-right: 5px;}
|
||||
#monacoTabs .tab-pane {display: none;}
|
||||
#monacoTabs {background: #FFFFFF;}
|
||||
#monacoTabs .tab-pane.active {display: block;}
|
||||
#monacoTabs .tab-nav-item {max-width: none !important;}
|
||||
#monacoTabs .tab-nav-item .icon {line-height: inherit;}
|
||||
#monacoTabs {overflow: hidden; position: relative; height: 100%;}
|
||||
#monacoTabs > .nav-tabs {position: absolute; display: flex; padding-right: 20px;}
|
||||
#fileTabs .arrow-left, #fileTabs .arrow-right {line-height: 28px; padding: 6px; width: 26px; background: #efefef; cursor: pointer;}
|
||||
#fileTabs .arrow-right {right: 40px; cursor: pointer;}
|
||||
#monacoTabs ul {min-width: 100%; padding-left: 25px; z-index: 1;}
|
||||
#monacoTabs .tab-content {margin-top: 40px;}
|
||||
#monacoTabsContainer {background: #efefef;}
|
||||
.monaco-dropmenu{background: #efefef; height: 40px; line-height: 40px;}
|
||||
#fileTabs > .btn {background: #efefef; border: none; --tw-ring-shadow: none;}
|
||||
#fileTabs > .btn-right {padding-right: 40px;}
|
||||
#repoBranchDropMenu > .dropmenu-btn {background: white; --tw-ring-color: none; color: inherit; margin-bottom: 10px; background: white;}
|
||||
.repo-select #repoBranchDropMenu > .dropmenu-btn {background: inherit; --tw-ring-color: none; color: inherit; margin-bottom: 0;}
|
||||
#repoBranchDropMenu > .dropmenu-btn > .icon-angle-right {display: none;}
|
||||
#log .action-btn .caret {display: none;}
|
||||
#fileTabs .monaco-dropmenu .caret {display: none;}
|
||||
#monacoTabs .gap-x-5 {-moz-column-gap: 0; column-gap: 0;}
|
||||
@@ -0,0 +1,18 @@
|
||||
.diff-back-btn {border: none; --tw-ring-shadow: none}
|
||||
.diff-back-btn::after {border: none;}
|
||||
.diff-back-btn::before {border: none;}
|
||||
.label-info {background-color: #37b2fe}
|
||||
.label-info[href]:focus,.label-info[href]:hover {color: #fff; background-color: #049efe}
|
||||
.label-info.label-outline {color: #37b2fe; background: 0 0; border: 1px solid #37b2fe}
|
||||
.label {padding: .2em .6em .2em; color: #fff;text-align: center; white-space: nowrap; vertical-align: middle; border-radius: .25em;}
|
||||
.diff-label {border: none; --tw-ring-shadow: none; margin-left: 5px; margin-right: 10px}
|
||||
.label-exchange {background-color: #566F7C; cursor: pointer;}
|
||||
|
||||
#fileTabs .tab-pane {display: none;}
|
||||
#fileTabs .tab-pane.active {display: block;}
|
||||
#fileTabs .nav-item {max-width: none !important;}
|
||||
.sidebar .tree{background-color: white;}
|
||||
.container .sidebar{width: 240px;}
|
||||
.tree li.tree-item.selected{color: #438EFF !important;}
|
||||
#monacoTree{overflow: auto;}
|
||||
.monaco-dropmenu{background: #efefef;}
|
||||
@@ -0,0 +1,3 @@
|
||||
.form-batch-row-actions>button:first-child {display: none;}
|
||||
#repoList tr td:last-child, #repoList tr th:last-child {text-align: right;}
|
||||
#repoList tr td:first-child {text-align: center;}
|
||||
@@ -0,0 +1 @@
|
||||
#featureBar .nav .btn>.icon {color: #ffffff;}
|
||||
@@ -0,0 +1 @@
|
||||
.btn-active-text {font-weight: 700; color: #1e6aeb; background: #e6eaf1; --tw-ring-color: var(--color-transparent);}
|
||||
@@ -0,0 +1,7 @@
|
||||
#fileTabs .tab-pane {display: none;}
|
||||
#fileTabs .tab-pane.active {display: block;}
|
||||
#fileTabs .nav-item {max-width: none !important;}
|
||||
.sidebar .tree{background-color: white;}
|
||||
.container .sidebar{width: 240px;}
|
||||
.tree li.tree-item.selected{color: #438EFF !important;}
|
||||
#monacoTree{overflow: auto;}
|
||||
@@ -0,0 +1,236 @@
|
||||
var blames = null;
|
||||
var codeHeight = 0;
|
||||
|
||||
window.onMouseDown = function(obj)
|
||||
{
|
||||
showBlameAndRelation(obj.target.position.lineNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示关联信息弹窗。
|
||||
* Show blame info and relations.
|
||||
*
|
||||
* @param int line
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function showBlameAndRelation(line)
|
||||
{
|
||||
if(!blames) return;
|
||||
|
||||
if(pageType == 'diff') line = diffContent.line.new[line -1];
|
||||
|
||||
var blame = blames[line];
|
||||
|
||||
if(!blame) return;
|
||||
|
||||
var p_line = parseInt(line);
|
||||
while(!blame.revision)
|
||||
{
|
||||
p_line--;
|
||||
blame = blames[p_line];
|
||||
}
|
||||
if($('#log').data('line') == line) return;
|
||||
|
||||
var time = blame.time != 'unknown' ? blame.time : '';
|
||||
var user = blame.committer != 'unknown' ? blame.committer : '';
|
||||
var version = blame.revision.toString().substring(0, 10);
|
||||
var content = blameTmpl.replace('%line', line).replace('%time', time).replace('%name', user).replace('%version', version).replace('%comment', blame.message);
|
||||
$('.history').html(content);
|
||||
$('#log').data('line', line);
|
||||
$('#log').css('display', 'flex');
|
||||
getRelation(blame.revision);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关联信息。
|
||||
* Get relation by commit.
|
||||
*
|
||||
* @param string $commit
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.getRelation = function(commit)
|
||||
{
|
||||
$('.table-empty-tip').show();
|
||||
$('#codeContainer').css('height', codeHeight / 5 * 3);
|
||||
var relatedHeight = codeHeight / 5 * 2 - $('#log').height() - 10;
|
||||
$('#related').css('height', relatedHeight);
|
||||
$('#relationTabs ul li').remove();
|
||||
$('#relationTabs .tab-content .tab-pane').remove();
|
||||
|
||||
$.post($.createLink('repo', 'ajaxGetCommitRelation', 'repoID=' + repoID + '&commit=' + commit), function(data)
|
||||
{
|
||||
var titleList = JSON.parse(data).titleList;
|
||||
$.each(titleList, function(i, titleObj)
|
||||
{
|
||||
openTab(titleObj);
|
||||
});
|
||||
|
||||
if(titleList.length > 0)
|
||||
{
|
||||
$('.table-empty-tip').hide();
|
||||
$('#related button').show();
|
||||
$('#relationTabs ul li a').first().trigger('click');
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!canLinkStory && !canLinkBug && !canLinkTask) $('#related button').hide();
|
||||
}
|
||||
|
||||
arrowTabs('relationTabs', 1);
|
||||
});
|
||||
|
||||
globalCommit = commit;
|
||||
var linkStory = $.createLink('repo', 'linkStory', 'repoID=' + repoID + '&commit=' + commit, '', true);
|
||||
var linkBug = $.createLink('repo', 'linkBug', 'repoID=' + repoID + '&commit=' + commit, '', true);
|
||||
var linkTask = $.createLink('repo', 'linkTask', 'repoID=' + repoID + '&commit=' + commit, '', true);
|
||||
$('#linkStory').data('link', linkStory);
|
||||
$('#linkBug').data('link', linkBug);
|
||||
$('#linkTask').data('link', linkTask);
|
||||
$('#related').show();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开关联信息tab。
|
||||
* Open tab.
|
||||
*
|
||||
* @param object $titleObj
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function openTab(titleObj)
|
||||
{
|
||||
var tabTemplate = `<li class="nav-item"><a class="font-medium" href="{href}" data-toggle="tab"><span><i class="icon icon-{prefixIcon}"></i>{title}</span></a><a title="{unlinkTitle}" class="unlinks" data-link="{unlinkHref}"><i class="icon icon-unlink"></i></a></li>`;
|
||||
|
||||
var eleId = titleObj.type + '-' + titleObj.id;
|
||||
var prefixIcon = titleObj.type == 'story' ? 'lightbulb' : (titleObj.type == 'task' ? 'check-sign' : 'bug');
|
||||
var unlinkHref = canUnlinkObject ? $.createLink('repo', 'unlink', 'repoID=' + repoID + '&commit=' + globalCommit + '&objectID=' + titleObj.type + '&objectType=' + titleObj.id) : '';
|
||||
var tabHtml = tabTemplate.replace('{title}', titleObj.title)
|
||||
.replace('{unlinkHref}', unlinkHref)
|
||||
.replace('{unlinkTitle}', unlinkTitle)
|
||||
.replace('{href}', '#related-' + eleId)
|
||||
.replace('{prefixIcon}', prefixIcon);
|
||||
|
||||
$('#relationTabs>ul').append(tabHtml);
|
||||
|
||||
var height = getRelationTabHeight();
|
||||
|
||||
$('#relationTabs .tab-content').append("<div id='related-" + eleId + "' class='tab-pane active in'><iframe class='repo-iframe' src='" + $.createLink('repo', 'ajaxGetRelationInfo', 'objectID=' + titleObj.id + '&objectType=' + titleObj.type) + "' width='100%' height='" + height + "' scrolling='no'></iframe></div>")
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关联信息弹窗高度。
|
||||
* Get relation tab height.
|
||||
*
|
||||
* @param object $titleObj
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function getRelationTabHeight()
|
||||
{
|
||||
var relatedHeight = $('#related').height();
|
||||
var tabHeight = $('#related #relationTabs>ul').height();
|
||||
|
||||
relatedHeight = parseInt(relatedHeight) ? parseInt(relatedHeight) : 0;
|
||||
tabHeight = parseInt(tabHeight) ? parseInt(tabHeight) : 0;
|
||||
|
||||
return relatedHeight - tabHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改比对差异方式。
|
||||
* Update diff editor inline style.
|
||||
*
|
||||
* @param bool display
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.updateEditorInline = function(display)
|
||||
{
|
||||
modifiedEditor.updateOptions({renderSideBySide: display});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取提交信息。
|
||||
* Show commit info.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function showCommitInfo()
|
||||
{
|
||||
var link = $.createLink('repo', 'ajaxGetCommitInfo');
|
||||
var data = {
|
||||
repoID : repoID,
|
||||
entry : encodePath,
|
||||
revision : revision,
|
||||
sourceRevision: sourceRevision,
|
||||
line : 0,
|
||||
returnType : 'json'
|
||||
};
|
||||
|
||||
$.post(link, data, function(res)
|
||||
{
|
||||
res = JSON.parse(res);
|
||||
blames = res.blames;
|
||||
})
|
||||
}
|
||||
|
||||
/* 初始化数据 */
|
||||
$(function()
|
||||
{
|
||||
setTimeout(() => {
|
||||
initPage();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
/**
|
||||
* 初始化页面。
|
||||
* Init page.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function initPage()
|
||||
{
|
||||
codeHeight = $.cookie.get('codeContainerHeight');
|
||||
$('#codeContainer').css('height', $.cookie.get('codeContainerHeight'));
|
||||
|
||||
$('.btn-left').on('click', function() {arrowTabs('relationTabs', 1);});
|
||||
$('.btn-right').on('click', function() {arrowTabs('relationTabs', -2);});
|
||||
|
||||
$('#linkStory, #linkBug, #linkTask').on('click', function()
|
||||
{
|
||||
var link = $(this).data('link');
|
||||
parent.loadLinkPage(link);
|
||||
});
|
||||
|
||||
$('#relationTabs').on('click', '.unlinks', function()
|
||||
{
|
||||
var link = $(this).data('link');
|
||||
$.post(link, function(data)
|
||||
{
|
||||
data = JSON.parse(data);
|
||||
if(data.result)
|
||||
{
|
||||
getRelation(data.revision);
|
||||
}
|
||||
else
|
||||
{
|
||||
alert(data.message);
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
$('#relationTabs').on('onOpen', function(event, tab)
|
||||
{
|
||||
$('#tab-nav-item-' + tab.id).attr('title', tab.title);
|
||||
|
||||
var relatedHeight = codeHeight / 5 * 2 - $('#log').height() - 45;
|
||||
$('#relationTabs iframe').css('height', relatedHeight);
|
||||
});
|
||||
|
||||
/* Get file commits. */
|
||||
showCommitInfo();
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
var revisionMap = {};
|
||||
var checkedIds = [];
|
||||
|
||||
window.renderCell = function(result, {col, row})
|
||||
{
|
||||
if(col.name === 'name')
|
||||
{
|
||||
var iconHtml = '<span class="' + (row.data.kind == 'dir' ? 'directory' : 'file') + ' mini-icon"></span>';
|
||||
result[0] = {html:iconHtml + '<a href="' + row.data.link + '">' + row.data.name + '</a>'};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if(col.name === 'originalComment')
|
||||
{
|
||||
result[0] = {html:'<span class="repo-comment">' + row.data.comment + '</span>'};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* commit表格渲染跳转链接。
|
||||
* Render jump link of version.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.renderCommentCell = function(result, {col, row})
|
||||
{
|
||||
if(col.name === 'revision')
|
||||
{
|
||||
result[0] = {html:'<a href="' + row.data.link + '">' + row.data.revision + '</a>', style:{flexDirection:"column"}};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if(col.name === 'originalComment')
|
||||
{
|
||||
result[0] = {html:'<span class="repo-comment">' + row.data.comment + '</span>', style:{flexDirection:"column"}};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/* Open download page when downZip btn click. */
|
||||
$('.downloadZip-btn').on('click', function()
|
||||
{
|
||||
var link = $.createLink('repo', 'downloadCode', 'repoID=' + repoID + '&branch=' + branch);
|
||||
window.open(link);
|
||||
})
|
||||
|
||||
/* Refresh page when repo changed. */
|
||||
$('#repo-select').on('change', function()
|
||||
{
|
||||
var index = $('#repo-select').prop('selectedIndex');
|
||||
if(menus[index - 1].url != undefined)
|
||||
{
|
||||
openUrl(menus[index - 1].url);
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 当选中两行时禁用其他行。
|
||||
* Disable checkable attribution when checked rows equal 2.
|
||||
*
|
||||
* @param object changes
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.checkedChange = function(changes)
|
||||
{
|
||||
checkedIds = getCurrentCheckedIds();
|
||||
|
||||
if(checkedIds.length < 2)
|
||||
{
|
||||
$('.btn-diff').addClass('disabled')
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.btn-diff').removeClass('disabled')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转比较差异页面。
|
||||
* Redirect to diff page.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.diffClick = function()
|
||||
{
|
||||
var checkedIds = getCurrentCheckedIds();
|
||||
var newDiffLink = diffLink.replace('{oldRevision}', revisionMap[checkedIds[1]]);
|
||||
newDiffLink = newDiffLink.replace('{newRevision}', revisionMap[checkedIds[0]]);
|
||||
|
||||
$.cookie.set('sideRepoSelected', checkedIds.join(','))
|
||||
|
||||
openUrl(newDiffLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当选中数量等于2,则禁用其他所有行。
|
||||
* When the selected row equals 2, disable all other rows.
|
||||
*
|
||||
* @param int rowID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
window.canRowCheckable = function(rowID)
|
||||
{
|
||||
const dtable = zui.DTable.query('#repo-comments-table');
|
||||
if(dtable == undefined) return;
|
||||
var data = dtable.$.props.data;
|
||||
|
||||
if(data.length == 0) return true;
|
||||
|
||||
initRevisionMap(data);
|
||||
|
||||
var currentCheckedIds = getCurrentCheckedIds();
|
||||
|
||||
if(currentCheckedIds.length < 2) return true;
|
||||
if(currentCheckedIds.indexOf(rowID) == -1) return 'disabled'
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测revisionMap是否跟当前页面数据一致,不一致重新生成。
|
||||
* Regenerate revisionMap when revisionMap is not in current list.
|
||||
*
|
||||
* @param array
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function initRevisionMap(data)
|
||||
{
|
||||
if(revisionMap[data[data.length - 1].id] !== undefined) return;
|
||||
|
||||
revisionMap = {};
|
||||
for (var i = 0; i < data.length; i++) revisionMap[data[i].id] = data[i].revision;
|
||||
|
||||
/* Check rows where id in cookie. */
|
||||
setTimeout(function()
|
||||
{
|
||||
checkColInCurrentPage()
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 选中当前页码对应的行。
|
||||
* Select the rows to the current page.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function checkColInCurrentPage()
|
||||
{
|
||||
const dtable = zui.DTable.query('#repo-comments-table');
|
||||
const checkedIds = $.cookie.get('sideRepoSelected') ? $.cookie.get('sideRepoSelected').split(',') : [];
|
||||
|
||||
|
||||
var currentCheckedIds = [];
|
||||
if(revisionMap[checkedIds[0]]) currentCheckedIds.push(checkedIds[0]);
|
||||
if(revisionMap[checkedIds[1]]) currentCheckedIds.push(checkedIds[1]);
|
||||
|
||||
dtable.$.toggleCheckRows(Object.keys(revisionMap), false);
|
||||
|
||||
if(currentCheckedIds.length > 0)
|
||||
{
|
||||
dtable.$.toggleCheckRows(currentCheckedIds, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
dtable.$.toggleCheckRows(Object.keys(revisionMap).slice(0, 2), true);
|
||||
}
|
||||
|
||||
window.checkedChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前页码选中的行。
|
||||
* Get checked rows in current page.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
function getCurrentCheckedIds()
|
||||
{
|
||||
const dtable = zui.DTable.query('#repo-comments-table');
|
||||
if(dtable.$ == undefined) return [];
|
||||
|
||||
var checkedIds = dtable.$.getChecks();
|
||||
var currentCheckedIds = [];
|
||||
|
||||
for (var i = 0; i < checkedIds.length; i++)
|
||||
{
|
||||
if(revisionMap[checkedIds[i]]) currentCheckedIds.push(checkedIds[i]);
|
||||
}
|
||||
|
||||
if(currentCheckedIds.length > 2) currentCheckedIds = currentCheckedIds.slice(0, 2);
|
||||
return currentCheckedIds;
|
||||
}
|
||||
|
||||
$('.copy-btn').on('click', function()
|
||||
{
|
||||
var copyText = $(this).parent().parent().find('input');
|
||||
copyText[0].select();
|
||||
document.execCommand("Copy");
|
||||
copyText[0].selectionStart = copyText[0].selectionEnd;
|
||||
copyText[0].blur();
|
||||
|
||||
$(that).tooltip('show');
|
||||
var that = this;
|
||||
setTimeout(function()
|
||||
{
|
||||
$(that).tooltip('hide');
|
||||
}, 2000)
|
||||
})
|
||||
|
||||
/* 此方法在页面被替换时执行。 */
|
||||
// function onPageUnmount()
|
||||
// {
|
||||
// /* 删除全局变量。 */
|
||||
// delete window.canRowCheckable;
|
||||
// delete window.diffClick;
|
||||
// delete window.checkedChange;
|
||||
// delete window.renderCommentCell;
|
||||
// delete window.renderCell;
|
||||
// }
|
||||
|
||||
window.afterPageUpdate = function()
|
||||
{
|
||||
setTimeout(function()
|
||||
{
|
||||
$('.copy-btn').tooltip({
|
||||
trigger: 'click',
|
||||
placement: 'bottom',
|
||||
title: copied,
|
||||
tipClass: 'success',
|
||||
});
|
||||
}, 200);
|
||||
};
|
||||
@@ -0,0 +1,223 @@
|
||||
$(function()
|
||||
{
|
||||
$('#log').on('click', '.btn-close', closeRelation);
|
||||
});
|
||||
|
||||
/**
|
||||
* 切换仓库。
|
||||
* Swtich repo.
|
||||
*
|
||||
* @param int $repoID
|
||||
* @param string $module
|
||||
* @param string $method
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function switchRepo(repoID, module, method)
|
||||
{
|
||||
if(typeof(eventKeyCode) == 'undefined') eventKeyCode = 0;
|
||||
if(eventKeyCode > 0 && eventKeyCode != 13) return false;
|
||||
|
||||
/* The project id is a string, use it as the project model. */
|
||||
if(isNaN(repoID))
|
||||
{
|
||||
$.cookie.set('projectMode', repoID, {expires:config.cookieLife, path:config.webRoot});
|
||||
repoID = 0;
|
||||
}
|
||||
|
||||
if(method != 'settings') method ="browse";
|
||||
link = createLink(module, method, 'repoID=' + repoID);
|
||||
location.href=link;
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换分支。
|
||||
* Switch branch for git.
|
||||
*
|
||||
* @param string $branchID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function switchBranch(branchID)
|
||||
{
|
||||
$.cookie.set('repoBranch', branchID, {expires:config.cookieLife, path:config.webRoot});
|
||||
$.cookie.set('repoRefresh', 1, {expires:config.cookieLife, path:config.webRoot});
|
||||
location.href=location.href;
|
||||
}
|
||||
|
||||
var distance = 0;
|
||||
|
||||
/**
|
||||
* 左右切换关联信息。
|
||||
* Aarrow tabs area.
|
||||
*
|
||||
* @param string domID
|
||||
* @param number shift 1|-1
|
||||
* @param bool hideRightBtn
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function arrowTabs(domID, shift, hideRightBtn)
|
||||
{
|
||||
if($('#' + domID).html() == '') return;
|
||||
|
||||
var hasParent = $('#' + domID + ' .btn-left').length;
|
||||
var $leftBtn = hasParent ? $('#' + domID + ' .btn-left') : $('.btn-left');
|
||||
var $rightBtn = hasParent ? $('#' + domID + ' .btn-right') : $('.btn-right');
|
||||
|
||||
$leftBtn.show();
|
||||
$rightBtn.show();
|
||||
if(hideRightBtn) $rightBtn.hide();
|
||||
|
||||
var tabItemWidth = 0;
|
||||
if($('#' + domID + ' > .nav-tabs')[0]) tabItemWidth = $('#' + domID + ' > .nav-tabs')[0].clientWidth;
|
||||
var tabsWidth = $('#' + domID)[0].clientWidth;
|
||||
if($('#' + domID + ' .close-bugs').length) tabsWidth = tabsWidth * 0.7;
|
||||
|
||||
if(tabItemWidth <= tabsWidth)
|
||||
{
|
||||
$leftBtn.hide();
|
||||
$rightBtn.hide();
|
||||
$('#' + domID + ' > .nav-tabs')[0].style.transform = 'translateX(0px)';
|
||||
return;
|
||||
}
|
||||
|
||||
distance += tabsWidth * shift * 0.2;
|
||||
if(distance > 0) distance = 0;
|
||||
if(distance == 0)
|
||||
{
|
||||
$leftBtn.hide();
|
||||
}
|
||||
|
||||
if((tabItemWidth + distance) <= tabsWidth * 0.75)
|
||||
{
|
||||
$rightBtn.hide();
|
||||
return arrowTabs(domID, 1, true);
|
||||
}
|
||||
|
||||
if(domID == 'monacoTabs' && distance < -60) distance = distance + 60;
|
||||
|
||||
$('#' + domID + ' > .nav-tabs')[0].style.transform = 'translateX('+ distance +'px)';
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭关联信息tab。
|
||||
* Close commit relations.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function closeRelation()
|
||||
{
|
||||
$('#relationTabs ul li').remove();
|
||||
$('#relationTabs .tab-content .tab-pane').remove();
|
||||
$('.history').html('');
|
||||
$('#log').data('line', 0);
|
||||
$('#log').hide();
|
||||
|
||||
$('#codeContainer').css('height', codeHeight);
|
||||
$('#related').css('height', 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取tabs内容高度。
|
||||
* Get tab-content height.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function getIframeHeight()
|
||||
{
|
||||
if(iframeHeight) return iframeHeight;
|
||||
|
||||
var windowHeight = $(window).height();
|
||||
var headerHeight = parseInt($('#header').height());
|
||||
var mainNavbar = parseInt($('#mainNavbar').height());
|
||||
var featureBar = parseInt($('#featureBar').height());
|
||||
var tabsbar = parseInt($('.nav-tabs').height());
|
||||
var mainMenuHeight = parseInt($('#mainMenu').css('padding-top')) + parseInt($('#mainMenu').css('padding-bottom'));
|
||||
var appTabsHeight = parseInt($('#appTabs').height());
|
||||
var appsBarHeight = parseInt($('#appsBar').height());
|
||||
featureBar = featureBar ? featureBar : 0;
|
||||
appsBarHeight = appsBarHeight ? appsBarHeight : 0;
|
||||
appTabsHeight = appTabsHeight ? appTabsHeight : 0;
|
||||
mainMenuHeight = mainMenuHeight ? mainMenuHeight : 0;
|
||||
mainNavbar = mainNavbar ? mainNavbar : 0;
|
||||
iframeHeight = windowHeight - headerHeight - appsBarHeight - appTabsHeight - mainMenuHeight - mainNavbar - tabsbar - 20 - featureBar;
|
||||
|
||||
return iframeHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取左侧边栏高度。
|
||||
* Get sidebar height.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function getSidebarHeight()
|
||||
{
|
||||
if(sidebarHeight) return sidebarHeight;
|
||||
|
||||
var windowHeight = $(window).height();
|
||||
var headerHeight = parseInt($('#header').height());
|
||||
var mainNavbar = parseInt($('#mainNavbar').height());
|
||||
var featureBar = parseInt($('#featureBar').height());
|
||||
var repoMenu = parseInt($('#repoBranchDropMenu').height());
|
||||
var mainMenuHeight = parseInt($('#mainMenu').css('padding-top')) + parseInt($('#mainMenu').css('padding-bottom'));
|
||||
var appTabsHeight = parseInt($('#appTabs').height());
|
||||
var appsBarHeight = parseInt($('#appsBar').height());
|
||||
repoMenu = repoMenu ? repoMenu : 0;
|
||||
featureBar = featureBar ? featureBar : 0;
|
||||
appsBarHeight = appsBarHeight ? appsBarHeight : 0;
|
||||
appTabsHeight = appTabsHeight ? appTabsHeight : 0;
|
||||
mainMenuHeight = mainMenuHeight ? mainMenuHeight : 0;
|
||||
mainNavbar = mainNavbar ? mainNavbar : 0;
|
||||
sidebarHeight = windowHeight - headerHeight - appsBarHeight - appTabsHeight - mainMenuHeight - mainNavbar - repoMenu - featureBar;
|
||||
|
||||
return sidebarHeight;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查找选中元素所有的父元素及选中元素的id。
|
||||
* Find parent nodes and item id of selected tree item.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
function findItemInTreeItems(list, key, level) {
|
||||
for (const item of list) {
|
||||
if(level === 0)
|
||||
{
|
||||
parentTree = [item.key];
|
||||
}
|
||||
|
||||
if (item.key === key) return item;
|
||||
|
||||
if (item.children && item.children.length > 0)
|
||||
{
|
||||
const findedItem = findItemInTreeItems(item.children, key);
|
||||
if (findedItem)
|
||||
{
|
||||
parentTree.push(item.key);
|
||||
return findedItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 展开树状结构。
|
||||
* Expand tree node.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function expandTree()
|
||||
{
|
||||
const treeObj = $('#monacoTree').parent().data('zui.Tree');
|
||||
if(treeObj == undefined || treeObj.$ == undefined) return;
|
||||
|
||||
for (const key of parentTree) treeObj.$.expand(key);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
$(function()
|
||||
{
|
||||
onScmChange();
|
||||
});
|
||||
|
||||
function onProductChange(event)
|
||||
{
|
||||
var projects = $('[name="projects[]"]').val();
|
||||
var products = $('[name="product[]"]').val();
|
||||
|
||||
$.post($.createLink('repo', 'ajaxProjectsOfProducts'), {products, projects}, function(response)
|
||||
{
|
||||
var data = JSON.parse(response);
|
||||
var $projects = $('#projects').zui('picker');
|
||||
$projects.render({items: data});
|
||||
$projects.$.clear();
|
||||
});
|
||||
}
|
||||
|
||||
function onHostChange()
|
||||
{
|
||||
var host = $('[name=serviceHost]').val();
|
||||
var url = $.createLink('repo', 'ajaxGetProjects', "host=" + host);
|
||||
if(host == '') return false;
|
||||
|
||||
toggleLoading('#serviceProject', true);
|
||||
$.get(url, function(response)
|
||||
{
|
||||
var data = JSON.parse(response);
|
||||
var $project = $('#serviceProject').zui('picker');
|
||||
$project.render({items: data});
|
||||
$project.$.clear();
|
||||
toggleLoading('#serviceProject', false);
|
||||
});
|
||||
}
|
||||
|
||||
function onProjectChange()
|
||||
{
|
||||
$option = $('#serviceProject option').eq($('#serviceProject').prop('selectedIndex'));
|
||||
$('#name').val($option.data('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Changed SCM.
|
||||
*
|
||||
* @param string $scm
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function onScmChange()
|
||||
{
|
||||
var scm = $('[name=SCM]').val();
|
||||
if(!scm)
|
||||
{
|
||||
for(i in scmList)
|
||||
{
|
||||
scm = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(scm == 'Git') ? $('.tips-git').removeClass('hidden') : $('.tips-git').addClass('hidden');
|
||||
if(scm == 'Git' || scm == 'Gitea' || scm == 'Gogs')
|
||||
{
|
||||
$('.account-fields').hide();
|
||||
$('#path').attr('placeholder', pathGitTip);
|
||||
$('#client').attr('placeholder', clientGitTip);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.account-fields').show();
|
||||
$('#path').attr('placeholder', pathSvnTip);
|
||||
$('#client').attr('placeholder', clientSvnTip);
|
||||
}
|
||||
|
||||
if(scm == 'Git' || scm == 'Subversion')
|
||||
{
|
||||
$('.service').toggle(false);
|
||||
$('.hide-service').toggle(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.service').toggle(true);
|
||||
if(scm == 'Gitea' || scm == 'Gogs')
|
||||
{
|
||||
$('.hide-service').each(function()
|
||||
{
|
||||
if(!$(this).hasClass('hide-git')) $(this).toggle(true);
|
||||
});
|
||||
$('.hide-git').toggle(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.hide-service').toggle(false);
|
||||
}
|
||||
|
||||
var url = $.createLink('repo', 'ajaxGetHosts', "scm=" + scm);
|
||||
$.get(url, function(response)
|
||||
{
|
||||
var data = JSON.parse(response);
|
||||
var $hostPicker = $('#serviceHost').zui('picker');
|
||||
$hostPicker.render({items: data});
|
||||
$hostPicker.$.clear();
|
||||
onHostChange();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
var iframeHeight = 0;
|
||||
var sidebarHeight = 0;
|
||||
var tabTemp;
|
||||
var diffAppose = $.cookie.get('renderSideBySide') == 'true';
|
||||
|
||||
/* Close tab. */
|
||||
$('#monacoTabs').on('click', '.monaco-close', function()
|
||||
{
|
||||
var eleId = $(this).parent().attr('href');
|
||||
var tabsEle = $(this).parent().parent().parent();
|
||||
var isActive = $(this).parent().hasClass('active');
|
||||
|
||||
$(this).parent().parent().remove();
|
||||
$(eleId).remove();
|
||||
$('#' + eleId.substring(5)).parent().removeClass('selected');
|
||||
if(isActive) tabsEle.children().last().find('a').trigger('click');
|
||||
});
|
||||
|
||||
window.afterPageUpdate = function()
|
||||
{
|
||||
setTimeout(function()
|
||||
{
|
||||
var fileAsId = file.replace(/=/g, '-');
|
||||
/* Resize moaco height. */
|
||||
$('#monacoTree').css('height', getSidebarHeight() - 8 + 'px');
|
||||
/* Init tab template. */
|
||||
if(!tabTemp) tabTemp = $('#monacoTabs ul li').first().clone();
|
||||
|
||||
/* Load default tab content. */
|
||||
var height = getIframeHeight();
|
||||
$('#tab-' + fileAsId).html("<iframe class='repo-iframe' src='" + $.createLink('repo', 'ajaxGetDiffEditorContent', urlParams.replace('%s', fileAsId)) + "' width='100%' height='" + height + "' scrolling='no'></iframe>")
|
||||
|
||||
/* Select default tree item. */
|
||||
const currentElement = findItemInTreeItems(tree, fileAsId, 0);
|
||||
|
||||
console.log(1111, $('#' + currentElement.id))
|
||||
expandTree();
|
||||
if(currentElement != undefined) setTimeout(() =>
|
||||
{
|
||||
$('#' + currentElement.id).parent().addClass('selected');
|
||||
}, 100);
|
||||
|
||||
$('.btn-left').on('click', function() {arrowTabs('monacoTabs', 1);});
|
||||
$('.btn-right').on('click', function() {arrowTabs('monacoTabs', -2);});
|
||||
|
||||
$('#repoDownloadCode').on('click', function()
|
||||
{
|
||||
var url = $(this).data('link');
|
||||
var activeFilePath = $('#monacoTabs .nav-item .active').attr('href').substring(5).replace(/-/g, '=');
|
||||
window.open(url.replace('{path}', activeFilePath));
|
||||
return;
|
||||
})
|
||||
}, 300);
|
||||
};
|
||||
|
||||
/**
|
||||
* 点击左侧菜单打开详情tab。
|
||||
* Open new tab when click tree item.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.treeClick = function(info)
|
||||
{
|
||||
if (info.item.items && info.item.items.length > 0) return;
|
||||
$('#' + info.item.id).parent().addClass('selected');
|
||||
openTab(info.item.key, info.item.text);
|
||||
arrowTabs('monacoTabs', -2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change code encoding.
|
||||
*
|
||||
* @param string encoding
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function changeEncoding(encoding)
|
||||
{
|
||||
$('#encoding').val(encoding);
|
||||
$('#encoding').parents('form').submit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Html code decode.
|
||||
*
|
||||
* @param string str
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
function htmlspecialchars_decode(str){
|
||||
str = str.replace(/&/g, '&');
|
||||
str = str.replace(/</g, '<');
|
||||
str = str.replace(/>/g, '>');
|
||||
str = str.replace(/"/g, "''");
|
||||
str = str.replace(/'/g, "'");
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get diffs by file name.
|
||||
*
|
||||
* @param string fileName
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
window.getDiffs = function(fileName)
|
||||
{
|
||||
if(fileName.indexOf('./') === 0) fileName = fileName.substring(2);
|
||||
|
||||
var result = {
|
||||
'code': {'new': '', 'old': ''},
|
||||
'line': {'new': [], 'old': []}
|
||||
};
|
||||
$.each(diffs, function(i, diff)
|
||||
{
|
||||
if(diff.fileName == fileName)
|
||||
{
|
||||
if(!diff.contents || typeof diff.contents[0].lines != 'object') return result;
|
||||
|
||||
$.each(diff.contents, function(k, content)
|
||||
{
|
||||
var lines = content.lines;
|
||||
$.each(lines, function(l, code)
|
||||
{
|
||||
if(code.type == 'all' || code.type == 'new')
|
||||
{
|
||||
result.code.new += htmlspecialchars_decode(code.line.substring(1)) + "\n";
|
||||
result.line.new.push(parseInt(code.newlc));
|
||||
}
|
||||
|
||||
if(code.type == 'all' || code.type == 'old')
|
||||
{
|
||||
result.code.old += htmlspecialchars_decode(code.line.substring(1)) + "\n";
|
||||
result.line.old.push(parseInt(code.oldlc));
|
||||
}
|
||||
})
|
||||
})
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开新tab。
|
||||
* Open new tab.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function openTab(entry, name)
|
||||
{
|
||||
var eleId = 'tab-' + entry.replace(/=/g, '-');
|
||||
var element = document.getElementById(eleId);
|
||||
if (element)
|
||||
{
|
||||
$("a[href='" + '#' + eleId + "']").trigger('click');
|
||||
return;
|
||||
}
|
||||
|
||||
var newTab = tabTemp.clone();
|
||||
newTab.find('a').attr('href', '#' + eleId);
|
||||
newTab.find('span').text(name);
|
||||
$('#monacoTabs .nav-tabs').append(newTab);
|
||||
|
||||
var height = getIframeHeight();
|
||||
$('#monacoTabs .tab-content').append("<div id='" + eleId + "' class='tab-pane active in'><iframe class='repo-iframe' src='" + $.createLink('repo', 'ajaxGetDiffEditorContent', urlParams.replace('%s', entry)) + "' width='100%' height='" + height + "' scrolling='no'></iframe></div>")
|
||||
|
||||
setTimeout(() => {
|
||||
$("a[href='" + '#' + eleId + "']").trigger('click');
|
||||
updateEditorInline('#' + eleId);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function updateEditorInline(eleId)
|
||||
{
|
||||
$.cookie.set('renderSideBySide', diffAppose);
|
||||
if(typeof $(eleId + ' iframe')[0].contentWindow.updateEditorInline == 'function')
|
||||
{
|
||||
$(eleId + ' iframe')[0].contentWindow.updateEditorInline(diffAppose);
|
||||
}
|
||||
}
|
||||
|
||||
$('#monacoTabs .nav-item a').on('click', function()
|
||||
{
|
||||
var eleId = $(this).attr('href');
|
||||
$(eleId + ' iframe')[0].contentWindow.updateEditorInline(diffAppose);
|
||||
});
|
||||
|
||||
$(document).ready(function()
|
||||
{
|
||||
if(diffAppose)
|
||||
{
|
||||
$('.dropdown-menu #inline').show();
|
||||
$('.dropdown-menu #appose').hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.dropdown-menu #appose').show();
|
||||
$('.dropdown-menu #inline').hide();
|
||||
}
|
||||
|
||||
$('.btn-left').on('click', function() {arrowTabs('monacoTabs', 1);});
|
||||
$('.btn-right').on('click', function() {arrowTabs('monacoTabs', -2);});
|
||||
});
|
||||
|
||||
$('.inline-appose').on('click', function()
|
||||
{
|
||||
$('.inline-appose').hide();
|
||||
diffAppose = !diffAppose;
|
||||
if(diffAppose)
|
||||
{
|
||||
$('.dropdown-menu #inline').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.dropdown-menu #appose').show();
|
||||
}
|
||||
var tabID = $('#monacoTabs .nav-item .active').attr('href');
|
||||
updateEditorInline(tabID);
|
||||
return;
|
||||
});
|
||||
|
||||
$(".label-exchange").on('click', function()
|
||||
{
|
||||
var newDiffLink = diffLink.replace('{oldRevision}', newRevision);
|
||||
newDiffLink = newDiffLink.replace('{newRevision}', oldRevision);
|
||||
openUrl(newDiffLink);
|
||||
});
|
||||
|
||||
/**
|
||||
* 在当前页面用modal加载链接。
|
||||
* Load link object page.
|
||||
*
|
||||
* @param string $link
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.loadLinkPage = function(link)
|
||||
{
|
||||
$('#linkObject').attr('href', link);
|
||||
$('#linkObject').trigger('click');
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
$(function()
|
||||
{
|
||||
onScmChange(true);
|
||||
});
|
||||
|
||||
function onProductChange(event)
|
||||
{
|
||||
var projects = $('[name="projects[]"]').val();
|
||||
var products = $('[name="product[]"]').val();
|
||||
|
||||
$.post($.createLink('repo', 'ajaxProjectsOfProducts'), {products, projects}, function(response)
|
||||
{
|
||||
var data = JSON.parse(response);
|
||||
var $projects = $('#projects').zui('picker');
|
||||
$projects.render({items: data});
|
||||
$projects.$.clear();
|
||||
});
|
||||
}
|
||||
|
||||
function onHostChange()
|
||||
{
|
||||
var host = $('[name=serviceHost]').val();
|
||||
var url = $.createLink('repo', 'ajaxGetProjects', "host=" + host);
|
||||
if(host == '') return false;
|
||||
|
||||
toggleLoading('#serviceProject', true);
|
||||
$.get(url, function(response)
|
||||
{
|
||||
var data = JSON.parse(response);
|
||||
var $project = $('#serviceProject').zui('picker');
|
||||
$project.render({items: data});
|
||||
$project.$.clear();
|
||||
toggleLoading('#serviceProject', false);
|
||||
});
|
||||
}
|
||||
|
||||
function onProjectChange()
|
||||
{
|
||||
$option = $('#serviceProject option').eq($('#serviceProject').prop('selectedIndex'));
|
||||
$('#name').val($option.data('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Changed SCM.
|
||||
*
|
||||
* @param bool $isFirstRequest
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function onScmChange(isFirstRequest = false)
|
||||
{
|
||||
var scm = $('[name=SCM]').val();
|
||||
if(!scm)
|
||||
{
|
||||
for(i in scmList)
|
||||
{
|
||||
scm = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(scm == 'Git') ? $('.tips-git').removeClass('hidden') : $('.tips-git').addClass('hidden');
|
||||
if(scm == 'Git' || scm == 'Gitea' || scm == 'Gogs')
|
||||
{
|
||||
$('.account-fields').hide();
|
||||
$('#path').attr('placeholder', pathGitTip);
|
||||
$('#client').attr('placeholder', clientGitTip);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.account-fields').show();
|
||||
$('#path').attr('placeholder', pathSvnTip);
|
||||
$('#client').attr('placeholder', clientSvnTip);
|
||||
}
|
||||
|
||||
if(scm == 'Git' || scm == 'Subversion')
|
||||
{
|
||||
$('.service').toggle(false);
|
||||
$('.hide-service').toggle(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.service').toggle(true);
|
||||
if(scm == 'Gitea' || scm == 'Gogs')
|
||||
{
|
||||
$('.hide-service').each(function()
|
||||
{
|
||||
if(!$(this).hasClass('hide-git')) $(this).toggle(true);
|
||||
});
|
||||
$('.hide-git').toggle(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.hide-service').toggle(false);
|
||||
}
|
||||
|
||||
if(!isFirstRequset)
|
||||
{
|
||||
var url = $.createLink('repo', 'ajaxGetHosts', "scm=" + scm);
|
||||
$.get(url, function(response)
|
||||
{
|
||||
var data = JSON.parse(response);
|
||||
var $hostPicker = $('#serviceHost').zui('picker');
|
||||
$hostPicker.render({items: data});
|
||||
$hostPicker.$.clear();
|
||||
onHostChange();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
$(function()
|
||||
{
|
||||
checkItem();
|
||||
$('.form-batch-row-actions .form-batch-btn').each(function()
|
||||
{
|
||||
if($(this).data('type') == 'add') $(this).addClass('hidden');
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Check the project.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function checkItem()
|
||||
{
|
||||
if(!$("#repoList tbody tr").length) $("#submit").prop('disabled', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change server.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function selectServer(event)
|
||||
{
|
||||
var server = $(event.target).val();
|
||||
console.log(server);
|
||||
if(server) loadPage($.createLink('repo', 'import', 'server=' + server));
|
||||
}
|
||||
|
||||
function loadProductProjects(event)
|
||||
{
|
||||
const $target = $(event.target);
|
||||
const $currentRow = $target.closest('tr');
|
||||
const products = $target.val();
|
||||
const projects = $currentRow.find('.form-batch-input[data-name="projects"]');
|
||||
const projectIds = $(projects).val();
|
||||
|
||||
$.post($.createLink('repo', 'ajaxProjectsOfProducts'), {products : products, projects: projectIds, number : 1}, function(response)
|
||||
{
|
||||
$(projects).html(response);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
window.createSortLink = function(col)
|
||||
{
|
||||
var sort = col.name + '_asc';
|
||||
if(sort == orderBy) sort = col.name + '_desc';
|
||||
|
||||
return sortLink.replace('{orderBy}', sort);
|
||||
}
|
||||
|
||||
$(document).off('click','.dtable-footer .batch-btn').on('click', '.dtable-footer .batch-btn', function(e)
|
||||
{
|
||||
const dtable = zui.DTable.query(e.target);
|
||||
const checkedList = dtable.$.getChecks();
|
||||
if(!checkedList.length) return;
|
||||
|
||||
const tabType = $(this).data('type');
|
||||
const postData = [];
|
||||
postData[`${tabType}[]`] = checkedList;
|
||||
|
||||
$.ajaxSubmit({
|
||||
url: $(this).data('url'),
|
||||
data: postData
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
window.createSortLink = function(col)
|
||||
{
|
||||
var sort = col.name + '_asc';
|
||||
if(sort == orderBy) sort = col.name + '_desc';
|
||||
|
||||
return sortLink.replace('{orderBy}', sort);
|
||||
}
|
||||
|
||||
$(document).off('click','.dtable-footer .batch-btn').on('click', '.dtable-footer .batch-btn', function(e)
|
||||
{
|
||||
const dtable = zui.DTable.query(e.target);
|
||||
const checkedList = dtable.$.getChecks();
|
||||
if(!checkedList.length) return;
|
||||
|
||||
const tabType = $(this).data('type');
|
||||
const postData = [];
|
||||
postData[`${tabType}[]`] = checkedList;
|
||||
|
||||
$.ajaxSubmit({
|
||||
url: $(this).data('url'),
|
||||
data: postData
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
window.createSortLink = function(col)
|
||||
{
|
||||
var sort = col.name + '_asc';
|
||||
if(sort == orderBy) sort = col.name + '_desc';
|
||||
|
||||
return sortLink.replace('{orderBy}', sort);
|
||||
}
|
||||
|
||||
$(document).off('click','.dtable-footer .batch-btn').on('click', '.dtable-footer .batch-btn', function(e)
|
||||
{
|
||||
const dtable = zui.DTable.query(e.target);
|
||||
const checkedList = dtable.$.getChecks();
|
||||
if(!checkedList.length) return;
|
||||
|
||||
const tabType = $(this).data('type');
|
||||
const postData = [];
|
||||
postData[`${tabType}[]`] = checkedList;
|
||||
|
||||
$.ajaxSubmit({
|
||||
url: $(this).data('url'),
|
||||
data: postData
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,106 @@
|
||||
var revisionMap = {};
|
||||
var checkedIds = [];
|
||||
|
||||
/**
|
||||
* 当选中两行时禁用其他行。
|
||||
* Disable checkable attribution when checked rows equal 2.
|
||||
*
|
||||
* @param object changes
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.checkedChange = function(changes)
|
||||
{
|
||||
checkedIds = getCurrentCheckedIds();
|
||||
|
||||
if(checkedIds.length < 2)
|
||||
{
|
||||
$('.btn-diff').addClass('disabled')
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.btn-diff').removeClass('disabled')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当选中数量等于2,则禁用其他所有行。
|
||||
* When the selected row equals 2, disable all other rows.
|
||||
*
|
||||
* @param int rowID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
window.canRowCheckable = function(rowID)
|
||||
{
|
||||
const dtable = zui.DTable.query('#repo-logs-table');
|
||||
if(dtable == undefined) return;
|
||||
var data = dtable.$.props.data;
|
||||
|
||||
if(data.length == 0) return true;
|
||||
|
||||
initRevisionMap(data);
|
||||
|
||||
var currentCheckedIds = getCurrentCheckedIds();
|
||||
|
||||
if(currentCheckedIds.length < 2) return true;
|
||||
if(currentCheckedIds.indexOf(rowID) == -1) return 'disabled'
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测revisionMap是否跟当前页面数据一致,不一致重新生成。
|
||||
* Regenerate revisionMap when revisionMap is not in current list.
|
||||
*
|
||||
* @param array
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function initRevisionMap(data)
|
||||
{
|
||||
if(revisionMap[data[data.length - 1].id] !== undefined) return;
|
||||
|
||||
revisionMap = {};
|
||||
for (var i = 0; i < data.length; i++) revisionMap[data[i].id] = data[i].revision;
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转比较差异页面。
|
||||
* Redirect to diff page.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.diffClick = function()
|
||||
{
|
||||
var checkedIds = getCurrentCheckedIds();
|
||||
var newDiffLink = diffLink.replace('{oldRevision}', revisionMap[checkedIds[1]]);
|
||||
newDiffLink = newDiffLink.replace('{newRevision}', revisionMap[checkedIds[0]]);
|
||||
|
||||
openUrl(newDiffLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前页码选中的行。
|
||||
* Get checked rows in current page.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
function getCurrentCheckedIds()
|
||||
{
|
||||
const dtable = zui.DTable.query('#repo-logs-table');
|
||||
if(dtable.$ == undefined) return [];
|
||||
|
||||
var checkedIds = dtable.$.getChecks();
|
||||
var currentCheckedIds = [];
|
||||
|
||||
for (var i = 0; i < checkedIds.length; i++)
|
||||
{
|
||||
if(revisionMap[checkedIds[i]]) currentCheckedIds.push(checkedIds[i]);
|
||||
}
|
||||
|
||||
if(currentCheckedIds.length > 2) currentCheckedIds = currentCheckedIds.slice(0, 2);
|
||||
return currentCheckedIds;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
var iframeHeight = 0;
|
||||
var sidebarHeight = 0;
|
||||
var tabTemp;
|
||||
var parentTree = [];
|
||||
|
||||
/* Close tab. */
|
||||
$('#monacoTabs').on('click', '.monaco-close', function()
|
||||
{
|
||||
var eleId = $(this).parent().attr('href');
|
||||
var tabsEle = $(this).parent().parent().parent();
|
||||
var isActive = $(this).parent().hasClass('active');
|
||||
|
||||
$(this).parent().parent().remove();
|
||||
$(eleId).remove();
|
||||
$('#' + eleId.substring(5)).parent().removeClass('selected');
|
||||
if(isActive) tabsEle.children().last().find('a').trigger('click');
|
||||
|
||||
arrowTabs('monacoTabs', -1);
|
||||
});
|
||||
|
||||
window.afterPageUpdate = function()
|
||||
{
|
||||
setTimeout(function()
|
||||
{
|
||||
var fileAsId = file.replace(/=/g, '-');
|
||||
/* Resize moaco height. */
|
||||
$('#monacoTree').css('height', getSidebarHeight() - 8 + 'px');
|
||||
/* Init tab template. */
|
||||
if(!tabTemp) tabTemp = $('#monacoTabs ul li').first().clone();
|
||||
|
||||
/* Load default tab content. */
|
||||
var height = getIframeHeight();
|
||||
$('#tab-' + fileAsId).html("<iframe class='repo-iframe' src='" + $.createLink('repo', 'ajaxGetEditorContent', urlParams.replace('%s', fileAsId)) + "' width='100%' height='" + height + "' scrolling='no'></iframe>")
|
||||
|
||||
/* Select default tree item. */
|
||||
const currentElement = findItemInTreeItems(tree, fileAsId, 0);
|
||||
if(currentElement != undefined) $('#' + currentElement.id).parent().addClass('selected');
|
||||
|
||||
if(['Git', 'Gitlab', 'Gogs', 'Gitea'].indexOf(repo.SCM) == -1)
|
||||
{
|
||||
$('#sourceSwapper').hide();
|
||||
}
|
||||
expandTree();
|
||||
|
||||
$('.btn-left').on('click', function() {arrowTabs('monacoTabs', 1);});
|
||||
$('.btn-right').on('click', function() {arrowTabs('monacoTabs', -2);});
|
||||
|
||||
/* Reload current page when click dropmeu. */
|
||||
$('body').on('click', '.dropmenu-tree .dropmenu-item', function()
|
||||
{
|
||||
var branchOrTag = $(this).attr('title');
|
||||
var url = $(this).data('url');
|
||||
|
||||
if(url != 'javascript:;') return;
|
||||
|
||||
if(branchOrTag != $.cookie.get('repoBranch')) $.cookie.set('repoBranch', branchOrTag);
|
||||
|
||||
openUrl(currentLink);
|
||||
})
|
||||
|
||||
$('.repoDropDownMenu').on('click', function()
|
||||
{
|
||||
var url = $(this).data('link');
|
||||
var activeFilePath = $('#monacoTabs .nav-item .active').attr('href').substring(5).replace(/-/g, '=');
|
||||
if(url.indexOf('blame') >=0 && url.indexOf('download') == -1)
|
||||
{
|
||||
openUrl(url.replace('{path}', activeFilePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
window.open(url.replace('{path}', activeFilePath));
|
||||
}
|
||||
return;
|
||||
})
|
||||
}, 200);
|
||||
};
|
||||
|
||||
/**
|
||||
* 点击左侧菜单打开详情tab。
|
||||
* Open new tab when click tree item.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.treeClick = function(info)
|
||||
{
|
||||
if (info.item.items && info.item.items.length > 0) return;
|
||||
$('#' + info.item.id).parent().addClass('selected');
|
||||
openTab(info.item.key, info.item.text);
|
||||
arrowTabs('monacoTabs', -2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开新tab。
|
||||
* Open new tab.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function openTab(entry, name)
|
||||
{
|
||||
var eleId = 'tab-' + entry.replace(/=/g, '-');
|
||||
var element = document.getElementById(eleId);
|
||||
if (element)
|
||||
{
|
||||
$("a[href='" + '#' + eleId + "']").trigger('click');
|
||||
return;
|
||||
}
|
||||
|
||||
var newTab = tabTemp.clone();
|
||||
newTab.find('a').attr('href', '#' + eleId);
|
||||
newTab.find('span').text(name);
|
||||
$('#monacoTabs .nav-tabs').append(newTab);
|
||||
|
||||
var height = getIframeHeight();
|
||||
$('#monacoTabs .tab-content').append("<div id='" + eleId + "' class='tab-pane active in'><iframe class='repo-iframe' src='" + $.createLink('repo', 'ajaxGetEditorContent', urlParams.replace('%s', entry)) + "' width='100%' height='" + height + "' scrolling='no'></iframe></div>")
|
||||
|
||||
setTimeout(() => {
|
||||
$("a[href='" + '#' + eleId + "']").trigger('click');
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前页面用modal加载链接。
|
||||
* Load link object page.
|
||||
*
|
||||
* @param string $link
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
window.loadLinkPage = function(link)
|
||||
{
|
||||
$('#linkObject').attr('href', link);
|
||||
$('#linkObject').trigger('click');
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
function syncComments()
|
||||
{
|
||||
$.get(link, function(data)
|
||||
{
|
||||
if(data == 'finish') return openUrl(browseLink);
|
||||
|
||||
var count = parseInt(data);
|
||||
if(isNaN(count)) count = 0;
|
||||
$('#commits').html(parseInt($('#commits').html()) + count);
|
||||
|
||||
setTimeout(syncComments, 100);
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(syncComments, 500);
|
||||
@@ -28,7 +28,7 @@ $lang->repo->branch = 'Branch';
|
||||
$lang->repo->tag = 'Tag';
|
||||
$lang->repo->addWebHook = 'Add Webhook';
|
||||
$lang->repo->apiGetRepoByUrl = 'API: Get repo by URL';
|
||||
$lang->repo->blameTmpl = 'Code for line <strong>%line</strong>, <span class="tip-circular"></span> %name commited at %time, %version %comment';
|
||||
$lang->repo->blameTmpl = 'Code for line <strong>%line</strong>: %name commited at %time, %version %comment';
|
||||
$lang->repo->notRelated = 'There is currently no related ZenTao object';
|
||||
|
||||
$lang->repo->browseAction = 'Browse Repo';
|
||||
@@ -51,6 +51,7 @@ $lang->repo->import = 'Import';
|
||||
$lang->repo->importName = 'Name after import';
|
||||
$lang->repo->importServer = 'Please select a server';
|
||||
$lang->repo->gitlabList = 'Gitlab Repo';
|
||||
$lang->repo->batchCreate = 'Batch create repo';
|
||||
|
||||
$lang->repo->submit = 'Submit';
|
||||
$lang->repo->cancel = 'Cancel';
|
||||
@@ -101,7 +102,7 @@ $lang->repo->diff = 'Diff';
|
||||
$lang->repo->diffAB = 'Diff';
|
||||
$lang->repo->diffAll = 'Diff All';
|
||||
$lang->repo->viewDiff = 'View diff';
|
||||
$lang->repo->allLog = 'All Revisions';
|
||||
$lang->repo->allLog = 'All Commits';
|
||||
$lang->repo->location = 'Location';
|
||||
$lang->repo->file = 'File';
|
||||
$lang->repo->action = 'Action';
|
||||
@@ -120,6 +121,7 @@ $lang->repo->linkBug = 'Link Bug';
|
||||
$lang->repo->linkTask = 'Link Task';
|
||||
$lang->repo->unlink = 'Unlink';
|
||||
$lang->repo->viewBugs = 'View Bugs';
|
||||
$lang->repo->lastSubmitTime = 'Final submission time';
|
||||
|
||||
$lang->repo->title = 'Title';
|
||||
$lang->repo->status = 'Status';
|
||||
@@ -239,3 +241,5 @@ $lang->repo->typeList['performance'] = 'Performance';
|
||||
$lang->repo->typeList['security'] = 'Security';
|
||||
$lang->repo->typeList['redundancy'] = 'Redundancy';
|
||||
$lang->repo->typeList['logicError'] = 'Logic Error';
|
||||
|
||||
$lang->repo->featureBar['maintain']['all'] = 'All';
|
||||
|
||||
@@ -28,7 +28,7 @@ $lang->repo->branch = 'Branch';
|
||||
$lang->repo->tag = 'Tag';
|
||||
$lang->repo->addWebHook = 'Add Webhook';
|
||||
$lang->repo->apiGetRepoByUrl = 'API: Get repo by URL';
|
||||
$lang->repo->blameTmpl = 'Code for line <strong>%line</strong>, <span class="tip-circular"></span> %name commited at %time, %version %comment';
|
||||
$lang->repo->blameTmpl = 'Code for line <strong>%line</strong>: %name commited at %time, %version %comment';
|
||||
$lang->repo->notRelated = 'There is currently no related ZenTao object';
|
||||
|
||||
$lang->repo->browseAction = 'Browse Repo';
|
||||
@@ -51,6 +51,7 @@ $lang->repo->import = 'Import';
|
||||
$lang->repo->importName = 'Name after import';
|
||||
$lang->repo->importServer = 'Please select a server';
|
||||
$lang->repo->gitlabList = 'Gitlab Repo';
|
||||
$lang->repo->batchCreate = 'Batch create repo';
|
||||
|
||||
$lang->repo->submit = 'Submit';
|
||||
$lang->repo->cancel = 'Cancel';
|
||||
@@ -101,7 +102,7 @@ $lang->repo->diff = 'Diff';
|
||||
$lang->repo->diffAB = 'Diff';
|
||||
$lang->repo->diffAll = 'Diff All';
|
||||
$lang->repo->viewDiff = 'View diff';
|
||||
$lang->repo->allLog = 'All Revisions';
|
||||
$lang->repo->allLog = 'All Commits';
|
||||
$lang->repo->location = 'Location';
|
||||
$lang->repo->file = 'File';
|
||||
$lang->repo->action = 'Action';
|
||||
@@ -120,6 +121,7 @@ $lang->repo->linkBug = 'Link Bug';
|
||||
$lang->repo->linkTask = 'Link Task';
|
||||
$lang->repo->unlink = 'Unlink';
|
||||
$lang->repo->viewBugs = 'View Bugs';
|
||||
$lang->repo->lastSubmitTime = 'Final submission time';
|
||||
|
||||
$lang->repo->title = 'Title';
|
||||
$lang->repo->status = 'Status';
|
||||
@@ -239,3 +241,5 @@ $lang->repo->typeList['performance'] = 'Performance';
|
||||
$lang->repo->typeList['security'] = 'Security';
|
||||
$lang->repo->typeList['redundancy'] = 'Redundancy';
|
||||
$lang->repo->typeList['logicError'] = 'Logic Error';
|
||||
|
||||
$lang->repo->featureBar['maintain']['all'] = 'All';
|
||||
|
||||
@@ -28,7 +28,7 @@ $lang->repo->branch = 'Branch';
|
||||
$lang->repo->tag = 'Tag';
|
||||
$lang->repo->addWebHook = 'Add Webhook';
|
||||
$lang->repo->apiGetRepoByUrl = 'API: Get repo by URL';
|
||||
$lang->repo->blameTmpl = 'Code for line <strong>%line</strong>, <span class="tip-circular"></span> %name commited at %time, %version %comment';
|
||||
$lang->repo->blameTmpl = 'Code for line <strong>%line</strong>: %name commited at %time, %version %comment';
|
||||
$lang->repo->notRelated = 'There is currently no related ZenTao object';
|
||||
|
||||
$lang->repo->browseAction = 'Browse Repo';
|
||||
@@ -51,6 +51,7 @@ $lang->repo->import = 'Import';
|
||||
$lang->repo->importName = 'Name after import';
|
||||
$lang->repo->importServer = 'Please select a server';
|
||||
$lang->repo->gitlabList = 'Gitlab Repo';
|
||||
$lang->repo->batchCreate = 'Batch create repo';
|
||||
|
||||
$lang->repo->submit = 'Soumettre';
|
||||
$lang->repo->cancel = 'Annuler';
|
||||
@@ -101,7 +102,7 @@ $lang->repo->diff = 'Diff';
|
||||
$lang->repo->diffAB = 'Diff';
|
||||
$lang->repo->diffAll = 'Toutes Diff';
|
||||
$lang->repo->viewDiff = 'Voir diff';
|
||||
$lang->repo->allLog = 'Toutes Révisions';
|
||||
$lang->repo->allLog = 'All Commits';
|
||||
$lang->repo->location = 'Localisation';
|
||||
$lang->repo->file = 'Fichier';
|
||||
$lang->repo->action = 'Action';
|
||||
@@ -120,6 +121,7 @@ $lang->repo->linkBug = 'Link Bug';
|
||||
$lang->repo->linkTask = 'Link Task';
|
||||
$lang->repo->unlink = 'Unlink';
|
||||
$lang->repo->viewBugs = 'View Bugs';
|
||||
$lang->repo->lastSubmitTime = 'Final submission time';
|
||||
|
||||
$lang->repo->title = 'Titre';
|
||||
$lang->repo->status = 'Statut';
|
||||
@@ -239,3 +241,5 @@ $lang->repo->typeList['performance'] = 'Performance';
|
||||
$lang->repo->typeList['security'] = 'Securité';
|
||||
$lang->repo->typeList['redundancy'] = 'Redondance';
|
||||
$lang->repo->typeList['logicError'] = 'Erreur Logique';
|
||||
|
||||
$lang->repo->featureBar['maintain']['all'] = 'All';
|
||||
|
||||
@@ -168,8 +168,7 @@ $lang->repo->placeholder->gitlabHost = 'Input url of gitlab';
|
||||
|
||||
$lang->repo->notice = new stdclass();
|
||||
$lang->repo->notice->syncing = 'Đang đồng bộ. Vui lòng đợi ...';
|
||||
$lang->repo->notice->syncComplete = 'Đồng bộ hóa hoàn tất, nhảy ...';
|
||||
$lang->repo->notice->syncFailed = 'Đồng bộ hóa không thành công.';
|
||||
$lang->repo->notice->syncComplete = 'Synchronized. Now redirecting ...';
|
||||
$lang->repo->notice->syncedCount = 'The number of records synchronized is ';
|
||||
$lang->repo->notice->delete = 'Bạn có muốn xóa this repo?';
|
||||
$lang->repo->notice->successDelete = 'Repository is removed.';
|
||||
@@ -231,3 +230,5 @@ $lang->repo->typeList['performance'] = 'Hiệu suất';
|
||||
$lang->repo->typeList['security'] = 'Bảo mật';
|
||||
$lang->repo->typeList['redundancy'] = 'Redundancy';
|
||||
$lang->repo->typeList['logicError'] = 'Logic Error';
|
||||
|
||||
$lang->repo->featureBar['maintain']['all'] = 'All';
|
||||
|
||||
@@ -28,7 +28,7 @@ $lang->repo->branch = '分支';
|
||||
$lang->repo->tag = '标签';
|
||||
$lang->repo->addWebHook = '添加Webhook';
|
||||
$lang->repo->apiGetRepoByUrl = '接口:通过URL获取代码库';
|
||||
$lang->repo->blameTmpl = '第 <strong>%line</strong> 行代码相关信息,<span class="tip-circular"></span> %name 于 %time 提交 %version %comment';
|
||||
$lang->repo->blameTmpl = '第 <strong>%line</strong> 行代码相关信息: %name 于 %time 提交 %version %comment';
|
||||
$lang->repo->notRelated = '暂时没有关联禅道对象';
|
||||
|
||||
$lang->repo->browseAction = '浏览代码库';
|
||||
@@ -51,6 +51,7 @@ $lang->repo->import = '导入';
|
||||
$lang->repo->importName = '导入后的名称';
|
||||
$lang->repo->importServer = '请选择服务器';
|
||||
$lang->repo->gitlabList = 'Gitlab代码库';
|
||||
$lang->repo->batchCreate = '批量添加代码库';
|
||||
|
||||
$lang->repo->submit = '提交';
|
||||
$lang->repo->cancel = '取消';
|
||||
@@ -101,7 +102,7 @@ $lang->repo->diff = '比较差异';
|
||||
$lang->repo->diffAB = '比较';
|
||||
$lang->repo->diffAll = '全部比较';
|
||||
$lang->repo->viewDiff = '查看差异';
|
||||
$lang->repo->allLog = '所有版本';
|
||||
$lang->repo->allLog = '所有提交';
|
||||
$lang->repo->location = '位置';
|
||||
$lang->repo->file = '文件';
|
||||
$lang->repo->action = '操作';
|
||||
@@ -120,6 +121,7 @@ $lang->repo->linkBug = '关联Bug';
|
||||
$lang->repo->linkTask = '关联任务';
|
||||
$lang->repo->unlink = '取消关联';
|
||||
$lang->repo->viewBugs = '查看Bug';
|
||||
$lang->repo->lastSubmitTime = '最后提交时间';
|
||||
|
||||
$lang->repo->title = '标题';
|
||||
$lang->repo->status = '状态';
|
||||
@@ -239,3 +241,5 @@ $lang->repo->typeList['performance'] = '性能';
|
||||
$lang->repo->typeList['security'] = '安全';
|
||||
$lang->repo->typeList['redundancy'] = '冗余';
|
||||
$lang->repo->typeList['logicError'] = '逻辑错误';
|
||||
|
||||
$lang->repo->featureBar['maintain']['all'] = '全部';
|
||||
|
||||
@@ -214,3 +214,5 @@ $lang->repo->typeList['performance'] = '性能';
|
||||
$lang->repo->typeList['security'] = '安全';
|
||||
$lang->repo->typeList['redundancy'] = '冗餘';
|
||||
$lang->repo->typeList['logicError'] = '邏輯錯誤';
|
||||
|
||||
$lang->repo->featureBar['maintain']['all'] = '全部';
|
||||
|
||||
+207
-163
@@ -44,7 +44,7 @@ class repoModel extends model
|
||||
/* Check the privilege. */
|
||||
if($repoID)
|
||||
{
|
||||
$repo = $this->getRepoByID($repoID);
|
||||
$repo = $this->getByID($repoID);
|
||||
if(empty($repo))
|
||||
{
|
||||
echo(js::alert($this->lang->repo->error->noFound));
|
||||
@@ -58,10 +58,10 @@ class repoModel extends model
|
||||
}
|
||||
|
||||
if(!in_array(strtolower($repo->SCM), $this->config->repo->gitServiceList)) unset($this->lang->devops->menu->mr);
|
||||
if(count($repos) > 1) $this->lang->switcherMenu = $this->getSwitcher($repoID);
|
||||
// if(count($repos) > 1) $this->lang->switcherMenu = $this->getSwitcher($repoID);
|
||||
}
|
||||
|
||||
common::setMenuVars('devops', $repoID);
|
||||
if(!in_array($this->app->methodName, array('maintain', 'create', 'edit','import'))) common::setMenuVars('devops', $repoID);
|
||||
if(!session_id()) session_start();
|
||||
$this->session->set('repoID', $repoID);
|
||||
session_write_close();
|
||||
@@ -81,7 +81,7 @@ class repoModel extends model
|
||||
if(!in_array($currentModule, $this->config->repo->switcherModuleList)) return '';
|
||||
if($currentModule == 'repo' and !in_array($currentMethod, $this->config->repo->switcherMethodList)) return '';
|
||||
|
||||
$currentRepo = $this->getRepoByID($repoID);
|
||||
$currentRepo = $this->getByID($repoID);
|
||||
$currentRepoName = $currentRepo->name;
|
||||
|
||||
if($this->app->viewType == 'mhtml' and $repoID)
|
||||
@@ -111,10 +111,38 @@ class repoModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getList($projectID = 0, $SCM = '', $orderBy = 'id_desc', $pager = null, $getCodePath = false)
|
||||
public function getList($projectID = 0, $SCM = '', $orderBy = 'id_desc', $pager = null, $getCodePath = false, $lastSubmitTime = false, $type = '', $param = 0)
|
||||
{
|
||||
$repoQuery = '';
|
||||
if($type == 'bySearch')
|
||||
{
|
||||
$queryID = $param;
|
||||
$queryName = 'repoQuery';
|
||||
|
||||
if($queryID && $queryID != 'myQueryID')
|
||||
{
|
||||
$query = $this->loadModel('search')->getQuery($queryID);
|
||||
if($query)
|
||||
{
|
||||
$this->session->set($queryName, $query->sql);
|
||||
$this->session->set($queryName . 'Form', $query->form);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->session->set($queryName, ' 1 = 1');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($this->session->$queryName == false) $this->session->set($queryName, ' 1 = 1');
|
||||
}
|
||||
|
||||
$repoQuery = $this->session->$queryName;
|
||||
}
|
||||
|
||||
$repos = $this->dao->select('*')->from(TABLE_REPO)
|
||||
->where('deleted')->eq('0')
|
||||
->beginIF(!empty($repoQuery))->andWhere($repoQuery)->fi()
|
||||
->beginIF($SCM)->andWhere('SCM')->eq($SCM)->fi()
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
@@ -154,6 +182,12 @@ class repoModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
if($lastSubmitTime)
|
||||
{
|
||||
$lastRevision = $this->repoTao->getLastRevision($repo->id);
|
||||
$repo->lastSubmitTime = isset($lastRevision->time) ? $lastRevision->time : '';
|
||||
}
|
||||
|
||||
if(in_array(strtolower($repo->SCM), $this->config->repo->gitServiceList)) $repo = $this->processGitService($repo, $getCodePath);
|
||||
}
|
||||
|
||||
@@ -189,52 +223,24 @@ class repoModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建版本库。
|
||||
* Create a repo.
|
||||
*
|
||||
* @param object $repo
|
||||
* @param bool $isPipelineServer
|
||||
* @access public
|
||||
* @return bool
|
||||
* @return int|false
|
||||
*/
|
||||
public function create()
|
||||
public function create(object $repo, bool $isPipelineServer): int|false
|
||||
{
|
||||
if(!$this->checkClient()) return false;
|
||||
if(!$this->checkConnection()) return false;
|
||||
|
||||
$isPipelineServer = in_array(strtolower($this->post->SCM), $this->config->repo->gitServiceList) ? true : false;
|
||||
|
||||
$data = fixer::input('post')
|
||||
->setIf($isPipelineServer, 'password', $this->post->serviceToken)
|
||||
->setIf($this->post->SCM == 'Gitlab', 'path', '')
|
||||
->setIf($this->post->SCM == 'Gitlab', 'client', '')
|
||||
->setIf($this->post->SCM == 'Gitlab', 'extra', $this->post->serviceProject)
|
||||
->setIf($isPipelineServer, 'prefix', '')
|
||||
->setIf($this->post->SCM == 'Git', 'account', '')
|
||||
->setIf($this->post->SCM == 'Git', 'password', '')
|
||||
->skipSpecial('path,client,account,password')
|
||||
->setDefault('product', '')
|
||||
->join('product', ',')
|
||||
->setDefault('projects', '')->join('projects', ',')
|
||||
->get();
|
||||
|
||||
$data->acl = empty($data->acl) ? '' : json_encode($data->acl);
|
||||
if($data->SCM == 'Subversion')
|
||||
{
|
||||
$scm = $this->app->loadClass('scm');
|
||||
$scm->setEngine($data);
|
||||
$info = $scm->info('');
|
||||
$infoRoot = urldecode($info->root);
|
||||
$data->prefix = empty($infoRoot) ? '' : trim(str_ireplace($infoRoot, '', str_replace('\\', '/', $data->path)), '/');
|
||||
if($data->prefix) $data->prefix = '/' . $data->prefix;
|
||||
}
|
||||
|
||||
if($data->encrypt == 'base64') $data->password = base64_encode($data->password);
|
||||
$this->dao->insert(TABLE_REPO)->data($data, $skip = 'serviceToken')
|
||||
$this->dao->insert(TABLE_REPO)->data($repo, 'serviceToken')
|
||||
->batchCheck($this->config->repo->create->requiredFields, 'notempty')
|
||||
->batchCheckIF($data->SCM != 'Gitlab', 'path,client', 'notempty')
|
||||
->batchCheckIF($repo->SCM != 'Gitlab', 'path,client', 'notempty')
|
||||
->batchCheckIF($isPipelineServer, 'serviceHost,serviceProject', 'notempty')
|
||||
->batchCheckIF($data->SCM == 'Subversion', $this->config->repo->svn->requiredFields, 'notempty')
|
||||
->check('name', 'unique', "`SCM` = '{$data->SCM}'")
|
||||
->checkIF($isPipelineServer, 'serviceProject', 'unique', "`SCM` = '{$data->SCM}' and `serviceHost` = '{$data->serviceHost}'")
|
||||
->checkIF(!$isPipelineServer, 'path', 'unique', "`SCM` = '{$data->SCM}' and `serviceHost` = '{$data->serviceHost}'")
|
||||
->batchCheckIF($repo->SCM == 'Subversion', $this->config->repo->svn->requiredFields, 'notempty')
|
||||
->check('name', 'unique', "`SCM` = '{$repo->SCM}'")
|
||||
->checkIF($isPipelineServer, 'serviceProject', 'unique', "`SCM` = '{$repo->SCM}' and `serviceHost` = '{$repo->serviceHost}'")
|
||||
->checkIF(!$isPipelineServer, 'path', 'unique', "`SCM` = '{$repo->SCM}' and `serviceHost` = '{$repo->serviceHost}'")
|
||||
->autoCheck()
|
||||
->exec();
|
||||
|
||||
@@ -242,46 +248,23 @@ class repoModel extends model
|
||||
|
||||
$this->rmClientVersionFile();
|
||||
|
||||
$repoID = $this->dao->lastInsertID();
|
||||
|
||||
if($this->post->SCM == 'Gitlab')
|
||||
{
|
||||
/* Add webhook. */
|
||||
$repo = $this->getRepoByID($repoID);
|
||||
$this->loadModel('gitlab')->addPushWebhook($repo);
|
||||
}
|
||||
|
||||
return $repoID;
|
||||
return $this->dao->lastInsertID();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量创建版本库。
|
||||
* Batch create repos.
|
||||
*
|
||||
* @param array $repos
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function batchCreate()
|
||||
public function batchCreate(array $repos, int $serviceHost): bool
|
||||
{
|
||||
$repos = fixer::input('post')->get();
|
||||
|
||||
$dataAry = array();
|
||||
foreach($repos as $key => $val)
|
||||
{
|
||||
if(strpos($key, 'serviceProject') === 0)
|
||||
{
|
||||
$i = substr($key, 14);
|
||||
if(empty($repos->{'product' . $i})) dao::$errors['product' . $i][] = sprintf($this->lang->error->notempty, $this->lang->repo->product);
|
||||
if(empty($repos->{'name' . $i})) dao::$errors['name' . $i][] = sprintf($this->lang->error->notempty, $this->lang->repo->name);
|
||||
|
||||
if(!empty($repos->{'product' . $i}) and !empty($repos->{'name' . $i})) $dataAry[] = array('serviceProject' => $repos->{'serviceProject' . $i}, 'product' => implode(',', $repos->{'product' . $i}), 'name' => $repos->{'name' . $i}, 'projects' => empty($repos->projects[$i]) ? '' : implode(',', $repos->projects[$i]));
|
||||
}
|
||||
}
|
||||
if(dao::isError()) return false;
|
||||
|
||||
foreach($dataAry as $data)
|
||||
foreach($repos as $data)
|
||||
{
|
||||
$repo = new stdclass();
|
||||
$repo->serviceHost = $repos->serviceHost;
|
||||
$repo->serviceHost = $serviceHost;
|
||||
$repo->serviceProject = $data['serviceProject'];
|
||||
$repo->product = $data['product'];
|
||||
$repo->name = $data['name'];
|
||||
@@ -305,11 +288,11 @@ class repoModel extends model
|
||||
if($repo->SCM == 'Gitlab')
|
||||
{
|
||||
/* Add webhook. */
|
||||
$repo = $this->getRepoByID($repoID);
|
||||
$repo = $this->getByID($repoID);
|
||||
$this->loadModel('gitlab')->addPushWebhook($repo);
|
||||
}
|
||||
|
||||
$actionID = $this->loadModel('action')->create('repo', $repoID, 'created');
|
||||
$this->loadModel('action')->create('repo', $repoID, 'created');
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -324,7 +307,7 @@ class repoModel extends model
|
||||
*/
|
||||
public function update($id)
|
||||
{
|
||||
$repo = $this->getRepoByID($id);
|
||||
$repo = $this->getByID($id);
|
||||
if($repo->client != $this->post->client and !$this->checkClient()) return false;
|
||||
if(!$this->checkConnection()) return false;
|
||||
|
||||
@@ -363,7 +346,7 @@ class repoModel extends model
|
||||
}
|
||||
|
||||
if($data->encrypt == 'base64') $data->password = base64_encode($data->password);
|
||||
$this->dao->update(TABLE_REPO)->data($data, $skip = 'serviceToken')
|
||||
$this->dao->update(TABLE_REPO)->data($data, 'serviceToken')
|
||||
->batchCheck($this->config->repo->edit->requiredFields, 'notempty')
|
||||
->batchCheckIF($data->SCM != 'Gitlab', 'path,client', 'notempty')
|
||||
->batchCheckIF($isPipelineServer, 'serviceHost,serviceProject', 'notempty')
|
||||
@@ -376,7 +359,7 @@ class repoModel extends model
|
||||
|
||||
$this->rmClientVersionFile();
|
||||
|
||||
if($data->SCM == 'Gitlab') $data->path = $this->getRepoByID($id)->path;
|
||||
if($data->SCM == 'Gitlab') $data->path = $this->getByID($id)->path;
|
||||
|
||||
if($repo->path != $data->path)
|
||||
{
|
||||
@@ -524,47 +507,70 @@ class repoModel extends model
|
||||
/**
|
||||
* Get repos group by repo type.
|
||||
*
|
||||
* @param string type
|
||||
* @param string $type
|
||||
* @param int $projectID
|
||||
* @param string $repoType
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getRepoGroup($type, $projectID = 0)
|
||||
public function getRepoGroup(string $type, int $projectID = 0, string $repoType = ''): array
|
||||
{
|
||||
$repoPairs = $this->getRepoPairs($type, $projectID);
|
||||
$repos = $this->dao->select('*')->from(TABLE_REPO)
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF($repoType == 'git')->andWhere('SCM')->in($this->config->repo->gitServiceTypeList)->fi()
|
||||
->fetchAll();
|
||||
|
||||
$repos = array();
|
||||
foreach($this->lang->repo->scmList as $scmType => $scm) $repos[$scmType] = array();
|
||||
|
||||
foreach($repoPairs as $id => $repo)
|
||||
$productIds = $productItems = array();
|
||||
foreach($repos as $repo)
|
||||
{
|
||||
if(strpos($repo, '[gitlab]') !== false)
|
||||
$productIds = array_merge($productIds, explode(',', $repo->product));
|
||||
}
|
||||
$products = $this->loadModel('product')->getByIdList(array_filter(array_unique($productIds)));
|
||||
foreach($products as $productID => $product)
|
||||
{
|
||||
$productItem = array();
|
||||
$productItem['id'] = $productID;
|
||||
$productItem['type'] = 'product';
|
||||
$productItem['text'] = $product->name;
|
||||
$productItem['items'] = array();
|
||||
|
||||
$productItems[$productID] = $productItem;
|
||||
}
|
||||
|
||||
/* Get project products. */
|
||||
$projectProductIds = ($type == 'project' or $type == 'execution') ? $this->loadModel('product')->getProductIDByProject((int)$projectID, false) : array();
|
||||
|
||||
/* Get repo data for dropmenu. */
|
||||
$repoPairs = array();
|
||||
foreach($repos as $repo)
|
||||
{
|
||||
$repo->acl = json_decode($repo->acl);
|
||||
$scm = $repo->SCM == 'Subversion' ? 'svn' : strtolower($repo->SCM);
|
||||
if($this->checkPriv($repo))
|
||||
{
|
||||
$repo = str_replace('[gitlab]', '', $repo);
|
||||
$repos['Gitlab'][$id] = $repo;
|
||||
}
|
||||
elseif(strpos($repo, '[gogs]') !== false)
|
||||
{
|
||||
$repo = str_replace('[gogs]', '', $repo);
|
||||
$repos['Gogs'][$id] = $repo;
|
||||
}
|
||||
elseif(strpos($repo, '[gitea]') !== false)
|
||||
{
|
||||
$repo = str_replace('[gitea]', '', $repo);
|
||||
$repos['Gitea'][$id] = $repo;
|
||||
}
|
||||
elseif(strpos($repo, '[svn]') !== false)
|
||||
{
|
||||
$repo = str_replace('[svn]', '', $repo);
|
||||
$repos['SVN'][$id] = $repo;
|
||||
}
|
||||
elseif(strpos($repo, '[git]') !== false)
|
||||
{
|
||||
$repo = str_replace('[git]', '', $repo);
|
||||
$repos['Git'][$id] = $repo;
|
||||
$repoItem = array();
|
||||
$repoItem['id'] = $repo->id;
|
||||
$repoItem['text'] = $repo->name;
|
||||
$repoItem['keys'] = zget(common::convert2Pinyin(array($repo->name)), $repo->name, '');
|
||||
|
||||
$repoProducts = explode(',', $repo->product);
|
||||
foreach($repoProducts as $productID)
|
||||
{
|
||||
if(($type == 'project' or $type == 'execution') and $projectID)
|
||||
{
|
||||
if(!in_array($productID, $projectProductIds)) continue;
|
||||
}
|
||||
|
||||
if(strpos(",$repo->product,", ",$productID,") !== false)
|
||||
{
|
||||
if(!isset($repoPairs[$productID])) $repoPairs[$productID] = $productItems[$productID];
|
||||
$repoPairs[$productID]['items'][] = $repoItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $repos;
|
||||
|
||||
return $repoPairs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -574,8 +580,9 @@ class repoModel extends model
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function getRepoByID($repoID)
|
||||
public function getByID($repoID)
|
||||
{
|
||||
if(empty($repoID)) return new stdclass();
|
||||
$repo = $this->dao->select('*')->from(TABLE_REPO)->where('id')->eq($repoID)->fetch();
|
||||
if(!$repo) return false;
|
||||
|
||||
@@ -637,7 +644,7 @@ class repoModel extends model
|
||||
|
||||
$conditions = array();
|
||||
foreach($matches as $matched) $conditions[] = "(`client`='$matched->gitlab' and `path`='$matched->project')";
|
||||
$conditions = '(' . join(' OR ', $conditions). ')';
|
||||
$conditions = '(' . implode(' OR ', $conditions). ')';
|
||||
|
||||
$matchedRepos = $this->dao->select('*')->from(TABLE_REPO)->where('SCM')->eq('Gitlab')
|
||||
->andWhere($conditions)
|
||||
@@ -716,7 +723,7 @@ class repoModel extends model
|
||||
|
||||
$conditions = array();
|
||||
foreach($matches as $matched) $conditions[] = "(`client`='$matched->gitlab' and `path`='$matched->project')";
|
||||
$conditions = '(' . join(' OR ', $conditions). ')';
|
||||
$conditions = '(' . implode(' OR ', $conditions). ')';
|
||||
|
||||
$matchedRepos = $this->dao->select('*')->from(TABLE_REPO)->where('SCM')->eq('Gitlab')
|
||||
->andWhere($conditions)
|
||||
@@ -742,7 +749,7 @@ class repoModel extends model
|
||||
public function getByIdList($idList)
|
||||
{
|
||||
$repos = $this->dao->select('*')->from(TABLE_REPO)->where('deleted')->eq(0)->andWhere('id')->in($idList)->fetchAll();
|
||||
foreach($repos as $i => $repo)
|
||||
foreach($repos as $repo)
|
||||
{
|
||||
if($repo->encrypt == 'base64') $repo->password = base64_decode($repo->password);
|
||||
$repo->acl = json_decode($repo->acl);
|
||||
@@ -803,6 +810,7 @@ class repoModel extends model
|
||||
*/
|
||||
public function getCommits($repo, $entry, $revision = 'HEAD', $type = 'dir', $pager = null, $begin = 0, $end = 0)
|
||||
{
|
||||
if(!isset($repo->id)) return array();
|
||||
if($repo->SCM == 'Gitlab') return $this->loadModel('gitlab')->getCommits($repo, $entry, $revision, $type, $pager, $begin, $end);
|
||||
|
||||
$entry = ltrim($entry, '/');
|
||||
@@ -859,6 +867,7 @@ class repoModel extends model
|
||||
$repoComment->originalComment = $repoComment->comment;
|
||||
$repoComment->comment = $this->replaceCommentLink($repoComment->comment);
|
||||
}
|
||||
|
||||
return $comments;
|
||||
}
|
||||
|
||||
@@ -886,7 +895,7 @@ class repoModel extends model
|
||||
->fetch();
|
||||
if(empty($lastComment)) return null;
|
||||
|
||||
$repo = $this->getRepoByID($repoID);
|
||||
$repo = $this->getByID($repoID);
|
||||
if($repo->SCM == 'Git' and $lastComment->commit != $count)
|
||||
{
|
||||
$this->fixCommit($repo->id);
|
||||
@@ -984,7 +993,7 @@ class repoModel extends model
|
||||
*/
|
||||
public function getProductsByRepo($repoID)
|
||||
{
|
||||
$repo = $this->getRepoByID($repoID);
|
||||
$repo = $this->getByID($repoID);
|
||||
if(empty($repo)) return array();
|
||||
|
||||
return $this->dao->select('id,name')->from(TABLE_PRODUCT)
|
||||
@@ -1347,7 +1356,7 @@ class repoModel extends model
|
||||
*/
|
||||
public function setRepoBranch($branch)
|
||||
{
|
||||
setcookie("repoBranch", $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure);
|
||||
helper::setcookie("repoBranch", $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure);
|
||||
$_COOKIE['repoBranch'] = $branch;
|
||||
}
|
||||
|
||||
@@ -1428,7 +1437,6 @@ class repoModel extends model
|
||||
|
||||
$blk = substr($content, 0, 512);
|
||||
return (
|
||||
false ||
|
||||
substr_count($blk, "^\r\n")/512 > 0.3 ||
|
||||
substr_count($blk, "^ -~")/512 > 0.3 ||
|
||||
substr_count($blk, "\x00") > 0
|
||||
@@ -1521,7 +1529,7 @@ class repoModel extends model
|
||||
exec($versionCommand, $versionOutput, $versionResult);
|
||||
if($versionResult)
|
||||
{
|
||||
$message = sprintf($this->lang->repo->error->output, $versionCommand, $versionResult, join("<br />", $versionOutput));
|
||||
$message = sprintf($this->lang->repo->error->output, $versionCommand, $versionResult, implode("<br />", $versionOutput));
|
||||
dao::$errors['client'] = $this->lang->repo->error->cmd . "<br />" . nl2br($message);
|
||||
return false;
|
||||
}
|
||||
@@ -1539,7 +1547,7 @@ class repoModel extends model
|
||||
$command = "$client info --username $account --password $password --non-interactive --trust-server-cert-failures=cn-mismatch --trust-server-cert --no-auth-cache $path 2>&1";
|
||||
if(version_compare($svnVersion, '1.9', '<')) $command = "$client info --username $account --password $password --non-interactive --trust-server-cert --no-auth-cache $path 2>&1";
|
||||
}
|
||||
else if(stripos($path, 'file://') === 1)
|
||||
elseif(stripos($path, 'file://') === 1)
|
||||
{
|
||||
$command = "$client info --non-interactive --no-auth-cache $path 2>&1";
|
||||
}
|
||||
@@ -1551,7 +1559,7 @@ class repoModel extends model
|
||||
exec($command, $output, $result);
|
||||
if($result)
|
||||
{
|
||||
$message = sprintf($this->lang->repo->error->output, $command, $result, join("<br />", $output));
|
||||
$message = sprintf($this->lang->repo->error->output, $command, $result, implode("<br />", $output));
|
||||
if(stripos($message, 'Expected FS format between') !== false and strpos($message, 'found format') !== false)
|
||||
{
|
||||
dao::$errors['client'] = $this->lang->repo->error->clientVersion;
|
||||
@@ -1614,7 +1622,7 @@ class repoModel extends model
|
||||
exec($command, $output, $result);
|
||||
if($result)
|
||||
{
|
||||
dao::$errors['submit'] = $this->lang->repo->error->connect . "<br />" . sprintf($this->lang->repo->error->output, $command, $result, join("<br />", $output));
|
||||
dao::$errors['submit'] = $this->lang->repo->error->connect . "<br />" . sprintf($this->lang->repo->error->output, $command, $result, implode("<br />", $output));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1631,9 +1639,6 @@ class repoModel extends model
|
||||
public function replaceCommentLink($comment)
|
||||
{
|
||||
$rules = $this->processRules();
|
||||
$stories = array();
|
||||
$tasks = array();
|
||||
$bugs = array();
|
||||
$storyReg = '/' . $rules['storyReg'] . '/i';
|
||||
$taskReg = '/' . $rules['taskReg'] . '/i';
|
||||
$bugReg = '/' . $rules['bugReg'] . '/i';
|
||||
@@ -1948,7 +1953,7 @@ class repoModel extends model
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->task->recordEstimate($taskID);
|
||||
$this->task->recordWorkhour($taskID);
|
||||
}
|
||||
|
||||
$action->action = $scm == 'svn' ? 'svncommited' : 'gitcommited';
|
||||
@@ -2168,7 +2173,7 @@ class repoModel extends model
|
||||
{
|
||||
$record = array();
|
||||
$record['execution'] = $executionID;
|
||||
$record['product'] = isset($products[$taskID]) ? "," . join(',', array_keys($products[$taskID])) . "," : ",0,";
|
||||
$record['product'] = isset($products[$taskID]) ? "," . implode(',', array_keys($products[$taskID])) . "," : ",0,";
|
||||
$records[$taskID] = $record;
|
||||
}
|
||||
return $records;
|
||||
@@ -2221,7 +2226,8 @@ class repoModel extends model
|
||||
{
|
||||
if($getCodePath) $project = $this->loadModel('gitlab')->apiGetSingleProject($repo->serviceHost, $repo->serviceProject);
|
||||
|
||||
$repo->path = $service ? sprintf($this->config->repo->{$service->type}->apiPath, $service->url, $repo->serviceProject) : '';
|
||||
$repo->path = (!$repo->path && $service) ? sprintf($this->config->repo->{$service->type}->apiPath, $service->url, $repo->serviceProject) : $repo->path;
|
||||
$repo->apiPath = sprintf($this->config->repo->{$service->type}->apiPath, $service->url, $repo->serviceProject);
|
||||
$repo->client = $service ? $service->url : '';
|
||||
$repo->password = $service ? $service->token : '';
|
||||
$repo->codePath = isset($project->web_url) ? $project->web_url : $repo->path;
|
||||
@@ -2382,7 +2388,7 @@ class repoModel extends model
|
||||
|
||||
/* Get file commits by repo. */
|
||||
if($repo->SCM != 'Subversion' and empty($branch)) $branch = $this->cookie->repoBranch;
|
||||
$fileCommits = $this->dao->select('t1.id,t1.path,t1.type,t1.action,t1.oldPath,t1.parent,t2.revision,t2.`comment`,t2.committer,t2.time')->from(TABLE_REPOFILES)->alias('t1')
|
||||
$fileCommits = $this->dao->select('t1.id,t1.path,t1.type,t1.action,t1.oldPath,t1.parent,t2.revision,t2.comment,t2.committer,t2.time')->from(TABLE_REPOFILES)->alias('t1')
|
||||
->leftJoin(TABLE_REPOHISTORY)->alias('t2')->on('t1.revision=t2.id')
|
||||
->leftJoin(TABLE_REPOBRANCH)->alias('t3')->on('t2.id=t3.revision')
|
||||
->where('t1.repo')->eq($repo->id)
|
||||
@@ -2526,14 +2532,11 @@ class repoModel extends model
|
||||
}
|
||||
$infos = array('revision' => $lastRevision, 'files' => $allFiles);
|
||||
|
||||
if($cacheFile)
|
||||
if($cacheFile && !file_exists($cacheFile . '.lock'))
|
||||
{
|
||||
if(!file_exists($cacheFile . '.lock'))
|
||||
{
|
||||
touch($cacheFile . '.lock');
|
||||
file_put_contents($cacheFile, serialize($infos));
|
||||
unlink($cacheFile . '.lock');
|
||||
}
|
||||
touch($cacheFile . '.lock');
|
||||
file_put_contents($cacheFile, serialize($infos));
|
||||
unlink($cacheFile . '.lock');
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2602,7 +2605,7 @@ class repoModel extends model
|
||||
{
|
||||
$files = array();
|
||||
$id = 0;
|
||||
foreach($allFiles as $key => $file)
|
||||
foreach($allFiles as $file)
|
||||
{
|
||||
$fileName = explode('/', $file);
|
||||
$parent = '';
|
||||
@@ -2612,40 +2615,24 @@ class repoModel extends model
|
||||
|
||||
$parentID = $parent == '' ? 0 : $files[$parent]['id'];
|
||||
$parent .= $parent == '' ? $path : '/' . $path;
|
||||
if(!isset($files[$parent])){
|
||||
if(!isset($files[$parent]))
|
||||
{
|
||||
$id++;
|
||||
|
||||
$id = str_replace('=', '-', base64_encode(urlencode($parent)));
|
||||
$files[$parent] = array(
|
||||
'id' => $id,
|
||||
'parent' => $parentID,
|
||||
'name' => $path,
|
||||
'path' => $parent,
|
||||
'key' => $key,
|
||||
'key' => $id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
sort($files);
|
||||
$fileTree = $this->buildTree($files);
|
||||
|
||||
$html = '<ul data-name="filesTree" data-ride="tree" data-initial-state="preserve" id="modules" class="tree">';
|
||||
foreach($fileTree as $file)
|
||||
{
|
||||
$html .= "<li class='open' data-id='{$file['id']}'>";
|
||||
if(isset($file['children']))
|
||||
{
|
||||
$html .= "<i class='icon icon-folder'></i> {$file['name']}";
|
||||
$html .= $this->getFrontFiles($file['children']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$html .= "<span class='item doc-title text-ellipsis'><i class='icon icon-file-text-alt'></i> " . html::a('#filePath' . $file['key'], $file['name'], '', "class='repoFileName' data-path='{$file['path']}' title='{$file['path']}'") . '</span>';
|
||||
}
|
||||
$html .= '</li>';
|
||||
}
|
||||
$html .= '</ul>';
|
||||
|
||||
return $html;
|
||||
return $this->buildTree($files);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2733,7 +2720,7 @@ class repoModel extends model
|
||||
$output = new stdClass();
|
||||
|
||||
$scm = $this->app->loadClass('scm');
|
||||
$repo = $this->getRepoByID($repoID);
|
||||
$repo = $this->getByID($repoID);
|
||||
if(!$repo) return $output;
|
||||
|
||||
$scm->setEngine($repo);
|
||||
@@ -2806,8 +2793,8 @@ class repoModel extends model
|
||||
}
|
||||
}
|
||||
$stories = empty($storyIDs) ? array() : $this->loadModel('story')->getByList($storyIDs);
|
||||
$bugs = empty($bugIDs) ? array() : $this->loadModel('bug')->getByList($bugIDs);
|
||||
$tasks = empty($taskIDs) ? array() : $this->loadModel('task')->getByList($taskIDs);
|
||||
$bugs = empty($bugIDs) ? array() : $this->loadModel('bug')->getByIdList($bugIDs);
|
||||
$tasks = empty($taskIDs) ? array() : $this->loadModel('task')->getByIdList($taskIDs);
|
||||
|
||||
$titleList = array();
|
||||
foreach($relationList as $key => $relation)
|
||||
@@ -2868,7 +2855,7 @@ class repoModel extends model
|
||||
public function insertDeleteRecord($repoID)
|
||||
{
|
||||
set_time_limit(0);
|
||||
$repo = $this->loadModel('repo')->getRepoByID($repoID);
|
||||
$repo = $this->loadModel('repo')->getByID($repoID);
|
||||
if(empty($repo)) return false;
|
||||
|
||||
$scm = $this->app->loadClass('scm');
|
||||
@@ -2935,7 +2922,7 @@ class repoModel extends model
|
||||
if($values)
|
||||
{
|
||||
$sql = 'INSERT INTO ' . TABLE_REPOFILES . ' (`repo`,`revision`,`path`,`oldPath`,`parent`,`type`,`action`) VALUES ' . trim($values, ',');
|
||||
$result = $this->dao->exec($sql);
|
||||
$this->dao->exec($sql);
|
||||
}
|
||||
|
||||
$this->loadModel('setting')->setItem('system.repo.synced', $this->config->repo->synced . ',' . $repoID);
|
||||
@@ -2974,7 +2961,7 @@ class repoModel extends model
|
||||
*/
|
||||
public function updateCommit($repoID, $objectID = 0, $branchID = 0)
|
||||
{
|
||||
$repo = $this->getRepoByID($repoID);
|
||||
$repo = $this->getByID($repoID);
|
||||
/* Update code commit history. */
|
||||
$commentGroup = $this->loadModel('job')->getTriggerGroup('commit', array($repoID));
|
||||
|
||||
@@ -3027,6 +3014,63 @@ class repoModel extends model
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断按钮是否可点击。
|
||||
* Judge an action is clickable or not.
|
||||
*
|
||||
* @param object $repo
|
||||
* @param string $action
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public static function isClickable(object $repo, string $action): bool
|
||||
{
|
||||
$action = strtolower($action);
|
||||
|
||||
if($action == 'execjob') return $repo->exec == '';
|
||||
if($action == 'reportview') return $repo->report == '';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取gitlab项目列表。
|
||||
* Get gitlab projects.
|
||||
*
|
||||
* @param int $gitlabID
|
||||
* @param string $projectIdList
|
||||
* @param string $filter
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getGitlabProjects(int $gitlabID, string $projectIdList = '', string $filter = ''): array
|
||||
{
|
||||
$showAll = ($filter == 'ALL' and common::hasPriv('repo', 'create')) ? true : false;
|
||||
if($this->app->user->admin or $showAll)
|
||||
{
|
||||
$projects = $this->loadModel('gitlab')->apiGetProjects($gitlabID, true, 0, 0, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$gitlabUser = $this->loadModel('gitlab')->getUserIDByZentaoAccount($gitlabID, $this->app->user->account);
|
||||
if(!$gitlabUser) $this->send(array('message' => array()));
|
||||
|
||||
$projects = $this->gitlab->apiGetProjects($gitlabID, $filter ? 'false' : 'true');
|
||||
$groupIDList = array(0 => 0);
|
||||
$groups = $this->gitlab->apiGetGroups($gitlabID, 'name_asc', 'developer');
|
||||
foreach($groups as $group) $groupIDList[] = $group->id;
|
||||
if($filter == 'IS_DEVELOPER')
|
||||
{
|
||||
foreach($projects as $key => $project)
|
||||
{
|
||||
if(!$this->gitlab->checkUserAccess($gitlabID, 0, $project, $groupIDList, 'developer')) unset($projects[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $projects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check str in array.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The tao file of repo module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Zeng Gang<zenggang@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
|
||||
class repoTao extends repoModel
|
||||
{
|
||||
/**
|
||||
* 获取最后一次提交信息。
|
||||
* Get last revision.
|
||||
*
|
||||
* @param int $repoID
|
||||
* @access protected
|
||||
* @return object|false
|
||||
*/
|
||||
protected function getLastRevision(int $repoID): object|false
|
||||
{
|
||||
return $this->dao->select('*')->from(TABLE_REPOHISTORY)->where('repo')->eq($repoID)->orderBy('time_desc')->fetch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The head switcher view file of repo module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Zeng Gang<zenggang@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
$data = array('repo' => array_values($repoGroup));
|
||||
|
||||
$tabs = array();
|
||||
$tabs[] = array('name' => 'repo', 'text' => $lang->repo->codeRepo);
|
||||
|
||||
$json = array();
|
||||
$json['data'] = $data;
|
||||
$json['tabs'] = $tabs;
|
||||
$json['searchHint'] = $lang->searchAB;
|
||||
$json['labelMap'] = array('product' => $lang->product->common);
|
||||
$json['link'] = array('repo' => sprintf($link, '{id}'));
|
||||
$json['itemType'] = 'repo';
|
||||
|
||||
renderJson($json);
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The ajaxgeteditorcontent view file of repo module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Ke Zhao<zhaoke@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
|
||||
namespace zin;
|
||||
|
||||
$canLinkStory = common::hasPriv('repo', 'linkStory');
|
||||
$canLinkBug = common::hasPriv('repo', 'linkBug');
|
||||
$canLinkTask = common::hasPriv('repo', 'linkTask');
|
||||
$canUnlinkObject = common::hasPriv('repo', 'unlink');
|
||||
|
||||
jsVar('unlinkTitle', $this->lang->repo->unlink);
|
||||
jsVar('canUnlinkObject', $canUnlinkObject);
|
||||
jsVar('fileExt', $this->config->repo->fileExt);
|
||||
jsVar('file', $pathInfo);
|
||||
jsVar('filePath', $entry);
|
||||
jsVar('blameTmpl', $lang->repo->blameTmpl);
|
||||
jsVar('repoID', $repoID);
|
||||
jsVar('showEditor', $showEditor);
|
||||
jsVar('canLinkStory', $canLinkStory);
|
||||
jsVar('canLinkBug', $canLinkBug);
|
||||
jsVar('canLinkTask', $canLinkTask);
|
||||
jsVar('objectID', 0);
|
||||
jsVar('objectType', 'story');
|
||||
jsVar('pageType', $type);
|
||||
jsVar('revision', $revision);
|
||||
jsVar('sourceRevision', $oldRevision);
|
||||
jsVar('encodePath', $this->repo->encodePath($entry));
|
||||
if($showEditor) jsVar('codeContent', $content);
|
||||
|
||||
$lang = 'php';
|
||||
foreach($this->config->repo->fileExt as $langName => $exts)
|
||||
{
|
||||
foreach($exts as $ext) if(isset($pathInfo['extension']) && str_contains('.' . $pathInfo['extension'], $ext)) $lang = $langName;
|
||||
}
|
||||
|
||||
if(strpos($config->repo->images, "|$suffix|") !== false)
|
||||
{
|
||||
$wg = div
|
||||
(
|
||||
set::class('image'),
|
||||
img(set::src('data:image/' . $suffix . ';base64,' . $content))
|
||||
);
|
||||
}
|
||||
elseif($suffix == 'binary')
|
||||
{
|
||||
$wg = div
|
||||
(
|
||||
set::class('binary'),
|
||||
a
|
||||
(
|
||||
set::href($this->repo->createLink('download', "repoID=$repoID&path=" . $this->repo->encodePath($entry) . "&fromRevision=$revision")),
|
||||
icon('download'),
|
||||
set::target('_blank'),
|
||||
set::title($this->lang->repo->download),
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$options = array(
|
||||
'value' => $content,
|
||||
'language' => $lang,
|
||||
'readOnly' => true,
|
||||
'autoIndent' => true,
|
||||
'contextmenu' => true,
|
||||
'automaticLayout' => true,
|
||||
'EditorMinimapOptions' => array('enabled' => false),
|
||||
);
|
||||
if($type == 'diff') $options = array(
|
||||
'language' => $lang,
|
||||
'readOnly' => true,
|
||||
'autoIndent' => true,
|
||||
'contextmenu' => true,
|
||||
'automaticLayout' => true,
|
||||
'renderSideBySide' => false,
|
||||
'EditorMinimapOptions' => array('enabled' => false),
|
||||
);
|
||||
$wg = monaco
|
||||
(
|
||||
set::id('codeContainer'),
|
||||
set::options($options),
|
||||
set::action($type == 'diff' ? 'diff' : 'create'),
|
||||
$type == 'diff' ? set::diffContent(jsRaw('parent.getDiffs(filePath)')) : null,
|
||||
set::onMouseDown('window.onMouseDown')
|
||||
);
|
||||
}
|
||||
|
||||
$dropMenus = array();
|
||||
if($canLinkStory) $dropMenus[] = array('id' => 'linkStory', 'text' => $this->lang->repo->linkStory, 'icon' => 'lightbulb');
|
||||
if($canLinkBug) $dropMenus[] = array('id' => 'linkBug', 'text' => $this->lang->repo->linkBug, 'icon' => 'bug');
|
||||
if($canLinkTask) $dropMenus[] = array('id' => 'linkTask', 'text' => $this->lang->repo->linkTask, 'icon' => 'todo');
|
||||
|
||||
$logWg = div
|
||||
(
|
||||
set::id('log'),
|
||||
div(set::class('history')),
|
||||
div
|
||||
(
|
||||
set::class('action-btn pull-right'),
|
||||
div(set::class('btn btn-close pull-right ghost text-black bg-light bg-opacity-50'), icon('close')),
|
||||
!empty($dropMenus) ? dropdown
|
||||
(
|
||||
set::arrow(false),
|
||||
set::staticMenu(true),
|
||||
btn
|
||||
(
|
||||
setClass('ghost text-black bg-light bg-opacity-50'),
|
||||
set::icon('ellipsis-v rotate-90'),
|
||||
),
|
||||
set::items
|
||||
(
|
||||
$dropMenus
|
||||
),
|
||||
) : '',
|
||||
),
|
||||
);
|
||||
|
||||
$relatedWg = div
|
||||
(
|
||||
set::id('related'),
|
||||
div(set::class('btn btn-left pull-left'), icon('chevron-left')),
|
||||
div(set::class('btn btn-right pull-right'), icon('chevron-right')),
|
||||
div
|
||||
(
|
||||
set::class('panel-title'),
|
||||
tabs
|
||||
(
|
||||
set::id('relationTabs'),
|
||||
tabPane
|
||||
(
|
||||
set::key('tab1'),
|
||||
set::title(''),
|
||||
tableData()
|
||||
),
|
||||
),
|
||||
),
|
||||
div(set::class('table-empty-tip'), p($this->lang->repo->notRelated))
|
||||
);
|
||||
|
||||
div
|
||||
(
|
||||
set::id('monacoEditor'),
|
||||
set::class('repoCode'),
|
||||
$wg,
|
||||
$logWg,
|
||||
$relatedWg
|
||||
);
|
||||
|
||||
set::zui(true);
|
||||
render('pageBase');
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The blame view file of repo module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Zeng Gang<zenggang@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
dropmenu(set::module('repo'), set::tab('repo'), set::objectID($repo->id));
|
||||
|
||||
/* Prepare breadcrumb navigation data. */
|
||||
$base64BranchID = helper::safe64Encode(base64_encode($branchID));
|
||||
$breadcrumbItems = array();
|
||||
$breadcrumbItems[] = h::a
|
||||
(
|
||||
set::href($this->repo->createLink('browse', "repoID=$repoID&branchID=$base64BranchID&objectID=$objectID")),
|
||||
$repo->name,
|
||||
);
|
||||
$breadcrumbItems[] = h::span('/', setStyle('margin', '0 5px'));
|
||||
|
||||
$paths = explode('/', $entry);
|
||||
$fileName = array_pop($paths);
|
||||
$postPath = '';
|
||||
foreach($paths as $pathName)
|
||||
{
|
||||
$postPath .= $pathName . '/';
|
||||
$breadcrumbItems[] = h::a
|
||||
(
|
||||
set::href($this->repo->createLink('browse', "repoID=$repoID&branchID=$base64BranchID&objectID=$objectID&path=" . $this->repo->encodePath($postPath))),
|
||||
trim($pathName, '/'),
|
||||
);
|
||||
$breadcrumbItems[] = h::span('/', setStyle('margin', '0 5px'));
|
||||
}
|
||||
if($fileName) $breadcrumbItems[] = h::span($fileName);
|
||||
|
||||
$breadcrumbItems[] = h::span
|
||||
(
|
||||
setClass('ml-2 label secondary'),
|
||||
html($revisionName),
|
||||
);
|
||||
|
||||
foreach($blames as $key => $blame)
|
||||
{
|
||||
if(isset($blame['lines']))
|
||||
{
|
||||
if($repo->SCM != 'Subversion') $blames[$key]['revision'] = substr($blame['revision'], 0, 10);
|
||||
}
|
||||
|
||||
$blames[$key]['content'] = htmlSpecialString($blame['content']);
|
||||
}
|
||||
|
||||
foreach($blames as $key => $blame) $blames[$key] = (object)$blame;
|
||||
|
||||
$blames = initTableData($blames, $config->repo->blameDtable->fieldList, $this->repo);
|
||||
|
||||
$encodePath = $this->repo->encodePath($entry);
|
||||
$encodes = array();
|
||||
foreach($lang->repo->encodingList as $key => $val)
|
||||
{
|
||||
$encodes[] = array('text' => $val, 'url' => inlink('blame', "repoID=$repoID&objectID=$objectID&entry=$encodePath&revision=$revision&encoding=$key"));
|
||||
}
|
||||
$defaultEncode = $lang->repo->encodingList[$encoding];
|
||||
|
||||
featureBar(
|
||||
backBtn
|
||||
(
|
||||
setClass('mr-5'),
|
||||
set::icon('back'),
|
||||
set::type('secondary'),
|
||||
set::back('GLOBAL'),
|
||||
$lang->goback
|
||||
),
|
||||
...$breadcrumbItems
|
||||
);
|
||||
|
||||
panel
|
||||
(
|
||||
set::title($fileName),
|
||||
to::headingActions(
|
||||
btnGroup
|
||||
(
|
||||
btn($defaultEncode),
|
||||
dropdown
|
||||
(
|
||||
btn(setClass('btn dropdown-toggle'),
|
||||
setStyle(array('padding' => '6px', 'border-radius' => '0 2px 2px 0'))),
|
||||
set::items($encodes),
|
||||
set::arrow(true),
|
||||
set::flip(true),
|
||||
set::placement('bottom-end'),
|
||||
),
|
||||
),
|
||||
),
|
||||
dtable
|
||||
(
|
||||
set::cols($config->repo->blameDtable->fieldList),
|
||||
set::data($blames),
|
||||
),
|
||||
);
|
||||
|
||||
render();
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The browse view file of repo module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Ke Zhao<zhaoke@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
|
||||
namespace zin;
|
||||
|
||||
jsVar('copied', $lang->repo->copied);
|
||||
|
||||
dropmenu(set::module('repo'), set::tab('repo'));
|
||||
|
||||
/* Prepare repo select data. */
|
||||
$branchMenus = array();
|
||||
$tagMenus = array();
|
||||
$selected = '';
|
||||
foreach($branches as $branchName)
|
||||
{
|
||||
$selected = ($branchName == $branchID and $branchOrTag == 'branch') ? $branchName : $selected;
|
||||
$base64BranchID = helper::safe64Encode(base64_encode($branchName));
|
||||
$branchLink = $this->createLink('repo', 'browse', "repoID=$repoID&branchID=$base64BranchID&objectID=$objectID");
|
||||
|
||||
$branchMenus[] = array('text' => $branchName, 'id' => $branchName, 'keys' => zget(common::convert2Pinyin(array($branchName), $branchName), ''), 'url' => $branchLink);
|
||||
}
|
||||
foreach($tags as $tagName)
|
||||
{
|
||||
$selected = ($tagName == $branchID and $branchOrTag == 'tag') ? $tagName : $selected;
|
||||
$base64TagID = helper::safe64Encode(base64_encode($tagName));
|
||||
$tagLink = $this->createLink('repo', 'browse', "repoID=$repoID&branchID=$base64TagID&objectID=$objectID&path=&revision=HEAD&refresh=0&branchOrTag=tag");
|
||||
|
||||
$tagMenus[] = array('text' => $tagName, 'id' => $tagName, 'keys' => zget(common::convert2Pinyin(array($tagName), $tagName), ''), 'url' => $tagLink);
|
||||
}
|
||||
|
||||
$tabs = array(array('name' => 'branch', 'text' => $lang->repo->branch), array('name' => 'tag', 'text' => $lang->repo->tag));
|
||||
$menuData = array('branch' => $branchMenus, 'tag' => $tagMenus);
|
||||
|
||||
/* Prepare breadcrumb navigation data. */
|
||||
$base64BranchID = helper::safe64Encode(base64_encode($branchID));
|
||||
$breadcrumbItems = array();
|
||||
$breadcrumbItems[] = h::a
|
||||
(
|
||||
set::href($this->repo->createLink('browse', "repoID=$repoID&branchID=$base64BranchID&objectID=$objectID")),
|
||||
$repo->name,
|
||||
);
|
||||
$breadcrumbItems[] = h::span('/', setStyle('margin', '0 5px'));
|
||||
|
||||
$paths = explode('/', $path);
|
||||
$fileName = array_pop($paths);
|
||||
$postPath = '';
|
||||
foreach($paths as $index => $pathName)
|
||||
{
|
||||
$postPath .= $pathName . '/';
|
||||
$breadcrumbItems[] = h::a
|
||||
(
|
||||
set::href($this->repo->createLink('browse', "repoID=$repoID&branchID=$base64BranchID&objectID=$objectID&path=" . $this->repo->encodePath($postPath))),
|
||||
trim($pathName, '/'),
|
||||
);
|
||||
$breadcrumbItems[] = h::span('/', setStyle('margin', '0 5px'));
|
||||
}
|
||||
if($fileName) $breadcrumbItems[] = h::span($fileName);
|
||||
|
||||
/* zin: Define the set::module('repo') feature bar on main menu. */
|
||||
featureBar(
|
||||
formGroup
|
||||
(
|
||||
set::class('repo-select'),
|
||||
set::required(true),
|
||||
dropmenu
|
||||
(
|
||||
setID('repoBranchDropMenu'),
|
||||
set::objectID($selected),
|
||||
set::text($selected),
|
||||
set::data(array('data' => $menuData, 'tabs' => $tabs)),
|
||||
),
|
||||
),
|
||||
...$breadcrumbItems
|
||||
);
|
||||
|
||||
/* zin: Define the toolbar on main menu. */
|
||||
$refreshLink = $this->createLink('repo', 'browse', "repoID=$repoID&branchID=" . $base64BranchID . "&objectID=$objectID&path=" . $this->repo->encodePath($path) . "&revision=$revision&refresh=1");
|
||||
$refreshItem = array('text' => $lang->refresh, 'url' => $refreshLink, 'class' => 'primary', 'icon' => 'refresh');
|
||||
|
||||
$tableData = initTableData($infos, $config->repo->repoDtable->fieldList, $this->repo);
|
||||
|
||||
$downloadWg = div
|
||||
(
|
||||
set::id('modal-downloadCode'),
|
||||
set::title($lang->repo->downloadCode),
|
||||
on('click', '', array('capture' => true, 'prevent' => true, 'stop' => true)),
|
||||
!empty($cloneUrl->svn) ? div
|
||||
(
|
||||
p(set::class('repo-downloadCode'), $lang->repo->cloneUrl),
|
||||
formRow
|
||||
(
|
||||
formGroup
|
||||
(
|
||||
set::width('450px'),
|
||||
input
|
||||
(
|
||||
set::type('text'),
|
||||
set::name('svnUrl'),
|
||||
set::value($cloneUrl->svn),
|
||||
set::readOnly(true),
|
||||
),
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::width('50px'),
|
||||
btn
|
||||
(
|
||||
set::icon('copy'),
|
||||
)
|
||||
)
|
||||
),
|
||||
) : null,
|
||||
|
||||
!empty($cloneUrl->ssh) ? div
|
||||
(
|
||||
p(set::class('repo-downloadCode'), $lang->repo->sshClone),
|
||||
formRow
|
||||
(
|
||||
formGroup
|
||||
(
|
||||
set::width('450px'),
|
||||
input
|
||||
(
|
||||
set::type('text'),
|
||||
set::name('sshUrl'),
|
||||
set::value($cloneUrl->ssh),
|
||||
set::readOnly(true),
|
||||
),
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::width('50px'),
|
||||
btn
|
||||
(
|
||||
set::class('copy-btn'),
|
||||
set::icon('copy'),
|
||||
)
|
||||
)
|
||||
),
|
||||
) : null,
|
||||
|
||||
!empty($cloneUrl->http) ? div
|
||||
(
|
||||
p(set::class('repo-downloadCode'), $lang->repo->httpClone),
|
||||
formRow
|
||||
(
|
||||
formGroup
|
||||
(
|
||||
set::width('450px'),
|
||||
input
|
||||
(
|
||||
set::type('text'),
|
||||
set::name('httpUrl'),
|
||||
set::value($cloneUrl->http),
|
||||
set::readOnly(true),
|
||||
),
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::width('50px'),
|
||||
btn
|
||||
(
|
||||
set::class('copy-btn'),
|
||||
set::icon('copy'),
|
||||
)
|
||||
)
|
||||
),
|
||||
) : null,
|
||||
|
||||
div
|
||||
(
|
||||
setStyle(array('margin-top' => '20px')),
|
||||
btn
|
||||
(
|
||||
set::icon('down-circle'),
|
||||
set::class('downloadZip-btn'),
|
||||
set::text($lang->repo->downloadZip),
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
toolbar
|
||||
(
|
||||
span(
|
||||
set::class('last-sync-time'),
|
||||
$lang->repo->notice->lastSyncTime . $cacheTime
|
||||
),
|
||||
item(set($refreshItem)),
|
||||
dropdown
|
||||
(
|
||||
set::staticMenu(true),
|
||||
btn
|
||||
(
|
||||
setClass('primary download-btn'),
|
||||
set::icon('download'),
|
||||
$lang->repo->download
|
||||
),
|
||||
to::items
|
||||
(
|
||||
array($downloadWg)
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
dtable
|
||||
(
|
||||
set::cols($config->repo->repoDtable->fieldList),
|
||||
set::data($tableData),
|
||||
set::onRenderCell(jsRaw('window.renderCell')),
|
||||
set::canRowCheckable(jsRaw('function(rowID){return false;}')),
|
||||
set::footPager(),
|
||||
);
|
||||
|
||||
/* zin: Define the sidebar in main content. */
|
||||
$encodePath = $this->repo->encodePath($path);
|
||||
$diffLink = $this->repo->createLink('diff', "repoID=$repoID&objectID=$objectID&entry=" . $encodePath . "&oldrevision={oldRevision}&newRevision={newRevision}");
|
||||
|
||||
jsVar('repoID', $repoID);
|
||||
jsVar('branch', $branchID);
|
||||
jsVar('diffLink', $diffLink);
|
||||
jsVar('sortLink', helper::createLink('repo', 'browse', "repoID={$repoID}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}"));
|
||||
|
||||
/* Disbale check all checkbox of table header */
|
||||
$config->repo->commentDtable->fieldList['id']['checkbox'] = jsRaw('(rowID) => rowID !== \'HEADER\'');
|
||||
|
||||
$commentsTableData = initTableData($revisions, $config->repo->commentDtable->fieldList, $this->repo);
|
||||
|
||||
$readAllLink = $this->repo->createLink('log', "repoID=$repoID&objectID=$objectID&entry=" . $encodePath . "&revision=HEAD&type=$logType");
|
||||
|
||||
$footToolbar['items'][] = array('text' => $lang->repo->diff, 'class' => "btn primary size-sm btn-diff", 'btnType' => 'primary', 'onClick' => jsRaw('window.diffClick'));
|
||||
$footToolbar['items'][] = array('text' => $lang->repo->allLog, 'url' => $readAllLink);
|
||||
|
||||
sidebar
|
||||
(
|
||||
set::side('right'),
|
||||
dtable
|
||||
(
|
||||
set::id('repo-comments-table'),
|
||||
set::cols($config->repo->commentDtable->fieldList),
|
||||
set::data($commentsTableData),
|
||||
set::onRenderCell(jsRaw('window.renderCommentCell')),
|
||||
set::onCheckChange(jsRaw('window.checkedChange')),
|
||||
set::canRowCheckable(jsRaw('function(rowID){return canRowCheckable(rowID);}')),
|
||||
set::footToolbar($footToolbar),
|
||||
set::footer(array('toolbar', 'flex', 'pager')),
|
||||
set::footPager(usePager()),
|
||||
set::showToolbarOnChecked(false),
|
||||
),
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -1,6 +1,206 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The create view file of repo module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Zeng Gang<zenggang@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
div('hello world');
|
||||
jsVar('pathGitTip', $lang->repo->example->path->git);
|
||||
jsVar('pathSvnTip', $lang->repo->example->path->svn);
|
||||
jsVar('clientGitTip', $lang->repo->example->client->git);
|
||||
jsVar('clientSvnTip', $lang->repo->example->client->svn);
|
||||
jsVar('scmList', $lang->repo->scmList);
|
||||
|
||||
render('page');
|
||||
formPanel
|
||||
(
|
||||
on::change('#product', 'onProductChange'),
|
||||
on::change('#SCM', 'onScmChange'),
|
||||
on::change('#serviceHost', 'onHostChange'),
|
||||
on::change('#serviceProject', 'onProjectChange'),
|
||||
set::title($lang->repo->createAction),
|
||||
set::back('repo-maintain'),
|
||||
formGroup
|
||||
(
|
||||
set::name("product[]"),
|
||||
set::label($lang->story->product),
|
||||
set::required(true),
|
||||
set::control(array("type" => "picker","multiple" => true)),
|
||||
set::items($products),
|
||||
set::value(empty($objectID) ? '' : array_keys($products))
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::name("projects[]"),
|
||||
set::label($lang->repo->projects),
|
||||
set::control(array("type" => "picker","multiple" => true)),
|
||||
set::items($projects),
|
||||
set::value($relatedProjects)
|
||||
),
|
||||
formRow
|
||||
(
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::id('SCM'),
|
||||
set::name('SCM'),
|
||||
set::label($lang->product->typeAB),
|
||||
set::required(true),
|
||||
set::value('Gitlab'),
|
||||
set::control('picker'),
|
||||
set::items($lang->repo->scmList)
|
||||
),
|
||||
h::span
|
||||
(
|
||||
setClass('tips-git leading-8 ml-2'),
|
||||
html($lang->repo->syncTips),
|
||||
),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('service hide'),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name("serviceHost"),
|
||||
set::label($lang->repo->serviceHost),
|
||||
set::required(true),
|
||||
set::value(""),
|
||||
set::control("picker"),
|
||||
set::items($serviceHosts)
|
||||
),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('service hide'),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name("serviceProject"),
|
||||
set::label($lang->repo->serviceProject),
|
||||
set::required(true),
|
||||
set::control("picker"),
|
||||
),
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name("name"),
|
||||
set::label($lang->user->name),
|
||||
set::required(true),
|
||||
set::control("text")
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('hide-service hide-git'),
|
||||
formGroup
|
||||
(
|
||||
set::name("path"),
|
||||
set::label($lang->repo->path),
|
||||
set::required(true),
|
||||
set::control("text"),
|
||||
set::placeholder($lang->repo->example->path->git),
|
||||
),
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name("encoding"),
|
||||
set::label($lang->repo->encoding),
|
||||
set::required(true),
|
||||
set::value("utf-8"),
|
||||
set::control("text"),
|
||||
set::placeholder($lang->repo->encodingsTips),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('hide-service'),
|
||||
formGroup
|
||||
(
|
||||
set::name("client"),
|
||||
set::label($lang->repo->client),
|
||||
set::required(true),
|
||||
set::control("text")
|
||||
),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('account-fields hide-service'),
|
||||
formGroup
|
||||
(
|
||||
set::name("account"),
|
||||
set::label($lang->user->account),
|
||||
set::control("text")
|
||||
),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('account-fields hide-service'),
|
||||
formGroup
|
||||
(
|
||||
set::label($lang->user->password),
|
||||
inputGroup
|
||||
(
|
||||
control(set(array
|
||||
(
|
||||
'name' => "password",
|
||||
'id' => "password",
|
||||
'value' => "",
|
||||
'type' => "password"
|
||||
))),
|
||||
control(set(array
|
||||
(
|
||||
'name' => "encrypt",
|
||||
'id' => "encrypt",
|
||||
'value' => "base64",
|
||||
'type' => "picker",
|
||||
'items' => $lang->repo->encryptList
|
||||
)))
|
||||
)
|
||||
)
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::label($lang->repo->acl),
|
||||
inputGroup
|
||||
(
|
||||
$lang->repo->group,
|
||||
width('full'),
|
||||
control(set(array
|
||||
(
|
||||
'name' => "acl[groups][]",
|
||||
'id' => "aclgroups",
|
||||
'value' => NULL,
|
||||
'type' => "picker",
|
||||
'items' => $groups,
|
||||
'multiple' => true
|
||||
)))
|
||||
),
|
||||
inputGroup
|
||||
(
|
||||
$lang->repo->user,
|
||||
control(set(array
|
||||
(
|
||||
'name' => "acl[users][]",
|
||||
'id' => "aclusers",
|
||||
'value' => NULL,
|
||||
'type' => "picker",
|
||||
'items' => $users,
|
||||
'multiple' => true
|
||||
))),
|
||||
setClass('mt-2')
|
||||
)
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::name("desc"),
|
||||
set::label($lang->story->spec),
|
||||
set::control("editor")
|
||||
)
|
||||
);
|
||||
|
||||
render();
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The diff view file of repo module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Ke Zhao<zhaoke@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
|
||||
namespace zin;
|
||||
|
||||
dropmenu(set::module('repo'), set::tab('repo'));
|
||||
|
||||
$browser = helper::getBrowser();
|
||||
jsVar('browser', $browser['name']);
|
||||
jsVar('edition', $config->edition);
|
||||
|
||||
$backURI = $this->session->repoView ? $this->session->repoView : $this->session->repoList;
|
||||
|
||||
$breadcrumbItems = array();
|
||||
$breadcrumbItems[] = h::a
|
||||
(
|
||||
set::href($this->repo->createLink('browse', "repoID=$repoID&branchID=&objectID=$objectID"), $repo->name, '', "data-app='{$app->tab}'"),
|
||||
$repo->name,
|
||||
);
|
||||
|
||||
$breadcrumbItems[] = h::span('/', setStyle('margin', '0 5px'));
|
||||
|
||||
$paths = explode('/', $entry);
|
||||
$fileName = array_pop($paths);
|
||||
$postPath = '';
|
||||
$base64BranchID = helper::safe64Encode(base64_encode($branchID));
|
||||
|
||||
foreach($paths as $pathName)
|
||||
{
|
||||
$postPath .= $pathName . '/';
|
||||
$breadcrumbItems[] = h::a
|
||||
(
|
||||
set::href($this->repo->createLink('browse', "repoID=$repoID&branchID=$base64BranchID&objectID=$objectID&path=" . $this->repo->encodePath($postPath))),
|
||||
trim($pathName, '/'),
|
||||
);
|
||||
|
||||
$breadcrumbItems[] = h::span('/', setStyle('margin', '0 5px'));
|
||||
}
|
||||
|
||||
if($fileName) $breadcrumbItems[] = h::span($fileName);
|
||||
|
||||
if(strpos($repo->SCM, 'Subversion') === false)
|
||||
{
|
||||
$oldRevision = $oldRevision == '^' ? "$newRevision" : $oldRevision;
|
||||
$revisionWg = h::span(setClass('label label-info diff-label'), substr($oldRevision, 0, 10) . " : " . substr($newRevision, 0, 10) . ' (' . zget($historys, $oldRevision, '') . ' : ' . zget($historys, $newRevision, ''));
|
||||
}
|
||||
else
|
||||
{
|
||||
$oldRevision = $oldRevision == '^' ? $newRevision - 1 : $oldRevision;
|
||||
$revisionWg = h::span(setClass('label label-info'), $oldRevision . ':' . $newRevision);
|
||||
|
||||
}
|
||||
|
||||
$breadcrumbItems[] = $revisionWg;
|
||||
$breadcrumbItems[] = span(setClass('label label-exchange'), icon('exchange'));
|
||||
|
||||
featureBar
|
||||
(
|
||||
backBtn(set::icon('back'), $backURI ? set::url($backURI) : null, setClass('bg-transparent diff-back-btn'), $lang->goback),
|
||||
item(set::type('divider')),
|
||||
...$breadcrumbItems,
|
||||
);
|
||||
|
||||
if($diffs) include 'diffeditor.html.php';
|
||||
|
||||
jsVar('oldRevision', $oldRevision);
|
||||
jsVar('newRevision', $newRevision);
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The diffeditor view file of repo module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Ke Zhao<zhaoke@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
|
||||
namespace zin;
|
||||
|
||||
$entry = count($diffs) ? $diffs[0]->fileName : '';
|
||||
$currentEntry = $this->repo->encodePath($entry);
|
||||
$fileInfo = $entry ? pathinfo($entry) : array();
|
||||
$showBug = isset($showBug) ? $showBug : true;
|
||||
$objectID = isset($objectID) ? $objectID : 0;
|
||||
$tree = $this->repo->getFileTree($repo, '', $diffs);
|
||||
$diffLink = $this->repo->createLink('diff', "repoID=$repoID&objectID=$objectID&entry=" . $file . "&oldrevision={oldRevision}&newRevision={newRevision}");
|
||||
|
||||
jsVar('diffs', $diffs);
|
||||
jsVar('tree', $tree);
|
||||
jsVar('file', $currentEntry);
|
||||
jsVar('entry', $entry);
|
||||
jsVar('diffLink', $diffLink);
|
||||
jsVar('urlParams', "repoID=$repoID&objectID=$objectID&entry=%s&oldRevision=$oldRevision&newRevision=$newRevision&showBug=$showBug&encoding=$encoding");
|
||||
|
||||
featureBar();
|
||||
|
||||
$dropMenus = array();
|
||||
if(common::hasPriv('repo', 'download')) $dropMenus[] = array('text' => $this->lang->repo->downloadDiff, 'icon' => 'download', 'data-link' => $this->repo->createLink('download', "repoID=$repoID&path={path}&fromRevision=$oldRevision&toRevision=$newRevision&type=path"), 'id' => 'repoDownloadCode');
|
||||
|
||||
$dropMenus[] = array('text' => $this->lang->repo->viewDiffList['inline'], 'icon' => 'snap-house', 'id' => 'inline', 'class' => 'inline-appose');
|
||||
$dropMenus[] = array('text' => $this->lang->repo->viewDiffList['appose'], 'icon' => 'col-archive', 'id' => 'appose', 'class' => 'inline-appose');
|
||||
div(
|
||||
set::id('fileTabs'),
|
||||
tabs
|
||||
(
|
||||
set::id('monacoTabs'),
|
||||
set::class('relative'),
|
||||
div(setStyle(array('position' => 'absolute', 'width' => '100%', 'height' => '35px', 'background' => '#efefef', 'top' => '0px'))),
|
||||
tabPane
|
||||
(
|
||||
set::title($fileInfo['basename']),
|
||||
set::active(true),
|
||||
set::key('tab-' . str_replace('=', '-', $currentEntry)),
|
||||
to::suffix
|
||||
(
|
||||
icon
|
||||
(
|
||||
'close',
|
||||
set::class('monaco-close'),
|
||||
)
|
||||
),
|
||||
div(set::id('tab-' . $currentEntry)),
|
||||
),
|
||||
dropdown
|
||||
(
|
||||
set::arrow(false),
|
||||
set::staticMenu(true),
|
||||
set::class('absolute top-0 right-0 z-10 monaco-dropmenu'),
|
||||
btn
|
||||
(
|
||||
setClass('ghost text-black pull-right'),
|
||||
set::icon('ellipsis-v rotate-90'),
|
||||
),
|
||||
set::items
|
||||
(
|
||||
$dropMenus
|
||||
),
|
||||
),
|
||||
div(set::class('absolute top-0 left-0 z-20 arrow-left btn-left'), icon('chevron-left')),
|
||||
div(set::class('absolute top-0 right-0 z-20 arrow-right btn-right'), icon('chevron-right')),
|
||||
)
|
||||
);
|
||||
|
||||
sidebar
|
||||
(
|
||||
set::side('left'),
|
||||
tree
|
||||
(
|
||||
set::id('monacoTree'),
|
||||
set::items($tree),
|
||||
set::canSplit(false),
|
||||
set::collapsedIcon('folder'),
|
||||
set::expandedIcon('folder-open'),
|
||||
set::normalIcon('file-text-alt'),
|
||||
set::activeKey($entry),
|
||||
set::onClickItem(jsRaw('window.treeClick')),
|
||||
)
|
||||
);
|
||||
|
||||
a(set::class('iframe'), setData('size', '1000px'), setData('toggle', 'modal'), set::id('linkObject'));
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The edit view file of repo module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Zeng Gang<zenggang@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
jsVar('pathGitTip', $lang->repo->example->path->git);
|
||||
jsVar('pathSvnTip', $lang->repo->example->path->svn);
|
||||
jsVar('clientGitTip', $lang->repo->example->client->git);
|
||||
jsVar('clientSvnTip', $lang->repo->example->client->svn);
|
||||
jsVar('scmList', $lang->repo->scmList);
|
||||
|
||||
formPanel
|
||||
(
|
||||
on::change('#product', 'onProductChange'),
|
||||
on::change('#SCM', 'onScmChange'),
|
||||
on::change('#serviceHost', 'onHostChange'),
|
||||
on::change('#serviceProject', 'onProjectChange'),
|
||||
set::title($lang->repo->edit),
|
||||
set::back('repo-maintain'),
|
||||
formGroup
|
||||
(
|
||||
set::name("product[]"),
|
||||
set::label($lang->story->product),
|
||||
set::required(true),
|
||||
set::control(array("type" => "picker","multiple" => true)),
|
||||
set::items($products),
|
||||
set::value($repo->product)
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::name("projects[]"),
|
||||
set::label($lang->repo->projects),
|
||||
set::control(array("type" => "picker","multiple" => true)),
|
||||
set::items($relatedProjects),
|
||||
set::value($repo->projects)
|
||||
),
|
||||
formRow
|
||||
(
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name("SCM"),
|
||||
set::label($lang->product->typeAB),
|
||||
set::required(true),
|
||||
set::value($repo->SCM),
|
||||
set::control("picker"),
|
||||
set::items($lang->repo->scmList)
|
||||
),
|
||||
h::span
|
||||
(
|
||||
setClass('tips-git leading-8 ml-2'),
|
||||
html($lang->repo->syncTips),
|
||||
),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('service hide'),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name("serviceHost"),
|
||||
set::label($lang->repo->serviceHost),
|
||||
set::required(true),
|
||||
set::value(isset($repo->gitService) ? $repo->gitService : ''),
|
||||
set::control("picker"),
|
||||
set::items($serviceHosts)
|
||||
),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('service hide'),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name("serviceProject"),
|
||||
set::label($lang->repo->serviceProject),
|
||||
set::required(true),
|
||||
set::control("picker"),
|
||||
set::items($projects),
|
||||
set::value(isset($repo->project) ? $repo->project : ''),
|
||||
),
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name("name"),
|
||||
set::label($lang->user->name),
|
||||
set::required(true),
|
||||
set::control("text"),
|
||||
set::value($repo->name),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('hide-service hide-git'),
|
||||
formGroup
|
||||
(
|
||||
set::name("path"),
|
||||
set::label($lang->repo->path),
|
||||
set::required(true),
|
||||
set::control("text"),
|
||||
set::placeholder($lang->repo->example->path->git),
|
||||
set::value($repo->path),
|
||||
),
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name("encoding"),
|
||||
set::label($lang->repo->encoding),
|
||||
set::required(true),
|
||||
set::value($repo->encoding),
|
||||
set::control("text"),
|
||||
set::placeholder($lang->repo->encodingsTips),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('hide-service'),
|
||||
formGroup
|
||||
(
|
||||
set::name("client"),
|
||||
set::label($lang->repo->client),
|
||||
set::required(true),
|
||||
set::control("text"),
|
||||
set::value($repo->client),
|
||||
),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('account-fields hide-service'),
|
||||
formGroup
|
||||
(
|
||||
set::name("account"),
|
||||
set::label($lang->user->account),
|
||||
set::control("text"),
|
||||
set::value($repo->account),
|
||||
),
|
||||
),
|
||||
formRow
|
||||
(
|
||||
setClass('account-fields hide-service'),
|
||||
formGroup
|
||||
(
|
||||
set::label($lang->user->password),
|
||||
inputGroup
|
||||
(
|
||||
control(set(array
|
||||
(
|
||||
'name' => "password",
|
||||
'id' => "password",
|
||||
'value' => $repo->password,
|
||||
'type' => "password"
|
||||
))),
|
||||
control(set(array
|
||||
(
|
||||
'name' => "encrypt",
|
||||
'id' => "encrypt",
|
||||
'value' => $repo->encrypt,
|
||||
'type' => "picker",
|
||||
'items' => $lang->repo->encryptList
|
||||
)))
|
||||
)
|
||||
)
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::label($lang->repo->acl),
|
||||
inputGroup
|
||||
(
|
||||
$lang->repo->group,
|
||||
width('full'),
|
||||
control(set(array
|
||||
(
|
||||
'name' => "acl[groups][]",
|
||||
'id' => "aclgroups",
|
||||
'value' => empty($repo->acl->groups) ? '' : implode(',', $repo->acl->groups),
|
||||
'type' => "picker",
|
||||
'items' => $groups,
|
||||
'multiple' => true
|
||||
)))
|
||||
),
|
||||
inputGroup
|
||||
(
|
||||
$lang->repo->user,
|
||||
control(set(array
|
||||
(
|
||||
'name' => "acl[users][]",
|
||||
'id' => "aclusers",
|
||||
'value' => empty($repo->acl->users) ? '' : implode(',', $repo->acl->users),
|
||||
'type' => "picker",
|
||||
'items' => $users,
|
||||
'multiple' => true
|
||||
))),
|
||||
setClass('mt-2')
|
||||
)
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::name("desc"),
|
||||
set::label($lang->story->spec),
|
||||
set::control("editor"),
|
||||
set::value($repo->desc),
|
||||
)
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The import view file of repo module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Zeng Gang<zenggang@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
$items = array();
|
||||
$items[] = array('name' => 'no', 'label' => $lang->user->abbr->id, 'control' => 'static', 'width' => '32px', 'class' => 'no');
|
||||
$items[] = array('name' => 'serviceProject', 'hidden' => true);
|
||||
$items[] = array('name' => 'name_with_namespace', 'label' => $lang->repo->repo, 'control' => 'static', 'width' => '264px');
|
||||
$items[] = array('name' => 'name', 'label' => $lang->repo->importName);
|
||||
$items[] = array('name' => 'product', 'label' => $lang->repo->product, 'control' => array('type' => 'picker', 'multiple' => true), 'items' => $products);
|
||||
$items[] = array('name' => 'projects', 'label' => $lang->repo->projects, 'control' => array('type' => 'picker', 'multiple' => true), 'items' => $projects);
|
||||
|
||||
$no = 1;
|
||||
foreach($repoList as $repo)
|
||||
{
|
||||
$repo->serviceProject = $repo->id;
|
||||
$repo->no = $no ++;
|
||||
}
|
||||
|
||||
featureBar
|
||||
(
|
||||
h::a
|
||||
(
|
||||
setClass('form-title'),
|
||||
set::href($this->createLink('repo', 'import')),
|
||||
$lang->repo->batchCreate,
|
||||
),
|
||||
picker
|
||||
(
|
||||
setClass('ml-3'),
|
||||
width('200px'),
|
||||
on::change('selectServer'),
|
||||
set::name('servers'),
|
||||
set::id('servers'),
|
||||
set::placeholder($lang->repo->importServer),
|
||||
set::items(array('' => '') + $gitlabPairs),
|
||||
set::value($gitlab->id)
|
||||
),
|
||||
);
|
||||
|
||||
formBatchPanel
|
||||
(
|
||||
set::id('repoList'),
|
||||
set::back('repo-maintain'),
|
||||
set::mode(count($repoList) == 0 ? 'edit' : 'add'),
|
||||
set::addRowIcon('false'),
|
||||
set::items($items),
|
||||
set::data($repoList),
|
||||
set::maxRows(count($repoList)),
|
||||
on::change('[data-name="product"]', 'loadProductProjects'),
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The linkbug file of repo module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Ke Zhao <zhaoke@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
jsVar('orderBy', $orderBy);
|
||||
jsVar('sortLink', createLink('repo', 'linkBug', "repoID=$repoID&revision=$revision&browseType=$browseType¶m=$param&orderBy={orderBy}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}"));
|
||||
|
||||
detailHeader
|
||||
(
|
||||
to::prefix(''),
|
||||
to::title
|
||||
(
|
||||
$lang->productplan->linkBug,
|
||||
)
|
||||
);
|
||||
|
||||
$footToolbar = array('items' => array
|
||||
(
|
||||
array('text' => $lang->productplan->linkBug, 'className' => 'batch-btn ajax-btn', 'data-url' => helper::createLink('repo', 'linkBug', "repoID=$repoID&revision=$revision&browseType=$browseType¶m=$param&orderBy=$orderBy"))
|
||||
), 'btnProps' => array('size' => 'sm', 'btnType' => 'secondary', 'data-type' => 'bugs'));
|
||||
|
||||
div(setID('searchFormPanel'), set('data-module', 'bug'), searchToggle(set::open(true), set::module('bug')));
|
||||
|
||||
div
|
||||
(
|
||||
set('class', 'repo-linkstory-title'),
|
||||
icon('unlink'),
|
||||
span
|
||||
(
|
||||
set('class', 'font-semibold ml-2'),
|
||||
$lang->productplan->unlinkedBugs . "({$pager->recTotal})"
|
||||
)
|
||||
);
|
||||
$cols = array();
|
||||
foreach($config->release->dtable->defaultFields['linkBug'] as $field) $cols[$field] = zget($config->bug->dtable->fieldList, $field, array());
|
||||
$cols['title']['data-size'] = 'lg';
|
||||
$cols['title']['data-toggle'] = 'modal';
|
||||
|
||||
$allBugs = initTableData($allBugs, $cols);
|
||||
$data = array_values($allBugs);
|
||||
dtable
|
||||
(
|
||||
set::userMap($users),
|
||||
set::data($data),
|
||||
set::cols($cols),
|
||||
set::checkable(true),
|
||||
set::footToolbar($footToolbar),
|
||||
set::sortLink(jsRaw('createSortLink')),
|
||||
set::footPager(usePager()),
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The linkstory file of repo module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Ke Zhao <zhaoke@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
jsVar('orderBy', $orderBy);
|
||||
jsVar('sortLink', createLink('repo', 'linkStory', "repoID=$repoID&revision=$revision&browseType=$browseType¶m=$param&orderBy={orderBy}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}"));
|
||||
|
||||
detailHeader
|
||||
(
|
||||
to::prefix(''),
|
||||
to::title
|
||||
(
|
||||
$lang->repo->linkStory,
|
||||
)
|
||||
);
|
||||
|
||||
$footToolbar = array('items' => array
|
||||
(
|
||||
array('text' => $lang->repo->linkStory, 'className' => 'batch-btn ajax-btn', 'data-url' => helper::createLink('repo', 'linkStory', "repoID=$repoID&revision=$revision&browseType=$browseType¶m=$param&orderBy=$orderBy"))
|
||||
), 'btnProps' => array('size' => 'sm', 'btnType' => 'secondary', 'data-type' => 'stories'));
|
||||
|
||||
div(setID('searchFormPanel'), set('data-module', 'story'), searchToggle(set::open(true), set::module('story')));
|
||||
|
||||
div
|
||||
(
|
||||
set('class', 'repo-linkstory-title'),
|
||||
icon('unlink'),
|
||||
span
|
||||
(
|
||||
set('class', 'font-semibold ml-2'),
|
||||
$lang->productplan->unlinkedStories . "({$pager->recTotal})"
|
||||
)
|
||||
);
|
||||
|
||||
$cols = array();
|
||||
foreach($config->release->dtable->defaultFields['linkStory'] as $field) $cols[$field] = zget($config->release->dtable->story->fieldList, $field, array());
|
||||
$cols = array_map(function($col){$col['show'] = true; return $col;}, $cols);
|
||||
$cols['title']['link'] = $this->createLink('story', 'view', "storyID={id}");
|
||||
$cols['title']['nestedToggle'] = false;
|
||||
$cols['title']['data-size'] = 'lg';
|
||||
|
||||
$allStories = initTableData($allStories, $cols);
|
||||
$data = array_values($allStories);
|
||||
dtable
|
||||
(
|
||||
set::userMap($users),
|
||||
set::data($data),
|
||||
set::cols($cols),
|
||||
set::checkable(true),
|
||||
set::footToolbar($footToolbar),
|
||||
set::sortLink(jsRaw('createSortLink')),
|
||||
set::footPager(usePager()),
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The linktask file of repo module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Ke Zhao <zhaoke@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
jsVar('orderBy', $orderBy);
|
||||
jsVar('sortLink', createLink('repo', 'linkTask', "repoID=$repoID&revision=$revision&browseType=$browseType¶m=$param&orderBy={orderBy}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}"));
|
||||
|
||||
detailHeader
|
||||
(
|
||||
to::prefix(''),
|
||||
to::title
|
||||
(
|
||||
$lang->repo->linkTask,
|
||||
)
|
||||
);
|
||||
|
||||
$footToolbar = array('items' => array
|
||||
(
|
||||
array('text' => $lang->repo->linkTask, 'className' => 'batch-btn ajax-btn', 'data-url' => helper::createLink('repo', 'linkTask', "repoID=$repoID&revision=$revision&browseType=$browseType¶m=$param&orderBy=$orderBy"))
|
||||
), 'btnProps' => array('size' => 'sm', 'btnType' => 'secondary', 'data-type' => 'tasks'));
|
||||
|
||||
div(setID('searchFormPanel'), set('data-module', 'task'), searchToggle(set::open(true), set::module('task')));
|
||||
|
||||
div
|
||||
(
|
||||
set('class', 'repo-linkstory-title'),
|
||||
icon('unlink'),
|
||||
span
|
||||
(
|
||||
set('class', 'font-semibold ml-2'),
|
||||
$lang->repo->unlinkedTasks . "({$pager->recTotal})"
|
||||
)
|
||||
);
|
||||
$allTasks = initTableData($allTasks, $config->repo->taskDtable->fieldList);
|
||||
$data = array_values($allTasks);
|
||||
dtable
|
||||
(
|
||||
set::userMap($users),
|
||||
set::data($data),
|
||||
set::cols($config->repo->taskDtable->fieldList),
|
||||
set::checkable(true),
|
||||
set::footToolbar($footToolbar),
|
||||
set::sortLink(jsRaw('createSortLink')),
|
||||
set::footPager(usePager()),
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The log view file of repo module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Zeng Gang<zenggang@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
dropmenu(set::module('repo'), set::tab('repo'));
|
||||
|
||||
$diffLink = $this->repo->createLink('diff', "repoID=$repoID&objectID=$objectID&entry=" . $this->repo->encodePath($entry) . "&oldrevision={oldRevision}&newRevision={newRevision}");
|
||||
|
||||
jsVar('diffLink', $diffLink);
|
||||
|
||||
/* Prepare breadcrumb navigation data. */
|
||||
$base64BranchID = helper::safe64Encode(base64_encode($branchID));
|
||||
$breadcrumbItems = array();
|
||||
$breadcrumbItems[] = h::a
|
||||
(
|
||||
set::href($this->repo->createLink('log', "repoID=$repoID&objectID=$objectID")),
|
||||
$repo->name,
|
||||
);
|
||||
$breadcrumbItems[] = h::span('/', setStyle('margin', '0 5px'));
|
||||
|
||||
$paths = explode('/', $entry);
|
||||
$fileName = array_pop($paths);
|
||||
$postPath = '';
|
||||
foreach($paths as $pathName)
|
||||
{
|
||||
$postPath .= $pathName . '/';
|
||||
$breadcrumbItems[] = h::a
|
||||
(
|
||||
set::href($this->repo->createLink('log', "repoID=$repoID&objectID=$objectID&entry=" . $this->repo->encodePath($postPath))),
|
||||
trim($pathName, '/'),
|
||||
);
|
||||
$breadcrumbItems[] = h::span('/', setStyle('margin', '0 5px'));
|
||||
}
|
||||
if($fileName) $breadcrumbItems[] = h::span($fileName);
|
||||
|
||||
foreach($logs as $log)
|
||||
{
|
||||
$log->revision = substr($log->revision, 0, 10);
|
||||
}
|
||||
|
||||
/* Disbale check all checkbox of table header */
|
||||
$config->repo->logDtable->fieldList['revision']['checkbox'] = jsRaw('(rowID) => rowID !== \'HEADER\'');
|
||||
|
||||
$config->repo->logDtable->fieldList['revision']['link'] = array('module' => 'repo', 'method' => 'revision', 'params' => "repoID={$repoID}&objectID={$objectID}&revision={revision}");
|
||||
|
||||
$logs = initTableData($logs, $config->repo->logDtable->fieldList);
|
||||
|
||||
$footToolbar['items'][] = array('text' => $lang->repo->diff, 'class' => "btn primary size-sm btn-diff", 'btnType' => 'primary', 'onClick' => jsRaw('window.diffClick'));
|
||||
|
||||
featureBar(
|
||||
backBtn
|
||||
(
|
||||
setClass('mr-5'),
|
||||
set::icon('back'),
|
||||
set::type('secondary'),
|
||||
set::back('repo-browse'),
|
||||
$lang->goback
|
||||
),
|
||||
...$breadcrumbItems
|
||||
);
|
||||
|
||||
dtable
|
||||
(
|
||||
set::id('repo-logs-table'),
|
||||
set::cols($config->repo->logDtable->fieldList),
|
||||
set::data($logs),
|
||||
set::onCheckChange(jsRaw('window.checkedChange')),
|
||||
set::canRowCheckable(jsRaw('function(rowID){return canRowCheckable(rowID);}')),
|
||||
set::footToolbar($footToolbar),
|
||||
set::footer(array('toolbar', 'flex', 'pager')),
|
||||
set::footPager(usePager('pager', 'noTotalCount')),
|
||||
set::showToolbarOnChecked(false),
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The maintain view file of repo module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Zeng Gang<zenggang@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
$createItem = array('text' => $lang->repo->createAction, 'url' => createLink('repo', 'create'));
|
||||
$batchCreateItem = array('text' => $lang->repo->batchCreate, 'url' => createLink('repo', 'import'));
|
||||
|
||||
foreach($repoList as $repo)
|
||||
{
|
||||
$jobID = 0;
|
||||
$repo->exec = 'disabled';
|
||||
$repo->report = 'disabled';
|
||||
if(isset($sonarRepoList[$repo->id]))
|
||||
{
|
||||
$repo->exec = '';
|
||||
$repo->job = $sonarRepoList[$repo->id]->id;
|
||||
if(in_array($repo->job, $successJobs)) $repo->report = '';
|
||||
}
|
||||
|
||||
$repo->productNames = '';
|
||||
$productList = explode(',', str_replace(' ', '', $repo->product));
|
||||
if($productList)
|
||||
{
|
||||
foreach($productList as $productID)
|
||||
{
|
||||
if(!isset($products[$productID])) continue;
|
||||
$repo->productNames .= ' ' . zget($products, $productID, $productID);
|
||||
}
|
||||
}
|
||||
|
||||
$repo->projectNames = '';
|
||||
$projectList = explode(',', str_replace(' ', '', $repo->projects));
|
||||
if($projectList)
|
||||
{
|
||||
foreach($projectList as $projectID)
|
||||
{
|
||||
if(!isset($projects[$projectID])) continue;
|
||||
$repo->projectNames .= ' ' . zget($projects, $projectID, $projectID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$config->repo->dtable->fieldList['name']['link'] = $this->createLink('repo', 'browse', "repoID={id}&branchID=&objectID={$objectID}");
|
||||
$config->repo->dtable->fieldList['actions']['list']['edit']['url'] = $this->createLink('repo', 'edit', "repoID={id}&objectID={$objectID}");
|
||||
$config->repo->dtable->fieldList['actions']['list']['delete']['url'] = $this->createLink('repo', 'delete', "repoID={id}&objectID={$objectID}");
|
||||
|
||||
$repos = initTableData($repoList, $config->repo->dtable->fieldList, $this->repo);
|
||||
|
||||
featureBar
|
||||
(
|
||||
set::current('all'),
|
||||
li(searchToggle()),
|
||||
);
|
||||
|
||||
toolBar
|
||||
(
|
||||
!hasPriv('repo', 'create') && hasPriv('repo', 'import') ? item(set($batchCreateItem + array
|
||||
(
|
||||
'icon' => 'plus',
|
||||
'class' => 'btn primary',
|
||||
))) : null,
|
||||
!hasPriv('repo', 'import') && hasPriv('repo', 'create') ? item(set($createItem + array
|
||||
(
|
||||
'icon' => 'plus',
|
||||
'class' => 'btn primary',
|
||||
))) : null,
|
||||
hasPriv('repo', 'import') && hasPriv('repo', 'create') ? btnGroup
|
||||
(
|
||||
btn(setClass('btn primary'), set::icon('plus'), set::url(createLink('repo', 'create')), $lang->repo->createAction),
|
||||
dropDown
|
||||
(
|
||||
btn(setClass('btn primary dropdown-toggle'),
|
||||
setStyle(array('padding' => '6px', 'border-radius' => '0 2px 2px 0'))),
|
||||
set::placement('bottom-end'),
|
||||
set::items(array($createItem, $batchCreateItem)),
|
||||
),
|
||||
) : null,
|
||||
);
|
||||
|
||||
dtable
|
||||
(
|
||||
set::cols($config->repo->dtable->fieldList),
|
||||
set::data($repos),
|
||||
set::footPager(usePager()),
|
||||
);
|
||||
|
||||
render();
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The monaco view file of repo module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Ke Zhao<zhaoke@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
|
||||
namespace zin;
|
||||
|
||||
dropmenu(set::module('repo'), set::tab('repo'));
|
||||
|
||||
$tree = $this->repo->getFileTree($repo);
|
||||
|
||||
jsVar('isonlybody', isonlybody());
|
||||
jsVar('entry', $entry);
|
||||
jsVar('repoID', $repoID);
|
||||
jsVar('repo', $repo);
|
||||
jsVar('revision', $revision);
|
||||
jsVar('branchID', $branchID);
|
||||
jsVar('branchMenus', $dropMenus);
|
||||
jsVar('file', $file);
|
||||
jsVar('tree', $tree);
|
||||
jsVar('openedFiles', array($entry));
|
||||
jsVar('urlParams', "repoID=$repoID&objectID=$objectID&entry=%s&revision=$revision&showBug=$showBug&encoding=$encoding");
|
||||
jsVar('currentLink', $this->createLink('repo', 'view', "repoID=$repoID&objectID=$objectID&entry=$file"));
|
||||
|
||||
featureBar();
|
||||
|
||||
$monacoDropMenus = array();
|
||||
if(common::hasPriv('repo', 'blame')) $monacoDropMenus[] = array('text' => $this->lang->repo->blame, 'icon' => 'blame', 'data-link' => $this->repo->createLink('blame', "repoID=$repoID&objectID=$objectID&entry={path}&revision=$revision&encoding=$encoding"), 'class' => 'repoDropDownMenu');
|
||||
if(common::hasPriv('repo', 'download')) $monacoDropMenus[] = array('text' => $this->lang->repo->download, 'icon' => 'download', 'data-link' => $this->repo->createLink('download', "repoID=$repoID&path={path}&fromRevision=$revision"), 'class' => 'repoDropDownMenu');
|
||||
|
||||
$tabs = array(array('name' => 'branch', 'text' => $lang->repo->branch), array('name' => 'tag', 'text' => $lang->repo->tag));
|
||||
$menuData = array('branch' => $dropMenus['branchMenus'], 'tag' => $dropMenus['tagMenus']);
|
||||
|
||||
div(
|
||||
set::id('fileTabs'),
|
||||
setStyle('position', 'relative'),
|
||||
tabs
|
||||
(
|
||||
set::id('monacoTabs'),
|
||||
set::class('relative'),
|
||||
div(setStyle(array('position' => 'absolute', 'width' => '100%', 'height' => '40px', 'background' => '#efefef', 'top' => '0px'))),
|
||||
tabPane
|
||||
(
|
||||
set::title($pathInfo['basename']),
|
||||
set::active(true),
|
||||
set::key('tab-' . str_replace('=', '-', $file)),
|
||||
to::suffix
|
||||
(
|
||||
icon
|
||||
(
|
||||
'close',
|
||||
set::class('monaco-close'),
|
||||
)
|
||||
),
|
||||
div(set::id('tab-' . $file)),
|
||||
),
|
||||
dropdown
|
||||
(
|
||||
set::arrow(false),
|
||||
set::staticMenu(true),
|
||||
set::key('dropdown'),
|
||||
set::class('absolute top-0 right-0 z-10 monaco-dropmenu'),
|
||||
btn
|
||||
(
|
||||
setClass('ghost text-black pull-right'),
|
||||
set::icon('ellipsis-v rotate-90'),
|
||||
),
|
||||
set::items
|
||||
(
|
||||
$monacoDropMenus
|
||||
),
|
||||
),
|
||||
div(set::class('absolute top-0 left-0 z-20 arrow-left btn-left'), icon('chevron-left')),
|
||||
div(set::class('absolute top-0 right-0 z-20 arrow-right btn-right'), icon('chevron-right')),
|
||||
)
|
||||
);
|
||||
|
||||
sidebar
|
||||
(
|
||||
set::side('left'),
|
||||
dropmenu
|
||||
(
|
||||
setID('repoBranchDropMenu'),
|
||||
on::click('window.changeBranch'),
|
||||
on::change('window.changeBranch'),
|
||||
set::objectID($dropMenus['selected']),
|
||||
set::text($dropMenus['selected']),
|
||||
set::data(array('data' => $menuData, 'tabs' => $tabs)),
|
||||
),
|
||||
tree
|
||||
(
|
||||
set::id('monacoTree'),
|
||||
set::items($tree),
|
||||
set::canSplit(false),
|
||||
set::collapsedIcon('folder'),
|
||||
set::expandedIcon('folder-open'),
|
||||
set::normalIcon('file-text-alt'),
|
||||
set::activeKey($entry),
|
||||
set::onClickItem(jsRaw('window.treeClick')),
|
||||
)
|
||||
);
|
||||
|
||||
a(set::class('iframe'), setData('size', '1000px'), setData('toggle', 'modal'), set::id('linkObject'));
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The showsynccommit view file of repo module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Ke Zhao<zhaoke@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
|
||||
namespace zin;
|
||||
|
||||
featureBar();
|
||||
|
||||
if(empty($branch))
|
||||
{
|
||||
$link = helper::createLink('repo', 'ajaxSyncCommit', "repoID=$repoID");
|
||||
}
|
||||
else
|
||||
{
|
||||
$link = helper::createLink('repo', 'ajaxSyncBranchCommit', "repoID=$repoID&branch=" . helper::safe64Encode(base64_encode($branch)));
|
||||
}
|
||||
|
||||
jsVar('link', $link);
|
||||
jsVar('browseLink', $browseLink);
|
||||
jsVar('syncComplete', $lang->repo->notice->syncComplete);
|
||||
div
|
||||
(
|
||||
setClass('sync-main-content'),
|
||||
div
|
||||
(
|
||||
set::class('sync-content'),
|
||||
div
|
||||
(
|
||||
setClass('alert light-pale flex items-center'),
|
||||
icon(setClass('icon icon-info-sign icon-2x alert-icon'), 'check-sign'),
|
||||
div
|
||||
(
|
||||
h3($lang->repo->notice->syncing),
|
||||
div(setClass('sync-line')),
|
||||
p($lang->repo->notice->syncedCount, span($version, set::id('commits')))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -0,0 +1,406 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The zen file of repo module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Zeng Gang<zenggang@easycorp.ltd>
|
||||
* @package repo
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class repoZen extends repo
|
||||
{
|
||||
/**
|
||||
* 准备创建版本库的数据。
|
||||
* Prepare create repo data.
|
||||
*
|
||||
* @param form $formData
|
||||
* @param bool $isPipelineServer
|
||||
* @access protected
|
||||
* @return object|false
|
||||
*/
|
||||
protected function prepareCreate(form $formData, bool $isPipelineServer): object|false
|
||||
{
|
||||
if(!$this->checkClient()) return false;
|
||||
if(!$this->checkConnection()) return false;
|
||||
|
||||
$repo = $formData
|
||||
->setIf($isPipelineServer, 'password', $this->post->serviceToken)
|
||||
->setIf($this->post->SCM == 'Gitlab', 'path', '')
|
||||
->setIf($this->post->SCM == 'Gitlab', 'client', '')
|
||||
->setIf($this->post->SCM == 'Gitlab', 'extra', $this->post->serviceProject)
|
||||
->setIf($isPipelineServer, 'prefix', '')
|
||||
->setIf($this->post->SCM == 'Git', 'account', '')
|
||||
->setIf($this->post->SCM == 'Git', 'password', '')
|
||||
->setIf(in_array($this->post->SCM, array('Gitea', 'Gogs')), 'path', $_POST['path'])
|
||||
->setIf($this->post->acl != '', 'acl', json_encode($this->post->acl))
|
||||
->setIf($this->post->encrypt == 'base64', 'password', base64_encode($this->post->password))
|
||||
->skipSpecial('path,client,account,password')
|
||||
->setDefault('product', '')->join('product', ',')
|
||||
->setDefault('projects', '')->join('projects', ',')
|
||||
->get();
|
||||
|
||||
if($repo->SCM == 'Subversion')
|
||||
{
|
||||
$scm = $this->app->loadClass('scm');
|
||||
$scm->setEngine($repo);
|
||||
$info = $scm->info('');
|
||||
$infoRoot = urldecode($info->root);
|
||||
$repo->prefix = empty($infoRoot) ? '' : trim(str_ireplace($infoRoot, '', str_replace('\\', '/', $repo->path)), '/');
|
||||
if($repo->prefix) $repo->prefix = '/' . $repo->prefix;
|
||||
}
|
||||
return $repo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查svn、git客户端。
|
||||
* Check svn/git client.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkClient(): bool
|
||||
{
|
||||
if($this->post->SCM == 'Gitlab') return true;
|
||||
if(!$this->config->features->checkClient) return true;
|
||||
|
||||
if(!$this->post->client)
|
||||
{
|
||||
dao::$errors['client'] = sprintf($this->lang->error->notempty, $this->lang->repo->client);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strpos($this->post->client, ' '))
|
||||
{
|
||||
dao::$errors['client'] = $this->lang->repo->error->clientPath;
|
||||
return false;
|
||||
}
|
||||
|
||||
$clientVersionFile = $this->session->clientVersionFile;
|
||||
if(empty($clientVersionFile))
|
||||
{
|
||||
$clientVersionFile = $this->app->getLogRoot() . uniqid('version_') . '.log';
|
||||
|
||||
session_start();
|
||||
$this->session->set('clientVersionFile', $clientVersionFile);
|
||||
session_write_close();
|
||||
}
|
||||
|
||||
if(file_exists($clientVersionFile)) return true;
|
||||
|
||||
$cmd = $this->post->client . " --version > $clientVersionFile";
|
||||
dao::$errors['client'] = sprintf($this->lang->repo->error->safe, $clientVersionFile, $cmd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查连接。
|
||||
* Check connection
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkConnection(): bool
|
||||
{
|
||||
if(empty($_POST)) return false;
|
||||
|
||||
$scm = $this->post->SCM;
|
||||
$client = $this->post->client;
|
||||
$account = $this->post->account;
|
||||
$password = $this->post->password;
|
||||
$encoding = strtoupper($this->post->encoding);
|
||||
$path = $this->post->path;
|
||||
if($encoding != 'UTF8' and $encoding != 'UTF-8') $path = helper::convertEncoding($path, 'utf-8', $encoding);
|
||||
|
||||
if($scm == 'Subversion')
|
||||
{
|
||||
/* Get svn version. */
|
||||
$versionCommand = "$client --version --quiet 2>&1";
|
||||
exec($versionCommand, $versionOutput, $versionResult);
|
||||
if($versionResult)
|
||||
{
|
||||
$message = sprintf($this->lang->repo->error->output, $versionCommand, $versionResult, implode("<br />", $versionOutput));
|
||||
dao::$errors['client'] = $this->lang->repo->error->cmd . "<br />" . nl2br($message);
|
||||
return false;
|
||||
}
|
||||
$svnVersion = end($versionOutput);
|
||||
|
||||
$path = '"' . str_replace(array('%3A', '%2F', '+'), array(':', '/', ' '), urlencode($path)) . '"';
|
||||
if(stripos($path, 'https://') === 1 or stripos($path, 'svn://') === 1)
|
||||
{
|
||||
if(version_compare($svnVersion, '1.6', '<'))
|
||||
{
|
||||
dao::$errors['client'] = $this->lang->repo->error->version;
|
||||
return false;
|
||||
}
|
||||
|
||||
$command = "$client info --username $account --password $password --non-interactive --trust-server-cert-failures=cn-mismatch --trust-server-cert --no-auth-cache $path 2>&1";
|
||||
if(version_compare($svnVersion, '1.9', '<')) $command = "$client info --username $account --password $password --non-interactive --trust-server-cert --no-auth-cache $path 2>&1";
|
||||
}
|
||||
elseif(stripos($path, 'file://') === 1)
|
||||
{
|
||||
$command = "$client info --non-interactive --no-auth-cache $path 2>&1";
|
||||
}
|
||||
else
|
||||
{
|
||||
$command = "$client info --username $account --password $password --non-interactive --no-auth-cache $path 2>&1";
|
||||
}
|
||||
|
||||
exec($command, $output, $result);
|
||||
if($result)
|
||||
{
|
||||
$message = sprintf($this->lang->repo->error->output, $command, $result, implode("<br />", $output));
|
||||
if(stripos($message, 'Expected FS format between') !== false and strpos($message, 'found format') !== false)
|
||||
{
|
||||
dao::$errors['client'] = $this->lang->repo->error->clientVersion;
|
||||
return false;
|
||||
}
|
||||
if(preg_match('/[^\:\/A-Za-z0-9_\-\'\"\.]/', $path))
|
||||
{
|
||||
dao::$errors['encoding'] = $this->lang->repo->error->encoding . "<br />" . nl2br($message);
|
||||
return false;
|
||||
}
|
||||
|
||||
dao::$errors['submit'] = $this->lang->repo->error->connect . "<br>" . nl2br($message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif(in_array($scm, array('Gitea', 'Gogs')))
|
||||
{
|
||||
if($this->post->name != '' and $this->post->serviceProject != '')
|
||||
{
|
||||
$module = strtolower($scm);
|
||||
$project = $this->loadModel($module)->apiGetSingleProject($this->post->serviceHost, $this->post->serviceProject);
|
||||
if(isset($project->tokenCloneUrl))
|
||||
{
|
||||
$path = $this->app->getAppRoot() . 'www/data/repo/' . $this->post->name . '_' . $module;
|
||||
if(!realpath($path))
|
||||
{
|
||||
$cmd = 'git clone --progress -v "' . $project->tokenCloneUrl . '" "' . $path . '" > "' . $this->app->getTmpRoot() . "log/clone.progress.$module.{$this->post->name}.log\" 2>&1 &";
|
||||
if(PHP_OS == 'WINNT') $cmd = "start /b $cmd";
|
||||
exec($cmd);
|
||||
}
|
||||
$_POST['path'] = $path;
|
||||
}
|
||||
else
|
||||
{
|
||||
dao::$errors['serviceProject'] = $this->lang->repo->error->noCloneAddr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($scm == 'Git')
|
||||
{
|
||||
if(!is_dir($path))
|
||||
{
|
||||
dao::$errors['path'] = sprintf($this->lang->repo->error->noFile, $path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!chdir($path))
|
||||
{
|
||||
if(!is_executable($path))
|
||||
{
|
||||
dao::$errors['path'] = sprintf($this->lang->repo->error->noPriv, $path);
|
||||
return false;
|
||||
}
|
||||
dao::$errors['path'] = $this->lang->repo->error->path;
|
||||
return false;
|
||||
}
|
||||
|
||||
$command = "$client tag 2>&1";
|
||||
exec($command, $output, $result);
|
||||
if($result)
|
||||
{
|
||||
dao::$errors['submit'] = $this->lang->repo->error->connect . "<br />" . sprintf($this->lang->repo->error->output, $command, $result, implode("<br />", $output));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建创建版本库页面数据。
|
||||
* Build form fields for create repo.
|
||||
*
|
||||
* @param int $objectID
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function buildCreateForm(int $objectID): void
|
||||
{
|
||||
$repoID = $this->repo->saveState(0, $objectID);
|
||||
$this->commonAction($repoID, $objectID);
|
||||
|
||||
$this->app->loadLang('action');
|
||||
|
||||
if($this->app->tab == 'project' or $this->app->tab == 'execution')
|
||||
{
|
||||
$products = $this->loadModel('product')->getProductPairsByProject($objectID);
|
||||
}
|
||||
else
|
||||
{
|
||||
$products = $this->loadModel('product')->getPairs('', 0, '', 'all');
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->repo->common . $this->lang->colon . $this->lang->repo->create;
|
||||
$this->view->groups = $this->loadModel('group')->getPairs();
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter|noempty|nodeleted|noclosed');
|
||||
$this->view->products = $products;
|
||||
$this->view->projects = $this->loadModel('product')->getProjectPairsByProductIDList(array_keys($products));
|
||||
$this->view->relatedProjects = ($this->app->tab == 'project' or $this->app->tab == 'execution') ? array($objectID) : array();
|
||||
$this->view->serviceHosts = $this->loadModel('gitlab')->getPairs();
|
||||
$this->view->objectID = $objectID;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* 准备批量创建版本库的数据。
|
||||
* Prepare batch create repo data.
|
||||
*
|
||||
* @access protected
|
||||
* @return array|false
|
||||
*/
|
||||
protected function prepareBatchCreate(): array|false
|
||||
{
|
||||
$data = array();
|
||||
foreach($_POST as $key => $val)
|
||||
{
|
||||
if(strpos($key, 'serviceProject') === 0)
|
||||
{
|
||||
$i = substr($key, 14);
|
||||
if($this->post->{'product' . $i} == '') dao::$errors['product' . $i][] = sprintf($this->lang->error->notempty, $this->lang->repo->product);
|
||||
if($this->post->{'name' . $i} == '') dao::$errors['name' . $i][] = sprintf($this->lang->error->notempty, $this->lang->repo->name);
|
||||
if(dao::isError()) continue;
|
||||
|
||||
$data[] = array('serviceProject' => $this->post->{'serviceProject' . $i}, 'product' => implode(',', $this->post->{'product' . $i}), 'name' => $this->post->{'name' . $i}, 'projects' => empty($_POST['projects'][$i]) ? '' : implode(',', $this->post->projects[$i]));
|
||||
}
|
||||
}
|
||||
if(dao::isError()) return false;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取gitlab还没存在禅道的项目列表。
|
||||
* Get gitlab not exist repos.
|
||||
*
|
||||
* @param object $gitlab
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function getGitlabNotExistRepos(object $gitlab): array
|
||||
{
|
||||
$repoList = array();
|
||||
if(!empty($gitlab))
|
||||
{
|
||||
$repoList = $this->loadModel('gitlab')->apiGetProjects($gitlab->id);
|
||||
$existRepoList = $this->dao->select('serviceProject,name')->from(TABLE_REPO)
|
||||
->where('SCM')->eq(ucfirst($gitlab->type))
|
||||
->andWhere('serviceHost')->eq($gitlab->id)
|
||||
->fetchPairs();
|
||||
foreach($repoList as $key => $repo)
|
||||
{
|
||||
if(isset($existRepoList[$repo->id])) unset($repoList[$key]);
|
||||
}
|
||||
}
|
||||
return $repoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本库文件列表信息。
|
||||
* Get repo files info.
|
||||
*
|
||||
* @param object $repo
|
||||
* @param string $path
|
||||
* @param string $branchID
|
||||
* @param int $refresh
|
||||
* @param string $revision
|
||||
* @param object $lastRevision
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function getFilesInfo(object $repo, string $path, string $branchID, int $refresh, string $revision, object $lastRevision): array
|
||||
{
|
||||
$cacheFile = $this->repo->getCacheFile($repo->id, $path, $branchID);
|
||||
$cacheRefreshTime = isset($lastRevision->time) ? date('Y-m-d H:i', strtotime($lastRevision->time)) : date('Y-m-d H:i');
|
||||
$this->scm->setEngine($repo);
|
||||
if($refresh or !$cacheFile or !file_exists($cacheFile) or filemtime($cacheFile) < strtotime($cacheRefreshTime))
|
||||
{
|
||||
if($repo->SCM == 'Gitlab')
|
||||
{
|
||||
$infos = $this->repo->getFileList($repo, $branchID, $path);
|
||||
}
|
||||
else
|
||||
{
|
||||
$infos = $this->scm->ls($path, $revision);
|
||||
$revisionList = array_column($infos, 'revision', 'revision');
|
||||
$comments = $this->repo->getHistory($repo->id, $revisionList);
|
||||
foreach($infos as $info)
|
||||
{
|
||||
if(isset($comments[$info->revision]))
|
||||
{
|
||||
$comment = $comments[$info->revision];
|
||||
$info->comment = $comment->comment;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($cacheFile) file_put_contents($cacheFile, serialize($infos), LOCK_EX);
|
||||
}
|
||||
else
|
||||
{
|
||||
$infos = unserialize(file_get_contents($cacheFile));
|
||||
}
|
||||
|
||||
foreach($infos as $info)
|
||||
{
|
||||
$info->originalComment = $info->comment;
|
||||
$info->comment = $this->repo->replaceCommentLink($info->comment);
|
||||
}
|
||||
|
||||
return $infos;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分支与tag下拉菜单组件配置。
|
||||
* Get items of branch and tags menu.
|
||||
*
|
||||
* @param object $repo
|
||||
* @param string $branchID
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function getBranchAndTagItems(object $repo, string $branchID): array
|
||||
{
|
||||
/* Set branch or tag for git. */
|
||||
$branches = $tags = array();
|
||||
if(!in_array($repo->SCM, $this->config->repo->gitTypeList)) return array();
|
||||
|
||||
$scm = $this->app->loadClass('scm');
|
||||
$scm->setEngine($repo);
|
||||
$branches = $scm->branch();
|
||||
$initTags = $scm->tags('');
|
||||
foreach($initTags as $tag) $tags[$tag] = $tag;
|
||||
|
||||
$selected = '';
|
||||
$branchMenus = array();
|
||||
$tagMenus = array();
|
||||
foreach($branches as $branchName)
|
||||
{
|
||||
$selected = ($branchName == $branchID) ? $branchName : $selected;
|
||||
$branchMenus[] = array('text' => $branchName, 'id' => $branchName, 'keys' => zget(common::convert2Pinyin(array($branchName)), $branchName, ''), 'url' => 'javascript:;');
|
||||
}
|
||||
foreach($tags as $tagName)
|
||||
{
|
||||
$selected = ($tagName == $branchID) ? $tagName : $selected;
|
||||
$tagMenus[] = array('text' => $tagName, 'id' => $tagName, 'keys' => zget(common::convert2Pinyin(array($tagName)), $tagName, ''), 'url' => 'javascript:;');
|
||||
}
|
||||
|
||||
return array('branchMenus' => $branchMenus, 'tagMenus' => $tagMenus, 'selected' => $selected);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user