mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
Merge pull request #73 from autobrr/feature/irc-show-more-info
Feature: Show IRC network status in settings list
This commit is contained in:
commit
3475dddec7
9 changed files with 348 additions and 117 deletions
2
go.mod
2
go.mod
|
@ -20,11 +20,9 @@ require (
|
||||||
github.com/spf13/viper v1.9.0
|
github.com/spf13/viper v1.9.0
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
|
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
|
||||||
golang.org/x/mod v0.5.1 // indirect
|
|
||||||
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9
|
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
||||||
golang.org/x/tools v0.1.8 // indirect
|
golang.org/x/tools v0.1.8 // indirect
|
||||||
gopkg.in/ini.v1 v1.64.0 // indirect
|
gopkg.in/ini.v1 v1.64.0 // indirect
|
||||||
|
|
15
go.sum
15
go.sum
|
@ -1162,8 +1162,6 @@ golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211023085530-d6a326fbbf70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211023085530-d6a326fbbf70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc=
|
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
|
@ -1254,7 +1252,6 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
|
|
||||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||||
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
|
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
|
||||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
|
@ -1468,7 +1465,6 @@ modernc.org/cc/v3 v3.35.10/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g
|
||||||
modernc.org/cc/v3 v3.35.15/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
modernc.org/cc/v3 v3.35.15/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||||
modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||||
modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||||
modernc.org/cc/v3 v3.35.18 h1:rMZhRcWrba0y3nVmdiQ7kxAgOOSq2m2f2VzjHLgEs6U=
|
|
||||||
modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||||
modernc.org/cc/v3 v3.35.20/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
modernc.org/cc/v3 v3.35.20/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||||
modernc.org/cc/v3 v3.35.22 h1:BzShpwCAP7TWzFppM4k2t03RhXhgYqaibROWkrWq7lE=
|
modernc.org/cc/v3 v3.35.22 h1:BzShpwCAP7TWzFppM4k2t03RhXhgYqaibROWkrWq7lE=
|
||||||
|
@ -1502,10 +1498,8 @@ modernc.org/ccgo/v3 v3.12.55/go.mod h1:rsXiIyJi9psOwiBkplOaHye5L4MOOaCjHg1Fxkj7I
|
||||||
modernc.org/ccgo/v3 v3.12.56/go.mod h1:ljeFks3faDseCkr60JMpeDb2GSO3TKAmrzm7q9YOcMU=
|
modernc.org/ccgo/v3 v3.12.56/go.mod h1:ljeFks3faDseCkr60JMpeDb2GSO3TKAmrzm7q9YOcMU=
|
||||||
modernc.org/ccgo/v3 v3.12.57/go.mod h1:hNSF4DNVgBl8wYHpMvPqQWDQx8luqxDnNGCMM4NFNMc=
|
modernc.org/ccgo/v3 v3.12.57/go.mod h1:hNSF4DNVgBl8wYHpMvPqQWDQx8luqxDnNGCMM4NFNMc=
|
||||||
modernc.org/ccgo/v3 v3.12.60/go.mod h1:k/Nn0zdO1xHVWjPYVshDeWKqbRWIfif5dtsIOCUVMqM=
|
modernc.org/ccgo/v3 v3.12.60/go.mod h1:k/Nn0zdO1xHVWjPYVshDeWKqbRWIfif5dtsIOCUVMqM=
|
||||||
modernc.org/ccgo/v3 v3.12.65/go.mod h1:D6hQtKxPNZiY6wDBtehSGKFKmyXn53F8nGTpH+POmS4=
|
|
||||||
modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/EhQ=
|
modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/EhQ=
|
||||||
modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84=
|
modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84=
|
||||||
modernc.org/ccgo/v3 v3.12.73 h1:AMk4wEpzWjpODXohKvvnlwLob4Xk8tq3we6CwYh88mA=
|
|
||||||
modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ=
|
modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ=
|
||||||
modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
|
modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
|
||||||
modernc.org/ccgo/v3 v3.12.84/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
|
modernc.org/ccgo/v3 v3.12.84/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
|
||||||
|
@ -1517,6 +1511,7 @@ modernc.org/ccgo/v3 v3.12.95/go.mod h1:ZcLyvtocXYi8uF+9Ebm3G8EF8HNY5hGomBqthDp4e
|
||||||
modernc.org/ccgo/v3 v3.13.1/go.mod h1:aBYVOUfIlcSnrsRVU8VRS35y2DIfpgkmVkYZ0tpIXi4=
|
modernc.org/ccgo/v3 v3.13.1/go.mod h1:aBYVOUfIlcSnrsRVU8VRS35y2DIfpgkmVkYZ0tpIXi4=
|
||||||
modernc.org/ccgo/v3 v3.14.0 h1:Zr1Ny9+7r5yAiXpBdgp8XiXqkNA4ARrRphHGHVXeAp0=
|
modernc.org/ccgo/v3 v3.14.0 h1:Zr1Ny9+7r5yAiXpBdgp8XiXqkNA4ARrRphHGHVXeAp0=
|
||||||
modernc.org/ccgo/v3 v3.14.0/go.mod h1:hBrkiBlUwvr5vV/ZH9YzXIp982jKE8Ek8tR1ytoAL6Q=
|
modernc.org/ccgo/v3 v3.14.0/go.mod h1:hBrkiBlUwvr5vV/ZH9YzXIp982jKE8Ek8tR1ytoAL6Q=
|
||||||
|
modernc.org/ccorpus v1.11.1 h1:K0qPfpVG1MJh5BYazccnmhywH4zHuOgJXgbjzyp6dWA=
|
||||||
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||||
|
@ -1549,10 +1544,8 @@ modernc.org/libc v1.11.54/go.mod h1:S/FVnskbzVUrjfBqlGFIPA5m7UwB3n9fojHhCNfSsnw=
|
||||||
modernc.org/libc v1.11.55/go.mod h1:j2A5YBRm6HjNkoSs/fzZrSxCuwWqcMYTDPLNx0URn3M=
|
modernc.org/libc v1.11.55/go.mod h1:j2A5YBRm6HjNkoSs/fzZrSxCuwWqcMYTDPLNx0URn3M=
|
||||||
modernc.org/libc v1.11.56/go.mod h1:pakHkg5JdMLt2OgRadpPOTnyRXm/uzu+Yyg/LSLdi18=
|
modernc.org/libc v1.11.56/go.mod h1:pakHkg5JdMLt2OgRadpPOTnyRXm/uzu+Yyg/LSLdi18=
|
||||||
modernc.org/libc v1.11.58/go.mod h1:ns94Rxv0OWyoQrDqMFfWwka2BcaF6/61CqJRK9LP7S8=
|
modernc.org/libc v1.11.58/go.mod h1:ns94Rxv0OWyoQrDqMFfWwka2BcaF6/61CqJRK9LP7S8=
|
||||||
modernc.org/libc v1.11.70/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw=
|
|
||||||
modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw=
|
modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw=
|
||||||
modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0=
|
modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0=
|
||||||
modernc.org/libc v1.11.82 h1:CSl/6n4odvPYWKKqBtFb8e0ZWVTjxDqwxTjaoee9V7E=
|
|
||||||
modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI=
|
modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI=
|
||||||
modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE=
|
modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE=
|
||||||
modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY=
|
modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY=
|
||||||
|
@ -1576,20 +1569,14 @@ modernc.org/memory v1.0.5 h1:XRch8trV7GgvTec2i7jc33YlUI0RKVDBvZ5eZ5m8y14=
|
||||||
modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
|
modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
|
||||||
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
|
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
|
||||||
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
modernc.org/sqlite v1.14.1 h1:jthfQCbWKfbK/lvZSjFEpBk0QzIBN6pQbFdDqBMR490=
|
|
||||||
modernc.org/sqlite v1.14.1/go.mod h1:04Lqa+3PuAEUhAPAPWeDMljT4UYA31nb2DHTFG47L1g=
|
|
||||||
modernc.org/sqlite v1.14.3 h1:psrTwgpEujgWEP3FNdsC9yNh5tSeA77U0GeWhHH4XmQ=
|
modernc.org/sqlite v1.14.3 h1:psrTwgpEujgWEP3FNdsC9yNh5tSeA77U0GeWhHH4XmQ=
|
||||||
modernc.org/sqlite v1.14.3/go.mod h1:xMpicS1i2MJ4C8+Ap0vYBqTwYfpFvdnPE6brbFOtV2Y=
|
modernc.org/sqlite v1.14.3/go.mod h1:xMpicS1i2MJ4C8+Ap0vYBqTwYfpFvdnPE6brbFOtV2Y=
|
||||||
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
|
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
|
||||||
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
|
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
|
||||||
modernc.org/tcl v1.8.13 h1:V0sTNBw0Re86PvXZxuCub3oO9WrSTqALgrwNZNvLFGw=
|
|
||||||
modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY=
|
|
||||||
modernc.org/tcl v1.9.2 h1:YA87dFLOsR2KqMka371a2Xgr+YsyUwo7OmHVSv/kztw=
|
modernc.org/tcl v1.9.2 h1:YA87dFLOsR2KqMka371a2Xgr+YsyUwo7OmHVSv/kztw=
|
||||||
modernc.org/tcl v1.9.2/go.mod h1:aw7OnlIoiuJgu1gwbTZtrKnGpDqH9wyH++jZcxdqNsg=
|
modernc.org/tcl v1.9.2/go.mod h1:aw7OnlIoiuJgu1gwbTZtrKnGpDqH9wyH++jZcxdqNsg=
|
||||||
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
|
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
|
||||||
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
modernc.org/z v1.2.19 h1:BGyRFWhDVn5LFS5OcX4Yd/MlpRTOc7hOPTdcIpCiUao=
|
|
||||||
modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY=
|
|
||||||
modernc.org/z v1.2.20 h1:DyboxM1sJR2NB803j2StnbnL6jcQXz273OhHDGu8dGk=
|
modernc.org/z v1.2.20 h1:DyboxM1sJR2NB803j2StnbnL6jcQXz273OhHDGu8dGk=
|
||||||
modernc.org/z v1.2.20/go.mod h1:zU9FiF4PbHdOTUxw+IF8j7ArBMRPsHgq10uVPt6xTzo=
|
modernc.org/z v1.2.20/go.mod h1:zU9FiF4PbHdOTUxw+IF8j7ArBMRPsHgq10uVPt6xTzo=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
|
|
@ -72,6 +72,24 @@ type IndexerIRC struct {
|
||||||
Settings []IndexerSetting `json:"settings"`
|
Settings []IndexerSetting `json:"settings"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i IndexerIRC) ValidAnnouncer(announcer string) bool {
|
||||||
|
for _, a := range i.Announcers {
|
||||||
|
if a == announcer {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IndexerIRC) ValidChannel(channel string) bool {
|
||||||
|
for _, a := range i.Channels {
|
||||||
|
if a == channel {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type IndexerParse struct {
|
type IndexerParse struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Lines []IndexerParseExtract `json:"lines"`
|
Lines []IndexerParseExtract `json:"lines"`
|
||||||
|
|
|
@ -34,6 +34,44 @@ type IrcNetwork struct {
|
||||||
ConnectedSince *time.Time `json:"connected_since"`
|
ConnectedSince *time.Time `json:"connected_since"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IrcNetworkWithHealth struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Server string `json:"server"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
TLS bool `json:"tls"`
|
||||||
|
Pass string `json:"pass"`
|
||||||
|
InviteCommand string `json:"invite_command"`
|
||||||
|
NickServ NickServ `json:"nickserv,omitempty"`
|
||||||
|
//Channels []IrcChannel `json:"channels"`
|
||||||
|
Channels []ChannelWithHealth `json:"channels"`
|
||||||
|
//Channels []struct {
|
||||||
|
// IrcChannel
|
||||||
|
// ChannelHealth
|
||||||
|
//} `json:"channels"`
|
||||||
|
Connected bool `json:"connected"`
|
||||||
|
ConnectedSince time.Time `json:"connected_since"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChannelWithHealth struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Detached bool `json:"detached"`
|
||||||
|
Monitoring bool `json:"monitoring"`
|
||||||
|
MonitoringSince time.Time `json:"monitoring_since"`
|
||||||
|
LastAnnounce time.Time `json:"last_announce"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChannelHealth struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Monitoring bool `json:"monitoring"`
|
||||||
|
MonitoringSince time.Time `json:"monitoring_since"`
|
||||||
|
LastAnnounce time.Time `json:"last_announce"`
|
||||||
|
}
|
||||||
|
|
||||||
type IrcRepo interface {
|
type IrcRepo interface {
|
||||||
StoreNetwork(network *IrcNetwork) error
|
StoreNetwork(network *IrcNetwork) error
|
||||||
UpdateNetwork(ctx context.Context, network *IrcNetwork) error
|
UpdateNetwork(ctx context.Context, network *IrcNetwork) error
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
type ircService interface {
|
type ircService interface {
|
||||||
ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
||||||
|
GetNetworksWithHealth(ctx context.Context) ([]domain.IrcNetworkWithHealth, error)
|
||||||
DeleteNetwork(ctx context.Context, id int64) error
|
DeleteNetwork(ctx context.Context, id int64) error
|
||||||
GetNetworkByID(id int64) (*domain.IrcNetwork, error)
|
GetNetworkByID(id int64) (*domain.IrcNetwork, error)
|
||||||
StoreNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
StoreNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
||||||
|
@ -46,7 +47,7 @@ func (h ircHandler) Routes(r chi.Router) {
|
||||||
func (h ircHandler) listNetworks(w http.ResponseWriter, r *http.Request) {
|
func (h ircHandler) listNetworks(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|
||||||
networks, err := h.service.ListNetworks(ctx)
|
networks, err := h.service.GetNetworksWithHealth(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,20 @@ type channelHealth struct {
|
||||||
name string
|
name string
|
||||||
monitoring bool
|
monitoring bool
|
||||||
monitoringSince time.Time
|
monitoringSince time.Time
|
||||||
lastPing time.Time
|
|
||||||
lastAnnounce time.Time
|
lastAnnounce time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLastAnnounce set last announce to now
|
||||||
|
func (h *channelHealth) SetLastAnnounce() {
|
||||||
|
h.lastAnnounce = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMonitoring set monitoring and time
|
||||||
|
func (h *channelHealth) SetMonitoring() {
|
||||||
|
h.monitoring = true
|
||||||
|
h.monitoringSince = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
network *domain.IrcNetwork
|
network *domain.IrcNetwork
|
||||||
filterService filter.Service
|
filterService filter.Service
|
||||||
|
@ -45,10 +55,13 @@ type Handler struct {
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
|
|
||||||
lastPing time.Time
|
lastPing time.Time
|
||||||
lastAnnounce time.Time
|
connected bool
|
||||||
|
connectedSince time.Time
|
||||||
|
// tODO disconnectedTime
|
||||||
|
|
||||||
validAnnouncers map[string]struct{}
|
validAnnouncers map[string]struct{}
|
||||||
channels map[string]channelHealth
|
validChannels map[string]struct{}
|
||||||
|
channelHealth map[string]*channelHealth
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(network domain.IrcNetwork, filterService filter.Service, releaseService release.Service, definitions []domain.IndexerDefinition) *Handler {
|
func NewHandler(network domain.IrcNetwork, filterService filter.Service, releaseService release.Service, definitions []domain.IndexerDefinition) *Handler {
|
||||||
|
@ -63,6 +76,8 @@ func NewHandler(network domain.IrcNetwork, filterService filter.Service, release
|
||||||
definitions: definitions,
|
definitions: definitions,
|
||||||
announceProcessors: map[string]announce.Processor{},
|
announceProcessors: map[string]announce.Processor{},
|
||||||
validAnnouncers: map[string]struct{}{},
|
validAnnouncers: map[string]struct{}{},
|
||||||
|
validChannels: map[string]struct{}{},
|
||||||
|
channelHealth: map[string]*channelHealth{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Networks can be shared by multiple indexers but channels are unique
|
// Networks can be shared by multiple indexers but channels are unique
|
||||||
|
@ -73,12 +88,22 @@ func NewHandler(network domain.IrcNetwork, filterService filter.Service, release
|
||||||
channel = strings.ToLower(channel)
|
channel = strings.ToLower(channel)
|
||||||
|
|
||||||
h.announceProcessors[channel] = announce.NewAnnounceProcessor(definition, filterService, releaseService)
|
h.announceProcessors[channel] = announce.NewAnnounceProcessor(definition, filterService, releaseService)
|
||||||
|
|
||||||
|
h.channelHealth[channel] = &channelHealth{
|
||||||
|
name: channel,
|
||||||
|
monitoring: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create map of valid announcers
|
// create map of valid announcers
|
||||||
for _, announcer := range definition.IRC.Announcers {
|
for _, announcer := range definition.IRC.Announcers {
|
||||||
h.validAnnouncers[announcer] = struct{}{}
|
h.validAnnouncers[announcer] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create map of valid channels
|
||||||
|
for _, ch := range definition.IRC.Channels {
|
||||||
|
h.validChannels[ch] = struct{}{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return h
|
return h
|
||||||
|
@ -216,10 +241,19 @@ func (s *Handler) Run() error {
|
||||||
|
|
||||||
s.client = client
|
s.client = client
|
||||||
|
|
||||||
|
// set connected since now
|
||||||
|
s.connectedSince = time.Now()
|
||||||
|
s.connected = true
|
||||||
|
|
||||||
// Connect
|
// Connect
|
||||||
err = client.RunContext(ctx)
|
err = client.RunContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("could not connect to %v", addr)
|
log.Error().Err(err).Msgf("could not connect to %v", addr)
|
||||||
|
|
||||||
|
// set connected false if we loose connection or stop
|
||||||
|
s.connectedSince = time.Time{}
|
||||||
|
s.connected = false
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +313,7 @@ func (s *Handler) onConnect(channels []domain.IrcChannel) error {
|
||||||
if s.network.NickServ.Password != "" {
|
if s.network.NickServ.Password != "" {
|
||||||
err := s.handleNickServPRIVMSG(s.network.NickServ.Account, s.network.NickServ.Password)
|
err := s.handleNickServPRIVMSG(s.network.NickServ.Account, s.network.NickServ.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("error nickserv: %v", s.network.Name)
|
log.Error().Stack().Err(err).Msgf("error nickserv: %v", s.network.Name)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
identified = true
|
identified = true
|
||||||
|
@ -291,7 +325,7 @@ func (s *Handler) onConnect(channels []domain.IrcChannel) error {
|
||||||
|
|
||||||
err := s.handleInvitePRIVMSG(s.network.InviteCommand)
|
err := s.handleInvitePRIVMSG(s.network.InviteCommand)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("error sending connect command %v to network: %v", s.network.InviteCommand, s.network.Name)
|
log.Error().Stack().Err(err).Msgf("error sending connect command %v to network: %v", s.network.InviteCommand, s.network.Name)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +336,7 @@ func (s *Handler) onConnect(channels []domain.IrcChannel) error {
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
err := s.HandleJoinChannel(channel.Name, channel.Password)
|
err := s.HandleJoinChannel(channel.Name, channel.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err)
|
log.Error().Stack().Err(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,6 +356,12 @@ func (s *Handler) onMessage(msg *irc.Message) error {
|
||||||
message := msg.Trailing()
|
message := msg.Trailing()
|
||||||
// TODO add network
|
// TODO add network
|
||||||
|
|
||||||
|
// check if message is from a valid channel, if not return
|
||||||
|
validChannel := s.isValidChannel(*channel)
|
||||||
|
if !validChannel {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// check if message is from announce bot, if not return
|
// check if message is from announce bot, if not return
|
||||||
validAnnouncer := s.isValidAnnouncer(*announcer)
|
validAnnouncer := s.isValidAnnouncer(*announcer)
|
||||||
if !validAnnouncer {
|
if !validAnnouncer {
|
||||||
|
@ -332,8 +372,6 @@ func (s *Handler) onMessage(msg *irc.Message) error {
|
||||||
cleanedMsg := cleanMessage(message)
|
cleanedMsg := cleanMessage(message)
|
||||||
log.Debug().Msgf("%v: %v %v: %v", s.network.Server, *channel, *announcer, cleanedMsg)
|
log.Debug().Msgf("%v: %v %v: %v", s.network.Server, *channel, *announcer, cleanedMsg)
|
||||||
|
|
||||||
s.setLastAnnounce()
|
|
||||||
|
|
||||||
if err := s.sendToAnnounceProcessor(*channel, cleanedMsg); err != nil {
|
if err := s.sendToAnnounceProcessor(*channel, cleanedMsg); err != nil {
|
||||||
log.Error().Stack().Err(err).Msgf("could not queue line: %v", cleanedMsg)
|
log.Error().Stack().Err(err).Msgf("could not queue line: %v", cleanedMsg)
|
||||||
return err
|
return err
|
||||||
|
@ -358,6 +396,13 @@ func (s *Handler) sendToAnnounceProcessor(channel string, msg string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v, ok := s.channelHealth[channel]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v.SetLastAnnounce()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,11 +437,15 @@ func (s *Handler) HandleJoinChannel(channel string, password string) error {
|
||||||
|
|
||||||
err := s.client.Write(m.String())
|
err := s.client.Write(m.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("error handling join: %v", m.String())
|
log.Error().Stack().Err(err).Msgf("error handling join: %v", m.String())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
//log.Info().Msgf("Monitoring channel %v %s", s.network.Name, channel)
|
// only set values if channel is found in map
|
||||||
|
v, ok := s.channelHealth[channel]
|
||||||
|
if ok {
|
||||||
|
v.SetMonitoring()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -561,6 +610,7 @@ func (s *Handler) handlePing(msg *irc.Message) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if announcer is one from the list in the definition
|
||||||
func (s *Handler) isValidAnnouncer(nick string) bool {
|
func (s *Handler) isValidAnnouncer(nick string) bool {
|
||||||
_, ok := s.validAnnouncers[nick]
|
_, ok := s.validAnnouncers[nick]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -570,12 +620,14 @@ func (s *Handler) isValidAnnouncer(nick string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Handler) setLastAnnounce() {
|
// check if channel is one from the list in the definition
|
||||||
s.lastAnnounce = time.Now()
|
func (s *Handler) isValidChannel(channel string) bool {
|
||||||
}
|
_, ok := s.validChannels[channel]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Handler) GetLastAnnounce() time.Time {
|
return true
|
||||||
return s.lastAnnounce
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Handler) setLastPing() {
|
func (s *Handler) setLastPing() {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package irc
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/autobrr/autobrr/internal/domain"
|
"github.com/autobrr/autobrr/internal/domain"
|
||||||
|
@ -18,6 +19,7 @@ type Service interface {
|
||||||
StopHandlers()
|
StopHandlers()
|
||||||
StopNetwork(name string) error
|
StopNetwork(name string) error
|
||||||
ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
||||||
|
GetNetworksWithHealth(ctx context.Context) ([]domain.IrcNetworkWithHealth, error)
|
||||||
GetNetworkByID(id int64) (*domain.IrcNetwork, error)
|
GetNetworkByID(id int64) (*domain.IrcNetwork, error)
|
||||||
DeleteNetwork(ctx context.Context, id int64) error
|
DeleteNetwork(ctx context.Context, id int64) error
|
||||||
StoreNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
StoreNetwork(ctx context.Context, network *domain.IrcNetwork) error
|
||||||
|
@ -349,12 +351,86 @@ func (s *service) ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error)
|
||||||
}
|
}
|
||||||
n.Channels = append(n.Channels, channels...)
|
n.Channels = append(n.Channels, channels...)
|
||||||
|
|
||||||
|
// TODO get handler channelHealth
|
||||||
|
|
||||||
ret = append(ret, n)
|
ret = append(ret, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *service) GetNetworksWithHealth(ctx context.Context) ([]domain.IrcNetworkWithHealth, error) {
|
||||||
|
networks, err := s.repo.ListNetworks(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("failed to list networks: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret []domain.IrcNetworkWithHealth
|
||||||
|
|
||||||
|
for _, n := range networks {
|
||||||
|
netw := domain.IrcNetworkWithHealth{
|
||||||
|
ID: n.ID,
|
||||||
|
Name: n.Name,
|
||||||
|
Enabled: n.Enabled,
|
||||||
|
Server: n.Server,
|
||||||
|
Port: n.Port,
|
||||||
|
TLS: n.TLS,
|
||||||
|
Pass: n.Pass,
|
||||||
|
InviteCommand: n.InviteCommand,
|
||||||
|
NickServ: n.NickServ,
|
||||||
|
Connected: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
handler, ok := s.handlers[n.Server]
|
||||||
|
if ok {
|
||||||
|
// only set connected and connected since if we have an active handler and connection
|
||||||
|
if handler.conn != nil {
|
||||||
|
netw.Connected = handler.connected
|
||||||
|
netw.ConnectedSince = handler.connectedSince
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
channels, err := s.repo.ListChannels(n.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Msgf("failed to list channels for network %q: %v", n.Server, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// combine from repo and handler
|
||||||
|
for _, channel := range channels {
|
||||||
|
ch := domain.ChannelWithHealth{
|
||||||
|
ID: channel.ID,
|
||||||
|
Enabled: channel.Enabled,
|
||||||
|
Name: channel.Name,
|
||||||
|
Password: channel.Password,
|
||||||
|
Detached: channel.Detached,
|
||||||
|
//Monitoring: false,
|
||||||
|
//MonitoringSince: time.Time{},
|
||||||
|
//LastAnnounce: time.Time{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// only check if we have a handler
|
||||||
|
if handler != nil {
|
||||||
|
name := strings.ToLower(channel.Name)
|
||||||
|
|
||||||
|
chan1, ok := handler.channelHealth[name]
|
||||||
|
if ok {
|
||||||
|
ch.Monitoring = chan1.monitoring
|
||||||
|
ch.MonitoringSince = chan1.monitoringSince
|
||||||
|
ch.LastAnnounce = chan1.lastAnnounce
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
netw.Channels = append(netw.Channels, ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = append(ret, netw)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *service) DeleteNetwork(ctx context.Context, id int64) error {
|
func (s *service) DeleteNetwork(ctx context.Context, id int64) error {
|
||||||
network, err := s.GetNetworkByID(id)
|
network, err := s.GetNetworkByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -140,7 +140,7 @@ export function ReleaseStatusCell({ value, column, row }: ReleaseStatusCellProps
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="flex text-sm font-medium text-gray-900 dark:text-gray-300">
|
<div className="flex text-sm font-medium text-gray-900 dark:text-gray-300">
|
||||||
{value.map(v => <div title={`action: ${v.action}, type: ${v.type}, status: ${v.status}, ;time: ${v.timestamp}`}>{statusMap[v.status]}</div>)}
|
{value.map((v, idx) => <div key={idx} title={`action: ${v.action}, type: ${v.type}, status: ${v.status}, ;time: ${v.timestamp}`}>{statusMap[v.status]}</div>)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,56 @@ import { useEffect } from "react";
|
||||||
import { IrcNetworkAddForm, IrcNetworkUpdateForm } from "../../forms";
|
import { IrcNetworkAddForm, IrcNetworkUpdateForm } from "../../forms";
|
||||||
import { useToggle } from "../../hooks/hooks";
|
import { useToggle } from "../../hooks/hooks";
|
||||||
import { useQuery } from "react-query";
|
import { useQuery } from "react-query";
|
||||||
import { Switch } from "@headlessui/react";
|
|
||||||
import { classNames } from "../../utils";
|
|
||||||
import { EmptySimple } from "../../components/emptystates";
|
import { EmptySimple } from "../../components/emptystates";
|
||||||
import APIClient from "../../api/APIClient";
|
import APIClient from "../../api/APIClient";
|
||||||
|
import { formatDistanceToNowStrict, formatISO9075 } from "date-fns";
|
||||||
|
|
||||||
interface IrcNetwork {
|
interface IrcNetwork {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
addr: string;
|
addr: string;
|
||||||
|
server: string;
|
||||||
|
port: string;
|
||||||
nick: string;
|
nick: string;
|
||||||
username: string;
|
username: string;
|
||||||
realname: string;
|
realname: string;
|
||||||
pass: string;
|
pass: string;
|
||||||
// connect_commands: string;
|
connected: boolean;
|
||||||
|
connected_since: string;
|
||||||
|
tls: boolean;
|
||||||
|
nickserv: {
|
||||||
|
account: string;
|
||||||
|
}
|
||||||
|
channels: Channel[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Channel {
|
||||||
|
id: number;
|
||||||
|
enabled: boolean;
|
||||||
|
name: string;
|
||||||
|
password: string;
|
||||||
|
detached: boolean;
|
||||||
|
monitoring: boolean;
|
||||||
|
monitoring_since: string;
|
||||||
|
last_announce: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function IsEmptyDate(date: string) {
|
||||||
|
if (date !== "0001-01-01T00:00:00Z") {
|
||||||
|
return formatDistanceToNowStrict(
|
||||||
|
new Date(date),
|
||||||
|
{ addSuffix: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return "n/a"
|
||||||
|
}
|
||||||
|
|
||||||
|
function simplifyDate(date: string) {
|
||||||
|
if (date !== "0001-01-01T00:00:00Z") {
|
||||||
|
return formatISO9075(new Date(date))
|
||||||
|
}
|
||||||
|
return "n/a"
|
||||||
}
|
}
|
||||||
|
|
||||||
function IrcSettings() {
|
function IrcSettings() {
|
||||||
|
@ -25,7 +60,7 @@ function IrcSettings() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { data } = useQuery<any[], Error>('networks', APIClient.irc.getNetworks,
|
const { data } = useQuery<IrcNetwork[], Error>('networks', APIClient.irc.getNetworks,
|
||||||
{
|
{
|
||||||
refetchOnWindowFocus: false
|
refetchOnWindowFocus: false
|
||||||
}
|
}
|
||||||
|
@ -40,7 +75,7 @@ function IrcSettings() {
|
||||||
<div className="ml-4 mt-4">
|
<div className="ml-4 mt-4">
|
||||||
<h3 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">IRC</h3>
|
<h3 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">IRC</h3>
|
||||||
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
IRC networks and channels.
|
IRC networks and channels. Click on a network to view channel status.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-4 mt-4 flex-shrink-0">
|
<div className="ml-4 mt-4 flex-shrink-0">
|
||||||
|
@ -54,68 +89,43 @@ function IrcSettings() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col mt-6">
|
|
||||||
{data && data.length > 0 ?
|
{data && data.length > 0 ?
|
||||||
<div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
<section className="mt-6 light:bg-white dark:bg-gray-800 light:shadow sm:rounded-md">
|
||||||
<div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
|
<ol className="min-w-full">
|
||||||
<div className="light:shadow overflow-hidden light:border-b light:border-gray-200 sm:rounded-lg">
|
<li className="grid grid-cols-12 gap-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
{/* <div className="col-span-1 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Enabled</div> */}
|
||||||
<thead className="light:bg-gray-50">
|
<div className="col-span-3 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Network</div>
|
||||||
<tr>
|
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Server</div>
|
||||||
<th
|
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Nick</div>
|
||||||
scope="col"
|
</li>
|
||||||
className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider"
|
|
||||||
>
|
|
||||||
Enabled
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
scope="col"
|
|
||||||
className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider"
|
|
||||||
>
|
|
||||||
Network
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
scope="col"
|
|
||||||
className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider"
|
|
||||||
>
|
|
||||||
Server
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
scope="col"
|
|
||||||
className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider"
|
|
||||||
>
|
|
||||||
Nick
|
|
||||||
</th>
|
|
||||||
<th scope="col" className="relative px-6 py-3">
|
|
||||||
<span className="sr-only">Edit</span>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody className="light:bg-white divide-y divide-gray-200 dark:divide-gray-700">
|
|
||||||
{data && data.map((network: IrcNetwork, idx) => (
|
{data && data.map((network: IrcNetwork, idx) => (
|
||||||
<ListItem key={idx} idx={idx} network={network} />
|
<LiItem key={idx} idx={idx} network={network} />
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</ol>
|
||||||
</table>
|
</section>
|
||||||
</div>
|
: <EmptySimple title="No networks" subtitle="Add a new network" buttonText="New network" buttonAction={toggleAddNetwork} />}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
: <EmptySimple title="No networks" subtitle="Add a new network" buttonText="New network" buttonAction={toggleAddNetwork} />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListItem = ({ idx, network }: any) => {
|
interface LiItemProps {
|
||||||
|
idx: number;
|
||||||
|
network: IrcNetwork;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LiItem = ({ idx, network }: LiItemProps) => {
|
||||||
const [updateIsOpen, toggleUpdate] = useToggle(false)
|
const [updateIsOpen, toggleUpdate] = useToggle(false)
|
||||||
|
const [edit, toggleEdit] = useToggle(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={network.name} className={idx % 2 === 0 ? 'light:bg-white' : 'light:bg-gray-50'}>
|
|
||||||
<IrcNetworkUpdateForm isOpen={updateIsOpen} toggle={toggleUpdate} network={network} />
|
|
||||||
|
|
||||||
<td className="px-6 py-4 whitespace-nowrap">
|
<li key={idx} >
|
||||||
|
<div className="grid grid-cols-12 gap-4 items-center hover:bg-gray-50 dark:hover:bg-gray-700 py-4">
|
||||||
|
|
||||||
|
<IrcNetworkUpdateForm isOpen={updateIsOpen} toggle={toggleUpdate} network={network} />
|
||||||
|
{/* <div className="col-span-1 flex items-center sm:px-6">
|
||||||
<Switch
|
<Switch
|
||||||
checked={network.enabled}
|
checked={network.enabled}
|
||||||
onChange={toggleUpdate}
|
onChange={toggleUpdate}
|
||||||
|
@ -133,17 +143,68 @@ const ListItem = ({ idx, network }: any) => {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</td>
|
</div> */}
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">{network.name}</td>
|
<div className="col-span-3 items-center sm:px-6 text-sm font-medium text-gray-900 dark:text-white cursor-pointer" onClick={toggleEdit}>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400"><span>{network.server}:{network.port}</span> {network.tls && <span className="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 dark:bg-green-300 text-green-800 dark:text-green-900">TLS</span>}</td>
|
<span className="relative inline-flex items-center">
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">{network.nickserv?.account}</td>
|
{network.connected ? (
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
<span className="mr-3 flex h-3 w-3 relative" title={`Connected since: ${simplifyDate(network.connected_since)}`}>
|
||||||
|
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
||||||
|
<span className="inline-flex absolute rounded-full h-3 w-3 bg-green-500"></span>
|
||||||
|
</span>
|
||||||
|
) : <span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-red-400" />}
|
||||||
|
{network.name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-span-4 flex justify-between items-center sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer" onClick={toggleEdit}>{network.server}:{network.port} {network.tls && <span className="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 dark:bg-green-300 text-green-800 dark:text-green-900">TLS</span>}</div>
|
||||||
|
<div className="col-span-4 items-center sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer" onClick={toggleEdit}>{network.nickserv.account}</div>
|
||||||
|
<div className="col-span-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
<span className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 cursor-pointer" onClick={toggleUpdate}>
|
<span className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 cursor-pointer" onClick={toggleUpdate}>
|
||||||
Edit
|
Edit
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{edit && (
|
||||||
|
<div className="px-4 py-4 flex border-b border-x-0 dark:border-gray-600 dark:bg-gray-700">
|
||||||
|
<div className="min-w-full">
|
||||||
|
<ol>
|
||||||
|
|
||||||
|
<li className="grid grid-cols-12 gap-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Channel</div>
|
||||||
|
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Monitoring since</div>
|
||||||
|
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Last announce</div>
|
||||||
|
</li>
|
||||||
|
{network.channels.map(c => (
|
||||||
|
<li key={c.id} className="text-gray-500 dark:text-gray-400">
|
||||||
|
|
||||||
|
<div className="grid grid-cols-12 gap-4 items-center py-4">
|
||||||
|
|
||||||
|
<div className="col-span-4 flex items-center sm:px-6 ">
|
||||||
|
<span className="relative inline-flex items-center">
|
||||||
|
{c.monitoring ? (
|
||||||
|
<span className="mr-3 flex h-3 w-3 relative" title="monitoring">
|
||||||
|
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
||||||
|
<span className="inline-flex absolute rounded-full h-3 w-3 bg-green-500"></span>
|
||||||
|
</span>
|
||||||
|
) : <span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-red-400" />}
|
||||||
|
{c.name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-4 flex items-center sm:px-6 ">
|
||||||
|
<span className="" title={simplifyDate(c.monitoring_since)}>{IsEmptyDate(c.monitoring_since)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-4 flex items-center sm:px-6 ">
|
||||||
|
<span className="" title={simplifyDate(c.last_announce)}>{IsEmptyDate(c.last_announce)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue