Add host from API, trigger rescan
This commit is contained in:
parent
1271b7b42e
commit
24ee0acb45
20 changed files with 255 additions and 24 deletions
|
|
@ -4,12 +4,10 @@ All notable changes to this project will be documented in this file.
|
|||
## [v2.1.4] - 2025-09
|
||||
### Added
|
||||
- Swagger API docs
|
||||
- Add host from API
|
||||
- Delete selected hosts
|
||||
- Wake-on-LAN [#135](https://github.com/aceberg/WatchYourLAN/issues/135), [#196](https://github.com/aceberg/WatchYourLAN/issues/196)
|
||||
|
||||
### Fixed
|
||||
- Names not fully saved while editing with GUI
|
||||
|
||||
## [v2.1.3] - 2025-07-26
|
||||
### Fixed
|
||||
- Memory leak bug [#149](https://github.com/aceberg/WatchYourLAN/issues/149)
|
||||
|
|
|
|||
|
|
@ -207,6 +207,53 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/host/add/{mac}": {
|
||||
"get": {
|
||||
"description": "Add host by MAC, with optional Name, IP, Hardware\nReturns ` + "`" + `models.Host` + "`" + ` with this MAC form DB, either just added or existing",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"hosts"
|
||||
],
|
||||
"summary": "Add host manually",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Host MAC",
|
||||
"name": "mac",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Name",
|
||||
"name": "name",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "IP",
|
||||
"name": "ip",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Hardware",
|
||||
"name": "hw",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.Host"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/host/del/{id}": {
|
||||
"get": {
|
||||
"description": "Remove a host from the database by its unique ID",
|
||||
|
|
@ -321,6 +368,26 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/rescan": {
|
||||
"get": {
|
||||
"description": "Manually trigger rescan",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"system"
|
||||
],
|
||||
"summary": "Rescan all interfaces now",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/status/{iface}": {
|
||||
"get": {
|
||||
"description": "Retrieve summary statistics of hosts, optionally filtered by interface",
|
||||
|
|
|
|||
|
|
@ -200,6 +200,53 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/host/add/{mac}": {
|
||||
"get": {
|
||||
"description": "Add host by MAC, with optional Name, IP, Hardware\nReturns `models.Host` with this MAC form DB, either just added or existing",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"hosts"
|
||||
],
|
||||
"summary": "Add host manually",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Host MAC",
|
||||
"name": "mac",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Name",
|
||||
"name": "name",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "IP",
|
||||
"name": "ip",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Hardware",
|
||||
"name": "hw",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.Host"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/host/del/{id}": {
|
||||
"get": {
|
||||
"description": "Remove a host from the database by its unique ID",
|
||||
|
|
@ -314,6 +361,26 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/rescan": {
|
||||
"get": {
|
||||
"description": "Manually trigger rescan",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"system"
|
||||
],
|
||||
"summary": "Rescan all interfaces now",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/status/{iface}": {
|
||||
"get": {
|
||||
"description": "Retrieve summary statistics of hosts, optionally filtered by interface",
|
||||
|
|
|
|||
|
|
@ -254,6 +254,39 @@ paths:
|
|||
summary: Get host by ID
|
||||
tags:
|
||||
- hosts
|
||||
/host/add/{mac}:
|
||||
get:
|
||||
description: |-
|
||||
Add host by MAC, with optional Name, IP, Hardware
|
||||
Returns `models.Host` with this MAC form DB, either just added or existing
|
||||
parameters:
|
||||
- description: Host MAC
|
||||
in: path
|
||||
name: mac
|
||||
required: true
|
||||
type: string
|
||||
- description: Name
|
||||
in: query
|
||||
name: name
|
||||
type: string
|
||||
- description: IP
|
||||
in: query
|
||||
name: ip
|
||||
type: string
|
||||
- description: Hardware
|
||||
in: query
|
||||
name: hw
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/models.Host'
|
||||
summary: Add host manually
|
||||
tags:
|
||||
- hosts
|
||||
/host/del/{id}:
|
||||
get:
|
||||
description: Remove a host from the database by its unique ID
|
||||
|
|
@ -310,6 +343,19 @@ paths:
|
|||
summary: Check port state
|
||||
tags:
|
||||
- network
|
||||
/rescan:
|
||||
get:
|
||||
description: Manually trigger rescan
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
summary: Rescan all interfaces now
|
||||
tags:
|
||||
- system
|
||||
/status/{iface}:
|
||||
get:
|
||||
description: Retrieve summary statistics of hosts, optionally filtered by interface
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/aceberg/WatchYourLAN/internal/check"
|
||||
"github.com/aceberg/WatchYourLAN/internal/gdb"
|
||||
"github.com/aceberg/WatchYourLAN/internal/models"
|
||||
)
|
||||
|
||||
// getAllHosts godoc
|
||||
|
|
@ -53,6 +54,42 @@ func delHost(c *gin.Context) {
|
|||
c.IndentedJSON(http.StatusOK, "OK")
|
||||
}
|
||||
|
||||
// addHost godoc
|
||||
// @Summary Add host manually
|
||||
// @Description Add host by MAC, with optional Name, IP, Hardware
|
||||
// @Description Returns `models.Host` with this MAC form DB, either just added or existing
|
||||
// @Tags hosts
|
||||
// @Produce json
|
||||
// @Param mac path string true "Host MAC"
|
||||
// @Param name query string false "Name"
|
||||
// @Param ip query string false "IP"
|
||||
// @Param hw query string false "Hardware"
|
||||
// @Success 200 {object} models.Host
|
||||
// @Router /host/add/{mac} [get]
|
||||
func addHost(c *gin.Context) {
|
||||
|
||||
mac := c.Param("mac")
|
||||
hosts := gdb.SelectByMAC("now", mac)
|
||||
|
||||
if len(hosts) > 0 {
|
||||
slog.Warn("Host with this MAC already exists", "host", hosts[0])
|
||||
} else {
|
||||
var host models.Host
|
||||
|
||||
host.Mac = mac
|
||||
host.Name = c.Query("name")
|
||||
host.IP = c.Query("ip")
|
||||
host.Hw = c.Query("hw")
|
||||
|
||||
gdb.Update("now", host)
|
||||
hosts = gdb.SelectByMAC("now", mac)
|
||||
|
||||
slog.Info("Added host to DB", "host", hosts[0])
|
||||
}
|
||||
|
||||
c.IndentedJSON(http.StatusOK, hosts[0])
|
||||
}
|
||||
|
||||
// editHost godoc
|
||||
// @Summary Edit host
|
||||
// @Description Update a host's name and optionally toggle its "known" status
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/aceberg/WatchYourLAN/internal/gdb"
|
||||
"github.com/aceberg/WatchYourLAN/internal/models"
|
||||
"github.com/aceberg/WatchYourLAN/internal/notify"
|
||||
"github.com/aceberg/WatchYourLAN/internal/routines"
|
||||
)
|
||||
|
||||
// getVersion godoc
|
||||
|
|
@ -22,6 +23,18 @@ func getVersion(c *gin.Context) {
|
|||
c.IndentedJSON(http.StatusOK, conf.AppConfig.Version)
|
||||
}
|
||||
|
||||
// triggerRescan godoc
|
||||
// @Summary Rescan all interfaces now
|
||||
// @Description Manually trigger rescan
|
||||
// @Tags system
|
||||
// @Produce json
|
||||
// @Success 200 {string} string "OK"
|
||||
// @Router /rescan [get]
|
||||
func triggerRescan(c *gin.Context) {
|
||||
routines.ScanRestart()
|
||||
c.Status(http.StatusOK)
|
||||
}
|
||||
|
||||
// getConfig godoc
|
||||
// @Summary Get application configuration
|
||||
// @Description Returns the current configuration used by the app
|
||||
|
|
|
|||
|
|
@ -16,11 +16,13 @@ func Routes(router *gin.Engine) {
|
|||
r0.GET("/edit/:id/:name/*known", editHost) // api-hosts.go
|
||||
r0.GET("/host/:id", getHost) // api-hosts.go
|
||||
r0.GET("/host/del/:id", delHost) // api-hosts.go
|
||||
r0.GET("/host/add/:mac", addHost) // api-hosts.go
|
||||
|
||||
r0.GET("/config", getConfig) // api-system.go
|
||||
r0.GET("/notify_test", notifyTest) // api-system.go
|
||||
r0.GET("/status/*iface", getStatus) // api-system.go
|
||||
r0.GET("/version", getVersion) // api-system.go
|
||||
r0.GET("/rescan", triggerRescan) // api-system.go
|
||||
|
||||
r0.GET("/history", getHistory) // api-history.go
|
||||
r0.GET("/history/:mac", getHistoryByMAC) // api-history.go
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ func SelectByID(id int) (host models.Host) {
|
|||
}
|
||||
|
||||
// SelectByMAC - get all hosts by MAC
|
||||
func SelectByMAC(mac string) (hosts []models.Host) {
|
||||
func SelectByMAC(table, mac string) (hosts []models.Host) {
|
||||
|
||||
tab := db.Table("history")
|
||||
tab := db.Table(table)
|
||||
tab.Where("\"MAC\" = ?", mac).Find(&hosts)
|
||||
|
||||
return hosts
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ func Unknown(host models.Host) {
|
|||
msg := fmt.Sprintf("Unknown host found. Name: '%s', IP: '%s', MAC: '%s', Hw: '%s', Iface: '%s'", host.DNS, host.IP, host.Mac, host.Hw, host.Iface)
|
||||
|
||||
slog.Warn(msg)
|
||||
|
||||
shout(msg)
|
||||
}
|
||||
|
||||
|
|
@ -25,6 +24,7 @@ func Unknown(host models.Host) {
|
|||
func Test() {
|
||||
|
||||
msg := "test notification"
|
||||
slog.Info("Sending " + msg)
|
||||
shout(msg)
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
import{u as at,t as o,i as e,j as I,b as C,s as K,v as j,w as B,x as st,y as dt,h as N,c as m,e as p,F as ct,z as ot,o as z,k as $t,A as ut,B as bt,C as ht}from"./index.js";import{M as ft}from"./MacHistory.js";var gt=o('<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'),_t=o('<i class="bi bi-check-circle-fill"style=color:var(--bs-success);>'),mt=o('<i class="bi bi-circle-fill"style=color:var(--bs-gray-500);>'),vt=o('<button type=button class="btn btn-outline-success">Wake-on-LAN');function St(t){let l="";const i=at(r=>{j(t.host.ID,r,""),B()},300),n=async r=>{l=r,i(r)},d=async()=>{l==""&&(l=t.host.Name),await j(t.host.ID,l,"toggle"),B()},_=async()=>{await dt(t.host.ID),window.location.href="/"},h=async()=>{await st(t.host.Mac)};return(()=>{var r=gt(),f=r.firstChild,v=f.nextSibling,$=v.firstChild,P=$.firstChild,a=P.firstChild,u=a.firstChild,g=u.nextSibling,s=a.nextSibling,y=s.firstChild,w=y.nextSibling,k=w.firstChild,S=s.nextSibling,c=S.firstChild,b=c.nextSibling,x=S.nextSibling,H=x.firstChild,G=H.nextSibling,M=x.nextSibling,R=M.firstChild,q=R.nextSibling,A=q.firstChild,L=M.nextSibling,J=L.firstChild,Q=J.nextSibling,E=L.nextSibling,U=E.firstChild,V=U.nextSibling,O=E.nextSibling,X=O.firstChild,Y=X.nextSibling,F=O.nextSibling,Z=F.firstChild,tt=Z.nextSibling,et=tt.firstChild,T=et.firstChild,lt=F.nextSibling,it=lt.firstChild,nt=it.nextSibling,rt=$.nextSibling;return e(g,()=>t.host.ID),k.$$input=D=>n(D.target.value),e(b,()=>t.host.DNS),e(G,()=>t.host.Iface),e(A,()=>t.host.IP),e(Q,()=>t.host.Mac),e(V,()=>t.host.Hw),e(Y,()=>t.host.Date),T.$$click=d,e(nt,(()=>{var D=I(()=>t.host.Now==1);return()=>D()?_t():[mt()," ",(()=>{var W=vt();return W.$$click=h,W})()]})()),rt.$$click=_,C(()=>K(A,"href","http://"+t.host.IP)),C(()=>k.value=t.host.Name),C(()=>T.checked=t.host.Known==1),r})()}N(["input","click"]);var xt=o('<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>'),Ct=o('<div class="d-flex justify-content-between mt-2"><button type=button class="btn btn-warning">Stop/Continue</button><div>Scanning port: '),pt=o("<a class=me-4 target=_blank>");function yt(t){let l=!1;const[i,n]=m(""),[d,_]=m(""),[h,r]=m(""),[f,v]=m([]),$=async()=>{l=!1;let a=Number(i());(Number.isNaN(a)||a<1||a>65535)&&(a=1);let u=Number(d());(Number.isNaN(u)||u<1||u>65535)&&(u=65535);let g;for(let s=a;s<=u&&!l;s++)r(s.toString()),g=await ot(t.IP,s),g&&v([...f(),s])},P=()=>{l?(n(h()),$()):l=!0};return(()=>{var a=xt(),u=a.firstChild,g=u.nextSibling,s=g.firstChild,y=s.firstChild,w=y.nextSibling,k=w.nextSibling,S=s.nextSibling;return y.$$input=c=>n(c.target.value),w.$$input=c=>_(c.target.value),k.$$click=$,e(g,(()=>{var c=I(()=>h()!="");return()=>c()?(()=>{var b=Ct(),x=b.firstChild,H=x.nextSibling;return H.firstChild,x.$$click=P,e(H,h,null),b})():[]})(),S),e(S,p(ct,{get each(){return f()},children:c=>(()=>{var b=pt();return e(b,c),C(()=>K(b,"href","http://"+t.IP+":"+c)),b})()})),a})()}N(["input","click"]);var wt=o('<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 kt(t){const[l,i]=m("");z(()=>{$t(15e3),i(new Date().toLocaleDateString("en-CA"))});const n=d=>{i(""),i(d)};return(()=>{var d=wt(),_=d.firstChild,h=_.firstChild,r=h.firstChild,f=r.nextSibling,v=_.nextSibling;return f.$$input=$=>n($.currentTarget.value),e(v,(()=>{var $=I(()=>t.mac!==""&&l()!=="");return()=>$()?p(ft,{get mac(){return t.mac},get date(){return l()}}):"Loading..."})()),C(()=>f.value=l()),d})()}N(["input"]);var Ht=o("<div class=row><div class=col-md></div><div class=col-md>"),Pt=o('<div class="row mt-4"><div class=col-md>');function Nt(){const[t,l]=m(ut);return z(async()=>{const i=bt(),n=await ht(i.id);l(n)}),[(()=>{var i=Ht(),n=i.firstChild,d=n.nextSibling;return e(n,p(St,{get host(){return t()}})),e(d,p(yt,{get IP(){return t().IP}})),i})(),(()=>{var i=Pt(),n=i.firstChild;return e(n,p(kt,{get mac(){return t().Mac}})),i})()]}export{Nt as default};
|
||||
import{u as at,t as o,i as e,j as I,b as y,s as B,v as j,w as rt,x as st,h as N,c as m,e as C,F as dt,y as ct,o as K,k as ot,z as $t,A as ut,B as bt}from"./index.js";import{M as ht}from"./MacHistory.js";var ft=o('<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'),gt=o('<i class="bi bi-check-circle-fill"style=color:var(--bs-success);>'),_t=o('<i class="bi bi-circle-fill"style=color:var(--bs-gray-500);>'),mt=o('<button type=button class="btn btn-outline-success">Wake-on-LAN');function vt(t){let l="";const i=at(async a=>{await j(t.host.ID,a,"")},300),n=async a=>{l=a,i(a)},d=async()=>{l==""&&(l=t.host.Name),await j(t.host.ID,l,"toggle")},_=async()=>{await st(t.host.ID),window.location.href="/"},h=async()=>{await rt(t.host.Mac)};return(()=>{var a=ft(),f=a.firstChild,v=f.nextSibling,$=v.firstChild,D=$.firstChild,r=D.firstChild,u=r.firstChild,g=u.nextSibling,s=r.nextSibling,p=s.firstChild,w=p.nextSibling,k=w.firstChild,S=s.nextSibling,c=S.firstChild,b=c.nextSibling,x=S.nextSibling,P=x.firstChild,z=P.nextSibling,M=x.nextSibling,G=M.firstChild,R=G.nextSibling,A=R.firstChild,L=M.nextSibling,q=L.firstChild,J=q.nextSibling,E=L.nextSibling,Q=E.firstChild,U=Q.nextSibling,O=E.nextSibling,V=O.firstChild,X=V.nextSibling,F=O.nextSibling,Y=F.firstChild,Z=Y.nextSibling,tt=Z.firstChild,T=tt.firstChild,et=F.nextSibling,lt=et.firstChild,it=lt.nextSibling,nt=$.nextSibling;return e(g,()=>t.host.ID),k.$$input=H=>n(H.target.value),e(b,()=>t.host.DNS),e(z,()=>t.host.Iface),e(A,()=>t.host.IP),e(J,()=>t.host.Mac),e(U,()=>t.host.Hw),e(X,()=>t.host.Date),T.$$click=d,e(it,(()=>{var H=I(()=>t.host.Now==1);return()=>H()?gt():[_t()," ",(()=>{var W=mt();return W.$$click=h,W})()]})()),nt.$$click=_,y(()=>B(A,"href","http://"+t.host.IP)),y(()=>k.value=t.host.Name),y(()=>T.checked=t.host.Known==1),a})()}N(["input","click"]);var St=o('<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>'),xt=o('<div class="d-flex justify-content-between mt-2"><button type=button class="btn btn-warning">Stop/Continue</button><div>Scanning port: '),yt=o("<a class=me-4 target=_blank>");function Ct(t){let l=!1;const[i,n]=m(""),[d,_]=m(""),[h,a]=m(""),[f,v]=m([]),$=async()=>{l=!1;let r=Number(i());(Number.isNaN(r)||r<1||r>65535)&&(r=1);let u=Number(d());(Number.isNaN(u)||u<1||u>65535)&&(u=65535);let g;for(let s=r;s<=u&&!l;s++)a(s.toString()),g=await ct(t.IP,s),g&&v([...f(),s])},D=()=>{l?(n(h()),$()):l=!0};return(()=>{var r=St(),u=r.firstChild,g=u.nextSibling,s=g.firstChild,p=s.firstChild,w=p.nextSibling,k=w.nextSibling,S=s.nextSibling;return p.$$input=c=>n(c.target.value),w.$$input=c=>_(c.target.value),k.$$click=$,e(g,(()=>{var c=I(()=>h()!="");return()=>c()?(()=>{var b=xt(),x=b.firstChild,P=x.nextSibling;return P.firstChild,x.$$click=D,e(P,h,null),b})():[]})(),S),e(S,C(dt,{get each(){return f()},children:c=>(()=>{var b=yt();return e(b,c),y(()=>B(b,"href","http://"+t.IP+":"+c)),b})()})),r})()}N(["input","click"]);var pt=o('<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 wt(t){const[l,i]=m("");K(()=>{ot(15e3),i(new Date().toLocaleDateString("en-CA"))});const n=d=>{i(""),i(d)};return(()=>{var d=pt(),_=d.firstChild,h=_.firstChild,a=h.firstChild,f=a.nextSibling,v=_.nextSibling;return f.$$input=$=>n($.currentTarget.value),e(v,(()=>{var $=I(()=>t.mac!==""&&l()!=="");return()=>$()?C(ht,{get mac(){return t.mac},get date(){return l()}}):"Loading..."})()),y(()=>f.value=l()),d})()}N(["input"]);var kt=o("<div class=row><div class=col-md></div><div class=col-md>"),Pt=o('<div class="row mt-4"><div class=col-md>');function It(){const[t,l]=m($t);return K(async()=>{const i=ut(),n=await bt(i.id);l(n)}),[(()=>{var i=kt(),n=i.firstChild,d=n.nextSibling;return e(n,C(vt,{get host(){return t()}})),e(d,C(Ct,{get IP(){return t().IP}})),i})(),(()=>{var i=Pt(),n=i.firstChild;return e(n,C(wt,{get mac(){return t().Mac}})),i})()]}export{It as default};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import{D as y,E as f,G as v,o as m,H,e as u,S as I,t as d,b as D,s as b,I 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 G(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(I,{get when(){return o()<M()},get children(){var i=x();return D(n=>{var c="Date:"+t.Date+`
|
||||
import{C as y,D as f,E as v,o as m,G as H,e as u,S as d,t as D,b as I,s as b,H 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{G as M};
|
||||
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
|
|
@ -38,7 +38,7 @@ function CardHead() {
|
|||
when={editNames()}
|
||||
fallback={<button class="btn btn-outline-primary" title="Toggle edit" onClick={[handleEditNames, true]}>Edit</button>}
|
||||
>
|
||||
<button type="button" onClick={handleDel} class="btn btn-outline-danger">Delete selected</button>
|
||||
<button type="button" onClick={handleDel} title="Delete selected hosts" class="btn btn-outline-danger">Delete selected</button>
|
||||
<button class="btn btn-primary" title="Toggle edit" onClick={[handleEditNames, false]}>Edit</button>
|
||||
</Show>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ function TableHead() {
|
|||
title={"Sort by " + key}
|
||||
></i></th>
|
||||
}</For>
|
||||
<th style="width: 2em;"></th>
|
||||
<th style="width: 2em;" title="Edit"><i class="bi bi-pencil-fill"></i></th>
|
||||
</tr>
|
||||
</thead>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ function TableRow(_props: any) {
|
|||
let known:boolean;
|
||||
_props.host.Known === 1 ? known = true : known = false;
|
||||
|
||||
const debouncedApi = debounce((val: string) => {
|
||||
apiEditHost(_props.host.ID, val, "");
|
||||
const debouncedApi = debounce(async (val: string) => {
|
||||
await apiEditHost(_props.host.ID, val, "");
|
||||
}, 300);
|
||||
|
||||
const handleInput = async (n: string) => {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ function About() {
|
|||
<div class="card-header">
|
||||
About (<a href={link()} target="_blank">{version()}</a>)
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-body table-responsive">
|
||||
<table class="table table-striped"><tbody>
|
||||
<tr>
|
||||
<td><b>Swagger API docs</b></td>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ function Scan() {
|
|||
</tr>
|
||||
<tr>
|
||||
<td><button type="submit" class="btn btn-primary">Save</button></td>
|
||||
<td></td>
|
||||
<td class="text-muted">*Pressing <b>Save</b> button will trigger rescan</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { apiDelHost, apiEditHost, apiWOL } from "../../functions/api";
|
||||
import { getHosts } from "../../functions/atstart";
|
||||
|
||||
import { debounce } from "@solid-primitives/scheduled";
|
||||
|
||||
|
|
@ -7,10 +6,8 @@ function HostCard(_props: any) {
|
|||
|
||||
let name:string = "";
|
||||
|
||||
const debouncedApi = debounce((val: string) => {
|
||||
apiEditHost(_props.host.ID, val, "");
|
||||
|
||||
getHosts();
|
||||
const debouncedApi = debounce(async (val: string) => {
|
||||
await apiEditHost(_props.host.ID, val, "");
|
||||
}, 300);
|
||||
|
||||
const handleInput = async (n: string) => {
|
||||
|
|
@ -26,7 +23,6 @@ function HostCard(_props: any) {
|
|||
}
|
||||
|
||||
await apiEditHost(_props.host.ID, name, 'toggle');
|
||||
getHosts();
|
||||
};
|
||||
|
||||
const handleDel = async () => {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,18 @@
|
|||
import { For } from "solid-js";
|
||||
import { For, onMount } from "solid-js";
|
||||
|
||||
import { allHosts } from "../functions/exports";
|
||||
|
||||
import TableRow from "../components/Body/TableRow";
|
||||
import TableHead from "../components/Body/TableHead";
|
||||
import CardHead from "../components/Body/CardHead";
|
||||
import { getHosts } from "../functions/atstart";
|
||||
|
||||
function Body() {
|
||||
|
||||
onMount(() => {
|
||||
getHosts();
|
||||
});
|
||||
|
||||
return (
|
||||
<div class="card border-primary">
|
||||
<div class="card-header">
|
||||
|
|
|
|||
Loading…
Reference in a new issue