🚀 dsahboard v0.13.26 custom dashboard theme

This commit is contained in:
naiba
2022-06-03 10:02:11 +08:00
parent 63ad192109
commit fc37a50759
12 changed files with 2 additions and 2 deletions

View File

@@ -0,0 +1,41 @@
{{define "dashboard-default/api"}}
{{template "common/header" .}}
{{template "common/menu" .}}
<div class="nb-container">
<div class="ui container">
<div class="ui grid">
<div class="right floated right aligned twelve wide column">
<button class="ui right labeled nezha-primary-btn icon button" onclick="issueNewApiToken()"><i class="add icon"></i>
{{tr "IssueNewApiToken"}}
</button>
</div>
</div>
<table class="ui very basic table">
<thead>
<tr>
<th>{{tr "Token"}}</th>
<th>{{tr "Note"}}</th>
</tr>
</thead>
<tbody>
{{range $token := .Tokens}}
<tr>
<td>{{$token.Token}}</td>
<td>{{$token.Note}}</td>
<td>
<div class="ui mini icon buttons">
<button class="ui button"
onclick="showConfirm('{{tr "DeleteToken"}}','{{tr "ConfirmToDeleteThisToken"}}',deleteRequest,'/api/token/'+{{$token.Token}})">
<i class="trash alternate outline icon"></i>
</button>
</div>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
{{template "component/api"}}
{{template "common/footer" .}}
{{end}}

View File

@@ -0,0 +1,64 @@
{{define "dashboard-default/cron"}}
{{template "common/header" .}}
{{template "common/menu" .}}
<div class="nb-container">
<div class="ui container">
<div class="ui grid">
<div class="right floated right aligned twelve wide column">
<button class="ui right labeled nezha-primary-btn icon button" onclick="addOrEditCron()"><i class="add icon"></i>
{{tr "AddScheduledTasks"}}
</button>
</div>
</div>
<table class="ui very basic table">
<thead>
<tr>
<th>ID</th>
<th>{{tr "Name"}}</th>
<th>{{tr "Scheduler"}}</th>
<th>{{tr "Command"}}</th>
<th>{{tr "NotificationMethodGroup"}}</th>
<th>{{tr "PushSuccessfully"}}</th>
<th>{{tr "Coverage"}}</th>
<th>{{tr "SpecificServers"}}</th>
<th>{{tr "LastExecution"}}</th>
<th>{{tr "LastResult"}}</th>
<th>{{tr "Administration"}}</th>
</tr>
</thead>
<tbody>
{{range $cron := .Crons}}
<tr>
<td>{{$cron.ID}}</td>
<td>{{$cron.Name}}</td>
<td>{{$cron.Scheduler}}</td>
<td>{{$cron.Command}}</td>
<td>{{$cron.NotificationTag}}</td>
<td>{{$cron.PushSuccessful}}</td>
<td>{{if eq $cron.Cover 0}}{{tr "IgnoreAll"}}{{else}}{{tr "CoverAll"}}{{end}}</td>
<td>{{$cron.ServersRaw}}</td>
<td>{{$cron.LastExecutedAt|tf}}</td>
<td>{{$cron.LastResult}}</td>
<td>
<div class="ui mini icon buttons">
<button class="ui button" onclick="manualTrigger(this, {{$cron.ID}})">
<i class="play icon"></i>
</button>
<button class="ui button" onclick="addOrEditCron({{$cron}})">
<i class="edit icon"></i>
</button>
<button class="ui button"
onclick="showConfirm('{{tr "DeleteScheduledTask"}}','{{tr "ConfirmToDeleteThisScheduledTask"}}',deleteRequest,'/api/cron/'+{{$cron.ID}})">
<i class="trash alternate outline icon"></i>
</button>
</div>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
{{template "component/cron"}}
{{template "common/footer" .}}
{{end}}

View File

@@ -0,0 +1,22 @@
{{define "dashboard-default/error"}}
{{template "common/header" .}}
<div class="login nb-container">
<div class="ui center aligned grid">
<div class="column">
<h2 class="ui image header">
<img src="/static/logo.svg?v20210804" class="image">
<div class="content">
{{tr "AccessDenied"}}
</div>
</h2>
<div class="ui message">
<p>
{{.Msg}}
</p>
<a href="{{.Link}}">{{.Btn}}</a>
</div>
</div>
</div>
</div>
{{template "common/footer" .}}
{{end}}

View File

