mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-17 22:30:25 +08:00
可以在创建、修改节点的时候选择分组,可以根据分组筛选节点
This commit is contained in:
@@ -42,6 +42,7 @@ func (this *CreateBatchAction) RunGet(params struct {
|
||||
|
||||
func (this *CreateBatchAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
GroupId int64
|
||||
IpList string
|
||||
|
||||
Must *actions.Must
|
||||
@@ -76,6 +77,7 @@ func (this *CreateBatchAction) RunPost(params struct {
|
||||
resp, err := this.RPC().NodeRPC().CreateNode(this.AdminContext(), &pb.CreateNodeRequest{
|
||||
Name: ip,
|
||||
ClusterId: params.ClusterId,
|
||||
GroupId: params.GroupId,
|
||||
Login: nil,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -43,6 +43,7 @@ func (this *CreateNodeAction) RunPost(params struct {
|
||||
Name string
|
||||
IpAddressesJSON []byte
|
||||
ClusterId int64
|
||||
GroupId int64
|
||||
GrantId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
@@ -78,6 +79,7 @@ func (this *CreateNodeAction) RunPost(params struct {
|
||||
createResp, err := this.RPC().NodeRPC().CreateNode(this.AdminContext(), &pb.CreateNodeRequest{
|
||||
Name: params.Name,
|
||||
ClusterId: params.ClusterId,
|
||||
GroupId: params.GroupId,
|
||||
Login: loginInfo,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
@@ -31,7 +32,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
params.Must.
|
||||
Field("name", params.Name).
|
||||
Require("请输入分组名称")
|
||||
_, err := this.RPC().NodeGroupRPC().CreateNodeGroup(this.AdminContext(), &pb.CreateNodeGroupRequest{
|
||||
createResp, err := this.RPC().NodeGroupRPC().CreateNodeGroup(this.AdminContext(), &pb.CreateNodeGroupRequest{
|
||||
ClusterId: params.ClusterId,
|
||||
Name: params.Name,
|
||||
})
|
||||
@@ -40,5 +41,10 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": createResp.GroupId,
|
||||
"name": params.Name,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type OptionsAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *OptionsAction) RunPost(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithClusterIdRequest{ClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.Groups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package groups
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
}) {
|
||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithClusterIdRequest{ClusterId: params.ClusterId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
|
||||
groupMaps := []maps.Map{}
|
||||
for _, group := range groupsResp.Groups {
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunPost(params struct {
|
||||
GroupId int64
|
||||
|
||||
Must *actions.Must
|
||||
}) {
|
||||
if params.GroupId <= 0 {
|
||||
this.Fail("请选择要使用的分组")
|
||||
}
|
||||
|
||||
groupResp, err := this.RPC().NodeGroupRPC().FindEnabledNodeGroup(this.AdminContext(), &pb.FindEnabledNodeGroupRequest{GroupId: params.GroupId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
group := groupResp.Group
|
||||
if group == nil {
|
||||
this.NotFound("nodeGroup", params.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
this.Data["group"] = maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -23,16 +23,19 @@ func (this *IndexAction) Init() {
|
||||
|
||||
func (this *IndexAction) RunGet(params struct {
|
||||
ClusterId int64
|
||||
GroupId int64
|
||||
InstalledState int
|
||||
ActiveState int
|
||||
Keyword string
|
||||
}) {
|
||||
this.Data["groupId"] = params.GroupId
|
||||
this.Data["installState"] = params.InstalledState
|
||||
this.Data["activeState"] = params.ActiveState
|
||||
this.Data["keyword"] = params.Keyword
|
||||
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{
|
||||
ClusterId: params.ClusterId,
|
||||
GroupId: params.GroupId,
|
||||
InstallState: types.Int32(params.InstalledState),
|
||||
ActiveState: types.Int32(params.ActiveState),
|
||||
Keyword: params.Keyword,
|
||||
@@ -49,6 +52,7 @@ func (this *IndexAction) RunGet(params struct {
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
ClusterId: params.ClusterId,
|
||||
GroupId: params.GroupId,
|
||||
InstallState: types.Int32(params.InstalledState),
|
||||
ActiveState: types.Int32(params.ActiveState),
|
||||
Keyword: params.Keyword,
|
||||
@@ -84,6 +88,14 @@ func (this *IndexAction) RunGet(params struct {
|
||||
})
|
||||
}
|
||||
|
||||
var groupMap maps.Map = nil
|
||||
if node.Group != nil {
|
||||
groupMap = maps.Map{
|
||||
"id": node.Group.Id,
|
||||
"name": node.Group.Name,
|
||||
}
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
@@ -110,9 +122,35 @@ func (this *IndexAction) RunGet(params struct {
|
||||
},
|
||||
"isSynced": isSynced,
|
||||
"ipAddresses": ipAddresses,
|
||||
"group": groupMap,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
// 所有分组
|
||||
groupMaps := []maps.Map{}
|
||||
groupsResp, err := this.RPC().NodeGroupRPC().FindAllEnabledNodeGroupsWithClusterId(this.AdminContext(), &pb.FindAllEnabledNodeGroupsWithClusterIdRequest{
|
||||
ClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, group := range groupsResp.Groups {
|
||||
countResp, err := this.RPC().NodeRPC().CountAllEnabledNodesWithGroupId(this.AdminContext(), &pb.CountAllEnabledNodesWithGroupIdRequest{GroupId: group.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
countNodes := countResp.Count
|
||||
|
||||
groupMaps = append(groupMaps, maps.Map{
|
||||
"id": group.Id,
|
||||
"name": group.Name,
|
||||
"countNodes": countNodes,
|
||||
})
|
||||
}
|
||||
this.Data["groups"] = groupMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ func init() {
|
||||
GetPost("/groups/updatePopup", new(groups.UpdatePopupAction)).
|
||||
Post("/groups/delete", new(groups.DeleteAction)).
|
||||
Post("/groups/sort", new(groups.SortAction)).
|
||||
Post("/groups/options", new(groups.OptionsAction)).
|
||||
GetPost("/groups/selectPopup", new(groups.SelectPopupAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
|
||||
@@ -120,6 +120,14 @@ func (this *NodeAction) RunGet(params struct {
|
||||
status.IsActive = status.IsActive && time.Now().Unix()-status.UpdatedAt <= 60 // N秒之内认为活跃
|
||||
}
|
||||
|
||||
var groupMap maps.Map = nil
|
||||
if node.Group != nil {
|
||||
groupMap = maps.Map{
|
||||
"id": node.Group.Id,
|
||||
"name": node.Group.Name,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
@@ -142,6 +150,8 @@ func (this *NodeAction) RunGet(params struct {
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||
},
|
||||
|
||||
"group": groupMap,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
|
||||
@@ -98,6 +98,14 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
var groupMap maps.Map = nil
|
||||
if node.Group != nil {
|
||||
groupMap = maps.Map{
|
||||
"id": node.Group.Id,
|
||||
"name": node.Group.Name,
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
@@ -106,6 +114,7 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
"login": loginMap,
|
||||
"maxCPU": node.MaxCPU,
|
||||
"isOn": node.IsOn,
|
||||
"group": groupMap,
|
||||
}
|
||||
|
||||
// 所有集群
|
||||
@@ -132,6 +141,7 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
LoginId int64
|
||||
NodeId int64
|
||||
GroupId int64
|
||||
Name string
|
||||
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
||||
ClusterId int64
|
||||
@@ -171,6 +181,7 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
// 保存
|
||||
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
GroupId: params.GroupId,
|
||||
Name: params.Name,
|
||||
ClusterId: params.ClusterId,
|
||||
Login: loginInfo,
|
||||
|
||||
50
web/public/js/components/node/node-group-selector.js
Normal file
50
web/public/js/components/node/node-group-selector.js
Normal file
@@ -0,0 +1,50 @@
|
||||
Vue.component("node-group-selector", {
|
||||
props: ["v-cluster-id", "v-group"],
|
||||
mounted: function () {
|
||||
let that = this
|
||||
Tea.action("/clusters/cluster/groups/options")
|
||||
.post()
|
||||
.params({
|
||||
clusterId: this.vClusterId
|
||||
})
|
||||
.success(function (resp) {
|
||||
|
||||
})
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
groups: [],
|
||||
selectedGroup: this.vGroup,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectGroup: function () {
|
||||
let that = this
|
||||
teaweb.popup("/clusters/cluster/groups/selectPopup?clusterId=" + this.vClusterId, {
|
||||
callback: function (resp) {
|
||||
that.selectedGroup = resp.data.group
|
||||
}
|
||||
})
|
||||
},
|
||||
addGroup: function () {
|
||||
let that = this
|
||||
teaweb.popup("/clusters/cluster/groups/createPopup?clusterId=" + this.vClusterId, {
|
||||
callback: function (resp) {
|
||||
that.selectedGroup = resp.data.group
|
||||
}
|
||||
})
|
||||
},
|
||||
removeGroup: function () {
|
||||
this.selectedGroup = null
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<div class="ui label tiny" v-if="selectedGroup != null">
|
||||
<input type="hidden" name="groupId" :value="selectedGroup.id"/>
|
||||
{{selectedGroup.name}} <a href="" title="删除" @click.prevent="removeGroup()"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
<div v-if="selectedGroup == null">
|
||||
<a href="" @click.prevent="selectGroup()">[选择分组]</a> <a href="" @click.prevent="addGroup()">[添加分组]</a>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
@@ -61,7 +61,7 @@
|
||||
right: 0;
|
||||
left: 18em;
|
||||
padding-right: 2em;
|
||||
padding-bottom: 1em;
|
||||
padding-bottom: 2em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.right-box.tiny {
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
right: 0;
|
||||
left: 18em;
|
||||
padding-right: 2em;
|
||||
padding-bottom: 1em;
|
||||
padding-bottom: 2em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
<p class="comment">每行一个节点IP。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属分组</td>
|
||||
<td>
|
||||
<node-group-selector :v-cluster-id="clusterId"></node-group-selector>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
<node-ip-addresses-box></node-ip-addresses-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属分组</td>
|
||||
<td>
|
||||
<node-group-selector :v-cluster-id="clusterId"></node-group-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td>分组名称 *</td>
|
||||
<td class="title">分组名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus"/>
|
||||
</td>
|
||||
|
||||
22
web/views/@default/clusters/cluster/groups/selectPopup.html
Normal file
22
web/views/@default/clusters/cluster/groups/selectPopup.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>选择分组</h3>
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="groupId" :value="groupId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">选择分组</td>
|
||||
<td>
|
||||
<div v-if="groups.length > 0">
|
||||
<a href="" class="ui label tiny" v-for="group in groups" :class="{blue:group.id == groupId}" style="margin-bottom:0.5em" @click.prevent="selectGroup(group)">{{group.name}}</a>
|
||||
<p class="comment">点击可已选中要使用的分组。</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p class="comment">暂时还没有可以使用的分组。</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn>确定</submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,8 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyPopup
|
||||
this.groupId = 0
|
||||
|
||||
this.selectGroup = function (group) {
|
||||
this.groupId = group.id
|
||||
}
|
||||
})
|
||||
@@ -5,7 +5,7 @@
|
||||
<input type="hidden" name="groupId" :value="group.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td>分组名称 *</td>
|
||||
<td class="title">分组名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus" v-model="group.name"/>
|
||||
</td>
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
<form class="ui form segment" action="/clusters/cluster">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field" v-if="groups.length > 0">
|
||||
所属分组:
|
||||
</div>
|
||||
<div class="ui field" v-if="groups.length > 0">
|
||||
<select class="ui dropdown" name="groupId" v-model="groupId">
|
||||
<option value="0">[全部]</option>
|
||||
<option v-for="group in groups" :value="group.id">{{group.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
安装状态:
|
||||
</div>
|
||||
@@ -41,8 +50,8 @@
|
||||
<tr>
|
||||
<th class="one wide">ID</th>
|
||||
<th>节点名称</th>
|
||||
<th>主机名</th>
|
||||
<th>IP</th>
|
||||
<th class="two wide">所属分组</th>
|
||||
<th class="three wide">IP</th>
|
||||
<th class="two wide">CPU</th>
|
||||
<th class="two wide">内存</th>
|
||||
<!--<th>流量</th>
|
||||
@@ -52,14 +61,14 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="node in nodes">
|
||||
<td>{{node.id}}</td>
|
||||
<td nowrap="">{{node.id}}</td>
|
||||
<td>{{node.name}}</td>
|
||||
<td>
|
||||
<span v-if="node.status.hostname != null && node.status.hostname.length > 0">{{node.status.hostname}}</span>
|
||||
<span v-else>-</span>
|
||||
<span v-if="node.group != null" class="ui label tiny">{{node.group.name}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="node.ipAddresses.length == 0">-</span>
|
||||
<span v-if="node.ipAddresses.length == 0" class="disabled">-</span>
|
||||
<div v-else class="address-box">
|
||||
<div v-for="addr in node.ipAddresses" style="margin-bottom:0.3em">
|
||||
<div class="ui label tiny">{{addr.ip}}
|
||||
@@ -71,11 +80,11 @@
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="node.status.isActive" :class="{red:node.status.cpuUsage > 0.80}">{{node.status.cpuUsageText}}</span>
|
||||
<span v-else>-</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="node.status.isActive" :class="{red:node.status.memUsage > 0.80}">{{node.status.memUsageText}}</span>
|
||||
<span v-else>-</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<div v-if="!node.isOn">
|
||||
|
||||
@@ -30,7 +30,14 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator>SSH等更多选项</more-options-indicator></td>
|
||||
<td>所属分组</td>
|
||||
<td>
|
||||
<span v-if="node.group != null" class="ui label tiny">{{node.group.name}}</span>
|
||||
<span v-else class="disabled">没有设置分组。</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator>更多选项</more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
|
||||
@@ -28,8 +28,15 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><strong>SSH登录信息:</strong></td>
|
||||
<td>所属分组</td>
|
||||
<td>
|
||||
<node-group-selector :v-cluster-id="clusterId" :v-group="node.group"></node-group-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>SSH主机地址</td>
|
||||
<td>
|
||||
@@ -50,10 +57,6 @@
|
||||
<grant-selector :v-grant="grant"></grant-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>CPU线程数</td>
|
||||
<td>
|
||||
|
||||
Reference in New Issue
Block a user