mirror of https://github.com/jetkvm/kvm.git
Compare commits
1 Commits
d4bc6b613a
...
07aaca36b2
| Author | SHA1 | Date |
|---|---|---|
|
|
07aaca36b2 |
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
if: github.event_name != 'pull_request_review' || github.event.review.state == 'approved'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@fa96338abe5531f6e34c5cc0bbe28c1a533d5505 # v4.2.1
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
|
|
|||
39
go.mod
39
go.mod
|
|
@ -6,31 +6,32 @@ require (
|
|||
github.com/Masterminds/semver/v3 v3.4.0
|
||||
github.com/beevik/ntp v1.4.3
|
||||
github.com/coder/websocket v1.8.13
|
||||
github.com/coreos/go-oidc/v3 v3.15.0
|
||||
github.com/coreos/go-oidc/v3 v3.14.1
|
||||
github.com/creack/pty v1.1.24
|
||||
github.com/fsnotify/fsnotify v1.9.0
|
||||
github.com/gin-contrib/logger v1.2.6
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/go-co-op/gocron/v2 v2.16.5
|
||||
github.com/go-co-op/gocron/v2 v2.16.3
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/guregu/null/v6 v6.0.0
|
||||
github.com/gwatts/rootcerts v0.0.0-20250901182336-dc5ae18bd79f
|
||||
github.com/gwatts/rootcerts v0.0.0-20250601184604-370a9a75f341
|
||||
github.com/hanwen/go-fuse/v2 v2.8.0
|
||||
github.com/pion/logging v0.2.4
|
||||
github.com/pion/mdns/v2 v2.0.7
|
||||
github.com/pion/webrtc/v4 v4.1.4
|
||||
github.com/pion/webrtc/v4 v4.1.3
|
||||
github.com/pojntfx/go-nbd v0.3.2
|
||||
github.com/prometheus/client_golang v1.23.0
|
||||
github.com/prometheus/common v0.66.0
|
||||
github.com/prometheus/procfs v0.17.0
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/prometheus/common v0.65.0
|
||||
github.com/prometheus/procfs v0.16.1
|
||||
github.com/psanford/httpreadat v0.1.0
|
||||
github.com/rs/zerolog v1.34.0
|
||||
github.com/sourcegraph/tf-dag v0.2.2-0.20250131204052-3e8ff1477b4f
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
go.bug.st/serial v1.6.4
|
||||
golang.org/x/crypto v0.41.0
|
||||
golang.org/x/net v0.43.0
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.org/x/crypto v0.40.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/sys v0.34.0
|
||||
)
|
||||
|
||||
replace github.com/pojntfx/go-nbd v0.3.2 => github.com/chemhack/go-nbd v0.0.0-20241006125820-59e45f5b1e7b
|
||||
|
|
@ -50,7 +51,6 @@ require (
|
|||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
|
||||
github.com/jonboulle/clockwork v0.5.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
|
|
@ -63,18 +63,18 @@ require (
|
|||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pilebones/go-udev v0.9.1 // indirect
|
||||
github.com/pion/datachannel v1.5.10 // indirect
|
||||
github.com/pion/dtls/v3 v3.0.7 // indirect
|
||||
github.com/pion/dtls/v3 v3.0.6 // indirect
|
||||
github.com/pion/ice/v4 v4.0.10 // indirect
|
||||
github.com/pion/interceptor v0.1.40 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.15 // indirect
|
||||
github.com/pion/rtp v1.8.22 // indirect
|
||||
github.com/pion/rtp v1.8.20 // indirect
|
||||
github.com/pion/sctp v1.8.39 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.16 // indirect
|
||||
github.com/pion/srtp/v3 v3.0.7 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.14 // indirect
|
||||
github.com/pion/srtp/v3 v3.0.6 // indirect
|
||||
github.com/pion/stun/v3 v3.0.0 // indirect
|
||||
github.com/pion/transport/v3 v3.0.7 // indirect
|
||||
github.com/pion/turn/v4 v4.1.1 // indirect
|
||||
github.com/pion/turn/v4 v4.0.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
|
|
@ -85,8 +85,7 @@ require (
|
|||
github.com/wlynxg/anet v0.0.5 // indirect
|
||||
golang.org/x/arch v0.18.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
|||
80
go.sum
80
go.sum
|
|
@ -18,8 +18,8 @@ github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJ
|
|||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
|
||||
github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
|
||||
github.com/coreos/go-oidc/v3 v3.15.0 h1:R6Oz8Z4bqWR7VFQ+sPSvZPQv4x8M+sJkDO5ojgwlyAg=
|
||||
github.com/coreos/go-oidc/v3 v3.15.0/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/goselect v0.1.3 h1:MaGNMclRo7P2Jl21hBpR1Cn33ITSbKP6E49RtfblLKc=
|
||||
github.com/creack/goselect v0.1.3/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
|
|
@ -38,8 +38,8 @@ github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w
|
|||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
||||
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-co-op/gocron/v2 v2.16.5 h1:j228Jxk7bb9CF8LKR3gS+bK3rcjRUINjlVI+ZMp26Ss=
|
||||
github.com/go-co-op/gocron/v2 v2.16.5/go.mod h1:zAfC/GFQ668qHxOVl/D68Jh5Ce7sDqX6TJnSQyRkRBc=
|
||||
github.com/go-co-op/gocron/v2 v2.16.3 h1:kYqukZqBa8RC2+AFAHnunmKcs9GRTjwBo8WRF3I6cbI=
|
||||
github.com/go-co-op/gocron/v2 v2.16.3/go.mod h1:aTf7/+5Jo2E+cyAqq625UQ6DzpkV96b22VHIUAt6l3c=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
|
|
@ -58,12 +58,12 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
|
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248=
|
||||
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
|
||||
github.com/guregu/null/v6 v6.0.0 h1:N14VRS+4di81i1PXRiprbQJ9EM9gqBa0+KVMeS/QSjQ=
|
||||
github.com/guregu/null/v6 v6.0.0/go.mod h1:hrMIhIfrOZeLPZhROSn149tpw2gHkidAqxoXNyeX3iQ=
|
||||
github.com/gwatts/rootcerts v0.0.0-20250901182336-dc5ae18bd79f h1:08t2PbrkDgW2+mwCQ3jhKUBrCM9Bc9SeH5j2Dst3B+0=
|
||||
github.com/gwatts/rootcerts v0.0.0-20250901182336-dc5ae18bd79f/go.mod h1:5Kt9XkWvkGi2OHOq0QsGxebHmhCcqJ8KCbNg/a6+n+g=
|
||||
github.com/gwatts/rootcerts v0.0.0-20250601184604-370a9a75f341 h1:zPrkLSKi7kKJoNJH4uUmsQ86+0/QqpwEns0NyNLwKv0=
|
||||
github.com/gwatts/rootcerts v0.0.0-20250601184604-370a9a75f341/go.mod h1:5Kt9XkWvkGi2OHOq0QsGxebHmhCcqJ8KCbNg/a6+n+g=
|
||||
github.com/hanwen/go-fuse/v2 v2.8.0 h1:wV8rG7rmCz8XHSOwBZhG5YcVqcYjkzivjmbaMafPlAs=
|
||||
github.com/hanwen/go-fuse/v2 v2.8.0/go.mod h1:yE6D2PqWwm3CbYRxFXV9xUd8Md5d6NG0WBs5spCswmI=
|
||||
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
|
|
@ -92,6 +92,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
|||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
||||
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
|
@ -105,8 +107,8 @@ github.com/pilebones/go-udev v0.9.1 h1:uN72M1C1fgzhsVmBGEM8w9RD1JY4iVsPZpr+Z6rb3
|
|||
github.com/pilebones/go-udev v0.9.1/go.mod h1:Bgcl07crebF3JSeS4+nuaRvhWFdCeFoBhXXeAp93XNo=
|
||||
github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o=
|
||||
github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M=
|
||||
github.com/pion/dtls/v3 v3.0.7 h1:bItXtTYYhZwkPFk4t1n3Kkf5TDrfj6+4wG+CZR8uI9Q=
|
||||
github.com/pion/dtls/v3 v3.0.7/go.mod h1:uDlH5VPrgOQIw59irKYkMudSFprY9IEFCqz/eTz16f8=
|
||||
github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E=
|
||||
github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU=
|
||||
github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4=
|
||||
github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw=
|
||||
github.com/pion/interceptor v0.1.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4=
|
||||
|
|
@ -119,33 +121,33 @@ github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
|||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
|
||||
github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
|
||||
github.com/pion/rtp v1.8.22 h1:8NCVDDF+uSJmMUkjLJVnIr/HX7gPesyMV1xFt5xozXc=
|
||||
github.com/pion/rtp v1.8.22/go.mod h1:rF5nS1GqbR7H/TCpKwylzeq6yDM+MM6k+On5EgeThEM=
|
||||
github.com/pion/rtp v1.8.20 h1:8zcyqohadZE8FCBeGdyEvHiclPIezcwRQH9zfapFyYI=
|
||||
github.com/pion/rtp v1.8.20/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk=
|
||||
github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE=
|
||||
github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE=
|
||||
github.com/pion/sdp/v3 v3.0.16 h1:0dKzYO6gTAvuLaAKQkC02eCPjMIi4NuAr/ibAwrGDCo=
|
||||
github.com/pion/sdp/v3 v3.0.16/go.mod h1:9tyKzznud3qiweZcD86kS0ff1pGYB3VX+Bcsmkx6IXo=
|
||||
github.com/pion/srtp/v3 v3.0.7 h1:QUElw0A/FUg3MP8/KNMZB3i0m8F9XeMnTum86F7S4bs=
|
||||
github.com/pion/srtp/v3 v3.0.7/go.mod h1:qvnHeqbhT7kDdB+OGB05KA/P067G3mm7XBfLaLiaNF0=
|
||||
github.com/pion/sdp/v3 v3.0.14 h1:1h7gBr9FhOWH5GjWWY5lcw/U85MtdcibTyt/o6RxRUI=
|
||||
github.com/pion/sdp/v3 v3.0.14/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E=
|
||||
github.com/pion/srtp/v3 v3.0.6 h1:E2gyj1f5X10sB/qILUGIkL4C2CqK269Xq167PbGCc/4=
|
||||
github.com/pion/srtp/v3 v3.0.6/go.mod h1:BxvziG3v/armJHAaJ87euvkhHqWe9I7iiOy50K2QkhY=
|
||||
github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
|
||||
github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU=
|
||||
github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0=
|
||||
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
|
||||
github.com/pion/turn/v4 v4.1.1 h1:9UnY2HB99tpDyz3cVVZguSxcqkJ1DsTSZ+8TGruh4fc=
|
||||
github.com/pion/turn/v4 v4.1.1/go.mod h1:2123tHk1O++vmjI5VSD0awT50NywDAq5A2NNNU4Jjs8=
|
||||
github.com/pion/webrtc/v4 v4.1.4 h1:/gK1ACGHXQmtyVVbJFQDxNoODg4eSRiFLB7t9r9pg8M=
|
||||
github.com/pion/webrtc/v4 v4.1.4/go.mod h1:Oab9npu1iZtQRMic3K3toYq5zFPvToe/QBw7dMI2ok4=
|
||||
github.com/pion/turn/v4 v4.0.2 h1:ZqgQ3+MjP32ug30xAbD6Mn+/K4Sxi3SdNOTFf+7mpps=
|
||||
github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs=
|
||||
github.com/pion/webrtc/v4 v4.1.3 h1:YZ67Boj9X/hk190jJZ8+HFGQ6DqSZ/fYP3sLAZv7c3c=
|
||||
github.com/pion/webrtc/v4 v4.1.3/go.mod h1:rsq+zQ82ryfR9vbb0L1umPJ6Ogq7zm8mcn9fcGnxomM=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
|
||||
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.66.0 h1:K/rJPHrG3+AoQs50r2+0t7zMnMzek2Vbv31OFVsMeVY=
|
||||
github.com/prometheus/common v0.66.0/go.mod h1:Ux6NtV1B4LatamKE63tJBntoxD++xmtI/lK0VtEplN4=
|
||||
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
|
||||
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
|
||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/psanford/httpreadat v0.1.0 h1:VleW1HS2zO7/4c7c7zNl33fO6oYACSagjJIyMIwZLUE=
|
||||
github.com/psanford/httpreadat v0.1.0/go.mod h1:Zg7P+TlBm3bYbyHTKv/EdtSJZn3qwbPwpfZ/I9GKCRE=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
|
|
@ -165,8 +167,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
|
||||
|
|
@ -183,10 +185,10 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
|||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc=
|
||||
golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
@ -194,17 +196,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
|
|
@ -148,8 +148,6 @@ func (u *UsbGadget) GetKeysDownState() KeysDownState {
|
|||
func (u *UsbGadget) updateKeyDownState(state KeysDownState) {
|
||||
u.log.Trace().Interface("old", u.keysDownState).Interface("new", state).Msg("acquiring keyboardStateLock for updateKeyDownState")
|
||||
|
||||
// this is intentional to unlock keyboard state lock before onKeysDownChange callback
|
||||
{
|
||||
u.keyboardStateLock.Lock()
|
||||
defer u.keyboardStateLock.Unlock()
|
||||
|
||||
|
|
@ -160,7 +158,6 @@ func (u *UsbGadget) updateKeyDownState(state KeysDownState) {
|
|||
|
||||
u.log.Trace().Interface("old", u.keysDownState).Interface("new", state).Msg("keysDownState updated")
|
||||
u.keysDownState = state
|
||||
}
|
||||
|
||||
if u.onKeysDownChange != nil {
|
||||
u.log.Trace().Interface("state", state).Msg("calling onKeysDownChange")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "kvm-ui",
|
||||
"private": true,
|
||||
"version": "2025.09.03.2100",
|
||||
"version": "2025.08.25.2300",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": "22.15.0"
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
"@xterm/addon-webgl": "^0.18.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"cva": "^1.0.0-beta.4",
|
||||
"dayjs": "^1.11.18",
|
||||
"dayjs": "^1.11.13",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"focus-trap-react": "^11.0.4",
|
||||
"framer-motion": "^12.23.12",
|
||||
|
|
@ -41,11 +41,11 @@
|
|||
"react-dom": "^19.1.1",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-router": "^7.8.2",
|
||||
"react-simple-keyboard": "^3.8.119",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-simple-keyboard": "^3.8.115",
|
||||
"react-use-websocket": "^4.13.0",
|
||||
"react-xtermjs": "^1.0.10",
|
||||
"recharts": "^3.1.2",
|
||||
"recharts": "^2.15.3",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"usehooks-ts": "^3.1.1",
|
||||
"validator": "^13.15.15",
|
||||
|
|
@ -59,13 +59,13 @@
|
|||
"@tailwindcss/postcss": "^4.1.12",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tailwindcss/vite": "^4.1.12",
|
||||
"@types/react": "^19.1.12",
|
||||
"@types/react-dom": "^19.1.9",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/validator": "^13.15.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.42.0",
|
||||
"@typescript-eslint/parser": "^8.42.0",
|
||||
"@vitejs/plugin-react-swc": "^4.0.1",
|
||||
"@types/react": "^19.1.11",
|
||||
"@types/react-dom": "^19.1.8",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@types/validator": "^13.15.2",
|
||||
"@typescript-eslint/eslint-plugin": "^8.41.0",
|
||||
"@typescript-eslint/parser": "^8.41.0",
|
||||
"@vitejs/plugin-react-swc": "^3.10.2",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^9.34.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
"prettier-plugin-tailwindcss": "^0.6.14",
|
||||
"tailwindcss": "^4.1.12",
|
||||
"typescript": "^5.9.2",
|
||||
"vite": "^7.1.4",
|
||||
"vite": "^6.3.5",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useLocation, useNavigation, useSearchParams } from "react-router";
|
||||
import { useLocation, useNavigation, useSearchParams } from "react-router-dom";
|
||||
|
||||
import { Button, LinkButton } from "@components/Button";
|
||||
import { GoogleIcon } from "@components/Icons";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import React, { JSX } from "react";
|
||||
import { Link, useNavigation } from "react-router";
|
||||
import type { FetcherWithComponents, LinkProps } from "react-router";
|
||||
import { FetcherWithComponents, Link, LinkProps, useNavigation } from "react-router-dom";
|
||||
|
||||
import ExtLink from "@/components/ExtLink";
|
||||
import LoadingSpinner from "@/components/LoadingSpinner";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import { useNavigation } from "react-router";
|
||||
import type { FetcherWithComponents } from "react-router";
|
||||
import { FetcherWithComponents, useNavigation } from "react-router-dom";
|
||||
|
||||
export default function Fieldset({
|
||||
children,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useCallback } from "react";
|
||||
import { useNavigate } from "react-router";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { ArrowLeftEndOnRectangleIcon, ChevronDownIcon } from "@heroicons/react/16/solid";
|
||||
import { Button, Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
|
||||
import { LuMonitorSmartphone } from "react-icons/lu";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { MdConnectWithoutContact } from "react-icons/md";
|
||||
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
|
||||
import { Link } from "react-router";
|
||||
import { Link } from "react-router-dom";
|
||||
import { LuEllipsisVertical } from "react-icons/lu";
|
||||
|
||||
import Card from "@components/Card";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Link } from "react-router";
|
||||
import { Link } from "react-router-dom";
|
||||
import React from "react";
|
||||
|
||||
import Container from "@/components/Container";
|
||||
|
|
|
|||
|
|
@ -7,14 +7,16 @@ import MacroBar from "@/components/MacroBar";
|
|||
import InfoBar from "@components/InfoBar";
|
||||
import notifications from "@/notifications";
|
||||
import useKeyboard from "@/hooks/useKeyboard";
|
||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
import { useHidRpc } from "@/hooks/useHidRpc";
|
||||
import { cx } from "@/cva.config";
|
||||
import { keys } from "@/keyboardMappings";
|
||||
import {
|
||||
useMouseStore,
|
||||
useRTCStore,
|
||||
useSettingsStore,
|
||||
useVideoStore,
|
||||
} from "@/hooks/stores";
|
||||
import useMouse from "@/hooks/useMouse";
|
||||
|
||||
import {
|
||||
HDMIErrorOverlay,
|
||||
|
|
@ -30,18 +32,10 @@ export default function WebRTCVideo() {
|
|||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [isPointerLockActive, setIsPointerLockActive] = useState(false);
|
||||
const [isKeyboardLockActive, setIsKeyboardLockActive] = useState(false);
|
||||
|
||||
const isPointerLockPossible = window.location.protocol === "https:" || window.location.hostname === "localhost";
|
||||
|
||||
// Store hooks
|
||||
const settings = useSettingsStore();
|
||||
const { handleKeyPress, resetKeyboardState } = useKeyboard();
|
||||
const {
|
||||
getRelMouseMoveHandler,
|
||||
getAbsMouseMoveHandler,
|
||||
getMouseWheelHandler,
|
||||
resetMousePosition,
|
||||
} = useMouse();
|
||||
const { setMousePosition, setMouseMove } = useMouseStore();
|
||||
const {
|
||||
setClientSize: setVideoClientSize,
|
||||
setSize: setVideoSize,
|
||||
|
|
@ -62,6 +56,13 @@ export default function WebRTCVideo() {
|
|||
const hdmiError = ["no_lock", "no_signal", "out_of_range"].includes(hdmiState);
|
||||
const isVideoLoading = !isPlaying;
|
||||
|
||||
// Mouse wheel states
|
||||
const [blockWheelEvent, setBlockWheelEvent] = useState(false);
|
||||
|
||||
// Misc states and hooks
|
||||
const { send } = useJsonRpc();
|
||||
const { reportAbsMouseEvent, reportRelMouseEvent, rpcHidReady } = useHidRpc();
|
||||
|
||||
// Video-related
|
||||
const handleResize = useCallback(
|
||||
({ width, height }: { width: number | undefined; height: number | undefined }) => {
|
||||
|
|
@ -100,6 +101,7 @@ export default function WebRTCVideo() {
|
|||
);
|
||||
|
||||
// Pointer lock and keyboard lock related
|
||||
const isPointerLockPossible = window.location.protocol === "https:" || window.location.hostname === "localhost";
|
||||
const isFullscreenEnabled = document.fullscreenEnabled;
|
||||
|
||||
const checkNavigatorPermissions = useCallback(async (permissionName: string) => {
|
||||
|
|
@ -211,32 +213,153 @@ export default function WebRTCVideo() {
|
|||
}
|
||||
};
|
||||
|
||||
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
||||
document.addEventListener("fullscreenchange ", handleFullscreenChange);
|
||||
}, [releaseKeyboardLock]);
|
||||
|
||||
const absMouseMoveHandler = useMemo(
|
||||
() => getAbsMouseMoveHandler({
|
||||
videoClientWidth,
|
||||
videoClientHeight,
|
||||
videoWidth,
|
||||
videoHeight,
|
||||
}),
|
||||
[getAbsMouseMoveHandler, videoClientWidth, videoClientHeight, videoWidth, videoHeight],
|
||||
// Mouse-related
|
||||
const calcDelta = (pos: number) => (Math.abs(pos) < 10 ? pos * 2 : pos);
|
||||
|
||||
const sendRelMouseMovement = useCallback(
|
||||
(x: number, y: number, buttons: number) => {
|
||||
if (settings.mouseMode !== "relative") return;
|
||||
// if we ignore the event, double-click will not work
|
||||
// if (x === 0 && y === 0 && buttons === 0) return;
|
||||
const dx = calcDelta(x);
|
||||
const dy = calcDelta(y);
|
||||
if (rpcHidReady) {
|
||||
reportRelMouseEvent(dx, dy, buttons);
|
||||
} else {
|
||||
// kept for backward compatibility
|
||||
send("relMouseReport", { dx, dy, buttons });
|
||||
}
|
||||
setMouseMove({ x, y, buttons });
|
||||
},
|
||||
[
|
||||
send,
|
||||
reportRelMouseEvent,
|
||||
setMouseMove,
|
||||
settings.mouseMode,
|
||||
rpcHidReady,
|
||||
],
|
||||
);
|
||||
|
||||
const relMouseMoveHandler = useMemo(
|
||||
() => getRelMouseMoveHandler({
|
||||
isPointerLockActive,
|
||||
isPointerLockPossible,
|
||||
}),
|
||||
[getRelMouseMoveHandler, isPointerLockActive, isPointerLockPossible],
|
||||
const relMouseMoveHandler = useCallback(
|
||||
(e: MouseEvent) => {
|
||||
if (settings.mouseMode !== "relative") return;
|
||||
if (isPointerLockActive === false && isPointerLockPossible) return;
|
||||
|
||||
// Send mouse movement
|
||||
const { buttons } = e;
|
||||
sendRelMouseMovement(e.movementX, e.movementY, buttons);
|
||||
},
|
||||
[isPointerLockActive, isPointerLockPossible, sendRelMouseMovement, settings.mouseMode],
|
||||
);
|
||||
|
||||
const mouseWheelHandler = useMemo(
|
||||
() => getMouseWheelHandler(),
|
||||
[getMouseWheelHandler],
|
||||
const sendAbsMouseMovement = useCallback(
|
||||
(x: number, y: number, buttons: number) => {
|
||||
if (settings.mouseMode !== "absolute") return;
|
||||
if (rpcHidReady) {
|
||||
reportAbsMouseEvent(x, y, buttons);
|
||||
} else {
|
||||
// kept for backward compatibility
|
||||
send("absMouseReport", { x, y, buttons });
|
||||
}
|
||||
// We set that for the debug info bar
|
||||
setMousePosition(x, y);
|
||||
},
|
||||
[
|
||||
send,
|
||||
reportAbsMouseEvent,
|
||||
setMousePosition,
|
||||
settings.mouseMode,
|
||||
rpcHidReady,
|
||||
],
|
||||
);
|
||||
|
||||
const absMouseMoveHandler = useCallback(
|
||||
(e: MouseEvent) => {
|
||||
if (!videoClientWidth || !videoClientHeight) return;
|
||||
if (settings.mouseMode !== "absolute") return;
|
||||
|
||||
// Get the aspect ratios of the video element and the video stream
|
||||
const videoElementAspectRatio = videoClientWidth / videoClientHeight;
|
||||
const videoStreamAspectRatio = videoWidth / videoHeight;
|
||||
|
||||
// Calculate the effective video display area
|
||||
let effectiveWidth = videoClientWidth;
|
||||
let effectiveHeight = videoClientHeight;
|
||||
let offsetX = 0;
|
||||
let offsetY = 0;
|
||||
|
||||
if (videoElementAspectRatio > videoStreamAspectRatio) {
|
||||
// Pillarboxing: black bars on the left and right
|
||||
effectiveWidth = videoClientHeight * videoStreamAspectRatio;
|
||||
offsetX = (videoClientWidth - effectiveWidth) / 2;
|
||||
} else if (videoElementAspectRatio < videoStreamAspectRatio) {
|
||||
// Letterboxing: black bars on the top and bottom
|
||||
effectiveHeight = videoClientWidth / videoStreamAspectRatio;
|
||||
offsetY = (videoClientHeight - effectiveHeight) / 2;
|
||||
}
|
||||
|
||||
// Clamp mouse position within the effective video boundaries
|
||||
const clampedX = Math.min(Math.max(offsetX, e.offsetX), offsetX + effectiveWidth);
|
||||
const clampedY = Math.min(Math.max(offsetY, e.offsetY), offsetY + effectiveHeight);
|
||||
|
||||
// Map clamped mouse position to the video stream's coordinate system
|
||||
const relativeX = (clampedX - offsetX) / effectiveWidth;
|
||||
const relativeY = (clampedY - offsetY) / effectiveHeight;
|
||||
|
||||
// Convert to HID absolute coordinate system (0-32767 range)
|
||||
const x = Math.round(relativeX * 32767);
|
||||
const y = Math.round(relativeY * 32767);
|
||||
|
||||
// Send mouse movement
|
||||
const { buttons } = e;
|
||||
sendAbsMouseMovement(x, y, buttons);
|
||||
},
|
||||
[settings.mouseMode, videoClientWidth, videoClientHeight, videoWidth, videoHeight, sendAbsMouseMovement],
|
||||
);
|
||||
|
||||
const mouseWheelHandler = useCallback(
|
||||
(e: WheelEvent) => {
|
||||
|
||||
if (settings.scrollThrottling && blockWheelEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine if the wheel event is an accel scroll value
|
||||
const isAccel = Math.abs(e.deltaY) >= 100;
|
||||
|
||||
// Calculate the accel scroll value
|
||||
const accelScrollValue = e.deltaY / 100;
|
||||
|
||||
// Calculate the no accel scroll value
|
||||
const noAccelScrollValue = Math.sign(e.deltaY);
|
||||
|
||||
// Get scroll value
|
||||
const scrollValue = isAccel ? accelScrollValue : noAccelScrollValue;
|
||||
|
||||
// Apply clamping (i.e. min and max mouse wheel hardware value)
|
||||
const clampedScrollValue = Math.max(-127, Math.min(127, scrollValue));
|
||||
|
||||
// Invert the clamped scroll value to match expected behavior
|
||||
const invertedScrollValue = -clampedScrollValue;
|
||||
|
||||
send("wheelReport", { wheelY: invertedScrollValue });
|
||||
|
||||
// Apply blocking delay based of throttling settings
|
||||
if (settings.scrollThrottling && !blockWheelEvent) {
|
||||
setBlockWheelEvent(true);
|
||||
setTimeout(() => setBlockWheelEvent(false), settings.scrollThrottling);
|
||||
}
|
||||
},
|
||||
[send, blockWheelEvent, settings],
|
||||
);
|
||||
|
||||
const resetMousePosition = useCallback(() => {
|
||||
sendAbsMouseMovement(0, 0, 0);
|
||||
}, [sendAbsMouseMovement]);
|
||||
|
||||
const keyDownHandler = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
|
|
@ -391,16 +514,14 @@ export default function WebRTCVideo() {
|
|||
function setMouseModeEventListeners() {
|
||||
const videoElmRefValue = videoElm.current;
|
||||
if (!videoElmRefValue) return;
|
||||
|
||||
const isRelativeMouseMode = (settings.mouseMode === "relative");
|
||||
const mouseHandler = isRelativeMouseMode ? relMouseMoveHandler : absMouseMoveHandler;
|
||||
|
||||
const abortController = new AbortController();
|
||||
const signal = abortController.signal;
|
||||
|
||||
videoElmRefValue.addEventListener("mousemove", mouseHandler, { signal });
|
||||
videoElmRefValue.addEventListener("pointerdown", mouseHandler, { signal });
|
||||
videoElmRefValue.addEventListener("pointerup", mouseHandler, { signal });
|
||||
videoElmRefValue.addEventListener("mousemove", isRelativeMouseMode ? relMouseMoveHandler : absMouseMoveHandler, { signal });
|
||||
videoElmRefValue.addEventListener("pointerdown", isRelativeMouseMode ? relMouseMoveHandler : absMouseMoveHandler, { signal });
|
||||
videoElmRefValue.addEventListener("pointerup", isRelativeMouseMode ? relMouseMoveHandler : absMouseMoveHandler, { signal });
|
||||
videoElmRefValue.addEventListener("wheel", mouseWheelHandler, {
|
||||
signal,
|
||||
passive: true,
|
||||
|
|
@ -428,16 +549,7 @@ export default function WebRTCVideo() {
|
|||
abortController.abort();
|
||||
};
|
||||
},
|
||||
[
|
||||
isPointerLockActive,
|
||||
isPointerLockPossible,
|
||||
requestPointerLock,
|
||||
absMouseMoveHandler,
|
||||
relMouseMoveHandler,
|
||||
mouseWheelHandler,
|
||||
resetMousePosition,
|
||||
settings.mouseMode,
|
||||
],
|
||||
[absMouseMoveHandler, isPointerLockActive, isPointerLockPossible, mouseWheelHandler, relMouseMoveHandler, requestPointerLock, resetMousePosition, settings.mouseMode],
|
||||
);
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
LuRadioReceiver,
|
||||
} from "react-icons/lu";
|
||||
import { useClose } from "@headlessui/react";
|
||||
import { useLocation } from "react-router";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
import { Button } from "@components/Button";
|
||||
import Card, { GridCard } from "@components/Card";
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ export class RpcMessage {
|
|||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public static unmarshal(_data: Uint8Array): RpcMessage | undefined {
|
||||
// @ts-expect-error: this is a base class, so we don't need to implement it
|
||||
public static unmarshal(data: Uint8Array): RpcMessage | undefined {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { useNavigate, useParams } from "react-router";
|
||||
import type { NavigateOptions } from "react-router";
|
||||
import { useNavigate, useParams, NavigateOptions } from "react-router-dom";
|
||||
import { useCallback, useMemo } from "react";
|
||||
|
||||
import { isOnDevice } from "../main";
|
||||
|
|
|
|||
|
|
@ -22,22 +22,16 @@ export default function useKeyboard() {
|
|||
// keysDownState when queried since the keyPressReport was introduced together with the
|
||||
// getKeysDownState API.
|
||||
const { keyPressReportApiAvailable, setkeyPressReportApiAvailable } = useHidStore();
|
||||
const enableKeyPressReport = useCallback((reason: string) => {
|
||||
if (keyPressReportApiAvailable) return;
|
||||
console.debug(`Enable keyPressReport API because ${reason}`);
|
||||
setkeyPressReportApiAvailable(true);
|
||||
}, [setkeyPressReportApiAvailable, keyPressReportApiAvailable]);
|
||||
|
||||
// HidRPC is a binary format for exchanging keyboard and mouse events
|
||||
const { reportKeyboardEvent, reportKeypressEvent, rpcHidReady } = useHidRpc((message) => {
|
||||
switch (message.constructor) {
|
||||
case KeysDownStateMessage:
|
||||
setKeysDownState((message as KeysDownStateMessage).keysDownState);
|
||||
enableKeyPressReport("HidRPC:KeysDownStateMessage received");
|
||||
setkeyPressReportApiAvailable(true);
|
||||
break;
|
||||
case KeyboardLedStateMessage:
|
||||
setKeyboardLedState((message as KeyboardLedStateMessage).keyboardLedState);
|
||||
enableKeyPressReport("HidRPC:KeyboardLedStateMessage received");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -57,7 +51,7 @@ export default function useKeyboard() {
|
|||
if (rpcHidReady) {
|
||||
console.debug("Sending keyboard report via HidRPC");
|
||||
reportKeyboardEvent(state.keys, state.modifier);
|
||||
enableKeyPressReport("HidRPC:KeyboardReport received");
|
||||
setkeyPressReportApiAvailable(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +66,7 @@ export default function useKeyboard() {
|
|||
rpcHidReady,
|
||||
send,
|
||||
reportKeyboardEvent,
|
||||
enableKeyPressReport,
|
||||
setkeyPressReportApiAvailable,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,178 +0,0 @@
|
|||
import { useCallback, useState } from "react";
|
||||
|
||||
import { useJsonRpc } from "./useJsonRpc";
|
||||
import { useHidRpc } from "./useHidRpc";
|
||||
import { useMouseStore, useSettingsStore } from "./stores";
|
||||
|
||||
const calcDelta = (pos: number) => (Math.abs(pos) < 10 ? pos * 2 : pos);
|
||||
|
||||
export interface AbsMouseMoveHandlerProps {
|
||||
videoClientWidth: number;
|
||||
videoClientHeight: number;
|
||||
videoWidth: number;
|
||||
videoHeight: number;
|
||||
}
|
||||
|
||||
export interface RelMouseMoveHandlerProps {
|
||||
isPointerLockActive: boolean;
|
||||
isPointerLockPossible: boolean;
|
||||
}
|
||||
|
||||
export default function useMouse() {
|
||||
// states
|
||||
const { setMousePosition, setMouseMove } = useMouseStore();
|
||||
const [blockWheelEvent, setBlockWheelEvent] = useState(false);
|
||||
|
||||
const { mouseMode, scrollThrottling } = useSettingsStore();
|
||||
|
||||
// RPC hooks
|
||||
const { send } = useJsonRpc();
|
||||
const { reportAbsMouseEvent, reportRelMouseEvent, rpcHidReady } = useHidRpc();
|
||||
// Mouse-related
|
||||
|
||||
const sendRelMouseMovement = useCallback(
|
||||
(x: number, y: number, buttons: number) => {
|
||||
if (mouseMode !== "relative") return;
|
||||
// if we ignore the event, double-click will not work
|
||||
// if (x === 0 && y === 0 && buttons === 0) return;
|
||||
const dx = calcDelta(x);
|
||||
const dy = calcDelta(y);
|
||||
if (rpcHidReady) {
|
||||
reportRelMouseEvent(dx, dy, buttons);
|
||||
} else {
|
||||
// kept for backward compatibility
|
||||
send("relMouseReport", { dx, dy, buttons });
|
||||
}
|
||||
setMouseMove({ x, y, buttons });
|
||||
},
|
||||
[
|
||||
send,
|
||||
reportRelMouseEvent,
|
||||
setMouseMove,
|
||||
mouseMode,
|
||||
rpcHidReady,
|
||||
],
|
||||
);
|
||||
|
||||
const getRelMouseMoveHandler = useCallback(
|
||||
({ isPointerLockActive, isPointerLockPossible }: RelMouseMoveHandlerProps) => (e: MouseEvent) => {
|
||||
if (mouseMode !== "relative") return;
|
||||
if (isPointerLockActive === false && isPointerLockPossible) return;
|
||||
|
||||
// Send mouse movement
|
||||
const { buttons } = e;
|
||||
sendRelMouseMovement(e.movementX, e.movementY, buttons);
|
||||
},
|
||||
[sendRelMouseMovement, mouseMode],
|
||||
);
|
||||
|
||||
const sendAbsMouseMovement = useCallback(
|
||||
(x: number, y: number, buttons: number) => {
|
||||
if (mouseMode !== "absolute") return;
|
||||
if (rpcHidReady) {
|
||||
reportAbsMouseEvent(x, y, buttons);
|
||||
} else {
|
||||
// kept for backward compatibility
|
||||
send("absMouseReport", { x, y, buttons });
|
||||
}
|
||||
// We set that for the debug info bar
|
||||
setMousePosition(x, y);
|
||||
},
|
||||
[
|
||||
send,
|
||||
reportAbsMouseEvent,
|
||||
setMousePosition,
|
||||
mouseMode,
|
||||
rpcHidReady,
|
||||
],
|
||||
);
|
||||
|
||||
const getAbsMouseMoveHandler = useCallback(
|
||||
({ videoClientWidth, videoClientHeight, videoWidth, videoHeight }: AbsMouseMoveHandlerProps) => (e: MouseEvent) => {
|
||||
if (!videoClientWidth || !videoClientHeight) return;
|
||||
if (mouseMode !== "absolute") return;
|
||||
|
||||
// Get the aspect ratios of the video element and the video stream
|
||||
const videoElementAspectRatio = videoClientWidth / videoClientHeight;
|
||||
const videoStreamAspectRatio = videoWidth / videoHeight;
|
||||
|
||||
// Calculate the effective video display area
|
||||
let effectiveWidth = videoClientWidth;
|
||||
let effectiveHeight = videoClientHeight;
|
||||
let offsetX = 0;
|
||||
let offsetY = 0;
|
||||
|
||||
if (videoElementAspectRatio > videoStreamAspectRatio) {
|
||||
// Pillarboxing: black bars on the left and right
|
||||
effectiveWidth = videoClientHeight * videoStreamAspectRatio;
|
||||
offsetX = (videoClientWidth - effectiveWidth) / 2;
|
||||
} else if (videoElementAspectRatio < videoStreamAspectRatio) {
|
||||
// Letterboxing: black bars on the top and bottom
|
||||
effectiveHeight = videoClientWidth / videoStreamAspectRatio;
|
||||
offsetY = (videoClientHeight - effectiveHeight) / 2;
|
||||
}
|
||||
|
||||
// Clamp mouse position within the effective video boundaries
|
||||
const clampedX = Math.min(Math.max(offsetX, e.offsetX), offsetX + effectiveWidth);
|
||||
const clampedY = Math.min(Math.max(offsetY, e.offsetY), offsetY + effectiveHeight);
|
||||
|
||||
// Map clamped mouse position to the video stream's coordinate system
|
||||
const relativeX = (clampedX - offsetX) / effectiveWidth;
|
||||
const relativeY = (clampedY - offsetY) / effectiveHeight;
|
||||
|
||||
// Convert to HID absolute coordinate system (0-32767 range)
|
||||
const x = Math.round(relativeX * 32767);
|
||||
const y = Math.round(relativeY * 32767);
|
||||
|
||||
// Send mouse movement
|
||||
const { buttons } = e;
|
||||
sendAbsMouseMovement(x, y, buttons);
|
||||
}, [mouseMode, sendAbsMouseMovement],
|
||||
);
|
||||
|
||||
const getMouseWheelHandler = useCallback(
|
||||
() => (e: WheelEvent) => {
|
||||
if (scrollThrottling && blockWheelEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine if the wheel event is an accel scroll value
|
||||
const isAccel = Math.abs(e.deltaY) >= 100;
|
||||
|
||||
// Calculate the accel scroll value
|
||||
const accelScrollValue = e.deltaY / 100;
|
||||
|
||||
// Calculate the no accel scroll value
|
||||
const noAccelScrollValue = Math.sign(e.deltaY);
|
||||
|
||||
// Get scroll value
|
||||
const scrollValue = isAccel ? accelScrollValue : noAccelScrollValue;
|
||||
|
||||
// Apply clamping (i.e. min and max mouse wheel hardware value)
|
||||
const clampedScrollValue = Math.max(-127, Math.min(127, scrollValue));
|
||||
|
||||
// Invert the clamped scroll value to match expected behavior
|
||||
const invertedScrollValue = -clampedScrollValue;
|
||||
|
||||
send("wheelReport", { wheelY: invertedScrollValue });
|
||||
|
||||
// Apply blocking delay based of throttling settings
|
||||
if (scrollThrottling && !blockWheelEvent) {
|
||||
setBlockWheelEvent(true);
|
||||
setTimeout(() => setBlockWheelEvent(false), scrollThrottling);
|
||||
}
|
||||
},
|
||||
[send, blockWheelEvent, scrollThrottling],
|
||||
);
|
||||
|
||||
const resetMousePosition = useCallback(() => {
|
||||
sendAbsMouseMovement(0, 0, 0);
|
||||
}, [sendAbsMouseMovement]);
|
||||
|
||||
return {
|
||||
getRelMouseMoveHandler,
|
||||
getAbsMouseMoveHandler,
|
||||
getMouseWheelHandler,
|
||||
resetMousePosition,
|
||||
};
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ import {
|
|||
redirect,
|
||||
RouterProvider,
|
||||
useRouteError,
|
||||
} from "react-router";
|
||||
} from "react-router-dom";
|
||||
import { ExclamationTriangleIcon } from "@heroicons/react/16/solid";
|
||||
|
||||
import { CLOUD_API, DEVICE_API } from "@/ui.config";
|
||||
|
|
@ -28,7 +28,7 @@ import DeviceIdRename from "@routes/devices.$id.rename";
|
|||
import DevicesRoute from "@routes/devices";
|
||||
import SettingsIndexRoute from "@routes/devices.$id.settings._index";
|
||||
import SettingsAccessIndexRoute from "@routes/devices.$id.settings.access._index";
|
||||
import Notifications from "@/notifications";
|
||||
const Notifications = lazy(() => import("@/notifications"));
|
||||
const SignupRoute = lazy(() => import("@routes/signup"));
|
||||
const LoginRoute = lazy(() => import("@routes/login"));
|
||||
const DevicesAlreadyAdopted = lazy(() => import("@routes/devices.already-adopted"));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Outlet } from "react-router";
|
||||
import { Outlet } from "react-router-dom";
|
||||
|
||||
function Root() {
|
||||
return <Outlet />;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { redirect } from "react-router";
|
||||
import type { LoaderFunction, LoaderFunctionArgs } from "react-router";
|
||||
import { LoaderFunctionArgs, redirect } from "react-router-dom";
|
||||
|
||||
import { DEVICE_API } from "@/ui.config";
|
||||
import api from "@/api";
|
||||
|
||||
import api from "../api";
|
||||
|
||||
export interface CloudState {
|
||||
connected: boolean;
|
||||
|
|
@ -10,7 +10,7 @@ export interface CloudState {
|
|||
appUrl: string;
|
||||
}
|
||||
|
||||
const loader: LoaderFunction = async ({ request }: LoaderFunctionArgs) => {
|
||||
const loader = async ({ request }: LoaderFunctionArgs) => {
|
||||
const url = new URL(request.url);
|
||||
const searchParams = url.searchParams;
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ const loader: LoaderFunction = async ({ request }: LoaderFunctionArgs) => {
|
|||
};
|
||||
|
||||
export default function AdoptRoute() {
|
||||
return (<></>);
|
||||
return <></>;
|
||||
}
|
||||
|
||||
AdoptRoute.loader = loader;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import { Form, redirect, useActionData, useLoaderData } from "react-router";
|
||||
import type { ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs } from "react-router";
|
||||
import {
|
||||
ActionFunctionArgs,
|
||||
Form,
|
||||
LoaderFunctionArgs,
|
||||
redirect,
|
||||
useActionData,
|
||||
useLoaderData,
|
||||
} from "react-router-dom";
|
||||
import { ChevronLeftIcon } from "@heroicons/react/16/solid";
|
||||
|
||||
import { Button, LinkButton } from "@components/Button";
|
||||
|
|
@ -16,7 +22,7 @@ interface LoaderData {
|
|||
user: User;
|
||||
}
|
||||
|
||||
const action: ActionFunction = async ({ request }: ActionFunctionArgs) => {
|
||||
const action = async ({ request }: ActionFunctionArgs) => {
|
||||
const { deviceId } = Object.fromEntries(await request.formData());
|
||||
|
||||
try {
|
||||
|
|
@ -28,17 +34,17 @@ const action: ActionFunction = async ({ request }: ActionFunctionArgs) => {
|
|||
});
|
||||
|
||||
if (!res.ok) {
|
||||
return { message: "There was an error deregistering your device. Please try again." };
|
||||
return { message: "There was an error renaming your device. Please try again." };
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return { message: "There was an error deregistering your device. Please try again." };
|
||||
return { message: "There was an error renaming your device. Please try again." };
|
||||
}
|
||||
|
||||
return redirect("/devices");
|
||||
};
|
||||
|
||||
const loader: LoaderFunction = async ({ params }: LoaderFunctionArgs) => {
|
||||
const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
const user = await checkAuth();
|
||||
const { id } = params;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
} from "react-icons/lu";
|
||||
import { PlusCircleIcon, ExclamationTriangleIcon } from "@heroicons/react/20/solid";
|
||||
import { TrashIcon } from "@heroicons/react/16/solid";
|
||||
import { useNavigate } from "react-router";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import Card, { GridCard } from "@/components/Card";
|
||||
import { Button } from "@components/Button";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useNavigate, useOutletContext } from "react-router";
|
||||
import { useNavigate, useOutletContext } from "react-router-dom";
|
||||
|
||||
import { GridCard } from "@/components/Card";
|
||||
import { Button } from "@components/Button";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import { Form, redirect, useActionData, useLoaderData } from "react-router";
|
||||
import type { ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs } from "react-router";
|
||||
import {
|
||||
ActionFunctionArgs,
|
||||
Form,
|
||||
LoaderFunctionArgs,
|
||||
redirect,
|
||||
useActionData,
|
||||
useLoaderData,
|
||||
} from "react-router-dom";
|
||||
import { ChevronLeftIcon } from "@heroicons/react/16/solid";
|
||||
|
||||
import { Button, LinkButton } from "@components/Button";
|
||||
|
|
@ -19,7 +25,7 @@ interface LoaderData {
|
|||
user: User;
|
||||
}
|
||||
|
||||
const action: ActionFunction = async ({ params, request }: ActionFunctionArgs) => {
|
||||
const action = async ({ params, request }: ActionFunctionArgs) => {
|
||||
const { id } = params;
|
||||
const { name } = Object.fromEntries(await request.formData());
|
||||
|
||||
|
|
@ -42,7 +48,7 @@ const action: ActionFunction = async ({ params, request }: ActionFunctionArgs) =
|
|||
return redirect("/devices");
|
||||
};
|
||||
|
||||
const loader: LoaderFunction = async ({ params }: LoaderFunctionArgs) => {
|
||||
const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
const user = await checkAuth();
|
||||
const { id } = params;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { redirect } from "react-router";
|
||||
import type { LoaderFunction, LoaderFunctionArgs } from "react-router";
|
||||
import { LoaderFunctionArgs, redirect } from "react-router-dom";
|
||||
|
||||
import { getDeviceUiPath } from "../hooks/useAppNavigation";
|
||||
|
||||
const loader: LoaderFunction = ({ params }: LoaderFunctionArgs) => {
|
||||
const loader = ({ params }: LoaderFunctionArgs) => {
|
||||
return redirect(getDeviceUiPath("/settings/general", params.id));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { useLoaderData, useNavigate } from "react-router";
|
||||
import type { LoaderFunction } from "react-router";
|
||||
import { useLoaderData, useNavigate } from "react-router-dom";
|
||||
import { ShieldCheckIcon } from "@heroicons/react/24/outline";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
|
|
@ -27,7 +26,7 @@ export interface TLSState {
|
|||
privateKey?: string;
|
||||
}
|
||||
|
||||
const loader: LoaderFunction = async () => {
|
||||
const loader = async () => {
|
||||
if (isOnDevice) {
|
||||
const status = await api
|
||||
.GET(`${DEVICE_API}/device`)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useEffect } from "react";
|
||||
import { useLocation, useRevalidator } from "react-router";
|
||||
import { useLocation, useRevalidator } from "react-router-dom";
|
||||
|
||||
import { Button } from "@components/Button";
|
||||
import { InputFieldWithLabel } from "@/components/InputField";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useNavigate } from "react-router";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useCallback } from "react";
|
||||
|
||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useLocation, useNavigate } from "react-router";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { CheckCircleIcon } from "@heroicons/react/20/solid";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useNavigate } from "react-router";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useState } from "react";
|
||||
|
||||
import { KeySequence, useMacrosStore, generateMacroId } from "@/hooks/stores";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useNavigate, useParams } from "react-router";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useState, useEffect } from "react";
|
||||
import { LuTrash2 } from "react-icons/lu";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect, Fragment, useMemo, useState, useCallback } from "react";
|
||||
import { useNavigate } from "react-router";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import {
|
||||
LuPenLine,
|
||||
LuCopy,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { NavLink, Outlet, useLocation } from "react-router";
|
||||
import { NavLink, Outlet, useLocation } from "react-router-dom";
|
||||
import {
|
||||
LuSettings,
|
||||
LuMouse,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
import { Form, redirect, useActionData, useParams, useSearchParams } from "react-router";
|
||||
import type { ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs } from "react-router";
|
||||
import {
|
||||
ActionFunctionArgs,
|
||||
Form,
|
||||
LoaderFunctionArgs,
|
||||
redirect,
|
||||
useActionData,
|
||||
useParams,
|
||||
useSearchParams,
|
||||
} from "react-router-dom";
|
||||
|
||||
import SimpleNavbar from "@components/SimpleNavbar";
|
||||
import GridBackground from "@components/GridBackground";
|
||||
|
|
@ -13,7 +20,7 @@ import { CLOUD_API } from "@/ui.config";
|
|||
|
||||
import api from "../api";
|
||||
|
||||
const loader: LoaderFunction = async ({ params }: LoaderFunctionArgs) => {
|
||||
const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
await checkAuth();
|
||||
const res = await fetch(`${CLOUD_API}/devices/${params.id}`, {
|
||||
method: "GET",
|
||||
|
|
@ -28,7 +35,7 @@ const loader: LoaderFunction = async ({ params }: LoaderFunctionArgs) => {
|
|||
}
|
||||
};
|
||||
|
||||
const action: ActionFunction = async ({ request }: ActionFunctionArgs) => {
|
||||
const action = async ({ request }: ActionFunctionArgs) => {
|
||||
// Handle form submission
|
||||
const { name, id, returnTo } = Object.fromEntries(await request.formData());
|
||||
const res = await api.PUT(`${CLOUD_API}/devices/${id}`, { name });
|
||||
|
|
@ -36,7 +43,7 @@ const action: ActionFunction = async ({ request }: ActionFunctionArgs) => {
|
|||
if (res.ok) {
|
||||
return redirect(returnTo?.toString() ?? `/devices/${id}`);
|
||||
} else {
|
||||
return { error: "There was an error registering your device" };
|
||||
return { error: "There was an error creating your device" };
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { lazy, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
LoaderFunctionArgs,
|
||||
Outlet,
|
||||
Params,
|
||||
redirect,
|
||||
useLoaderData,
|
||||
useLocation,
|
||||
|
|
@ -8,8 +10,7 @@ import {
|
|||
useOutlet,
|
||||
useParams,
|
||||
useSearchParams,
|
||||
} from "react-router";
|
||||
import type { LoaderFunction, LoaderFunctionArgs, Params } from "react-router";
|
||||
} from "react-router-dom";
|
||||
import { useInterval } from "usehooks-ts";
|
||||
import { FocusTrap } from "focus-trap-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
|
@ -111,7 +112,7 @@ const cloudLoader = async (params: Params<string>): Promise<CloudLoaderResp> =>
|
|||
return { user, iceConfig, deviceName: device.name || device.id };
|
||||
};
|
||||
|
||||
const loader: LoaderFunction = ({ params }: LoaderFunctionArgs) => {
|
||||
const loader = ({ params }: LoaderFunctionArgs) => {
|
||||
return import.meta.env.MODE === "device" ? deviceLoader() : cloudLoader(params);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { useLoaderData, useRevalidator } from "react-router";
|
||||
import type { LoaderFunction } from "react-router";
|
||||
import { useLoaderData, useRevalidator } from "react-router-dom";
|
||||
import { LuMonitorSmartphone } from "react-icons/lu";
|
||||
import { ArrowRightIcon } from "@heroicons/react/16/solid";
|
||||
import { useInterval } from "usehooks-ts";
|
||||
|
|
@ -17,7 +16,7 @@ interface LoaderData {
|
|||
user: User;
|
||||
}
|
||||
|
||||
const loader: LoaderFunction = async () => {
|
||||
const loader = async () => {
|
||||
const user = await checkAuth();
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { Form, redirect, useActionData } from "react-router";
|
||||
import type { ActionFunction, ActionFunctionArgs, LoaderFunction } from "react-router";
|
||||
import { ActionFunctionArgs, Form, redirect, useActionData } from "react-router-dom";
|
||||
import { useState } from "react";
|
||||
import { LuEye, LuEyeOff } from "react-icons/lu";
|
||||
|
||||
|
|
@ -18,7 +17,7 @@ import ExtLink from "../components/ExtLink";
|
|||
|
||||
import { DeviceStatus } from "./welcome-local";
|
||||
|
||||
const loader: LoaderFunction = async () => {
|
||||
const loader = async () => {
|
||||
const res = await api
|
||||
.GET(`${DEVICE_API}/device/status`)
|
||||
.then(res => res.json() as Promise<DeviceStatus>);
|
||||
|
|
@ -30,7 +29,7 @@ const loader: LoaderFunction = async () => {
|
|||
return null;
|
||||
};
|
||||
|
||||
const action: ActionFunction = async ({ request }: ActionFunctionArgs) => {
|
||||
const action = async ({ request }: ActionFunctionArgs) => {
|
||||
const formData = await request.formData();
|
||||
const password = formData.get("password");
|
||||
|
||||
|
|
@ -87,7 +86,6 @@ export default function LoginLocalRoute() {
|
|||
label="Password"
|
||||
type={showPassword ? "text" : "password"}
|
||||
name="password"
|
||||
autoComplete="current-password"
|
||||
placeholder="Enter your password"
|
||||
autoFocus
|
||||
error={actionData?.error}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useLocation, useSearchParams } from "react-router";
|
||||
import { useLocation, useSearchParams } from "react-router-dom";
|
||||
|
||||
import AuthLayout from "@components/AuthLayout";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useLocation, useSearchParams } from "react-router";
|
||||
import { useLocation, useSearchParams } from "react-router-dom";
|
||||
|
||||
import AuthLayout from "@components/AuthLayout";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { Form, redirect, useActionData } from "react-router";
|
||||
import type { ActionFunction, ActionFunctionArgs, LoaderFunction } from "react-router";
|
||||
import { ActionFunctionArgs, Form, redirect, useActionData } from "react-router-dom";
|
||||
import { useState } from "react";
|
||||
|
||||
import GridBackground from "@components/GridBackground";
|
||||
|
|
@ -15,7 +14,7 @@ import api from "../api";
|
|||
|
||||
import { DeviceStatus } from "./welcome-local";
|
||||
|
||||
const loader: LoaderFunction = async () => {
|
||||
const loader = async () => {
|
||||
const res = await api
|
||||
.GET(`${DEVICE_API}/device/status`)
|
||||
.then(res => res.json() as Promise<DeviceStatus>);
|
||||
|
|
@ -24,7 +23,7 @@ const loader: LoaderFunction = async () => {
|
|||
return null;
|
||||
};
|
||||
|
||||
const action: ActionFunction = async ({ request }: ActionFunctionArgs) => {
|
||||
const action = async ({ request }: ActionFunctionArgs) => {
|
||||
const formData = await request.formData();
|
||||
const localAuthMode = formData.get("localAuthMode");
|
||||
if (!localAuthMode) return { error: "Please select an authentication mode" };
|
||||
|
|
@ -163,5 +162,5 @@ export default function WelcomeLocalModeRoute() {
|
|||
);
|
||||
}
|
||||
|
||||
WelcomeLocalModeRoute.loader = loader;
|
||||
WelcomeLocalModeRoute.action = action;
|
||||
WelcomeLocalModeRoute.loader = loader;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { Form, redirect, useActionData } from "react-router";
|
||||
import type { ActionFunction, ActionFunctionArgs, LoaderFunction } from "react-router";
|
||||
import { ActionFunctionArgs, Form, redirect, useActionData } from "react-router-dom";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { LuEye, LuEyeOff } from "react-icons/lu";
|
||||
|
||||
|
|
@ -16,7 +15,7 @@ import api from "../api";
|
|||
|
||||
import { DeviceStatus } from "./welcome-local";
|
||||
|
||||
const loader: LoaderFunction = async () => {
|
||||
const loader = async () => {
|
||||
const res = await api
|
||||
.GET(`${DEVICE_API}/device/status`)
|
||||
.then(res => res.json() as Promise<DeviceStatus>);
|
||||
|
|
@ -25,7 +24,7 @@ const loader: LoaderFunction = async () => {
|
|||
return null;
|
||||
};
|
||||
|
||||
const action: ActionFunction = async ({ request }: ActionFunctionArgs) => {
|
||||
const action = async ({ request }: ActionFunctionArgs) => {
|
||||
const formData = await request.formData();
|
||||
const password = formData.get("password");
|
||||
const confirmPassword = formData.get("confirmPassword");
|
||||
|
|
@ -175,5 +174,5 @@ export default function WelcomeLocalPasswordRoute() {
|
|||
);
|
||||
}
|
||||
|
||||
WelcomeLocalPasswordRoute.loader = loader;
|
||||
WelcomeLocalPasswordRoute.action = action;
|
||||
WelcomeLocalPasswordRoute.loader = loader;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { cx } from "cva";
|
||||
import { redirect } from "react-router";
|
||||
import type { LoaderFunction } from "react-router";
|
||||
import { redirect } from "react-router-dom";
|
||||
|
||||
import GridBackground from "@components/GridBackground";
|
||||
import Container from "@components/Container";
|
||||
|
|
@ -18,7 +17,7 @@ export interface DeviceStatus {
|
|||
isSetup: boolean;
|
||||
}
|
||||
|
||||
const loader: LoaderFunction = async () => {
|
||||
const loader = async () => {
|
||||
const res = await api
|
||||
.GET(`${DEVICE_API}/device/status`)
|
||||
.then(res => res.json() as Promise<DeviceStatus>);
|
||||
|
|
|
|||
|
|
@ -158,11 +158,7 @@ func newSession(config SessionConfig) (*Session, error) {
|
|||
case "hidrpc":
|
||||
session.HidChannel = d
|
||||
d.OnMessage(func(msg webrtc.DataChannelMessage) {
|
||||
l := scopedLogger.With().Int("length", len(msg.Data)).Logger()
|
||||
// only log data if the log level is debug or lower
|
||||
if scopedLogger.GetLevel() > zerolog.DebugLevel {
|
||||
l = l.With().Str("data", string(msg.Data)).Logger()
|
||||
}
|
||||
l := scopedLogger.With().Str("data", string(msg.Data)).Int("length", len(msg.Data)).Logger()
|
||||
|
||||
if msg.IsString {
|
||||
l.Warn().Msg("received string data in HID RPC message handler")
|
||||
|
|
|
|||
Loading…
Reference in New Issue