333 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			333 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
		
			Vendored
		
	
	
	
{{define "theme-server-status/home"}}
 | 
						|
{{template "theme-server-status/header" .}}
 | 
						|
<div id="app">
 | 
						|
    {{template "theme-server-status/content-nav" .}}
 | 
						|
    <div class="container table-responsive content" style="max-width: 95vw">
 | 
						|
        <table class="table table-striped table-condensed table-hover">
 | 
						|
            <thead>
 | 
						|
            <tr>
 | 
						|
                <th class="node-cell status center">🍀 {{tr "Status"}}</th>
 | 
						|
                <th class="node-cell name">🚀 {{tr "Name"}}</th>
 | 
						|
                <th class="node-cell os">🗂 {{tr "Platform"}}</th>
 | 
						|
                <th class="node-cell location center">🌍 {{tr "Location"}}</th>
 | 
						|
                <th class="node-cell uptime center">⏱️ {{tr "Uptime"}}</th>
 | 
						|
                <th class="node-cell load center">📋{{tr "Load"}}</th>
 | 
						|
                <th class="node-cell network center">🚦 {{tr "NetSpeed"}}↓|↑</th>
 | 
						|
                <th class="node-cell traffic center">📊 {{tr "NetTransfer"}}↓|↑</th>
 | 
						|
                <th class="node-cell cpu center">🎯 {{tr "CpuUsed"}}</th>
 | 
						|
                <th class="node-cell ram center">⚡ {{tr "MemUsed"}}</th>
 | 
						|
                <th class="node-cell hdd center">💾 {{tr "DiskUsed"}}</th>
 | 
						|
            </tr>
 | 
						|
            </thead>
 | 
						|
            <tbody id="servers">
 | 
						|
            <template v-for="(node,index) in nodes">
 | 
						|
                <tr :id="'r'+index" data-toggle="collapse" :data-target="'#rt'+index" class="accordion-toggle"
 | 
						|
                    :class="index % 2 === 0 ? 'odd': 'even'">
 | 
						|
                    <td class="node-cell status center">
 | 
						|
                        <div class="status-container">
 | 
						|
                            <div v-if="node.online" class="status-icon online"></div>
 | 
						|
                            <div v-else class="status-icon offline"></div>
 | 
						|
                        </div>
 | 
						|
                    </td>
 | 
						|
                    <td class="node-cell name">@#node.name#@</td>
 | 
						|
                    <td class="node-cell os">
 | 
						|
                        <i v-if='node.os == "darwin"' class="apple icon"></i>
 | 
						|
                        <i v-else-if='isWindowsPlatform(node.host.Platform)' class="windows icon"></i>
 | 
						|
                        <i v-else :class="'fl-' + getFontLogoClass(node.host.Platform)"></i>
 | 
						|
                        @#node.os#@
 | 
						|
                    </td>
 | 
						|
                    <td style="text-align: center;" class="node-cell location">
 | 
						|
                        <i :class="node.location + ' flag'"></i> 
 | 
						|
                        <span class="text-uppercase">@#node.location#@</span>
 | 
						|
                    </td>
 | 
						|
                    <td style="text-align: center;" class="node-cell uptime">@#node.uptime#@</td>
 | 
						|
                    <td style="text-align: center;" class="node-cell load">@#node.load#@</td>
 | 
						|
                    <td style="text-align: center;" class="node-cell network">@#node.network#@</td>
 | 
						|
                    <td style="text-align: center;" class="node-cell traffic">@#node.traffic#@</td>
 | 
						|
                    <td class="node-cell cpu">
 | 
						|
                        <div class="progress">
 | 
						|
                            <div :style="node.cpu.style" :class="node.cpu.class"><small>@#node.cpu.percent#@%</small>
 | 
						|
                            </div>
 | 
						|
                        </div>
 | 
						|
                    </td>
 | 
						|
                    <td class="node-cell memory">
 | 
						|
                        <div class="progress">
 | 
						|
                            <div :style="node.memory.style" :class="node.memory.class">
 | 
						|
                                <small>@#node.memory.percent#@%</small>
 | 
						|
                            </div>
 | 
						|
                        </div>
 | 
						|
                    </td>
 | 
						|
                    <td class="node-cell hdd">
 | 
						|
                        <div class="progress">
 | 
						|
                            <div :style="node.hdd.style" :class="node.hdd.class"><small>@#node.hdd.percent#@%</small>
 | 
						|
                            </div>
 | 
						|
                        </div>
 | 
						|
                    </td>
 | 
						|
                </tr>
 | 
						|
                <tr class="expandRow" :class="index % 2 === 0 ? 'odd': 'even'">
 | 
						|
                    <td colspan="16">
 | 
						|
                        <div class="accordian-body collapse" :id="'rt'+index">
 | 
						|
                            <div style="display: flex;align-items: center;justify-content: center;flex-direction: column;">
 | 
						|
                                <div style="display: flex;align-items: flex-start;justify-content: center;flex-direction: column; width: 450px;max-width: 90vw">
 | 
						|
                                <span class="node-cell-expand">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "Platform"}}:</span>
 | 
						|
                                    @#node.host.Platform#@
 | 
						|
                                </span>
 | 
						|
                                <span class="node-cell-expand">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "Location"}}:</span>
 | 
						|
                                    <i :class="node.location + ' flag'"></i>
 | 
						|
                                </span>
 | 
						|
                                <span class="node-cell-expand" v-if="node.host.CPU">
 | 
						|
                                    <span class="node-cell-expand-label">CPU:</span>
 | 
						|
                                    @#node.host.CPU.join(",")#@
 | 
						|
                                </span>
 | 
						|
                                    <span class="node-cell-expand load">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "Load"}}:</span>
 | 
						|
                                    @#toFixed2(node.state.Load1)#@ / @#toFixed2(node.state.Load5)#@ /@#toFixed2(node.state.Load15)#@
 | 
						|
                                </span>
 | 
						|
                                    <span class="node-cell-expand">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "DiskUsed"}}:</span>
 | 
						|
                                    @#formatByteSize(node.state.DiskUsed)#@ / @#formatByteSize(node.host.DiskTotal)#@
 | 
						|
                                </span>
 | 
						|
                                    <span class="node-cell-expand">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "MemUsed"}}:</span>
 | 
						|
                                    @#formatByteSize(node.state.MemUsed)#@ / @#formatByteSize(node.host.MemTotal)#@(@#toFixed2(node.state.MemUsed / node.host.MemTotal * 100)#@%)
 | 
						|
                                </span>
 | 
						|
                                    <span class="node-cell-expand">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "NetTransfer"}}:</span>
 | 
						|
                                    <i class="arrow alternate circle down outline icon"
 | 
						|
                                       style="margin: 0"></i>@#formatByteSize(node.state.NetInTransfer)#@
 | 
						|
                                    <i class="arrow alternate circle up outline icon"
 | 
						|
                                       style="margin: 0"></i>@#formatByteSize(node.state.NetOutTransfer)#@
 | 
						|
                                </span>
 | 
						|
                                    <span class="node-cell-expand">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "SwapUsed"}}:</span>
 | 
						|
                                    @#formatByteSize(node.state.SwapUsed)#@ / @#formatByteSize(node.host.SwapTotal)#@
 | 
						|
                                    <span v-if="node.host.SwapTotal">(@#toFixed2(node.state.SwapUsed / node.host.SwapTotal * 100)#@%)</span>
 | 
						|
                                </span>
 | 
						|
                                    <span class="node-cell-expand">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "BootTime"}}:</span>
 | 
						|
                                    @#formatTimestamp(node.host.BootTime)#@
 | 
						|
                                </span>
 | 
						|
                                    <span class="node-cell-expand">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "LastActive"}}:</span>
 | 
						|
                                    @#new Date(node.lastActive).toLocaleString()#@
 | 
						|
                                </span>
 | 
						|
                                    <span class="node-cell-expand" v-if="node.host.Virtualization">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "Virtualization"}}:</span>
 | 
						|
                                    @#node.host.Virtualization#@
 | 
						|
                                </span>
 | 
						|
                                    <span class="node-cell-expand">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "ProcessCount"}}:</span>
 | 
						|
                                    @#node.state.ProcessCount#@
 | 
						|
                                </span>
 | 
						|
                                    <span class="node-cell-expand">
 | 
						|
                                    <span class="node-cell-expand-label">{{tr "ConnCount"}}:</span>
 | 
						|
                                    TCP @#node.state.TcpConnCount#@ / UDP @#node.state.UdpConnCount#@
 | 
						|
                                </span>
 | 
						|
                                </div>
 | 
						|
                            </div>
 | 
						|
                        </div>
 | 
						|
                    </td>
 | 
						|
                </tr>
 | 
						|
            </template>
 | 
						|
 | 
						|
            </tbody>
 | 
						|
        </table>
 | 
						|
        <br/>
 | 
						|
    </div>
 | 
						|
    {{template "theme-server-status/content-footer" .}}
 | 
						|
