Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -66,22 +66,38 @@ angular | |||||
} | } | ||||
}) | }) | ||||
.state('dashboard.flow', { | |||||
templateUrl: 'app/views/flow.html', | |||||
url: '/flow/:app', | |||||
controller: 'FlowCtl', | |||||
.state('dashboard.flowV1', { | |||||
templateUrl: 'app/views/flow_old.html', | |||||
url: '/v1/flow/:app', | |||||
controller: 'FlowControllerV1', | |||||
resolve: { | resolve: { | ||||
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | ||||
return $ocLazyLoad.load({ | return $ocLazyLoad.load({ | ||||
name: 'sentinelDashboardApp', | name: 'sentinelDashboardApp', | ||||
files: [ | files: [ | ||||
'app/scripts/controllers/flow.js', | |||||
'app/scripts/controllers/flow_old.js', | |||||
] | ] | ||||
}); | }); | ||||
}] | }] | ||||
} | } | ||||
}) | }) | ||||
.state('dashboard.flow', { | |||||
templateUrl: 'app/views/flow.html', | |||||
url: '/flow/:app', | |||||
controller: 'FlowController', | |||||
resolve: { | |||||
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | |||||
return $ocLazyLoad.load({ | |||||
name: 'sentinelDashboardApp', | |||||
files: [ | |||||
'app/scripts/controllers/flow.js', | |||||
] | |||||
}); | |||||
}] | |||||
} | |||||
}) | |||||
.state('dashboard.paramFlow', { | .state('dashboard.paramFlow', { | ||||
templateUrl: 'app/views/param_flow.html', | templateUrl: 'app/views/param_flow.html', | ||||
url: '/paramFlow/:app', | url: '/paramFlow/:app', | ||||
@@ -98,6 +114,22 @@ angular | |||||
} | } | ||||
}) | }) | ||||
.state('dashboard.clusterAll', { | |||||
templateUrl: 'app/views/cluster.html', | |||||
url: '/cluster/:app', | |||||
controller: 'SentinelClusterController', | |||||
resolve: { | |||||
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | |||||
return $ocLazyLoad.load({ | |||||
name: 'sentinelDashboardApp', | |||||
files: [ | |||||
'app/scripts/controllers/cluster.js', | |||||
] | |||||
}); | |||||
}] | |||||
} | |||||
}) | |||||
.state('dashboard.authority', { | .state('dashboard.authority', { | ||||
templateUrl: 'app/views/authority.html', | templateUrl: 'app/views/authority.html', | ||||
url: '/authority/:app', | url: '/authority/:app', | ||||
@@ -0,0 +1,237 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | |||||
app.controller('SentinelClusterController', ['$scope', '$stateParams', 'ngDialog', | |||||
'MachineService', 'ClusterStateService', | |||||
function ($scope, $stateParams, ngDialog, MachineService, ClusterStateService) { | |||||
$scope.app = $stateParams.app; | |||||
const UNSUPPORTED_CODE = 4041; | |||||
const CLUSTER_MODE_CLIENT = 0; | |||||
const CLUSTER_MODE_SERVER = 1; | |||||
$scope.macsInputConfig = { | |||||
searchField: ['text', 'value'], | |||||
persist: true, | |||||
create: false, | |||||
maxItems: 1, | |||||
render: { | |||||
item: function (data, escape) { | |||||
return '<div>' + escape(data.text) + '</div>'; | |||||
} | |||||
}, | |||||
onChange: function (value, oldValue) { | |||||
$scope.macInputModel = value; | |||||
} | |||||
}; | |||||
function convertSetToString(set) { | |||||
if (set === undefined) { | |||||
return ''; | |||||
} | |||||
let s = ''; | |||||
for (let i = 0; i < set.length; i++) { | |||||
s = s + set[i]; | |||||
if (i < set.length - 1) { | |||||
s = s + ','; | |||||
} | |||||
} | |||||
return s; | |||||
} | |||||
function convertStrToNamespaceSet(str) { | |||||
if (str === undefined || str == '') { | |||||
return []; | |||||
} | |||||
let arr = []; | |||||
let spliced = str.split(','); | |||||
spliced.forEach((v) => { | |||||
arr.push(v.trim()); | |||||
}); | |||||
return arr; | |||||
} | |||||
function fetchMachineClusterState() { | |||||
if (!$scope.macInputModel) { | |||||
return; | |||||
} | |||||
let mac = $scope.macInputModel.split(':'); | |||||
ClusterStateService.fetchClusterUniversalState($scope.app, mac[0], mac[1]).success(function (data) { | |||||
if (data.code == 0 && data.data) { | |||||
$scope.loadError = undefined; | |||||
$scope.stateVO = data.data; | |||||
$scope.stateVO.currentMode = $scope.stateVO.stateInfo.mode; | |||||
if ($scope.stateVO.server && $scope.stateVO.server.namespaceSet) { | |||||
$scope.stateVO.server.namespaceSetStr = convertSetToString($scope.stateVO.server.namespaceSet); | |||||
} | |||||
} else { | |||||
$scope.stateVO = {}; | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
$scope.loadError = {message: '机器 ' + mac[0] + ':' + mac[1] + ' 的 Sentinel 客户端版本不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'} | |||||
} else { | |||||
$scope.loadError = {message: data.msg}; | |||||
} | |||||
} | |||||
}).error((data, header, config, status) => { | |||||
$scope.loadError = {message: '未知错误'}; | |||||
}); | |||||
} | |||||
fetchMachineClusterState(); | |||||
function checkValidClientConfig(stateVO) { | |||||
if (!stateVO.client || !stateVO.client.clientConfig) { | |||||
alert('不合法的配置'); | |||||
return false; | |||||
} | |||||
let config = stateVO.client.clientConfig; | |||||
if (!config.serverHost || config.serverHost.trim() == '') { | |||||
alert('请输入有效的 Token Server IP'); | |||||
return false; | |||||
} | |||||
if (config.serverPort === undefined || config.serverPort <= 0 || config.serverPort > 65535) { | |||||
alert('请输入有效的 Token Server 端口'); | |||||
return false; | |||||
} | |||||
if (config.requestTimeout === undefined || config.requestTimeout <= 0) { | |||||
alert('请输入有效的请求超时时长'); | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
function sendClusterClientRequest(stateVO) { | |||||
if (!checkValidClientConfig(stateVO)) { | |||||
return; | |||||
} | |||||
if (!$scope.macInputModel) { | |||||
return; | |||||
} | |||||
let mac = $scope.macInputModel.split(':'); | |||||
let request = { | |||||
app: $scope.app, | |||||
ip: mac[0], | |||||
port: mac[1], | |||||
}; | |||||
request.mode = CLUSTER_MODE_CLIENT; | |||||
request.clientConfig = stateVO.client.clientConfig; | |||||
ClusterStateService.modifyClusterConfig(request).success(function (data) { | |||||
if (data.code == 0 && data.data) { | |||||
alert('修改集群限流客户端配置成功'); | |||||
window.location.reload(); | |||||
} else { | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
alert('机器 ' + mac[0] + ':' + mac[1] + ' 的 Sentinel 客户端版本不支持集群限流客户端,请升级至 1.4.0 以上版本并引入相关依赖。'); | |||||
} else { | |||||
alert('修改失败:' + data.msg); | |||||
} | |||||
} | |||||
}).error((data, header, config, status) => { | |||||
alert('未知错误'); | |||||
}); | |||||
} | |||||
function checkValidServerConfig(stateVO) { | |||||
if (!stateVO.server || !stateVO.server.transport) { | |||||
alert('不合法的配置'); | |||||
return false; | |||||
} | |||||
if (stateVO.server.namespaceSetStr === undefined || stateVO.server.namespaceSetStr == '') { | |||||
alert('请输入有效的命名空间集合(多个 namespace 以 , 分隔)'); | |||||
return false; | |||||
} | |||||
let transportConfig = stateVO.server.transport; | |||||
if (transportConfig.port === undefined || transportConfig.port <= 0 || transportConfig.port > 65535) { | |||||
alert('请输入有效的 Token Server 端口'); | |||||
return false; | |||||
} | |||||
// if (transportConfig.idleSeconds === undefined || transportConfig.idleSeconds <= 0) { | |||||
// alert('请输入有效的连接清理时长 (idleSeconds)'); | |||||
// return false; | |||||
// } | |||||
return true; | |||||
} | |||||
function sendClusterServerRequest(stateVO) { | |||||
if (!checkValidServerConfig(stateVO)) { | |||||
return; | |||||
} | |||||
if (!$scope.macInputModel) { | |||||
return; | |||||
} | |||||
let mac = $scope.macInputModel.split(':'); | |||||
let request = { | |||||
app: $scope.app, | |||||
ip: mac[0], | |||||
port: mac[1], | |||||
}; | |||||
request.mode = CLUSTER_MODE_SERVER; | |||||
request.flowConfig = stateVO.server.flow; | |||||
request.transportConfig = stateVO.server.transport; | |||||
request.namespaceSet = convertStrToNamespaceSet(stateVO.server.namespaceSetStr); | |||||
ClusterStateService.modifyClusterConfig(request).success(function (data) { | |||||
if (data.code == 0 && data.data) { | |||||
alert('修改集群限流服务端配置成功'); | |||||
window.location.reload(); | |||||
} else { | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
alert('机器 ' + mac[0] + ':' + mac[1] + ' 的 Sentinel 客户端版本不支持集群限流服务端,请升级至 1.4.0 以上版本并引入相关依赖。'); | |||||
} else { | |||||
alert('修改失败:' + data.msg); | |||||
} | |||||
} | |||||
}).error((data, header, config, status) => { | |||||
alert('未知错误'); | |||||
}); | |||||
} | |||||
$scope.saveConfig = () => { | |||||
let ok = confirm('是否确定修改集群限流配置?'); | |||||
if (!ok) { | |||||
return; | |||||
} | |||||
let mode = $scope.stateVO.stateInfo.mode; | |||||
if (mode != 1 && mode != 0) { | |||||
alert('未知的集群限流模式'); | |||||
return; | |||||
} | |||||
if (mode == 0) { | |||||
sendClusterClientRequest($scope.stateVO); | |||||
} else { | |||||
sendClusterServerRequest($scope.stateVO); | |||||
} | |||||
}; | |||||
function queryAppMachines() { | |||||
MachineService.getAppMachines($scope.app).success( | |||||
function (data) { | |||||
if (data.code == 0) { | |||||
// $scope.machines = data.data; | |||||
if (data.data) { | |||||
$scope.machines = []; | |||||
$scope.macsInputOptions = []; | |||||
data.data.forEach(function (item) { | |||||
if (item.health) { | |||||
$scope.macsInputOptions.push({ | |||||
text: item.ip + ':' + item.port, | |||||
value: item.ip + ':' + item.port | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
if ($scope.macsInputOptions.length > 0) { | |||||
$scope.macInputModel = $scope.macsInputOptions[0].value; | |||||
} | |||||
} else { | |||||
$scope.macsInputOptions = []; | |||||
} | |||||
} | |||||
); | |||||
}; | |||||
$scope.$watch('macInputModel', function () { | |||||
if ($scope.macInputModel) { | |||||
fetchMachineClusterState(); | |||||
} | |||||
}); | |||||
queryAppMachines(); | |||||
}]); |
@@ -1,6 +1,6 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | var app = angular.module('sentinelDashboardApp'); | ||||
app.controller('FlowCtl', ['$scope', '$stateParams', 'FlowService', 'ngDialog', | |||||
app.controller('FlowController', ['$scope', '$stateParams', 'FlowServiceV2', 'ngDialog', | |||||
'MachineService', | 'MachineService', | ||||
function ($scope, $stateParams, FlowService, ngDialog, | function ($scope, $stateParams, FlowService, ngDialog, | ||||
MachineService) { | MachineService) { | ||||
@@ -72,7 +72,11 @@ app.controller('FlowCtl', ['$scope', '$stateParams', 'FlowService', 'ngDialog', | |||||
app: $scope.app, | app: $scope.app, | ||||
ip: mac[0], | ip: mac[0], | ||||
port: mac[1], | port: mac[1], | ||||
limitApp: 'default' | |||||
limitApp: 'default', | |||||
clusterMode: false, | |||||
clusterConfig: { | |||||
thresholdType: 0 | |||||
} | |||||
}; | }; | ||||
$scope.flowRuleDialog = { | $scope.flowRuleDialog = { | ||||
title: '新增流控规则', | title: '新增流控规则', | ||||
@@ -0,0 +1,203 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | |||||
app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', 'ngDialog', | |||||
'MachineService', | |||||
function ($scope, $stateParams, FlowService, ngDialog, | |||||
MachineService) { | |||||
$scope.app = $stateParams.app; | |||||
$scope.rulesPageConfig = { | |||||
pageSize: 10, | |||||
currentPageIndex: 1, | |||||
totalPage: 1, | |||||
totalCount: 0, | |||||
}; | |||||
$scope.macsInputConfig = { | |||||
searchField: ['text', 'value'], | |||||
persist: true, | |||||
create: false, | |||||
maxItems: 1, | |||||
render: { | |||||
item: function (data, escape) { | |||||
return '<div>' + escape(data.text) + '</div>'; | |||||
} | |||||
}, | |||||
onChange: function (value, oldValue) { | |||||
$scope.macInputModel = value; | |||||
} | |||||
}; | |||||
getMachineRules(); | |||||
function getMachineRules() { | |||||
if (!$scope.macInputModel) { | |||||
return; | |||||
} | |||||
var mac = $scope.macInputModel.split(':'); | |||||
FlowService.queryMachineRules($scope.app, mac[0], mac[1]).success( | |||||
function (data) { | |||||
if (data.code == 0 && data.data) { | |||||
$scope.rules = data.data; | |||||
$scope.rulesPageConfig.totalCount = $scope.rules.length; | |||||
} else { | |||||
$scope.rules = []; | |||||
$scope.rulesPageConfig.totalCount = 0; | |||||
} | |||||
}); | |||||
}; | |||||
$scope.getMachineRules = getMachineRules; | |||||
var flowRuleDialog; | |||||
$scope.editRule = function (rule) { | |||||
$scope.currentRule = rule; | |||||
$scope.flowRuleDialog = { | |||||
title: '编辑流控规则', | |||||
type: 'edit', | |||||
confirmBtnText: '保存', | |||||
showAdvanceButton: rule.controlBehavior == 0 && rule.strategy == 0 | |||||
}; | |||||
flowRuleDialog = ngDialog.open({ | |||||
template: '/app/views/dialog/flow-rule-dialog.html', | |||||
width: 680, | |||||
overlay: true, | |||||
scope: $scope | |||||
}); | |||||
}; | |||||
$scope.addNewRule = function () { | |||||
var mac = $scope.macInputModel.split(':'); | |||||
$scope.currentRule = { | |||||
grade: 1, | |||||
strategy: 0, | |||||
controlBehavior: 0, | |||||
app: $scope.app, | |||||
ip: mac[0], | |||||
port: mac[1], | |||||
limitApp: 'default' | |||||
}; | |||||
$scope.flowRuleDialog = { | |||||
title: '新增流控规则', | |||||
type: 'add', | |||||
confirmBtnText: '新增', | |||||
showAdvanceButton: true, | |||||
}; | |||||
flowRuleDialog = ngDialog.open({ | |||||
template: '/app/views/dialog/flow-rule-dialog.html', | |||||
width: 680, | |||||
overlay: true, | |||||
scope: $scope | |||||
}); | |||||
}; | |||||
$scope.saveRule = function () { | |||||
if (!FlowService.checkRuleValid($scope.currentRule)) { | |||||
return; | |||||
} | |||||
if ($scope.flowRuleDialog.type === 'add') { | |||||
addNewRule($scope.currentRule); | |||||
} else if ($scope.flowRuleDialog.type === 'edit') { | |||||
saveRule($scope.currentRule, true); | |||||
} | |||||
}; | |||||
var confirmDialog; | |||||
$scope.deleteRule = function (rule) { | |||||
$scope.currentRule = rule; | |||||
$scope.confirmDialog = { | |||||
title: '删除流控规则', | |||||
type: 'delete_rule', | |||||
attentionTitle: '请确认是否删除如下流控规则', | |||||
attention: '资源名: ' + rule.resource + ', 流控应用: ' + rule.limitApp | |||||
+ ', 阈值类型: ' + (rule.grade == 0 ? '线程数' : 'QPS') + ', 阈值: ' + rule.count, | |||||
confirmBtnText: '删除', | |||||
}; | |||||
confirmDialog = ngDialog.open({ | |||||
template: '/app/views/dialog/confirm-dialog.html', | |||||
scope: $scope, | |||||
overlay: true | |||||
}); | |||||
}; | |||||
$scope.confirm = function () { | |||||
if ($scope.confirmDialog.type === 'delete_rule') { | |||||
deleteRule($scope.currentRule); | |||||
} else { | |||||
console.error('error'); | |||||
} | |||||
}; | |||||
function deleteRule(rule) { | |||||
FlowService.deleteRule(rule).success(function (data) { | |||||
if (data.code == 0) { | |||||
getMachineRules(); | |||||
confirmDialog.close(); | |||||
} else { | |||||
alert('失败!'); | |||||
} | |||||
}); | |||||
}; | |||||
function addNewRule(rule) { | |||||
FlowService.newRule(rule).success(function (data) { | |||||
if (data.code == 0) { | |||||
getMachineRules(); | |||||
flowRuleDialog.close(); | |||||
} else { | |||||
alert('失败!'); | |||||
} | |||||
}); | |||||
}; | |||||
$scope.onOpenAdvanceClick = function () { | |||||
$scope.flowRuleDialog.showAdvanceButton = false; | |||||
}; | |||||
$scope.onCloseAdvanceClick = function () { | |||||
$scope.flowRuleDialog.showAdvanceButton = true; | |||||
}; | |||||
function saveRule(rule, edit) { | |||||
FlowService.saveRule(rule).success(function (data) { | |||||
if (data.code == 0) { | |||||
getMachineRules(); | |||||
if (edit) { | |||||
flowRuleDialog.close(); | |||||
} else { | |||||
confirmDialog.close(); | |||||
} | |||||
} else { | |||||
alert('失败!'); | |||||
} | |||||
}); | |||||
} | |||||
queryAppMachines(); | |||||
function queryAppMachines() { | |||||
MachineService.getAppMachines($scope.app).success( | |||||
function (data) { | |||||
if (data.code == 0) { | |||||
// $scope.machines = data.data; | |||||
if (data.data) { | |||||
$scope.machines = []; | |||||
$scope.macsInputOptions = []; | |||||
data.data.forEach(function (item) { | |||||
if (item.health) { | |||||
$scope.macsInputOptions.push({ | |||||
text: item.ip + ':' + item.port, | |||||
value: item.ip + ':' + item.port | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
if ($scope.macsInputOptions.length > 0) { | |||||
$scope.macInputModel = $scope.macsInputOptions[0].value; | |||||
} | |||||
} else { | |||||
$scope.macsInputOptions = []; | |||||
} | |||||
} | |||||
); | |||||
}; | |||||
$scope.$watch('macInputModel', function () { | |||||
if ($scope.macInputModel) { | |||||
getMachineRules(); | |||||
} | |||||
}); | |||||
}]); |
@@ -1,7 +1,7 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | var app = angular.module('sentinelDashboardApp'); | ||||
app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | ||||
'ngDialog', 'FlowService', 'DegradeService', 'AuthorityRuleService', 'ParamFlowService', 'MachineService', | |||||
'ngDialog', 'FlowServiceV2', 'DegradeService', 'AuthorityRuleService', 'ParamFlowService', 'MachineService', | |||||
'$interval', '$location', '$timeout', | '$interval', '$location', '$timeout', | ||||
function ($scope, $stateParams, IdentityService, ngDialog, | function ($scope, $stateParams, IdentityService, ngDialog, | ||||
FlowService, DegradeService, AuthorityRuleService, ParamFlowService, MachineService, $interval, $location, $timeout) { | FlowService, DegradeService, AuthorityRuleService, ParamFlowService, MachineService, $interval, $location, $timeout) { | ||||
@@ -33,9 +33,13 @@ | |||||
</li> | </li> | ||||
<li ui-sref-active="active"> | <li ui-sref-active="active"> | ||||
<a ui-sref="dashboard.flow({app: entry.app})"> | |||||
<a ui-sref="dashboard.flowV1({app: entry.app})"> | |||||
<i class="glyphicon glyphicon-filter"></i> 流控规则</a> | <i class="glyphicon glyphicon-filter"></i> 流控规则</a> | ||||
</li> | </li> | ||||
<!--<li ui-sref-active="active">--> | |||||
<!--<a ui-sref="dashboard.flow({app: entry.app})">--> | |||||
<!--<i class="glyphicon glyphicon-filter"></i> 流控规则 V1</a>--> | |||||
<!--</li>--> | |||||
<li ui-sref-active="active"> | <li ui-sref-active="active"> | ||||
<a ui-sref="dashboard.degrade({app: entry.app})"> | <a ui-sref="dashboard.degrade({app: entry.app})"> | ||||
<i class="glyphicon glyphicon-flash"></i> 降级规则</a> | <i class="glyphicon glyphicon-flash"></i> 降级规则</a> | ||||
@@ -52,6 +56,10 @@ | |||||
<a ui-sref="dashboard.authority({app: entry.app})"> | <a ui-sref="dashboard.authority({app: entry.app})"> | ||||
<i class="glyphicon glyphicon-check"></i> 授权规则</a> | <i class="glyphicon glyphicon-check"></i> 授权规则</a> | ||||
</li> | </li> | ||||
<li ui-sref-active="active"> | |||||
<a ui-sref="dashboard.clusterAll({app: entry.app})"> | |||||
<i class="glyphicon glyphicon-cloud"></i> 集群限流</a> | |||||
</li> | |||||
<li ui-sref-active="active"> | <li ui-sref-active="active"> | ||||
<a ui-sref="dashboard.machine({app: entry.app})"> | <a ui-sref="dashboard.machine({app: entry.app})"> | ||||
<i class="glyphicon glyphicon-th-list"></i> 机器列表</a> | <i class="glyphicon glyphicon-th-list"></i> 机器列表</a> | ||||
@@ -0,0 +1,28 @@ | |||||
/** | |||||
* Parameter flow control service. | |||||
* | |||||
* @author Eric Zhao | |||||
*/ | |||||
angular.module('sentinelDashboardApp').service('ClusterStateService', ['$http', function ($http) { | |||||
this.fetchClusterUniversalState = function(app, ip, port) { | |||||
var param = { | |||||
app: app, | |||||
ip: ip, | |||||
port: port | |||||
}; | |||||
return $http({ | |||||
url: '/cluster/state', | |||||
params: param, | |||||
method: 'GET' | |||||
}); | |||||
}; | |||||
this.modifyClusterConfig = function(config) { | |||||
return $http({ | |||||
url: '/cluster/config/modify', | |||||
data: config, | |||||
method: 'POST' | |||||
}); | |||||
}; | |||||
}]); |
@@ -1,6 +1,6 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | var app = angular.module('sentinelDashboardApp'); | ||||
app.service('FlowService', ['$http', function ($http) { | |||||
app.service('FlowServiceV1', ['$http', function ($http) { | |||||
this.queryMachineRules = function (app, ip, port) { | this.queryMachineRules = function (app, ip, port) { | ||||
var param = { | var param = { | ||||
app: app, | app: app, | ||||
@@ -8,7 +8,7 @@ app.service('FlowService', ['$http', function ($http) { | |||||
port: port | port: port | ||||
}; | }; | ||||
return $http({ | return $http({ | ||||
url: 'flow/rules.json', | |||||
url: '/v1/flow/rules', | |||||
params: param, | params: param, | ||||
method: 'GET' | method: 'GET' | ||||
}); | }); | ||||
@@ -31,9 +31,9 @@ app.service('FlowService', ['$http', function ($http) { | |||||
}; | }; | ||||
return $http({ | return $http({ | ||||
url: '/flow/new.json', | |||||
params: param, | |||||
method: 'GET' | |||||
url: '/v1/flow/rule', | |||||
data: rule, | |||||
method: 'POST' | |||||
}); | }); | ||||
}; | }; | ||||
@@ -52,9 +52,9 @@ app.service('FlowService', ['$http', function ($http) { | |||||
}; | }; | ||||
return $http({ | return $http({ | ||||
url: '/flow/save.json', | |||||
url: '/v1/flow/save.json', | |||||
params: param, | params: param, | ||||
method: 'GET' | |||||
method: 'PUT' | |||||
}); | }); | ||||
}; | }; | ||||
@@ -65,9 +65,9 @@ app.service('FlowService', ['$http', function ($http) { | |||||
}; | }; | ||||
return $http({ | return $http({ | ||||
url: '/flow/delete.json', | |||||
url: '/v1/flow/delete.json', | |||||
params: param, | params: param, | ||||
method: 'GET' | |||||
method: 'DELETE' | |||||
}); | }); | ||||
}; | }; | ||||
@@ -0,0 +1,85 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | |||||
app.service('FlowServiceV2', ['$http', function ($http) { | |||||
this.queryMachineRules = function (app, ip, port) { | |||||
var param = { | |||||
app: app, | |||||
ip: ip, | |||||
port: port | |||||
}; | |||||
return $http({ | |||||
url: '/v2/flow/rules', | |||||
params: param, | |||||
method: 'GET' | |||||
}); | |||||
}; | |||||
this.newRule = function (rule) { | |||||
return $http({ | |||||
url: '/v2/flow/rule', | |||||
data: rule, | |||||
method: 'POST' | |||||
}); | |||||
}; | |||||
this.saveRule = function (rule) { | |||||
return $http({ | |||||
url: '/v2/flow/rule/' + rule.id, | |||||
data: rule, | |||||
method: 'PUT' | |||||
}); | |||||
}; | |||||
this.deleteRule = function (rule) { | |||||
return $http({ | |||||
url: '/v2/flow/rule/' + rule.id, | |||||
method: 'DELETE' | |||||
}); | |||||
}; | |||||
function notNumberAtLeastZero(num) { | |||||
return num === undefined || num === '' || isNaN(num) || num < 0; | |||||
} | |||||
function notNumberGreaterThanZero(num) { | |||||
return num === undefined || num === '' || isNaN(num) || num <= 0; | |||||
} | |||||
this.checkRuleValid = function (rule) { | |||||
if (rule.resource === undefined || rule.resource === '') { | |||||
alert('资源名称不能为空'); | |||||
return false; | |||||
} | |||||
if (rule.count === undefined || rule.count < 0) { | |||||
alert('限流阈值必须大于等于 0'); | |||||
return false; | |||||
} | |||||
if (rule.strategy === undefined || rule.strategy < 0) { | |||||
alert('无效的流控模式'); | |||||
return false; | |||||
} | |||||
if (rule.strategy == 1 || rule.strategy == 2) { | |||||
if (rule.refResource === undefined || rule.refResource == '') { | |||||
alert('请填写关联资源或入口'); | |||||
return false; | |||||
} | |||||
} | |||||
if (rule.controlBehavior === undefined || rule.controlBehavior < 0) { | |||||
alert('无效的流控整形方式'); | |||||
return false; | |||||
} | |||||
if (rule.controlBehavior == 1 && notNumberGreaterThanZero(rule.warmUpPeriodSec)) { | |||||
alert('预热时长必须大于 0'); | |||||
return false; | |||||
} | |||||
if (rule.controlBehavior == 2 && notNumberGreaterThanZero(rule.maxQueueingTimeMs)) { | |||||
alert('排队超时时间必须大于 0'); | |||||
return false; | |||||
} | |||||
if (rule.clusterMode && (rule.clusterConfig === undefined || rule.clusterConfig.thresholdType === undefined)) { | |||||
alert('集群限流配置不正确'); | |||||
return false; | |||||
} | |||||
return true; | |||||
}; | |||||
}]); |
@@ -0,0 +1,96 @@ | |||||
<div class="row" style="margin-left: 1px; margin-top:10px; height: 50px;"> | |||||
<div class="col-md-6" style="margin-bottom: 10px;"> | |||||
<span style="font-size: 30px;font-weight: bold;">{{app}}</span> | |||||
</div> | |||||
</div> | |||||
<div class="separator"></div> | |||||
<div class="container-fluid"> | |||||
<div class="row" style="margin-top: 20px; margin-bottom: 20px;"> | |||||
<div class="col-md-12"> | |||||
<div class="card"> | |||||
<div class="inputs-header"> | |||||
<span class="brand" style="font-size: 13px;">集群限流</span> | |||||
<button class="btn btn-primary" style="float: right; margin-right: 10px; height: 30px;font-size: 12px;" ng-click="getMachineRules()">刷新</button> | |||||
<input class="form-control witdh-200" placeholder="关键字" ng-model="searchKey"> | |||||
<div class="control-group" style="float:right;margin-right: 10px;margin-bottom: -10px;"> | |||||
<selectize id="gsInput" class="selectize-input-200" config="macsInputConfig" options="macsInputOptions" ng-model="macInputModel" | |||||
placeholder="机器"></selectize> | |||||
</div> | |||||
</div> | |||||
<!-- error panel --> | |||||
<div class="row clearfix" ng-if="loadError"> | |||||
<div class="col-md-6 col-md-offset-3"> | |||||
<div class="panel panel-default"> | |||||
<div class="panel-body"> | |||||
<center> | |||||
<p>{{loadError.message}}</p> | |||||
</center> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!--.tools-header --> | |||||
<div class="card-body" style="padding: 0px 0px;"> | |||||
<!--<span class="brand" style="font-weight:bold;">集群限流状态</span>--> | |||||
<form role="form" class="form-horizontal"> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">当前模式</label> | |||||
<p class="col-sm-6 control-label" style="text-align: left; font-weight: normal;" ng-if="stateVO.currentMode == 0">Client</p> | |||||
<p class="col-sm-6 control-label" style="text-align: left; font-weight: normal;" ng-if="stateVO.currentMode == 1">Server</p> | |||||
<p class="col-sm-6 control-label" style="text-align: left; font-weight: normal;" ng-if="stateVO.currentMode == -1">未开启</p> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">集群限流模式变换</label> | |||||
<div class="col-sm-4"> | |||||
<div class="form-control highlight-border" align="center"> | |||||
<input type="radio" name="mode" value="0" ng-model='stateVO.stateInfo.mode' ng-disabled="!stateVO.stateInfo.clientAvailable" /> Client | |||||
<input type="radio" name="mode" value="1" ng-model='stateVO.stateInfo.mode' ng-disabled="!stateVO.stateInfo.serverAvailable" /> Server | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
<!-- no-cluster-mode-available-panel.start --> | |||||
<div ng-if="!stateVO.stateInfo.clientAvailable && !stateVO.stateInfo.serverAvailable"> | |||||
<!-- error panel --> | |||||
<div class="row clearfix"> | |||||
<div class="col-md-6 col-md-offset-3"> | |||||
<div class="panel panel-default"> | |||||
<div class="panel-body"> | |||||
<center> | |||||
<p>该机器未引入 Sentinel 集群限流客户端或服务端的相关依赖,请引入相关依赖。</p> | |||||
</center> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!-- no-cluster-mode-available-panel.stop --> | |||||
<div ng-if="stateVO.stateInfo.clientAvailable || stateVO.stateInfo.serverAvailable"> | |||||
<div ng-if="stateVO.stateInfo.clientAvailable && stateVO.stateInfo.mode == 0"> | |||||
<div ng-include="'app/views/cluster/client.html'"></div> | |||||
</div> | |||||
<div ng-if="stateVO.stateInfo.serverAvailable && stateVO.stateInfo.mode == 1"> | |||||
<div ng-include="'app/views/cluster/server.html'"></div> | |||||
</div> | |||||
<div class="separator"></div> | |||||
<div clss="row" style="margin-top: 20px;"> | |||||
<button style="margin: 0 10px 10px 10px;" class="btn btn-outline-success" ng-click="saveConfig()">保存配置</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!-- .card-body --> | |||||
</div> | |||||
<!-- .card --> | |||||
</div> | |||||
<!-- .col-md-12 --> | |||||
</div> | |||||
<!-- --> | |||||
</div> | |||||
<!-- .container-fluid --> |
@@ -0,0 +1,22 @@ | |||||
<div class="row clearfix"> | |||||
<form role="form" class="form-horizontal"> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">Token Server IP</label> | |||||
<div class="col-sm-4"> | |||||
<input type="text" class="form-control highlight-border" ng-model='stateVO.client.clientConfig.serverHost' placeholder='请指定 Token Server IP' /> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">Token Server 端口</label> | |||||
<div class="col-sm-4"> | |||||
<input type="number" min="0" max="65535" required class="form-control highlight-border" ng-model='stateVO.client.clientConfig.serverPort' placeholder='请指定 Token Server 端口' /> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">请求超时时间(ms)</label> | |||||
<div class="col-sm-4"> | |||||
<input type="number" min="0" required class="form-control highlight-border" ng-model='stateVO.client.clientConfig.requestTimeout' placeholder='请指定请求超时时间(ms)' /> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> |
@@ -0,0 +1,16 @@ | |||||
<div class="row clearfix"> | |||||
<form role="form" class="form-horizontal"> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">Token Server 端口</label> | |||||
<div class="col-sm-4"> | |||||
<input type="number" min="0" max="65535" required class="form-control highlight-border" ng-model='stateVO.server.transport.port' placeholder='请指定 Token Server 端口' /> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">命名空间集合</label> | |||||
<div class="col-sm-4"> | |||||
<input type="text" required class="form-control highlight-border" ng-model='stateVO.server.namespaceSetStr' placeholder='请指定服务端服务的命名空间集合(以,分隔)' /> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> |
@@ -30,9 +30,39 @@ | |||||
<input type="radio" name="grade" value="0" ng-model='currentRule.grade' /> 线程数 | <input type="radio" name="grade" value="0" ng-model='currentRule.grade' /> 线程数 | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<label class="col-sm-2 control-label">单机阈值</label> | |||||
<div class="col-sm-3"> | |||||
<input type='number' min="0" class="form-control highlight-border" ng-model='currentRule.count' placeholder="单机阈值" /> | |||||
<div ng-if="!currentRule.clusterMode"> | |||||
<label class="col-sm-2 control-label">单机阈值</label> | |||||
<div class="col-sm-3"> | |||||
<input type='number' min="0" class="form-control highlight-border" ng-model='currentRule.count' placeholder="单机阈值" /> | |||||
</div> | |||||
</div> | |||||
<div ng-if="currentRule.clusterMode && currentRule.clusterConfig.thresholdType == 0"> | |||||
<label class="col-sm-2 control-label">均摊阈值</label> | |||||
<div class="col-sm-3"> | |||||
<input type='number' min="0" class="form-control highlight-border" ng-model='currentRule.count' placeholder="单机均摊阈值" /> | |||||
</div> | |||||
</div> | |||||
<div ng-if="currentRule.clusterMode && currentRule.clusterConfig.thresholdType == 1"> | |||||
<label class="col-sm-2 control-label">集群阈值</label> | |||||
<div class="col-sm-3"> | |||||
<input type='number' min="0" class="form-control highlight-border" ng-model='currentRule.count' placeholder="集群总体阈值" /> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">是否集群</label> | |||||
<div class="col-sm-2"> | |||||
<input type="checkbox" name="clusterMode" ng-model="currentRule.clusterMode"> | |||||
</div> | |||||
<div ng-if="currentRule.clusterMode"> | |||||
<label class="col-sm-3 control-label">集群阈值模式</label> | |||||
<div class="col-sm-4"> | |||||
<div class="form-control highlight-border" align="center"> | |||||
<input type="radio" name="clusterThresholdType" value="0" ng-model='currentRule.clusterConfig.thresholdType' /> 单机均摊 | |||||
<input type="radio" name="clusterThresholdType" value="1" ng-model='currentRule.clusterConfig.thresholdType' /> Global | |||||
</div> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -3,8 +3,11 @@ | |||||
<span style="font-size: 30px;font-weight: bold;">{{app}}</span> | <span style="font-size: 30px;font-weight: bold;">{{app}}</span> | ||||
</div> | </div> | ||||
<div class="col-md-6"> | <div class="col-md-6"> | ||||
<button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-disabled="!macInputModel" ng-click="addNewRule()"> | |||||
<i class="fa fa-plus"></i> 新增流控规则</button> | |||||
<button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-click="addNewRule()"> | |||||
<i class="fa fa-plus"></i> 新增流控规则 | |||||
</button> | |||||
<a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.flowV1({app: app})"> | |||||
回到旧版(单机)</a> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -16,13 +19,7 @@ | |||||
<div class="card"> | <div class="card"> | ||||
<div class="inputs-header"> | <div class="inputs-header"> | ||||
<span class="brand" style="font-size: 13px;">流控规则</span> | <span class="brand" style="font-size: 13px;">流控规则</span> | ||||
<!--<button class="btn btn-danger" style="float: right;margin-right: 10px;height: 30px;font-size: 12px;" ng-click="disableAll()">全部禁用</button>--> | |||||
<button class="btn btn-primary" style="float: right; margin-right: 10px; height: 30px;font-size: 12px;" ng-click="getMachineRules()">刷新</button> | |||||
<input class="form-control witdh-200" placeholder="关键字" ng-model="searchKey"> | <input class="form-control witdh-200" placeholder="关键字" ng-model="searchKey"> | ||||
<div class="control-group" style="float:right;margin-right: 10px;margin-bottom: -10px;"> | |||||
<selectize id="gsInput" class="selectize-input-200" config="macsInputConfig" options="macsInputOptions" ng-model="macInputModel" | |||||
placeholder="机器"></selectize> | |||||
</div> | |||||
</div> | </div> | ||||
<!--.tools-header --> | <!--.tools-header --> | ||||
@@ -36,21 +33,21 @@ | |||||
<td style="width: 10%;"> | <td style="width: 10%;"> | ||||
流控应用 | 流控应用 | ||||
</td> | </td> | ||||
<td style="width: 10%;"> | |||||
<td style="width: 8%;"> | |||||
流控模式 | 流控模式 | ||||
</td> | </td> | ||||
<td style="width: 10%;"> | |||||
<td style="width: 8%;"> | |||||
阈值类型 | 阈值类型 | ||||
</td> | </td> | ||||
<td style="width: 10%;"> | |||||
<td style="width: 8%;"> | |||||
单机阈值 | 单机阈值 | ||||
</td> | </td> | ||||
<td style="width: 10%;"> | |||||
<td style="width: 8%;"> | |||||
是否集群 | |||||
</td> | |||||
<td style="width: 8%;"> | |||||
流控效果 | 流控效果 | ||||
</td> | </td> | ||||
<!--<td style="width: 8%;">--> | |||||
<!--状态--> | |||||
<!--</td>--> | |||||
<td style="width: 12%;"> | <td style="width: 12%;"> | ||||
操作 | 操作 | ||||
</td> | </td> | ||||
@@ -67,15 +64,20 @@ | |||||
<span ng-if="rule.strategy == 2">链路</span> | <span ng-if="rule.strategy == 2">链路</span> | ||||
</td> | </td> | ||||
<td> | <td> | ||||
{{rule.grade==0 ? '线程数' : 'QPS'}} | |||||
{{rule.grade == 0 ? '线程数' : 'QPS'}} | |||||
</td> | </td> | ||||
<td style="word-wrap:break-word;word-break:break-all;"> | <td style="word-wrap:break-word;word-break:break-all;"> | ||||
{{rule.count}} | {{rule.count}} | ||||
</td> | </td> | ||||
<td> | |||||
<span ng-if="rule.clusterMode">是</span> | |||||
<span ng-if="!rule.clusterMode">否</span> | |||||
</td> | |||||
<td> | <td> | ||||
<span ng-if="rule.controlBehavior == 0">快速失败</span> | <span ng-if="rule.controlBehavior == 0">快速失败</span> | ||||
<span ng-if="rule.controlBehavior == 1">Warm Up</span> | <span ng-if="rule.controlBehavior == 1">Warm Up</span> | ||||
<span ng-if="rule.controlBehavior == 2">排队等待</span> | <span ng-if="rule.controlBehavior == 2">排队等待</span> | ||||
<span ng-if="rule.controlBehavior == 3">预热排队</span> | |||||
</td> | </td> | ||||
<td> | <td> | ||||
<button class="btn btn-xs btn-default" type="button" ng-click="editRule(rule)" style="font-size: 12px; height:25px;">编辑</button> | <button class="btn btn-xs btn-default" type="button" ng-click="editRule(rule)" style="font-size: 12px; height:25px;">编辑</button> | ||||
@@ -0,0 +1,113 @@ | |||||
<div class="row" style="margin-left: 1px; margin-top:10px; height: 50px;"> | |||||
<div class="col-md-6" style="margin-bottom: 10px;"> | |||||
<span style="font-size: 30px;font-weight: bold;">{{app}}</span> | |||||
</div> | |||||
<div class="col-md-6"> | |||||
<button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-disabled="!macInputModel" ng-click="addNewRule()"> | |||||
<i class="fa fa-plus"></i> 新增流控规则</button> | |||||
<a class="btn btn-outline-success" style="float: right; margin-right: 10px;" ui-sref="dashboard.flow({app: app})"> | |||||
回到新版</a> | |||||
</div> | |||||
</div> | |||||
<div class="separator"></div> | |||||
<div class="container-fluid"> | |||||
<div class="row" style="margin-top: 20px; margin-bottom: 20px;"> | |||||
<div class="col-md-12"> | |||||
<div class="card"> | |||||
<div class="inputs-header"> | |||||
<span class="brand" style="font-size: 13px;">流控规则</span> | |||||
<!--<button class="btn btn-danger" style="float: right;margin-right: 10px;height: 30px;font-size: 12px;" ng-click="disableAll()">全部禁用</button>--> | |||||
<button class="btn btn-primary" style="float: right; margin-right: 10px; height: 30px;font-size: 12px;" ng-click="getMachineRules()">刷新</button> | |||||
<input class="form-control witdh-200" placeholder="关键字" ng-model="searchKey"> | |||||
<div class="control-group" style="float:right;margin-right: 10px;margin-bottom: -10px;"> | |||||
<selectize id="gsInput" class="selectize-input-200" config="macsInputConfig" options="macsInputOptions" ng-model="macInputModel" | |||||
placeholder="机器"></selectize> | |||||
</div> | |||||
</div> | |||||
<!--.tools-header --> | |||||
<div class="card-body" style="padding: 0px 0px;"> | |||||
<table class="table" style="border-left: none; border-right:none;margin-top: 10px;"> | |||||
<thead> | |||||
<tr style="background: #F3F5F7;"> | |||||
<td style="width: 40%"> | |||||
资源名 | |||||
</td> | |||||
<td style="width: 10%;"> | |||||
流控应用 | |||||
</td> | |||||
<td style="width: 10%;"> | |||||
流控模式 | |||||
</td> | |||||
<td style="width: 10%;"> | |||||
阈值类型 | |||||
</td> | |||||
<td style="width: 10%;"> | |||||
单机阈值 | |||||
</td> | |||||
<td style="width: 10%;"> | |||||
流控效果 | |||||
</td> | |||||
<!--<td style="width: 8%;">--> | |||||
<!--状态--> | |||||
<!--</td>--> | |||||
<td style="width: 12%;"> | |||||
操作 | |||||
</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<tr dir-paginate="rule in rules | filter: searchKey | itemsPerPage: rulesPageConfig.pageSize " current-page="rulesPageConfig.currentPageIndex" | |||||
pagination-id="entriesPagination"> | |||||
<td style="word-wrap:break-word;word-break:break-all;">{{rule.resource}}</td> | |||||
<td style="word-wrap:break-word;word-break:break-all;">{{rule.limitApp }}</td> | |||||
<td> | |||||
<span ng-if="rule.strategy == 0">直接</span> | |||||
<span ng-if="rule.strategy == 1">关联</span> | |||||
<span ng-if="rule.strategy == 2">链路</span> | |||||
</td> | |||||
<td> | |||||
{{rule.grade==0 ? '线程数' : 'QPS'}} | |||||
</td> | |||||
<td style="word-wrap:break-word;word-break:break-all;"> | |||||
{{rule.count}} | |||||
</td> | |||||
<td> | |||||
<span ng-if="rule.controlBehavior == 0">快速失败</span> | |||||
<span ng-if="rule.controlBehavior == 1">Warm Up</span> | |||||
<span ng-if="rule.controlBehavior == 2">排队等待</span> | |||||
</td> | |||||
<td> | |||||
<button class="btn btn-xs btn-default" type="button" ng-click="editRule(rule)" style="font-size: 12px; height:25px;">编辑</button> | |||||
<button class="btn btn-xs btn-default" type="button" ng-click="deleteRule(rule)" style="font-size: 12px; height:25px;">删除</button> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
<!-- .card-body --> | |||||
<div class="pagination-footer"> | |||||
<dir-pagination-controls boundary-links="true" template-url="app/views/pagination.tpl.html" pagination-id="entriesPagination" | |||||
on-page-change=""> | |||||
</dir-pagination-controls> | |||||
<div class="tools" style=""> | |||||
<span>共 {{rulesPageConfig.totalCount}} 条记录, </span> | |||||
<span> | |||||
每页 | |||||
<input class="form-control" ng-model="rulesPageConfig.pageSize"> 条记录 | |||||
</span> | |||||
<!--<span>第 {{rulesPageConfig.currentPageIndex}} / {{rulesPageConfig.totalPage}} 页</span>--> | |||||
</div> | |||||
<!-- .tools --> | |||||
</div> | |||||
<!-- pagination-footer --> | |||||
</div> | |||||
<!-- .card --> | |||||
</div> | |||||
<!-- .col-md-12 --> | |||||
</div> | |||||
<!-- --> | |||||
</div> | |||||
<!-- .container-fluid --> |
@@ -44,7 +44,8 @@ const JS_APP = [ | |||||
'app/scripts/app.js', | 'app/scripts/app.js', | ||||
'app/scripts/filters/filters.js', | 'app/scripts/filters/filters.js', | ||||
'app/scripts/services/appservice.js', | 'app/scripts/services/appservice.js', | ||||
'app/scripts/services/flowservice.js', | |||||
'app/scripts/services/flow_service_v1.js', | |||||
'app/scripts/services/flow_service_v2.js', | |||||
'app/scripts/services/degradeservice.js', | 'app/scripts/services/degradeservice.js', | ||||
'app/scripts/services/systemservice.js', | 'app/scripts/services/systemservice.js', | ||||
'app/scripts/services/machineservice.js', | 'app/scripts/services/machineservice.js', | ||||
@@ -52,6 +53,7 @@ const JS_APP = [ | |||||
'app/scripts/services/metricservice.js', | 'app/scripts/services/metricservice.js', | ||||
'app/scripts/services/param_flow_service.js', | 'app/scripts/services/param_flow_service.js', | ||||
'app/scripts/services/authority_service.js', | 'app/scripts/services/authority_service.js', | ||||
'app/scripts/services/cluster_state_service.js', | |||||
]; | ]; | ||||
gulp.task('lib', function () { | gulp.task('lib', function () { | ||||