@@ -0,0 +1,20 @@
{{define "dashboard-default/login"}}
{{template "common/header" .}}
<div class="login nb-container">
<div class="ui center aligned grid">
<div class="column">
<h2 class="ui image header">
<img src="static/logo.svg?v20210804" class="image">
<div class="content">
{{tr "Use"}} {{.LoginType}} {{tr "AccountToLogin"}}
</div>
</h2>
<a href="/oauth2/login" class="ui fluid large nezha-primary-btn submit button">{{tr "Login"}}</a>
<div class="ui message">
{{tr "DontHaveAnAccount"}} <a href="{{.RegistrationLink}}" target="_blank" rel="noopener noreferrer">{{tr "SignUp"}}</a>
</div>
</div>
</div>
</div>
{{template "common/footer" .}}
{{end}}

View File

@@ -0,0 +1,63 @@
{{define "dashboard-default/monitor"}} {{template "common/header" .}} {{template
"common/menu" .}}
<div class="nb-container">
<div class="ui container">
<div class="ui grid">
<div class="right floated right aligned twelve wide column">
<button class="ui right labeled nezha-primary-btn icon button" onclick="addOrEditMonitor()">
<i class="add icon"></i> {{tr "AddMonitor"}}
</button>
</div>
</div>
<table class="ui very basic table">
<thead>
<tr>
<th>ID</th>
<th>{{tr "Name"}}</th>
<th>{{tr "Target"}}</th>
<th>{{tr "Coverage"}}</th>
<th>{{tr "SpecificServers"}}</th>
<th>{{tr "Type"}}</th>
<th>{{tr "Duration"}}</th>
<th>{{tr "NotificationMethodGroup"}}</th>
<th>{{tr "Notification"}}</th>
<th>{{tr "Administration"}}</th>
</tr>
</thead>
<tbody>
{{range $monitor := .Monitors}}
<tr>
<td>{{$monitor.ID}}</td>
<td>{{$monitor.Name}}</td>
<td>{{$monitor.Target}}</td>
<td>{{if eq $monitor.Cover 0}}{{tr "CoverAll"}}{{else}}{{tr "IgnoreAll"}}{{end}}</td>
<td>{{$monitor.SkipServersRaw}}</td>
<td>
{{if eq $monitor.Type 1}}{{tr "SSLCertificate"}} {{else if eq $monitor.Type
2}} ICMP Ping {{else}} {{tr "TCPPort"}} {{end}}
</td>
<td>{{$monitor.Duration}} {{tr "Seconds"}}</td>
<td>{{$monitor.NotificationTag}}</td>
<td>{{$monitor.Notify}}</td>
<td>
<div class="ui mini icon buttons">
<button class="ui button" onclick="addOrEditMonitor({{$monitor}})">
<i class="edit icon"></i>
</button>
<button class="ui button"
onclick="showConfirm('{{tr "DeleteService"}}','{{tr "ConfirmToDeleteThisService"}}',deleteRequest,'/api/monitor/'+{{$monitor.ID}})">
<i class="trash alternate outline icon"></i>
</button>
</div>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
{{template "component/monitor"}} {{template "common/footer" .}}
<script>
$(".checkbox").checkbox();
</script>
{{end}}

View File

