History GUI upd
This commit is contained in:
parent
5c449f76ba
commit
e6f3b150ab
20 changed files with 157 additions and 98 deletions
|
|
@ -8,6 +8,9 @@ All notable changes to this project will be documented in this file.
|
|||
- Moved to `github.com/nicholas-fedor/shoutrrr` [#197](https://github.com/aceberg/WatchYourLAN/pull/197)
|
||||
- Removed `HIST_IN_DB` config option. Now history is always stored in `DB`
|
||||
|
||||
### Fixed
|
||||
- Memory leak bug [#149](https://github.com/aceberg/WatchYourLAN/pull/149)
|
||||
|
||||
## [v2.1.2] - 2025-03-30
|
||||
### Fixed
|
||||
- Edit names bug
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "watchyourlan",
|
||||
"private": true,
|
||||
"version": "2.1.2",
|
||||
"version": "2.1.3",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
|
|
|||
|
|
@ -19,16 +19,15 @@ function About() {
|
|||
</div>
|
||||
<div class="card-body">
|
||||
<p>● After changing <b>Host</b> or <b>Port</b> the app must be restarted</p>
|
||||
<p>● <b>Shoutrrr URL</b> provides notifications to Discord, Email, Gotify, Telegram and other services. <a href="https://containrrr.dev/shoutrrr/v0.8/" target="_blank">Link to documentation</a></p>
|
||||
<p>● <b>Shoutrrr URL</b> provides notifications to Discord, Email, Gotify, Telegram and other services. <a href="https://nicholas-fedor.github.io/shoutrrr/" target="_blank">Link to documentation</a></p>
|
||||
<p>● <b>Interfaces</b> - one or more, space separated</p>
|
||||
<p>● <b>Timeout (seconds)</b> - time between scans</p>
|
||||
<p>● <b>Args for arp-scan</b> - pass your own arguments to <code>arp-scan</code>. Enable <b>debug</b> log level to see resulting command. (Example: <code>-r 1</code>). See <a href="https://github.com/aceberg/WatchYourLAN/blob/main/docs/VLAN_ARP_SCAN.md" target="_blank">docs</a> for more.</p>
|
||||
<p>● <b>Arp Strings</b> - can setup scans for <code>vlans</code>, <code>docker0</code> and etcetera. See <a href="https://github.com/aceberg/WatchYourLAN/blob/main/docs/VLAN_ARP_SCAN.md" target="_blank">docs</a> for more.</p>
|
||||
<p>● <b>Trim History</b> - remove history after (hours)</p>
|
||||
<p>● <b>Store History in DB</b> - if off, the History will be stored only in memory and will be lost on app restart. Though, it will keep the app DB smaller and InfluxDB is recommended for long term History storage</p>
|
||||
<p>● <b>Store History in DB</b> - DEPRECATED. Now History is always stored in DB. Use <b>Trim History</b> to reduce DB size</p>
|
||||
<p>● <b>PG Connect URL</b> - address to connect to PostgreSQL DB. (Example: <code>postgres://username:password@192.168.0.1:5432/dbname?sslmode=disable</code>). Full list of URL parameters <a href="https://pkg.go.dev/github.com/lib/pq#hdr-Connection_String_Parameters" target="_blank">here</a></p>
|
||||
<p>● If you find this app useful, please, <a href="https://github.com/aceberg#donate" target="_blank">donate</a></p>
|
||||
<p>● Commission you own app (Golang, React/SolidJS). Contact <a href="https://github.com/aceberg" target="_blank">here</a></p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -48,17 +48,6 @@ function Scan() {
|
|||
<td>Trim History (hours)</td>
|
||||
<td><input name="trim" type="number" class="form-control" value={appConfig().TrimHist}></input></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Store History in DB</td>
|
||||
<td>
|
||||
<div class="form-check form-switch">
|
||||
{appConfig().HistInDB
|
||||
? <input class="form-check-input" type="checkbox" name="histdb" checked></input>
|
||||
: <input class="form-check-input" type="checkbox" name="histdb"></input>
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Use DB</td>
|
||||
<td><select name="usedb" class="form-select">
|
||||
|
|
|
|||
|
|
@ -1,22 +1,37 @@
|
|||
import { setShow, show } from "../../functions/exports";
|
||||
import HistShow from "../HistShow"
|
||||
import { createSignal, onMount } from "solid-js";
|
||||
import { setShow } from "../../functions/exports";
|
||||
import MacHistory from "../MacHistory"
|
||||
|
||||
function HistCard(_props: any) {
|
||||
|
||||
const showStr = localStorage.getItem("hostShow") as string;
|
||||
setShow(+showStr);
|
||||
(show() === 0 || isNaN(show())) ? setShow(500) : '';
|
||||
const [today, setToday] = createSignal('');
|
||||
|
||||
onMount(() => {
|
||||
setShow(15000);
|
||||
setToday(new Date().toLocaleDateString("en-CA"));
|
||||
});
|
||||
|
||||
const handleDate = (date: string) => {
|
||||
setToday("");
|
||||
setToday(date);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="card border-primary">
|
||||
<div class="card-header d-flex justify-content-between">
|
||||
<div>Host History</div>
|
||||
<HistShow name="hostShow"></HistShow>
|
||||
<div class="card-header">
|
||||
<div class="input-group" style="width: fit-content;">
|
||||
<span class="input-group-text">Host History for</span>
|
||||
<input
|
||||
type="date"
|
||||
class="form-control"
|
||||
value={today()}
|
||||
onInput={(e) => handleDate(e.currentTarget.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{_props.mac !== ""
|
||||
? <MacHistory mac={_props.mac}></MacHistory>
|
||||
{_props.mac !== "" && today() !== ""
|
||||
? <MacHistory mac={_props.mac} date={today()}></MacHistory>
|
||||
: <>Loading...</>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ function MacHistory(_props: any) {
|
|||
let interval: number;
|
||||
|
||||
onMount(async () => {
|
||||
const newHistory = await getHistoryForMac(_props.mac);
|
||||
const newHistory = await getHistoryForMac(_props.mac, _props.date);
|
||||
setHist(newHistory);
|
||||
interval = setInterval(async () => {
|
||||
// console.log("Upd Hist", new Date());
|
||||
const newHistory = await getHistoryForMac(_props.mac);
|
||||
const newHistory = await getHistoryForMac(_props.mac, _props.date);
|
||||
setHist(newHistory);
|
||||
}, 60000); // 60000 ms = 1 minute
|
||||
});
|
||||
|
|
|
|||
|
|
@ -67,3 +67,10 @@ export const apiGetHistory = async (mac:string) => {
|
|||
|
||||
return hosts;
|
||||
};
|
||||
|
||||
export const apiGetHistoryByDate = async (mac:string, date: string) => {
|
||||
const url = apiPath+'/api/history/'+mac+'/'+date;
|
||||
const hosts = await (await fetch(url)).json();
|
||||
|
||||
return hosts;
|
||||
};
|
||||
|
|
@ -27,7 +27,6 @@ export interface Conf {
|
|||
ArpArgs: string;
|
||||
ArpStrs: string[];
|
||||
TrimHist: number;
|
||||
HistInDB: boolean;
|
||||
ShoutURL: string;
|
||||
UseDB: string;
|
||||
PGConnect: string;
|
||||
|
|
@ -68,7 +67,6 @@ export const emptyConf:Conf = {
|
|||
ArpArgs: "",
|
||||
ArpStrs: [],
|
||||
TrimHist: 48,
|
||||
HistInDB: false,
|
||||
ShoutURL: "",
|
||||
UseDB: "",
|
||||
PGConnect: "",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
import { apiGetHistory } from "./api";
|
||||
import { apiGetHistory, apiGetHistoryByDate } from "./api";
|
||||
import { Host } from "./exports";
|
||||
|
||||
export async function getHistoryForMac(mac: string) {
|
||||
export async function getHistoryForMac(mac: string, date: string) {
|
||||
let h:Host[] = [];
|
||||
h = await apiGetHistory(mac);
|
||||
if (date === "") {
|
||||
h = await apiGetHistory(mac);
|
||||
} else {
|
||||
h = await apiGetHistoryByDate(mac, date);
|
||||
}
|
||||
|
||||
if (h != null) {
|
||||
h.sort((a:Host, b:Host) => (a.Date < b.Date ? 1 : -1));
|
||||
return h;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ function History() {
|
|||
<a href={"http://"+host.IP}>{host.IP}</a>
|
||||
</td>
|
||||
<td>
|
||||
<MacHistory mac={host.Mac}></MacHistory>
|
||||
<MacHistory mac={host.Mac} date=""></MacHistory>
|
||||
</td>
|
||||
</tr>
|
||||
}</For>
|
||||
|
|
|
|||
|
|
@ -14,39 +14,50 @@ import (
|
|||
"github.com/aceberg/WatchYourLAN/internal/portscan"
|
||||
)
|
||||
|
||||
func apiAll(c *gin.Context) {
|
||||
func getAllHosts(c *gin.Context) {
|
||||
|
||||
allHosts := gdb.Select("now")
|
||||
|
||||
c.IndentedJSON(http.StatusOK, allHosts)
|
||||
}
|
||||
|
||||
func apiVersion(c *gin.Context) {
|
||||
func getVersion(c *gin.Context) {
|
||||
|
||||
c.IndentedJSON(http.StatusOK, conf.AppConfig.Version)
|
||||
}
|
||||
|
||||
func apiGetConfig(c *gin.Context) {
|
||||
func getConfig(c *gin.Context) {
|
||||
|
||||
c.IndentedJSON(http.StatusOK, conf.AppConfig)
|
||||
}
|
||||
|
||||
func apiHistory(c *gin.Context) {
|
||||
var hosts []models.Host
|
||||
func getHistory(c *gin.Context) {
|
||||
|
||||
mac := c.Param("mac")
|
||||
|
||||
if mac != "/" {
|
||||
mac = mac[1:]
|
||||
hosts = gdb.SelectByMAC(mac)
|
||||
} else {
|
||||
hosts = gdb.Select("history")
|
||||
}
|
||||
hosts := gdb.Select("history")
|
||||
|
||||
c.IndentedJSON(http.StatusOK, hosts)
|
||||
}
|
||||
|
||||
func apiHost(c *gin.Context) {
|
||||
func getHistoryByMAC(c *gin.Context) {
|
||||
|
||||
mac := c.Param("mac")
|
||||
|
||||
hosts := gdb.SelectLatest(mac, 200)
|
||||
|
||||
c.IndentedJSON(http.StatusOK, hosts)
|
||||
}
|
||||
|
||||
func getHistoryByDate(c *gin.Context) {
|
||||
|
||||
mac := c.Param("mac")
|
||||
date := c.Param("date")
|
||||
|
||||
hosts := gdb.SelectByDate(mac, date)
|
||||
|
||||
c.IndentedJSON(http.StatusOK, hosts)
|
||||
}
|
||||
|
||||
func getHost(c *gin.Context) {
|
||||
|
||||
idStr := c.Param("id")
|
||||
|
||||
|
|
@ -56,7 +67,7 @@ func apiHost(c *gin.Context) {
|
|||
c.IndentedJSON(http.StatusOK, host)
|
||||
}
|
||||
|
||||
func apiHostDel(c *gin.Context) {
|
||||
func delHost(c *gin.Context) {
|
||||
|
||||
idStr := c.Param("id")
|
||||
host := getHostByID(idStr) // functions.go
|
||||
|
|
@ -67,7 +78,7 @@ func apiHostDel(c *gin.Context) {
|
|||
c.IndentedJSON(http.StatusOK, "OK")
|
||||
}
|
||||
|
||||
func apiPort(c *gin.Context) {
|
||||
func getPortState(c *gin.Context) {
|
||||
|
||||
addr := c.Param("addr")
|
||||
port := c.Param("port")
|
||||
|
|
@ -76,7 +87,7 @@ func apiPort(c *gin.Context) {
|
|||
c.IndentedJSON(http.StatusOK, state)
|
||||
}
|
||||
|
||||
func apiEdit(c *gin.Context) {
|
||||
func editHost(c *gin.Context) {
|
||||
|
||||
idStr := c.Param("id")
|
||||
name := c.Param("name")
|
||||
|
|
@ -95,14 +106,14 @@ func apiEdit(c *gin.Context) {
|
|||
c.IndentedJSON(http.StatusOK, "OK")
|
||||
}
|
||||
|
||||
func apiNotifyTest(c *gin.Context) {
|
||||
func notifyTest(c *gin.Context) {
|
||||
|
||||
notify.Test()
|
||||
|
||||
c.Status(http.StatusOK)
|
||||
}
|
||||
|
||||
func apiStatus(c *gin.Context) {
|
||||
func getStatus(c *gin.Context) {
|
||||
var status models.Stat
|
||||
var searchHosts []models.Host
|
||||
|
||||
|
|
|
|||
|
|
@ -7,16 +7,18 @@ import (
|
|||
// Routes - start API routes
|
||||
func Routes(router *gin.Engine) {
|
||||
|
||||
router.GET("/api/all", apiAll) // api.go
|
||||
router.GET("/api/config", apiGetConfig) // api.go
|
||||
router.GET("/api/edit/:id/:name/*known", apiEdit) // api.go
|
||||
router.GET("/api/history/*mac", apiHistory) // api.go
|
||||
router.GET("/api/host/:id", apiHost) // api.go
|
||||
router.GET("/api/host/del/:id", apiHostDel) // api.go
|
||||
router.GET("/api/notify_test", apiNotifyTest) // api.go
|
||||
router.GET("/api/port/:addr/:port", apiPort) // api.go
|
||||
router.GET("/api/status/*iface", apiStatus) // api.go
|
||||
router.GET("/api/version", apiVersion) // api.go
|
||||
router.GET("/api/all", getAllHosts) // api.go
|
||||
router.GET("/api/config", getConfig) // api.go
|
||||
router.GET("/api/edit/:id/:name/*known", editHost) // api.go
|
||||
router.GET("/api/history", getHistory) // api.go
|
||||
router.GET("/api/history/:mac", getHistoryByMAC) // api.go
|
||||
router.GET("/api/history/:mac/:date", getHistoryByDate) // api.go
|
||||
router.GET("/api/host/:id", getHost) // api.go
|
||||
router.GET("/api/host/del/:id", delHost) // api.go
|
||||
router.GET("/api/notify_test", notifyTest) // api.go
|
||||
router.GET("/api/port/:addr/:port", getPortState) // api.go
|
||||
router.GET("/api/status/*iface", getStatus) // api.go
|
||||
router.GET("/api/version", getVersion) // api.go
|
||||
|
||||
router.POST("/api/config/", saveConfigHandler) // config.go
|
||||
router.POST("/api/config_settings/", saveSettingsHandler) // config.go
|
||||
|
|
|
|||
|
|
@ -5,33 +5,6 @@ import (
|
|||
"github.com/aceberg/WatchYourLAN/internal/models"
|
||||
)
|
||||
|
||||
// Select - get all hosts
|
||||
func Select(table string) (dbHosts []models.Host) {
|
||||
|
||||
tab := db.Table(table)
|
||||
tab.Find(&dbHosts)
|
||||
|
||||
return dbHosts
|
||||
}
|
||||
|
||||
// SelectByID - get host by ID
|
||||
func SelectByID(id int) (host models.Host) {
|
||||
|
||||
tab := db.Table("now")
|
||||
tab.First(&host, id)
|
||||
|
||||
return host
|
||||
}
|
||||
|
||||
// SelectByMAC - get all hosts by MAC
|
||||
func SelectByMAC(mac string) (hosts []models.Host) {
|
||||
|
||||
tab := db.Table("history")
|
||||
tab.Where("MAC = ?", mac).Find(&hosts)
|
||||
|
||||
return hosts
|
||||
}
|
||||
|
||||
// Update - update or create host
|
||||
func Update(table string, oneHost models.Host) {
|
||||
|
||||
|
|
|
|||
57
internal/gdb/select.go
Normal file
57
internal/gdb/select.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package gdb
|
||||
|
||||
import (
|
||||
"github.com/aceberg/WatchYourLAN/internal/models"
|
||||
)
|
||||
|
||||
// Select - get all hosts
|
||||
func Select(table string) (dbHosts []models.Host) {
|
||||
|
||||
tab := db.Table(table)
|
||||
tab.Find(&dbHosts)
|
||||
|
||||
return dbHosts
|
||||
}
|
||||
|
||||
// SelectByID - get host by ID
|
||||
func SelectByID(id int) (host models.Host) {
|
||||
|
||||
tab := db.Table("now")
|
||||
tab.First(&host, id)
|
||||
|
||||
return host
|
||||
}
|
||||
|
||||
// SelectByMAC - get all hosts by MAC
|
||||
func SelectByMAC(mac string) (hosts []models.Host) {
|
||||
|
||||
tab := db.Table("history")
|
||||
tab.Where("MAC = ?", mac).Find(&hosts)
|
||||
|
||||
return hosts
|
||||
}
|
||||
|
||||
// SelectByDate - get all hosts by MAC
|
||||
func SelectByDate(mac, date string) (hosts []models.Host) {
|
||||
|
||||
tab := db.Table("history")
|
||||
tab.
|
||||
Where("MAC = ?", mac).
|
||||
Where("DATE LIKE ?", date+"%").
|
||||
Find(&hosts)
|
||||
|
||||
return hosts
|
||||
}
|
||||
|
||||
// SelectLatest - get latest hosts by MAC
|
||||
func SelectLatest(mac string, number int) (hosts []models.Host) {
|
||||
|
||||
tab := db.Table("history")
|
||||
tab.
|
||||
Where("MAC = ?", mac).
|
||||
Order("DATE DESC").
|
||||
Limit(number).
|
||||
Find(&hosts)
|
||||
|
||||
return hosts
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +0,0 @@
|
|||
import{B as h,C as y,o as d,D as H,e as m,S,t as v,b as I,s as g,E as p,m as f,F as b,l as u,h as D}from"./index.js";async function w(n){let t=[];return t=await h(n),t!=null?(t.sort((e,o)=>e.Date<o.Date?1:-1),t):[]}var $=v("<i>");function C(n){const[t,e]=y([]);let o;return d(async()=>{const a=await w(n.mac);e(a),o=setInterval(async()=>{const s=await w(n.mac);e(s)},6e4)}),H(()=>{clearInterval(o)}),m(b,{each:t,children:(a,s)=>m(S,{get when(){return s()<f()},get children(){var l=$();return I(r=>{var i="Date:"+a.Date+`
|
||||
Iface:`+a.Iface+`
|
||||
IP:`+a.IP+`
|
||||
Known:`+a.Known,c=a.Now===0?"my-box-off":"my-box-on";return i!==r.e&&g(l,"title",r.e=i),c!==r.t&&p(l,r.t=c),r},{e:void 0,t:void 0}),l}})})}var x=v('<input class=form-control placeholder="Show elements"title="Nomber of elements to show"style=max-width:10em;>');function E(n){const t=e=>{localStorage.setItem(n.name,e),u(+e),f()==0&&u(200)};return(()=>{var e=x();return e.$$input=o=>t(o.target.value),e})()}D(["input"]);export{E as H,C as M};
|
||||
|
|
@ -1 +1 @@
|
|||
import{k as m,l as u,m as p,n as I,p as v,q as M,t as _,i as e,e as l,r as N,F as U,b as E,s as S,S as O}from"./index.js";import{H as P,M as j}from"./HistShow.js";var k=_('<div class="card border-primary"><div class="card-header d-flex justify-content-between"></div><div class=card-body><table class="table table-striped table-hover"><tbody></tbody>'),q=_("<tr><td class=opacity-50 style=width:2em;>.</td><td><a></a><br><a></a></td><td>");function R(){let s=[];s.push(...m);const $=localStorage.getItem("histShow");return u(+$),(p()===0||isNaN(p()))&&u(200),I(()=>{v()&&(s=[],s.push(...m),console.log("Upd on Filter"),M(!1))}),(()=>{var d=k(),a=d.firstChild,g=a.nextSibling,w=g.firstChild,y=w.firstChild;return e(a,l(N,{}),null),e(a,l(P,{name:"histShow"}),null),e(y,l(O,{get when(){return!v()},get children(){return l(U,{each:s,children:(t,x)=>(()=>{var o=q(),i=o.firstChild,C=i.firstChild,h=i.nextSibling,n=h.firstChild,F=n.nextSibling,c=F.nextSibling,H=h.nextSibling;return e(i,()=>x()+1,C),e(n,()=>t.Name),e(c,()=>t.IP),e(H,l(j,{get mac(){return t.Mac}})),E(r=>{var f="/host/"+t.ID,b="http://"+t.IP;return f!==r.e&&S(n,"href",r.e=f),b!==r.t&&S(c,"href",r.t=b),r},{e:void 0,t:void 0}),o})()})}})),d})()}export{R as default};
|
||||
import{t as m,k as n,l as c,h as I,m as $,n as N,p as S,q as E,i as t,e as i,r as M,F as U,b as O,s as _,S as P}from"./index.js";import{M as j}from"./MacHistory.js";var k=m('<input class=form-control placeholder="Show elements"title="Nomber of elements to show"style=max-width:10em;>');function q(l){const o=e=>{localStorage.setItem(l.name,e),n(+e),c()==0&&n(200)};return(()=>{var e=k();return e.$$input=r=>o(r.target.value),e})()}I(["input"]);var A=m('<div class="card border-primary"><div class="card-header d-flex justify-content-between"></div><div class=card-body><table class="table table-striped table-hover"><tbody></tbody>'),D=m("<tr><td class=opacity-50 style=width:2em;>.</td><td><a></a><br><a></a></td><td>");function B(){let l=[];l.push(...$);const o=localStorage.getItem("histShow");return n(+o),(c()===0||isNaN(c()))&&n(200),N(()=>{S()&&(l=[],l.push(...$),console.log("Upd on Filter"),E(!1))}),(()=>{var e=A(),r=e.firstChild,g=r.nextSibling,w=g.firstChild,y=w.firstChild;return t(r,i(M,{}),null),t(r,i(q,{name:"histShow"}),null),t(y,i(P,{get when(){return!S()},get children(){return i(U,{each:l,children:(a,x)=>(()=>{var f=D(),d=f.firstChild,C=d.firstChild,u=d.nextSibling,h=u.firstChild,F=h.nextSibling,b=F.nextSibling,H=u.nextSibling;return t(d,()=>x()+1,C),t(h,()=>a.Name),t(b,()=>a.IP),t(H,i(j,{get mac(){return a.Mac},date:""})),O(s=>{var p="/host/"+a.ID,v="http://"+a.IP;return p!==s.e&&_(h,"href",s.e=p),v!==s.t&&_(b,"href",s.t=v),s},{e:void 0,t:void 0}),f})()})}})),e})()}export{B as default};
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
import{t as c,i as e,j as k,b as w,s as G,u as K,v as O,w as rt,h as L,c as x,e as u,F as nt,x as at,l as z,m as B,y as st,o as dt,z as ct,A as ot}from"./index.js";import{H as $t,M as ht}from"./HistShow.js";var bt=c('<div class="card border-primary"><div class=card-header>Host</div><div class="card-body table-responsive"><table class="table table-striped table-hover"><tbody><tr><td>ID</td><td></td></tr><tr><td>Name</td><td><input type=text class=form-control></td></tr><tr><td>DNS name</td><td></td></tr><tr><td>Iface</td><td></td></tr><tr><td>IP</td><td><a target=_blank></a></td></tr><tr><td>MAC</td><td></td></tr><tr><td>Hardware</td><td></td></tr><tr><td>Date</td><td></td></tr><tr><td>Known</td><td><div class="form-check form-switch"><input class=form-check-input type=checkbox></div></td></tr><tr><td>Online</td><td></td></tr></tbody></table><button type=button class="btn btn-outline-danger">Delete host'),ut=c('<i class="bi bi-check-circle-fill"style=color:var(--bs-success);>'),ft=c('<i class="bi bi-circle-fill"style=color:var(--bs-gray-500);>');function gt(t){let i="";const r=async o=>{i=o,await K(t.host.ID,i,""),O()},l=async()=>{i==""&&(i=t.host.Name),await K(t.host.ID,i,"toggle"),O()},h=async()=>{await rt(t.host.ID),window.location.href="/"};return(()=>{var o=bt(),f=o.firstChild,p=f.nextSibling,g=p.firstChild,H=g.firstChild,_=H.firstChild,I=_.firstChild,a=I.nextSibling,s=_.nextSibling,b=s.firstChild,d=b.nextSibling,m=d.firstChild,v=s.nextSibling,N=v.firstChild,C=N.nextSibling,n=v.nextSibling,$=n.firstChild,y=$.nextSibling,S=n.nextSibling,R=S.firstChild,T=R.nextSibling,D=T.firstChild,M=S.nextSibling,q=M.firstChild,J=q.nextSibling,E=M.nextSibling,Q=E.firstChild,U=Q.nextSibling,j=E.nextSibling,V=j.firstChild,W=V.nextSibling,A=j.nextSibling,X=A.firstChild,Y=X.nextSibling,Z=Y.firstChild,F=Z.firstChild,tt=A.nextSibling,et=tt.firstChild,lt=et.nextSibling,it=g.nextSibling;return e(a,()=>t.host.ID),m.$$input=P=>r(P.target.value),e(C,()=>t.host.DNS),e(y,()=>t.host.Iface),e(D,()=>t.host.IP),e(J,()=>t.host.Mac),e(U,()=>t.host.Hw),e(W,()=>t.host.Date),F.$$click=l,e(lt,(()=>{var P=k(()=>t.host.Now==1);return()=>P()?ut():ft()})()),it.$$click=h,w(()=>G(D,"href","http://"+t.host.IP)),w(()=>m.value=t.host.Name),w(()=>F.checked=t.host.Known==1),o})()}L(["input","click"]);var _t=c('<div class="card border-primary"><div class=card-header>Port Scan</div><div class=card-body><form class=input-group><input type=text class=form-control placeholder=1><input type=text class=form-control placeholder=65535><button type=button class="btn btn-primary">Scan</button></form><div class=mt-2>'),mt=c('<div class="d-flex justify-content-between mt-2"><button type=button class="btn btn-warning">Stop/Continue</button><div>Scanning port: '),vt=c("<a class=me-4 target=_blank>");function St(t){let i=!1;const[r,l]=x(""),[h,o]=x(""),[f,p]=x(""),[g,H]=x([]),_=async()=>{i=!1;let a=Number(r());(Number.isNaN(a)||a<1||a>65535)&&(a=1);let s=Number(h());(Number.isNaN(s)||s<1||s>65535)&&(s=65535);let b;for(let d=a;d<=s&&!i;d++)p(d.toString()),b=await at(t.IP,d),b&&H([...g(),d])},I=()=>{i?(l(f()),_()):i=!0};return(()=>{var a=_t(),s=a.firstChild,b=s.nextSibling,d=b.firstChild,m=d.firstChild,v=m.nextSibling,N=v.nextSibling,C=d.nextSibling;return m.$$input=n=>l(n.target.value),v.$$input=n=>o(n.target.value),N.$$click=_,e(b,(()=>{var n=k(()=>f()!="");return()=>n()?(()=>{var $=mt(),y=$.firstChild,S=y.nextSibling;return S.firstChild,y.$$click=I,e(S,f,null),$})():[]})(),C),e(C,u(nt,{get each(){return g()},children:n=>(()=>{var $=vt();return e($,n),w(()=>G($,"href","http://"+t.IP+":"+n)),$})()})),a})()}L(["input","click"]);var xt=c('<div class="card border-primary"><div class="card-header d-flex justify-content-between"><div>Host History</div></div><div class=card-body>');function Ct(t){const i=localStorage.getItem("hostShow");return z(+i),(B()===0||isNaN(B()))&&z(500),(()=>{var r=xt(),l=r.firstChild;l.firstChild;var h=l.nextSibling;return e(l,u($t,{name:"hostShow"}),null),e(h,(()=>{var o=k(()=>t.mac!=="");return()=>o()?u(ht,{get mac(){return t.mac}}):"Loading..."})()),r})()}var yt=c("<div class=row><div class=col-md></div><div class=col-md>"),wt=c('<div class="row mt-4"><div class=col-md>');function It(){const[t,i]=x(st);return dt(async()=>{const r=ct(),l=await ot(r.id);i(l)}),[(()=>{var r=yt(),l=r.firstChild,h=l.nextSibling;return e(l,u(gt,{get host(){return t()}})),e(h,u(St,{get IP(){return t().IP}})),r})(),(()=>{var r=wt(),l=r.firstChild;return e(l,u(Ct,{get mac(){return t().Mac}})),r})()]}export{It as default};
|
||||
import{t as u,i as l,j as I,b as p,s as O,u as K,v as L,w as it,h as N,c as _,e as y,F as nt,x as rt,o as z,k as at,y as st,z as dt,A as ct}from"./index.js";import{M as ot}from"./MacHistory.js";var $t=u('<div class="card border-primary"><div class=card-header>Host</div><div class="card-body table-responsive"><table class="table table-striped table-hover"><tbody><tr><td>ID</td><td></td></tr><tr><td>Name</td><td><input type=text class=form-control></td></tr><tr><td>DNS name</td><td></td></tr><tr><td>Iface</td><td></td></tr><tr><td>IP</td><td><a target=_blank></a></td></tr><tr><td>MAC</td><td></td></tr><tr><td>Hardware</td><td></td></tr><tr><td>Date</td><td></td></tr><tr><td>Known</td><td><div class="form-check form-switch"><input class=form-check-input type=checkbox></div></td></tr><tr><td>Online</td><td></td></tr></tbody></table><button type=button class="btn btn-outline-danger">Delete host'),ut=u('<i class="bi bi-check-circle-fill"style=color:var(--bs-success);>'),bt=u('<i class="bi bi-circle-fill"style=color:var(--bs-gray-500);>');function ht(t){let e="";const i=async o=>{e=o,await K(t.host.ID,e,""),L()},n=async()=>{e==""&&(e=t.host.Name),await K(t.host.ID,e,"toggle"),L()},a=async()=>{await it(t.host.ID),window.location.href="/"};return(()=>{var o=$t(),f=o.firstChild,m=f.nextSibling,b=m.firstChild,v=b.firstChild,$=v.firstChild,P=$.firstChild,s=P.nextSibling,d=$.nextSibling,g=d.firstChild,c=g.nextSibling,S=c.firstChild,x=d.nextSibling,k=x.firstChild,w=k.nextSibling,r=x.nextSibling,h=r.firstChild,H=h.nextSibling,C=r.nextSibling,B=C.firstChild,G=B.nextSibling,M=G.firstChild,A=C.nextSibling,R=A.firstChild,q=R.nextSibling,E=A.nextSibling,J=E.firstChild,Q=J.nextSibling,F=E.nextSibling,U=F.firstChild,V=U.nextSibling,T=F.nextSibling,W=T.firstChild,X=W.nextSibling,Y=X.firstChild,j=Y.firstChild,Z=T.nextSibling,tt=Z.firstChild,et=tt.nextSibling,lt=b.nextSibling;return l(s,()=>t.host.ID),S.$$input=D=>i(D.target.value),l(w,()=>t.host.DNS),l(H,()=>t.host.Iface),l(M,()=>t.host.IP),l(q,()=>t.host.Mac),l(Q,()=>t.host.Hw),l(V,()=>t.host.Date),j.$$click=n,l(et,(()=>{var D=I(()=>t.host.Now==1);return()=>D()?ut():bt()})()),lt.$$click=a,p(()=>O(M,"href","http://"+t.host.IP)),p(()=>S.value=t.host.Name),p(()=>j.checked=t.host.Known==1),o})()}N(["input","click"]);var ft=u('<div class="card border-primary"><div class=card-header>Port Scan</div><div class=card-body><form class=input-group><input type=text class=form-control placeholder=1><input type=text class=form-control placeholder=65535><button type=button class="btn btn-primary">Scan</button></form><div class=mt-2>'),gt=u('<div class="d-flex justify-content-between mt-2"><button type=button class="btn btn-warning">Stop/Continue</button><div>Scanning port: '),_t=u("<a class=me-4 target=_blank>");function mt(t){let e=!1;const[i,n]=_(""),[a,o]=_(""),[f,m]=_(""),[b,v]=_([]),$=async()=>{e=!1;let s=Number(i());(Number.isNaN(s)||s<1||s>65535)&&(s=1);let d=Number(a());(Number.isNaN(d)||d<1||d>65535)&&(d=65535);let g;for(let c=s;c<=d&&!e;c++)m(c.toString()),g=await rt(t.IP,c),g&&v([...b(),c])},P=()=>{e?(n(f()),$()):e=!0};return(()=>{var s=ft(),d=s.firstChild,g=d.nextSibling,c=g.firstChild,S=c.firstChild,x=S.nextSibling,k=x.nextSibling,w=c.nextSibling;return S.$$input=r=>n(r.target.value),x.$$input=r=>o(r.target.value),k.$$click=$,l(g,(()=>{var r=I(()=>f()!="");return()=>r()?(()=>{var h=gt(),H=h.firstChild,C=H.nextSibling;return C.firstChild,H.$$click=P,l(C,f,null),h})():[]})(),w),l(w,y(nt,{get each(){return b()},children:r=>(()=>{var h=_t();return l(h,r),p(()=>O(h,"href","http://"+t.IP+":"+r)),h})()})),s})()}N(["input","click"]);var vt=u('<div class="card border-primary"><div class=card-header><div class=input-group style=width:fit-content;><span class=input-group-text>Host History for</span><input type=date class=form-control></div></div><div class=card-body>');function St(t){const[e,i]=_("");z(()=>{at(15e3),i(new Date().toLocaleDateString("en-CA"))});const n=a=>{i(""),i(a)};return(()=>{var a=vt(),o=a.firstChild,f=o.firstChild,m=f.firstChild,b=m.nextSibling,v=o.nextSibling;return b.$$input=$=>n($.currentTarget.value),l(v,(()=>{var $=I(()=>t.mac!==""&&e()!=="");return()=>$()?y(ot,{get mac(){return t.mac},get date(){return e()}}):"Loading..."})()),p(()=>b.value=e()),a})()}N(["input"]);var xt=u("<div class=row><div class=col-md></div><div class=col-md>"),Ct=u('<div class="row mt-4"><div class=col-md>');function wt(){const[t,e]=_(st);return z(async()=>{const i=dt(),n=await ct(i.id);e(n)}),[(()=>{var i=xt(),n=i.firstChild,a=n.nextSibling;return l(n,y(ht,{get host(){return t()}})),l(a,y(mt,{get IP(){return t().IP}})),i})(),(()=>{var i=Ct(),n=i.firstChild;return l(n,y(St,{get mac(){return t().Mac}})),i})()]}export{wt as default};
|
||||
|
|
|
|||
4
internal/web/public/assets/MacHistory.js
Normal file
4
internal/web/public/assets/MacHistory.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import{B as y,C as f,D as v,o as m,E as H,e as u,S as d,t as D,b as I,s as b,G as h,l as M,F as g}from"./index.js";async function w(a,r){let e=[];return r===""?e=await y(a):e=await f(a,r),e!=null?(e.sort((s,t)=>s.Date<t.Date?1:-1),e):[]}var x=D("<i>");function F(a){const[r,e]=v([]);let s;return m(async()=>{const t=await w(a.mac,a.date);e(t),s=setInterval(async()=>{const o=await w(a.mac,a.date);e(o)},6e4)}),H(()=>{clearInterval(s)}),u(g,{each:r,children:(t,o)=>u(d,{get when(){return o()<M()},get children(){var i=x();return I(n=>{var c="Date:"+t.Date+`
|
||||
Iface:`+t.Iface+`
|
||||
IP:`+t.IP+`
|
||||
Known:`+t.Known,l=t.Now===0?"my-box-off":"my-box-on";return c!==n.e&&b(i,"title",n.e=c),l!==n.t&&h(i,n.t=l),n},{e:void 0,t:void 0}),i}})})}export{F as M};
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue