Merge branch 'main' into feature/doctemplate

This commit is contained in:
qixinzhi
2024-12-02 07:21:31 +00:00
154 changed files with 1314 additions and 102899 deletions
+2 -2
View File
@@ -29,8 +29,6 @@ clean:
rm -f *.sh
rm -f *.deb *.rpm
common:
curl https://$(GITFOX_HOST)/_artifacts/zentao/raw/zui3/static/blocksuite/$(SUITEVERSION)/blocksuite-$(SUITEVERSION).tar.gz | tar zxf - -C www/js/zui3/editor/
mkdir zentaopms
cp -fr api zentaopms/
cp -fr bin zentaopms/
@@ -44,6 +42,8 @@ common:
cp -fr sdk zentaopms/
cp -fr roadrunner zentaopms/
cp -fr www zentaopms && rm -fr zentaopms/www/data/ && mkdir -p zentaopms/www/data/upload && mkdir zentaopms/www/data/course
if [ ! -d "zentaopms/www/js/zui3/editor" ]; then mkdir -p zentaopms/www/js/zui3/editor; fi
curl https://$(GITFOX_HOST)/_artifacts/zentao/raw/zui3/static/blocksuite/$(SUITEVERSION)/blocksuite-$(SUITEVERSION).tar.gz | tar zxf - -C zentaopms/www/js/zui3/editor/
mkdir zentaopms/tmp
mkdir zentaopms/tmp/cache/
mkdir zentaopms/tmp/duckdb/
+5 -4
View File
@@ -1,8 +1,8 @@
{
"pkg": {
"xuanxuan": {
"gitVersion": "ca19e71757be425f4cd3b29b00d29a49ce99d221",
"version": "9.2"
"gitVersion": "78d92ad400d384dae664112fca03b6c599ce0e5e",
"version": "9.2.1"
},
"zentaoext": {
"gitRepo": "zentao/zentaoext"
@@ -17,7 +17,7 @@
"gitRepo": "ci/zentaoext-downgrade"
},
"blocksuite": {
"version": "0.17.32"
"version": "0.17.33"
}
},
"image": {
@@ -42,7 +42,8 @@
"bucket": "download",
"nexus": {
"release": "easycorp",
"snapshot": "easycorp-snapshot"
"snapshot": "easycorp-snapshot",
"source": "easycorp-source"
}
},
"push_version": "true",
+1 -1
View File
@@ -201,7 +201,7 @@ REPLACE INTO `zt_bug` (`id`, `project`, `product`, `injection`, `identify`, `bra
(3, 2, 1, 0, 0, 0, 4, 3, 0, 4, 1, 7, 0, 0, '成果展示页面问题', '', 3, 1, 'codeerror', '', '', '', '', '<p><span style=\"font-size:13px;font-family:\'Source Han Sans CN\', PingFangSC, \'Microsoft YaHei\', HiraginoSansGB, Roboto, Helvetica, Tahoma, sans-serif;\">[步骤] 进入首页</span></p><p><span style=\"font-size:13px;font-family:\'Source Han Sans CN\', PingFangSC, \'Microsoft YaHei\', HiraginoSansGB, Roboto, Helvetica, Tahoma, sans-serif;\">[结果] 出现乱码</span></p><p><span style=\"font-size:13px;font-family:\'Source Han Sans CN\', PingFangSC, \'Microsoft YaHei\', HiraginoSansGB, Roboto, Helvetica, Tahoma, sans-serif;\">[期望] 正常显示</span></p>', 'active', '', '', 0, 0, NULL, '', '', '', 'admin', '2024-04-02 16:14:38', 'trunk', '', NULL, NULL, '', '', '', NULL, '', NULL, 0, '', 0, 0, 0, 0, 0, 0, NULL, '', '', '', '', '', 0, '', NULL, '0'),
(4, 2, 1, 0, 0, 0, 4, 3, 0, 4, 1, 8, 0, 0, '售后服务页面问题', '', 3, 1, 'codeerror', '', '', '', '', '<p><span style=\"font-size:13px;font-family:\'Source Han Sans CN\', PingFangSC, \'Microsoft YaHei\', HiraginoSansGB, Roboto, Helvetica, Tahoma, sans-serif;\">[步骤] 进入售后服务</span></p><p><span style=\"font-size:13px;font-family:\'Source Han Sans CN\', PingFangSC, \'Microsoft YaHei\', HiraginoSansGB, Roboto, Helvetica, Tahoma, sans-serif;\">[结果]乱码</span></p><p><span style=\"font-size:13px;font-family:\'Source Han Sans CN\', PingFangSC, \'Microsoft YaHei\', HiraginoSansGB, Roboto, Helvetica, Tahoma, sans-serif;\">[期望]正常显示</span></p>', 'resolved', '', '', 1, 0, NULL, '', '', '', 'admin', '2024-04-02 16:15:52', 'trunk', 'admin', '2024-04-02 16:17:48', NULL, 'admin', 'fixed', 'trunk', '2024-04-02 00:00:00', '', NULL, 0, '', 0, 0, 0, 0, 0, 0, NULL, '', '', '', '', '', 0, 'admin', '2024-04-02 16:17:48', '0');
REPLACE INTO `zt_build` (`id`, `project`, `product`, `branch`, `execution`, `builds`, `name`, `system`, `scmPath`, `filePath`, `date`, `stories`, `bugs`, `artifactRepoID`, `builder`, `desc`, `createdBy`, `createdDate`, `deleted`) VALUES
(1, 2, 1, '0', 3, '', '第一期版本', 1, '', '', '2024-04-02', ',4', '', 0, 'admin', '', 'admin', '2024-04-02 16:07:17', '0');
(1, 2, 1, '0', 3, '', '第一期构建', 1, '', '', '2024-04-02', ',4', '', 0, 'admin', '', 'admin', '2024-04-02 16:07:17', '0');
REPLACE INTO `zt_burn` (`execution`, `product`, `task`, `date`, `estimate`, `left`, `consumed`, `storyPoint`) VALUES
(3, 0, 0, '2024-04-02', 35, 35, 19, 2);
REPLACE INTO `zt_case` (`id`, `project`, `product`, `execution`, `branch`, `lib`, `module`, `path`, `story`, `storyVersion`, `title`, `precondition`, `keywords`, `pri`, `type`, `auto`, `frame`, `stage`, `howRun`, `script`, `scriptedBy`, `scriptedDate`, `scriptStatus`, `scriptLocation`, `status`, `subStatus`, `color`, `frequency`, `order`, `openedBy`, `openedDate`, `reviewedBy`, `reviewedDate`, `lastEditedBy`, `lastEditedDate`, `version`, `linkCase`, `fromBug`, `fromCaseID`, `fromCaseVersion`, `deleted`, `lastRunner`, `lastRunDate`, `lastRunResult`, `scene`, `sort`) VALUES
+3 -2
View File
@@ -1158,6 +1158,7 @@ CREATE TABLE `zt_dataview` (
`name` varchar(155) NOT NULL DEFAULT '',
`code` varchar(50) NOT NULL DEFAULT '',
`mode` enum('text','builder') NOT NULL DEFAULT 'builder',
`driver` enum('mysql','duckdb') NOT NULL DEFAULT 'mysql',
`view` varchar(57) NOT NULL DEFAULT '',
`sql` text DEFAULT NULL,
`fields` mediumtext DEFAULT NULL,
@@ -1413,7 +1414,7 @@ CREATE TABLE `zt_doccontent` (
`title` varchar(255) NOT NULL DEFAULT '',
`digest` varchar(255) NOT NULL DEFAULT '',
`content` longtext DEFAULT NULL,
`html` longtext DEFAULT NULL,
`rawContent` longtext DEFAULT NULL,
`files` text DEFAULT NULL,
`type` varchar(10) NOT NULL DEFAULT '',
`version` smallint(6) unsigned NOT NULL DEFAULT 0,
@@ -3618,7 +3619,7 @@ CREATE TABLE `zt_system` (
`product` mediumint(8) unsigned NOT NULL DEFAULT 0,
`integrated` enum('0','1') NOT NULL DEFAULT '0',
`latestRelease` mediumint(8) unsigned NOT NULL DEFAULT 0,
`latestDate` date DEFAULT NULL,
`latestDate` datetime DEFAULT NULL,
`children` varchar(255) NOT NULL DEFAULT '',
`status` enum('active','inactive') NOT NULL DEFAULT 'active',
`desc` mediumtext DEFAULT NULL,
+6 -2
View File
@@ -84,8 +84,8 @@ CREATE INDEX `idx_object` ON `zt_mark`(`objectType`,`objectID`);
CREATE INDEX `idx_account` ON `zt_mark`(`account`);
UPDATE `zt_grouppriv` SET `module` = 'cache', `method` = 'setting' WHERE `module` = 'admin' AND `method` = 'cache';
REPLACE INTO `zt_grouppriv` SELECT `group`, 'cache', 'clear' FROM `zt_grouppriv` WHERE `module` = 'cache' AND `method` = 'setting';
REPLACE INTO `zt_grouppriv` SELECT `group`, 'system', 'create' FROM `zt_grouppriv` WHERE `module` IN ('release', 'projectrelease', 'build', 'projectbuild') AND `method` = 'create';
INSERT INTO `zt_grouppriv` SELECT `group`, 'cache', 'clear' FROM `zt_grouppriv` WHERE `module` = 'cache' AND `method` = 'setting';
INSERT INTO `zt_grouppriv` SELECT DISTINCT `group`, 'system', 'create' FROM `zt_grouppriv` WHERE `module` IN ('release', 'projectrelease', 'build', 'projectbuild') AND `method` = 'create';
UPDATE `zt_pivot` SET `version` = '1';
UPDATE `zt_pivot` SET `builtin` = '1', `createdDate` = '2009-03-14' WHERE `id` >= 1000 AND `id` <= 1028;
@@ -95,3 +95,7 @@ UPDATE `zt_pivotdrill` SET `version` = '1';
DELETE FROM `zt_cron` WHERE `command` = 'moduleName=misc&methodName=cleanCache';
INSERT INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type`, `buildin`, `status`) VALUES ('0', '2', '*', '*', '*', 'moduleName=system&methodName=initSystem', '初始化产品下应用数据', 'zentao', 1, 'normal');
DELETE FROM `zt_object` WHERE `type` = 'taged' AND `deleted` = '1';
ALTER TABLE `zt_doccontent` ADD `rawContent` longtext DEFAULT NULL AFTER `content`;
-1
View File
@@ -1 +0,0 @@
ALTER TABLE `zt_doccontent` ADD `html` longtext DEFAULT NULL AFTER `content`;
+1 -1
View File
@@ -802,7 +802,7 @@ CREATE TABLE IF NOT EXISTS `zt_doccontent` (
`title` varchar(255) NOT NULL DEFAULT '',
`digest` varchar(255) NOT NULL DEFAULT '',
`content` longtext NULL,
`html` longtext DEFAULT NULL,
`rawContent` longtext DEFAULT NULL,
`files` text NULL,
`type` varchar(10) NOT NULL DEFAULT '',
`version` smallint(6) unsigned NOT NULL DEFAULT '0',
@@ -41,7 +41,7 @@ formPanel
set::url('#copyProjectModal'),
set('data-destroyOnHide', true),
set('data-toggle', 'modal'),
set('data-size', 'sm'),
set('data-size', 'md'),
$lang->project->copy
)
),
@@ -17,6 +17,7 @@ class xuanxuanMessage extends messageModel
if($objectType == 'story') $field = 'obj.*,product.name as productName';
if($objectType == 'bug') $field = 'obj.*,project.name as projectName,product.name as productName,execu.name as execuName';
if($objectType == 'feedback') $field = 'obj.*,product.name as productName';
if($objectType == 'demand') $field = 'obj.*,pool.name as poolName';
$object = $this->dao->select($field)->from($this->config->objectTables[$objectType])->alias('obj')
->beginIF($objectType == 'task')
@@ -34,6 +35,9 @@ class xuanxuanMessage extends messageModel
->beginIF($objectType == 'feedback')
->leftJoin($this->config->objectTables['product'])->alias('product')->on('product.id = obj.product')
->fi()
->beginIF($objectType == 'demand')
->leftJoin($this->config->objectTables['demandpool'])->alias('pool')->on('pool.id = obj.pool')
->fi()
->where('obj.id')->eq($objectID)
->fetch();
$field = $this->config->action->objectNameFields[$objectType];
@@ -70,6 +74,21 @@ class xuanxuanMessage extends messageModel
foreach($senderUser as $user) $target .= ',' . $user;
}
}
elseif($objectType == 'demandpool')
{
if(!empty($object->owner)) $target .= trim($object->owner, ',');
if(!empty($object->reviewer)) $target .= ',' . trim($object->reviewer, ',');
}
elseif($objectType == 'demand')
{
$target .= $object->createdBy;
if(!empty($object->assignedTo)) $target .= $object->assignedTo == 'closed' ? '' : $object->assignedTo;
if(!empty($object->mailto)) $target .= ",{$object->mailto}";
$reviewers = $this->loadModel('demand')->getReviewerPairs($object->id, $object->version);
$reviewers = array_keys($reviewers);
if($reviewers) $target .= ',' . implode(',', $reviewers);
$target = trim($target, ',');
}
else
{
if(!empty($object->assignedTo)) $target .= $object->assignedTo == 'closed' ? $object->openedBy : $object->assignedTo;
@@ -126,18 +145,19 @@ class xuanxuanMessage extends messageModel
}
elseif($objectType == 'demandpool')
{
if(!empty($object->owner)) $target .= trim($object->owner, ',');
if(!empty($object->reviewer)) $target .= ',' . trim($object->reviewer, ',');
$subcontent->headTitle = $object->name;
$subcontent->parentType = '';
$subcontent->parent = 0;
$subcontent->parentURL = "xxc:openInApp/zentao-integrated/" . urlencode($server . helper::createLink('demandpool', 'browse', '', 'html'));
$subcontent->cardURL = $url;
}
elseif($objectType == 'demand')
{
$target .= $object->createdBy;
if(!empty($object->assignedTo)) $target .= $object->assignedTo == 'closed' ? '' : $object->assignedTo;
if(!empty($object->mailto)) $target .= ",{$object->mailto}";
$reviewers = $this->loadModel('demand')->getReviewerPairs($object->id, $object->version);
$reviewers = array_keys($reviewers);
if($reviewers) $target .= ',' . implode(',', $reviewers);
$target = trim($target, ',');
$subcontent->headTitle = $object->poolName;
$subcontent->parentType = 'demandpool';
$subcontent->parent = $object->pool;
$subcontent->parentURL = "xxc:openInApp/zentao-integrated/" . urlencode($server . helper::createLink('demand', 'browse', "id=$object->pool", 'html'));
$subcontent->cardURL = $url;
}
else
{
@@ -179,7 +199,7 @@ class xuanxuanMessage extends messageModel
$content = json_encode($contentData);
$avatarUrl = $server . $this->app->getWebRoot() . 'favicon.ico';
if($target && ($objectType == 'bug' || $objectType == 'task' || $objectType == 'story' || $objectType == 'feedback')) $this->loadModel('im')->messageCreateNotify($target, $title, $subtitle = '', $content, $contentType = 'object', $url, $actions = array(), $sender = array('id' => 'zentao', 'realname' => $this->lang->message->sender, 'name' => $this->lang->message->sender, 'avatar' => $avatarUrl));
if($target && ($objectType == 'bug' || $objectType == 'task' || $objectType == 'story' || $objectType == 'feedback' || $objectType == 'demand' || $objectType == 'demandpool')) $this->loadModel('im')->messageCreateNotify($target, $title, $subtitle = '', $content, $contentType = 'object', $url, $actions = array(), $sender = array('id' => 'zentao', 'realname' => $this->lang->message->sender, 'name' => $this->lang->message->sender, 'avatar' => $avatarUrl));
if($objectType == 'mr' and is_array($this->lang->message->mr->$actionType) and !empty($object->assignee))
{
+1 -1
View File
@@ -565,7 +565,7 @@ class baseMao
if(is_string($value)) $value = explode(',', str_replace(' ', '', $value));
if(is_array($value))
{
$rawResult = $this->cache->fetchAll($this->table, $value);
$rawResult = $this->cache->fetchAll($this->table, array_filter($value));
break;
}
}
+5 -1
View File
@@ -653,7 +653,11 @@ class cache
if(empty($objectIdList)) $objectIdList = $allObjectIdList;
$keys = [];
foreach($objectIdList as $objectID) $keys[$objectID] = $this->getRawCacheKey($code, $objectID);
foreach($objectIdList as $objectID)
{
if(!$objectID) continue;
$keys[$objectID] = $this->getRawCacheKey($code, $objectID);
}
$objects = $this->cache->getMultiple(array_values($keys));
+24 -6
View File
@@ -63,11 +63,13 @@ function hasPriv(priv, value)
function isApiLib(lib, docApp)
{
if(docApp && docApp.spaceType === 'api') return true;
if(typeof lib === 'number') lib = getDocApp().getLib(lib);
if(!lib)
{
docApp = docApp || getDocApp();
if(!docApp) return false;
if(docApp.spaceType === 'api') return true;
lib = docApp.lib;
}
return lib && lib.data.type === 'api';
@@ -76,6 +78,7 @@ function isApiLib(lib, docApp)
function isApiDoc(doc)
{
const docApp = getDocApp();
if(docApp && docApp.spaceType === 'api') return true;
if(typeof doc !== 'object' && docApp) doc = docApp.getDoc(doc);
if(doc && doc.api !== undefined) return doc.api;
const id = typeof doc === 'object' ? doc.id : doc;
@@ -243,8 +246,8 @@ function submitNewDoc(doc, spaceID, libID, moduleID, formData)
const url = $.createLink('doc', 'create', `objectType=${spaceType}&objectID=${Math.max(spaceID, 0)}&libID=${libID}&moduleID=${moduleID}`);
const docData =
{
content : doc.content,
html : doc.html,
rawContent : doc.content,
content : doc.html,
status : doc.status || 'normal',
contentType: doc.contentType,
type : 'text',
@@ -319,7 +322,7 @@ function handleSaveDoc(doc)
const moduleID = docApp.signals.moduleID.value;
const url = $.createLink('doc', 'edit', `docID=${doc.id}`);
const docData = {
content : doc.content,
rawContent : doc.content,
status : doc.status || 'normal',
contentType: doc.contentType,
type : 'text',
@@ -328,7 +331,7 @@ function handleSaveDoc(doc)
title : doc.title,
keywords : doc.keywords,
acl : doc.acl,
html : doc.html,
content : doc.html,
space : spaceType,
uid : (doc.uid || `doc${doc.id}`),
};
@@ -370,6 +373,19 @@ function handleSaveDoc(doc)
});
}
/**
* 迁移文档。
* Migrate doc.
*/
function handleMigrateDoc(doc)
{
const url = $.createLink('doc', 'ajaxMigrateDoc', `docID=${doc.id}`);
const docData = {html : doc.html};
return new Promise((resolve) => {
$.post(url, docData, (res) => resolve(!!res));
});
}
/**
* 检查给定的文档是否可以进行移动操作。
* Check if the given doc can be moved.
@@ -547,8 +563,9 @@ const actionsMap =
const canAddModule = canModify && hasPriv('addModule');
/* 获取侧边栏没有模块时的操作按钮。 Get actions when sidebar no module. */
if(canAddModule && info.ui === 'sidebar-no-module')
if(info.ui === 'sidebar-no-module')
{
if(!canAddModule) return;
return [{text: lang.actions.addModule, command: `addModule/${lib.id}/0/${lib.id}/child`, icon: 'plus', type: 'primary-pale'}];
}
@@ -857,7 +874,7 @@ const commands =
{
const docApp = getDocApp();
const libID = args[0] || docApp.libID;
const url = $.createLink('doc', 'editLib', `libID=${libID}`);
const url = $.createLink(isApiLib(libID) ? 'api' : 'doc', 'editLib', `libID=${libID}`);
zui.Modal.open({size: 'sm', url: url});
},
deleteLib: function(_, args)
@@ -1660,6 +1677,7 @@ window.setDocAppOptions = function(_, options)
customRenders : customRenders,
onCreateDoc : userPrivs.create ? handleCreateDoc : null,
onSaveDoc : userPrivs.edit ? handleSaveDoc : null,
onMigrateDoc : userPrivs.edit ? handleMigrateDoc : null,
canMoveDoc : canMoveDoc,
onSwitchView : handleSwitchView,
getActions : getActions,
+1 -1
View File
@@ -104,7 +104,7 @@ class featureBar extends wg
$subItems[] = $subItem;
if($key === $current || ($current == 'bysearch' && $key == $param))
if($key === $current || ($current == 'bysearch' && $key === $param))
{
$isActive = true;
$activeText = $text;
+1
View File
@@ -38,6 +38,7 @@ class filter extends wg
set::items($items),
set::menu($menu),
set::multiple($multiple),
set::toolbar($multiple),
on::change()->do(<<<JS
const hasUrl = () => \$this.zui().\$.props.items.hasOwnProperty('url');
if(hasUrl()) \$this.zui().\$.props.items.data.values = \$this.zui().\$.value;
+5 -2
View File
@@ -9,14 +9,17 @@ class graph extends wg
'responsive?: bool=false',
'width?: number|string="100%"',
'height?: number|string="500"',
'graphID?: number=0',
);
protected function build(): zui
{
list($type, $width, $height, $responsive) = $this->prop(array('type', 'width', 'height', 'responsive'));
list($type, $width, $height, $responsive, $graphID) = $this->prop(array('type', 'width', 'height', 'responsive', 'graphID'));
if(empty($graphID)) $graphID = uniqid();
return zui::graph(
set::_id('zin_graph_' . uniqid()),
set::_id('zin_graph_' . $graphID),
set::type($type),
set::responsive($responsive),
set::_style(array('width' => is_int($width) ? "{$width}px" : $width, 'height' => is_int($height) ? "{$height}px" : $height)),
+20 -7
View File
@@ -33,7 +33,7 @@ class thinkAppeals extends thinkModel
return echarts
(
set::animationDuration(0),
set::width('1000px'),
set::width('1600px'),
set::height('1000px'),
set::color(array('#29AA93', '#FF9F46')),
set::legend(array(array(
@@ -42,17 +42,30 @@ class thinkAppeals extends thinkModel
'itemGap' => 90,
'itemWidth' => 14,
'itemHeight' => 14,
'bottom' => 40,
'textStyle' => array('color' => '#64758B', 'padding' => array(0, 0, 0, 16))
'bottom' => 20,
'textStyle' => array('color' => '#64758B', 'fontSize' => 20, 'padding' => array(0, 0, 0, 16))
))),
set::radar(array('nameGap' => 32, 'indicator' => $this->getIndicator())),
set::radar(array(
'nameGap' => 32,
'splitArea' => array('areaStyle' => array('color' => array('#EAF5FF'))),
'splitLine' => array('lineStyle' => array('color' => '#CFE7FE', 'width' => 3)),
'axisLine' => array('lineStyle' => array('color' => '#CFE7FE', 'width' => 3)),
'axisLabel' => array('color' => '#9EA3B0', 'textStyle' => array('fontSize' => 24)),
'name' => array('textStyle' => array('fontSize' => 24)),
'indicator' => $this->getIndicator()
)),
set::series
(
array(
array(
'type' => 'radar',
'data' => $blocks['seriesData'],
'label' => array('normal' => array('show' => true, 'formatter' => jsRaw('formatSeriesLabel')))
'symbolSize' => 10,
'type' => 'radar',
'data' => $blocks['seriesData'],
'label' => array('normal' => array(
'show' => true,
'formatter' => jsRaw('formatSeriesLabel'),
'textStyle' => array('fontSize' => 24)
))
)
)
)
+3 -3
View File
@@ -2,8 +2,8 @@
.think-form-batch .form-batch-container::-webkit-scrollbar-track {background: var(--color-gray-200);}
.think-form-batch .form-batch-head .form-label {text-overflow: unset; white-space: unset; font-weight: 400; position: static; padding: 0;}
.think-form-batch .form-batch-table>*>tr>* {padding-top: calc(var(--space)); padding-bottom: calc(var(--space));}
.think-form-batch .form-batch-col-actions {padding: 0.5rem 0 !important;}
.think-form-batch .form-batch-head[data-name="ACTIONS"], .think-form-batch .form-batch-row-actions {width: 3.325rem; position: sticky; right: 0; background: var(--color-canvas);}
.think-form-batch td[data-name="ACTIONS"] {padding: 0.5rem 0 !important;}
.think-form-batch .form-batch-head[data-name="ACTIONS"], .think-form-batch td[data-name="ACTIONS"] {width: 3.325rem; position: sticky; right: 0; background: var(--color-canvas);}
.think-form-batch .form-batch-head[data-name="ACTIONS"] .form-label {display: none;}
.think-form-batch .form-batch-col-actions .btn {color: var(--color-primary-500);}
.think-form-batch td[data-name="ACTIONS"] .btn {color: var(--color-primary-500);}
.think-form-batch .form-control[disabled] {background-color: rgba(var(--color-gray-100-rgb),var(--tw-bg-opacity)); --tw-bg-opacity: .4; color:rgba(var(--color-gray-700-rgb),var(--tw-bg-opacity))}
+13 -9
View File
@@ -15,16 +15,20 @@ window.changeRows = function()
window.renderRowData = function()
{
$(modeClass + ' .think-form-batch .form-batch-col-actions .btn[data-type="add"]').prop({
disabled: ($(modeClass + ' .think-form-batch tbody tr').length >= canAddRowsOfMulticol || disabled),
title: $(modeClass + ' .think-form-batch tbody tr').length >= canAddRowsOfMulticol ? addRowsTips.replace('%s', canAddRowsOfMulticol) : addLang,
});
$(modeClass + ' .think-form-batch .form-batch-col-actions .btn[data-type="delete"]').prop({
disabled: disabled,
})
const modeClass = $('.think-form-batch').data('modeClass');
if(modeClass != undefined)
{
$(modeClass + ' .think-form-batch td[data-name="ACTIONS"] .btn[data-type="add"]').prop({
disabled: ($(modeClass + ' .think-form-batch tbody tr').length >= canAddRowsOfMulticol || disabled),
title: $(modeClass + ' .think-form-batch tbody tr').length >= canAddRowsOfMulticol ? addRowsTips.replace('%s', canAddRowsOfMulticol) : addLang,
});
$(modeClass + ' .think-form-batch td[data-name="ACTIONS"] .btn[data-type="delete"]').prop({
disabled: disabled,
})
}
}
$(document).on('click', '.form-batch-col-actions .btn', function()
$(document).on('click', 'td[data-name="ACTIONS"] .btn', function()
{
renderRowData();
if($(this).data('type') == 'add') $(this).closest('tr').next().find('td:first-child .form-control')[0].focus();
@@ -161,4 +165,4 @@ window.changeMulticolumnSetOption = function(target)
$('.text-danger').remove();
$('.has-error').removeClass('has-error');
$('.required-tip button').toggleClass('hidden', target.value == 0);
}
}
+1 -1
View File
@@ -94,7 +94,6 @@ class thinkMulticolumn extends thinkQuestion
jsVar('addRowsTips', $lang->thinkrun->tips->addRow);
jsVar('addLang', $lang->thinkrun->add);
jsVar('disabled', $runDisabled || $preViewDisabled);
jsVar('modeClass', !empty($modeClass) ? '.' . $modeClass : '');
$fields = array_values((array)$fields);
$batchItems = array();
@@ -113,6 +112,7 @@ class thinkMulticolumn extends thinkQuestion
set::onRenderRow(jsRaw('renderRowData')),
$isRun ? formHidden('status', '') : null,
set::data($result),
setData('modeClass', !empty($modeClass) ? '.' . $modeClass : ''),
$batchItems
);
return $detailWg;
+1 -1
View File
@@ -4,4 +4,4 @@
.score-content .check-items .item-control{border-color:rgba(var(--color-primary-100-rgb),var(--tw-border-opacity));}
.score-content .check-items .item-control:hover{background: rgba(var(--color-primary-100-rgb),var(--tw-bg-opacity));}
.score-content .check-items .item-control .radio-primary{display: none;}
.score-content .check-items .item-control.is-checked{background: rgba(var(--color-primary-500-rgb),var(--tw-bg-opacity)); color: rgba(var(--color-white-rgb),var(--tw-text-opacity));}
.score-content .check-items .item-control.is-checked{background: rgba(var(--color-primary-500-rgb),var(--tw-bg-opacity)); color: rgba(var(--color-white-rgb),var(--tw-text-opacity)); border-color: rgba(var(--color-primary-500-rgb),var(--tw-bg-opacity));}
+12 -9
View File
@@ -122,6 +122,12 @@ class thinkStepBase extends wg
$sourceQuestion = array();
$sourceItems = array();
$wizard->config = !empty($wizard->config) ? $wizard->config : array();
$wizard->config = is_string($wizard->config) ? json_decode($wizard->config, true) : $wizard->config;
$configureObjects = !empty($wizard->config['configureObjects']) ? json_decode($wizard->config['configureObjects'], true) : array();
$isAssignedObject = !empty($configureObjects['isAssignedObject']) ? $configureObjects['isAssignedObject'] : 0;
$showBuiltTip = isset($step->options->canConfigureRatio) && $step->options->canConfigureRatio == 0;
if(!empty($quotedQuestions))
{
foreach($quotedQuestions as $item)
@@ -161,12 +167,13 @@ class thinkStepBase extends wg
);
}
}
$runSourceTip = !empty($sourceQuestion) && !$preViewModel;
if($isRun && (!empty($quotedQuestions) || !empty($sourceQuestion)))
if($isRun && (!empty($quotedQuestions) || $runSourceTip))
{
$tipType = $lang->thinkstep->label->option;
$sourceQuestionTip = array();
if(!empty($sourceQuestion))
if($runSourceTip)
{
foreach ($sourceQuestion as $sourceQuestionItem)
{
@@ -180,11 +187,11 @@ class thinkStepBase extends wg
);
}
}
$showRunTips = (!empty($quotedQuestions) || !empty($sourceQuestion)) && !$preViewModel;
$showRunTips = ((!empty($quotedQuestions) && empty($isAssignedObject)) || !empty($sourceQuestion));
$detailTip[] = $showRunTips ? div
(
setClass('bg-primary-50 text-gray p-2 mt-3 leading-normal'),
!empty($quotedQuestions) ? div
(!empty($quotedQuestions) && empty($isAssignedObject)) ? div
(
setClass('flex items-center'),
icon(setClass('font text-warning mr-1'), 'about'),
@@ -220,11 +227,7 @@ class thinkStepBase extends wg
}
if($preViewModel)
{
$wizard->config = !empty($wizard->config) ? $wizard->config : array();
$wizard->config = is_string($wizard->config) ? json_decode($wizard->config, true) : $wizard->config;
$configureObjects = !empty($wizard->config['configureObjects']) ? json_decode($wizard->config['configureObjects'], true) : array();
$isAssignedObject = !empty($configureObjects['isAssignedObject']) ? $configureObjects['isAssignedObject'] : 0;
$detailTip[] = (!empty($quotedQuestions) && !empty($isAssignedObject)) ? div
$detailTip[] = ((!empty($quotedQuestions) && !empty($isAssignedObject)) || $showBuiltTip)? div
(
setClass('flex text-gray-400 mt-2 items-center text-sm ml-2'),
icon(setClass('text-important mr-2'), 'about'),
+18 -1
View File
@@ -53,6 +53,7 @@ class thinkStepMenu extends wg
private function buildMenuTree(array $items, int $parentID = 0): array
{
global $config;
if(empty($items)) $items = $this->modules;
if(empty($items)) return array();
@@ -60,7 +61,13 @@ class thinkStepMenu extends wg
$toggleNonNodeShow = $this->prop('toggleNonNodeShow');
$hidden = $this->prop('hidden');
$sortTree = $this->prop('sortable') || $this->prop('onSort');
$wizard = $this->prop('wizard');
$hiddenModelType = in_array($wizard->model, $config->thinkwizard->hiddenMenuModel);
$parentItems = array();
$questionItems = array();
if($hiddenModelType) $questionItems = array_values($items);
foreach($items as $setting)
{
if(!is_object($setting)) continue;
@@ -73,8 +80,18 @@ class thinkStepMenu extends wg
$quotedText = $this->getQuotedText($this->modules, $quotedTitle);
}
$itemQuestionIndex = 0;
foreach ($questionItems as $index => $questionItem)
{
if($questionItem->id == $setting->id) $itemQuestionIndex = $index;
}
if(!empty($itemQuestionIndex) && $hiddenModelType) $preStep = $questionItems[$itemQuestionIndex - 1];
$canView = common::hasPriv('thinkstep', 'view');
$unClickable = $toggleNonNodeShow && $setting->id != $activeKey && $setting->type != 'node' && json_decode($setting->answer) == null;
$hiddenStep = $unClickable || (!empty($preStep) && empty($preStep->answer));
$item = array(
'key' => $setting->id,
'text' => (isset($setting->index) ? ($setting->index . '. ') : '') . $setting->title,
@@ -90,7 +107,7 @@ class thinkStepMenu extends wg
'disabled' => $unClickable,
'actions' => $this->prop('showAction') ? $this->getActions($setting) : null,
'data-wizard' => $setting->wizard,
'class' => $unClickable && $hidden ? 'hidden': ''
'class' => $hiddenStep && $hidden ? 'hidden' : ''
);
if($sortTree) $item['trailingIcon'] = 'move muted cursor-move';
+1 -1
View File
@@ -1,3 +1,3 @@
.form-horz .form-group {align-items: center;}
.result-width {width: calc(100% - 148px);}
.form-control[disabled] {background-color: rgba(var(--color-gray-100-rgb),var(--tw-bg-opacity)); --tw-bg-opacity: .4; color:rgba(var(--color-gray-700-rgb),var(--tw-bg-opacity))}
.form-control[readonly] {cursor: not-allowed; background-color: rgba(var(--color-gray-100-rgb),var(--tw-bg-opacity)); --tw-bg-opacity: .4; color:rgba(var(--color-gray-700-rgb),var(--tw-bg-opacity))}
+46 -44
View File
@@ -57,56 +57,58 @@ class thinkTableInput extends thinkQuestion
foreach($fields as $item)
{
$value = !empty($result) && isset($result[$index]) ? $result[$index] : '';
$tableInputItems[] = formGroup
(
setClass('flex items-center'),
div
$tableInputItems[] = array(
formGroup
(
setClass('flex items-center'),
div
(
setClass('text-right mr-2 w-24 line-clamp-2'),
$item,
set::title($item)
),
div
(
set::title($value),
setClass(empty($inputType) ? 'result-width' : '', $index == 0 ? '' : 'mt-2'),
empty($inputType) ? textarea
(
set::rows('2'),
set::name('result[' . $index . ']'),
set::value($value),
set::placeholder($lang->thinkrun->pleaseInput)
) : inputControl
(
input(set(array(
'class' => 'w-72 h-10 dimension-weight',
'name' => 'result[' . $index . ']',
'type' => 'number',
'min' => 1,
'max' => 100,
'value' => $value,
'disabled' => ($value && !$canConfigureRatio ),
'placeholder' => $lang->thinkrun->pleaseInput
)),
on::input('changePercentInput')
),
to::suffix($lang->thinkwizard->dimension->percentageSign),
set::suffixWidth(32)
),
),
div
(
setClass('flex'),
setStyle(array('min-width' => '40px')),
($index == count($fields) - 1 && $supportAdd) ? icon
div
(
'plus',
setClass('mr-1 btn-add ml-2 text-sm text-primary add-rows cursor-pointer', $disabledAdd ? 'disabled' : ''),
setData('canAddRows', $canAddRows),
setData('fieldsCount', count($fields)),
set::title(sprintf($lang->thinkrun->tips->add, $canAddRows)),
) : null,
)
set::title($value),
setClass(empty($inputType) ? 'result-width' : '', $index == 0 ? '' : 'mt-2'),
empty($inputType) ? textarea
(
set::rows('2'),
set::name('result[' . $index . ']'),
set::value($value),
set::placeholder($lang->thinkrun->pleaseInput)
) : inputControl
(
input(set(array(
'class' => 'w-72 h-10 dimension-weight',
'name' => 'result[' . $index . ']',
'type' => 'number',
'min' => 1,
'max' => 100,
'value' => $value,
'readonly' => ($value && !$canConfigureRatio),
'placeholder' => $lang->thinkrun->pleaseInput
)),
on::input('changePercentInput')
),
to::suffix($lang->thinkwizard->dimension->percentageSign),
set::suffixWidth(32)
),
),
div
(
setClass('flex'),
setStyle(array('min-width' => '40px')),
($index == count($fields) - 1 && $supportAdd) ? icon
(
'plus',
setClass('mr-1 btn-add ml-2 text-sm text-primary add-rows cursor-pointer', $disabledAdd ? 'disabled' : ''),
setData('canAddRows', $canAddRows),
setData('fieldsCount', count($fields)),
set::title(sprintf($lang->thinkrun->tips->add, $canAddRows)),
) : null,
)
),
);
$index ++;
}
+2 -2
View File
@@ -1,5 +1,5 @@
library 'z-common@main'
library 'z-zentaopms@feat-241030'
library 'z-common@feat-241129'
library 'z-zentaopms@feat-241129'
pipeline {
agent {
+2
View File
@@ -129,3 +129,5 @@ $config->action->multipleObjectFields['testtask']['type'] = 'typeList';
$config->action->approvalFields['reviewStatus'] = 'reviewStatusList';
$config->action->approvalFields['reviewResult'] = 'reviewResultList';
$config->action->hiddenTrashObjects = 'object,cm';
+2 -1
View File
@@ -189,6 +189,7 @@ $lang->action->objectTypes['projectbuild'] = 'Build';
$lang->action->objectTypes['board'] = 'Board';
$lang->action->objectTypes['boardspace'] = 'Board Space';
$lang->action->objectTypes['productline'] = 'Product Line';
$lang->action->objectTypes['system'] = $lang->product->system;
/* Used to describe operation history. */
$lang->action->desc = new stdclass();
@@ -562,7 +563,7 @@ $lang->action->label->createbackup = 'Created system backup';
$lang->action->label->deletebackup = 'Deleted system backup';
$lang->action->label->restorebackup = 'Restored system backup';
$lang->action->label->upgradesystem = 'Executed system upgrade';
$lang->action->label->system = 'Application';
$lang->action->label->system = $lang->product->system;
$lang->action->label->manualbackup = 'Manual backup';
$lang->action->label->autobackup = 'Automatic backup';
$lang->action->label->openautobackup = 'Enable automatic backup';
+2 -1
View File
@@ -189,6 +189,7 @@ $lang->action->objectTypes['projectbuild'] = 'Build';
$lang->action->objectTypes['board'] = 'Board';
$lang->action->objectTypes['boardspace'] = 'Board Space';
$lang->action->objectTypes['productline'] = 'Product Line';
$lang->action->objectTypes['system'] = $lang->product->system;
/* Used to describe operation history. */
$lang->action->desc = new stdclass();
@@ -562,7 +563,7 @@ $lang->action->label->createbackup = 'Created system backup';
$lang->action->label->deletebackup = 'Deleted system backup';
$lang->action->label->restorebackup = 'Restored system backup';
$lang->action->label->upgradesystem = 'Executed system upgrade';
$lang->action->label->system = 'Application';
$lang->action->label->system = $lang->product->system;
$lang->action->label->manualbackup = 'Manual backup';
$lang->action->label->autobackup = 'Automatic backup';
$lang->action->label->openautobackup = 'Enable automatic backup';
+2 -1
View File
@@ -189,6 +189,7 @@ $lang->action->objectTypes['projectbuild'] = 'Build';
$lang->action->objectTypes['board'] = 'Board';
$lang->action->objectTypes['boardspace'] = 'Board Space';
$lang->action->objectTypes['productline'] = 'Product Line';
$lang->action->objectTypes['system'] = $lang->product->system;
/* Used to describe operation history. */
$lang->action->desc = new stdclass();
@@ -562,7 +563,7 @@ $lang->action->label->createbackup = 'Created system backup';
$lang->action->label->deletebackup = 'Deleted system backup';
$lang->action->label->restorebackup = 'Restored system backup';
$lang->action->label->upgradesystem = 'Executed system upgrade';
$lang->action->label->system = 'Application';
$lang->action->label->system = $lang->product->system;
$lang->action->label->manualbackup = 'Manual backup';
$lang->action->label->autobackup = 'Automatic backup';
$lang->action->label->openautobackup = 'Enable automatic backup';
+2 -2
View File
@@ -189,7 +189,7 @@ $lang->action->objectTypes['projectbuild'] = '构建';
$lang->action->objectTypes['board'] = '白板';
$lang->action->objectTypes['boardspace'] = '白板空间';
$lang->action->objectTypes['productline'] = '产品线';
$lang->action->objectTypes['system'] = '应用';
$lang->action->objectTypes['system'] = $lang->product->system;
/* 用来描述操作历史记录。*/
$lang->action->desc = new stdclass();
@@ -563,7 +563,7 @@ $lang->action->label->createbackup = '创建了系统备份';
$lang->action->label->deletebackup = '删除了系统备份';
$lang->action->label->restorebackup = '还原了系统备份';
$lang->action->label->upgradesystem = '执行了系统升级';
$lang->action->label->system = '应用';
$lang->action->label->system = $lang->product->system;
$lang->action->label->manualbackup = '手动备份了';
$lang->action->label->autobackup = '自动备份了';
$lang->action->label->openautobackup = '开启自动备份';
+8 -1
View File
@@ -404,6 +404,7 @@ class actionModel extends model
->orWhere('(objectType')->eq('execution')->andWhere('objectID')->notIn($noMultipleExecutions)
->markRight(2)
->fi()
->andWhere('objectType')->notIn($this->config->action->hiddenTrashObjects)
->andWhere('extra')->eq($extra)
->andWhere('vision')->eq($this->config->vision)
->orderBy($orderBy)
@@ -511,6 +512,7 @@ class actionModel extends model
->andWhere($trashQuery)
->andWhere('t1.extra')->eq($extra)
->andWhere('t1.vision')->eq($this->config->vision)
->andWhere('objectType')->notIn($this->config->action->hiddenTrashObjects)
->beginIF($objectType != 'pipeline' && $objectType != 'all')->andWhere('t1.objectType')->eq($objectType)->fi()
->beginIF($objectType == 'pipeline')
@@ -1103,7 +1105,7 @@ class actionModel extends model
$shadowProducts = $this->dao->select('id')->from(TABLE_PRODUCT)->where('shadow')->eq(1)->fetchPairs();
$projectMultiples = $this->dao->select('id,type,multiple')->from(TABLE_PROJECT)->where('id')->in($projectIdList)->fetchAll('id');
$docList = $this->loadModel('doc')->getPrivDocs(array(), 0, 'all');
$apiList = $this->loadModel('api')->getPrivApis();
$apiList = $this->loadModel('api')->getPrivApis('all');
$docLibList = $this->doc->getLibs('hasApi');
foreach($actions as $i => $action)
{
@@ -1501,6 +1503,11 @@ class actionModel extends model
}
if($action->objectType == 'demand' && !empty($object->parent)) $this->loadModel('demand')->updateParentDemandStage($object->parent);
if($action->objectType == 'release') $this->loadModel('system')->setSystemRelease((int)$object->system, $action->objectID);
if(in_array($action->objectType, array('release', 'build')) && !empty($object->system))
{
$systemActionID = $this->dao->select('id')->from(TABLE_ACTION)->where('objectType')->eq('system')->andWhere('objectID')->eq($object->system)->andWhere('action')->eq('deleted')->orderBy('id_desc')->fetch('id');
if($systemActionID) $this->undelete($systemActionID);
}
/* 在action表中更新action记录。 */
/* Update action record in action table. */
+1 -1
View File
@@ -86,7 +86,7 @@ $lang->admin->menuList->model['menuOrder']['15'] = 'waterfall';
$lang->admin->menuList->model['menuOrder']['20'] = 'agileplus';
$lang->admin->menuList->model['menuOrder']['25'] = 'waterfallplus';
$lang->admin->menuList->model['tabMenu']['common']['project'] = array('link' => "{$lang->project->common}|custom|required|module=project", 'alias' => 'set,project', 'links' => array('custom|set|module=project&field=unitList'));
$lang->admin->menuList->model['tabMenu']['common']['project'] = array('link' => "{$lang->project->common}|custom|required|module=project", 'alias' => 'set,project', 'exclude' => 'custom-required', 'links' => array('custom|set|module=project&field=unitList'));
if(helper::hasFeature('waterfall') or helper::hasFeature('waterfallplus')) $lang->admin->menuList->model['tabMenu']['common']['stage'] = array('link' => "{$lang->stage->type}|stage|settype|", 'subModule' => 'stage');
$lang->admin->menuList->model['tabMenu']['common']['build'] = array('link' => "{$lang->build->common}|custom|required|module=build", 'alias' => 'set', 'exclude' => 'custom');
$lang->admin->menuList->model['tabMenu']['common']['flow'] = array('link' => "{$lang->custom->flow}|custom|flow|", 'divider' => true);
+2
View File
@@ -75,6 +75,8 @@ $config->api->dtable->release->fieldList['addedDate']['type'] = 'date';
$config->api->dtable->release->fieldList['actions']['name'] = 'actions';
$config->api->dtable->release->fieldList['actions']['title'] = $lang->actions;
$config->api->dtable->release->fieldList['actions']['width'] = '70px';
$config->api->dtable->release->fieldList['actions']['align'] = 'center';
$config->api->dtable->release->fieldList['actions']['type'] = 'actions';
$config->api->dtable->release->fieldList['actions']['menu'] = array('deleteRelease');
$config->api->dtable->release->fieldList['actions']['list']['deleteRelease']['icon'] = 'trash';
+4 -2
View File
@@ -159,8 +159,9 @@ class api extends control
{
if(!isset($programs[$product->program])) continue;
$program = $programs[$product->program];
$program->products[] = $product;
$product->apiCount = isset($productsCount[$product->id]) ? $productsCount[$product->id] : 0;
if($notempty && $product->apiCount == 0) continue;
$program->products[] = $product;
$program->apiCount = isset($program->apiCount) ? $program->apiCount + $product->apiCount : $product->apiCount;
}
}
@@ -172,9 +173,10 @@ class api extends control
$topParent = $project->parent ? explode(',', trim($project->path, ','))[0] : 0;
if(!isset($programs[$topParent])) continue;
$program = $programs[$topParent];
$program->projects[] = $project;
$project->apiCount = isset($projectsCount[$project->id]) ? $projectsCount[$project->id] : 0;
if($notempty && $project->apiCount == 0) continue;
$program->apiCount = isset($program->apiCount) ? $program->apiCount + $project->apiCount : $project->apiCount;
$program->projects[] = $project;
}
}
+5
View File
@@ -1,2 +1,7 @@
.table-empty-tip {padding: 80px 10px; text-align: center; background: #fff;}
.table-empty-tip .btn-group .btn {background-color: rgba(var(--color-primary-50-rgb),var(--tw-bg-opacity)); color: var(--nav-active-color); --tw-ring-color: rgba(var(--color-primary-50-rgb),var(--tw-bg-opacity));}
.picker-menu .menu-item.is-nested > .item-inner .item-content .item-title {flex-grow: 0!important; opacity: .6;}
.picker-menu .menu-item.is-nested > .item-inner .item-content .item-subtitle {--skin-pale-rgb: var(--color-gray-500-rgb); height: 1rem; min-width: 1rem; border-radius: var(--radius-full); --skin-color: rgba(var(--skin-pale-rgb), .1); --skin-text: rgba(var(--skin-pale-rgb), 1); --state-color: rgba(var(--skin-pale-rgb), .1); --skin-bg: var(--skin-color); --skin-ring: var(--skin-color); --skin-border: var(--skin-color); --skin-hover-text: var(--skin-text); --skin-hover-bg: var(--skin-bg); --tw-ring-color: var(--skin-ring); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); --color-link-hover: var(--skin-text); background-color: var(--skin-bg); border-color: var(--skin-border); box-shadow: var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000); color: var(--skin-text); display: inline-flex; font-size: .75rem; align-items: center; justify-content: center; line-height: 1rem; padding-left: .25rem; padding-right: .25rem;}
.picker-menu .menu-item.is-nested > .item-inner {background-color: inherit!important; color: inherit!important; cursor: default;}
.picker-menu .menu-item.is-nested > .item-inner::before {display: none;}
+1
View File
@@ -0,0 +1 @@
.dropmenu-nav .nav-item {white-space: nowrap;}
+3 -1
View File
@@ -228,8 +228,10 @@ function getSpaceMenuText(text, state)
function getSpaceMenuOptions(spaceType, spaceID)
{
const libID = this.libID;
const lang = $('html').attr('lang');
return {
popWidth : 350,
popWidth : ['zh-cn', 'zh-tw'].includes(lang) ? 350 : 400,
onClickItem : handleClickSpaceMenu,
defaultValue: spaceID === 'nolink' ? `lib.${libID}`: spaceID,
display : getSpaceMenuText.bind(this)
+3 -3
View File
@@ -188,9 +188,9 @@ $lang->api->requestTypeOptions['application/x-www-form-urlencoded'] = 'applicati
$lang->api->requestTypeOptions['multipart/form-data'] = 'multipart/form-data';
$lang->api->libTypeList = array();
$lang->api->libTypeList['product'] = $lang->productCommon . ' Api Library';
$lang->api->libTypeList['project'] = $lang->projectCommon . ' Api Library';
$lang->api->libTypeList['nolink'] = 'Independent Api Library';
$lang->api->libTypeList['product'] = $lang->productCommon . ' API';
$lang->api->libTypeList['project'] = $lang->projectCommon . ' API';
$lang->api->libTypeList['nolink'] = 'Independent API';
$lang->api->statusOptions = array(
'done' => 'Done',
+3 -3
View File
@@ -188,9 +188,9 @@ $lang->api->requestTypeOptions['application/x-www-form-urlencoded'] = 'applicati
$lang->api->requestTypeOptions['multipart/form-data'] = 'multipart/form-data';
$lang->api->libTypeList = array();
$lang->api->libTypeList['product'] = $lang->productCommon . ' Api Library';
$lang->api->libTypeList['project'] = $lang->projectCommon . ' Api Library';
$lang->api->libTypeList['nolink'] = 'Independent Api Library';
$lang->api->libTypeList['product'] = $lang->productCommon . ' API';
$lang->api->libTypeList['project'] = $lang->projectCommon . ' API';
$lang->api->libTypeList['nolink'] = 'Independent API';
$lang->api->statusOptions = array(
'done' => 'Done',
+1 -1
View File
@@ -137,7 +137,7 @@ if($config->inQuickon)
if($this->config->inQuickon)
{
$data = null;
$data = array();
if(!empty($backups)) $data = initTableData($backups, $config->system->dtable->backup->fieldList, $this->system);
foreach($data as &$backup)
+1 -1
View File
@@ -901,7 +901,7 @@ class biModel extends model
/* 如果是升级模式,那么需要采用当前时间,确保用户可以看到“新”标签。*/
$pivotSpec->createdDate = $isInstall ? $createdDate : helper::now();
$pivotSpecStmt = $this->dao->insert(TABLE_PIVOTSPEC)->data($pivotSpec);
$pivotSpecSQLs[] = $pivotSpecStmt->get();
$pivotSQLs[] = $pivotSpecStmt->get();
}
}
+2 -2
View File
@@ -770,6 +770,7 @@ class bugZen extends bug
/* Get story and task id list. */
$storyIdList = $taskIdList = array();
if($this->config->edition == 'max') $identifyList = $this->loadModel('review')->getPairs(0, 0, true);
if($this->config->edition != 'open') $bugRelatedObjectList = $this->custom->getRelatedObjectList(array_keys($bugs), 'bug', 'byRelation', true);
foreach($bugs as $bug)
{
if($bug->story) $storyIdList[$bug->story] = $bug->story;
@@ -781,8 +782,7 @@ class bugZen extends bug
$bug->injection = zget($identifyList, $bug->injection, '');
$bug->identify = zget($identifyList, $bug->identify, '');
}
if($this->config->edition != 'open') $bug->relatedObject = $this->custom->getRelatedObjectList($bug->id, 'bug', 'byRelation', true);
if($this->config->edition != 'open') $bug->relatedObject = zget($bugRelatedObjectList, $bug->id, 0);
}
$showModule = !empty($this->config->bug->browse->showModule) ? $this->config->bug->browse->showModule : '';
+2
View File
@@ -12,6 +12,7 @@ $config->build->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools')
global $lang, $app;
$config->build->search['module'] = 'build';
$config->build->search['fields']['name'] = $lang->build->nameAB;
$config->build->search['fields']['system'] = $lang->build->system;
$config->build->search['fields']['id'] = $lang->build->id;
$config->build->search['fields']['product'] = $lang->build->product;
$config->build->search['fields']['scmPath'] = $lang->build->scmPath;
@@ -21,6 +22,7 @@ $config->build->search['fields']['builder'] = $lang->build->builder;
$config->build->search['fields']['desc'] = $lang->build->desc;
$config->build->search['params']['name'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
$config->build->search['params']['system'] = array('operator' => '=', 'control' => 'select', 'values' => array());
$config->build->search['params']['product'] = array('operator' => '=', 'control' => 'select', 'values' => 'products');
$config->build->search['params']['scmPath'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
$config->build->search['params']['filePath'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
-1
View File
@@ -35,7 +35,6 @@ window.loadSystem = function(productID)
{
productID = parseInt(productID);
if(!productID) productID = $('input[name=product]').val();
if(typeof(productID) == "undefined") return;
$.get($.createLink('build', 'ajaxGetSystemList', 'productID=' + productID), function(data)
{
+9 -4
View File
@@ -10,8 +10,8 @@ $().ready(function()
$(document).off('change', '[name=product], [name^=branch]').on('change', '[name=product], [name^=branch]', function()
{
let projectID = $('input[name=project]').val();
let productID = $('input[name=product]').val();
let systemID = $('input[name=system]').val();
let productID = $('#createBuildForm input[name=product]').val();
let systemID = $('input[name=system]').val();
$.get($.createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=builds&build=&branch=all&&needCreate=&type=noempty,notrunk,separate,singled&systemID=' + systemID), function(data)
{
if(data)
@@ -30,7 +30,10 @@ $().ready(function()
{
$('#branch').prev('.form-label').html(data.branchName);
}, 'json');
loadSystem(productID);
}
});
$(document).on('change', 'input[name=isIntegrated]', function()
@@ -67,7 +70,6 @@ $().ready(function()
}
});
loadBranches();
loadSystem();
if(multipleProject)
{
window.waitDom('[name=execution]', function()
@@ -75,6 +77,10 @@ $().ready(function()
loadProducts();
})
}
if(hidden == 'hide')
{
loadSystem(currentProduct);
}
});
/**
@@ -115,7 +121,6 @@ function loadProducts(executionID)
});
loadLastBuild();
loadSystem();
}
/**
+2 -2
View File
@@ -22,8 +22,8 @@ $lang->build->batchUnlinkStory = "Batch {$lang->SRCommon} Unlink";
$lang->build->batchUnlinkBug = 'Batch Bug Unlink';
$lang->build->viewBug = 'Bugs';
$lang->build->bugList = 'Bug List';
$lang->build->system = 'Application';
$lang->build->addSystem = 'Add Application';
$lang->build->system = $lang->product->system;
$lang->build->addSystem = 'Add ' . $lang->product->system;
$lang->build->confirmDelete = "Möchten Sie dieses Build löschen?";
$lang->build->confirmUnlinkStory = "Möchten Sie diese {$lang->SRCommon} löschen?";
+2 -2
View File
@@ -22,8 +22,8 @@ $lang->build->batchUnlinkStory = "Batch Unlink {$lang->SRCommon}";
$lang->build->batchUnlinkBug = 'Batch Unlink Bugs';
$lang->build->viewBug = 'Bugs';
$lang->build->bugList = 'Bug List';
$lang->build->system = 'Application';
$lang->build->addSystem = 'Add Application';
$lang->build->system = $lang->product->system;
$lang->build->addSystem = 'Add ' . $lang->product->system;
$lang->build->confirmDelete = "Do you want to delete this build?";
$lang->build->confirmUnlinkStory = "Do you want to unlink this {$lang->SRCommon}?";
+2 -2
View File
@@ -22,8 +22,8 @@ $lang->build->batchUnlinkStory = "Retirer {$lang->SRCommon} par Lot";
$lang->build->batchUnlinkBug = 'Retirer Bugs par Lot';
$lang->build->viewBug = 'Bugs';
$lang->build->bugList = 'Bug List';
$lang->build->system = 'Application';
$lang->build->addSystem = 'Ajouter Application';
$lang->build->system = $lang->product->system;
$lang->build->addSystem = 'Add ' . $lang->product->system;
$lang->build->confirmDelete = "Voulez-vous supprimer ce build ?";
$lang->build->confirmUnlinkStory = "Voulez-vous retirer cette {$lang->SRCommon} du Build ?";
+2 -2
View File
@@ -22,8 +22,8 @@ $lang->build->batchUnlinkStory = "批量移除{$lang->SRCommon}";
$lang->build->batchUnlinkBug = '批量移除Bug';
$lang->build->viewBug = '查看Bug';
$lang->build->bugList = 'Bug列表';
$lang->build->system = '所属应用';
$lang->build->addSystem = '新建应用';
$lang->build->system = '所属' . $lang->product->system;
$lang->build->addSystem = '新建' . $lang->product->system;
$lang->build->confirmDelete = "您确认删除该构建吗?";
$lang->build->confirmUnlinkStory = "您确认移除该{$lang->SRCommon}吗?";
+3
View File
@@ -18,6 +18,8 @@ jsVar('projectID', $projectID);
jsVar('executionID', $executionID);
jsVar('today', helper::today());
jsVar('projectModel', isset($project->model) ? $project->model : '');
jsVar('currentProduct', $productID);
jsVar('hidden', $hidden);
$integratedRow = '';
if($app->tab == 'project' && !empty($multipleProject))
@@ -108,6 +110,7 @@ $productBranches = zget($product, 'branches', array());
formPanel
(
set::title($lang->build->create),
set::formID('createBuildForm'),
on::change('[name=newSystem]', 'setSystemBox'),
on::change('[name=system]', 'loadBuilds'),
$integratedRow,
+1
View File
@@ -59,6 +59,7 @@ class buildZen extends build
$this->view->executions = $executions;
$this->view->lastBuild = $this->build->getLast($executionID, $projectID);
$this->view->project = $this->project->getByID($projectID);
$this->view->productID = $productID;
$this->display();
}
+1
View File
@@ -282,6 +282,7 @@ $lang->store->common = 'Store';
$lang->instance->common = 'Instance';
$lang->ai->common = 'AI';
$lang->aiapp->common = 'AI';
$lang->product->system = 'Application';
$lang->programstakeholder->common = 'Stakeholder';
$lang->featureswitch->common = 'Features On/Off';
+1
View File
@@ -282,6 +282,7 @@ $lang->store->common = 'Store';
$lang->instance->common = 'Instance';
$lang->ai->common = 'AI';
$lang->aiapp->common = 'AI';
$lang->product->system = 'Application';
$lang->programstakeholder->common = 'Stakeholder';
$lang->featureswitch->common = 'Features On/Off';
+1
View File
@@ -282,6 +282,7 @@ $lang->store->common = 'Store';
$lang->instance->common = 'Instance';
$lang->ai->common = 'AI';
$lang->aiapp->common = 'AI';
$lang->product->system = 'Application';
$lang->programstakeholder->common = 'Stakeholder';
$lang->featureswitch->common = 'Features On/Off';
+1
View File
@@ -282,6 +282,7 @@ $lang->store->common = '应用市场';
$lang->instance->common = '服务';
$lang->ai->common = 'AI';
$lang->aiapp->common = 'AI';
$lang->product->system = '应用';
$lang->programstakeholder->common = '干系人';
$lang->featureswitch->common = '功能开关';
+1 -1
View File
@@ -1321,7 +1321,7 @@ eof;
* The following pages can be allowed to open in non-iframe, so ignore these pages.
*/
$module = $this->app->getModuleName();
$whitelist = is_string($whitelist) ? $whitelist : '|index|tutorial|install|upgrade|sso|cron|misc|user-login|user-deny|user-logout|user-reset|user-forgetpassword|user-resetpassword|my-changepassword|my-preference|file-read|file-download|file-preview|file-uploadimages|file-ajaxwopifiles|report-annualdata|misc-captcha|execution-printkanban|traincourse-ajaxuploadlargefile|traincourse-playvideo|screen-view|zanode-create|screen-ajaxgetchart|ai-chat|integration-wopi|instance-terminal|conference-getconferencepermissions|';
$whitelist = is_string($whitelist) ? $whitelist : '|index|tutorial|install|upgrade|sso|cron|misc|user-login|user-deny|user-logout|user-reset|user-forgetpassword|user-resetpassword|my-changepassword|my-preference|file-read|file-download|file-preview|file-uploadimages|file-ajaxwopifiles|report-annualdata|misc-captcha|execution-printkanban|traincourse-ajaxuploadlargefile|traincourse-playvideo|screen-view|zanode-create|screen-ajaxgetchart|ai-chat|integration-wopi|instance-terminal|conference-getconferencepermissions|instance-logs|';
$iframeList = '|cron-index|zanode-create|';
if(strpos($iframeList, "|{$module}-{$method}|") === false && (strpos($whitelist, "|{$module}|") !== false || strpos($whitelist, "|{$module}-{$method}|") !== false)) return true;
+17 -3
View File
@@ -8,9 +8,11 @@ title=测试 commonModel::checkIframe();
timeout=0
cid=1
- 查看任务一和任务二的描述差异长度 @77
- 查看返回的差异中<ins>标签的位置 @44
- 查看返回的差异中<del>标签的位置 @5
- 查看任务一和任务二的描述差异长度 @1
- 查看返回的差异中<ins>标签的位置 查看返回的差异中<del>标签的位置 @1
- 查看实例的终端页面instance-terminal会跳出iframe打开 @1
- 实例的日志页面instance-logs也会跳出iframe打开 @1
- 查看实例的事件页面instance-events会在iframe中打开 @1
*/
@@ -24,3 +26,15 @@ r($tester->common->checkIframe()) && p() && e('1'); // 查看该页面是否要
$app->moduleName = 'execution';
$app->methodName = 'task';
r($tester->common->checkIframe()) && p() && e('1'); // 查看该页面是否要在iframe中打开
$app->moduleName = 'instance';
$app->methodName = 'terminal';
r($tester->common->checkIframe()) && p(0) && e('1');
$app->moduleName = 'instance';
$app->methodName = 'logs';
r($tester->common->checkIframe()) && p('0') && e('1');
$app->moduleName = 'instance';
$app->methodName = 'events';
r($tester->common->checkIframe()) && p(0) && e('1');
+1 -1
View File
@@ -111,7 +111,7 @@ $config->custom->customFields['todo'] = array('custom' => array('batchCre
$config->custom->customFields['user'] = array('custom' => array('batchCreateFields', 'batchEditFields'));
global $lang;
$config->custom->commonLang = array('$URCOMMON' => $lang->URCommon, '$SRCOMMON' => $lang->SRCommon, '$PRODUCTCOMMON' => $lang->productCommon, '$PROJECTCOMMON' => $lang->projectCommon, '$EXECUTIONCOMMON' => $lang->executionCommon);
$config->custom->commonLang = array('$ERCOMMON' => $lang->ERCommon, '$URCOMMON' => $lang->URCommon, '$SRCOMMON' => $lang->SRCommon, '$PRODUCTCOMMON' => $lang->productCommon, '$PROJECTCOMMON' => $lang->projectCommon, '$EXECUTIONCOMMON' => $lang->executionCommon);
$config->custom->browseStoryConcept = new stdclass();
+1
View File
@@ -52,6 +52,7 @@ class customModel extends model
}
else
{
if($customLang->module == 'productMenu' && $customLang->key == 'system') $this->lang->product->system = $customLang->value;
$processedLang[$customLang->module][$customLang->section][$customLang->key] = $customLang->value;
}
}
+2 -2
View File
@@ -115,8 +115,8 @@ class design extends control
$designs = $this->design->getList($projectID, $productID, $type, $queryID, $orderBy, $pager);
if($this->config->edition != 'open')
{
$this->loadModel('custom');
foreach($designs as $design) $design->relatedObject = $this->custom->getRelatedObjectList($design->id, 'design', 'byRelation', true);
$designRelatedObjectList = $this->loadModel('custom')->getRelatedObjectList(array_keys($designs), 'design', 'byRelation', true);
foreach($designs as $design) $design->relatedObject = zget($designRelatedObjectList, $design->id, 0);
}
$this->view->title = $this->lang->design->common . $this->lang->hyphen . $this->lang->design->browse;
+2
View File
@@ -121,6 +121,8 @@ class dev extends control
$method = 'work';
}
$moduleName = $module . 'SubMenu';
if($moduleName == 'qa' && $method = 'automation') $this->loadModel('zanode')->setMenu();
}
if($type == 'tag')
+6
View File
@@ -318,6 +318,12 @@ class devModel extends model
if(isset($defaultLang->$module->menu))
{
if($module == 'product')
{
$defaultLang->product->menu->system = $defaultLang->product->system;
$defaultLang->product->menuOrder[41] = 'system';
}
$menuList = $defaultLang->$module->menu;
if(isset($defaultLang->$module->menuOrder)) $menuList->menuOrder = $defaultLang->$module->menuOrder;
$menuList = $this->sortMenus($menuList);
+3 -3
View File
@@ -55,7 +55,7 @@ $config->doc->form->create['users'] = array('type' => 'array', 'requir
$config->doc->form->create['mailto'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join');
$config->doc->form->create['contentType'] = array('type' => 'string', 'required' => false, 'default' => 'doc');
$config->doc->form->create['content'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor', 'skipRequired' => true);
$config->doc->form->create['html'] = array('type' => 'string', 'required' => false, 'default' => '', 'skipRequired' => true);
$config->doc->form->create['rawContent'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor', 'skipRequired' => true);
$config->doc->form->create['template'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->doc->form->create['templateType'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->doc->form->create['chapterType'] = array('type' => 'string', 'required' => false, 'default' => '');
@@ -72,9 +72,9 @@ $config->doc->form->edit['status'] = array('type' => 'string', 'required'
$config->doc->form->edit['type'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->doc->form->edit['keywords'] = array('type' => 'string', 'required' => false, 'default' => '', 'skipRequired' => true);
$config->doc->form->edit['acl'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->doc->form->edit['contentType']= array('type' => 'string', 'required' => false, 'default' => 'html');
$config->doc->form->edit['contentType']= array('type' => 'string', 'required' => false, 'default' => 'doc');
$config->doc->form->edit['content'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor', 'skipRequired' => true);
$config->doc->form->edit['html'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor', 'skipRequired' => true);
$config->doc->form->edit['rawContent'] = array('type' => 'string', 'required' => false, 'default' => '', 'control' => 'editor', 'skipRequired' => true);
$config->doc->form->edit['groups'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join');
$config->doc->form->edit['users'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join');
$config->doc->form->edit['mailto'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join');
+59 -10
View File
@@ -1825,6 +1825,46 @@ class doc extends control
$this->send($data);
}
/**
* Ajax: Get migrate docs id list.
* Ajax: 获取迁移文档ID列表。
*
* @param string $type
* @access public
* @return void
*/
public function ajaxGetMigrateDocs(string $type)
{
$docs = $this->doc->getMigrateDocs($type);
echo json_encode($docs);
}
/**
* Ajax: Migrate doc.
* Ajax: 迁移文档。
*
* @param int $docID
* @access public
* @return void
*/
public function ajaxMigrateDoc(int $docID)
{
if(!common::hasPriv('doc', 'edit')) return $this->send(array('result' => 'fail', 'message' => $this->lang->doc->errorPrivilege));
if(empty($_POST)) return $this->send(array('result' => 'fail', 'message' => $this->lang->error->unsupportedReq));
$doc = $this->doc->getByID($docID);
if(empty($doc)) return $this->send(array('result' => 'fail', 'message' => $this->lang->notFound));
if(!$this->doc->checkPrivDoc($doc)) return $this->send(array('result' => 'fail', 'message' => $this->lang->doc->errorPrivilege));
$html = $this->post->html;
$result = $this->doc->migrateDoc($docID, $doc->version, $html);
if(!$result) return $this->send(array('result' => 'fail', 'message' => $this->lang->saveFailed));
$this->send(array('result' => 'success'));
}
/**
* Ajax: Get doc data.
* Ajax: 获取文档数据。
@@ -1869,10 +1909,12 @@ class doc extends control
$doc->object = $object;
}
if(!empty($doc->rawContent)) $doc->content = $doc->rawContent;
if($doc->contentType === 'doc' && is_string($doc->content)) $doc->content = htmlspecialchars_decode($doc->content);
if(is_string($doc->title)) $doc->title = htmlspecialchars_decode($doc->title);
if(!empty($doc->keywords) && is_string($doc->keywords)) $doc->keywords = htmlspecialchars_decode($doc->keywords);
unset($doc->rawContent);
if($docID) $this->doc->createAction($docID, 'view');
$this->send($doc);
@@ -1894,18 +1936,25 @@ class doc extends control
*/
public function ajaxGetFiles(string $type, int $objectID, string $browseType = '', string $orderBy = 'id_desc', int $recTotal = 0, int $recPerPage = 9999, int $pageID = 1)
{
/* Load pager. */
$rawMethod = $this->app->rawMethod;
$this->app->rawMethod = 'showFiles';
$this->app->loadClass('pager', true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$this->app->rawMethod = $rawMethod;
if(common::hasPriv('doc', 'showFiles'))
{
/* Load pager. */
$rawMethod = $this->app->rawMethod;
$this->app->rawMethod = 'showFiles';
$this->app->loadClass('pager', true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$this->app->rawMethod = $rawMethod;
$files = $this->doc->getLibFiles($type, $objectID, $browseType, 0, $orderBy, $pager);
$sourcePairs = $this->doc->getFileSourcePairs($files);
$files = $this->docZen->processFiles($files, array(), $sourcePairs, true);
$files = $this->doc->getLibFiles($type, $objectID, $browseType, 0, $orderBy, $pager);
$sourcePairs = $this->doc->getFileSourcePairs($files);
$files = $this->docZen->processFiles($files, array(), $sourcePairs, true);
echo json_encode(array_values($files)); // $this->send($files); not work.
echo json_encode(array_values($files)); // $this->send($files); not work.
}
else
{
echo '[]';
}
}
/**
+4 -4
View File
@@ -31,7 +31,7 @@
.files-grid .img-holder > img {width: 33%; margin: 0 auto; max-height: 64px;}
.files-grid .img-holder > img.not-exist {opacity: 0;}
.menu-item.is-nested > .item-inner .item-content .item-title {flex-grow: 0!important; opacity: .6;}
.menu-item.is-nested > .item-inner .item-content .item-subtitle {--skin-pale-rgb: var(--color-gray-500-rgb); height: 1rem; min-width: 1rem; border-radius: var(--radius-full); --skin-color: rgba(var(--skin-pale-rgb), .1); --skin-text: rgba(var(--skin-pale-rgb), 1); --state-color: rgba(var(--skin-pale-rgb), .1); --skin-bg: var(--skin-color); --skin-ring: var(--skin-color); --skin-border: var(--skin-color); --skin-hover-text: var(--skin-text); --skin-hover-bg: var(--skin-bg); --tw-ring-color: var(--skin-ring); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); --color-link-hover: var(--skin-text); background-color: var(--skin-bg); border-color: var(--skin-border); box-shadow: var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000); color: var(--skin-text); display: inline-flex; font-size: .75rem; align-items: center; justify-content: center; line-height: 1rem; padding-left: .25rem; padding-right: .25rem;}
.menu-item.is-nested > .item-inner {background-color: inherit!important; color: inherit!important; cursor: default;}
.menu-item.is-nested > .item-inner::before {display: none;}
.picker-menu .menu-item.is-nested > .item-inner .item-content .item-title {flex-grow: 0!important; opacity: .6;}
.picker-menu .menu-item.is-nested > .item-inner .item-content .item-subtitle {--skin-pale-rgb: var(--color-gray-500-rgb); height: 1rem; min-width: 1rem; border-radius: var(--radius-full); --skin-color: rgba(var(--skin-pale-rgb), .1); --skin-text: rgba(var(--skin-pale-rgb), 1); --state-color: rgba(var(--skin-pale-rgb), .1); --skin-bg: var(--skin-color); --skin-ring: var(--skin-color); --skin-border: var(--skin-color); --skin-hover-text: var(--skin-text); --skin-hover-bg: var(--skin-bg); --tw-ring-color: var(--skin-ring); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); --color-link-hover: var(--skin-text); background-color: var(--skin-bg); border-color: var(--skin-border); box-shadow: var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000); color: var(--skin-text); display: inline-flex; font-size: .75rem; align-items: center; justify-content: center; line-height: 1rem; padding-left: .25rem; padding-right: .25rem;}
.picker-menu .menu-item.is-nested > .item-inner {background-color: inherit!important; color: inherit!important; cursor: default;}
.picker-menu .menu-item.is-nested > .item-inner::before {display: none;}
+2
View File
@@ -20,6 +20,7 @@ window.changeDoclibAcl = function(e)
{
$('.apilib').removeClass('hidden');
$('#orderBox').addClass('hidden');
$('#orderBox #orderByid_asc').trigger('click');
$('#aclBox .check-list').html($('#aclAPIBox .check-list').html());
$("#aclBox input[id='aclopen']").prop('checked', true);
@@ -28,6 +29,7 @@ window.changeDoclibAcl = function(e)
else
{
$('.apilib').addClass('hidden');
$('#orderBox').removeClass('hidden');
$('#aclBox .check-list').html($('#aclOtherBox .check-list').html());
$("#aclBox input[id='acldefault']").prop('checked', true);
+18 -20
View File
@@ -1,32 +1,30 @@
window.loadExecutions = function(e)
window.loadExecutions = function()
{
const officeTypes = $('#setDocBasicForm').data('officeTypes');
const docType = $('#setDocBasicForm').data('docType');
const isOfficeType = officeTypes.includes(docType);
const projectElement = isOfficeType ? '.projectBox input[name="project"]': '#setDocBasicForm input[name="project"]';
const executionElement = isOfficeType ? '.executionBox input[name="execution"]': '#setDocBasicForm input[name="execution"]';
const projectID = $(projectElement).val();
if($(executionElement))
const $project = $('#setDocBasicForm input[name="project"]');
const $execution = $('#setDocBasicForm input[name="execution"]');
const projectID = $project.val();
if($execution.length)
{
const executionID = $(executionElement).val();
const link = $.createLink('project', 'ajaxGetExecutions', "projectID=" + projectID + "&mode=multiple,leaf,noprefix");
const executionID = $execution.val();
const link = $.createLink('project', 'ajaxGetExecutions', `projectID=${projectID}&mode=multiple,leaf,noprefix`);
$.getJSON(link, function(data)
{
let $picker = $(executionElement).zui('picker');
$picker.render({items: data.items, disabled: !data.multiple});
$picker.$.setValue(executionID);
const picker = $(executionElement).zui('picker');
picker.render({items: data.items, disabled: !data.multiple});
picker.$.setValue(executionID);
});
}
const link = $.createLink('doc', 'ajaxGetModules', 'objectType=project&objectID=' + projectID + '&type=doc');
const link = $.createLink('doc', 'ajaxGetModules', `objectType=project&objectID=${projectID}&type=doc`);
$.getJSON(link, function(data)
{
const $libPicker = $(`${isOfficeType ? '' : '#setDocBasicForm'} [name='lib']`).zui('picker');
$libPicker.render({items: data.libs});
$libPicker.$.setValue('');
const libPicker = $(`#setDocBasicForm [name="lib"]`).zui('picker');
libPicker.render({items: data.libs});
libPicker.$.setValue('');
const $modulePicker = $(`${isOfficeType ? '' : '#setDocBasicForm'} [name='module']`).zui('picker');
$modulePicker.render({items: data.modules});
$modulePicker.$.setValue('');
const modulePicker = $(`#setDocBasicForm [name="module"]`).zui('picker');
modulePicker.render({items: data.modules});
modulePicker.$.setValue('');
});
}
+74 -19
View File
@@ -775,8 +775,9 @@ class docModel extends model
->andWhere('vision')->eq($this->config->vision)
->andWhere('templateType')->eq('')
->andWhere("(status = 'normal' or (status = 'draft' and addedBy='{$this->app->user->account}'))")
->andWhere('module')->eq(0)
->andWhere('module')->in(array('0', ''))
->andWhere('deleted')->eq('0')
->andWhere('type')->ne('chapter')
->orderBy('`order` asc, id_asc')
->fetchAll('id');
@@ -813,6 +814,58 @@ class docModel extends model
return $docs;
}
/**
* 获取需要迁移的文档ID列表。
* Get docs need to migrate.
*
* @param string $spaceType
* @access public
* @return array
*/
public function getMigrateDocs(string $spaceType)
{
$docs = $this->dao->select('t1.*,t2.title,t2.content,t2.type as contentType,t2.html')->from(TABLE_DOC)->alias('t1')
->leftJoin(TABLE_DOCCONTENT)->alias('t2')->on('t1.id=t2.doc && t1.version=t2.version')
->where('t2.type')->eq('doc')
->andWhere('t1.status')->ne('draft')
->andWhere('t2.html')->in(null)
->andWhere('t1.deleted')->eq('0')
->fetchAll('id');
$docs = $this->filterPrivDocs($docs, $spaceType);
$ids = array();
foreach($docs as $doc)
{
if(empty($doc->rawContent) && !empty($doc->content)) $ids[] = $doc->id;
}
return $ids;
}
/**
* 迁移文档,设置新编辑器文档的 html。
* Migrate doc, set doc html generated by new editor.
*
* @param int $docID
* @param int $version
* @param string $html
*/
public function migrateDoc(int $docID, int $version, string $html): bool
{
$docContent = $this->dao->select('*')->from(TABLE_DOCCONTENT)->where('doc')->eq($docID)->andWhere('version')->eq($version)->fetch();
if(empty($docContent)) return false;
$rawContent = empty($docContent->rawContent) ? $docContent->content : $docContent->rawContent;
$this->dao->update(TABLE_DOCCONTENT)
->set('rawContent')->eq($rawContent)
->set('content')->eq($html)
->where('id')->eq($docContent->id)
->exec();
if(dao::isError()) return false;
return true;
}
/**
* 过滤出有权限的文档列表。
* Filter docs which has privilege.
@@ -1094,6 +1147,7 @@ class docModel extends model
$doc->title = isset($docContent->title) ? $docContent->title : $doc->title;
$doc->digest = isset($docContent->digest) ? $docContent->digest : '';
$doc->content = isset($docContent->content) ? $docContent->content : '';
$doc->rawContent = isset($docContent->rawContent) ? $docContent->rawContent : '';
$doc->contentType = isset($docContent->type) ? $docContent->type : '';
$doc->contentVersion = isset($docContent->version) ? $docContent->version : $version;
if($doc->type != 'url' && $doc->contentType != 'markdown' && $doc->contentType != 'doc') $doc = $this->loadModel('file')->replaceImgURL($doc, 'content,draft');
@@ -1395,6 +1449,7 @@ class docModel extends model
$docContent->digest = '';
$docContent->version = 1;
unset($doc->contentType);
unset($doc->rawContent);
return $this->insertSeperateDocs($doc, $docContent, $files);
}
@@ -1477,15 +1532,15 @@ class docModel extends model
$doc->execution = $lib->execution;
}
$docContent = new stdclass();
$docContent->title = $doc->title;
$docContent->content = $doc->content;
$docContent->type = $doc->contentType;
$docContent->html = isset($doc->html) ? $doc->html : '';
$docContent->digest = '';
$docContent->version = 1;
$docContent = new stdclass();
$docContent->title = $doc->title;
$docContent->content = $doc->content;
$docContent->type = $doc->contentType;
$docContent->rawContent = isset($doc->rawContent) ? $doc->rawContent : '';
$docContent->digest = '';
$docContent->version = 1;
unset($doc->contentType);
unset($doc->html);
unset($doc->rawContent);
$requiredFields = $type == 'doc' ? $this->config->doc->create->requiredFields : $this->config->doc->createTemplate->requiredFields;
if($doc->status == 'draft') $requiredFields = 'title';
@@ -1550,15 +1605,15 @@ class docModel extends model
if($changed)
{
$docContent = new stdclass();
$docContent->doc = $oldDoc->id;
$docContent->title = $doc->title;
$docContent->content = isset($doc->content) ? $doc->content : '';
$docContent->files = $oldDocContent->files;
$docContent->type = isset($doc->contentType) ? $doc->contentType : $oldDocContent->type;
$docContent = new stdclass();
$docContent->doc = $oldDoc->id;
$docContent->title = $doc->title;
$docContent->content = isset($doc->content) ? $doc->content : '';
$docContent->files = $oldDocContent->files;
$docContent->type = isset($doc->contentType) ? $doc->contentType : $oldDocContent->type;
if($files) $docContent->files .= ',' . join(',', array_keys($files));
$docContent->html = isset($doc->html) ? $doc->html : '';
$docContent->files = trim($docContent->files, ',');
$docContent->rawContent = isset($doc->rawContent) ? $doc->rawContent : '';
$docContent->files = trim($docContent->files, ',');
if(isset($doc->digest)) $docContent->digest = $doc->digest;
if($oldDoc->status == 'draft') $this->dao->update(TABLE_DOCCONTENT)->data($docContent)->where('id')->eq($oldDocContent->id)->exec();
@@ -1571,7 +1626,7 @@ class docModel extends model
}
unset($doc->contentType);
unset($doc->html);
unset($doc->rawContent);
$doc->draft = isset($doc->content) ? $doc->content : '';
$this->dao->update(TABLE_DOC)->data($doc, 'content')
->autoCheck()
@@ -3304,7 +3359,7 @@ class docModel extends model
{
$allLibs = $this->getLibs('hasApi');
$hasPrivDocIdList = $this->getPrivDocs(array(), 0, 'all');
$apiList = $this->loadModel('api')->getPrivApis();
$apiList = $this->loadModel('api')->getPrivApis('all');
$actionCondition = $this->loadModel('action')->getActionCondition('doc');
$actions = $this->dao->select('*')->from(TABLE_ACTION)
+3
View File
@@ -53,6 +53,7 @@ $privs['sortModule'] = hasPriv('doc', 'sortCatalog');
$privs['sortDoclib'] = hasPriv('doc', 'sortDoclib');
$privs['sortDoc'] = hasPriv('doc', 'sortDoc');
$privs['batchMoveDoc'] = hasPriv('doc', 'batchMoveDoc');
$privs['showFiles'] = hasPriv('doc', 'showFiles');
$privs['createApi'] = hasPriv('api', 'create');
$privs['editApi'] = hasPriv('api', 'edit');
$privs['viewApi'] = hasPriv('api', 'view');
@@ -74,5 +75,7 @@ docApp
set::homeName($homeName),
set::pager(array('recTotal' => $recTotal, 'recPerPage' => $recPerPage, 'page' => $pageID)),
set::privs($privs),
set::showLibFiles($privs['showFiles'] ? array('product', 'project', 'execution') : false),
set::migrateUrl(createLink('doc', 'ajaxGetMigrateDocs', "type=$type")),
set('$options', jsRaw('window.setDocAppOptions'))
);
+9 -33
View File
@@ -17,28 +17,25 @@ $apiType = isset($params['apiType']) ? $params['apiType'] : 'product';
$products = $this->loadModel('product')->getPairs();
$projects = $this->loadModel('project')->getPairsByProgram(0, 'all', false, 'order_asc');
$libs = array();
if($apiType == 'product')
{
$useType = $apiType;
$objectID = isset($params['objectID']) ? (int)$params['objectID'] : key($products);
$libPairs = $this->doc->getLibs($useType, '', '', (int)$objectID);
$libs = $this->doc->getApiLibs(0, $useType, (int)$objectID);
}
elseif($apiType == 'project')
{
$objectID = isset($params['objectID']) ? (int)$params['objectID'] : key($projects);
$executions = $this->loadModel('execution')->getPairs($objectID, 'all', 'multiple,leaf,noprefix');
$executionID = (isset($params['executionID']) && isset($executions[$params['executionID']])) ? $params['executionID'] : '';
$useType = $executionID ? 'execution' : 'project';
$useID = $executionID ? $executionID : $objectID;
$libPairs = $this->doc->getLibs($useType, '', '', (int)$useID);
$useType = $apiType;
$objectID = isset($params['objectID']) ? (int)$params['objectID'] : key($projects);
$libs = $this->doc->getApiLibs(0, $useType, (int)$objectID);
}
elseif($apiType == 'nolink')
{
$libs = $this->doc->getApiLibs(0, 'nolink');
$libPairs = array();
foreach($libs as $libID => $lib) $libPairs[$libID] = $lib->name;
$libs = $this->doc->getApiLibs(0, 'nolink');
}
$libPairs = array();
foreach($libs as $libID => $lib) $libPairs[$libID] = $lib->name;
$libID = isset($params['libID']) && isset($libPairs[$params['libID']]) ? $params['libID'] : key($libPairs);
@@ -74,32 +71,11 @@ form
formGroup
(
set::label($lang->doc->project),
set::width('2/5'),
set::width('4/5'),
set::name('project'),
set::items(createLink('project', 'ajaxGetDropMenu', "objectID=$objectID&module=&method=&extra=selectmode&useLink=0")),
set::value($objectID),
set::required(true)
),
formGroup
(
set::width('2/5'),
set::label($lang->doc->execution),
set::labelClass('executionTH'),
set::control(array('control' => 'picker', 'name' => 'execution', 'items' => $executions, 'value' => $executionID))
),
formGroup
(
setClass('executionHelp'),
icon
(
'help',
set('data-toggle', 'tooltip'),
set('data-title', $lang->doc->placeholder->execution),
set('data-placement', 'right'),
set('data-type', 'white'),
set('data-class-name', 'text-gray border border-light'),
setClass('ml-2 mt-2 text-gray')
)
)
) : null,
$apiType == 'product' ? formRow
+1 -1
View File
@@ -64,7 +64,7 @@ form
formGroup
(
set::label($lang->doc->project),
set::width('2/5'),
set::width($docType == 'doc' ? '2/5' : '4/5'),
set::name('project'),
set::items(createLink('project', 'ajaxGetDropMenu', "objectID=$objectID&module=&method=&extra=selectmode&useLink=0")),
set::value($objectID),
+6
View File
@@ -664,6 +664,12 @@ class docZen extends doc
}
if(isInModal()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true));
if(!empty($doc->rawContent)) $doc->content = $doc->rawContent;
if($doc->contentType === 'doc' && is_string($doc->content)) $doc->content = htmlspecialchars_decode($doc->content);
if(is_string($doc->title)) $doc->title = htmlspecialchars_decode($doc->title);
if(!empty($doc->keywords) && is_string($doc->keywords)) $doc->keywords = htmlspecialchars_decode($doc->keywords);
unset($doc->rawContent);
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $link, 'doc' => $doc));
}
+4 -2
View File
@@ -161,9 +161,10 @@ class execution extends control
foreach($this->view->teamMembers as $key => $member) $memberPairs[$key] = $member->realname;
$memberPairs = $this->loadModel('user')->setCurrentUserFirst($memberPairs);
if($this->config->edition != 'open') $taskRelatedObject = $this->loadModel('custom')->getRelatedObjectList(array_keys($tasks), 'task', 'byRelation', true);
/* Append branches to task. */
$this->loadModel('task');
$this->loadModel('custom');
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($this->view->products));
foreach($tasks as $task)
{
@@ -183,7 +184,7 @@ class execution extends control
}
if(isset($branchGroups[$task->product][$task->branch])) $task->branch = $branchGroups[$task->product][$task->branch];
if($task->needConfirm) $task->status = 'changed';
if($this->config->edition != 'open') $task->relatedObject = $this->custom->getRelatedObjectList($task->id, 'task', 'byRelation', true);
if($this->config->edition != 'open') $task->relatedObject = zget($taskRelatedObject, $task->id, 0);
}
$showAllModule = empty($this->config->execution->task->allModule) ? '' : 'allModule';
@@ -1599,6 +1600,7 @@ class execution extends control
$this->view->title = $this->view->execution->name . $this->lang->hyphen .$this->lang->execution->close;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->from = $from;
$this->view->actions = $this->loadModel('action')->getList($this->objectType, $executionID);
$this->view->unclosedTasks = $this->loadModel('task')->getUnclosedTasksByExecution($executionID);
$this->display();
+7 -4
View File
@@ -1051,7 +1051,7 @@ class executionModel extends model
$project = $this->loadModel('project')->getByID($projectID);
if(empty($project)) return;
if(($project->model == 'waterfall' || $project->model == 'waterfallplus') && $parentID != $projectID)
if(in_array($project->model, array('waterfall', 'waterfallplus', 'ipd')) && $parentID != $projectID)
{
$this->app->loadLang('programplan');
$parent = $this->getByID($parentID);
@@ -4507,27 +4507,30 @@ class executionModel extends model
$this->app->loadLang('story');
$gradePairs = zget($gradeGroup, $tree->type, array());
$grade = zget($gradePairs, $tree->grade, $tree->grade);
$gradeName = ($grade && isset($grade->name)) ? "<span class='label gray-pale rounded-full'>{$grade->name}</span>" : '';
$treeData[$index]['url'] = $canViewStory ? helper::createLink('execution', 'treeStory', "taskID={$tree->storyId}") : '';
$treeData[$index]['content'] = array(
'html' => "<div class='tree-link'><span class='label gray-pale rounded-full'>{$grade->name}</span><span class='ml-4'>{$tree->storyId}</span><span class='title " . ($canViewStory ? 'text-primary' : '') . " ml-4' title='{$tree->title}'>{$tree->title}</span>" . $assigedToHtml . '</div>',
'html' => "<div class='tree-link'>{$gradeName}<span class='ml-4'>{$tree->storyId}</span><span class='title " . ($canViewStory ? 'text-primary' : '') . " ml-4' title='{$tree->title}'>{$tree->title}</span>" . $assigedToHtml . '</div>',
);
break;
case 'requirement':
$this->app->loadLang('requirement');
$gradePairs = zget($gradeGroup, $tree->type, array());
$grade = zget($gradePairs, $tree->grade, $tree->grade);
$gradeName = ($grade && isset($grade->name)) ? "<span class='label gray-pale rounded-full'>{$grade->name}</span>" : '';
$treeData[$index]['url'] = helper::createLink('execution', 'treeStory', "taskID={$tree->storyId}");
$treeData[$index]['content'] = array(
'html' => "<div class='tree-link'><span class='label gray-pale rounded-full'>{$grade->name}</span><span class='ml-4'>{$tree->storyId}</span><span class='title text-primary ml-4' title='{$tree->title}'>{$tree->title}</span>" . $assigedToHtml . '</div>',
'html' => "<div class='tree-link'>{$gradeName}<span class='ml-4'>{$tree->storyId}</span><span class='title text-primary ml-4' title='{$tree->title}'>{$tree->title}</span>" . $assigedToHtml . '</div>',
);
break;
case 'epic':
$this->app->loadLang('epic');
$gradePairs = zget($gradeGroup, $tree->type, array());
$grade = zget($gradePairs, $tree->grade, $tree->grade);
$gradeName = ($grade && isset($grade->name)) ? "<span class='label gray-pale rounded-full'>{$grade->name}</span>" : '';
$treeData[$index]['url'] = helper::createLink('execution', 'treeStory', "taskID={$tree->storyId}");
$treeData[$index]['content'] = array(
'html' => "<div class='tree-link'><span class='label gray-pale rounded-full'>{$grade->name}</span><span class='ml-4'>{$tree->storyId}</span><span class='title text-primary ml-4' title='{$tree->title}'>{$tree->title}</span>" . $assigedToHtml . '</div>',
'html' => "<div class='tree-link'>{$gradeName}<span class='ml-4'>{$tree->storyId}</span><span class='title text-primary ml-4' title='{$tree->title}'>{$tree->title}</span>" . $assigedToHtml . '</div>',
);
break;
case 'branch':
+1
View File
@@ -27,6 +27,7 @@ jsVar('hourPointNotError', sprintf($lang->story->float, $lang->story->convertRe
/* Show feature bar. */
$queryMenuLink = createLink($app->rawModule, $app->rawMethod, "&executionID=$execution->id&storyType=$storyType&orderBy=$orderBy&type=bySearch&param={queryID}");
if(empty($param) && $this->cookie->storyModuleParam) $param = $this->cookie->storyModuleParam;
featureBar
(
to::leading
+1 -1
View File
@@ -1578,7 +1578,7 @@ class executionZen extends execution
if($this->config->edition != 'open')
{
$flow = $this->loadModel('workflow')->getByModule($module);
if(in_array($flow->app, array('scrum', 'waterfall'))) $flow->app = 'project';
if(!empty($flow) && in_array($flow->app, array('scrum', 'waterfall'))) $flow->app = 'project';
if(!empty($flow) && $flow->buildin == '0') return helper::createLink('flow', 'ajaxSwitchBelong', "objectID=%s&moduleName=$module") . "#app=$flow->app";
}
+1 -1
View File
@@ -1010,7 +1010,7 @@ class fileModel extends model
$contentType = isset($mimes[$fileType]) ? $mimes[$fileType] : $mimes['default'];
/* Safari浏览器下载文件名乱码问题。 */
if($_SERVER['CONTENT_TYPE'] == 'application/x-www-form-urlencoded' && preg_match("/Safari/", $_SERVER["HTTP_USER_AGENT"]))
if(isset($_SERVER['CONTENT_TYPE']) && isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['CONTENT_TYPE'] == 'application/x-www-form-urlencoded' && preg_match("/Safari/", $_SERVER["HTTP_USER_AGENT"]))
{
$fileName = rawurlencode($fileName);
$attachment = 'attachment; filename*=utf-8\'\'' . $fileName;
+6 -8
View File
@@ -21,19 +21,17 @@ $config->instance->enableAutoRestore = in_array('auto-rollback', $features);
global $lang, $app;
$app->loadLang('space');
$config->instance->actionList['showLogs']['icon'] = 'time';
$config->instance->actionList['showLogs']['hint'] = $lang->instance->log->viewButton;
$config->instance->actionList['showLogs']['text'] = $lang->instance->log->viewButton;
$config->instance->actionList['showLogs']['url'] = array('module' => 'instance', 'method' => 'logs', 'params' => 'id={id}&zin=1');
$config->instance->actionList['showLogs']['data-toggle'] = 'modal';
$config->instance->actionList['showLogs']['class'] = 'task-record-btn';
$config->instance->actionList['showLogs']['icon'] = 'time';
$config->instance->actionList['showLogs']['hint'] = $lang->instance->log->viewButton;
$config->instance->actionList['showLogs']['text'] = $lang->instance->log->viewButton;
$config->instance->actionList['showLogs']['url'] = array('module' => 'instance', 'method' => 'logs', 'params' => 'id={id}');
$config->instance->actionList['showLogs']['target'] = '_blank';
$config->instance->actionList['showEvents']['icon'] = 'magic';
$config->instance->actionList['showEvents']['icon'] = 'summary';
$config->instance->actionList['showEvents']['hint'] = $lang->instance->event->viewButton;
$config->instance->actionList['showEvents']['text'] = $lang->instance->event->viewButton;
$config->instance->actionList['showEvents']['url'] = array('module' => 'instance', 'method' => 'events', 'params' => 'id={id}');
$config->instance->actionList['showEvents']['data-toggle'] = 'modal';
$config->instance->actionList['showEvents']['class'] = 'task-record-btn';
$config->instance->actionList['ajaxStart']['icon'] = 'play';
$config->instance->actionList['ajaxStart']['className'] = 'ajax-submit';
+1
View File
@@ -726,6 +726,7 @@ class instance extends control
$instance = $this->instance->getByID($id);
$this->view->instance = $instance;
$this->view->title = $this->lang->instance->log->viewButton;
$this->display();
}
+14 -7
View File
@@ -8,22 +8,29 @@ window.initComponent = function (instanceID)
{
toggleLoading('#events-panel', false);
$picker.render({items: items});
if (typeof (items) !== 'undefined')
{
$picker.$.setValue(items.component);
}
if (typeof (items) !== 'undefined') $picker.$.setValue(items.component);
if (items.length === 1) $('#component-events').addClass('hidden');
showEvents(instanceID);
});
};
window.showEvents = function (instanceID)
window.showEvents = function (instanceID, noEventTip)
{
const instanceComponent = $('[name=component]').val();
const target = $.createLink('instance', 'showEvents', 'id=' + instanceID + "&component=" + instanceComponent);
toggleLoading('#events-panel', true);
$.getJSON(target, function (data)
$.getJSON(target, function (resp)
{
toggleLoading('#events-panel', false);
$('#events-content').html(data.data.map(item => item.lastSeen + ' ' + item.type + ' ' + item.reason + ' ' + item.object + ' ' + item.message).join('\n'));
$('#events-content').removeClass('dtable-empty-tip flex');
if (resp.code !== 200 || resp.data.length === 0)
{
$('#events-content').html(noEventTip);
$('#events-content').addClass('dtable-empty-tip flex');
return;
}
$('#events-content').html(resp.data.map(item => item.lastSeen + ' ' + item.type + ' ' + item.reason + ' ' + item.object + ' ' + item.message).join('\n'));
$('#events-content')[0].scrollTop = $('#events-content')[0].scrollHeight;
});
};
+38 -8
View File
@@ -15,7 +15,7 @@ window.initComponent = function (instanceID)
});
};
window.changeComponent = function (instanceID)
window.changeComponent = function (instanceID, noLogsTip)
{
toggleLoading('#logs-panel', true);
const $picker = $('[name=pod]').zui('picker');
@@ -29,20 +29,50 @@ window.changeComponent = function (instanceID)
$picker.$.setValue(items.pod);
}
toggleLoading('#logs-panel', false);
showLogs(instanceID);
showLogs(instanceID, noLogsTip);
startAutoRefreshLogs(instanceID, noLogsTip);
});
};
window.showLogs = function (instanceID)
window.showLogs = function (instanceID, noLogsTip)
{
const headerHeight = document.getElementById('logs-header').offsetHeight;
document.getElementById('logs-content').style.height = `calc(100vh - ${headerHeight}px - 16px)`;
const instanceComponent = $('[name=component]').val();
const instancePod = $('[name=pod]').val();
const previous = $('[name=previous]').val();
const previous = $('[name=previous]:checked').val();
const target = $.createLink('instance', 'showlogs', 'id=' + instanceID + "&component=" + instanceComponent + "&pod=" + instancePod + "&previous=" + previous);
toggleLoading('#logs-panel', true);
$.getJSON(target, function (data)
$.getJSON(target, function (resp)
{
toggleLoading('#logs-panel', false);
$('#logs-content').html(data.data.map(item => item.timestamp + ' ' + item.content).join('\n'));
$('#logs-content').removeClass('dtable-empty-tip flex');
if (resp.code !== 200 || resp.data.length === 0)
{
$('#logs-content').html(noLogsTip);
$('#logs-content').addClass('dtable-empty-tip flex');
return;
}
$('#logs-content').html(resp.data.map(item => item.timestamp + ' ' + item.content).join('\n'));
$('#logs-content')[0].scrollTop = $('#logs-content')[0].scrollHeight;
});
};
let logsTimer = null;
window.startAutoRefreshLogs = function (instanceID, noLogsTip) {
if(logsTimer) clearInterval(logsTimer);
logsTimer = setInterval(function() {
showLogs(instanceID, noLogsTip);
}, 5000);
}
window.toggleAutoRefresh = function(instanceID, noLogsTip) {
const $toggleBtn = $('#autoRefreshBtn');
if(logsTimer) {
clearInterval(logsTimer);
logsTimer = null;
$toggleBtn.html('<i class="icon icon-play"></i>');
} else {
startAutoRefreshLogs(instanceID, noLogsTip);
$toggleBtn.html('<i class="icon icon-pause"></i>');
}
}
+10 -6
View File
@@ -187,20 +187,24 @@ $lang->instance->log = new stdclass;
$lang->instance->log->date = 'date';
$lang->instance->log->message = 'Content';
$lang->instance->log->viewButton = 'Logs';
$lang->instance->log->title = 'Watch Logs';
$lang->instance->log->button = 'View Now';
$lang->instance->log->viewButton = 'Logs';
$lang->instance->log->title = 'Watch Logs';
$lang->instance->log->button = 'View Now';
$lang->instance->log->autoRefresh = 'Switch refresh status';
$lang->instance->log->tips = 'The logs are refreshed automatically by default, and you can switch the button to switch';
$lang->instance->log->noLog = 'No logs yet';
$lang->instance->component = 'Component';
$lang->instance->pod = 'Pod';
$lang->instance->isPrevious = 'Is Previous container';
$lang->instance->isPreviousList[0] = 'No';
$lang->instance->isPreviousList[1] = 'Yes';
$lang->instance->isPreviousList[0] = 'Current container';
$lang->instance->isPreviousList[1] = 'Previous container';
$lang->instance->event = new stdClass;
$lang->instance->event->viewButton = 'Events';
$lang->instance->event->title = 'Watch Events';
$lang->instance->event->button = 'View Now';
$lang->instance->event->noEvents = 'No events yet';
$lang->instance->actionList = array();
$lang->instance->actionList['install'] = '%s installed';
+10 -6
View File
@@ -187,20 +187,24 @@ $lang->instance->log = new stdclass;
$lang->instance->log->date = 'date';
$lang->instance->log->message = 'Content';
$lang->instance->log->viewButton = 'Logs';
$lang->instance->log->title = 'Watch Logs';
$lang->instance->log->button = 'View Now';
$lang->instance->log->viewButton = 'Logs';
$lang->instance->log->title = 'Watch Logs';
$lang->instance->log->button = 'View Now';
$lang->instance->log->autoRefresh = 'Switch refresh status';
$lang->instance->log->tips = 'The logs are refreshed automatically by default, and you can switch the button to switch';
$lang->instance->log->noLog = 'No logs yet';
$lang->instance->component = 'Component';
$lang->instance->pod = 'Pod';
$lang->instance->isPrevious = 'Is Previous container';
$lang->instance->isPreviousList[0] = 'No';
$lang->instance->isPreviousList[1] = 'Yes';
$lang->instance->isPreviousList[0] = 'Current container';
$lang->instance->isPreviousList[1] = 'Previous container';
$lang->instance->event = new stdClass;
$lang->instance->event->viewButton = 'Events';
$lang->instance->event->title = 'Watch Events';
$lang->instance->event->button = 'View Now';
$lang->instance->event->noEvents = 'No events yet';
$lang->instance->actionList = array();
$lang->instance->actionList['install'] = '%s installed';
+10 -6
View File
@@ -187,20 +187,24 @@ $lang->instance->log = new stdclass;
$lang->instance->log->date = 'date';
$lang->instance->log->message = 'Content';
$lang->instance->log->viewButton = 'Logs';
$lang->instance->log->title = 'Watch Logs';
$lang->instance->log->button = 'View Now';
$lang->instance->log->viewButton = 'Logs';
$lang->instance->log->title = 'Watch Logs';
$lang->instance->log->button = 'View Now';
$lang->instance->log->autoRefresh = 'Switch refresh status';
$lang->instance->log->tips = 'The logs are refreshed automatically by default, and you can switch the button to switch';
$lang->instance->log->noLog = 'No logs yet';
$lang->instance->component = 'Component';
$lang->instance->pod = 'Pod';
$lang->instance->isPrevious = 'Is Previous container';
$lang->instance->isPreviousList[0] = 'No';
$lang->instance->isPreviousList[1] = 'Yes';
$lang->instance->isPreviousList[0] = 'Current container';
$lang->instance->isPreviousList[1] = 'Previous container';
$lang->instance->event = new stdClass;
$lang->instance->event->viewButton = 'Events';
$lang->instance->event->title = 'Watch Events';
$lang->instance->event->button = 'View Now';
$lang->instance->event->noEvents = 'No events yet';
$lang->instance->actionList = array();
$lang->instance->actionList['install'] = '%s installed';
+11 -7
View File
@@ -187,24 +187,28 @@ $lang->instance->management = '管理';
$lang->instance->dbReady = '正常';
$lang->instance->dbWaiting = '等待就绪';
$lang->instance->log = new stdclass;
$lang->instance->log = new stdClass;
$lang->instance->log->date = '日期';
$lang->instance->log->message = '内容';
$lang->instance->log->viewButton = '日志';
$lang->instance->log->title = '查看日志';
$lang->instance->log->button = '立即查看';
$lang->instance->log->viewButton = '日志';
$lang->instance->log->title = '查看日志';
$lang->instance->log->button = '立即查看';
$lang->instance->log->autoRefresh = '切换刷新状态';
$lang->instance->log->tips = '日志默认自动刷新,可点切换按钮切换';
$lang->instance->log->noLog = '暂无日志';
$lang->instance->component = '组件';
$lang->instance->pod = 'Pod';
$lang->instance->isPrevious = '是否上个退出容器';
$lang->instance->isPreviousList[0] = '否';
$lang->instance->isPreviousList[1] = '是';
$lang->instance->isPreviousList[0] = '当前容器';
$lang->instance->isPreviousList[1] = '上个容器';
$lang->instance->event = new stdClass;
$lang->instance->event->viewButton = '事件';
$lang->instance->event->title = '查看事件';
$lang->instance->event->button = '立即查看';
$lang->instance->event->noEvents = '暂无事件';
$lang->instance->actionList = array();
$lang->instance->actionList['install'] = '安装了%s';
+21 -33
View File
@@ -15,52 +15,40 @@ namespace zin;
formPanel
(
set::title($lang->instance->event->title),
set::actions(array(
array(
'text' => $lang->instance->event->button,
'type' => 'primary',
'onclick' => 'window.showEvents('.$instance->id.')',
)
)),
set::actions(false),
setID('events-panel'),
setClass('w-full'),
formRow
inputGroup
(
formGroup
input
(
setClass('hidden'),
set::name('name'),
set::labelWidth('160px'),
set::required(true),
set::label($lang->instance->name),
set::value($instance->name),
set::disabled(true),
)
),
formRow
(
formGroup
set::inline(true),
),
inputGroup
(
setID('component-events'),
set::name('component'),
set::labelWidth('160px'),
set::control('picker'),
set::required(true),
set::label($lang->instance->component),
on::inited()->call('initComponent', $instance->id),
on::change()->call('showEvents', $instance->id)
$lang->instance->component,
picker
(
set::name('component'),
set::control('picker'),
set::required(true),
set::label($lang->instance->component),
set::inline(true),
on::inited()->call('initComponent', $instance->id),
on::change()->call('showEvents', $instance->id, $lang->instance->event->noEvents)
)
)
),
div
(
setClass('px-1 mt-2 w-full'),
panel
(
setClass('py-2'),
form
(
h::pre(setID('events-content'), setClass('bg-gray-800 text-white progress block h-96')),
set::actions(false)
)
)
setClass('w-full'),
h::pre(setID('events-content'), setClass('bg-gray-800 text-white block h-96 scrollbar-thin')),
set::actions(false)
)
);
+66 -64
View File
@@ -11,83 +11,85 @@ declare(strict_types=1);
*/
namespace zin;
set::zui(true);
formPanel
div
(
set::title($lang->instance->log->title),
set::actions(array(
array(
'text' => $lang->instance->log->button,
'type' => 'primary',
'onclick' => 'window.showLogs('.$instance->id.')',
)
)),
setID('logs-panel'),
setClass('w-full'),
formRow
(
formGroup
(
set::name('name'),
set::labelWidth('160px'),
set::required(true),
set::label($lang->instance->name),
set::value($instance->name),
set::disabled(true)
)
),
formRow
(
formGroup
(
setID('component-logs'),
set::name('component'),
set::labelWidth('160px'),
set::control('picker'),
set::required(true),
set::label($lang->instance->component),
on::change()->call('changeComponent', $instance->id)
)
),
formRow
(
formGroup
(
setID('pod-logs'),
set::name('pod'),
set::labelWidth('160px'),
set::control('picker'),
set::required(true),
set::label($lang->instance->pod),
set::items(array())
)
),
setClass('px-1 mt-2 w-full'),
formRow
(
setID('logs-header'),
setClass('flex px-1 top-0 bg-white'),
formGroup(
inputGroup
(
h::button
(
setClass('btn primary'),
$lang->instance->log->autoRefresh,
span(
setID('autoRefreshBtn'),
icon(setClass('icon icon-pause'))
),
on::click()->call('toggleAutoRefresh', $instance->id, $lang->instance->log->noLog)
),
$lang->instance->name,
input
(
set::class('input-group-addon'),
set::name('name'),
set::required(true),
set::value($instance->name),
set::disabled(true)
),
$lang->instance->component,
picker
(
setClass('input-group-addon w-48'),
setID('component-logs'),
set::name('component'),
set::control('picker'),
set::required(true),
on::change()->call('changeComponent', $instance->id, $lang->instance->log->noLog)
),
$lang->instance->pod,
picker
(
setClass('input-group-addon w-72'),
setID('pod-logs'),
set::name('pod'),
set::required(true),
set::items(array()),
set::inline(true),
on::inited()->call('initComponent', $instance->id, $lang->instance->log->noLog)
)
)
),
formGroup
(
setClass('flex mx-2'),
setID('is-previous'),
set::name('previous'),
set::labelWidth('160px'),
set::control('picker'),
set::label($lang->instance->isPrevious),
set::control('radioListInline'),
set::items($lang->instance->isPreviousList),
set::value(0),
on::change()->call('showLogs', $instance->id),
on::inited()->call('initComponent', $instance->id)
set::inline(true),
on::change()->call('showLogs', $instance->id, $lang->instance->log->noLog)
),
formGroup(
setClass('flex mx-2 text-sm text-gray-500'),
set::label( setClass('text-danger'), $lang->instance->log->tips)
)
),
div
(
setClass('px-1 mt-2 w-full'),
panel
(
setClass('py-2'),
form
(
h::pre(setID('logs-content'), setClass('bg-gray-800 text-white progress block h-96')),
set::actions(false)
)
)
setClass('px-1 mt-2 w-full h-full'),
h::pre(
setID('logs-content'),
setClass('bg-gray-800 text-white block h-screen scrollbar-thin')
),
set::actions(false)
)
);
);
render('pagebase');
+4 -2
View File
@@ -1504,7 +1504,8 @@ class kanbanModel extends model
if(in_array($laneType, array('epic', 'requirement')) && strpos($project->storyType, $laneType) === false) continue;
list($laneData, $columnData, $cardsData) = $this->buildExecutionGroup($lane, $columns, $objectGroup, $searchValue, $menus);
if($lane->type == 'risk') $cardsData = $this->appendRiskField($cardsData, $objectGroup['risk']);
if($lane->type == 'risk' && in_array($this->config->edition, array('max', 'ipd'))) $cardsData = $this->appendRiskField($cardsData, $objectGroup['risk']);
$kanbanID = 'group' . $lane->id;
$kanbanGroup[$laneType]['id'] = $lane->id;
@@ -2885,7 +2886,8 @@ class kanbanModel extends model
if($laneType == 'story') $cardPairs = $this->kanbanTao->refreshStoryCards($cardPairs, $executionID, $otherCardList);
if($laneType == 'bug') $cardPairs = $this->kanbanTao->refreshBugCards($cardPairs, $executionID, $otherCardList);
if($laneType == 'task') $cardPairs = $this->kanbanTao->refreshTaskCards($cardPairs, $executionID, $otherCardList);
if($laneType == 'risk') $cardPairs = $this->refreshRiskCards($cardPairs, $executionID, $otherCardList);
if($laneType == 'risk' && in_array($this->config->edition, array('max', 'ipd'))) $cardPairs = $this->refreshRiskCards($cardPairs, $executionID, $otherCardList);
$colPairs = $this->dao->select('t2.type, t2.id')->from(TABLE_KANBANCELL)->alias('t1')
->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.`column` = t2.id')
+16 -13
View File
@@ -517,20 +517,23 @@ class kanbanTao extends kanbanModel
$strLength = strlen($realname);
$displayText = '';
if($strLength === $mbLength)
if($realname)
{
/* Pure alphabet or numbers 纯英文情况 */
$displayText = strtoupper($realname[0]);
}
else if($strLength % $mbLength == 0 && $strLength % 3 == 0)
{
/* Pure chinese characters 纯中文的情况 */
$displayText = $mbLength <= $maxTextLen ? $realname : mb_substr($realname, $mbLength - $maxTextLen, $mbLength, 'utf-8');
}
else
{
/* Mix of Chinese and English 中英文混合的情况 */
$displayText = $mbLength <= $maxTextLen ? $realname : mb_substr($realname, 0, $maxTextLen, 'utf-8');
if(isset($realname[0]) && $strLength === $mbLength)
{
/* Pure alphabet or numbers 纯英文情况 */
$displayText = strtoupper($realname[0]);
}
else if($strLength % $mbLength == 0 && $strLength % 3 == 0)
{
/* Pure chinese characters 纯中文的情况 */
$displayText = $mbLength <= $maxTextLen ? $realname : mb_substr($realname, $mbLength - $maxTextLen, $mbLength, 'utf-8');
}
else
{
/* Mix of Chinese and English 中英文混合的情况 */
$displayText = $mbLength <= $maxTextLen ? $realname : mb_substr($realname, 0, $maxTextLen, 'utf-8');
}
}
$userAvatar = zget($avatarPairs, $account, '');
+1 -1
View File
@@ -934,7 +934,7 @@ class my extends control
$this->view->mode = 'audit';
$this->view->flows = $flows;
$this->view->products = $this->loadModel('product')->getPairs('', 0, '', 'all');;
$this->view->projects = $this->loadModel('project')->getPairsByProgram();;
$this->view->projects = $this->loadModel('project')->getPairs();
$this->display();
}
+3
View File
@@ -1422,6 +1422,9 @@ class myModel extends model
$review->status = $objectType == 'attend' ? $object->reviewStatus : (isset($object->status) && !isset($flows[$objectType]) ? $object->status : 'done');
if(strpos($review->result, ',') !== false) list($review->result) = explode(',', $review->result);
$review->product = isset($object->product) ? $object->product : 0;
$review->project = isset($object->project) ? $object->project : 0;
if($objectType == 'story') $review->storyType = $object->type;
if($review->type == 'review') $review->type = 'projectreview';
if($review->type == 'case') $review->type = 'testcase';
+7 -2
View File
@@ -95,11 +95,16 @@ class pivot extends control
$this->pivotZen->show($groupID, $pivotID, '', $version);
$this->loadModel('mark')->setMark(array($pivotID), 'pivot', $version, 'version');
$marks = $this->loadModel('mark')->getNeededMarks(array($pivotID), 'pivot', 'all', 'version');
$marks = array();
if($pivot->builtin == 1)
{
$this->loadModel('mark')->setMark(array($pivotID), 'pivot', $version, 'version');
$marks = $this->loadModel('mark')->getNeededMarks(array($pivotID), 'pivot', 'all', 'version');
}
$this->view->versionSpecs = $versionSpecs;
$this->view->markedVersions = array_column($marks, 'version');
$this->view->builtin = $pivot->builtin;
$this->view->version = $version;
$this->view->groupID = $groupID;
$this->view->pivotID = $groupID;
+3 -9
View File
@@ -1863,7 +1863,7 @@ class pivotModel extends model
$data->array = array();
$data->drills = array();
if(!isset($settings['columns'])) return array(data, array());
if(!isset($settings['columns'])) return array($data, array());
$filters = $this->processQueryFilterDefaults($filters);
/* Replace the variable with the default value. */
@@ -2947,14 +2947,8 @@ class pivotModel extends model
foreach($pivots as $index => $pivot)
{
if(isset($pivotMaxVersion[$pivot->id]) && $pivotMaxVersion[$pivot->id] != $pivot->version)
{
$pivots[$index]->versionChange = true;
}
else
{
$pivots[$index]->versionChange = false;
}
$maxVersion = zget($pivotMaxVersion, $pivot->id, '');
$pivots[$index]->versionChange = $maxVersion != $pivot->version && $pivot->builtin == 1;
}
return $isObject ? current($pivots) : $pivots;
+13 -5
View File
@@ -18,22 +18,30 @@ include_once 'show.html.php';
$versionsTableBody = array();
foreach($versionSpecs as $versionSpec)
{
$isMarked = in_array($versionSpec->version, $markedVersions);
$isBuiltIn = $builtin == 1;
$isFirstVersion = $versionSpec->version == 1;
$isMainVersion = filter_var($versionSpec->version, FILTER_VALIDATE_INT) !== false;
$versionsTableBody[] = h::tr
(
$version == $versionSpec->version ? setClass('bg-secondary-50') : null,
on::click("previewVersion"),
h::td
(
on::click("previewVersion"),
setData(array('pivot' => $pivot->id, 'version' => $versionSpec->version, 'group' => $groupID)),
'#' . $versionSpec->version,
!in_array($versionSpec->version, $markedVersions) ? span
span
(
setData(array('pivot' => $pivot->id, 'version' => $versionSpec->version, 'group' => $groupID)),
setClass("label ghost size-sm bg-secondary-50 text-secondary-500 rounded-full"),
setClass("label ghost size-sm bg-secondary-50 text-secondary-500 rounded-full", array('hidden' => $isMarked || $isFirstVersion || !$isBuiltIn || ($isBuiltIn && !$isMainVersion))),
$lang->pivot->newVersion
) : null
)
),
h::td(empty($versionSpec->desc) ? $lang->pivot->noDesc : $versionSpec->desc)
h::td
(
setData(array('pivot' => $pivot->id, 'version' => $versionSpec->version, 'group' => $groupID)),
empty($versionSpec->desc) ? $lang->pivot->noDesc : $versionSpec->desc
)
);
}
+8 -3
View File
@@ -125,12 +125,17 @@ class pivotZen extends pivot
*/
protected function setNewMark(object $pivot, object $firstAction, array $builtins): void
{
// 版本没有改变,此时讨论是不是新透视表
/* 如果不是内置透视表,则不需要展示“新”标签。*/
/* If the pivot is not built-in, no need to display the "new" tag. */
if($pivot->builtin == 0) return;
/* 版本没有改变,此时讨论是不是新透视表。*/
/* The version has not changed, so it is judged whether it is a new pivot. */
if(!$pivot->versionChange)
{
if(!isset($builtins[$pivot->id])) return;
if(!$pivot->mark && $pivot->createdDate < $firstAction->date) $pivot->mark = true;
if(!$pivot->mark) $pivot->name = array('text' => $pivot->name, 'html' => $pivot->name . ' <span class="label ghost size-sm bg-secondary-50 text-secondary-500 rounded-full">' . $this->lang->pivot->new . '</span>');
$isMainVersion = filter_var($pivot->version, FILTER_VALIDATE_INT) !== false;
if(!$pivot->mark && $isMainVersion) $pivot->name = array('text' => $pivot->name, 'html' => $pivot->name . ' <span class="label ghost size-sm bg-secondary-50 text-secondary-500 rounded-full">' . $this->lang->pivot->new . '</span>');
}
else
{
@@ -202,7 +207,7 @@ class pivotZen extends pivot
$driver = $pivot->driver;
$this->pivot->isVersionChange($pivot);
if($mark)
if($mark && $pivot->builtin == 1)
{
$markVersion = $pivot->versionChange ? $this->pivot->getMaxVersion($pivot->id) : $pivot->version;
+1 -1
View File
@@ -22,7 +22,7 @@ if($app->rawModule == 'programplan')
if($project->stageBy == 'product')
{
$viewName = $productID != 0 ? zget($productList, $productID) : $lang->product->allProduct;
$items = array(array('text' => $lang->product->allProduct, 'url' => $this->createLink('programplan', 'browse', "projectID=$projectID&productID=all&type=gantt")));
$items = array(array('text' => $lang->product->allProduct, 'url' => $this->createLink('programplan', 'browse', "projectID=$projectID&productID=0&type=gantt")));
foreach($productList as $key => $productName) $items[] = array('text' => $productName, 'url' => $this->createLink('programplan', 'browse', "projectID=$projectID&productID=$key&type=gantt"));
$productDropdown = dropdown
(
+1 -1
View File
@@ -292,7 +292,7 @@ $config->project->linkMap->reviewissue = array();
$config->project->linkMap->reviewissue[''] = array('reviewissue', 'issue', 'projectID=%s', '');
$config->project->linkMap->cm = array();
$config->project->linkMap->cm['report'] = array('cm', 'report', 'projectID=%s', '');
$config->project->linkMap->cm['report'] = array('project', 'index', 'projectID=%s', '');
$config->project->linkMap->weekly = array();
$config->project->linkMap->weekly['index'] = array('weekly', 'index', 'projectID=%s', '');
+1
View File
@@ -122,6 +122,7 @@ class project extends control
$this->view->method = $method;
$this->view->programs = $programs;
$this->view->extra = $extra;
$this->view->useLink = $useLink;
$this->view->projects = $orderedProjects;
$this->view->involvedProjects = $involvedProjects;
+1
View File
@@ -976,6 +976,7 @@ class projectModel extends model
$this->config->build->search['actionURL'] = helper::createLink($this->app->rawModule, $this->app->rawMethod, "projectID=$projectID&type=bysearch&queryID=myQueryID");
$this->config->build->search['queryID'] = $queryID;
$this->config->build->search['params']['product']['values'] = $products;
$this->config->build->search['params']['system']['values'] = $this->loadModel('system')->getPairs((int)$productID, '0');
$this->loadModel('search')->setSearchParams($this->config->build->search);
return true;
+9 -2
View File
@@ -110,10 +110,17 @@ else
$item['text'] = $project->name;
$item['icon'] = $project->model == 'scrum' ? 'sprint' : $project->model;
$item['keys'] = zget(common::convert2Pinyin(array($project->name)), $project->name, '');
$item['url'] = sprintf($link, $project->id);
$item['involved'] = isset($involvedProjects[$project->id]);
if((empty($project->multiple) || $project->type == 'kanban' || $project->model == 'kanban') && strpos($link, 'ajaxSwitchBelong') === false) $item['url'] = helper::createLink('project', 'index', "projectID={$project->id}");
if($useLink == 1)
{
$item['url'] = sprintf($link, $project->id);
if((empty($project->multiple) || $project->type == 'kanban' || $project->model == 'kanban') && strpos($link, 'ajaxSwitchBelong') === false) $item['url'] = helper::createLink('project', 'index', "projectID={$project->id}");
}
else
{
$item['url'] = '#';
}
if(empty($activeGroup) && $projectID == $project->id) $activeGroup = $group;

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