@@ -0,0 +1,97 @@
{{define "dashboard-default/notification"}}
{{template "common/header" .}}
{{template "common/menu" .}}
<div class="nb-container">
<div class="ui container">
<div class="ui grid">
<div class="right floated right aligned twelve wide column">
<button class="ui right labeled nezha-primary-btn icon button" onclick="addOrEditNotification()"><i
class="add icon"></i> {{tr "AddNotificationMethod"}}
</button>
</div>
</div>
<table class="ui very basic table">
<thead>
<tr>
<th>ID</th>
<th>{{tr "Name"}}</th>
<th>{{tr "Tag"}}</th>
<th>URL</th>
<th>{{tr "VerifySSL"}}</th>
<th>{{tr "Administration"}}</th>
</tr>
</thead>
<tbody>
{{range $notification := .Notifications}}
<tr>
<td>{{$notification.ID}}</td>
<td>{{$notification.Name}}</td>
<td>{{$notification.Tag}}</td>
<td>{{$notification.URL}}</td>
<td>{{$notification.VerifySSL}}</td>
<td>
<div class="ui mini icon buttons">
<button class="ui button" onclick="addOrEditNotification({{$notification}})">
<i class="edit icon"></i>
</button>
<button class="ui button"
onclick="showConfirm('{{tr "DeleteNotificationMethod"}}','{{tr "ConfirmToDeleteThisNotificationMethod"}}',deleteRequest,'/api/notification/'+{{$notification.ID}})">
<i class="trash alternate outline icon"></i>
</button>
</div>
</td>
</tr>
{{end}}
</tbody>
</table>
<div class="ui grid">
<div class="right floated right aligned twelve wide column">
<button class="ui right labeled nezha-primary-btn icon button" onclick="addOrEditAlertRule()"><i
class="add icon"></i>
{{tr "AddNotificationRule"}}
</button>
</div>
</div>
<table class="ui very basic table">
<thead>
<tr>
<th>ID</th>
<th>{{tr "Name"}}</th>
<th>{{tr "NotificationMethodGroup"}}</th>
<th>{{tr "Rules"}}</th>
<th>{{tr "Enable"}}</th>
<th>{{tr "Administration"}}</th>
</tr>
</thead>
<tbody>
{{range $rule := .AlertRules}}
<tr>
<td>{{$rule.ID}}</td>
<td>{{$rule.Name}}</td>
<td>{{$rule.NotificationTag}}</td>
<td>{{$rule.RulesRaw}}</td>
<td>{{$rule.Enable}}</td>
<td>
<div class="ui mini icon buttons">
<button class="ui button" onclick="addOrEditAlertRule({{$rule}})">
<i class="edit icon"></i>
</button>
<button class="ui button"
onclick="showConfirm('{{tr "DeleteNotificationMethod"}}','{{tr "ConfirmToDeleteThisNotificationMethod"}}',deleteRequest,'/api/alert-rule/'+{{$rule.ID}})">
<i class="trash alternate outline icon"></i>
</button>
</div>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
{{template "component/notification"}}
{{template "component/rule"}}
{{template "common/footer" .}}
<script>
$('.checkbox').checkbox()
</script>
{{end}}

View File

@@ -0,0 +1,18 @@
{{define "dashboard-default/redirect"}}
<!DOCTYPE html>
<html lang="{{.Conf.Language}}">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Redireting..</title>
</head>
<body>
<p>Please click <a href="{{.URL}}">here</a> if you are not redirected.</p>
<script>window.location.href = "{{.URL}}"</script>
</body>
</html>
{{end}}

View File

@@ -0,0 +1,132 @@
{{define "dashboard-default/server"}}
{{template "common/header" .}}
{{template "common/menu" .}}
<div class="nb-container">
<div class="ui container">
<div class="ui grid">
<div class="right floated right aligned twelve wide column">
<button class="ui right labeled nezha-primary-btn icon button" onclick="addOrEditServer()"><i
class="add icon"></i> {{tr "AddServer"}}
</button>
<button class="ui right labeled nezha-primary-btn icon button" onclick="forceUpdate()"><i
class="arrow alternate circle up outline icon"></i> {{tr "ForceUpdate"}}
</button>
</div>
</div>
<table class="ui very basic table">
<thead>
<tr>
<th><button onclick="checkAllServer()" class="ui mini nezha-primary-btn button">{{tr "SelectAll"}}</button></th>
<th>ID({{tr "DisplayIndex"}})</th>
<th>{{tr "Name"}}</th>
<th>{{tr "ServerGroup"}}</th>
<th>IP</th>
<th>{{tr "VersionNumber"}}</th>
<th>{{tr "Secret"}}</th>
<th>{{tr "OneKeyInstall"}}</th>
<th>{{tr "Note"}}</th>
<th>{{tr "Administration"}}</th>
</tr>
</thead>
<tbody>
{{range $server := .Servers}}
<tr>
<td><input type="checkbox" class="nezha-servers" value="{{$server.ID}}" /></td>
<td>{{$server.ID}}({{$server.DisplayIndex}})</td>
<td>{{$server.Name}}</td>
<td>{{$server.Tag}}</td>
<td>{{$server.Host.IP}}</td>
<td>{{$server.Host.Version}}</td>
<td>{{$server.Secret}}</td>
<td>
<button class="ui icon green mini button"
data-clipboard-text="{{if $.Conf.GRPCHost}}curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.sh -o nezha.sh && chmod +x nezha.sh && sudo ./nezha.sh install_agent {{$.Conf.GRPCHost}} {{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"
data-tooltip="{{tr "ClickToCopyTheInstallationCommand"}}">
<i class="linux icon"></i>
</button>
<button class="ui icon green mini button"
data-clipboard-text="{{if $.Conf.GRPCHost}}set-ExecutionPolicy RemoteSigned;Invoke-WebRequest https://raw.githubusercontent.com/naiba/nezha/master/script/install.ps1 -OutFile C:\install.ps1;powershell.exe C:\install.ps1 {{$.Conf.GRPCHost}}:{{if $.Conf.ProxyGRPCPort}}{{$.Conf.ProxyGRPCPort}}{{else}}{{$.Conf.GRPCPort}}{{end}} {{$server.Secret}}{{if $.Conf.TLS}} --tls{{end}}{{else}}{{tr "NoDomainAlert"}}{{end}}"
data-tooltip="{{tr "ClickToCopyTheInstallationCommand"}}">
<i class="windows icon"></i>
</button>
</td>
<td style="word-break: break-word;">{{$server.Note}}</td>
<td>
<div class="ui mini icon buttons">
<button class="ui button" onclick="connectToServer({{$server.ID}})">
<i class="terminal icon"></i>
</button>
<button class="ui button" onclick="addOrEditServer({{$server.Marshal}})">
<i class="edit icon"></i>
</button>
<button class="ui button"
onclick="showConfirm('{{tr "DeleteServer"}}','{{tr "ConfirmToDeleteThisServer"}}',deleteRequest,'/api/server/'+{{$server.ID}})">
<i class="trash alternate outline icon"></i>
</button>
</div>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
{{template "component/server" .}}
{{template "common/footer" .}}
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/clipboard.js/2.0.10/clipboard.min.js" type="application/javascript"></script>
<script>
var clipboard = new ClipboardJS('.ui.icon.green.mini.button');
const checkBoxList = document.querySelectorAll('tbody > tr > td > input.nezha-servers[type=checkbox]')
function checkAllServer() {
checkBoxList.forEach(cb => {
cb.checked = true
})
}
function forceUpdate() {
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
}
$.post('/api/force-update', JSON.stringify(servers))
.then((resp) => {
if (resp.code == 200) {
$.suiAlert({
title: '{{tr "ExecutionResults"}}',
description: resp.message,
type: 'success',
time: '3',
position: 'top-center',
});
} else {
$.suiAlert({
title: '',
description: resp.message,
type: 'error',
time: '3',
position: 'top-center',
});
}
}).catch(err => {
$.suiAlert({
title: '',
description: err,
type: 'error',
time: '3',
position: 'top-center',
});
})
}
</script>
{{end}}