</div>
 | 
						|
<script>
 | 
						|
    new Vue({
 | 
						|
        el: '#app',
 | 
						|
        delimiters: ['@#', '#@'],
 | 
						|
        data: {
 | 
						|
            nodes: [],
 | 
						|
        },
 | 
						|
        mixins: [mixinsVue],
 | 
						|
        created() {
 | 
						|
            const initData = JSON.parse('{{.Servers}}').servers;
 | 
						|
            this.nodes = this.handleNodes(initData);
 | 
						|
            this.initTheme()
 | 
						|
        },
 | 
						|
        mounted() {
 | 
						|
            this.connect();
 | 
						|
        },
 | 
						|
        methods: {
 | 
						|
            isWindowsPlatform(str) {
 | 
						|
                return str.includes('Windows')
 | 
						|
            },
 | 
						|
            getFontLogoClass(str) {
 | 
						|
                if (["almalinux",
 | 
						|
                        "alpine",
 | 
						|
                        "aosc",
 | 
						|
                        "apple",
 | 
						|
                        "archlinux",
 | 
						|
                        "archlabs",
 | 
						|
                        "artix",
 | 
						|
                        "budgie",
 | 
						|
                        "centos",
 | 
						|
                        "coreos",
 | 
						|
                        "debian",
 | 
						|
                        "deepin",
 | 
						|
                        "devuan",
 | 
						|
                        "docker",
 | 
						|
                        "elementary",
 | 
						|
                        "fedora",
 | 
						|
                        "ferris",
 | 
						|
                        "flathub",
 | 
						|
                        "freebsd",
 | 
						|
                        "gentoo",
 | 
						|
                        "gnu-guix",
 | 
						|
                        "illumos",
 | 
						|
                        "kali-linux",
 | 
						|
                        "linuxmint",
 | 
						|
                        "mageia",
 | 
						|
                        "mandriva",
 | 
						|
                        "manjaro",
 | 
						|
                        "nixos",
 | 
						|
                        "openbsd",
 | 
						|
                        "opensuse",
 | 
						|
                        "pop-os",
 | 
						|
                        "raspberry-pi",
 | 
						|
                        "redhat",
 | 
						|
                        "rocky-linux",
 | 
						|
                        "sabayon",
 | 
						|
                        "slackware",
 | 
						|
                        "snappy",
 | 
						|
                        "solus",
 | 
						|
                        "tux",
 | 
						|
                        "ubuntu",
 | 
						|
                        "void",
 | 
						|
                        "zorin"].indexOf(str)
 | 
						|
                    > -1) {
 | 
						|
                    return str;
 | 
						|
                }
 | 
						|
                if (['openwrt', 'linux', "immortalwrt"].indexOf(str) > -1) {
 | 
						|
                    return 'tux';
 | 
						|
                }
 | 
						|
                if (str == 'amazon') {
 | 
						|
                    return 'redhat';
 | 
						|
                }
 | 
						|
                if (str == 'arch') {
 | 
						|
                    return 'archlinux';
 | 
						|
                }
 | 
						|
                return '';
 | 
						|
            },
 | 
						|
            secondToDate(s) {
 | 
						|
                const d = Math.floor(s / 3600 / 24);
 | 
						|
                if (d > 0) {
 | 
						|
                    return d + ' {{tr "Day"}}'
 | 
						|
                }
 | 
						|
                const h = Math.floor(s / 3600 % 24);
 | 
						|
                const m = Math.floor(s / 60 % 60);
 | 
						|
                const second = Math.floor(s % 60);
 | 
						|
                return h + ":" + ("0" + m).slice(-2) + ":" + ("0" + second).slice(-2);
 | 
						|
            },
 | 
						|
            formatTimestamp(t) {
 | 
						|
                return new Date(t * 1000).toLocaleString()
 | 
						|
            },
 | 
						|
            formatByteSize(bs) {
 | 
						|
                const x = this.readableBytes(bs)
 | 
						|
                return x !== "NaN undefined" ? x : '0B'
 | 
						|
            },
 | 
						|
            formatPercent(live, used, total) {
 | 
						|
                const percent = live ? (this.toFixed2(used / total * 100) || 0) : 1
 | 
						|
                return this.formatPercents(percent)
 | 
						|
            },
 | 
						|
            formatPercents(percent) {
 | 
						|
                if (percent <= 0) {
 | 
						|
                    percent = 1;
 | 
						|
                }
 | 
						|
                if (!this.cache[percent]) {
 | 
						|
                    this.cache[percent] = {
 | 
						|
                        class: 'progress-bar progress-bar-success',
 | 
						|
                        style: `width: ${parseInt(percent)}%`,
 | 
						|
                        percent,
 | 
						|
                    }
 | 
						|
                    if (percent < 80) {
 | 
						|
                        this.cache[percent].class = 'progress-bar progress-bar-success'
 | 
						|
                    } else if (percent < 90) {
 | 
						|
                        this.cache[percent].class = 'progress-bar progress-bar-warning'
 | 
						|
                    } else {
 | 
						|
                        this.cache[percent].class = 'progress-bar progress-bar-danger'
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                return this.cache[percent]
 | 
						|
            },
 | 
						|
            readableBytes(bytes) {
 | 
						|
                if (!bytes) {
 | 
						|
                    return '0B'
 | 
						|
                }
 | 
						|
                const i = Math.floor(Math.log(bytes) / Math.log(1024)),
 | 
						|
                    sizes = ["B", "K", "M", "G", "T", "P", "E", "Z", "Y"];
 | 
						|
                return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + sizes[i];
 | 
						|
            },
 | 
						|
            connect() {
 | 
						|
                const wsProtocol = window.location.protocol === "https:" ? "wss" : "ws"
 | 
						|
                const ws = new WebSocket(wsProtocol + '://' + window.location.host + '/ws');
 | 
						|
                ws.onopen = function () {
 | 
						|
                    console.log("Connection open ...")
 | 
						|
                }
 | 
						|
                ws.onmessage = (evt) => {
 | 
						|
                    let jsonData = evt.data
 | 
						|
                    const data = JSON.parse(jsonData)
 | 
						|
                    for (let i = 0; i < data.servers?.length; i++) {
 | 
						|
                        const ns = data.servers[i];
 | 
						|
                        if (!ns.Host) {
 | 
						|
                            data.servers[i].live = false
 | 
						|
                        } else {
 | 
						|
                            const lastActive = new Date(ns.LastActive).getTime()
 | 
						|
                            data.servers[i].live = data.now - lastActive <= 10 * 1000;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    this.nodes = this.handleNodes(data.servers)
 | 
						|
                }
 | 
						|
                ws.onclose = () => {
 | 
						|
                    setTimeout(function () {
 | 
						|
                        this.connect()
 | 
						|
                    }, 5000);
 | 
						|
                }
 | 
						|
                ws.onerror = function () {
 | 
						|
                    ws.close()
 | 
						|
                }
 | 
						|
            },
 | 
						|
            handleNodes(servers) {
 | 
						|
                let nodes = []
 | 
						|
                servers?.forEach(server => {
 | 
						|
                    let platform = server.Host.Platform
 | 
						|
                    if (this.isWindowsPlatform(server.Host.Platform)) {
 | 
						|
                        platform = "windows"
 | 
						|
                    }else if (platform === "immortalwrt") {
 | 
						|
                        platform = "openwrt"
 | 
						|
                    }
 | 
						|
                    let node = {
 | 
						|
                        name: server.Name,
 | 
						|
                        os: platform,
 | 
						|
                        location: server.Host.CountryCode,
 | 
						|
                        uptime: this.secondToDate(server.State.Uptime),
 | 
						|
                        load: this.toFixed2(server.State.Load1),
 | 
						|
                        network: this.getNetworkSpeed(server.State.NetInSpeed, server.State.NetOutSpeed),
 | 
						|
                        traffic: this.formatByteSize(server.State.NetInTransfer) + ' | ' + this.formatByteSize(server.State.NetOutTransfer),
 | 
						|
                        cpu: this.formatPercents(this.toFixed2(server.State.CPU)),
 | 
						|
                        memory: this.formatPercent(server.live, server.State.MemUsed, server.Host.MemTotal),
 | 
						|
                        hdd: this.formatPercent(server.live, server.State.DiskUsed, server.Host.DiskTotal),
 | 
						|
                        online: server.live,
 | 
						|
                        state: server.State,
 | 
						|
                        host: server.Host,
 | 
						|
                        lastActive: server.LastActive,
 | 
						|
                    }
 | 
						|
                    nodes.push(node)
 | 
						|
                })
 | 
						|
                return nodes;
 | 
						|
            },
 | 
						|
            getNetworkSpeed(netInSpeed, netOutSpeed) {
 | 
						|
                return this.formatByteSize(netInSpeed) + ' | ' + this.formatByteSize(netOutSpeed)
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
    })
 | 
						|
</script>
 | 
						|
{{template "theme-server-status/footer" .}}
 | 
						|
{{end}} |