mirror of
https://github.com/nezhahq/nezha.git
synced 2025-01-22 12:48:14 -05:00
v0.15.1 批量删除服务器 bulk delete the servers
This commit is contained in:
parent
42c038c829
commit
45e26f4082
@ -4,7 +4,7 @@
|
||||
<br>
|
||||
<small><i>LOGO designed by <a href="https://xio.ng" target="_blank">熊大</a> .</i></small>
|
||||
<br><br>
|
||||
<img src="https://img.shields.io/github/actions/workflow/status/naiba/nezha/dashboard.yml?branch=master&label=Dash%20v0.15.0&logo=github&style=for-the-badge"> <img src="https://img.shields.io/github/v/release/nezhahq/agent?color=brightgreen&label=Agent&style=for-the-badge&logo=github"> <img src="https://img.shields.io/github/actions/workflow/status/nezhahq/agent/agent.yml?branch=v0.15.0&label=Agent%20CI&logo=github&style=for-the-badge"> <img src="https://img.shields.io/badge/Installer-v0.15.0-brightgreen?style=for-the-badge&logo=linux">
|
||||
<img src="https://img.shields.io/github/actions/workflow/status/naiba/nezha/dashboard.yml?branch=master&label=Dash%20v0.15.1&logo=github&style=for-the-badge"> <img src="https://img.shields.io/github/v/release/nezhahq/agent?color=brightgreen&label=Agent&style=for-the-badge&logo=github"> <img src="https://img.shields.io/github/actions/workflow/status/nezhahq/agent/agent.yml?branch=v0.15.1&label=Agent%20CI&logo=github&style=for-the-badge"> <img src="https://img.shields.io/badge/Installer-v0.15.0-brightgreen?style=for-the-badge&logo=linux">
|
||||
<br>
|
||||
<br>
|
||||
<p>:trollface: <b>Nezha Monitoring: Self-hostable, lightweight, servers and websites monitoring and O&M tool.</b></p>
|
||||
|
@ -41,6 +41,7 @@ func (ma *memberAPI) serve() {
|
||||
mr.GET("/cron/:id/manual", ma.manualTrigger)
|
||||
mr.POST("/force-update", ma.forceUpdate)
|
||||
mr.POST("/batch-update-server-group", ma.batchUpdateServerGroup)
|
||||
mr.POST("/batch-delete-server", ma.batchDeleteServer)
|
||||
mr.POST("/notification", ma.addOrEditNotification)
|
||||
mr.POST("/alert-rule", ma.addOrEditAlertRule)
|
||||
mr.POST("/setting", ma.updateSetting)
|
||||
@ -187,37 +188,9 @@ func (ma *memberAPI) delete(c *gin.Context) {
|
||||
if err == nil {
|
||||
// 删除服务器
|
||||
singleton.ServerLock.Lock()
|
||||
tag := singleton.ServerList[id].Tag
|
||||
delete(singleton.SecretToID, singleton.ServerList[id].Secret)
|
||||
delete(singleton.ServerList, id)
|
||||
index := -1
|
||||
for i := 0; i < len(singleton.ServerTagToIDList[tag]); i++ {
|
||||
if singleton.ServerTagToIDList[tag][i] == id {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index > -1 {
|
||||
// 删除旧 Tag-ID 绑定关系
|
||||
singleton.ServerTagToIDList[tag] = append(singleton.ServerTagToIDList[tag][:index], singleton.ServerTagToIDList[tag][index+1:]...)
|
||||
if len(singleton.ServerTagToIDList[tag]) == 0 {
|
||||
delete(singleton.ServerTagToIDList, tag)
|
||||
}
|
||||
}
|
||||
onServerDelete(id)
|
||||
singleton.ServerLock.Unlock()
|
||||
singleton.ReSortServer()
|
||||
// 删除循环流量状态中的此服务器相关的记录
|
||||
singleton.AlertsLock.Lock()
|
||||
for i := 0; i < len(singleton.Alerts); i++ {
|
||||
if singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID] != nil {
|
||||
delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].ServerName, id)
|
||||
delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].Transfer, id)
|
||||
delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].NextUpdate, id)
|
||||
}
|
||||
}
|
||||
singleton.AlertsLock.Unlock()
|
||||
// 删除服务器相关循环流量记录
|
||||
singleton.DB.Unscoped().Delete(&model.Transfer{}, "server_id = ?", id)
|
||||
}
|
||||
case "notification":
|
||||
err = singleton.DB.Unscoped().Delete(&model.Notification{}, "id = ?", id).Error
|
||||
@ -446,10 +419,12 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) {
|
||||
if err == nil {
|
||||
err = utils.Json.Unmarshal([]byte(mf.RecoverTriggerTasksRaw), &m.RecoverTriggerTasks)
|
||||
}
|
||||
if m.ID == 0 {
|
||||
err = singleton.DB.Create(&m).Error
|
||||
} else {
|
||||
err = singleton.DB.Save(&m).Error
|
||||
if err == nil {
|
||||
if m.ID == 0 {
|
||||
err = singleton.DB.Create(&m).Error
|
||||
} else {
|
||||
err = singleton.DB.Save(&m).Error
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
@ -933,3 +908,63 @@ func (ma *memberAPI) updateSetting(c *gin.Context) {
|
||||
Code: http.StatusOK,
|
||||
})
|
||||
}
|
||||
|
||||
func (ma *memberAPI) batchDeleteServer(c *gin.Context) {
|
||||
var servers []uint64
|
||||
if err := c.ShouldBindJSON(&servers); err != nil {
|
||||
c.JSON(http.StatusOK, model.Response{
|
||||
Code: http.StatusBadRequest,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := singleton.DB.Unscoped().Delete(&model.Server{}, "id in (?)", servers).Error; err != nil {
|
||||
c.JSON(http.StatusOK, model.Response{
|
||||
Code: http.StatusBadRequest,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
singleton.ServerLock.Lock()
|
||||
for i := 0; i < len(servers); i++ {
|
||||
id := servers[i]
|
||||
onServerDelete(id)
|
||||
}
|
||||
singleton.ServerLock.Unlock()
|
||||
singleton.ReSortServer()
|
||||
c.JSON(http.StatusOK, model.Response{
|
||||
Code: http.StatusOK,
|
||||
})
|
||||
}
|
||||
|
||||
func onServerDelete(id uint64) {
|
||||
tag := singleton.ServerList[id].Tag
|
||||
delete(singleton.SecretToID, singleton.ServerList[id].Secret)
|
||||
delete(singleton.ServerList, id)
|
||||
index := -1
|
||||
for i := 0; i < len(singleton.ServerTagToIDList[tag]); i++ {
|
||||
if singleton.ServerTagToIDList[tag][i] == id {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index > -1 {
|
||||
|
||||
singleton.ServerTagToIDList[tag] = append(singleton.ServerTagToIDList[tag][:index], singleton.ServerTagToIDList[tag][index+1:]...)
|
||||
if len(singleton.ServerTagToIDList[tag]) == 0 {
|
||||
delete(singleton.ServerTagToIDList, tag)
|
||||
}
|
||||
}
|
||||
|
||||
singleton.AlertsLock.Lock()
|
||||
for i := 0; i < len(singleton.Alerts); i++ {
|
||||
if singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID] != nil {
|
||||
delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].ServerName, id)
|
||||
delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].Transfer, id)
|
||||
delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].NextUpdate, id)
|
||||
}
|
||||
}
|
||||
singleton.AlertsLock.Unlock()
|
||||
|
||||
singleton.DB.Unscoped().Delete(&model.Transfer{}, "server_id = ?", id)
|
||||
}
|
||||
|
5
resource/l10n/en-US.toml
vendored
5
resource/l10n/en-US.toml
vendored
@ -202,6 +202,9 @@ other = "Add Server"
|
||||
[BatchEditServerGroup]
|
||||
other = "Batch Modify Groups"
|
||||
|
||||
[BatchDeleteServer]
|
||||
other = "Batch Delete Server"
|
||||
|
||||
[InputServerGroupName]
|
||||
other = "Enter the name of the group"
|
||||
|
||||
@ -307,7 +310,7 @@ other = "Click To Copy"
|
||||
[DeleteServer]
|
||||
other = "Delete Server"
|
||||
|
||||
[ConfirmToDeleteThisServer]
|
||||
[ConfirmToDeleteServer]
|
||||
other = "Confirm Delete?"
|
||||
|
||||
[NoServerSelected]
|
||||
|
7
resource/l10n/es-ES.toml
vendored
7
resource/l10n/es-ES.toml
vendored
@ -202,6 +202,9 @@ other = "Añadir un servidor"
|
||||
[BatchEditServerGroup]
|
||||
other = "Modificación de grupos por lotes"
|
||||
|
||||
[BatchDeleteServer]
|
||||
other = "Batch Delete Server"
|
||||
|
||||
[InputServerGroupName]
|
||||
other = "Introduzca un nombre de grupo"
|
||||
|
||||
@ -307,8 +310,8 @@ other = "Haga clic para copiar"
|
||||
[DeleteServer]
|
||||
other = "Eliminar el servidor"
|
||||
|
||||
[ConfirmToDeleteThisServer]
|
||||
other = "¿Confirma que quiere eliminar este servidor?"
|
||||
[ConfirmToDeleteServer]
|
||||
other = "¿Confirma que quiere eliminar servidor?"
|
||||
|
||||
[NoServerSelected]
|
||||
other = "No hay servidores seleccionados actualmente"
|
||||
|
7
resource/l10n/zh-CN.toml
vendored
7
resource/l10n/zh-CN.toml
vendored
@ -202,6 +202,9 @@ other = "添加服务器"
|
||||
[BatchEditServerGroup]
|
||||
other = "批量修改分组"
|
||||
|
||||
[BatchDeleteServer]
|
||||
other = "批量删除服务器"
|
||||
|
||||
[InputServerGroupName]
|
||||
other = "输入分组名称"
|
||||
|
||||
@ -307,8 +310,8 @@ other = "点击复制"
|
||||
[DeleteServer]
|
||||
other = "删除主机"
|
||||
|
||||
[ConfirmToDeleteThisServer]
|
||||
other = "确认删除此主机?"
|
||||
[ConfirmToDeleteServer]
|
||||
other = "确认删除主机?"
|
||||
|
||||
[NoServerSelected]
|
||||
other = "当前没有选中的服务器"
|
||||
|
7
resource/l10n/zh-TW.toml
vendored
7
resource/l10n/zh-TW.toml
vendored
@ -202,6 +202,9 @@ other = "添加服務器"
|
||||
[BatchEditServerGroup]
|
||||
other = "批量修改分組"
|
||||
|
||||
[BatchDeleteServer]
|
||||
other = "批量删除服务器"
|
||||
|
||||
[InputServerGroupName]
|
||||
other = "輸入分組名稱"
|
||||
|
||||
@ -307,8 +310,8 @@ other = "點擊複製"
|
||||
[DeleteServer]
|
||||
other = "刪除主機"
|
||||
|
||||
[ConfirmToDeleteThisServer]
|
||||
other = "確認刪除此主機?"
|
||||
[ConfirmToDeleteServer]
|
||||
other = "確認刪除主機?"
|
||||
|
||||
[NoServerSelected]
|
||||
other = "當前沒有選中的服務器"
|
||||
|
@ -44,6 +44,30 @@ function showConfirm(title, content, callFn, extData) {
|
||||
.modal("show");
|
||||
}
|
||||
|
||||
function postJson(url, data) {
|
||||
return $.ajax({
|
||||
url: url,
|
||||
type: "POST",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(data),
|
||||
}).done((resp) => {
|
||||
if (resp.code == 200) {
|
||||
if (resp.message) {
|
||||
alert(resp.message);
|
||||
} else {
|
||||
alert("删除成功");
|
||||
}
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert("删除失败 " + resp.code + ":" + resp.message);
|
||||
confirmBtn.toggleClass("loading");
|
||||
}
|
||||
})
|
||||
.fail((err) => {
|
||||
alert("网络错误:" + err.responseText);
|
||||
});
|
||||
}
|
||||
|
||||
function showFormModal(modelSelector, formID, URL, getData) {
|
||||
$(modelSelector)
|
||||
.modal({
|
||||
@ -344,11 +368,11 @@ function addOrEditMonitor(monitor) {
|
||||
const node = modal.find("i.dropdown.icon.specificServer");
|
||||
for (let i = 0; i < serverList.length; i++) {
|
||||
node.after(
|
||||
'<a class="ui label transition visible" data-value="' +
|
||||
serverList[i] +
|
||||
'" style="display: inline-block !important;">ID:' +
|
||||
serverList[i] +
|
||||
'<i class="delete icon"></i></a>'
|
||||
'<a class="ui label transition visible" data-value="' +
|
||||
serverList[i] +
|
||||
'" style="display: inline-block !important;">ID:' +
|
||||
serverList[i] +
|
||||
'<i class="delete icon"></i></a>'
|
||||
);
|
||||
}
|
||||
|
||||
@ -360,31 +384,31 @@ function addOrEditMonitor(monitor) {
|
||||
const node2 = modal.find("i.dropdown.icon.recoverTask");
|
||||
for (let i = 0; i < failTriggerTasksList.length; i++) {
|
||||
node1.after(
|
||||
'<a class="ui label transition visible" data-value="' +
|
||||
failTriggerTasksList[i] +
|
||||
'" style="display: inline-block !important;">ID:' +
|
||||
failTriggerTasksList[i] +
|
||||
'<i class="delete icon"></i></a>'
|
||||
'<a class="ui label transition visible" data-value="' +
|
||||
failTriggerTasksList[i] +
|
||||
'" style="display: inline-block !important;">ID:' +
|
||||
failTriggerTasksList[i] +
|
||||
'<i class="delete icon"></i></a>'
|
||||
);
|
||||
}
|
||||
for (let i = 0; i < recoverTriggerTasksList.length; i++) {
|
||||
node2.after(
|
||||
'<a class="ui label transition visible" data-value="' +
|
||||
recoverTriggerTasksList[i] +
|
||||
'" style="display: inline-block !important;">ID:' +
|
||||
recoverTriggerTasksList[i] +
|
||||
'<i class="delete icon"></i></a>'
|
||||
'<a class="ui label transition visible" data-value="' +
|
||||
recoverTriggerTasksList[i] +
|
||||
'" style="display: inline-block !important;">ID:' +
|
||||
recoverTriggerTasksList[i] +
|
||||
'<i class="delete icon"></i></a>'
|
||||
);
|
||||
}
|
||||
}
|
||||
modal
|
||||
modal
|
||||
.find("input[name=FailTriggerTasksRaw]")
|
||||
.val(monitor ? "[]," + failTriggerTasks.substr(1, failTriggerTasks.length - 2) : "[]");
|
||||
modal
|
||||
modal
|
||||
.find("input[name=RecoverTriggerTasksRaw]")
|
||||
.val(monitor ? "[]," + recoverTriggerTasks.substr(1, recoverTriggerTasks.length - 2) : "[]");
|
||||
|
||||
modal
|
||||
modal
|
||||
.find("input[name=SkipServersRaw]")
|
||||
.val(monitor ? "[]," + servers.substr(1, servers.length - 2) : "[]");
|
||||
showFormModal(".monitor.modal", "#monitorForm", "/api/monitor");
|
||||
|
2
resource/template/common/footer.html
vendored
2
resource/template/common/footer.html
vendored
@ -10,7 +10,7 @@
|
||||
<script src="https://cdn.staticfile.org/semantic-ui/2.4.1/semantic.min.js"></script>
|
||||
<script src="/static/semantic-ui-alerts.min.js"></script>
|
||||
<script src="https://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script>
|
||||
<script src="/static/main.js?v20230417"></script>
|
||||
<script src="/static/main.js?v20230614"></script>
|
||||
<script>
|
||||
(function () {
|
||||
updateLang({{.LANG }});
|
||||
|
24
resource/template/dashboard-default/server.html
vendored
24
resource/template/dashboard-default/server.html
vendored
@ -8,6 +8,9 @@
|
||||
<button class="ui right labeled nezha-primary-btn icon button" onclick="batchEditServerGroup()"><i
|
||||
class="edit icon"></i> {{tr "BatchEditServerGroup"}}
|
||||
</button>
|
||||
<button class="ui right labeled nezha-primary-btn icon button" onclick="batchDeleteServer()"><i
|
||||
class="trash icon"></i> {{tr "BatchDeleteServer"}}
|
||||
</button>
|
||||
<button class="ui right labeled nezha-primary-btn icon button" onclick="addOrEditServer()"><i
|
||||
class="add icon"></i> {{tr "AddServer"}}
|
||||
</button>
|
||||
@ -69,7 +72,7 @@
|
||||
<i class="edit icon"></i>
|
||||
</button>
|
||||
<button class="ui button"
|
||||
onclick="showConfirm('{{tr "DeleteServer"}}','{{tr "ConfirmToDeleteThisServer"}}',deleteRequest,'/api/server/'+{{$server.ID}})">
|
||||
onclick="showConfirm('{{tr "DeleteServer"}}','{{tr "ConfirmToDeleteServer"}}',deleteRequest,'/api/server/'+{{$server.ID}})">
|
||||
<i class="trash alternate outline icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
@ -188,5 +191,24 @@
|
||||
});
|
||||
})
|
||||
}
|
||||
function batchDeleteServer() {
|
||||
const servers = []
|
||||
checkBoxList.forEach(cb => {
|
||||
if (cb.checked) {
|
||||
servers.push(parseInt(cb.value))
|
||||
}
|
||||
})
|
||||
if (servers.length == 0) {
|
||||
$.suiAlert({
|
||||
title: '{{tr "NoServerSelected"}}',
|
||||
description: '',
|
||||
type: 'warning',
|
||||
time: '2',
|
||||
position: 'top-center',
|
||||
});
|
||||
return
|
||||
}
|
||||
showConfirm('{{tr "DeleteServer"}}', '{{tr "ConfirmToDeleteServer"}}', () => postJson('/api/batch-delete-server', servers), '')
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
|
@ -12,7 +12,7 @@
|
||||
<script src="https://cdn.staticfile.org/semantic-ui/2.4.1/semantic.min.js"></script>
|
||||
<script src="/static/semantic-ui-alerts.min.js"></script>
|
||||
<script src="https://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script>
|
||||
<script src="/static/main.js?v20230417"></script>
|
||||
<script src="/static/main.js?v20230614"></script>
|
||||
<script>
|
||||
(function () {
|
||||
updateLang({{.LANG }});
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/naiba/nezha/pkg/utils"
|
||||
)
|
||||
|
||||
var Version = "v0.15.0" // !!记得修改 README 中的 badge 版本!!
|
||||
var Version = "v0.15.1" // !!记得修改 README 中的 badge 版本!!
|
||||
|
||||
var (
|
||||
Conf *model.Config
|
||||
|
Loading…
Reference in New Issue
Block a user