View File

@@ -0,0 +1,132 @@
{{define "dashboard-default/setting"}}
{{template "common/header" .}}
{{template "common/menu" .}}
<div class="nb-container">
<div class="ui container">
<form id="settingForm" class="ui large form" onsubmit="return false;">
<div class="field">
<label>{{tr "SiteTitle"}}</label>
<input type="text" name="Title" placeholder="{{tr "NezhaMonitoring"}}" value="{{.Conf.Site.Brand}}">
</div>
<div class="field">
<label>{{tr "AdministratorList"}}</label>
<input type="text" name="Admin" placeholder="1010,2020" value="{{.Conf.Oauth2.Admin}}">
</div>
<div class="field">
<label>{{tr "Theme"}}</label>
<select name="Theme">
{{range $k,$v := .Themes}}
<option value="{{$k}}" {{if eq $.Conf.Site.Theme $k }} selected="selected" {{end}}>{{$v}}
{{end}}
</select>
</div>
<div class="field">
<label>{{tr "DashboardTheme"}}</label>
<select name="DashboardTheme">
{{range $k,$v := .DashboardThemes}}
<option value="{{$k}}" {{if eq $.Conf.Site.DashboardTheme $k }} selected="selected" {{end}}>{{$v}}
{{end}}
</select>
</div>
<div class="field">
<label>Language</label>
<select name="Language">
{{range $k,$v := .Languages}}
<option value="{{$k}}" {{if eq $.Conf.Language $k }} selected="selected" {{end}}>
{{$v}}</option>
{{end}}
</select>
</div>
<div class="field">
<label>{{tr "CustomCodes"}}</label>
<textarea name="CustomCode">{{.Conf.Site.CustomCode}}</textarea>
</div>
<div class="field">
<label>{{tr "AccessPassword"}}</label>
<input type="text" name="ViewPassword" placeholder="" value="{{.Conf.Site.ViewPassword}}">
</div>
<div class="field">
<label>{{tr "PanelServerDomainAndIP"}}</label>
<input type="text" name="GRPCHost" placeholder="" value="{{.Conf.GRPCHost}}">
</div>
<div class="field">
<label>{{tr "IPChangeAlert"}}</label>
</div>
<div class="ui segment">
<div class="field">
<label>{{tr "Coverage"}}</label>
<select name="Cover" class="ui fluid dropdown">
<option value=0>{{tr "AllIncludedOnlySpecificServersAreNotAlerted"}}</option>
<option value=1>{{tr "IgnoreAllOnlyAlertSpecificServers"}}</option>
</select>
</div>
<div class="field">
<label>{{tr "SpecificServers"}}</label>
<input type="text" name="IgnoredIPNotification" placeholder="{{tr "ServerIDSeparatedByCommas"}} 1001,1002,1003"
value="{{.Conf.IgnoredIPNotification}}">
</div>
<div class="field">
<label>{{tr "IPChangeNotificationTag"}}</label>
<input type="text" name="IPChangeNotificationTag" placeholder="" value="{{.Conf.IPChangeNotificationTag}}">
</div>
<div class="field">
<div class="ui nf-ssl checkbox ip-change">
<input name="EnableIPChangeNotification" type="checkbox" tabindex="0" class="hidden">
<label>{{tr "Enable"}}</label>
</div>
</div>
</div>
<div class="field">
<div class="ui nf-ssl checkbox plain-ip">
<input name="EnablePlainIPInNotification" type="checkbox" tabindex="0" class="hidden">
<label>{{tr "NotificationMessagesDoNotHideIP"}}</label>
</div>
</div>
<button class="ui button" type="submit">{{tr "Save"}}</button>
</form>
</div>
</div>
{{template "common/footer" .}}
<script>
$('#settingForm').submit(function () {
$.post('/api/setting', $('#settingForm').serialize())
.then((resp) => {
if (resp.code == 200) {
$.suiAlert({
title: '',
description: '{{tr "ModifiedSuccessfully"}}',
type: 'success',
time: '3',
position: 'top-center',
});
window.location.reload()
} else {
$.suiAlert({
title: '',
description: resp.message,
type: 'error',
time: '3',
position: 'top-center',
});
}
}).catch(err => {
$.suiAlert({
title: '',
description: err,
type: 'error',
time: '3',
position: 'top-center',
});
})
return false;
})
$('.checkbox').checkbox()
$('#settingForm').find("select[name=Cover]").val({{.Conf.Cover }});
{{if .Conf.EnableIPChangeNotification}}
$('.checkbox.ip-change').checkbox('set checked')
{{ end }}
{{if .Conf.EnablePlainIPInNotification}}
$('.checkbox.plain-ip').checkbox('set checked')
{{ end }}
</script>
{{end}}

