ソースを参照

Add frontend service and pages for Sentinel cluster flow control in dashboard

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
master
Eric Zhao 6年前
コミット
0059b1a42d
17個のファイルの変更917行の追加39行の削除
  1. +37
    -5
      sentinel-dashboard/src/main/webapp/resources/app/scripts/app.js
  2. +237
    -0
      sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/cluster.js
  3. +6
    -2
      sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/flow.js
  4. +203
    -0
      sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/flow_old.js
  5. +1
    -1
      sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/identity.js
  6. +9
    -1
      sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html
  7. +28
    -0
      sentinel-dashboard/src/main/webapp/resources/app/scripts/services/cluster_state_service.js
  8. +9
    -9
      sentinel-dashboard/src/main/webapp/resources/app/scripts/services/flow_service_v1.js
  9. +85
    -0
      sentinel-dashboard/src/main/webapp/resources/app/scripts/services/flow_service_v2.js
  10. +96
    -0
      sentinel-dashboard/src/main/webapp/resources/app/views/cluster.html
  11. +22
    -0
      sentinel-dashboard/src/main/webapp/resources/app/views/cluster/client.html
  12. +16
    -0
      sentinel-dashboard/src/main/webapp/resources/app/views/cluster/server.html
  13. +33
    -3
      sentinel-dashboard/src/main/webapp/resources/app/views/dialog/flow-rule-dialog.html
  14. +18
    -16
      sentinel-dashboard/src/main/webapp/resources/app/views/flow.html
  15. +113
    -0
      sentinel-dashboard/src/main/webapp/resources/app/views/flow_old.html
  16. +1
    -1
      sentinel-dashboard/src/main/webapp/resources/dist/js/app.js
  17. +3
    -1
      sentinel-dashboard/src/main/webapp/resources/gulpfile.js

+ 37
- 5
sentinel-dashboard/src/main/webapp/resources/app/scripts/app.js ファイルの表示

@@ -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: {
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) {
return $ocLazyLoad.load({
name: 'sentinelDashboardApp',
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', {
templateUrl: 'app/views/param_flow.html',
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', {
templateUrl: 'app/views/authority.html',
url: '/authority/:app',


+ 237
- 0
sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/cluster.js ファイルの表示

@@ -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();
}]);

+ 6
- 2
sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/flow.js ファイルの表示

@@ -1,6 +1,6 @@
var app = angular.module('sentinelDashboardApp');

