diff --git a/README.md b/README.md index 7c23f64a..ace826c5 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,11 @@ Open up [localhost:5173/](localhost:5173/) - [ ] form for adding new devices - [ ] add per device settings - [x] theme toggle button - - [ ] add device ports to cards + - [x] add device ports to cards - backend - - [ ] make sure ping works + - [x] make sure ping works - [ ] make sure arp works - [ ] make sure wake works - [ ] remove nmap? diff --git a/backend/cronjobs/cronjobs.go b/backend/cronjobs/cronjobs.go index b4f73dd9..8cf0bbed 100644 --- a/backend/cronjobs/cronjobs.go +++ b/backend/cronjobs/cronjobs.go @@ -42,7 +42,17 @@ func RunCron(app *pocketbase.PocketBase) { // init cronjob c := cron.New() c.AddFunc(fmt.Sprintf("@every %s", interval), func() { + // expand ports field + expandFetchFunc := func(c *models.Collection, ids []string) ([]*models.Record, error) { + return app.Dao().FindRecordsByIds(c.Id, ids, nil) + } + merr := app.Dao().ExpandRecords(Devices, []string{"ports"}, expandFetchFunc) + if len(merr) > 0 { + return + } + for _, device := range Devices { + // ping go func(device *models.Record) { oldStatus := device.Get("status") newStatus := networking.PingDevice(device) @@ -58,6 +68,23 @@ func RunCron(app *pocketbase.PocketBase) { } } }(device) + + // scan ports + go func(device *models.Record) { + ports, err := app.Dao().FindRecordsByIds("ports", device.GetStringSlice("ports")) + if err != nil { + logger.Error.Println(err) + } + for _, port := range ports { + isUp := networking.CheckPort(device.GetString("ip"), port.GetString("number")) + if isUp != port.GetBool("status") { + port.Set("status", isUp) + app.Dao().SaveRecord(port) + device.RefreshUpdated() + app.Dao().SaveRecord(device) + } + } + }(device) } }) c.Run() diff --git a/backend/migrations/1673733059_collections_snapshot.go b/backend/migrations/1673733059_collections_snapshot.go deleted file mode 100644 index 68fe59e8..00000000 --- a/backend/migrations/1673733059_collections_snapshot.go +++ /dev/null @@ -1,214 +0,0 @@ -package migrations - -import ( - "encoding/json" - - "github.com/pocketbase/dbx" - "github.com/pocketbase/pocketbase/daos" - m "github.com/pocketbase/pocketbase/migrations" - "github.com/pocketbase/pocketbase/models" -) - -func init() { - m.Register(func(db dbx.Builder) error { - jsonData := `[ - { - "id": "z5lghx2r3tm45n1", - "created": "2023-01-14 21:50:42.797Z", - "updated": "2023-01-14 21:50:42.797Z", - "name": "devices", - "type": "base", - "system": false, - "schema": [ - { - "system": false, - "id": "tiqcmnjo", - "name": "name", - "type": "text", - "required": true, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "1si6ajha", - "name": "ip", - "type": "text", - "required": true, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "fyqmpon6", - "name": "mac", - "type": "text", - "required": true, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "s8c5z7n0", - "name": "netmask", - "type": "text", - "required": true, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "gdctb8hj", - "name": "link", - "type": "url", - "required": false, - "unique": false, - "options": { - "exceptDomains": null, - "onlyDomains": null - } - }, - { - "system": false, - "id": "ilrwvlev", - "name": "port", - "type": "relation", - "required": false, - "unique": false, - "options": { - "maxSelect": null, - "collectionId": "cti4l8f4mz8df3r", - "cascadeDelete": false - } - }, - { - "system": false, - "id": "qqvyfrex", - "name": "status", - "type": "text", - "required": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "1a7yrwo9", - "name": "shutdown_cmd", - "type": "text", - "required": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - } - ], - "listRule": "", - "viewRule": "", - "createRule": "", - "updateRule": "", - "deleteRule": "", - "options": {} - }, - { - "id": "cti4l8f4mz8df3r", - "created": "2023-01-14 21:50:42.797Z", - "updated": "2023-01-14 21:50:42.797Z", - "name": "ports", - "type": "base", - "system": false, - "schema": [ - { - "system": false, - "id": "8nwuncgg", - "name": "number", - "type": "number", - "required": true, - "unique": false, - "options": { - "min": null, - "max": 65535 - } - }, - { - "system": false, - "id": "o0he3pu6", - "name": "name", - "type": "text", - "required": true, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - } - ], - "listRule": "", - "viewRule": "", - "createRule": "", - "updateRule": "", - "deleteRule": "", - "options": {} - }, - { - "id": "nmj3ko20gzkg8n3", - "created": "2023-01-14 21:50:42.797Z", - "updated": "2023-01-14 21:50:42.797Z", - "name": "settings", - "type": "base", - "system": false, - "schema": [ - { - "system": false, - "id": "ysutxavs", - "name": "interval", - "type": "number", - "required": true, - "unique": false, - "options": { - "min": 1, - "max": null - } - } - ], - "listRule": null, - "viewRule": null, - "createRule": null, - "updateRule": null, - "deleteRule": null, - "options": {} - } - ]` - - collections := []*models.Collection{} - if err := json.Unmarshal([]byte(jsonData), &collections); err != nil { - return err - } - - return daos.New(db).ImportCollections(collections, true, nil) - }, func(db dbx.Builder) error { - return nil - }) -} diff --git a/backend/migrations/1673887022_updated_devices.go b/backend/migrations/1673887022_updated_devices.go deleted file mode 100644 index abbd4836..00000000 --- a/backend/migrations/1673887022_updated_devices.go +++ /dev/null @@ -1,52 +0,0 @@ -package migrations - -import ( - "encoding/json" - - "github.com/pocketbase/dbx" - "github.com/pocketbase/pocketbase/daos" - m "github.com/pocketbase/pocketbase/migrations" - "github.com/pocketbase/pocketbase/models/schema" -) - -func init() { - m.Register(func(db dbx.Builder) error { - dao := daos.New(db); - - collection, err := dao.FindCollectionByNameOrId("z5lghx2r3tm45n1") - if err != nil { - return err - } - - // add - new_wake := &schema.SchemaField{} - json.Unmarshal([]byte(`{ - "system": false, - "id": "kzvdbbws", - "name": "wake", - "type": "text", - "required": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }`), new_wake) - collection.Schema.AddField(new_wake) - - return dao.SaveCollection(collection) - }, func(db dbx.Builder) error { - dao := daos.New(db); - - collection, err := dao.FindCollectionByNameOrId("z5lghx2r3tm45n1") - if err != nil { - return err - } - - // remove - collection.Schema.RemoveField("kzvdbbws") - - return dao.SaveCollection(collection) - }) -} diff --git a/backend/migrations/1673887034_updated_devices.go b/backend/migrations/1673887034_updated_devices.go deleted file mode 100644 index 5d43dfd0..00000000 --- a/backend/migrations/1673887034_updated_devices.go +++ /dev/null @@ -1,66 +0,0 @@ -package migrations - -import ( - "encoding/json" - - "github.com/pocketbase/dbx" - "github.com/pocketbase/pocketbase/daos" - m "github.com/pocketbase/pocketbase/migrations" - "github.com/pocketbase/pocketbase/models/schema" -) - -func init() { - m.Register(func(db dbx.Builder) error { - dao := daos.New(db); - - collection, err := dao.FindCollectionByNameOrId("z5lghx2r3tm45n1") - if err != nil { - return err - } - - // update - edit_shutdown := &schema.SchemaField{} - json.Unmarshal([]byte(`{ - "system": false, - "id": "1a7yrwo9", - "name": "shutdown", - "type": "text", - "required": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }`), edit_shutdown) - collection.Schema.AddField(edit_shutdown) - - return dao.SaveCollection(collection) - }, func(db dbx.Builder) error { - dao := daos.New(db); - - collection, err := dao.FindCollectionByNameOrId("z5lghx2r3tm45n1") - if err != nil { - return err - } - - // update - edit_shutdown := &schema.SchemaField{} - json.Unmarshal([]byte(`{ - "system": false, - "id": "1a7yrwo9", - "name": "shutdown_cmd", - "type": "text", - "required": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }`), edit_shutdown) - collection.Schema.AddField(edit_shutdown) - - return dao.SaveCollection(collection) - }) -} diff --git a/backend/migrations/1674429704_created_devices.go b/backend/migrations/1674429704_created_devices.go new file mode 100644 index 00000000..47e6823f --- /dev/null +++ b/backend/migrations/1674429704_created_devices.go @@ -0,0 +1,163 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models" +) + +func init() { + m.Register(func(db dbx.Builder) error { + jsonData := `{ + "id": "z5lghx2r3tm45n1", + "created": "2023-01-22 23:21:44.280Z", + "updated": "2023-01-22 23:21:44.280Z", + "name": "devices", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "tiqcmnjo", + "name": "name", + "type": "text", + "required": true, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "1si6ajha", + "name": "ip", + "type": "text", + "required": true, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "fyqmpon6", + "name": "mac", + "type": "text", + "required": true, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "s8c5z7n0", + "name": "netmask", + "type": "text", + "required": true, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "qqvyfrex", + "name": "status", + "type": "text", + "required": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "ilrwvlev", + "name": "ports", + "type": "relation", + "required": false, + "unique": false, + "options": { + "maxSelect": null, + "collectionId": "cti4l8f4mz8df3r", + "cascadeDelete": false + } + }, + { + "system": false, + "id": "gdctb8hj", + "name": "link", + "type": "url", + "required": false, + "unique": false, + "options": { + "exceptDomains": null, + "onlyDomains": null + } + }, + { + "system": false, + "id": "1a7yrwo9", + "name": "shutdown", + "type": "text", + "required": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "kzvdbbws", + "name": "wake", + "type": "text", + "required": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + } + ], + "listRule": "", + "viewRule": "", + "createRule": "", + "updateRule": "", + "deleteRule": "", + "options": {} + }` + + collection := &models.Collection{} + if err := json.Unmarshal([]byte(jsonData), &collection); err != nil { + return err + } + + return daos.New(db).SaveCollection(collection) + }, func(db dbx.Builder) error { + dao := daos.New(db); + + collection, err := dao.FindCollectionByNameOrId("z5lghx2r3tm45n1") + if err != nil { + return err + } + + return dao.DeleteCollection(collection) + }) +} diff --git a/backend/migrations/1674429704_created_ports.go b/backend/migrations/1674429704_created_ports.go new file mode 100644 index 00000000..aeff8d28 --- /dev/null +++ b/backend/migrations/1674429704_created_ports.go @@ -0,0 +1,81 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models" +) + +func init() { + m.Register(func(db dbx.Builder) error { + jsonData := `{ + "id": "cti4l8f4mz8df3r", + "created": "2023-01-22 23:21:44.280Z", + "updated": "2023-01-22 23:21:44.280Z", + "name": "ports", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "8nwuncgg", + "name": "number", + "type": "number", + "required": true, + "unique": false, + "options": { + "min": null, + "max": 65535 + } + }, + { + "system": false, + "id": "o0he3pu6", + "name": "name", + "type": "text", + "required": true, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "w0bh39gv", + "name": "status", + "type": "bool", + "required": false, + "unique": false, + "options": {} + } + ], + "listRule": "", + "viewRule": "", + "createRule": "", + "updateRule": "", + "deleteRule": "", + "options": {} + }` + + collection := &models.Collection{} + if err := json.Unmarshal([]byte(jsonData), &collection); err != nil { + return err + } + + return daos.New(db).SaveCollection(collection) + }, func(db dbx.Builder) error { + dao := daos.New(db); + + collection, err := dao.FindCollectionByNameOrId("cti4l8f4mz8df3r") + if err != nil { + return err + } + + return dao.DeleteCollection(collection) + }) +} diff --git a/backend/migrations/1674429704_created_settings.go b/backend/migrations/1674429704_created_settings.go new file mode 100644 index 00000000..c3e15c72 --- /dev/null +++ b/backend/migrations/1674429704_created_settings.go @@ -0,0 +1,59 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models" +) + +func init() { + m.Register(func(db dbx.Builder) error { + jsonData := `{ + "id": "nmj3ko20gzkg8n3", + "created": "2023-01-22 23:21:44.281Z", + "updated": "2023-01-22 23:21:44.281Z", + "name": "settings", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "ysutxavs", + "name": "interval", + "type": "number", + "required": true, + "unique": false, + "options": { + "min": 1, + "max": null + } + } + ], + "listRule": null, + "viewRule": null, + "createRule": null, + "updateRule": null, + "deleteRule": null, + "options": {} + }` + + collection := &models.Collection{} + if err := json.Unmarshal([]byte(jsonData), &collection); err != nil { + return err + } + + return daos.New(db).SaveCollection(collection) + }, func(db dbx.Builder) error { + dao := daos.New(db); + + collection, err := dao.FindCollectionByNameOrId("nmj3ko20gzkg8n3") + if err != nil { + return err + } + + return dao.DeleteCollection(collection) + }) +} diff --git a/backend/migrations/1674429704_deleted_users.go b/backend/migrations/1674429704_deleted_users.go new file mode 100644 index 00000000..f1d9ace0 --- /dev/null +++ b/backend/migrations/1674429704_deleted_users.go @@ -0,0 +1,90 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models" +) + +func init() { + m.Register(func(db dbx.Builder) error { + dao := daos.New(db); + + collection, err := dao.FindCollectionByNameOrId("_pb_users_auth_") + if err != nil { + return err + } + + return dao.DeleteCollection(collection) + }, func(db dbx.Builder) error { + jsonData := `{ + "id": "_pb_users_auth_", + "created": "2023-01-22 23:21:16.599Z", + "updated": "2023-01-22 23:21:16.600Z", + "name": "users", + "type": "auth", + "system": false, + "schema": [ + { + "system": false, + "id": "users_name", + "name": "name", + "type": "text", + "required": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "users_avatar", + "name": "avatar", + "type": "file", + "required": false, + "unique": false, + "options": { + "maxSelect": 1, + "maxSize": 5242880, + "mimeTypes": [ + "image/jpg", + "image/jpeg", + "image/png", + "image/svg+xml", + "image/gif", + "image/webp" + ], + "thumbs": null + } + } + ], + "listRule": "id = @request.auth.id", + "viewRule": "id = @request.auth.id", + "createRule": "", + "updateRule": "id = @request.auth.id", + "deleteRule": "id = @request.auth.id", + "options": { + "allowEmailAuth": true, + "allowOAuth2Auth": true, + "allowUsernameAuth": true, + "exceptEmailDomains": null, + "manageRule": null, + "minPasswordLength": 8, + "onlyEmailDomains": null, + "requireEmail": false + } + }` + + collection := &models.Collection{} + if err := json.Unmarshal([]byte(jsonData), &collection); err != nil { + return err + } + + return daos.New(db).SaveCollection(collection) + }) +} diff --git a/backend/networking/ping.go b/backend/networking/ping.go index e78c6feb..50991237 100644 --- a/backend/networking/ping.go +++ b/backend/networking/ping.go @@ -1,7 +1,9 @@ package networking import ( + "net" "runtime" + "time" "github.com/go-ping/ping" "github.com/pocketbase/pocketbase/models" @@ -31,3 +33,16 @@ func PingDevice(device *models.Record) bool { return true } } + +func CheckPort(host string, port string) bool { + timeout := 500 * time.Millisecond + conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), timeout) + if err != nil { + return false + } + if conn != nil { + defer conn.Close() + return true + } + return false +} diff --git a/frontend/package.json b/frontend/package.json index 2c796ae7..c798f16e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,8 +10,8 @@ "format": "prettier --plugin-search-dir . --write ." }, "devDependencies": { - "@sveltejs/adapter-static": "^1.0.1", - "@sveltejs/kit": "^1.1.1", + "@sveltejs/adapter-static": "^1.0.5", + "@sveltejs/kit": "^1.2.2", "eslint": "^8.32.0", "eslint-config-prettier": "^8.6.0", "eslint-plugin-svelte3": "^4.0.0", @@ -27,7 +27,7 @@ "@popperjs/core": "^2.11.6", "bootstrap": "5.3.0-alpha1", "date-fns": "^2.29.3", - "pocketbase": "^0.10.0", + "pocketbase": "^0.10.1", "sass": "^1.57.1", "svelte-fa": "^3.0.3" } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 0a29213c..6e26be76 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -3,14 +3,14 @@ lockfileVersion: 5.4 specifiers: '@fortawesome/free-solid-svg-icons': ^6.2.1 '@popperjs/core': ^2.11.6 - '@sveltejs/adapter-static': ^1.0.1 - '@sveltejs/kit': ^1.1.1 + '@sveltejs/adapter-static': ^1.0.5 + '@sveltejs/kit': ^1.2.2 bootstrap: 5.3.0-alpha1 date-fns: ^2.29.3 eslint: ^8.32.0 eslint-config-prettier: ^8.6.0 eslint-plugin-svelte3: ^4.0.0 - pocketbase: ^0.10.0 + pocketbase: ^0.10.1 prettier: ^2.8.3 prettier-plugin-svelte: ^2.9.0 sass: ^1.57.1 @@ -24,13 +24,13 @@ dependencies: '@popperjs/core': 2.11.6 bootstrap: 5.3.0-alpha1_@popperjs+core@2.11.6 date-fns: 2.29.3 - pocketbase: 0.10.0 + pocketbase: 0.10.1 sass: 1.57.1 svelte-fa: 3.0.3 devDependencies: - '@sveltejs/adapter-static': 1.0.4_@sveltejs+kit@1.1.1 - '@sveltejs/kit': 1.1.1_svelte@3.55.1+vite@4.0.4 + '@sveltejs/adapter-static': 1.0.5_@sveltejs+kit@1.2.2 + '@sveltejs/kit': 1.2.2_svelte@3.55.1+vite@4.0.4 eslint: 8.32.0 eslint-config-prettier: 8.6.0_eslint@8.32.0 eslint-plugin-svelte3: 4.0.0_tmo5zkisvhu6htudosk5k7m6pu @@ -324,16 +324,16 @@ packages: resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} dev: false - /@sveltejs/adapter-static/1.0.4_@sveltejs+kit@1.1.1: - resolution: {integrity: sha512-L6kGg19MBHW3kv3GWAPl9tJo3ohNM+dcj9Yq1U1XVu0J0MKrusyCWQ62XOfxFgS6T8Fq0KYJ5NSSAPGppvX4xA==} + /@sveltejs/adapter-static/1.0.5_@sveltejs+kit@1.2.2: + resolution: {integrity: sha512-W5jbgvy9sbYEHs27NQOSFEun+zQwdcL4kpk5qc2kSHl8cKsP5wfXuWDTDRmD1Co40aFcesi5Az5ZzdnPI8KCVg==} peerDependencies: '@sveltejs/kit': ^1.0.0 dependencies: - '@sveltejs/kit': 1.1.1_svelte@3.55.1+vite@4.0.4 + '@sveltejs/kit': 1.2.2_svelte@3.55.1+vite@4.0.4 dev: true - /@sveltejs/kit/1.1.1_svelte@3.55.1+vite@4.0.4: - resolution: {integrity: sha512-5hZef6yTqiLm8fLMFD78udJI3pG9ptSndg3NNmDqxv5fS9KFABkASQwnWB25Pf1HkPNqvL+x4Tl8kyW1N8thKQ==} + /@sveltejs/kit/1.2.2_svelte@3.55.1+vite@4.0.4: + resolution: {integrity: sha512-aZUjAZ/6gWEYFQDrDNINuvOi6VxlG86kCcIDRWDIFJjI38Ueieo1fySb0j0d2VkQVrYXU7VqjTVMBZFix+hByA==} engines: {node: ^16.14 || >=18} hasBin: true requiresBuild: true @@ -354,7 +354,7 @@ packages: sirv: 2.0.2 svelte: 3.55.1 tiny-glob: 0.2.9 - undici: 5.15.0 + undici: 5.15.1 vite: 4.0.4_sass@1.57.1 transitivePeerDependencies: - supports-color @@ -699,7 +699,7 @@ packages: imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 - js-sdsl: 4.2.0 + js-sdsl: 4.3.0 js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 @@ -944,8 +944,8 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true - /js-sdsl/4.2.0: - resolution: {integrity: sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==} + /js-sdsl/4.3.0: + resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==} dev: true /js-yaml/4.1.0: @@ -1122,8 +1122,8 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - /pocketbase/0.10.0: - resolution: {integrity: sha512-OWcPRcOPNiTqek5wkf56mCmkox4w5/h1x+ySBNqzQ0Ux7ztEv3aq3Gr91bwn3VcXN7o48XVbKny7A922hNIbQw==} + /pocketbase/0.10.1: + resolution: {integrity: sha512-FMBhF+9o2AmdKJYbfz2qunnk4Q5/efYMRcukdQF49UfhsIuaSYl39fSPN1l880bYI4XAvDDeySAjK1MlxrK37A==} dev: false /postcss/8.4.21: @@ -1156,8 +1156,8 @@ packages: hasBin: true dev: true - /punycode/2.2.0: - resolution: {integrity: sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==} + /punycode/2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} dev: true @@ -1209,8 +1209,8 @@ packages: glob: 7.2.3 dev: true - /rollup/3.10.0: - resolution: {integrity: sha512-JmRYz44NjC1MjVF2VKxc0M1a97vn+cDxeqWmnwyAF4FvpjK8YFdHpaqvQB+3IxCvX05vJxKZkoMDU8TShhmJVA==} + /rollup/3.10.1: + resolution: {integrity: sha512-3Er+yel3bZbZX1g2kjVM+FW+RUWDxbG87fcqFM5/9HbPCTpbVp6JOLn7jlxnNlbu7s/N/uDA4EV/91E2gWnxzw==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: @@ -1431,8 +1431,8 @@ packages: engines: {node: '>=10'} dev: true - /undici/5.15.0: - resolution: {integrity: sha512-wCAZJDyjw9Myv+Ay62LAoB+hZLPW9SmKbQkbHIhMw/acKSlpn7WohdMUc/Vd4j1iSMBO0hWwU8mjB7a5p5bl8g==} + /undici/5.15.1: + resolution: {integrity: sha512-XLk8g0WAngdvFqTI+VKfBtM4YWXgdxkf1WezC771Es0Dd+Pm1KmNx8t93WTC+Hh9tnghmVxkclU1HN+j+CvIUA==} engines: {node: '>=12.18'} dependencies: busboy: 1.6.0 @@ -1441,7 +1441,7 @@ packages: /uri-js/4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: - punycode: 2.2.0 + punycode: 2.3.0 dev: true /vite/4.0.4_sass@1.57.1: @@ -1472,7 +1472,7 @@ packages: esbuild: 0.16.17 postcss: 8.4.21 resolve: 1.22.1 - rollup: 3.10.0 + rollup: 3.10.1 sass: 1.57.1 optionalDependencies: fsevents: 2.3.2 diff --git a/frontend/src/components/DeviceCard.svelte b/frontend/src/components/DeviceCard.svelte index 83d1a0e0..8a110863 100644 --- a/frontend/src/components/DeviceCard.svelte +++ b/frontend/src/components/DeviceCard.svelte @@ -1,7 +1,7 @@
{device.name}
-{device.ip}
-+
{device.ip}
+ {#if device?.expand?.ports} +
+
{formatDistance(parseISO(device.updated), now, { includeSeconds: true, addSuffix: true diff --git a/frontend/src/components/Navbar.svelte b/frontend/src/components/Navbar.svelte index d5af61e5..033d2611 100644 --- a/frontend/src/components/Navbar.svelte +++ b/frontend/src/components/Navbar.svelte @@ -1,9 +1,13 @@