View File

@@ -0,0 +1,98 @@
{{define "dashboard-default/terminal"}}
<!DOCTYPE html>
<html lang="{{.Conf.Language}}">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>tty@{{.ServerName}} - {{.Title}}</title>
<link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" />
<link href="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/xterm/4.11.0/xterm.css" type="text/css" rel="stylesheet"/>
</head>
<style>
html,
body,
#terminal-container {
padding: unset;
margin: unset;
width: 100vw;
height: 100vh;
}
body {
background-color: black;
}
</style>
<body onresize="onResize()">
<div id="terminal-container"></div>
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/xterm/4.11.0/xterm.js" type="application/javascript"></script>
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/xterm/4.11.0/addons/attach/xterm-addon-attach.js"></script>
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/xterm/4.11.0/addons/fit/xterm-addon-fit.js"></script>
<script>
let sendResizing = false;
function doResize() {
fitAddon.fit()
const w = fitAddon.proposeDimensions();
const prefix = new Int8Array([1]);
const resizeMessage = new TextEncoder().encode(JSON.stringify({
Rows: w.rows,
Cols: w.cols,
}));
var msg = new Int8Array(prefix.length + resizeMessage.length);
msg.set(prefix);
msg.set(resizeMessage, prefix.length);
socket.send(msg)
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function onResize() {
if (sendResizing) return;
sendResizing = true;
try {
await sleep(1500);
doResize();
} catch (error) {
console.log('resize', error);
} finally {
sendResizing = false
}
}
const term = new Terminal({
screenKeys: true,
useStyle: true,
cursorBlink: true,
});
const socket = new WebSocket((window.location.protocol == 'https:' ? 'wss' : 'ws') + '://' + window.location.host + '/terminal/' + '{{.SessionID}}');
const attachAddon = new AttachAddon.AttachAddon(socket);
const fitAddon = new FitAddon.FitAddon();
term.loadAddon(attachAddon);
term.loadAddon(fitAddon);
term.open(document.getElementById('terminal-container'));
socket.onopen = () => {
onResize()
}
socket.onclose = () => {
alert('{{tr "TerminalConnectionTimeOutOrSessionEnded"}}')
window.close()
}
socket.onerror = () => {
alert('{{tr "TerminalConnectionFailed"}}')
}
</script>
</body>
</html>
{{end}}