app.controller('FlowCtl', ['$scope', '$stateParams', 'FlowService', 'ngDialog',
app.controller('FlowController', ['$scope', '$stateParams', 'FlowServiceV2', 'ngDialog',
'MachineService',
function ($scope, $stateParams, FlowService, ngDialog,
MachineService) {
@@ -72,7 +72,11 @@ app.controller('FlowCtl', ['$scope', '$stateParams', 'FlowService', 'ngDialog',
app: $scope.app,
ip: mac[0],
port: mac[1],
limitApp: 'default'
limitApp: 'default',
clusterMode: false,
clusterConfig: {
thresholdType: 0
}
};
$scope.flowRuleDialog = {
title: '新增流控规则',


+ 203
- 0
sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/flow_old.js ファイルの表示

@@ -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
- 1
sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/identity.js ファイルの表示

@@ -1,7 +1,7 @@
var app = angular.module('sentinelDashboardApp');

app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService',
'ngDialog', 'FlowService', 'DegradeService', 'AuthorityRuleService', 'ParamFlowService', 'MachineService',
'ngDialog', 'FlowServiceV2', 'DegradeService', 'AuthorityRuleService', 'ParamFlowService', 'MachineService',
'$interval', '$location', '$timeout',
function ($scope, $stateParams, IdentityService, ngDialog,
FlowService, DegradeService, AuthorityRuleService, ParamFlowService, MachineService, $interval, $location, $timeout) {


+ 9
- 1
sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html ファイルの表示

@@ -33,9 +33,13 @@
</li>

<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>&nbsp;&nbsp;流控规则</a>
</li>
<!--<li ui-sref-active="active">-->
<!--<a ui-sref="dashboard.flow({app: entry.app})">-->
<!--<i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则 V1</a>-->
<!--</li>-->
<li ui-sref-active="active">
<a ui-sref="dashboard.degrade({app: entry.app})">
<i class="glyphicon glyphicon-flash"></i>&nbsp;&nbsp;降级规则</a>
@@ -52,6 +56,10 @@
<a ui-sref="dashboard.authority({app: entry.app})">
<i class="glyphicon glyphicon-check"></i>&nbsp;&nbsp;授权规则</a>
</li>
<li ui-sref-active="active">
<a ui-sref="dashboard.clusterAll({app: entry.app})">
<i class="glyphicon glyphicon-cloud"></i>&nbsp;&nbsp;集群限流</a>
</li>
<li ui-sref-active="active">
<a ui-sref="dashboard.machine({app: entry.app})">
<i class="glyphicon glyphicon-th-list"></i>&nbsp;&nbsp;机器列表</a>


+ 28
- 0
sentinel-dashboard/src/main/webapp/resources/app/scripts/services/cluster_state_service.js ファイルの表示

@@ -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'
});
};
}]);

sentinel-dashboard/src/main/webapp/resources/app/scripts/services/flowservice.js → sentinel-dashboard/src/main/webapp/resources/app/scripts/services/flow_service_v1.js ファイルの表示

@@ -1,6 +1,6 @@
var app = angular.module('sentinelDashboardApp');

app.service('FlowService', ['$http', function ($http) {
app.service('FlowServiceV1', ['$http', function ($http) {
this.queryMachineRules = function (app, ip, port) {
var param = {
app: app,
@@ -8,7 +8,7 @@ app.service('FlowService', ['$http', function ($http) {
port: port
};
return $http({
url: 'flow/rules.json',
url: '/v1/flow/rules',
params: param,
method: 'GET'
});
@@ -31,9 +31,9 @@ app.service('FlowService', ['$http', function ($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({
url: '/flow/save.json',
url: '/v1/flow/save.json',
params: param,
method: 'GET'
method: 'PUT'
});
};

@@ -65,9 +65,9 @@ app.service('FlowService', ['$http', function ($http) {
};

return $http({
url: '/flow/delete.json',
url: '/v1/flow/delete.json',
params: param,
method: 'GET'
method: 'DELETE'
});
};


+ 85
- 0
sentinel-dashboard/src/main/webapp/resources/app/scripts/services/flow_service_v2.js ファイルの表示

@@ -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;
};
}]);

+ 96
- 0
sentinel-dashboard/src/main/webapp/resources/app/views/cluster.html ファイルの表示

@@ -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" />&nbsp;Client&nbsp;&nbsp;
<input type="radio" name="mode" value="1" ng-model='stateVO.stateInfo.mode' ng-disabled="!stateVO.stateInfo.serverAvailable" />&nbsp;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 -->

+ 22
- 0
sentinel-dashboard/src/main/webapp/resources/app/views/cluster/client.html ファイルの表示

@@ -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>

+ 16
- 0
sentinel-dashboard/src/main/webapp/resources/app/views/cluster/server.html ファイルの表示

@@ -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>

+ 33
- 3
sentinel-dashboard/src/main/webapp/resources/app/views/dialog/flow-rule-dialog.html ファイルの表示

@@ -30,9 +30,39 @@
<input type="radio" name="grade" value="0" ng-model='currentRule.grade' />&nbsp;线程数
</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' />&nbsp;单机均摊&nbsp;&nbsp;
<input type="radio" name="clusterThresholdType" value="1" ng-model='currentRule.clusterConfig.thresholdType' />&nbsp;Global
</div>
</div>
</div>
</div>



+ 18
- 16
sentinel-dashboard/src/main/webapp/resources/app/views/flow.html ファイルの表示

@@ -3,8 +3,11 @@
<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>&nbsp;&nbsp;新增流控规则</button>
<button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-click="addNewRule()">
<i class="fa fa-plus"></i>&nbsp;&nbsp;新增流控规则
</button>
<a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.flowV1({app: app})">
回到旧版(单机)</a>
</div>
</div>

@@ -16,13 +19,7 @@
<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 -->
@@ -36,21 +33,21 @@
<td style="width: 10%;">
流控应用
</td>
<td style="width: 10%;">
<td style="width: 8%;">
流控模式
</td>
<td style="width: 10%;">
<td style="width: 8%;">
阈值类型
</td>
<td style="width: 10%;">
<td style="width: 8%;">
单机阈值
</td>
<td style="width: 10%;">
<td style="width: 8%;">
是否集群
</td>
<td style="width: 8%;">
流控效果
</td>
<!--<td style="width: 8%;">-->
<!--状态-->
<!--</td>-->
<td style="width: 12%;">
操作
</td>
@@ -67,15 +64,20 @@
<span ng-if="rule.strategy == 2">链路</span>
</td>
<td>
{{rule.grade==0 ? '线程数' : 'QPS'}}
{{rule.grade == 0 ? '线程数' : 'QPS'}}
</td>
<td style="word-wrap:break-word;word-break:break-all;">
{{rule.count}}
</td>
<td>
<span ng-if="rule.clusterMode">是</span>
<span ng-if="!rule.clusterMode">否</span>
</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>
<span ng-if="rule.controlBehavior == 3">预热排队</span>
</td>
<td>
<button class="btn btn-xs btn-default" type="button" ng-click="editRule(rule)" style="font-size: 12px; height:25px;">编辑</button>


+ 113
- 0
sentinel-dashboard/src/main/webapp/resources/app/views/flow_old.html ファイルの表示

@@ -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>&nbsp;&nbsp;新增流控规则</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 -->

+ 1
- 1
sentinel-dashboard/src/main/webapp/resources/dist/js/app.js
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 3
- 1
sentinel-dashboard/src/main/webapp/resources/gulpfile.js ファイルの表示

@@ -44,7 +44,8 @@ const JS_APP = [
'app/scripts/app.js',
'app/scripts/filters/filters.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/systemservice.js',
'app/scripts/services/machineservice.js',
@@ -52,6 +53,7 @@ const JS_APP = [
'app/scripts/services/metricservice.js',
'app/scripts/services/param_flow_service.js',
'app/scripts/services/authority_service.js',
'app/scripts/services/cluster_state_service.js',
];

gulp.task('lib', function () {


読み込み中…
キャンセル
保存