Compare commits
235 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e32a37a747 | ||
|
|
7805a71332 | ||
|
|
6fb2aee210 | ||
|
|
ce9bb588ed | ||
|
|
55fb914537 | ||
|
|
6f7bfd6c9c | ||
|
|
fbc0d981ba | ||
|
|
48d1c673a9 | ||
|
|
889a0eb8b3 | ||
|
|
b01c10b73e | ||
|
|
f6ad64bf69 | ||
|
|
a5e8443735 | ||
|
|
2860929a47 | ||
|
|
ecdac56616 | ||
|
|
25918e56fa | ||
|
|
df91f016f2 | ||
|
|
f7d259f653 | ||
|
|
82ab4328d4 | ||
|
|
b21e19a223 | ||
|
|
c6aed4eb57 | ||
|
|
760d466b38 | ||
|
|
258eecc55b | ||
|
|
7b93f5d7cf | ||
|
|
3be7676970 | ||
|
|
48ee2f8a42 | ||
|
|
ec83d0eb86 | ||
|
|
19347d263a | ||
|
|
b22b16d98c | ||
|
|
cadb765b7d | ||
|
|
1116da8b83 | ||
|
|
c65700923a | ||
|
|
7030c7c24c | ||
|
|
09718a2170 | ||
|
|
77cda2c2c5 | ||
|
|
d9c57cdd9a | ||
|
|
0dad53b5f7 | ||
|
|
9a7315dbea | ||
|
|
a21558f418 | ||
|
|
4f928be393 | ||
|
|
f543b47261 | ||
|
|
66b831072c | ||
|
|
80eb339896 | ||
|
|
c69639c013 | ||
|
|
5f6fbe8e08 | ||
|
|
b40bbf0260 | ||
|
|
a11c8e91ab | ||
|
|
618d0e596c | ||
|
|
fde9ea5cb1 | ||
|
|
03d9803238 | ||
|
|
bd64b8b014 | ||
|
|
67fe064fcf | ||
|
|
471668d19a | ||
|
|
42762dfe54 | ||
|
|
c9314610d4 | ||
|
|
16755c37d8 | ||
|
|
73fcbd6ea2 | ||
|
|
30244f361f | ||
|
|
083991fb21 | ||
|
|
e3200d5046 | ||
|
|
21f6ed36fe | ||
|
|
77d04d44eb | ||
|
|
b34d119255 | ||
|
|
63bd71a10c | ||
|
|
faf2b32389 | ||
|
|
d23da1b757 | ||
|
|
beb8e36eee | ||
|
|
fe70161c01 | ||
|
|
39fa4b1f8e | ||
|
|
c7a8883201 | ||
|
|
3fd467413c | ||
|
|
9728dd856f | ||
|
|
ecadf78d60 | ||
|
|
eba4612d72 | ||
|
|
9200163f85 | ||
|
|
3c17853344 | ||
|
|
993a3fc42c | ||
|
|
7bb9b2416b | ||
|
|
2de321ce24 | ||
|
|
30b2b85ff1 | ||
|
|
6ea4788f56 | ||
|
|
3c52a021b9 | ||
|
|
0ceea9af5f | ||
|
|
39b404be19 | ||
|
|
56dc3eab02 | ||
|
|
554a38eeb1 | ||
|
|
c8d3afe869 | ||
|
|
44222c604c | ||
|
|
cbf221585e | ||
|
|
48322f6d0d | ||
|
|
d5a213c639 | ||
|
|
8166c4bc33 | ||
|
|
133cd9ef6b | ||
|
|
11146f73ed | ||
|
|
1beb18db47 | ||
|
|
f7bc2273a7 | ||
|
|
d1e735a003 | ||
|
|
af4ff5c748 | ||
|
|
fc951c1226 | ||
|
|
f81fd42472 | ||
|
|
1029ea5966 | ||
|
|
c0abdb4bc7 | ||
|
|
6681178ad3 | ||
|
|
e73605c4c5 | ||
|
|
c7017d49aa | ||
|
|
191d3bde49 | ||
|
|
18876a8e5c | ||
|
|
aa4a0d9880 | ||
|
|
d03d731d65 | ||
|
|
33b58a42fe | ||
|
|
2e9e708647 | ||
|
|
8ad22841ab | ||
|
|
32cf02264c | ||
|
|
0e8445b38f | ||
|
|
cb27ecd6c0 | ||
|
|
535220b3df | ||
|
|
7b9cfa94f8 | ||
|
|
b3f2e88e9c | ||
|
|
aa7a8d45e4 | ||
|
|
49cdef3d6a | ||
|
|
fecd146552 | ||
|
|
b01efd8c98 | ||
|
|
bd4dfb261c | ||
|
|
e754e4d2f6 | ||
|
|
b220e35c99 | ||
|
|
4f5131f423 | ||
|
|
dcb043df5f | ||
|
|
86e5756262 | ||
|
|
ba0cf5739b | ||
|
|
c4a13b92d2 | ||
|
|
723279121a | ||
|
|
3ad7649f7d | ||
|
|
2898a49d86 | ||
|
|
1547f9d35e | ||
|
|
adadd55c42 | ||
|
|
33b0225aa4 | ||
|
|
97d4058d80 | ||
|
|
86207e719d | ||
|
|
113f94ff46 | ||
|
|
5673deb391 | ||
|
|
3548a393ed | ||
|
|
254515f274 | ||
|
|
bccbecc6ea | ||
|
|
66f53803af | ||
|
|
faef005ce7 | ||
|
|
941cd2a562 | ||
|
|
6a4a9a0239 | ||
|
|
b9dbe6f1b6 | ||
|
|
7fec111ef8 | ||
|
|
5e1bd99718 | ||
|
|
9d75f72ceb | ||
|
|
d98d96db1a | ||
|
|
6a0ef2df15 | ||
|
|
75c2eb4c8a | ||
|
|
d021a67d66 | ||
|
|
4ed97cab12 | ||
|
|
a38742eed7 | ||
|
|
5efa95ed26 | ||
|
|
04db7db607 | ||
|
|
d17c6c6bb3 | ||
|
|
b2052f2ef1 | ||
|
|
cddcf852c2 | ||
|
|
1def426b45 | ||
|
|
b114fd5279 | ||
|
|
d27c3284f6 | ||
|
|
ba24a26b53 | ||
|
|
3e6678b6b4 | ||
|
|
83fd6f9782 | ||
|
|
52bc1b3f10 | ||
|
|
dd2153b7ac | ||
|
|
dd96a34861 | ||
|
|
daf26ee25a | ||
|
|
7e140eaaac | ||
|
|
d07a712988 | ||
|
|
95863288bf | ||
|
|
ea12be658b | ||
|
|
faa7c9aae5 | ||
|
|
e3653e8c25 | ||
|
|
b40cb24822 | ||
|
|
74004c1aa0 | ||
|
|
3e240741f1 | ||
|
|
6cfdbef1a5 | ||
|
|
d9bde6425b | ||
|
|
e2ae9e1591 | ||
|
|
5ebcbfa9ad | ||
|
|
e276bd7a31 | ||
|
|
659b2529bf | ||
|
|
97b3ed43ab | ||
|
|
767d6d3f28 | ||
|
|
31fc9bfc52 | ||
|
|
3f06b02409 | ||
|
|
5bf958ec6b | ||
|
|
959d9ff9a0 | ||
|
|
4813b4de25 | ||
|
|
119100924c | ||
|
|
bd584de4ee | ||
|
|
ede85ab2f2 | ||
|
|
12c20288e4 | ||
|
|
5bbbf89c10 | ||
|
|
d55393ecd5 | ||
|
|
2b5927306f | ||
|
|
4f016b6ed7 | ||
|
|
3a2a6d10ec | ||
|
|
2491426b09 | ||
|
|
5ebdd1390e | ||
|
|
b7f0247575 | ||
|
|
e28186a28a | ||
|
|
de1a7ce48f | ||
|
|
48480fb33b | ||
|
|
f41332fe6b | ||
|
|
1f8b340b8f | ||
|
|
fdaf1d09d3 | ||
|
|
b9682c4f10 | ||
|
|
69dcb4effd | ||
|
|
d50fd0ba91 | ||
|
|
c2c7b4c731 | ||
|
|
952d5f3a3d | ||
|
|
3f126c9ec9 | ||
|
|
0be58ef918 | ||
|
|
8f9053e2fc | ||
|
|
68452e5330 | ||
|
|
2eacc46eaa | ||
|
|
74dcc91ea7 | ||
|
|
dd7bf61323 | ||
|
|
2819d6cace | ||
|
|
75355a6883 | ||
|
|
e9c007d56b | ||
|
|
84c9085516 | ||
|
|
9f36e57c1e | ||
|
|
7528699fc2 | ||
|
|
d280151c18 | ||
|
|
b44c755d25 | ||
|
|
e4078e87a1 | ||
|
|
be36204756 | ||
|
|
b5409d6d00 | ||
|
|
f3d6bce03e |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -1,7 +1,7 @@
|
||||
'name': 'build'
|
||||
|
||||
'env':
|
||||
'GO_VERSION': '1.23.5'
|
||||
'GO_VERSION': '1.22.2'
|
||||
'NODE_VERSION': '16'
|
||||
|
||||
'on':
|
||||
@@ -95,7 +95,7 @@
|
||||
'key': "${{ runner.os }}-node-${{ hashFiles('client/package-lock.json') }}"
|
||||
'restore-keys': '${{ runner.os }}-node-'
|
||||
- 'name': 'Set up Snapcraft'
|
||||
'run': 'sudo snap install snapcraft --classic'
|
||||
'run': 'sudo apt-get -yq --no-install-suggests --no-install-recommends install snapcraft'
|
||||
- 'name': 'Set up QEMU'
|
||||
'uses': 'docker/setup-qemu-action@v1'
|
||||
- 'name': 'Set up Docker Buildx'
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -1,7 +1,7 @@
|
||||
'name': 'lint'
|
||||
|
||||
'env':
|
||||
'GO_VERSION': '1.23.5'
|
||||
'GO_VERSION': '1.22.2'
|
||||
|
||||
'on':
|
||||
'push':
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,8 +1,3 @@
|
||||
# This comment is used to simplify checking local copies of the file. Bump
|
||||
# this number every time a significant change is made to this file.
|
||||
#
|
||||
# AdGuard-Project-Version: 1
|
||||
|
||||
# Please, DO NOT put your text editors' temporary files here. The more are
|
||||
# added, the harder it gets to maintain and manage projects' gitignores. Put
|
||||
# them into your global gitignore file instead.
|
||||
@@ -13,7 +8,6 @@
|
||||
# bottom to make sure they take effect.
|
||||
*.db
|
||||
*.log
|
||||
*.out
|
||||
*.snap
|
||||
*.test
|
||||
/agh-backup/
|
||||
@@ -27,7 +21,6 @@
|
||||
/launchpad_credentials
|
||||
/querylog.json*
|
||||
/snapcraft_login
|
||||
/test-reports/
|
||||
AdGuardHome
|
||||
AdGuardHome.exe
|
||||
AdGuardHome.yaml*
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"ul-indent": {
|
||||
"indent": 4
|
||||
},
|
||||
"ul-style": {
|
||||
"style": "dash"
|
||||
},
|
||||
"emphasis-style": {
|
||||
"style": "asterisk"
|
||||
},
|
||||
"no-duplicate-heading": {
|
||||
"siblings_only": true
|
||||
},
|
||||
"no-inline-html": {
|
||||
"allowed_elements": [
|
||||
"a"
|
||||
]
|
||||
},
|
||||
"no-trailing-spaces": {
|
||||
"br_spaces": 0
|
||||
},
|
||||
"line-length": false,
|
||||
"no-bare-urls": false,
|
||||
"link-fragments": false
|
||||
}
|
||||
2431
CHANGELOG.md
2431
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
77
Makefile
77
Makefile
@@ -1,14 +1,14 @@
|
||||
# Keep the Makefile POSIX-compliant. We currently allow hyphens in
|
||||
# target names, but that may change in the future.
|
||||
#
|
||||
# See https://pubs.opengroup.org/onlinepubs/9799919799/utilities/make.html.
|
||||
# See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html.
|
||||
.POSIX:
|
||||
|
||||
# This comment is used to simplify checking local copies of the
|
||||
# Makefile. Bump this number every time a significant change is made to
|
||||
# this Makefile.
|
||||
#
|
||||
# AdGuard-Project-Version: 9
|
||||
# AdGuard-Project-Version: 4
|
||||
|
||||
# Don't name these macros "GO" etc., because GNU Make apparently makes
|
||||
# them exported environment variables with the literal value of
|
||||
@@ -22,12 +22,12 @@ VERBOSE.MACRO = $${VERBOSE:-0}
|
||||
|
||||
CHANNEL = development
|
||||
CLIENT_DIR = client
|
||||
DEPLOY_SCRIPT_PATH = not/a/real/path
|
||||
COMMIT = $$( git rev-parse --short HEAD )
|
||||
DIST_DIR = dist
|
||||
GOAMD64 = v1
|
||||
GOPROXY = https://proxy.golang.org|direct
|
||||
GOTELEMETRY = off
|
||||
GOTOOLCHAIN = go1.23.5
|
||||
GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct
|
||||
GOSUMDB = sum.golang.google.cn
|
||||
GOTOOLCHAIN = go1.22.2
|
||||
GPG_KEY = devteam@adguard.com
|
||||
GPG_KEY_PASSPHRASE = not-a-real-password
|
||||
NPM = npm
|
||||
@@ -35,9 +35,7 @@ NPM_FLAGS = --prefix $(CLIENT_DIR)
|
||||
NPM_INSTALL_FLAGS = $(NPM_FLAGS) --quiet --no-progress --ignore-engines\
|
||||
--ignore-optional --ignore-platform --ignore-scripts
|
||||
RACE = 0
|
||||
REVISION = $${REVISION:-$$(git rev-parse --short HEAD)}
|
||||
SIGN = 1
|
||||
SIGNER_API_KEY = not-a-real-key
|
||||
VERSION = v0.0.0
|
||||
YARN = yarn
|
||||
|
||||
@@ -60,29 +58,21 @@ BUILD_RELEASE_DEPS_1 = go-deps
|
||||
|
||||
ENV = env\
|
||||
CHANNEL='$(CHANNEL)'\
|
||||
DEPLOY_SCRIPT_PATH='$(DEPLOY_SCRIPT_PATH)' \
|
||||
COMMIT='$(COMMIT)'\
|
||||
DIST_DIR='$(DIST_DIR)'\
|
||||
GO="$(GO.MACRO)"\
|
||||
GOAMD64='$(GOAMD64)'\
|
||||
GOAMD64="$(GOAMD64)"\
|
||||
GOPROXY='$(GOPROXY)'\
|
||||
GOTELEMETRY='$(GOTELEMETRY)'\
|
||||
GOSUMDB='$(GOSUMDB)'\
|
||||
GOTOOLCHAIN='$(GOTOOLCHAIN)'\
|
||||
GPG_KEY='$(GPG_KEY)'\
|
||||
GPG_KEY_PASSPHRASE='$(GPG_KEY_PASSPHRASE)'\
|
||||
NEXTAPI='$(NEXTAPI)'\
|
||||
PATH="$${PWD}/bin:$$( "$(GO.MACRO)" env GOPATH )/bin:$${PATH}"\
|
||||
RACE='$(RACE)'\
|
||||
REVISION='$(REVISION)'\
|
||||
SIGN='$(SIGN)'\
|
||||
SIGNER_API_KEY='$(SIGNER_API_KEY)' \
|
||||
VERBOSE="$(VERBOSE.MACRO)"\
|
||||
VERSION="$(VERSION)"\
|
||||
|
||||
# Keep the line above blank.
|
||||
|
||||
ENV_MISC = env\
|
||||
PATH="$${PWD}/bin:$$("$(GO.MACRO)" env GOPATH)/bin:$${PATH}"\
|
||||
NEXTAPI='$(NEXTAPI)'\
|
||||
VERBOSE="$(VERBOSE.MACRO)"\
|
||||
VERSION='$(VERSION)'\
|
||||
|
||||
# Keep the line above blank.
|
||||
|
||||
@@ -90,8 +80,6 @@ ENV_MISC = env\
|
||||
# full build.
|
||||
build: deps quick-build
|
||||
|
||||
init: ; git config core.hooksPath ./scripts/hooks
|
||||
|
||||
quick-build: js-build go-build
|
||||
|
||||
deps: js-deps go-deps
|
||||
@@ -105,38 +93,39 @@ build-docker: ; $(ENV) "$(SHELL)" ./scripts/make/build-docker.sh
|
||||
build-release: $(BUILD_RELEASE_DEPS_$(FRONTEND_PREBUILT))
|
||||
$(ENV) "$(SHELL)" ./scripts/make/build-release.sh
|
||||
|
||||
clean: ; $(ENV) "$(SHELL)" ./scripts/make/clean.sh
|
||||
init: ; git config core.hooksPath ./scripts/hooks
|
||||
|
||||
js-build: ; $(NPM) $(NPM_FLAGS) run build-prod
|
||||
js-deps: ; $(NPM) $(NPM_INSTALL_FLAGS) ci
|
||||
js-lint: ; $(NPM) $(NPM_FLAGS) run lint
|
||||
js-test: ; $(NPM) $(NPM_FLAGS) run test
|
||||
|
||||
go-bench: ; $(ENV) "$(SHELL)" ./scripts/make/go-bench.sh
|
||||
go-build: ; $(ENV) "$(SHELL)" ./scripts/make/go-build.sh
|
||||
go-deps: ; $(ENV) "$(SHELL)" ./scripts/make/go-deps.sh
|
||||
go-env: ; $(ENV) "$(GO.MACRO)" env
|
||||
go-fuzz: ; $(ENV) "$(SHELL)" ./scripts/make/go-fuzz.sh
|
||||
go-lint: ; $(ENV) "$(SHELL)" ./scripts/make/go-lint.sh
|
||||
go-bench: ; $(ENV) "$(SHELL)" ./scripts/make/go-bench.sh
|
||||
go-build: ; $(ENV) "$(SHELL)" ./scripts/make/go-build.sh
|
||||
go-deps: ; $(ENV) "$(SHELL)" ./scripts/make/go-deps.sh
|
||||
go-fuzz: ; $(ENV) "$(SHELL)" ./scripts/make/go-fuzz.sh
|
||||
go-lint: ; $(ENV) "$(SHELL)" ./scripts/make/go-lint.sh
|
||||
go-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.sh
|
||||
|
||||
# TODO(a.garipov): Think about making RACE='1' the default for all
|
||||
# targets.
|
||||
go-test: ; $(ENV) RACE='1' "$(SHELL)" ./scripts/make/go-test.sh
|
||||
go-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.sh
|
||||
go-upd-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-upd-tools.sh
|
||||
go-test: ; $(ENV) RACE='1' "$(SHELL)" ./scripts/make/go-test.sh
|
||||
|
||||
go-upd-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-upd-tools.sh
|
||||
|
||||
go-check: go-tools go-lint go-test
|
||||
|
||||
# A quick check to make sure that all operating systems relevant to the
|
||||
# development of the project can be typechecked and built successfully.
|
||||
# A quick check to make sure that all supported operating systems can be
|
||||
# typechecked and built successfully.
|
||||
go-os-check:
|
||||
$(ENV) GOOS='darwin' "$(GO.MACRO)" vet ./internal/...
|
||||
$(ENV) GOOS='freebsd' "$(GO.MACRO)" vet ./internal/...
|
||||
$(ENV) GOOS='openbsd' "$(GO.MACRO)" vet ./internal/...
|
||||
$(ENV) GOOS='linux' "$(GO.MACRO)" vet ./internal/...
|
||||
$(ENV) GOOS='windows' "$(GO.MACRO)" vet ./internal/...
|
||||
|
||||
txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh
|
||||
|
||||
md-lint: ; $(ENV_MISC) "$(SHELL)" ./scripts/make/md-lint.sh
|
||||
sh-lint: ; $(ENV_MISC) "$(SHELL)" ./scripts/make/sh-lint.sh
|
||||
env GOOS='darwin' "$(GO.MACRO)" vet ./internal/...
|
||||
env GOOS='freebsd' "$(GO.MACRO)" vet ./internal/...
|
||||
env GOOS='openbsd' "$(GO.MACRO)" vet ./internal/...
|
||||
env GOOS='linux' "$(GO.MACRO)" vet ./internal/...
|
||||
env GOOS='windows' "$(GO.MACRO)" vet ./internal/...
|
||||
|
||||
openapi-lint: ; cd ./openapi/ && $(YARN) test
|
||||
openapi-show: ; cd ./openapi/ && $(YARN) start
|
||||
|
||||
txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh
|
||||
|
||||
15
README.md
15
README.md
@@ -114,7 +114,7 @@ If you're running **Linux,** there's a secure and easy way to install AdGuard Ho
|
||||
|
||||
[Docker Hub]: https://hub.docker.com/r/adguard/adguardhome
|
||||
[Snap Store]: https://snapcraft.io/adguard-home
|
||||
[wiki-start]: https://adguard-dns.io/kb/adguard-home/getting-started/
|
||||
[wiki-start]: https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started
|
||||
|
||||
### <a href="#guides" id="guides" name="guides">Guides</a>
|
||||
|
||||
@@ -205,9 +205,10 @@ Run `make init` to prepare the development environment.
|
||||
|
||||
You will need this to build AdGuard Home:
|
||||
|
||||
- [Go](https://golang.org/dl/) v1.23 or later;
|
||||
- [Node.js](https://nodejs.org/en/download/) v18.18 or later;
|
||||
- [Go](https://golang.org/dl/) v1.22 or later;
|
||||
- [Node.js](https://nodejs.org/en/download/) v16 or later;
|
||||
- [npm](https://www.npmjs.com/) v8 or later;
|
||||
- [yarn](https://yarnpkg.com/) v1.22.5 or later.
|
||||
|
||||
### <a href="#building" id="building" name="building">Building</a>
|
||||
|
||||
@@ -219,6 +220,14 @@ cd AdGuardHome
|
||||
make
|
||||
```
|
||||
|
||||
#### <a href="#building-node" id="building-node" name="building-node">Building with Node.js 17 and later</a>
|
||||
|
||||
In order to build AdGuard Home with Node.js 17 and later, specify `--openssl-legacy-provider` option.
|
||||
|
||||
```sh
|
||||
export NODE_OPTIONS=--openssl-legacy-provider
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> The non-standard `-j` flag is currently not supported, so building with `make -j 4` or setting your `MAKEFLAGS` to include, for example, `-j 4` is likely to break the build. If you do have your `MAKEFLAGS` set to that, and you don't want to change it, you can override it by running `make -j 1`.
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
# Make sure to sync any changes with the branch overrides below.
|
||||
'variables':
|
||||
'channel': 'edge'
|
||||
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||
'dockerGo': 'adguard/go-builder:1.23.5--1'
|
||||
'dockerFrontend': 'adguard/home-js-builder:1.1'
|
||||
'dockerGo': 'adguard/go-builder:1.22.2--1'
|
||||
|
||||
'stages':
|
||||
- 'Build frontend':
|
||||
@@ -91,11 +91,6 @@
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'checkout':
|
||||
'repository': 'bamboo-deploy-publisher'
|
||||
# The paths are always relative to the working directory.
|
||||
'path': 'bamboo-deploy-publisher'
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
@@ -104,9 +99,6 @@
|
||||
|
||||
set -e -f -u -x
|
||||
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "${bamboo.repository.revision.number}"
|
||||
|
||||
# Run the build with the specified channel.
|
||||
echo "${bamboo.gpgSecretKeyPart1}${bamboo.gpgSecretKeyPart2}"\
|
||||
| awk '{ gsub(/\\n/, "\n"); print; }'\
|
||||
@@ -115,8 +107,6 @@
|
||||
make\
|
||||
CHANNEL=${bamboo.channel}\
|
||||
GPG_KEY_PASSPHRASE=${bamboo.gpgPassword}\
|
||||
DEPLOY_SCRIPT_PATH="./bamboo-deploy-publisher/deploy.sh"\
|
||||
SIGNER_API_KEY="${bamboo.adguardHomeWinSignerSecretApiKey}"\
|
||||
FRONTEND_PREBUILT=1\
|
||||
PARALLELISM=1\
|
||||
VERBOSE=2\
|
||||
@@ -142,15 +132,13 @@
|
||||
# Install Qemu, create builder.
|
||||
docker version -f '{{ .Server.Experimental }}'
|
||||
docker buildx rm buildx-builder || :
|
||||
docker buildx create \
|
||||
--name buildx-builder \
|
||||
--driver docker-container \
|
||||
--use
|
||||
docker buildx create --name buildx-builder --driver docker-container\
|
||||
--use
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
# Login to DockerHub.
|
||||
docker login -u="${bamboo.dockerHubUsername}" \
|
||||
-p="${bamboo.dockerHubPassword}"
|
||||
docker login -u="${bamboo.dockerHubUsername}"\
|
||||
-p="${bamboo.dockerHubPassword}"
|
||||
|
||||
# Boot the builder.
|
||||
docker buildx inspect --bootstrap
|
||||
@@ -159,14 +147,14 @@
|
||||
docker info
|
||||
|
||||
# Prepare and push the build.
|
||||
env \
|
||||
CHANNEL="${bamboo.channel}" \
|
||||
REVISION="${bamboo.repository.revision.number}" \
|
||||
DIST_DIR='dist' \
|
||||
DOCKER_IMAGE_NAME='adguard/adguardhome' \
|
||||
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true" \
|
||||
VERBOSE='1' \
|
||||
sh ./scripts/make/build-docker.sh
|
||||
env\
|
||||
CHANNEL="${bamboo.channel}"\
|
||||
COMMIT="${bamboo.repository.revision.number}"\
|
||||
DIST_DIR='dist'\
|
||||
DOCKER_IMAGE_NAME='adguard/adguardhome'\
|
||||
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true"\
|
||||
VERBOSE='1'\
|
||||
sh ./scripts/make/build-docker.sh
|
||||
'environment':
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
'final-tasks':
|
||||
@@ -261,7 +249,7 @@
|
||||
'recipients':
|
||||
- 'webhook':
|
||||
'name': 'Build webhook'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo?channel=adguard-qa-dns-builds'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo?channel=adguard-qa'
|
||||
|
||||
'labels': []
|
||||
'other':
|
||||
@@ -277,8 +265,8 @@
|
||||
# need to build a few of these.
|
||||
'variables':
|
||||
'channel': 'beta'
|
||||
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||
'dockerGo': 'adguard/go-builder:1.23.5--1'
|
||||
'dockerFrontend': 'adguard/home-js-builder:1.1'
|
||||
'dockerGo': 'adguard/go-builder:1.22.2--1'
|
||||
# release-vX.Y.Z branches are the branches from which the actual final
|
||||
# release is built.
|
||||
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
||||
@@ -293,5 +281,5 @@
|
||||
# are the ones that actually get released.
|
||||
'variables':
|
||||
'channel': 'release'
|
||||
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||
'dockerGo': 'adguard/go-builder:1.23.5--1'
|
||||
'dockerFrontend': 'adguard/home-js-builder:1.1'
|
||||
'dockerGo': 'adguard/go-builder:1.22.2--1'
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
'recipients':
|
||||
- 'webhook':
|
||||
'name': 'Build webhook'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo?channel=adguard-qa-dns-builds'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo?channel=adguard-qa'
|
||||
|
||||
'labels': []
|
||||
'other':
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
'key': 'AHBRTSPECS'
|
||||
'name': 'AdGuard Home - Build and run tests'
|
||||
'variables':
|
||||
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||
'dockerGo': 'adguard/go-builder:1.23.5--1'
|
||||
'dockerFrontend': 'adguard/home-js-builder:1.1'
|
||||
'dockerGo': 'adguard/go-builder:1.22.2--1'
|
||||
'channel': 'development'
|
||||
|
||||
'stages':
|
||||
@@ -54,7 +54,6 @@
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
# TODO(e.burkov): Add the linting stage for markdown docs and shell scripts.
|
||||
'Test backend':
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
@@ -195,6 +194,6 @@
|
||||
# Set the default release channel on the release branch to beta, as we
|
||||
# may need to build a few of these.
|
||||
'variables':
|
||||
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||
'dockerGo': 'adguard/go-builder:1.23.5--1'
|
||||
'dockerFrontend': 'adguard/home-js-builder:1.1'
|
||||
'dockerGo': 'adguard/go-builder:1.22.2--1'
|
||||
'channel': 'candidate'
|
||||
|
||||
60
client/.eslintrc.json
vendored
60
client/.eslintrc.json
vendored
@@ -1,13 +1,9 @@
|
||||
{
|
||||
"plugins": ["prettier"],
|
||||
"parser": "babel-eslint",
|
||||
"extends": [
|
||||
"airbnb-base",
|
||||
"prettier",
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
"airbnb-base"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": {
|
||||
"jest": true,
|
||||
"node": true,
|
||||
@@ -20,21 +16,50 @@
|
||||
"version": "16.4"
|
||||
},
|
||||
"import/resolver": {
|
||||
"node": {
|
||||
"extensions": [".js", ".jsx", ".ts", ".tsx"]
|
||||
"webpack": {
|
||||
"config": "webpack.common.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"import/extensions": [
|
||||
"indent": [
|
||||
"error",
|
||||
"ignorePackages",
|
||||
4,
|
||||
{
|
||||
"js": "never",
|
||||
"jsx": "never",
|
||||
"ts": "never",
|
||||
"tsx": "never"
|
||||
"SwitchCase": 1,
|
||||
"VariableDeclarator": 1,
|
||||
"outerIIFEBody": 1,
|
||||
"FunctionDeclaration": {
|
||||
"parameters": 1,
|
||||
"body": 1
|
||||
},
|
||||
"FunctionExpression": {
|
||||
"parameters": 1,
|
||||
"body": 1
|
||||
},
|
||||
"CallExpression": {
|
||||
"arguments": 1
|
||||
},
|
||||
"ArrayExpression": 1,
|
||||
"ObjectExpression": 1,
|
||||
"ImportDeclaration": 1,
|
||||
"flatTernaryExpressions": false,
|
||||
"ignoredNodes": [
|
||||
"JSXElement",
|
||||
"JSXElement > *",
|
||||
"JSXAttribute",
|
||||
"JSXIdentifier",
|
||||
"JSXNamespacedName",
|
||||
"JSXMemberExpression",
|
||||
"JSXSpreadAttribute",
|
||||
"JSXExpressionContainer",
|
||||
"JSXOpeningElement",
|
||||
"JSXClosingElement",
|
||||
"JSXText",
|
||||
"JSXEmptyExpression",
|
||||
"JSXSpreadChild"
|
||||
],
|
||||
"ignoreComments": false
|
||||
}
|
||||
],
|
||||
"class-methods-use-this": "off",
|
||||
@@ -43,7 +68,10 @@
|
||||
"no-console": [
|
||||
"warn",
|
||||
{
|
||||
"allow": ["warn", "error"]
|
||||
"allow": [
|
||||
"warn",
|
||||
"error"
|
||||
]
|
||||
}
|
||||
],
|
||||
"import/no-extraneous-dependencies": [
|
||||
|
||||
2
client/.gitattributes
vendored
2
client/.gitattributes
vendored
@@ -1 +1 @@
|
||||
*.ts text eol=lf
|
||||
*.js text eol=lf
|
||||
|
||||
10
client/.prettierrc
vendored
10
client/.prettierrc
vendored
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": true,
|
||||
"tabWidth": 4,
|
||||
"semi": true,
|
||||
"arrowParens": "always",
|
||||
}
|
||||
46
client/.stylelintrc
vendored
Normal file
46
client/.stylelintrc
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"defaultSeverity": "warning",
|
||||
"rules": {
|
||||
"block-closing-brace-empty-line-before": "never",
|
||||
"block-no-empty": true,
|
||||
"block-opening-brace-newline-after": "always",
|
||||
"block-opening-brace-space-before": "always",
|
||||
"color-hex-case": "lower",
|
||||
"color-named": "never",
|
||||
"color-no-invalid-hex": true,
|
||||
"length-zero-no-unit": true,
|
||||
"declaration-block-trailing-semicolon": "always",
|
||||
"custom-property-empty-line-before": ["always", {
|
||||
"except": [
|
||||
"after-custom-property",
|
||||
"first-nested"
|
||||
]
|
||||
}],
|
||||
"declaration-block-no-duplicate-properties": true,
|
||||
"declaration-colon-space-after": "always",
|
||||
"declaration-empty-line-before": ["always", {
|
||||
"except": [
|
||||
"after-declaration",
|
||||
"first-nested",
|
||||
"after-comment"
|
||||
]
|
||||
}],
|
||||
"font-weight-notation": "numeric",
|
||||
"indentation": [4, {
|
||||
"except": ["value"]
|
||||
}],
|
||||
"max-empty-lines": 2,
|
||||
"no-missing-end-of-source-newline": true,
|
||||
"number-leading-zero": "always",
|
||||
"property-no-unknown": [true, {
|
||||
"ignoreProperties": "/lost-.+/"
|
||||
}],
|
||||
"rule-empty-line-before": [ "always-multi-line", {
|
||||
"except": ["first-nested"],
|
||||
"ignore": ["after-comment"]
|
||||
}],
|
||||
"string-quotes": "double",
|
||||
"value-list-comma-space-after": "always",
|
||||
"unit-case": "lower"
|
||||
}
|
||||
}
|
||||
44
client/.stylelintrc.js
vendored
44
client/.stylelintrc.js
vendored
@@ -1,44 +0,0 @@
|
||||
module.exports = {
|
||||
rules: {
|
||||
"selector-type-no-unknown": true,
|
||||
"block-closing-brace-empty-line-before": "never",
|
||||
"block-no-empty": true,
|
||||
"block-opening-brace-newline-after": "always",
|
||||
"block-opening-brace-space-before": "always",
|
||||
"color-hex-case": "lower",
|
||||
"color-named": "never",
|
||||
"color-no-invalid-hex": true,
|
||||
"length-zero-no-unit": true,
|
||||
"declaration-block-trailing-semicolon": "always",
|
||||
"custom-property-empty-line-before": ["always", {
|
||||
"except": [
|
||||
"after-custom-property",
|
||||
"first-nested"
|
||||
]
|
||||
}],
|
||||
"declaration-block-no-duplicate-properties": true,
|
||||
"declaration-colon-space-after": "always",
|
||||
"declaration-empty-line-before": ["always", {
|
||||
"except": [
|
||||
"after-declaration",
|
||||
"first-nested",
|
||||
"after-comment"
|
||||
]
|
||||
}],
|
||||
"font-weight-notation": "numeric",
|
||||
"indentation": [4, {
|
||||
"except": ["value"]
|
||||
}],
|
||||
"max-empty-lines": 2,
|
||||
"no-missing-end-of-source-newline": true,
|
||||
"number-leading-zero": "always",
|
||||
"property-no-unknown": true,
|
||||
"rule-empty-line-before": ["always-multi-line", {
|
||||
"except": ["first-nested"],
|
||||
"ignore": ["after-comment"]
|
||||
}],
|
||||
"string-quotes": "double",
|
||||
"value-list-comma-space-after": "always",
|
||||
"unit-case": "lower"
|
||||
}
|
||||
}
|
||||
14
client/babel.config.cjs
vendored
14
client/babel.config.cjs
vendored
@@ -1,14 +0,0 @@
|
||||
module.exports = (api) => {
|
||||
api.cache(false);
|
||||
return {
|
||||
presets: ['@babel/preset-env', '@babel/preset-typescript', '@babel/preset-react'],
|
||||
plugins: [
|
||||
'@babel/plugin-transform-runtime',
|
||||
'@babel/plugin-transform-class-properties',
|
||||
'@babel/plugin-transform-object-rest-spread',
|
||||
'@babel/plugin-transform-nullish-coalescing-operator',
|
||||
'@babel/plugin-transform-optional-chaining',
|
||||
'react-hot-loader/babel',
|
||||
],
|
||||
};
|
||||
};
|
||||
17
client/babel.config.js
vendored
Normal file
17
client/babel.config.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
module.exports = (api) => {
|
||||
api.cache(false);
|
||||
return {
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react',
|
||||
],
|
||||
plugins: [
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
'@babel/plugin-transform-runtime',
|
||||
'@babel/plugin-proposal-object-rest-spread',
|
||||
'@babel/plugin-proposal-nullish-coalescing-operator',
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
'react-hot-loader/babel',
|
||||
],
|
||||
};
|
||||
};
|
||||
9
client/constants.js
vendored
9
client/constants.js
vendored
@@ -1,6 +1,11 @@
|
||||
export const BUILD_ENVS = {
|
||||
const BUILD_ENVS = {
|
||||
dev: 'development',
|
||||
prod: 'production',
|
||||
};
|
||||
|
||||
export const BASE_URL = 'control';
|
||||
const BASE_URL = 'control';
|
||||
|
||||
module.exports = {
|
||||
BUILD_ENVS,
|
||||
BASE_URL,
|
||||
};
|
||||
|
||||
6
client/global.d.ts
vendored
6
client/global.d.ts
vendored
@@ -1,6 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
declare module '*.svg' {
|
||||
const content: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
|
||||
export default content;
|
||||
}
|
||||
5
client/jest.config.js
vendored
Normal file
5
client/jest.config.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
transform: {
|
||||
'^.+\\.jsx?$': 'babel-jest',
|
||||
},
|
||||
};
|
||||
6
client/jest.config.mjs
vendored
6
client/jest.config.mjs
vendored
@@ -1,6 +0,0 @@
|
||||
export default {
|
||||
testEnvironment: 'jsdom',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': 'babel-jest',
|
||||
},
|
||||
};
|
||||
38385
client/package-lock.json
generated
vendored
38385
client/package-lock.json
generated
vendored
File diff suppressed because it is too large
Load Diff
110
client/package.json
vendored
110
client/package.json
vendored
@@ -3,23 +3,19 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build-dev": "cross-env NODE_ENV=development BUILD_ENV=dev webpack --config webpack.dev.js",
|
||||
"build-dev": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js",
|
||||
"build-prod": "cross-env BUILD_ENV=prod webpack --config webpack.prod.js",
|
||||
"watch": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js --watch",
|
||||
"watch:hot": "cross-env BUILD_ENV=dev webpack-dev-server --config webpack.dev.js",
|
||||
"lint": "echo 'Lint temporarily disabled'",
|
||||
"lint-new": "eslint './src/**/*.(ts|tsx)'",
|
||||
"lint:fix": "eslint './src/**/*.(ts|tsx)' --fix",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"typecheck:watch": "tsc --noEmit --watch"
|
||||
"test:watch": "jest --watch"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@nivo/line": "^0.64.0",
|
||||
"axios": "^0.19.2",
|
||||
"classnames": "^2.5.1",
|
||||
"classnames": "^2.2.6",
|
||||
"countries-and-timezones": "^3.6.0",
|
||||
"date-fns": "^1.29.0",
|
||||
"i18next": "^19.6.2",
|
||||
@@ -28,8 +24,7 @@
|
||||
"js-yaml": "^3.14.0",
|
||||
"lodash": "^4.17.19",
|
||||
"nanoid": "^3.1.9",
|
||||
"popper.js": "^1.16.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"query-string": "^6.13.1",
|
||||
"react": "^16.13.1",
|
||||
"react-click-outside": "^3.0.1",
|
||||
@@ -43,64 +38,53 @@
|
||||
"react-router-hash-link": "^1.2.2",
|
||||
"react-select": "^3.1.0",
|
||||
"react-table": "^6.11.4",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"react-transition-group": "^4.4.1",
|
||||
"redux": "^4.0.5",
|
||||
"redux-actions": "^2.6.5",
|
||||
"redux-form": "^8.3.10",
|
||||
"redux-form": "^8.3.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"ts-migrate": "^0.1.35",
|
||||
"url-polyfill": "^1.1.12"
|
||||
"url-polyfill": "^1.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.5",
|
||||
"@babel/plugin-transform-class-properties": "^7.24.1",
|
||||
"@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1",
|
||||
"@babel/plugin-transform-object-rest-spread": "^7.24.5",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.24.5",
|
||||
"@babel/plugin-transform-runtime": "^7.24.3",
|
||||
"@babel/preset-env": "^7.24.5",
|
||||
"@babel/preset-react": "^7.24.1",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/lodash": "^4.17.4",
|
||||
"@types/react": "^17.0.80",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react-redux": "^7.1.33",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-table": "^7.7.20",
|
||||
"@types/redux-actions": "^2.6.5",
|
||||
"@types/redux-form": "^8.3.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.11.0",
|
||||
"@typescript-eslint/parser": "^7.10.0",
|
||||
"babel-loader": "^9.1.3",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^7.1.2",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"file-loader": "^6.2.0",
|
||||
"html-webpack-plugin": "^5.6.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"jscodeshift": "^0.15.2",
|
||||
"mini-css-extract-plugin": "^2.9.0",
|
||||
"@babel/core": "^7.9.6",
|
||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.9.6",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.10.4",
|
||||
"@babel/plugin-transform-runtime": "^7.9.6",
|
||||
"@babel/preset-env": "^7.9.6",
|
||||
"@babel/preset-react": "^7.9.4",
|
||||
"autoprefixer": "^9.8.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.1.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^6.0.1",
|
||||
"cross-env": "^7.0.2",
|
||||
"css-loader": "^3.5.3",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-airbnb": "^18.1.0",
|
||||
"eslint-import-resolver-webpack": "^0.12.1",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||
"eslint-plugin-react": "^7.24.0",
|
||||
"eslint-plugin-react-hooks": "^2.5.0",
|
||||
"file-loader": "6.0.0",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"jest": "^26.0.1",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"path": "^0.12.7",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"prettier": "^3.2.5",
|
||||
"react-hot-loader": "^4.13.1",
|
||||
"style-loader": "^4.0.0",
|
||||
"stylelint": "^16.5.0",
|
||||
"ts-loader": "^9.5.1",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.91.0",
|
||||
"webpack-cli": "^5.1.4",
|
||||
"webpack-dev-server": "^5.0.4",
|
||||
"webpack-merge": "^5.10.0"
|
||||
"postcss-flexbugs-fixes": "4.2.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"react-hot-loader": "^4.12.21",
|
||||
"style-loader": "^1.2.1",
|
||||
"stylelint": "^13.5.0",
|
||||
"stylelint-webpack-plugin": "2.0.0",
|
||||
"url-loader": "^4.1.0",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.11.0",
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"browserslist": {
|
||||
"development": [
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
{
|
||||
"client_settings": "إعدادات العميل",
|
||||
"example_upstream_reserved": "من المنبع <0>لمجالات محددة</0>;",
|
||||
"example_multiple_upstreams_reserved": "منابع متعددة <0>لمجالات محددة</0>;",
|
||||
"example_upstream_comment": "تعليق.",
|
||||
"upstream_parallel": "استخدم الاستعلامات المتوازية لتسريع عملية الحل عن طريق الاستعلام عن جميع الخوادم المنبع في وقت واحد.",
|
||||
"parallel_requests": "الطلبات الموازية",
|
||||
"load_balancing": "موازنة الأحمال",
|
||||
"example_upstream_reserved": "يمكنك تحديد <0> DNS upstream لنطاق معين (نطاقات) </0>",
|
||||
"example_upstream_comment": "يمكنك تحديد تعليق",
|
||||
"upstream_parallel": "استخدام الاستعلامات المتوازية لتسريع الحل عن طريق الاستعلام في وقت واحد عن جميع خوادم المنبع",
|
||||
"parallel_requests": "طلبات موازية",
|
||||
"load_balancing": "توزيع الحمل",
|
||||
"load_balancing_desc": "الاستعلام عن خادم واحد في كل مرة سيستخدم AdGuard الرئيسية الخوارزمية العشوائية الموزونة لاختيار الخادم بحيث يتم استخدام أسرع خادم في كثير من الأحيان",
|
||||
"bootstrap_dns": "خوادم Bootstrap DNS",
|
||||
"bootstrap_dns_desc": "عناوين IP لخوادم DNS المستخدمة لحل عناوين IP الخاصة بمحللات DoH/DoT التي تحددها كمصدرين رئيسيين. التعليقات غير مسموح بها.",
|
||||
"fallback_dns_title": "خوادم DNS الاحتياطية",
|
||||
"fallback_dns_desc": "قائمة الخوادم الاحتياطية المستخدمة في حالة عدم الاستجابة من خوادم DNS الرئيسية. تمتلك تلك الخوادم والخوادم الرئيسية نفس الأوامر.",
|
||||
"fallback_dns_placeholder": "أدخل خادم DNS احتياطي واحد لكل سطر",
|
||||
"local_ptr_title": "خوادم DNS العكسية الخاصة",
|
||||
"local_ptr_desc": "خوادم DNS التي يستخدمها AdGuard Home لاستعلامات PTR المحلية. تُستخدم هذه الخوادم لحل أسماء المضيفين للعملاء بعناوين IP خاصة ، على سبيل المثال \"192.168.12.34\" ، باستخدام DNS العكسي. في حالة عدم التعيين ، يستخدم AdGuard Home عناوين محللات DNS الافتراضية لنظام التشغيل الخاص بك باستثناء عناوين AdGuard Home نفسها.",
|
||||
"local_ptr_default_resolver": "بشكل افتراضي ، يستخدم AdGuard Home محللات DNS العكسية التالية: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "لم يتمكن AdGuard Home من تحديد محللات DNS العكسية المناسبة لهذا النظام.",
|
||||
"local_ptr_placeholder": "أدخل عنوان IP واحد لكل سطر",
|
||||
"local_ptr_placeholder": "أدخل عنوان خادم واحد لكل سطر",
|
||||
"resolve_clients_title": "تفعيل التحليل العكسي لعناوين IP للعملاء",
|
||||
"resolve_clients_desc": "حل عكسيًا لعناوين IP للعملاء في أسماء مضيفيهم عن طريق إرسال استعلامات PTR إلى أدوات الحل المقابلة (خوادم DNS الخاصة للعملاء المحليين ، والخوادم الأولية للعملاء الذين لديهم عناوين IP عامة).",
|
||||
"use_private_ptr_resolvers_title": "استخدم محللات DNS العكسية الخاصة",
|
||||
@@ -38,7 +34,7 @@
|
||||
"dhcp_leases_not_found": "لم يتم العثور على عقود إيجار DHCP",
|
||||
"dhcp_config_saved": "الإعدادات محفوظة لخادم DHCP",
|
||||
"dhcp_ipv4_settings": "DHCP IPv4 إعدادات",
|
||||
"dhcp_ipv6_settings": "إعدادات DHCP IPv6",
|
||||
"dhcp_ipv6_settings": "DHCP IPv6 إعدادات",
|
||||
"form_error_required": "الحقل مطلوب",
|
||||
"form_error_ip4_format": "عنوان IPv4 غير صالح",
|
||||
"form_error_ip4_gateway_format": "عنوان IPv4 غير صالح للبوابة",
|
||||
@@ -67,16 +63,14 @@
|
||||
"dhcp_ip_addresses": "عناوين الـIP",
|
||||
"ip": "IP",
|
||||
"dhcp_table_hostname": "اسم المضيف",
|
||||
"dhcp_table_expires": "تنتهي",
|
||||
"dhcp_table_expires": "يتنهي في",
|
||||
"dhcp_warning": "إذا كنت تريد تمكين خادم DHCP على أي حال ، فتأكد من عدم وجود خادم DHCP نشط آخر في شبكتك. خلاف ذلك ، يمكن أن يعطل خدمة الإنترنت للأجهزة المتصلة!",
|
||||
"dhcp_error": "لم نتمكن من تحديد ما إذا كان هناك خادم DHCP آخر في الشبكة.",
|
||||
"dhcp_static_ip_error": "من أجل استخدام خادم DHCP ، يجب تعيين عنوان IP ثابت. فشلنا في تحديد ما إذا تم تكوين واجهة الشبكة هذه باستخدام عنوان IP ثابت. يرجى تعيين عنوان IP ثابت يدويًا.",
|
||||
"dhcp_dynamic_ip_found": "يستخدم نظامك عنوان IP الديناميكي للواجهة <0>{{interfaceName}}</0>. من أجل استعمال خادم DHCP ، يجب تعيين عنوان IP ثابت. عنوان IP الحالي الخاص بك هو <0>{{ipAddress}}</0>. إذا ضغطت على زر تفعيل DHCP سنقوم تلقائيًا بتعيين عنوان الIP هذا على أنه ثابت.",
|
||||
"dhcp_lease_added": "تمت أضافة مدة الايجار \"{{key}}\" بنجاح",
|
||||
"dhcp_lease_deleted": "تمت ازالة مدة الايجار \"{{key}}\" بنجاح",
|
||||
"dhcp_lease_updated": "Static lease \"{{key}}\" تمّ التحديث بنجاح",
|
||||
"dhcp_new_static_lease": "عقد إيجار ثابت جديد",
|
||||
"dhcp_edit_static_lease": "تحرير عقد الإيجار الثابت",
|
||||
"dhcp_static_leases_not_found": "لم يتم العثور على عقود إيجار ثابتة DHCP",
|
||||
"dhcp_add_static_lease": "إضافة عقد إيجار ثابت",
|
||||
"dhcp_reset_leases": "إعادة تعيين كافة عقود الإيجار",
|
||||
@@ -89,7 +83,7 @@
|
||||
"form_enter_hostname": "أدخل اسم الhostname",
|
||||
"error_details": "مزيد من التفاصيل حول الخطأ",
|
||||
"response_details": "تفاصيل الاستجابة",
|
||||
"request_details": "طلب التفاصيل",
|
||||
"request_details": "تفاصيل الطلب",
|
||||
"client_details": "تفاصيل العميل",
|
||||
"details": "التفاصيل",
|
||||
"back": "رجوع",
|
||||
@@ -99,13 +93,13 @@
|
||||
"filter": "فلتر",
|
||||
"query_log": "سجل الQuery",
|
||||
"compact": "المدمج",
|
||||
"nothing_found": "لم يتم العثور على شيء",
|
||||
"faq": "الأسئلة المتداولة",
|
||||
"nothing_found": "لم يتم العثور علي شيء...",
|
||||
"faq": "أسئلة مكررة",
|
||||
"version": "الإصدار",
|
||||
"address": "العنوان",
|
||||
"address": "العناوين",
|
||||
"protocol": "البروتوكول",
|
||||
"on": "قيد التشغيل",
|
||||
"off": "قيد الإيقاف",
|
||||
"on": "ON",
|
||||
"off": "OFF",
|
||||
"copyright": "حقوق النشر",
|
||||
"homepage": "الصفحة الرئيسية",
|
||||
"report_an_issue": "الإبلاغ عن مشكلة",
|
||||
@@ -120,8 +114,7 @@
|
||||
"stats_malware_phishing": "حسر البرامج الضارة / والتصيّد",
|
||||
"stats_adult": "حظر مواقع الويب الخاصة بالبالغين",
|
||||
"stats_query_domain": "اعلى النطاقات التي تم الاستعلام عنها",
|
||||
"for_last_hours": "لآخر {{count}} ساعة",
|
||||
"for_last_hours_plural": "لآخر {{count}} ساعة",
|
||||
"for_last_24_hours": "لأخر 24 ساعة",
|
||||
"for_last_days": "لآخر {{value}} يوم",
|
||||
"for_last_days_plural": "لآخر {{count}} ايام",
|
||||
"stats_disabled": "تم تعطيل الإحصائيات. يمكنك تشغيله من <0> صفحة الإعدادات </0>.",
|
||||
@@ -136,16 +129,13 @@
|
||||
"no_upstreams_data_found": "لم يتم العثور على بيانات خوادم upstream",
|
||||
"number_of_dns_query_days": "عدد استعلامات DNS التي تمت معالجتها لآخر {{count}} يوم",
|
||||
"number_of_dns_query_days_plural": "عدد استعلامات DNS التي تمت معالجتها لآخر {{count}} أيام",
|
||||
"number_of_dns_query_hours": "عدد استفسارات DNS التي تمت معالجتها لآخر {{count}} ساعة",
|
||||
"number_of_dns_query_hours_plural": "عدد استعلامات DNS التي تمت معالجتها خلال آخر {{count}} ساعة",
|
||||
"number_of_dns_query_24_hours": "عدد استعلامات DNS التي تمت معالجتها لآخر 24 ساعة",
|
||||
"number_of_dns_query_blocked_24_hours": "عدد طلبات DNS المحظورة بواسطة فلاتر adblock وقوائم حظر المضيفين",
|
||||
"number_of_dns_query_blocked_24_hours_by_sec": "عدد طلبات DNS التي تم حظرها من قبل وحدة أمان التصفح AdGuard",
|
||||
"number_of_dns_query_blocked_24_hours_adult": "عدد من المواقع (الإباحية) للبالغين تم حجبها",
|
||||
"enforced_save_search": "فرض البحث الآمن",
|
||||
"number_of_dns_query_to_safe_search": "عدد طلبات DNS لمحركات البحث التي تم فرض البحث الآمن عنها",
|
||||
"average_processing_time": "متوسط وقت المعالجة",
|
||||
"average_upstream_response_time": "متوسط وقت استجابة المنبع",
|
||||
"response_time": "وقت الاستجابة",
|
||||
"average_processing_time_hint": "متوسط الوقت بالمللي ثانية عند معالجة طلب DNS",
|
||||
"block_domain_use_filters_and_hosts": "حظر النطاقات باستخدام عوامل التصفية وملفات المضيفين",
|
||||
"filters_block_toggle_hint": "يمكنك إعداد قواعد حظر في <a>المرشحات</a> اعدادات.",
|
||||
@@ -180,9 +170,8 @@
|
||||
"enabled_parental_toast": "تفعيل الرقابة الأبوية",
|
||||
"disabled_safe_search_toast": "تعطيل البحث الآمن",
|
||||
"enabled_save_search_toast": "تفعيل البحث الآمن",
|
||||
"updated_save_search_toast": "تم تحديث إعدادات البحث الآمن",
|
||||
"enabled_table_header": "قيد التشغيل",
|
||||
"name_table_header": "الاِسْم",
|
||||
"enabled_table_header": "تمكين",
|
||||
"name_table_header": "الاسم",
|
||||
"list_url_table_header": "قائمة الروابط",
|
||||
"rules_count_table_header": "عدد القواعد",
|
||||
"last_time_updated_table_header": "آخر تحديث",
|
||||
@@ -236,7 +225,6 @@
|
||||
"updated_upstream_dns_toast": "تم حفظ خوادم Upstream بنجاح",
|
||||
"dns_test_ok_toast": "تعمل خوادم DNS المحددة بشكل صحيح",
|
||||
"dns_test_not_ok_toast": "خادم \"{{key}}\": لا يمكن استخدامه يرجى التحقق من كتابته بشكل صحيح",
|
||||
"dns_test_parsing_error_toast": "القسم {{section}}: السطر {{line}}: لا يمكن استخدامه، يرجى التحقق من أنك قد كتبته بشكل صحيح",
|
||||
"dns_test_warning_toast": "المنبع \"{{key}}\" لا يستجيب لطلبات الاختبار وقد لا يعمل بشكل صحيح",
|
||||
"unblock": "إلغاء الحظر",
|
||||
"block": "حظر",
|
||||
@@ -244,8 +232,7 @@
|
||||
"allow_this_client": "السماح لهذا العميل",
|
||||
"block_for_this_client_only": "احجب هذا العميل فقط",
|
||||
"unblock_for_this_client_only": "إلغاء حجب هذا العميل فقط",
|
||||
"add_persistent_client": "إضافة كعميل دائم",
|
||||
"time_table_header": "الوقت",
|
||||
"time_table_header": "وقت",
|
||||
"date": "التاريخ",
|
||||
"domain_name_table_header": "اسم النطاق",
|
||||
"domain_or_client": "الدومين أو العميل",
|
||||
@@ -260,7 +247,7 @@
|
||||
"refresh_btn": "تحديث",
|
||||
"previous_btn": "السابق",
|
||||
"next_btn": "التالي",
|
||||
"loading_table_status": "التحميل جارٍ...",
|
||||
"loading_table_status": "جار التحميل...",
|
||||
"page_table_footer_text": "الصفحة",
|
||||
"rows_table_footer_text": "صفوف",
|
||||
"updated_custom_filtering_toast": "تحديث قواعد الفلترة المخصصة",
|
||||
@@ -272,12 +259,12 @@
|
||||
"query_log_cleared": "تم مسح سجل الاستعلام بنجاح",
|
||||
"query_log_updated": "تم تحديث سجل الاستعلام بنجاح",
|
||||
"query_log_clear": "مسح سجلات الاستعلام",
|
||||
"query_log_retention": "تناوب سجلات الاستعلام",
|
||||
"query_log_retention": "الاحتفاظ بسجلات الاستعلام",
|
||||
"query_log_enable": "تمكين السجل",
|
||||
"query_log_configuration": "تكوين السجلات",
|
||||
"query_log_disabled": "سجل الاستعلام معطل ويمكن تهيئته من<0>الاعدادات</0>",
|
||||
"query_log_strict_search": "استخدم علامات الاقتباس المزدوجة للبحث الدقيق",
|
||||
"query_log_retention_confirm": "هل أنت متيقِّن من أنك تريد تغيير دوران سجل الاستعلام؟ إذا قمت بتقليل قيمة الفاصل الزمني، ستفقد بعض البيانات",
|
||||
"query_log_retention_confirm": "هل أنت متأكد من أنك تريد تغيير الاحتفاظ بسجل الاستعلام؟ إذا قمت بتقليل قيمة الفاصل الزمني سيتم فقدان بعض البيانات",
|
||||
"anonymize_client_ip": "إخفاء عنوان IP العميل",
|
||||
"anonymize_client_ip_desc": "لا تقم بحفظ كامل عنوان IP العميل في السجلات والإحصائيات",
|
||||
"dns_config": "إعداد خادم DNS",
|
||||
@@ -291,9 +278,7 @@
|
||||
"custom_ip": "عنوان IP مخصص",
|
||||
"blocking_ipv4": "حجب عنوان IPv4",
|
||||
"blocking_ipv6": "حجب عنوان IPv6",
|
||||
"blocked_response_ttl": "حظر استجابة TTL",
|
||||
"blocked_response_ttl_desc": "تحديد عدد الثواني التي يجب على العملاء تخزين الاستجابة التي تمت تصفيتها مؤقتًا",
|
||||
"form_enter_blocked_response_ttl": "أدخل وقت الاستجابة المحظورة TTL (بالثواني)",
|
||||
"blocked_response_ttl": "زمن حظر الاستجابة",
|
||||
"dnscrypt": "DNSCrypt",
|
||||
"dns_over_https": "DNS-over-HTTPS",
|
||||
"dns_over_tls": "DNS-over-TLS",
|
||||
@@ -309,19 +294,7 @@
|
||||
"rate_limit": "حدود التقييم",
|
||||
"edns_enable": "فعل EDNS client subnet",
|
||||
"edns_cs_desc": "أضف EDNS الشبكة الفرعية للعميل (ECS) إلى الطلبات الأولية وقم بتسجيل القيم المرسلة من قبل العملاء في سجل الاستعلام.",
|
||||
"edns_use_custom_ip": "استخدام IP مخصص لـ EDNS",
|
||||
"edns_use_custom_ip_desc": "السماح باستخدام IP مخصص لـ EDNS",
|
||||
"rate_limit_desc": "عدد الطلبات في الثانية المسموح بها لكل عميل. جعله على 0 يعني عدم وجود حد.",
|
||||
"rate_limit_subnet_len_ipv4": "طول بادئة الشبكة لعناوين IPv4",
|
||||
"rate_limit_subnet_len_ipv4_desc": "طول بادئة الشبكة لعناوين IPv4 المستخدمة لتحديد معدل الحد الأقصى. الافتراضي هو 24",
|
||||
"rate_limit_subnet_len_ipv4_error": "يجب أن يكون طول بادئة الشبكة IPv4 بين 0 و 32",
|
||||
"rate_limit_subnet_len_ipv6": "طول بادئة الشبكة لعناوين IPv6",
|
||||
"rate_limit_subnet_len_ipv6_desc": "طول بادئة الشبكة لعناوين IPv6 المستخدمة لتحديد معدل الحد الأقصى. الافتراضي هو 56",
|
||||
"rate_limit_subnet_len_ipv6_error": "يجب أن يكون طول بادئة الشبكة IPv6 بين 0 و 128",
|
||||
"form_enter_rate_limit_subnet_len": "أدخل طول بادئة الشبكة الفرعية لتحديد معدل الحد الأقصى",
|
||||
"rate_limit_whitelist": "قائمة السماح بتحديد معدل الحد الأقصى",
|
||||
"rate_limit_whitelist_desc": "عناوين IP المستبعدة من تحديد معدل الحد الأقصى",
|
||||
"rate_limit_whitelist_placeholder": "أدخل عنوان IP واحد لكل سطر",
|
||||
"blocking_ipv4_desc": "سيتم إرجاع عنوان IP لطلب محظور",
|
||||
"blocking_ipv6_desc": "سيتم إرجاع عنوان IP لطلب AAAA محظور",
|
||||
"blocking_mode_default": "الافتراضي: الرد بعنوان IP صفري (0.0.0.0 لـ A ؛ :: لـ AAAA) عند حظره بواسطة قاعدة نمط Adblock ؛ الرد بعنوان IP المحدد في القاعدة عند حظره بواسطة / etc / hosts-style rule",
|
||||
@@ -329,15 +302,14 @@
|
||||
"blocking_mode_nxdomain": "NXDOMAIN: الرد باستخدام رمز NXDOMAIN",
|
||||
"blocking_mode_null_ip": "IP Null: الاستجابة بعنوان IP صفري (0.0.0.0 لـ A ؛ :: لـ AAAA)",
|
||||
"blocking_mode_custom_ip": "استجابة IP مخصصة بعنوان IP تم تعيينه يدويًا",
|
||||
"theme_auto": "تلقائي",
|
||||
"theme_light": "فاتح",
|
||||
"theme_dark": "داكن",
|
||||
"theme_dark": "ليلي",
|
||||
"upstream_dns_client_desc": "إذا احتفظت بهذا الحقل فارغًا ، فسيستخدم AdGuard Home الخوادم التي تم تكوينها في<0>DNS إعدادات</0>.",
|
||||
"tracker_source": "مصدر المتعقب",
|
||||
"source_label": "المصدر",
|
||||
"found_in_known_domain_db": "تم العثور عليه في قاعدة بيانات دومينات معروفة.",
|
||||
"category_label": "الفئة",
|
||||
"rule_label": "قاعدة (قواعد)",
|
||||
"rule_label": "قواعد",
|
||||
"list_label": "قائمه",
|
||||
"unknown_filter": "فلتر غير معروف {{filterId}}",
|
||||
"known_tracker": "متعقب معروف",
|
||||
@@ -348,14 +320,14 @@
|
||||
"install_settings_port": "المنفذ",
|
||||
"install_settings_interface_link": "ستكون واجهة الويب الخاصة بمسؤول AdGuard Home متاحة على العناوين التالية:",
|
||||
"form_error_port": "أدخل رقم منفذ صالح",
|
||||
"install_settings_dns": "خَادِم DNS",
|
||||
"install_settings_dns": "خادم DNS",
|
||||
"install_settings_dns_desc": "ستحتاج إلى ضبط أجهزتك أو جهاز التوجيه الخاص بك لاستخدام خادم DNS على العناوين التالية:",
|
||||
"install_settings_all_interfaces": "جميع الواجهات",
|
||||
"install_auth_title": "المصادقة",
|
||||
"install_auth_desc": "يجب إعداد مصادقة كلمة المرور لواجهة ويب مسؤول AdGuard Home. في حال كان AdGuard Home لا يمكن الوصول إليه إلا في شبكتك المحلية ، فلا يزال من المهم حمايته من الوصول غير المقيد.",
|
||||
"install_auth_username": "اسم المستخدم",
|
||||
"install_auth_password": "الكلمة السرية",
|
||||
"install_auth_confirm": "تأكيد كلمة المرور",
|
||||
"install_auth_confirm": "تاكيد كلمه المرور",
|
||||
"install_auth_username_enter": "أدخل اسم المستخدم",
|
||||
"install_auth_password_enter": "أدخل كلمة المرور",
|
||||
"install_step": "خطوة",
|
||||
@@ -425,9 +397,6 @@
|
||||
"encryption_hostnames": "اسم المستضيف",
|
||||
"encryption_reset": "هل أنت متأكد أنك تريد إعادة تعيين إعدادات التشفير؟",
|
||||
"encryption_warning": "تحذير",
|
||||
"encryption_plain_dns_enable": "تمكين DNS العادي",
|
||||
"encryption_plain_dns_desc": "الـDNS العادي مفعل افتراضيًا. يمكنك تعطيله لإجبار جميع الأجهزة على استخدام DNS المشفر. للقيام بذلك، يجب عليك تفعيل بروتوكول DNS المشفر على الأقل",
|
||||
"encryption_plain_dns_error": "لتعطيل DNS العادي، قم بتمكين بروتوكول DNS المشفر على الأقل",
|
||||
"topline_expiring_certificate": "شهادة SSL الخاصة بك على وشك الانتهاء. قم بتحديث <0>إعدادات التشفير</0>.",
|
||||
"topline_expired_certificate": "انتهت صلاحية شهادة SSL الخاصة بك. قم بتحديث <0>إعدادات التشفير</0>.",
|
||||
"form_error_port_range": "أدخل رقم المنفذ في النطاق 80-65535",
|
||||
@@ -467,7 +436,6 @@
|
||||
"form_add_id": "أضافة معّرف",
|
||||
"form_client_name": "ادخل اسم العميل",
|
||||
"name": "اسم",
|
||||
"client_name": "العميل {{id}}",
|
||||
"client_global_settings": "استخدم إعدادات عالمية",
|
||||
"client_deleted": "تم حذف العميل \"{{key}}\" بنجاح",
|
||||
"client_added": "تم اضافة العميل \"{{key}}\" بنجاح",
|
||||
@@ -476,7 +444,7 @@
|
||||
"client_confirm_delete": "هل أنت متأكد من أنك تريد حذف العميل \"{{key}}\"?",
|
||||
"list_confirm_delete": "هل أنت متأكد أنك تريد حذف هذه القائمة؟",
|
||||
"auto_clients_title": "Runtime clients",
|
||||
"auto_clients_desc": "معلومات حول عناوين IP للأجهزة التي تستخدم أو قد تستخدم AdGuard Home. يتم جمع هذه المعلومات من عدة مصادر، بما في ذلك ملفات المضيفين، و DNS العكسي، إلخ.",
|
||||
"auto_clients_desc": "الأجهزة غير المدرجة في قائمة العملاء الدائمين الذين قد لا يزالون يستخدمون AdGuard Home",
|
||||
"access_title": "إعدادات الوصول",
|
||||
"access_desc": "هنا يمكنك ضبط قواعد الوصول لخادم AdGuard Home DNS",
|
||||
"access_allowed_title": "العملاء المسموحين",
|
||||
@@ -489,7 +457,6 @@
|
||||
"updates_checked": "يتوفر إصدار جديد من AdGuard Home",
|
||||
"updates_version_equal": "AdGuard Home محدث",
|
||||
"check_updates_now": "تحقق من وجود تحديثات الآن",
|
||||
"version_request_error": "فشل التحقق من التحديث. يرجى التحقق من اتصالك بالإنترنت.",
|
||||
"dns_privacy": "خصوصية DNS",
|
||||
"setup_dns_privacy_1": "<0> DNS-over-TLS: </0> استخدم سلسلة <1> {{address}} </1>.",
|
||||
"setup_dns_privacy_2": "<0> DNS-over-HTTPS: </0> استخدم سلسلة <1> {{address}} </1>.",
|
||||
@@ -510,9 +477,7 @@
|
||||
"setup_dns_notice": "من أجل استخدام <0> DNS-over-HTTPS </0> أو <1> DNS-over-TLS </1> ، تحتاج إلى <1> تكوين التشفير </1> في إعدادات AdGuard Home.",
|
||||
"rewrite_added": "تمت إضافة إعادة كتابة DNS لـ \"{{key}}\" بنجاح",
|
||||
"rewrite_deleted": "تم حذف إعادة كتابة DNS لـ \"{{key}}\" بنجاح",
|
||||
"rewrite_updated": "تم تحديث إعادة كتابة DNS بنجاح",
|
||||
"rewrite_add": "إضافة إعادة كتابة DNS",
|
||||
"rewrite_edit": "تحرير إعادة كتابة DNS",
|
||||
"rewrite_not_found": "لم يتم العثور على إعادة كتابة DNS",
|
||||
"rewrite_confirm_delete": "هل أنت متأكد من أنك تريد حذف إعادة كتابة DNS لـ \"{{key}}\"؟",
|
||||
"rewrite_desc": "يسمح بتكوين استجابة DNS المخصصة بسهولة لاسم نطاق معين.",
|
||||
@@ -541,7 +506,7 @@
|
||||
"encryption_key_source_content": "الصق محتويات المفتاح الخاص",
|
||||
"stats_params": "ضبط الاحصائيات",
|
||||
"config_successfully_saved": "تم حفظ الاعدادات بنجاح",
|
||||
"interval_6_hour": "6 ساعات",
|
||||
"interval_6_hour": "ساعات6",
|
||||
"interval_24_hour": "24 ساعة",
|
||||
"interval_days": "{{count}} يوم",
|
||||
"interval_days_plural": "{{count}} الأيام",
|
||||
@@ -552,18 +517,14 @@
|
||||
"filter_added_successfully": "تم إضافة القائمة بنجاح",
|
||||
"filter_removed_successfully": "تم ازالته من القائمة بنجاح",
|
||||
"filter_updated": "تم تحديث القائمة بنجاح",
|
||||
"statistics_configuration": "تكوين الإحصائيات",
|
||||
"statistics_configuration": "ضبط الاحصائيات",
|
||||
"statistics_retention": "الاحتفاظ بالإحصاءات",
|
||||
"statistics_retention_desc": "إذا قمت بتقليل قيمة الفاصل الزمني ، فستفقد بعض البيانات",
|
||||
"statistics_clear": "إعادة تعيين الإحصائيات",
|
||||
"statistics_clear_confirm": "هل أنت متيقِّن من أنك تريد مسح الإحصائيات؟",
|
||||
"statistics_clear_confirm": "هل أنت متأكد من أنك تريد مسح الإحصاءات؟",
|
||||
"statistics_retention_confirm": "هل أنت متأكد أنك تريد تغيير الاحتفاظ بالإحصاءات؟ إذا قمت بتقليل قيمة الفاصل الزمني ، فستفقد بعض البيانات",
|
||||
"statistics_cleared": "تم مسح الإحصائيات بنجاح",
|
||||
"statistics_enable": "تفعيل الاحصائيات",
|
||||
"ignore_domains": "المجالات التي تم تجاهلها (مفصولة بسطر جديد)",
|
||||
"ignore_domains_title": "نطاقات تم تجاهلها",
|
||||
"ignore_domains_desc_stats": "لا تتم كتابة الاستعلامات المطابقة لهذه القواعد في الإحصائيات",
|
||||
"ignore_domains_desc_query": "لا تتم كتابة الاستعلامات المطابقة لهذه القواعد في سجل الاستعلامات",
|
||||
"interval_hours": "{{count}} ساعة",
|
||||
"interval_hours_plural": "{{count}} ساعات",
|
||||
"filters_configuration": "اضبط الفلاتر",
|
||||
@@ -636,20 +597,20 @@
|
||||
"dnssec_enable_desc": "قم بتعيين علامة DNSSEC في استعلامات DNS الواردة وتحقق من النتيجة (مطلوب محلل يدعم DNSSEC).",
|
||||
"validated_with_dnssec": "تم التحقق من صحتها باستخدام DNSSEC",
|
||||
"all_queries": "كافة الاستفسارات",
|
||||
"show_blocked_responses": "ما تمّ حظره",
|
||||
"show_whitelisted_responses": "المسموح به",
|
||||
"show_processed_responses": "تمت معالجتها",
|
||||
"show_blocked_responses": "حظر",
|
||||
"show_whitelisted_responses": "القائمة البيضاء",
|
||||
"show_processed_responses": "معالجة",
|
||||
"blocked_safebrowsing": "محظور بواسطة التصفح الآمن",
|
||||
"blocked_adult_websites": "محظور بواسطة الرِّقابة الأبوية",
|
||||
"blocked_adult_websites": "محظور بواسطة الرقابة الأبوية",
|
||||
"blocked_threats": "التهديدات المحظورة",
|
||||
"allowed": "المسموح به",
|
||||
"allowed": "القائمة البيضاء",
|
||||
"filtered": "تمت الفلترة",
|
||||
"rewritten": "أعيدت كتابته",
|
||||
"safe_search": "البحث الآمن",
|
||||
"safe_search": "البحث الأمن",
|
||||
"blocklist": "قائمة الحظر",
|
||||
"milliseconds_abbreviation": "ms",
|
||||
"cache_size": "حجم ذاكرة التخزين المؤقت",
|
||||
"cache_size_desc": "حجم ذاكرة التخزين المؤقت لنظام أسماء النطاق (بالبايت). لتعطيل التخزين المؤقت، اتركه فارغًا.",
|
||||
"cache_size_desc": "حجم ذاكرة التخزين المؤقت لنظام أسماء النطاقات (بالبايت).",
|
||||
"cache_ttl_min_override": "تجاوز الحد الأدنى من مدة البقاء TTL",
|
||||
"cache_ttl_max_override": "تجاوز الحد الاقصى من مدة البقاء TTL",
|
||||
"enter_cache_size": "أدخل حجم ذاكرة التخزين المؤقت (بايت)",
|
||||
@@ -660,14 +621,14 @@
|
||||
"ttl_cache_validation": "يجب أن يكون الحد الأدنى لتجاوز TTL لذاكرة التخزين المؤقت أقل من أو يساوي الحد الأقصى",
|
||||
"cache_optimistic": "متفائل التخزين المؤقت",
|
||||
"cache_optimistic_desc": "اجعل AdGuard Home يستجيب من ذاكرة التخزين المؤقت حتى عندما تنتهي صلاحية الإدخالات وحاول أيضًا تحديثها.",
|
||||
"filter_category_general": "عام",
|
||||
"filter_category_security": "الأمان",
|
||||
"filter_category_general": "General",
|
||||
"filter_category_security": "الامان",
|
||||
"filter_category_regional": "إقليمي",
|
||||
"filter_category_other": "أخرى",
|
||||
"filter_category_general_desc": "القوائم التي تحظر التتبع والإعلانات على معظم الأجهزة",
|
||||
"filter_category_general_desc": "القوائم التي تمنع التتبع والإعلان على معظم الأجهزة",
|
||||
"filter_category_security_desc": "القوائم المصممة خصيصًا لحظر النطاقات الخبيثة والتصيد الاحتيالي والخداع",
|
||||
"filter_category_regional_desc": "القوائم التي تركز على الإعلانات الإقليمية وخوادم التتبع",
|
||||
"filter_category_other_desc": "قوائم الحظر الأخرى",
|
||||
"filter_category_other_desc": "قوائم حظر أخرى",
|
||||
"setup_config_to_enable_dhcp_server": "أضبط الاعدادات لتمكين خادم DHCP",
|
||||
"original_response": "الرد الأصلي",
|
||||
"click_to_view_queries": "انقر لعرض الـ queries",
|
||||
@@ -676,72 +637,16 @@
|
||||
"filter_allowlist": "تحذير: سيؤدي هذا الإجراء أيضًا إلى استبعاد القاعدة \"{{disallowed_rule}}\" من قائمة العملاء المسموح لهم.",
|
||||
"last_rule_in_allowlist": "لا يمكن منع هذا العميل لأن استبعاد القاعدة \"{{disallowed_rule}}\" سيؤدي إلى تعطيل قائمة \"العملاء المسموح لهم\".",
|
||||
"use_saved_key": "استخدم المفتاح المحفوظ مسبقًا",
|
||||
"parental_control": "الرِّقابة الأبوية",
|
||||
"parental_control": "الرقابة الابويه",
|
||||
"safe_browsing": "تصفح آمن",
|
||||
"served_from_cache_label": "يتم تقديمه من ذاكرة التخزين المؤقت",
|
||||
"form_error_password_length": "يجب أن تتكون كلمة المرور من {{min}} إلى {{max}} من الأحرف في الأقل",
|
||||
"anonymizer_notification": "<0>ملاحظة:</0> تم تمكين إخفاء هُوِيَّة IP. يمكنك تعطيله في <1>الإعدادات العامة</1>.",
|
||||
"confirm_dns_cache_clear": "هل تريد بالتأكيد مسح ذاكرة التخزين المؤقت لنظام أسماء النطاقات DNS؟",
|
||||
"cache_cleared": "تم مسح ذاكرة التخزين المؤقت لنظام أسماء النطاق بنجاح",
|
||||
"clear_cache": "مسح ذاكرة التخزين المؤقت",
|
||||
"make_static": "اجعلها ثابتة",
|
||||
"theme_auto_desc": "تلقائي (بناءً على نظام ألوان جهازك)",
|
||||
"theme_dark_desc": "المظهر الداكن",
|
||||
"theme_light_desc": "المظهر فاتح",
|
||||
"disable_for_seconds": "لـ {{count}} ثانية",
|
||||
"disable_for_seconds_plural": "لمدة {{count}} ثانية",
|
||||
"disable_for_minutes": "لمدة {{count}} دقيقة",
|
||||
"disable_for_minutes_plural": "لمدة {{count}} دقيقة",
|
||||
"disable_for_hours": "لمدة {{count}} ساعة",
|
||||
"disable_for_hours_plural": "لمدة {{count}} ساعات",
|
||||
"disable_until_tomorrow": "حتى الغد",
|
||||
"disable_notify_for_seconds": "تعطيل الحماية لـ {{count}} ثانية",
|
||||
"disable_notify_for_seconds_plural": "تعطيل الحماية ل {{count}} ثواني",
|
||||
"disable_notify_for_minutes": "تعطيل الحماية لـ {{count}} دقيقة",
|
||||
"disable_notify_for_minutes_plural": "تعطيل الحماية لـ {{count}} دقائق",
|
||||
"disable_notify_for_hours": "تعطيل الحماية لـ {{count}} ساعة",
|
||||
"disable_notify_for_hours_plural": "تعطيل الحماية لـ {{count}} ساعات",
|
||||
"disable_notify_until_tomorrow": "تعطيل الحماية حتى الغد",
|
||||
"enable_protection_timer": "سيتم تمكين الحماية في {{time}}",
|
||||
"custom_retention_input": "أدخل الاحتفاظ بالساعات",
|
||||
"custom_rotation_input": "أدخل التناوب بالساعات",
|
||||
"served_from_cache": "{{value}} <i>(يتم تقديمه من ذاكرة التخزين المؤقت)</i>",
|
||||
"form_error_password_length": "يجب أن تتكون كلمة المرور من {{value}} من الأحرف على الأقل",
|
||||
"protection_section_label": "الحماية",
|
||||
"log_and_stats_section_label": "سجل الاستعلام والإحصائيات",
|
||||
"ignore_query_log": "تجاهل هذا العميل في سجل الاستعلام",
|
||||
"ignore_statistics": "تجاهل هذا العميل في الإحصائيات",
|
||||
"schedule_services": "إيقاف حظر الخدمة مؤقتًا",
|
||||
"schedule_services_desc": "تهيئة جدول إيقاف فلتر خدمة الحظر",
|
||||
"schedule_services_desc_client": "تهيئة جدول إيقاف فلتر خدمة الحظر لهذا العميل",
|
||||
"schedule_desc": "تعيين فترات عدم النشاط للخدمات المحظورة",
|
||||
"schedule_invalid_select": "يجب أن يكون وقت البَدْء قبل وقت الانتهاء",
|
||||
"schedule_select_days": "اختر الأيام",
|
||||
"schedule_timezone": "قم باختيار منطقة زمنية",
|
||||
"schedule_current_timezone": "المنطقة الزمنية الحالية: {{value}}",
|
||||
"schedule_time_all_day": "طوال اليوم",
|
||||
"schedule_modal_description": "سيحل هذا الجدول الزمني محل أي جداول موجودة لنفس اليوم من الأسبوع. يمكن أن يكون لكل يوم من أيام الأسبوع مدّة خمول واحدة فقط.",
|
||||
"schedule_modal_time_off": "لا يوجد حظر للخدمة:",
|
||||
"schedule_new": "جدول زمني جديد",
|
||||
"schedule_edit": "تحرير الجدول الزمني",
|
||||
"schedule_save": "حفظ الجدول الزمني",
|
||||
"schedule_add": "إضافة جدول زمني",
|
||||
"schedule_remove": "إزالة الجدول الزمني",
|
||||
"schedule_from": "من",
|
||||
"schedule_to": "إلى",
|
||||
"sunday": "الأحد",
|
||||
"monday": "الإثنين",
|
||||
"tuesday": "الثلاثاء",
|
||||
"wednesday": "الأربعاء",
|
||||
"thursday": "الخميس",
|
||||
"friday": "الجمعة",
|
||||
"saturday": "السبت",
|
||||
"sunday_short": "الأحد",
|
||||
"sunday_short": "الاحد",
|
||||
"monday_short": "الإثنين",
|
||||
"tuesday_short": "الثلاثاء",
|
||||
"wednesday_short": "الأربعاء",
|
||||
"wednesday_short": "الاربعاء",
|
||||
"thursday_short": "الخميس",
|
||||
"friday_short": "الجمعة",
|
||||
"saturday_short": "السبت",
|
||||
"upstream_dns_cache_configuration": "تهيئة ذاكرة التخزين المؤقت لنظام أسماء النطاقات المستقبلي",
|
||||
"enable_upstream_dns_cache": "تمكين التخزين المؤقت لنظام أسماء النطاقات DNS لتكوين المنبع المخصص لهذا العميل",
|
||||
"dns_cache_size": "حجم ذاكرة التخزين المؤقت لنظام أسماء النطاقات، بالبايت"
|
||||
"saturday_short": "السبت"
|
||||
}
|
||||
|
||||
@@ -159,8 +159,6 @@
|
||||
"dns_over_https": "DNS-пред-HTTPS",
|
||||
"dns_over_quic": "DNS-over-QUIC",
|
||||
"plain_dns": "Обикновен DNS",
|
||||
"theme_light": "Светла тема",
|
||||
"theme_dark": "Тъмна тема",
|
||||
"source_label": "Източник",
|
||||
"found_in_known_domain_db": "Намерен в списъците с домейни.",
|
||||
"category_label": "Категория",
|
||||
@@ -285,12 +283,5 @@
|
||||
"filter_category_general": "General",
|
||||
"filter_category_security": "Сигурност",
|
||||
"port_53_faq_link": "Порт 53 често е зает от \"DNSStubListener\" или \"systemd-resolved\" услуги. Моля, прочетете <0>тази инструкция</0> как да решите това.",
|
||||
"parental_control": "Родителски контрол",
|
||||
"sunday_short": "Нд",
|
||||
"monday_short": "Пон",
|
||||
"tuesday_short": "Вт",
|
||||
"wednesday_short": "Ср",
|
||||
"thursday_short": "Чт",
|
||||
"friday_short": "Пт",
|
||||
"saturday_short": "Съб"
|
||||
"parental_control": "Родителски контрол"
|
||||
}
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Použijte paralelní požadavky na urychlení řešení simultánním dotazováním na všechny navazující servery.",
|
||||
"parallel_requests": "Paralelní požadavky",
|
||||
"load_balancing": "Optimalizace vytížení",
|
||||
"load_balancing_desc": "Dotazy jednoho odchozího serveru ve stejný čas. AdGuard Home používá náhodný algoritmus pro výběr serverů s nejnižším počtem neúspěšných vyhledávání a nejnižší průměrnou dobou vyhledávání.",
|
||||
"load_balancing_desc": "Optimalizovaný dotaz na odchozí server. AdGuard Home použije vážený náhodný algoritmus k výběru serveru, takže nejrychlejší server je používán častěji.",
|
||||
"bootstrap_dns": "Bootstrap DNS servery",
|
||||
"bootstrap_dns_desc": "IP adresy DNS serverů používaných k překladu IP adres řešitelů DoH/DoT, které zadáte jako odchozí servery. Komentáře nejsou povoleny.",
|
||||
"fallback_dns_title": "Záložní DNS servery",
|
||||
"fallback_dns_desc": "Seznam záložních DNS serverů používaných v případě, že odchozí DNS servery neodpovídají. Syntaxe je stejná jako v hlavním poli pro odchozí servery výše.",
|
||||
"fallback_dns_placeholder": "Zadejte jeden záložní DNS server na řádek",
|
||||
"local_ptr_title": "Soukromé reverzní DNS servery",
|
||||
"local_ptr_desc": "DNS servery používané AdGuard Home pro soukromé požadavky PTR, SOA a NS. Požadavek je považován za soukromý, pokud požaduje doménu ARPA obsahující podsíť v rámci soukromých IP rozsahů (například \"192.168.12.34\") a pochází od klienta se soukromou IP adresou. Pokud není nastaveno, budou použity výchozí DNS řešitele vašeho operačního systému, s výjimkou IP adres AdGuard Home.",
|
||||
"local_ptr_desc": "Servery DNS, které AdGuard Home používá pro lokální dotazy PTR. Tyto servery se používají k řešení požadavků PTR na adresy v soukromých rozmezích IP, například \"192.168.12.34\", pomocí reverzního DNS. Pokud není nastaveno, AdGuard Home automaticky použije výchozí řešitele vašeho OS s výjimkou adres samotného AdGuard Home.",
|
||||
"local_ptr_default_resolver": "Ve výchozím nastavení používá AdGuard Home následující reverzní DNS řešitele: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home nemohl určit vhodné soukromé reverzní DNS řešitele pro tento systém.",
|
||||
"local_ptr_placeholder": "Zadejte jednu IP adresu na řádek",
|
||||
"resolve_clients_title": "Povolit zpětné řešení IP adres klientů",
|
||||
"resolve_clients_desc": "Obráceně vyřešit IP adresy klientů na jejich názvy hostitelů zasláním dotazů PTR příslušným řešitelům (soukromé DNS servery pro místní klienty, odchozí servery pro klienty s veřejnou IP adresou).",
|
||||
"use_private_ptr_resolvers_title": "Použít soukromé reverzní rDNS řešitele",
|
||||
"use_private_ptr_resolvers_desc": "Řešení požadavků PTR, SOA a NS pro domény ARPA obsahující soukromé IP adresy prostřednictvím soukromých odchozích serverů, DHCP, /etc/hosts atd. Pokud je zakázáno, AdGuard Home bude na všechny takové požadavky odpovídat pomocí NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Realizuje reverzní DNS vyhledávání pro lokální adresy pomocí těchto odchozích serverů. Pokud je funkce vypnuta, Adguard Home reaguje s NXDOMAIN na všechny takové PTR dotazy kromě klientů známých z DHCP, /etc/hosts, atd.",
|
||||
"check_dhcp_servers": "Zkontrolovat DHCP servery",
|
||||
"save_config": "Uložit konfiguraci",
|
||||
"enabled_dhcp": "DHCP server zapnutý",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Použít službu AdGuard Rodičovská kontrola",
|
||||
"use_adguard_parental_hint": "AdGuard Home zkontroluje, zda doména obsahuje materiály pro dospělé. Používá stejné API přátelské k ochraně osobních údajů jako služba Bezpečnost prohlížení.",
|
||||
"enforce_safe_search": "Použít bezpečné vyhledávání",
|
||||
"enforce_save_search_hint": "AdGuard Home vynutí bezpečné vyhledávání v následujících vyhledávačích: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home vynutí bezpečné vyhledávání v následujících vyhledávačích: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Nebyly specifikovány žádné servery",
|
||||
"general_settings": "Obecná nastavení",
|
||||
"dns_settings": "Nastavení DNS",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Brug parallelforespørgsler til at accelerere fortolkningen ved at forespørge alle upstream-servere samtidigt.",
|
||||
"parallel_requests": "Parallelle forespørgsler",
|
||||
"load_balancing": "Belastningsfordeling",
|
||||
"load_balancing_desc": "Forespørg én upstream-server ad gangen. AdGuard Home bruger en vægtet tilfældighedsalgoritme til vælg af servere med det laveste antal fejlslagne opslag og den laveste gennemsnitlige opslagstid.",
|
||||
"load_balancing_desc": "Forespørg én server ad gangen. AdGuard Home vil bruge en vægtet randomiseringsalgoritme til valg af server, så den hurtigste server oftere anvendes.",
|
||||
"bootstrap_dns": "Bootstrap DNS-servere",
|
||||
"bootstrap_dns_desc": "IP-adresser på DNS-servere, som bruges til at opløse IP-adresser på de DoH/DoT-opløsere, som angives som upstreams. Kommentarer er ikke tilladt.",
|
||||
"fallback_dns_title": "Reserve DNS-servere",
|
||||
"fallback_dns_desc": "Liste over reserve (fallback) DNS-servere, som bruges, når upstream DNS-servere ikke reagerer. Samme syntaks som i upstream-hovedfeltet ovenfor.",
|
||||
"fallback_dns_placeholder": "Angiv én reserve DNS-server pr. linje",
|
||||
"local_ptr_title": "Private reverse DNS-servere",
|
||||
"local_ptr_desc": "DNS-serverne brugt af AdGuard Home til private PTR-, SOA- og NS-forespørgsler. En forespørgsel anses som privat, hvis den omhandler et ARPA-domæne indeholdende et undernet i et privat IP-områder, (såsom \"192.168.12.34\") og kommer fra en klient med en privat adresse. Hvis ikke opsat, bruger AdGuard Home OS'ets adresser på standard DNS-opløserne, bortset fra AdGuard Home-adresserne.",
|
||||
"local_ptr_desc": "DNS-servere brugt af AdGuard Home til lokale PTR-forespørgsler. Disse servere bruges til at opløse PTR-forespørgsler fra private IP-adresseområder, f.eks. \"192.168.12.34\", vha. reverse DNS. Hvis ikke opsat, bruger AdGuard Home operativsystems standard DNS-opløsere undtagen for sine egne adresser.",
|
||||
"local_ptr_default_resolver": "AdGuard Home bruger som standard flg. reverse DNS-opløsere: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home kunne ikke fastslå egnede private reverse DNS-opløsere for dette system.",
|
||||
"local_ptr_placeholder": "Angiv én IP-adresse pr. linje",
|
||||
"resolve_clients_title": "Aktivér omvendt løsning af klienters IP-adresser",
|
||||
"resolve_clients_desc": "Opløs klienters IP-adresser reverseret til deres værtsnavne ved at sende PTR-forespørgsler til korresponderende opløsere (private DNS-servere til lokale klienter, upstream-servere til klienter med offentlige IP-adresser).",
|
||||
"use_private_ptr_resolvers_title": "Brug private reverse DNS-opløsere",
|
||||
"use_private_ptr_resolvers_desc": "Opløs PTR-, SOA- og NS-forespørgsler til ARPA-domæner indeholdende private adresser vha. private upstream-servere, DHCP, /etc/hosts mv. Hvis deaktiveret, besvarer AdGuard Home sådanne forespørgsler med NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Udfør reverse DNS-opslag for lokalt leverede adresser vha. disse upstream-servere. Hvis deaktiveret, svarer AdGuard Home med NXDOMAIN på alle sådanne PTR-forespørgsler bortset fra for klienter kendt via DHCP, /etc/hosts mv.",
|
||||
"check_dhcp_servers": "Søg efter DHCP-servere",
|
||||
"save_config": "Gem opsætning",
|
||||
"enabled_dhcp": "DHCP-server aktiveret",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Brug AdGuards forældrekontrolwebtjeneste",
|
||||
"use_adguard_parental_hint": "AdGuard Home vil tjekke, om domænet indeholder voksenindhold vha. den samme fortrolighedsvenlige API som browsingsikkerhedswebtjenesten.",
|
||||
"enforce_safe_search": "Brug sikker søgning",
|
||||
"enforce_save_search_hint": "AdGuard Home vil håndhæve sikker søgning i flg. søgemaskiner: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home vil håndhæve sikker søgning i flg. søgemaskiner: Google, YouTube, Bing, DuckDuckGo, Yandex og Pixabay.",
|
||||
"no_servers_specified": "Ingen servere angivet",
|
||||
"general_settings": "Generelle indstillinger",
|
||||
"dns_settings": "DNS-indstillinger",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Parallele Abfragen verwenden, um das Auflösen zu beschleunigen, indem alle Upstream-Server gleichzeitig abgefragt werden.",
|
||||
"parallel_requests": "Paralleles Abfragen",
|
||||
"load_balancing": "Lastverteilung",
|
||||
"load_balancing_desc": "Es wird jeweils ein Upstream-Server abgefragt. AdGuard Home verwendet einen gewichteten Zufallsalgorithmus, um die Server mit der geringsten Anzahl an fehlgeschlagenen Suchvorgängen und der niedrigsten durchschnittlichen Suchzeit auszuwählen.",
|
||||
"load_balancing_desc": "Einen Server nach dem anderen abfragen. AdGuard Home verwendet den gewichteten Zufallsalgorithmus, um den Server so auszuwählen, dass der schnellste Server häufiger verwendet wird.",
|
||||
"bootstrap_dns": "Bootstrap-DNS-Server",
|
||||
"bootstrap_dns_desc": "IP-Adressen der DNS-Server, die zum Auflösen der IP-Adressen von DoH/DoT Upstream-Servern verwendet werden, die Sie angegeben haben. Kommentare sind nicht erlaubt.",
|
||||
"fallback_dns_title": "Fallback-DNS-Server",
|
||||
"fallback_dns_desc": "Liste der Fallback-DNS-Server, die verwendet werden, wenn die Upstream-DNS-Server nicht antworten. Die Syntax ist die gleiche wie im Hauptfeld für Upstream-Server oben.",
|
||||
"fallback_dns_placeholder": "Geben Sie einen Fallback-DNS-Server pro Zeile ein",
|
||||
"local_ptr_title": "Private inverse DNS-Server",
|
||||
"local_ptr_desc": "Von AdGuard Home verwendete DNS-Server für private PTR-, SOA- und NS-Anfragen. Eine Anfrage gilt als privat, wenn sie nach einer ARPA-Domain fragt, die ein Subnetz innerhalb privater IP-Bereiche enthält (z. B. „192.168.12.34“) und von einem Client mit privater IP-Adresse stammt. Wenn nicht eingestellt, werden die Standard-DNS-Auflöser Ihres Betriebssystems verwendet, außer für die IP-Adressen von AdGuard Home.",
|
||||
"local_ptr_desc": "Die DNS-Server, die AdGuard Home für lokale PTR-Abfragen verwendet. Diese Server werden verwendet, um die Hostnamen von Clients mit privaten IP-Adressen, z. B. „192.168.12.34“, per inverse DNS-Anfragen aufzulösen. Wenn nicht festgelegt, verwendet AdGuard Home die Adressen der Standard-DNS-Auflöser Ihres Betriebssystems mit Ausnahme der Adressen von AdGuard Home selbst.",
|
||||
"local_ptr_default_resolver": "Standardmäßig verwendet AdGuard Home die folgenden inversen DNS-Resolver: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home konnte keine geeigneten privaten Invers-DNS-Resolver für dieses System ermitteln.",
|
||||
"local_ptr_placeholder": "Geben Sie eine IP-Adresse pro Zeile ein",
|
||||
"resolve_clients_title": "Hostnamenauflösung der Clients aktivieren",
|
||||
"resolve_clients_desc": "Inverses Auflösen der IP-Adressen der Clients in ihre Hostnamen durch Senden von PTR-Anfragen an die entsprechenden Resolver (private DNS-Server für lokale Kunden, Upstream-Server für Kunden mit öffentlichen IP-Adressen).",
|
||||
"use_private_ptr_resolvers_title": "Private Reverse-DNS-Resolver verwenden",
|
||||
"use_private_ptr_resolvers_desc": "Löst PTR-, SOA- und NS-Anfragen für ARD-Domains mit privaten IP-Adressen über private Upstream-Server, DHCP, /etc/hosts usw. auf. Ist diese Option deaktiviert, antwortet AdGuard Home auf alle derartigen Anfragen mit NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Führt inverse DNS-Abfragen für lokal bereitgestellte Adressen mit diesen Upstream-Servern durch. Wenn deaktiviert, antwortet AdGuard Home mit NXDOMAIN auf alle solchen PTR-Anfragen, außer für Clients, die über DHCP, /etc/hosts usw. bekannt sind.",
|
||||
"check_dhcp_servers": "Auf DHCP-Server prüfen",
|
||||
"save_config": "Konfiguration speichern",
|
||||
"enabled_dhcp": "DHCP-Server aktiviert",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "AdGuard Webservice für Kindersicherung verwenden",
|
||||
"use_adguard_parental_hint": "AdGuard Home wird prüfen, ob die Domain jugendgefährdende Inhalte enthält. Zum Schutz Ihrer Privatsphäre wird die selbe API wie für den Webservice für Internetsicherheit verwendet.",
|
||||
"enforce_safe_search": "Sichere Suche verwenden",
|
||||
"enforce_save_search_hint": "AdGuard kann Sichere Suche für folgende Suchmaschinen erzwingen: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex und Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard kann Sichere Suche für folgende Suchmaschinen erzwingen: Google, YouTube, Bing, DuckDuckGo, Yandex und Pixabay.",
|
||||
"no_servers_specified": "Keine Server festgelegt",
|
||||
"general_settings": "Allgemeine Einstellungen",
|
||||
"dns_settings": "DNS-Einstellungen",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Use parallel queries to speed up resolving by querying all upstream servers simultaneously.",
|
||||
"parallel_requests": "Parallel requests",
|
||||
"load_balancing": "Load-balancing",
|
||||
"load_balancing_desc": "Query one upstream server at a time. AdGuard Home uses a weighted random algorithm to select servers with the lowest number of failed lookups and the lowest average lookup time.",
|
||||
"load_balancing_desc": "Query one upstream server at a time. AdGuard Home uses its weighted random algorithm to pick the server so that the fastest server is used more often.",
|
||||
"bootstrap_dns": "Bootstrap DNS servers",
|
||||
"bootstrap_dns_desc": "IP addresses of DNS servers used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams. Comments are not permitted.",
|
||||
"fallback_dns_title": "Fallback DNS servers",
|
||||
"fallback_dns_desc": "List of fallback DNS servers used when upstream DNS servers are not responding. The syntax is the same as in the main upstreams field above.",
|
||||
"fallback_dns_placeholder": "Enter one fallback DNS server per line",
|
||||
"local_ptr_title": "Private reverse DNS servers",
|
||||
"local_ptr_desc": "DNS servers used by AdGuard Home for private PTR, SOA, and NS requests. A request is considered private if it asks for an ARPA domain containing a subnet within private IP ranges (such as \"192.168.12.34\") and comes from a client with a private IP address. If not set, the default DNS resolvers of your OS will be used, except for the AdGuard Home IP addresses.",
|
||||
"local_ptr_desc": "The DNS servers that AdGuard Home uses for local PTR queries. These servers are used to resolve PTR requests for addresses in private IP ranges, for example \"192.168.12.34\", using reverse DNS. If not set, AdGuard Home uses the addresses of the default DNS resolvers of your OS except for the addresses of AdGuard Home itself.",
|
||||
"local_ptr_default_resolver": "By default, AdGuard Home uses the following reverse DNS resolvers: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home could not determine suitable private reverse DNS resolvers for this system.",
|
||||
"local_ptr_placeholder": "Enter one IP address per line",
|
||||
"resolve_clients_title": "Enable reverse resolving of clients' IP addresses",
|
||||
"resolve_clients_desc": "Reversely resolve clients' IP addresses into their hostnames by sending PTR queries to corresponding resolvers (private DNS servers for local clients, upstream servers for clients with public IP addresses).",
|
||||
"use_private_ptr_resolvers_title": "Use private reverse DNS resolvers",
|
||||
"use_private_ptr_resolvers_desc": "Resolve PTR, SOA, and NS requests for ARPA domains containing private IP addresses through private upstream servers, DHCP, /etc/hosts, etc. If disabled, AdGuard Home will respond to all such requests with NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Perform reverse DNS lookups for locally served addresses using these upstream servers. If disabled, AdGuard Home responds with NXDOMAIN to all such PTR requests except for clients known from DHCP, /etc/hosts, and so on.",
|
||||
"check_dhcp_servers": "Check for DHCP servers",
|
||||
"save_config": "Save configuration",
|
||||
"enabled_dhcp": "DHCP server enabled",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Use AdGuard parental control web service",
|
||||
"use_adguard_parental_hint": "AdGuard Home will check if domain contains adult materials. It uses the same privacy-friendly API as the browsing security web service.",
|
||||
"enforce_safe_search": "Use Safe Search",
|
||||
"enforce_save_search_hint": "AdGuard Home will enforce safe search in the following search engines: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home will enforce safe search in the following search engines: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"no_servers_specified": "No servers specified",
|
||||
"general_settings": "General settings",
|
||||
"dns_settings": "DNS settings",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Usar consultas paralelas para acelerar la resolución al consultar simultáneamente a todos los servidores DNS de subida.",
|
||||
"parallel_requests": "Consultas paralelas",
|
||||
"load_balancing": "Balanceo de carga",
|
||||
"load_balancing_desc": "Consulta un servidor upstream a la vez. AdGuard Home utiliza un algoritmo aleatorio ponderado para seleccionar los servidores con el menor número de fallos y el menor tiempo medio de búsqueda.",
|
||||
"load_balancing_desc": "Consulta un servidor DNS de subida a la vez. AdGuard Home utiliza su algoritmo aleatorio ponderado para elegir el servidor más rápido y sea utilizado con más frecuencia.",
|
||||
"bootstrap_dns": "Servidores DNS de arranque",
|
||||
"bootstrap_dns_desc": "Direcciones IP de servidores DNS utilizadas para resolver direcciones IP de los solucionadores DoH/DoT que especifiques como ascendentes. No se permiten comentarios.",
|
||||
"fallback_dns_title": "Servidores DNS alternativos",
|
||||
"fallback_dns_desc": "Lista de servidores DNS alternativos utilizados cuando los servidores DNS de subida no responden. La sintaxis es la misma que en el campo de los principales DNS de subida anterior.",
|
||||
"fallback_dns_placeholder": "Ingresa un servidor DNS alternativo por línea",
|
||||
"local_ptr_title": "Servidores DNS inversos y privados",
|
||||
"local_ptr_desc": "Los servidores DNS que AdGuard Home utiliza para consultas PTR, SOA y NS privadas. La petición se considera privada si solicita un dominio ARPA que contiene una subred dentro de rangos IP privados, por ejemplo \"192.168.12.34\", y procede de un cliente con dirección privada. Si no se configura, AdGuard Home utiliza las direcciones de los resolvedores DNS predeterminados de tu sistema operativo, excepto las direcciones del propio AdGuard Home.",
|
||||
"local_ptr_desc": "Los servidores DNS que AdGuard Home utiliza para las consultas PTR locales. Estos servidores se utilizan para resolver las peticiones PTR de direcciones en rangos de IP privadas, por ejemplo \"192.168.12.34\", utilizando DNS inverso. Si no está establecido, AdGuard Home utilizará los resolutores DNS predeterminados de tu sistema operativo, excepto las direcciones del propio AdGuard Home.",
|
||||
"local_ptr_default_resolver": "Por defecto, AdGuard Home utiliza los siguientes resolutores DNS inversos: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home no pudo determinar los resolutores DNS inversos y privados adecuados para este sistema.",
|
||||
"local_ptr_placeholder": "Ingresa una dirección IP por línea",
|
||||
"resolve_clients_title": "Habilitar la resolución inversa de las direcciones IP de clientes",
|
||||
"resolve_clients_desc": "Resolve de manera inversa las direcciones IP de los clientes a sus nombres de hosts enviando consultas PTR a los resolutores correspondientes (servidores DNS privados para clientes locales, servidores DNS de subida para clientes con direcciones IP públicas).",
|
||||
"use_private_ptr_resolvers_title": "Usar resolutores DNS inversos y privados",
|
||||
"use_private_ptr_resolvers_desc": "Resolver las peticiones PTR, SOA y NS para dominios ARPA que contienen direcciones privadas utilizando servidores upstream privados, DHCP, /etc/hosts, etc. Si se desactiva, AdGuard Home responde a todas estas consultas con NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Realiza búsquedas DNS inversas para direcciones servidas localmente utilizando estos servidores DNS de subida. Si está deshabilitado, AdGuard Home responderá con NXDOMAIN a todas las peticiones PTR de este tipo, excepto para los clientes conocidos por DHCP, /etc/hosts, etc.",
|
||||
"check_dhcp_servers": "Comprobar si hay servidores DHCP",
|
||||
"save_config": "Guardar configuración",
|
||||
"enabled_dhcp": "Servidor DHCP habilitado",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Usar el control parental de AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home comprobará si el dominio contiene materiales para adultos. Utiliza la misma API amigable con la privacidad del servicio web de seguridad de navegación.",
|
||||
"enforce_safe_search": "Usar búsqueda segura",
|
||||
"enforce_save_search_hint": "AdGuard Home reforzará la búsqueda segura en los siguientes motores de búsqueda: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex y Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home reforzará la búsqueda segura en los siguientes motores de búsqueda: Google, YouTube, Bing, DuckDuckGo, Yandex y Pixabay.",
|
||||
"no_servers_specified": "No hay servidores especificados",
|
||||
"general_settings": "Configuración general",
|
||||
"dns_settings": "Configuración del DNS",
|
||||
|
||||
@@ -589,7 +589,6 @@
|
||||
"cache_optimistic_desc": "AdGuard Home را وادار می کند که از سمت حافظه پنهان پاسخ دهد حتی وقتی که موارد وارد شده منقضی شده باشد و همچنین سعی بر تازه کردن آنها می کند.",
|
||||
"filter_category_general": "General",
|
||||
"filter_category_security": "مسدودسازی بدافزار و فیشینگ",
|
||||
"filter_category_regional": "منطقهای",
|
||||
"filter_category_other": "ساير",
|
||||
"use_saved_key": "از کلید ذخیره شده قبلی استفاده کنید",
|
||||
"parental_control": "نظارت والدین",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Käytä rinnakkaisia pyyntöjä ja nopeuta selvitystä käyttämällä kaikkia ylävirtapalvelimia samanaikaisesti.",
|
||||
"parallel_requests": "Rinnakkaiset pyynnöt",
|
||||
"load_balancing": "Kuormantasaus",
|
||||
"load_balancing_desc": "Lähetä kysely kerrallaan yhdelle ylävirtapalvelimelle. AdGuard Home valitsee painotetun satunnaisalgoritmin avulla palvelimet, joilla on vähiten epäonnistuneita hakuja ja keskimääräisesti lyhin hakuaika.",
|
||||
"load_balancing_desc": "Lähetä pyyntö yhdelle ylävirtapalvelimelle kerrallaan. AdGuard Home pyrkii valitsemaan nopeimman palvelimen painotetun satunnaisalgoritminsa avulla.",
|
||||
"bootstrap_dns": "Bootstrap DNS-palvelimet",
|
||||
"bootstrap_dns_desc": "Ylävirroiksi määrittämiesi DoH/DoT-resolverien IP-osoitteiden selvitykseen käytettävien DNS-palvelimien IP-osoitteet. Kommentteja ei sallita.",
|
||||
"fallback_dns_title": "DNS-varapalvelimet",
|
||||
"fallback_dns_desc": "Listaus DNS-varapalvelimista, joita käytetään kun lähtevät DNS-palvelimet eivät vastaa. Syntaksi on sama kuin yllä olevassa pääylävirrat-kentässä.",
|
||||
"fallback_dns_placeholder": "Syötä yksi DNS-varapalvelin per rivi",
|
||||
"local_ptr_title": "Yksityiset käänteis-DNS-palvelimet",
|
||||
"local_ptr_desc": "AdGuard Homen yksityisille PTR-, SOA- ja NS-pyynnöille käyttämät DNS-palvelimet. Pyyntöä luokitellaan yksityiseksi, jos se pyytää yksityistä IP-aluetta (kuten \"192.168.12.34\") käyttävän aliverkon sisältävää ARPA-verkkotunnusta ja on lähtöisin päätteeltä, jolla on yksityinen IP-osoite. Jos tätä ei ole määritetty, käytetään käyttöjärjestelmän oletusarvoisia DNS-resolvereita (AdGuard Homen IP-osoitteet pois lukien).",
|
||||
"local_ptr_desc": "DNS-palvelimet, joita AdGuard Home käyttää paikallisille PTR-pyynnöille. Näitä palvelimia käytetään yksityistä IP-osoitetta käyttävien PTR-pyyntöjen osoitteiden, kuten \"192.168.12.34\", selvitykseen käänteis-DNS:n avulla. Jos ei käytössä, AdGuard Home käyttää käyttöjärjestelmän oletusarvoisia DNS-resolvereita, poislukien AdGuard Homen omat osoitteet.",
|
||||
"local_ptr_default_resolver": "Oletusarvoisesti AdGuard Home käyttää seuraavia käänteis-DNS-resolvereita: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home ei voinut määrittää tälle järjestelmälle sopivaa yksityistä käänteis-DNS-resolveria.",
|
||||
"local_ptr_placeholder": "Syötä yksi IP-osoite per rivi",
|
||||
"resolve_clients_title": "Käytä päätelaitteiden IP-osoitteille käänteistä selvitystä",
|
||||
"resolve_clients_desc": "Selvitä päätelaitteiden IP-osoitteiden isäntänimet käänteisesti lähettämällä PTR-pyynnöt sopiville resolvereille (yksityiset DNS-palvelimet paikallisille päätelaitteille, ylävirtapalvelimet päätelaitteille, joilla on julkiset IP-osoitteet).",
|
||||
"use_private_ptr_resolvers_title": "Käytä yksityisiä käänteis-DNS-resolvereita",
|
||||
"use_private_ptr_resolvers_desc": "Selvitä yksityisiä IP-osoitteita sisältävien ARPA-verkkotunnusten PTR-, SOA- ja NS-pyynnöt käyttäen yksityisiä ylävirtapalvelimia, DHCP:tä, /etc/hosts-määrityksiä, yms. Jos tämä ei ole käytössä, AdGuard Home vastaa tällaisiin pyyntöihin NXDOMAIN-tiedolla.",
|
||||
"use_private_ptr_resolvers_desc": "Suorita käänteis-DNS-selvitykset paikallisesti tarjotuille osoitteille käyttäen näitä ylävirtapalvelimia. Jos ei käytössä, vastaa AdGuard Home kaikkiin sen tyyppisiin PTR-pyyntöihin NXDOMAIN-arvolla, pois lukien DHCP, /etc/hosts, yms. -tiedoista tunnistettut päätelaitteet.",
|
||||
"check_dhcp_servers": "Etsi DHCP-palvelimia",
|
||||
"save_config": "Tallenna asetukset",
|
||||
"enabled_dhcp": "DHCP-palvelin otettiin käyttöön",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Käytä AdGuardin lapsilukko-palvelua",
|
||||
"use_adguard_parental_hint": "AdGuard Home tarkistaa, sisältääkö verkkotunnus aikuisille tarkoitettua sisältöä. Se käyttää samaa tietosuojapainotteista rajapintaa, kuin turvallisen selauksen palvelu.",
|
||||
"enforce_safe_search": "Käytä turvallista hakua",
|
||||
"enforce_save_search_hint": "AdGuard Home pakottaa turvallisen haun käyttöön seuraavissa hakukoneissa: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex ja Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home voi pakottaa turvallisen haun käyttöön seuraavissa hakukoneissa: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Palvelimia ei ole määritetty",
|
||||
"general_settings": "Yleiset asetukset",
|
||||
"dns_settings": "DNS-asetukset",
|
||||
@@ -326,7 +326,7 @@
|
||||
"blocking_ipv6_desc": "Estettyyn AAAA-pyyntöön palautettava IP-osoite",
|
||||
"blocking_mode_default": "Oletus: Vastaa IP-nollaosoitteella (0.0.0.0 korvaa A; :: korvaa AAAA) kun estetään mainoseston säännöllä; vastaa säännön määrittämällä IP-osoitteella kun estetään /etc/hosts-tyyppisellä säännöllä",
|
||||
"blocking_mode_refused": "REFUSED: Vastaa REFUSED-koodilla",
|
||||
"blocking_mode_nxdomain": "NXDOMAIN: Vastaa NXDOMAIN-tiedolla",
|
||||
"blocking_mode_nxdomain": "NXDOMAIN: Vastaa NXDOMAIN-koodilla",
|
||||
"blocking_mode_null_ip": "Tyhjä IP: Vastaa IP-nollaosoitteella (0.0.0.0 korvaa A; :: korvaa AAAA)",
|
||||
"blocking_mode_custom_ip": "Mukautettu IP: Vastaa manuaalisesti määritetyllä IP-osoitteella",
|
||||
"theme_auto": "Automaattinen",
|
||||
@@ -501,8 +501,8 @@
|
||||
"setup_dns_privacy_ios_1": "<0>DNSCloak</0> tukee <1>DNS-over-HTTPS</1>, mutta oman palvelimen käyttö' varten sille on luotava <2>DNS Stamp</2> -merkintä.",
|
||||
"setup_dns_privacy_ios_2": "<0>AdGuard iOS:lle</0> tukee <1>DNS-over-HTTPS</1> ja <1>DNS-over-TLS</1> -toteutuksia.",
|
||||
"setup_dns_privacy_other_title": "Muita toteutuksia",
|
||||
"setup_dns_privacy_other_1": "AdGuard Home voi itse olla suojattu DNS -pääte millä tahansa alustalla.",
|
||||
"setup_dns_privacy_other_2": "<0>dnsproxy</0> tukee kaikkia tunnettuja suojattuja DNS-protokollia.",
|
||||
"setup_dns_privacy_other_1": "AdGuard Home voi itse olla turvallinen DNS-päätelaite millä tahansa alustalla.",
|
||||
"setup_dns_privacy_other_2": "<0>dnsproxy</0> tukee kaikkia tunnettuja turvallisia DNS-protokollia.",
|
||||
"setup_dns_privacy_other_3": "<0>dnscrypt-proxy</0> tukee <1>DNS-over-HTTPS</1> -protokollaa.",
|
||||
"setup_dns_privacy_other_4": "<0>Mozilla Firefox</0> tukee <1>DNS-over-HTTPS</1>-toteutusta.",
|
||||
"setup_dns_privacy_other_5": "Löydät lisää toteutuksia <0>täältä</0> ja <1>täältä</1>.",
|
||||
@@ -542,7 +542,7 @@
|
||||
"stats_params": "Tilastoinnin määritys",
|
||||
"config_successfully_saved": "Asetukset tallennettiin",
|
||||
"interval_6_hour": "6 tuntia",
|
||||
"interval_24_hour": "24 tunnilta",
|
||||
"interval_24_hour": "24 tuntia",
|
||||
"interval_days": "{{count}} päivä",
|
||||
"interval_days_plural": "{{count}} päivää",
|
||||
"domain": "Verkkotunnus",
|
||||
@@ -709,9 +709,9 @@
|
||||
"log_and_stats_section_label": "Pyyntöhistoria ja tilastot",
|
||||
"ignore_query_log": "Älä huomioi tätä päätelaitetta pyyntöhistoriassa",
|
||||
"ignore_statistics": "Älä huomioi tätä päätettä tilastoissa",
|
||||
"schedule_services": "Pysäytä palveluesto",
|
||||
"schedule_services_desc": "Määritä palvelunestosuodattimen pysäytysajoitus.",
|
||||
"schedule_services_desc_client": "Määritä palvelunestosuodattimen pysäytysajoitus tälle päätteelle.",
|
||||
"schedule_services": "Keskeytä palveluesto",
|
||||
"schedule_services_desc": "Määritä palvelunestosuodattimen keskeytysajoitus.",
|
||||
"schedule_services_desc_client": "Määritä palvelunestosuodattimen keskeytysajoitus tälle päätteelle.",
|
||||
"schedule_desc": "Aseta estettujen palveluiden käyttämättömyysjaksot",
|
||||
"schedule_invalid_select": "Aloitusaika on oltava ennen lopetusaikaa",
|
||||
"schedule_select_days": "Valitse päivät",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Utilisez des requêtes parallèles pour accélérer la résolution en requêtant simultanément tous les serveurs en amont.",
|
||||
"parallel_requests": "Requêtes en parallèle",
|
||||
"load_balancing": "Équilibrage de charge",
|
||||
"load_balancing_desc": "Une requête par serveur en amont à la fois. AdGuard Home utilise un algorithme aléatoire pondéré pour sélectionner les serveurs avec le plus petit nombre d'échecs de recherche et le temps de recherche moyen le plus bas.",
|
||||
"load_balancing_desc": "Interroger un serveur en amont à la fois. AdGuard Home utilise son algorithme aléatoire pondéré pour choisir le serveur de sorte que le serveur le plus rapide soit utilisé plus souvent.",
|
||||
"bootstrap_dns": "Serveurs DNS d'amorçage",
|
||||
"bootstrap_dns_desc": "Les adresses IP des serveurs DNS utilisées pour résoudre les adresses IP des résolveurs DoH/DoT que vous spécifiez comme en amont. Les commentaires ne sont pas autorisés.",
|
||||
"fallback_dns_title": "Serveurs DNS de repli",
|
||||
"fallback_dns_desc": "Liste des serveurs DNS de repli utilisés lorsque les serveurs DNS en amont ne répondent pas. La syntaxe est la même que dans le champ principal en amont ci-dessus.",
|
||||
"fallback_dns_placeholder": "Saisissez un serveur DNS de repli par ligne",
|
||||
"local_ptr_title": "Serveurs DNS privés inverses",
|
||||
"local_ptr_desc": "Les serveurs DNS utilisés par AdGuard Home pour les requêtes privées PTR, SOA et NS. Une requête est considérée privée si elle demande un domaine ARPA contenant un sous-réseau entre les plages IP privées (par exemple \"192.168.12.34\") et provient d'un client avec une adresse IP privée. Sans réglages additionnels, les résolveurs DNS par défaut de votre système d'exploitation seront utilisés, sauf pour les adresses IP d'AdGuard Home.",
|
||||
"local_ptr_desc": "Les serveurs DNS que AdGuard Home utilise pour les requêtes PTR locales. Ces serveurs sont utilisés pour résoudre les noms d'hôte des clients avec des adresses IP privées, par exemple « 192.168.12.34 », en utilisant le DNS inversé. Si ce paramètre n'est pas défini, AdGuard Home utilise les adresses des résolveurs DNS par défaut de votre système d'exploitation, à l'exception des adresses d'AdGuard Home lui-même.",
|
||||
"local_ptr_default_resolver": "Par défaut, AdGuard Home utilise les résolveurs DNS inversés suivants : {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home n'a pas pu déterminer de résolveurs DNS inversés privés appropriés pour ce système.",
|
||||
"local_ptr_placeholder": "Saisissez une adresse IP par ligne",
|
||||
"resolve_clients_title": "Activer la résolution inverse des adresses IP des clients",
|
||||
"resolve_clients_desc": "Résoudre inversement les adresses IP des clients en leurs noms d'hôtes en envoyant des requêtes PTR aux résolveurs correspondants (serveurs DNS privés pour les clients locaux, serveurs en amont pour les clients ayant une adresse IP publique).",
|
||||
"use_private_ptr_resolvers_title": "Utiliser des résolveurs DNS inversés privés",
|
||||
"use_private_ptr_resolvers_desc": "Résolvez les requêtes PTR, SOA et NS pour les domaines ARPA contenant des adresses IP privées par aide des serveurs privés en amont, DHCP, /etc/hosts, etc. S'il est désactivé, AdGuard Home répondra à toutes ces requêtes avec NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Effectuer des recherches DNS inversées pour les adresses servies localement en utilisant ces serveurs en amont. S'il est désactivé, AdGuard Home répond avec NXDOMAIN à toutes les requêtes PTR de ce type, sauf pour les clients connus par DHCP, /etc/hosts, etc.",
|
||||
"check_dhcp_servers": "Rechercher les serveurs DHCP",
|
||||
"save_config": "Sauvegarder la configuration",
|
||||
"enabled_dhcp": "Serveur DHCP activé",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Utiliser le contrôle parental d'AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home va vérifier s'il y a du contenu pour adultes sur le domaine. Ce sera fait par aide du même API discret que celui utilisé par le service de Sécurité de navigation.",
|
||||
"enforce_safe_search": "Utiliser la Recherche Sécurisée",
|
||||
"enforce_save_search_hint": "AdGuard Home appliquera la recherche sécurisée dans les moteurs de recherche suivants : Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home appliquera la recherche sécurisée dans les moteurs de recherche suivants : Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Pas de serveurs spécifiés",
|
||||
"general_settings": "Paramètres généraux",
|
||||
"dns_settings": "Paramètres DNS",
|
||||
@@ -676,7 +676,7 @@
|
||||
"filter_allowlist": "ATTENTION : Cette action exclura également la règle « {{disallowed_rule}} » de la liste des clients autorisés.",
|
||||
"last_rule_in_allowlist": "Impossible d’interdire ce client, car l’exclusion de la règle « {{disallowed_rule}} » DÉSACTIVERA la liste des « clients autorisés ».",
|
||||
"use_saved_key": "Utiliser la clef précédemment enregistrée",
|
||||
"parental_control": "Contrôle Parental",
|
||||
"parental_control": "Contrôle parental",
|
||||
"safe_browsing": "Navigation sécurisée",
|
||||
"served_from_cache_label": "Servi depuis le cache",
|
||||
"form_error_password_length": "Le mot de passe doit comporter entre {{min}} et {{max}} caractères",
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
"fallback_dns_desc": "Popis rezervnih DNS poslužitelja koji se koriste kada uzvodni DNS poslužitelji ne odgovaraju. Sintaksa je ista kao u gornjem polju glavnog uzvodnog toka.",
|
||||
"fallback_dns_placeholder": "Unesite jedan rezervni DNS poslužitelj po retku",
|
||||
"local_ptr_title": "Privatni obrnuti DNS poslužitelji",
|
||||
"local_ptr_desc": "DNS poslužitelji koje koristi AdGuard Home za privatne PTR, SOA i NS zahtjeve. Zahtjev se smatra privatnim ako traži ARPA domenu koja sadrži podmrežu unutar privatnih IP raspona (kao što je \"192.168.12.34\") i dolazi od klijenta s privatnom IP adresom. Ako nije postavljeno, koristit će se zadani DNS rezolveri vašeg OS-a, osim za AdGuard Home IP adrese.",
|
||||
"local_ptr_desc": "DNS poslužitelji koje AdGuard Home koristi za lokalne PTR upite. Ti se poslužitelji koriste za razrješavanje naziva glavnog računala klijenata s privatnim IP adresama, na primjer \"192.168.12.34\", koristeći obrnuti DNS. Ako nije postavljeno, AdGuard Home koristi adrese zadanih DNS razrješivača vašeg OS-a, osim za adrese samog AdGuard Homea.",
|
||||
"local_ptr_default_resolver": "Prema zadanim postavkama AdGuard Home koristi sljedeće obrnute DNS razrješivače: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home nije mogao odrediti prikladne privatne obrnute DNS razrješivače za ovaj sustav.",
|
||||
"local_ptr_placeholder": "Unesite jednu adresu poslužitelja po retku",
|
||||
"resolve_clients_title": "Omogući obrnuto rješavanje IP adresa klijenata",
|
||||
"resolve_clients_desc": "Obrnuto razriješite IP adrese klijenata u nazive glavnih računala slanjem PTR upita odgovarajućim razrješivačima (privatni DNS poslužitelji za lokalne klijente, uzvodni poslužitelji za klijente s javnim IP adresama).",
|
||||
"use_private_ptr_resolvers_title": "Koristi privatne reverzne DNS razrješivače",
|
||||
"use_private_ptr_resolvers_desc": "Razriješi PTR, SOA i NS zahtjeve za ARPA domene koje sadrže privatne IP adrese putem privatnih uzvodnih poslužitelja, DHCP-a, /etc/hostova itd. Ako je onemogućeno, AdGuard Home će na sve takve zahtjeve odgovoriti s NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Izvršite obrnuta DNS traženja za lokalno poslužene adrese pomoću ovih uzlaznih poslužitelja. Ako je onemogućen, AdGuard Home odgovara S NXDOMAIN-om na sve takve PTR zahtjeve osim za klijente poznate iz DHCP-a, /etc/hosts i tako dalje.",
|
||||
"check_dhcp_servers": "Provjera DHCP poslužitelja",
|
||||
"save_config": "Spremi konfiguraciju",
|
||||
"enabled_dhcp": "DHCP poslužitelj je omogućen",
|
||||
@@ -425,9 +425,6 @@
|
||||
"encryption_hostnames": "Nazivi računala",
|
||||
"encryption_reset": "Jeste li sigurni da želite poništiti postavke šifriranja?",
|
||||
"encryption_warning": "Upozorenje",
|
||||
"encryption_plain_dns_enable": "Omogući obični DNS",
|
||||
"encryption_plain_dns_desc": "Obični DNS je omogućen prema zadanim postavkama. Možete ga onemogućiti kako biste prisilili sve uređaje da koriste šifrirani DNS. Da biste to učinili, morate omogućiti barem jedan kriptirani DNS protokol",
|
||||
"encryption_plain_dns_error": "Da biste onemogućili obični DNS, omogućite barem jedan kriptirani DNS protokol",
|
||||
"topline_expiring_certificate": "Vaš SSL certifikat uskoro ističe. Ažurirajte <0>Postavke šifriranja</0>.",
|
||||
"topline_expired_certificate": "Vaš SSL certifikat je istekao. Ažurirajte <0>Postavke šifriranja</0>.",
|
||||
"form_error_port_range": "Unesite broj porta od 80 do 65536",
|
||||
@@ -678,7 +675,7 @@
|
||||
"use_saved_key": "Korištenje prethodno spremljenog ključa",
|
||||
"parental_control": "Roditeljska zaštita",
|
||||
"safe_browsing": "Sigurno surfanje",
|
||||
"served_from_cache_label": "Posluženo iz predmemorije",
|
||||
"served_from_cache": "{{value}} <i>(dohvaćeno iz predmemorije)</i>",
|
||||
"form_error_password_length": "Lozinka mora sadržavati od {{min}} do {{max}} znakova",
|
||||
"anonymizer_notification": "<0>Napomena:</0>IP anonimizacija je omogućena. Možete ju onemogućiti u <1>općim postavkama</1>.",
|
||||
"confirm_dns_cache_clear": "Jeste li sigurni da želite očistiti DNS predmemoriju?",
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
"average_upstream_response_time": "Rata-rata waktu respons hulu",
|
||||
"response_time": "Waktu respons",
|
||||
"average_processing_time_hint": "Rata-rata waktu dalam milidetik untuk pemrosesan sebuah permintaan DNS",
|
||||
"block_domain_use_filters_and_hosts": "Blokir domain menggunakan filter dan berkas host",
|
||||
"block_domain_use_filters_and_hosts": "Blokir domain menggunakan filter dan file hosts",
|
||||
"filters_block_toggle_hint": "Anda dapat menyiapkan aturan pemblokiran dalam pengaturan <a>Filter</a>.",
|
||||
"use_adguard_browsing_sec": "Gunakan layanan web Keamanan Penjelajahan AdGuard",
|
||||
"use_adguard_browsing_sec_hint": "AdGuard Home akan memeriksa apakah domain diblokir oleh layanan web keamanan penjelajahan. Ini akan menggunakan API pencarian yang ramah privasi untuk melakukan pemeriksaan: hanya awalan singkat dari hash nama domain SHA256 yang dikirim ke server.",
|
||||
@@ -191,7 +191,7 @@
|
||||
"edit_table_action": "Ubah",
|
||||
"delete_table_action": "Hapus",
|
||||
"elapsed": "Berlalu",
|
||||
"filters_and_hosts_hint": "AdGuard Home memahami aturan dasar adblock dan sintak berkas host.",
|
||||
"filters_and_hosts_hint": "AdGuard Home memahami aturan dasar adblock dan sintak file hosts.",
|
||||
"no_blocklist_added": "Tidak ada daftar hitam yang ditambahkan",
|
||||
"no_whitelist_added": "Tidak ada daftar putih yang ditambahkan",
|
||||
"add_blocklist": "Tambahkan daftar hitam",
|
||||
@@ -211,8 +211,8 @@
|
||||
"form_error_url_format": "Format URL tidak valid",
|
||||
"form_error_url_or_path_format": "URL atau jalur absolut dari daftar tidak valid",
|
||||
"custom_filter_rules": "Aturan penyaringan khusus",
|
||||
"custom_filter_rules_hint": "Masukkan satu aturan pada satu baris. Anda dapat menggunakan aturan adblock atau sintaks berkas host.",
|
||||
"system_host_files": "Berkas host sistem",
|
||||
"custom_filter_rules_hint": "Masukkan satu aturan dalam sebuah baris. Anda dapat menggunakan baik aturan adblock maupun sintaks file hosts.",
|
||||
"system_host_files": "File host sistem",
|
||||
"examples_title": "Contoh",
|
||||
"example_meaning_filter_block": "blokir akses ke example.org dan seluruh subdomainnya;",
|
||||
"example_meaning_filter_whitelist": "buka blokir akses ke domain example.orf dan seluruh subdomainnya;",
|
||||
@@ -476,7 +476,7 @@
|
||||
"client_confirm_delete": "Apakah anda yakin ingin menghapus klien \"{{key}}\"?",
|
||||
"list_confirm_delete": "Anda yakin ingin menghapus daftar ini?",
|
||||
"auto_clients_title": "Klien (waktu berjalan)",
|
||||
"auto_clients_desc": "Informasi tentang alamat IP perangkat yang menggunakan atau mungkin menggunakan AdGuard Home. Informasi ini dikumpulkan dari beberapa sumber, termasuk berkas host, DNS terbalik, dll.",
|
||||
"auto_clients_desc": "Informasi tentang alamat IP perangkat yang menggunakan atau mungkin menggunakan AdGuard Home. Informasi ini dikumpulkan dari beberapa sumber, termasuk file host, reverse DNS, dll.",
|
||||
"access_title": "Pengaturan akses",
|
||||
"access_desc": "Disini anda dapat mengatur aturan akses untuk server AdGuard Home DNS",
|
||||
"access_allowed_title": "Klien yang diizinkan",
|
||||
@@ -494,7 +494,7 @@
|
||||
"setup_dns_privacy_1": "<0>DNS melalui TLS:</0> Gunakan <1>{{address}}</1> string.",
|
||||
"setup_dns_privacy_2": "<0>DNS-over-TLS:</0> Memakai <1>{{address}}</1> string.",
|
||||
"setup_dns_privacy_3": "<0>Berikut daftar perangkat lunak yang dapat Anda gunakan.</0>",
|
||||
"setup_dns_privacy_4": "Pada perangkat iOS 14 atau macOS Big Sur, Anda dapat mengunduh berkas khusus '.mobileconfig' yang menambahkan server <highlight>DNS melalui HTTPS</highlight> atau <highlight>DNS melalui TLS</highlight> ke pengaturan DNS.",
|
||||
"setup_dns_privacy_4": "Di perangkat iOS 14 atau macOS Big Sur, Anda dapat mengunduh file '.mobileconfig' khusus yang menambahkan server <highlight>DNS-over-HTTPS</highlight> atau <highlight>DNS-over-TLS</highlight> ke pengaturan DNS.",
|
||||
"setup_dns_privacy_android_1": "Android 9 mendukung DNS-over-TLS secara asli. Untuk mengkonfigurasinya, buka Pengaturan → Jaringan & internet → Tingkat Lanjut → DNS Pribadi dan masukkan nama domain Anda di sana.",
|
||||
"setup_dns_privacy_android_2": "<0>AdGuard untuk Android</0> mendukung <1>DNS-over-HTTPS</1> dan <1>DNS-over-TLS</1>.",
|
||||
"setup_dns_privacy_android_3": "<0>Intra</0> menambahkan dukungan <1>DNS-over-HTTPS</1> untuk Android.",
|
||||
@@ -517,7 +517,7 @@
|
||||
"rewrite_confirm_delete": "Apakah anda yakin ingin menghapus DNS rewrite untuk \"{{key}}\"?",
|
||||
"rewrite_desc": "Memungkinkan untuk dengan mudah mengkonfigurasi respons DNS kustom untuk nama domain tertentu.",
|
||||
"rewrite_applied": "Aturan Rewrite yang diterapkan",
|
||||
"rewrite_hosts_applied": "Ditulis ulang oleh aturan berkas host",
|
||||
"rewrite_hosts_applied": "Ditulis ulang oleh aturan file hosts",
|
||||
"dns_rewrites": "DNS rewrite",
|
||||
"form_domain": "Masukkan nama domain",
|
||||
"form_answer": "Masaukan alamat IP atau nama domain",
|
||||
@@ -676,7 +676,7 @@
|
||||
"filter_allowlist": "PERINGATAN: Tindakan ini juga akan mengecualikan aturan \"{{disallowed_rule}}\" dari daftar klien yang diizinkan.",
|
||||
"last_rule_in_allowlist": "Tidak dapat melarang klien ini karena mengecualikan aturan \"{{disallowed_rule}}\" akan MENONAKTIFKAN daftar \"Klien yang diizinkan\".",
|
||||
"use_saved_key": "Gunakan kunci yang disimpan sebelumnya",
|
||||
"parental_control": "Pengawasan Orang Tua",
|
||||
"parental_control": "Kontrol Orang Tua",
|
||||
"safe_browsing": "Penjelajahan Aman",
|
||||
"served_from_cache": "{{value}} <i>(disajikan dari cache)</i>",
|
||||
"form_error_password_length": "Kata sandi harus terdiri dari {{min}} hingga {{max}}",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Utilizza richieste parallele per accelerare la risoluzione interrogando simultaneamente tutti i server upstream.",
|
||||
"parallel_requests": "Richieste parallele",
|
||||
"load_balancing": "Bilanciamento del carico",
|
||||
"load_balancing_desc": "Esegui una query su un server upstream alla volta. AdGuard Home utilizza un algoritmo casuale ponderato per selezionare i server con il minor numero di ricerche fallite e il tempo medio di ricerca più basso.",
|
||||
"load_balancing_desc": "Interroga un server upstream per volta. AdGuard Home utilizzerà un algoritmo casuale ponderato per la selezione del server, in maniera tale da scegliere spesso il più veloce.",
|
||||
"bootstrap_dns": "Server DNS bootstrap",
|
||||
"bootstrap_dns_desc": "Indirizzi IP dei server DNS utilizzati per risolvere gli indirizzi IP dei resolver DoH/DoT specificati come upstream. I commenti non sono ammessi.",
|
||||
"fallback_dns_title": "Server DNS di fallback",
|
||||
"fallback_dns_desc": "Elenco dei server DNS fallback utilizzati quando i server DNS upstream non rispondono. La sintassi è la stessa del campo principale upstream sopra.",
|
||||
"fallback_dns_placeholder": "Inserisci un server DNS fallback per riga",
|
||||
"local_ptr_title": "Server DNS privati inversi",
|
||||
"local_ptr_desc": "I server DNS usati da AdGuard Home per richieste private PTR, SOA e NS. Una richiesta è considerata privata se richiede un dominio ARPA contenente una sottorete all'interno di intervalli IP privati (come \"192.168.12.34\") e proviene da un client con un indirizzo IP privato. Se non impostato, saranno usati i risolutori DNS predefiniti del tuo sistema operativo, ad eccezione degli indirizzi IP di AdGuard Home.",
|
||||
"local_ptr_desc": "I server DNS che AdGuard Home utilizza per le richieste PTR locali. Questi server vengono utilizzati per risolvere i nomi host dei client con indirizzi IP privati, ad esempio \"192.168.12.34\", utilizzando il DNS inverso. Se non è impostato, AdGuard Home utilizzerà gli indirizzi dei resolutori DNS predefiniti del tuo sistema operativo ad eccezione degli indirizzi di AdGuard Home stesso.",
|
||||
"local_ptr_default_resolver": "Per impostazione predefinita, AdGuard Home utilizzerà i seguenti risolutori DNS inversi: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home non è stato in grado di determinare i risolutori DNS inversi privati adatti per questo sistema.",
|
||||
"local_ptr_placeholder": "Inserisci un indirizzo IP per riga",
|
||||
"resolve_clients_title": "Attiva la risoluzione inversa degli indirizzi IP dei client",
|
||||
"resolve_clients_desc": "Risolve inversamente gli indirizzi IP dei client nei loro nomi host inviando richieste PTR ai risolutori corrispondenti (server DNS privati per client locali, server upstream per client con indirizzi IP pubblici).",
|
||||
"use_private_ptr_resolvers_title": "Utilizza dei resolver rDNS privati",
|
||||
"use_private_ptr_resolvers_desc": "Risolvi le richieste PTR, SOA e NS per domini ARPA contenenti indirizzi IP privati tramite server upstream privati, DHCP, /etc/hosts, ecc. Se disabilitato, AdGuard Home risponderà a tutte queste richieste con NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Esegue ricerche DNS inverse per indirizzi locali utilizzando questi server upstream. Se disattivata, AdGuard Home risponderà con NXDOMAIN a tutte le richieste PTR ad eccezione dei client noti da DHCP, /etc/hosts, e così via.",
|
||||
"check_dhcp_servers": "Controlla la presenza di server DHCP",
|
||||
"save_config": "Salva configurazione",
|
||||
"enabled_dhcp": "Server DHCP attivo",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Utilizza il Controllo Parentale di AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home verificherà se il dominio contiene materiale per adulti. Utilizza le stesse API privacy-friendly del servizio web 'sicurezza di navigazione'.",
|
||||
"enforce_safe_search": "Utilizza Ricerca Sicura",
|
||||
"enforce_save_search_hint": "AdGuard Home applicherà la ricerca sicura nei seguenti motori di ricerca: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home forzerà la ricerca sicura sui seguenti motori di ricerca: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Nessun server specificato",
|
||||
"general_settings": "Impostazioni generali",
|
||||
"dns_settings": "Impostazioni DNS",
|
||||
@@ -341,7 +341,7 @@
|
||||
"list_label": "Elenco",
|
||||
"unknown_filter": "Filtro sconosciuto {{filterId}}",
|
||||
"known_tracker": "Tracciatore noto",
|
||||
"install_welcome_title": "Benvenuto in AdGuard Home!",
|
||||
"install_welcome_title": "Benvenuto nella Home di AdGuard!",
|
||||
"install_welcome_desc": "AdGuard Home è un server DNS che blocca annunci e tracciatori a livello di rete. Il suo scopo è quello di permetterti il controllo dell'intera rete e di tutti i dispositivi, e non richiede l'utilizzo di un programma lato client.",
|
||||
"install_settings_title": "Interfaccia Web dell'Admin",
|
||||
"install_settings_listen": "Interfaccia d'ascolto",
|
||||
@@ -446,7 +446,7 @@
|
||||
"update_now": "Aggiorna ora",
|
||||
"update_failed": "Aggiornamento automatico non riuscito. Ti suggeriamo di <a>seguire questi passaggi</a> per aggiornare manualmente.",
|
||||
"manual_update": "Ti invitiamo a <a>seguire questi passaggi</a> per aggiornare manualmente.",
|
||||
"processing_update": "Attendi per favore, AdGuard Home si sta aggiornando",
|
||||
"processing_update": "Perfavore aspetta, AdGuard Home si sta aggiornando",
|
||||
"clients_title": "Client persistenti",
|
||||
"clients_desc": "Configura le registrazioni dei client persistenti per i dispositivi connessi ad AdGuard Home",
|
||||
"settings_global": "Globale",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "並列リクエストを使用する(同時にすべてのアップストリームサーバーに処理要求することで解決スピードが向上)",
|
||||
"parallel_requests": "並列リクエスト",
|
||||
"load_balancing": "ロードバランシング",
|
||||
"load_balancing_desc": "一度に1つのアップストリームサーバーをクエリします。AdGuard Home は、重み付き乱択アルゴリズムを使用して、ルックアップに失敗した回数が最も少なく、平均ルックアップ時間が最も短いサーバーを選択します。",
|
||||
"load_balancing_desc": "一度に1つのアップストリームサーバに処理要求します。 AdGuard Homeは、重み付きランダムアルゴリズム(weighted random algorithm)を使用してサーバを選択するため、最速のサーバがより頻繁に使用されます。",
|
||||
"bootstrap_dns": "ブートストラップDNSサーバ",
|
||||
"bootstrap_dns_desc": "アップストリームとして指定したDoH/DoTリゾルバのIPアドレスを解決するために使用されるDNSサーバーのIPアドレスです。(コメントは許可されていません)",
|
||||
"fallback_dns_title": "フォールバックDNSサーバー",
|
||||
"fallback_dns_desc": "アップストリームDNSサーバーが応答しない場合に使用されるフォールバックDNSサーバーのリストです。構文は上記のmain upstreamsフィールドと同じです。",
|
||||
"fallback_dns_placeholder": "フォールバックDNSサーバーを1行に1つずつ入力してください。",
|
||||
"local_ptr_title": "プライベートリバースDNSサーバー",
|
||||
"local_ptr_desc": "AdGuard Home がプライベート PTR、SOA、および NS リクエストに使用する DNS サーバー。プライベート IP 範囲内のサブネット (「192.168.12.34」など) を含む ARPA ドメインを要求し、プライベート IP アドレスを持つクライアントから来たリクエストが、プライベートリクエストとみなされます。本設定が特に指定されていない場合、OS のデフォルト DNS リゾルバ(AdGuard Home の IP アドレスを除く)が使用されます。",
|
||||
"local_ptr_desc": "AdGuard HomeがローカルPTRクエリに使用するDNSサーバーです。これらのサーバーは、rDNSを使ってプライベートIPアドレス(例えば\"192.168.12.34\")を持つクライアントのホスト名を解決するために使用されます。設定されていない場合、AdGuard HomeはOSのデフォルトDNSリゾルバーのアドレス(AdGuard Home自体のアドレスを除く)を自動的に使用します。",
|
||||
"local_ptr_default_resolver": "デフォルトでは、AdGuard Homeは次のリバースDNSリゾルバを使用します: {{ip}}",
|
||||
"local_ptr_no_default_resolver": "AdGuard Homeは、このシステムに適したプライベートリバースDNSリゾルバを特定できませんでした。",
|
||||
"local_ptr_placeholder": "IPアドレスを1行に1つずづ入力してください。",
|
||||
"resolve_clients_title": "クライアントのIPアドレスの逆解決を有効にする",
|
||||
"resolve_clients_desc": "対応するリゾルバー(ローカルクライアントの場合はプライベートDNSサーバ、パブリックIPを持つクライアントの場合はアップストリームサーバー)にPTRクエリを送信することにより、クライアントのIPアドレスをホストネームに逆解決します。",
|
||||
"use_private_ptr_resolvers_title": "プライベートリバースDNSリゾルバを使用",
|
||||
"use_private_ptr_resolvers_desc": "プライベートアップストリームサーバー、DHCP、/etc/hosts などを通じて、プライベート IP アドレスを含む ARPA ドメインの PTR、SOA、および NS リクエストを解決します。無効にした場合、AdGuard Home はこのようなリクエストのすべてに NXDOMAIN で応答します。",
|
||||
"use_private_ptr_resolvers_desc": "これらのアップストリームサーバーを使用して、ローカルで提供されるアドレスのリバースDNSルックアップを実行します。無効にすると、AdGuard Homeは、DHCP, /etc/hosts などから認識されるクライアントを除き、すべてのこのようなPTR要求にNXDOMAINで応答します。",
|
||||
"check_dhcp_servers": "DHCPサーバをチェックする",
|
||||
"save_config": "構成を保存する",
|
||||
"enabled_dhcp": "DHCPサーバを有効にしました",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "AdGuardペアレンタルコントロール・ウェブサービスを使用する",
|
||||
"use_adguard_parental_hint": "AdGuard Homeは、ドメインにアダルトコンテンツが含まれているかどうかを確認します。 ブラウジングセキュリティ・ウェブサービスと同じプライバシーに優しいAPIを使用します。",
|
||||
"enforce_safe_search": "セーフサーチを使用する",
|
||||
"enforce_save_search_hint": "AdGuard Homeは、次の検索エンジンでセーフサーチを強制適用します: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay",
|
||||
"enforce_save_search_hint": "AdGuard Homeは、次の検索エンジンでセーフサーチを強制適用します: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay",
|
||||
"no_servers_specified": "サーバが指定されていません",
|
||||
"general_settings": "一般設定",
|
||||
"dns_settings": "DNS設定",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "쿼리 처리 속도를 높이려면 모든 업스트림 서버에서 동시에 병렬 쿼리를 사용해주세요.",
|
||||
"parallel_requests": "병렬 처리 요청",
|
||||
"load_balancing": "로드 밸런싱",
|
||||
"load_balancing_desc": "한 번에 하나의 업스트림 서버를 쿼리합니다. AdGuard Home은 가중 무작위 알고리즘을 사용하여 조회 실패 횟수가 가장 적고 평균 조회 시간이 가장 짧은 서버를 선택합니다.",
|
||||
"load_balancing_desc": "한 번에 하나의 서버씩 질의합니다. AdGuard Home은 가중 랜덤 알고리즘를 사용해서 가장 빠른 서버가 자주 사용되도록 서버를 선택합니다.",
|
||||
"bootstrap_dns": "부트스트랩 DNS 서버",
|
||||
"bootstrap_dns_desc": "업스트림으로 지정한 DoH/DoT 리졸버의 IP 주소를 확인하는 데 사용되는 DNS 서버의 IP 주소입니다. 주석은 허용되지 않습니다.",
|
||||
"fallback_dns_title": "폴백 DNS 서버",
|
||||
"fallback_dns_desc": "업스트림 DNS 서버가 응답하지 않을 때 사용되는 폴백 DNS 서버 목록입니다. 구문은 위의 기본 업스트림 필드와 동일합니다.",
|
||||
"fallback_dns_placeholder": "한 줄에 하나의 폴백 DNS 서버를 입력하세요.",
|
||||
"local_ptr_title": "프라이빗 역방향 DNS 서버",
|
||||
"local_ptr_desc": "AdGuard Home에서 비공개 PTR, SOA 및 NS 요청에 사용하는 DNS 서버입니다. 요청이 비공개 IP 범위 내의 서브넷(예: \"192.168.12.34\")을 포함하는 ARPA 도메인을 요청하고 비공개 IP 주소를 가진 클라이언트로부터 오는 경우 비공개로 간주됩니다. 설정하지 않으면 AdGuard Home IP 주소를 제외한 OS의 기본 DNS 리졸버가 사용됩니다.",
|
||||
"local_ptr_desc": "AdGuard Home이 로컬 PTR 쿼리에 사용하는 DNS 서버입니다. 이러한 서버는 역방향 DNS를 사용하여 개인 IP 주소(예: '192.168.12.34')가 있는 클라이언트의 호스트 이름을 확인하는 데 사용됩니다. 설정되지 않은 경우, AdGuard Home은 AdGuard Home의 주소를 제외하고 운영 체제의 기본 DNS 리졸버의 주소를 사용합니다.",
|
||||
"local_ptr_default_resolver": "기본적으로 AdGuard Home에서는 {{ip}} 역방향 DNS 서버를 이용합니다.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home에서 이 시스템에 적합한 사설 역방향 프라이빗 DNS 서버를 결정할 수 없습니다.",
|
||||
"local_ptr_placeholder": "한 줄에 하나씩 IP 주소를 입력하세요.",
|
||||
"resolve_clients_title": "클라이언트 IP 주소에 대한 호스트명 확인 활성화",
|
||||
"resolve_clients_desc": "해당 서버에 대한 PTR 쿼리를 통해 클라이언트의 도메인 이름을 정의합니다. (로컬 클라이언트의 경우 프라이빗 DNS 서버, 공용 IP 주소가 있는 클라이언트의 경우 업스트림 서버).",
|
||||
"use_private_ptr_resolvers_title": "프라이빗 역방향 DNS 리졸버 사용",
|
||||
"use_private_ptr_resolvers_desc": "사설 업스트림 서버, DHCP, / etc/hosts 등을 통해 사설 IP 주소가 포함된 ARPA 도메인에 대한 PTR, SOA 및 NS 요청을 처리합니다. 비활성화하면 AdGuard Home은 NXDOMAIN을 사용하여 이러한 모든 요청에 응답합니다.",
|
||||
"use_private_ptr_resolvers_desc": "업스트림 서버를 사용해 로컬로 제공되는 주소의 역방향 DNS를 조회합니다. 끄는 경우, AdGuard Home은 DHCP, /etc/hosts 등에서 알려진 클라이언트를 제외한 모든 PTR 요청에 NXDOMAIN으로 응답합니다.",
|
||||
"check_dhcp_servers": "DHCP 서버 체크",
|
||||
"save_config": "구성 저장",
|
||||
"enabled_dhcp": "DHCP 서버 활성화됨",
|
||||
@@ -108,7 +108,7 @@
|
||||
"off": "OFF",
|
||||
"copyright": "Copyright",
|
||||
"homepage": "홈페이지",
|
||||
"report_an_issue": "문제 신고",
|
||||
"report_an_issue": "문제를 보고합니다",
|
||||
"privacy_policy": "개인정보취급방침",
|
||||
"enable_protection": "보호 활성화",
|
||||
"enabled_protection": "보호 활성화됨",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "AdGuard 자녀 보호 웹 서비스 사용",
|
||||
"use_adguard_parental_hint": "AdGuard Home은 도메인에 성인 자료가 포함되어 있는지 확인합니다. 브라우징 보안 웹 서비스와 동일한 개인정보 보호 API를 사용함.",
|
||||
"enforce_safe_search": "세이프서치 사용",
|
||||
"enforce_save_search_hint": "AdGuard Home은 Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay와 같은 검색 엔진에서 세이프서치를 시행합니다.",
|
||||
"enforce_save_search_hint": "AdGuard Home은 Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay와 같은 검색 엔진에서 세이프서치를 시행합니다.",
|
||||
"no_servers_specified": "지정된 서버 없음",
|
||||
"general_settings": "일반 설정",
|
||||
"dns_settings": "DNS 설정",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Parallelle verzoeken gebruiken om te versnellen door gelijktijdig verzoeken te sturen naar alle upstream servers.",
|
||||
"parallel_requests": "Parallelle verzoeken",
|
||||
"load_balancing": "Volume balanceren",
|
||||
"load_balancing_desc": "Voer zoekopdrachten uit op één upstream-server tegelijk. AdGuard Home gebruikt een gewogen willekeurig algoritme om servers te selecteren met het laagste aantal mislukte zoekopdrachten en de laagste gemiddelde opzoektijd.",
|
||||
"load_balancing_desc": "Eén server per keer bevragen. AdGuard Home gebruikt hiervoor een gewogen willekeurig algoritme om de server te kiezen zodat de snelste server meer zal gebruikt worden.",
|
||||
"bootstrap_dns": "Bootstrap DNS-servers",
|
||||
"bootstrap_dns_desc": "IP-adressen van DNS-servers die worden gebruikt om IP-adressen om te zetten van de DoH/DoT-resolvers die je opgeeft als upstreams. Opmerkingen zijn niet toegestaan.",
|
||||
"fallback_dns_title": "Back-up DNS-servers",
|
||||
"fallback_dns_desc": "Lijst met DNS-back-up-noodservers die worden gebruikt wanneer upstream DNS-servers niet reageren. De syntaxis is hetzelfde als in het veld hoofdstroomopwaarts hierboven.",
|
||||
"fallback_dns_placeholder": "Voer één DNS-back-upserver per regel in",
|
||||
"local_ptr_title": "Private omgekeerde DNS-servers",
|
||||
"local_ptr_desc": "DNS-servers die door AdGuard Home worden gebruikt voor privé PTR-, SOA- en NS-verzoeken. Een verzoek wordt als privé beschouwd als het vraagt om een ARPA-domein dat een subnet binnen privé-IP-bereiken bevat (zoals \"192.168.12.34\") en afkomstig is van een client met een privé-IP-adres. Indien niet ingesteld, zullen de standaard DNS-resolvers van je besturingssysteem worden gebruikt, behalve de AdGuard Home IP-adressen.",
|
||||
"local_ptr_desc": "De DNS-servers die AdGuard Home gebruikt voor lokale PTR-zoekopdrachten. Deze servers worden gebruikt om PTR-verzoeken voor adressen in privé-IP-bereiken op te lossen, bijvoorbeeld \"192.168.12.34\", met behulp van reverse DNS. Indien niet ingesteld, gebruikt AdGuard Home de adressen van de standaard DNS-resolvers van uw besturingssysteem, behalve de adressen van AdGuard Home zelf.",
|
||||
"local_ptr_default_resolver": "Standaard gebruikt AdGuard Home de volgende omgekeerde DNS-resolvers: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home kon voor dit systeem geen geschikte private omgekeerde DNS-resolvers bepalen.",
|
||||
"local_ptr_placeholder": "Voer één IP-adres per regel in",
|
||||
"resolve_clients_title": "Omzetten van hostnamen van clients inschakelen",
|
||||
"resolve_clients_desc": "Indien ingeschakeld, zal AdGuard Home proberen om IP-adressen van apparaten te converteren in hun hostnamen door PTR-verzoeken te sturen naar overeenkomstige resolvers (privé-DNS-servers voor lokale apparaten, upstream-server voor apparaten met een openbaar IP-adres).",
|
||||
"use_private_ptr_resolvers_title": "Private omgekeerde DNS-resolvers gebruiken",
|
||||
"use_private_ptr_resolvers_desc": "PTR-, SOA- en NS-verzoeken voor ARPA-domeinen die privé-IP-adressen bevatten oplossen via privé-upstreamservers, DHCP, /etc/hosts, enz. Indien uitgeschakeld, zal AdGuard Home op al dergelijke verzoeken reageren met NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Omgekeerde DNS opzoekingen uitvoeren voor locale adressen door deze upstream servers te gebruiken. Indien uitgeschakeld, reageert AdGuard Home met NXDOMAIN op al dergelijke PTR-verzoeken, uitgezonderd voor apparaten gekend van DHCP, /etc/hosts, enz.",
|
||||
"check_dhcp_servers": "Zoek achter DHCP servers",
|
||||
"save_config": "Configuratie opslaan",
|
||||
"enabled_dhcp": "DHCP server inschakelen",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Gebruik AdGuard Ouderlijk toezicht web service",
|
||||
"use_adguard_parental_hint": "AdGuard Home controleert of het domein 18+ content bevat. Dit gebeurt dmv dezelfde privacy vriendelijke API als de Browsing Security web service.",
|
||||
"enforce_safe_search": "Veilig zoeken gebruiken",
|
||||
"enforce_save_search_hint": "AdGuard Home dwingt veilig zoeken af in de volgende zoekmachines: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home kan veilig zoeken forceren voor de volgende zoekmachines: Google, Youtube, Bing, en DuckDuckGo, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Geen servers gespecificeerd",
|
||||
"general_settings": "Algemene instellingen",
|
||||
"dns_settings": "DNS instellingen",
|
||||
@@ -166,7 +166,7 @@
|
||||
"encryption_settings": "Encryptie instellingen",
|
||||
"dhcp_settings": "DHCP instellingen",
|
||||
"upstream_dns": "Upstream DNS-servers",
|
||||
"upstream_dns_help": "Een server-adres per regel invoeren. <a>Meer informatie</a> over het configureren van upstream DNS-servers.",
|
||||
"upstream_dns_help": "Een server-adres per regel invoeren. <a>Meer weten</a> over het configureren van upstream DNS-servers.",
|
||||
"upstream_dns_configured_in_file": "Geconfigureerd in {{path}}",
|
||||
"test_upstream_btn": "Test upstream",
|
||||
"upstreams": "Upstreams",
|
||||
@@ -254,8 +254,8 @@
|
||||
"response_code": "Reactiecode",
|
||||
"client_table_header": "Gebruiker",
|
||||
"empty_response_status": "Leeg",
|
||||
"show_all_filter_type": "Alles weergeven",
|
||||
"show_filtered_type": "Gefilterde weergeven",
|
||||
"show_all_filter_type": "Toon alles",
|
||||
"show_filtered_type": "Toon gefilterde",
|
||||
"no_logs_found": "Geen logboeken gevonden",
|
||||
"refresh_btn": "Verversen",
|
||||
"previous_btn": "Vorige",
|
||||
@@ -495,7 +495,7 @@
|
||||
"setup_dns_privacy_2": "<0>DNS-via-HTTPS:</0> Gebruik <1>{{address}}</1> string.",
|
||||
"setup_dns_privacy_3": "<0>Hou er rekening mee dat het beveiligde DNS protocol alleen beschikbaar is voor Android 9. U moet dus extra software installeren voor andere besturingssystemen.</0><0>Hier is een lijst van te gebruiken software.</0>",
|
||||
"setup_dns_privacy_4": "Op een iOS 14 of macOS Big Sur apparaat kan je een speciaal '.mobileconfig'-bestand downloaden dat <highlight>DNS-via-HTTPS</highlight> of <highlight>DNS-via-TLS</highlight> servers aan de DNS-instellingen toevoegt.",
|
||||
"setup_dns_privacy_android_1": "Android 9 ondersteunt native DNS-via-TLS. Om het te configureren, ga naar Instellingen → Netwerk & internet → Geavanceerd → Privé-DNS en voer daar je domeinnaam in.",
|
||||
"setup_dns_privacy_android_1": "Android 9 ondersteunt native DNS-via-TLS. Om het te configureren, ga naar Instellingen → Netwerk & internet → Geavanceerd → Privé DNS en voer daar je domeinnaam in.",
|
||||
"setup_dns_privacy_android_2": "<0>AdGuard voor Android</0>ondersteunt<1>DNS-via-HTTPS </1>en<1>DNS-via-TLS</1>.",
|
||||
"setup_dns_privacy_android_3": "<0> Intra </0> voegt <1> DNS-via-HTTPS</1> ondersteuning toe aan Android.",
|
||||
"setup_dns_privacy_ios_1": "<0>DNSCloak</0> ondersteunt <1> DNS-via-HTTPS </1>, maar om het te configureren op jouw eigen server moet er een <2> DNS-stempel </2> gegenereerd worden.",
|
||||
@@ -532,7 +532,7 @@
|
||||
"blocked_services_global": "Gebruik algemeen geblokkeerde services",
|
||||
"blocked_service": "Geblokkeerde service",
|
||||
"block_all": "Blokkeer alles",
|
||||
"unblock_all": "Alles deblokkeren",
|
||||
"unblock_all": "Deblokkeer alles",
|
||||
"encryption_certificate_path": "Certificaat pad",
|
||||
"encryption_private_key_path": "Privé sleutel pad",
|
||||
"encryption_certificates_source_path": "Certificaten bestandspad instellen",
|
||||
|
||||
@@ -128,7 +128,6 @@
|
||||
"enforced_save_search": "Påtvungede barnevennlige søk",
|
||||
"number_of_dns_query_to_safe_search": "Antall DNS-forespørsler til søkemotorer der \"Safe Search\" ble fremtvunget",
|
||||
"average_processing_time": "Gjennomsnittlig behandlingstid",
|
||||
"response_time": "Responstid",
|
||||
"average_processing_time_hint": "Gjennomsnittstid for behandling av DNS-forespørsler i millisekunder",
|
||||
"block_domain_use_filters_and_hosts": "Blokker domener ved hjelp av filtre, «hosts»-filer, og rå domener",
|
||||
"filters_block_toggle_hint": "Du kan sette opp blokkeringsoppføringer i <a>Filtre</a>-innstillingene.",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Użyj zapytań równoległych, aby przyspieszyć rozwiązywanie przez jednoczesne wysyłanie zapytań do wszystkich serwerów nadrzędnych.",
|
||||
"parallel_requests": "Równoległe żądania",
|
||||
"load_balancing": "Równoważenie obciążenia",
|
||||
"load_balancing_desc": "Zapytaj jeden serwer nadrzędny na raz. AdGuard Home używa ważonego, losowego algorytmu do wybierania serwerów z najmniejszą liczbą nieudanych wyszukiwań i najniższym uśrednionym czasem wyszukiwania.",
|
||||
"load_balancing_desc": "Wysyłaj zapytania do jednego serwera nadrzędnego na raz. AdGuard Home używa swojego losowego algorytmu ważonego, aby wybrać serwer, tak aby najszybszy serwer był używany częściej.",
|
||||
"bootstrap_dns": "Serwery DNS Bootstrap",
|
||||
"bootstrap_dns_desc": "Adresy IP serwerów DNS używanych do rozpoznawania adresów IP programów rozpoznawania nazw DoH/DoT określonych jako nadrzędne. Komentarze są niedozwolone.",
|
||||
"fallback_dns_title": "Rezerwowe serwery DNS",
|
||||
"fallback_dns_desc": "Lista rezerwowych serwerów DNS używanych, gdy nadrzędne serwery DNS nie odpowiadają. Składnia jest taka sama jak w głównym polu powyżej.",
|
||||
"fallback_dns_placeholder": "Wprowadź jeden rezerwowy serwer DNS w każdym wierszu",
|
||||
"local_ptr_title": "Prywatne odwrotne serwery DNS",
|
||||
"local_ptr_desc": "Serwery DNS używane przez AdGuard Home do prywatnych żądań PTR, SOA i NS. Żądanie jest uważane za prywatne, jeśli prosi o domenę ARPA zawierającą podsieć w prywatnym zakresie adresów IP (np. „192.168.12.34”) i pochodzi od klienta z prywatnym adresem IP. Jeśli nie zostanie ustawione, zostaną użyte domyślne programy rozpoznawania nazw DNS Twojego systemu operacyjnego, z wyjątkiem domowych adresów IP AdGuard.",
|
||||
"local_ptr_desc": "Serwery DNS, których AdGuard Home używa do lokalnych zapytań PTR. Serwery te są używane do rozpoznawania nazw hostów klientów z prywatnymi adresami IP, na przykład „192.168.12.34”, przy użyciu odwrotnego DNS. Jeśli nie jest ustawiona, AdGuard Home używa adresów domyślnych resolwerów DNS systemu operacyjnego, z wyjątkiem adresów samego AdGuard Home.",
|
||||
"local_ptr_default_resolver": "Domyślnie AdGuard Home używa następujących odwrotnych resolwerów DNS: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home nie mógł określić odpowiednich prywatnych resolwerów DNS dla tego systemu.",
|
||||
"local_ptr_placeholder": "Wprowadź po jednym adresie IP w każdym wierszu",
|
||||
"resolve_clients_title": "Włącz odwrotne rozpoznawanie adresów IP klientów",
|
||||
"resolve_clients_desc": "Odwróć adresy IP klientów na ich nazwy hostów, wysyłając zapytania PTR do odpowiednich programów tłumaczących (prywatne serwery DNS dla klientów lokalnych, serwery nadrzędne dla klientów z publicznymi adresami IP).",
|
||||
"use_private_ptr_resolvers_title": "Użyj prywatnych odwrotnych resolwerów DNS",
|
||||
"use_private_ptr_resolvers_desc": "Rozwiązuj żądania PTR, SOA i NS dla domen ARPA zawierających prywatne adresy IP za pośrednictwem prywatnych serwerów nadrzędnych, DHCP, /etc/hosts itp. Jeśli ta opcja jest wyłączona, AdGuard Home będzie odpowiadać na wszystkie takie żądania za pomocą NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Wykonuj odwrotne wyszukiwania DNS dla adresów obsługiwanych lokalnie przy użyciu tych serwerów nadrzędnych. Po wyłączeniu AdGuard Home odpowiada za pomocą NXDOMAIN na wszystkie takie żądania PTR, z wyjątkiem klientów znanych z DHCP, /etc/hosts i tak dalej.",
|
||||
"check_dhcp_servers": "Sprawdź serwery DHCP",
|
||||
"save_config": "Zapisz konfigurację",
|
||||
"enabled_dhcp": "Serwer DHCP włączony",
|
||||
@@ -122,7 +122,7 @@
|
||||
"stats_query_domain": "Najczęściej wyszukiwane domeny",
|
||||
"for_last_hours": "w ciągu ostatniej {{count}} godziny",
|
||||
"for_last_hours_plural": "w ciągu ostatnich {{count}} godzin",
|
||||
"for_last_days": "za ostatni {{count}} dzień",
|
||||
"for_last_days": "za ostatni dzień {{count}}",
|
||||
"for_last_days_plural": "z ostatnich {{count}} dni",
|
||||
"stats_disabled": "Statystyki zostały wyłączone. Można je włączyć na <0>stronie ustawień</0>.",
|
||||
"stats_disabled_short": "Statystyki zostały wyłączone",
|
||||
@@ -130,7 +130,7 @@
|
||||
"requests_count": "Licznik żądań",
|
||||
"top_blocked_domains": "Najpopularniejsze zablokowane domeny",
|
||||
"top_clients": "Główni klienci",
|
||||
"no_clients_found": "Nie znaleziono klientów",
|
||||
"no_clients_found": "Nie znaleziono klienta",
|
||||
"general_statistics": "Ogólne statystyki",
|
||||
"top_upstreams": "Często żądane serwery nadrzędne",
|
||||
"no_upstreams_data_found": "Brak danych dotyczących serwerów nadrzędnych",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Użyj usługi Kontrola Rodzicielska AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home sprawdzi, czy domena zawiera materiały dla dorosłych. Używa tego samego interfejsu API przyjaznego prywatności, co usługa sieciowa Bezpieczne Przeglądanie. ",
|
||||
"enforce_safe_search": "Użyj bezpiecznego wyszukiwania",
|
||||
"enforce_save_search_hint": "AdGuard Home wymusza bezpieczne wyszukiwanie w następujących wyszukiwarkach: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home wymusza bezpieczne wyszukiwanie w następujących wyszukiwarkach: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Nie określono serwerów",
|
||||
"general_settings": "Ustawienia główne",
|
||||
"dns_settings": "Ustawienia DNS",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Usar consultas paralelas para acelerar a resolução consultando simultaneamente todos os servidores DNS primário",
|
||||
"parallel_requests": "Solicitações paralelas",
|
||||
"load_balancing": "Balanceamento de carga",
|
||||
"load_balancing_desc": "Consulte um servidor upstream por vez. O AdGuard Home usa um algoritmo aleatório ponderado para selecionar servidores com o menor número de falhas e o menor tempo médio de consulta.",
|
||||
"load_balancing_desc": "Consulte um servidor DNS primário por vez. O AdGuard Home usa seu algoritmo aleatório ponderado para escolher o servidor para que o servidor mais rápido seja usado com mais frequência.",
|
||||
"bootstrap_dns": "Servidores DNS de inicialização",
|
||||
"bootstrap_dns_desc": "Endereços IP de servidores DNS usados para resolver endereços IP dos resolvedores DoH/DoT que você especifica como upstreams. Comentários não são permitidos.",
|
||||
"fallback_dns_title": "Servidores DNS Fallback",
|
||||
"fallback_dns_desc": "Lista de servidores DNS Fallback usados quando os servidores DNS primários não estão respondendo. A sintaxe é a mesma dos campos de servidores principais na seção acima.",
|
||||
"fallback_dns_placeholder": "Insira um servidor DNS fallback por linha",
|
||||
"local_ptr_title": "Servidores DNS reversos privados",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home utiliza para consultas privadas de PTR, SOA e NS. A solicitação é considerada privada se solicitar um domínio ARPA contendo uma sub-rede dentro de intervalos de IP privados, por exemplo \"192.168.12.34\", e vier de um cliente com endereço privado. Se não for definido, o AdGuard Home usará os endereços dos resolvedores DNS padrão do seu sistema operacional, exceto os endereços do próprio AdGuard Home.",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver solicitações de PTR para endereços em intervalos de IP privados, por exemplo \"192.168.12.34\", usando DNS reverso. Se não estiver definido, o AdGuard Home usa os endereços dos resolvedores de DNS padrão do seu sistema operacional, exceto os endereços do próprio AdGuard Home.",
|
||||
"local_ptr_default_resolver": "Por padrão, o AdGuard Home usa os seguintes resolvedores de DNS reverso: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "A página inicial do AdGuard não conseguiu determinar resolvedores DNS reversos privados adequados para este sistema.",
|
||||
"local_ptr_placeholder": "Insira um endereço IP por linha",
|
||||
"resolve_clients_title": "Ativar resolução reversa de endereços IP de clientes",
|
||||
"resolve_clients_desc": "Resolva reversamente os endereços IP dos clientes em seus nomes de host, enviando consultas PTR aos resolvedores correspondentes (servidores DNS privados para clientes locais, servidores upstream para clientes com endereços IP públicos).",
|
||||
"use_private_ptr_resolvers_title": "Usar resolvedores DNS reversos privados",
|
||||
"use_private_ptr_resolvers_desc": "Resolver solicitações PTR, SOA e NS para domínios ARPA contendo endereços privados usando servidores upstream privados, DHCP, /etc/hosts e assim por diante. Se desativado, o AdGuard Home responde a todas essas consultas com NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Execute pesquisas reversas de DNS para endereços servidos localmente usando esses servidores DNS primário. Se desativado, o AdGuard Home responde com NXDOMAIN a todas essas solicitações PTR, exceto para clientes conhecidos de DHCP, /etc/hosts e assim por diante.",
|
||||
"check_dhcp_servers": "Verificar por servidores DHCP",
|
||||
"save_config": "Salvar configuração",
|
||||
"enabled_dhcp": "Servidor DHCP ativado",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Usar o serviço de controle parental do AdGuard",
|
||||
"use_adguard_parental_hint": "O AdGuard Home irá verificar se o domínio contém conteúdo adulto. Ele usa a mesma API amigável de privacidade que o serviço de segurança da navegação.",
|
||||
"enforce_safe_search": "Usar pesquisa segura",
|
||||
"enforce_save_search_hint": "O AdGuard Home forcará a pesquisa segura nos seguintes motores de busca: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "O AdGuard Home forcará a pesquisa segura nos seguintes motores de busca: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Nenhum servidor especificado",
|
||||
"general_settings": "Configurações gerais",
|
||||
"dns_settings": "Configurações de DNS",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Usar consultas paralelas para acelerar a resolução consultando simultaneamente todos os servidores DNS",
|
||||
"parallel_requests": "Solicitações paralelas",
|
||||
"load_balancing": "Balanceamento de carga",
|
||||
"load_balancing_desc": "Consulta um servidor a montante de cada vez. O AdGuard Home usa um algoritmo aleatório ponderado para selecionar servidores com o menor número de pesquisas com falha e o menor tempo médio de pesquisa.",
|
||||
"load_balancing_desc": "Consulte um servidor DNS primário por vez. O AdGuard Home usa seu algoritmo aleatório ponderado para escolher o servidor para que o servidor mais rápido seja usado com mais frequência.",
|
||||
"bootstrap_dns": "Servidores DNS de arranque",
|
||||
"bootstrap_dns_desc": "Endereços IP de servidores DNS usados para resolver endereços IP dos resolvedores DoH/DoT que você especifica como upstreams. Comentários não são permitidos.",
|
||||
"fallback_dns_title": "Servidores DNS de fallback",
|
||||
"fallback_dns_desc": "Lista de servidores DNS de fallback usados quando os servidores DNS upstream não estão respondendo. A sintaxe é a mesma do campo principal de upstreams acima.",
|
||||
"fallback_dns_placeholder": "Insira um servidor DNS de fallback por linha",
|
||||
"local_ptr_title": "Servidores DNS reversos privados",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home utiliza para consultas privadas de PTR, SOA e NS. A solicitação é considerada privada se solicitar um domínio ARPA contendo uma sub-rede dentro de intervalos de IP privados, por exemplo \"192.168.12.34\", e vier de um cliente com endereço privado. Se não for definido, o AdGuard Home usará os endereços dos resolvedores DNS padrão do seu sistema operacional, exceto os endereços do próprio AdGuard Home.",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver solicitações de PTR para endereços em intervalos de IP privados, por exemplo \"192.168.12.34\", usando DNS reverso. Se não estiver definido, o AdGuard Home usa os endereços dos resolvedores de DNS padrão do seu sistema operacional, exceto os endereços do próprio AdGuard Home.",
|
||||
"local_ptr_default_resolver": "Por predefinição, o AdGuard Home usa os seguintes resolvedores de DNS reverso: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "A página inicial do AdGuard não conseguiu determinar resolvedores DNS reversos privados adequados para este sistema.",
|
||||
"local_ptr_placeholder": "Insira um endereço IP por linha",
|
||||
"resolve_clients_title": "Ativar resolução reversa de endereços IP de clientes",
|
||||
"resolve_clients_desc": "Resolva reversamente os endereços IP dos clientes em seus nomes de host, enviando consultas PTR aos resolvedores correspondentes (servidores DNS privados para clientes locais, servidores upstream para clientes com endereços IP públicos).",
|
||||
"use_private_ptr_resolvers_title": "Usar resolvedores DNS reversos privados",
|
||||
"use_private_ptr_resolvers_desc": "Resolver solicitações PTR, SOA e NS para domínios ARPA contendo endereços privados usando servidores upstream privados, DHCP, /etc/hosts e assim por diante. Se desativado, o AdGuard Home responde a todas essas consultas com NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Execute pesquisas reversas de DNS para endereços servidos localmente usando esses servidores DNS primário. Se desativado, o AdGuard Home responde com NXDOMAIN a todas essas solicitações PTR, exceto para clientes conhecidos de DHCP, /etc/hosts e assim por diante.",
|
||||
"check_dhcp_servers": "Verificar por servidores DHCP",
|
||||
"save_config": "Guardar definição",
|
||||
"enabled_dhcp": "Servidor DHCP ativado",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Usar o serviço de controlo parental do AdGuard",
|
||||
"use_adguard_parental_hint": "O AdGuard Home irá verificar se o domínio contém conteúdo adulto. Usa a mesma API amigável de privacidade que o serviço de segurança da navegação.",
|
||||
"enforce_safe_search": "Usar pesquisa segura",
|
||||
"enforce_save_search_hint": "O AdGuard Home aplicará pesquisa segura nos seguintes motores de busca: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "O AdGuard Home forçará a pesquisa segura nos seguintes motores de busca: Google, Youtube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Nenhum servidor especificado",
|
||||
"general_settings": "Definições gerais",
|
||||
"dns_settings": "Definições de DNS",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Использовать параллельные запросы ко всем серверам одновременно для ускорения обработки запроса.",
|
||||
"parallel_requests": "Параллельные запросы",
|
||||
"load_balancing": "Распределение нагрузки\n",
|
||||
"load_balancing_desc": "Запрашивайте по одному серверу за раз. AdGuard Home использует алгоритм случайной выборки с учётом веса для выбора серверов с наименьшим количеством неудачных запросов и наименьшим средним временем выполнения запроса.",
|
||||
"load_balancing_desc": "Запрашивать по одному серверу за раз. AdGuard Home использует алгоритм взвешенного случайного выбора сервера, так что самый быстрый сервер используется чаще.",
|
||||
"bootstrap_dns": "Bootstrap DNS-серверы",
|
||||
"bootstrap_dns_desc": "IP-адреса DNS-серверов, используемых для поиска IP-адресов DoH/DoT upstream-серверов, которые вы указали. Комментарии не допускаются.",
|
||||
"fallback_dns_title": "Резервные DNS-серверы",
|
||||
"fallback_dns_desc": "Список резервных DNS-серверов, используемых в тех случаях, когда вышестоящие DNS-серверы недоступны. Синтаксис такой же, как и в поле Upstream DNS-серверы выше.",
|
||||
"fallback_dns_placeholder": "Введите один резервный DNS-сервер в каждой строке",
|
||||
"local_ptr_title": "Приватные серверы для обратного DNS",
|
||||
"local_ptr_desc": "DNS-серверы, которые AdGuard Home использует для локальных PTR, SOA и NS-запросов. Запрос считается локальным, если он запрашивает информацию об ARPA-домене, подсеть которого в локальном IP-диапазоне (например, «192.168.12.34»), и если при этом запрос пришел от клиента с локальным адресом. Если значение не установлено, AdGuard Home использует адреса DNS-серверы по умолчанию в вашей ОС, за исключением адресов самого AdGuard Home.",
|
||||
"local_ptr_desc": "DNS-серверы, которые AdGuard Home использует для локальных PTR-запросов. Эти серверы используются, чтобы получить доменные имена клиентов с приватными IP-адресами, например «192.168.12.34», с помощью обратного DNS. Если список пуст, AdGuard Home использует DNS-серверы по умолчанию вашей ОС.",
|
||||
"local_ptr_default_resolver": "По умолчанию AdGuard Home использует следующие обратные DNS-резолверы: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home не смог определить подходящие приватные обратные DNS-резолверы для этой системы.",
|
||||
"local_ptr_placeholder": "Введите по одному адресу на строчку",
|
||||
"resolve_clients_title": "Включить запрашивание доменных имён для IP-адресов клиентов",
|
||||
"resolve_clients_desc": "Определять доменные имена клиентов через PTR-запросы к соответствующим серверам (приватные DNS-серверы для локальных клиентов, upstream-серверы для клиентов с публичным IP-адресом).",
|
||||
"use_private_ptr_resolvers_title": "Использовать приватные обратные DNS-резолверы",
|
||||
"use_private_ptr_resolvers_desc": "Посылать PTR, SOA и NS-запросы для ARPA-доменов, содержащих локальные адреса, с помощью указанных upstream-серверов, DHCP, /etc/hosts и так далее. Если отключено, AdGuard Home отвечает NXDOMAIN на все подобные запросы.",
|
||||
"use_private_ptr_resolvers_desc": "Посылать обратные DNS-запросы для локально обслуживаемых адресов на указанные серверы. Если отключено, AdGuard Home будет отвечать NXDOMAIN на все подобные PTR-запросы, кроме запросов о клиентах, уже известных по DHCP, /etc/hosts и так далее.",
|
||||
"check_dhcp_servers": "Проверить DHCP-серверы",
|
||||
"save_config": "Сохранить конфигурацию",
|
||||
"enabled_dhcp": "DHCP-сервер включён",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Включить модуль Родительского контроля AdGuard ",
|
||||
"use_adguard_parental_hint": "AdGuard Home проверит, содержит ли домен материалы 18+. Он использует тот же API для обеспечения конфиденциальности, что и веб-служба безопасности браузера.",
|
||||
"enforce_safe_search": "Включить безопасный поиск",
|
||||
"enforce_save_search_hint": "AdGuard Home будет обеспечивать безопасный поиск в следующих поисковых системах: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home может обеспечить безопасный поиск в следующих поисковых системах: Google, YouTube, Bing, DuckDuckGo, Yandex и Pixabay.",
|
||||
"no_servers_specified": "Нет указанных серверов",
|
||||
"general_settings": "Основные настройки",
|
||||
"dns_settings": "Настройки DNS",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"local_ptr_desc": "ස්ථානීය PTR විමසුම් සඳහා ඇඩ්ගාර්ඩ් හෝම් භාවිතා කරන ව.නා.ප. සේවාදායක. මෙම සේවාදායක පුද්ගලික අ.ජා.කෙ. ලිපින පරාසවල PTR විමසුම් විසඳීමට භාවිතා කරයි, උදාහරණයක් ලෙස ප්රතිවර්ත ව.නා.ප. භාවිතයෙන් \"192.168.12.34\". මෙය සකසා නැති නම්, ඇඩ්ගාර්ඩ් හෝම් හි ලිපින සඳහා හැරුනු විට ඔබගේ මෙහෙයුම් පද්ධතියේ පෙරනිමි ව.නා.ප. විසදුම්වල ලිපින භාවිතා කරයි.",
|
||||
"local_ptr_default_resolver": "පෙරනිමි පරිදි, ඇඩ්ගාර්ඩ් හෝම් පහත ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු භාවිතා කරයි: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "ඇඩ්ගාර්ඩ් හෝම් හට මෙම පද්ධතිය සඳහා සුදුසු පුද්ගලික ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු නිශ්චය කරගත නොහැකි විය.",
|
||||
"local_ptr_placeholder": "පේළියකට අ.ජා.කෙ. ලිපිනය බැගින් ලියන්න",
|
||||
"local_ptr_placeholder": "පේළියකට එක් සේවාදායක ලිපිනය බැගින් යොදන්න",
|
||||
"resolve_clients_title": "අනුග්රාහකවල අ.ජා.කෙ. ලිපින ප්රතිවර්ත විසඳීම සබල කරන්න",
|
||||
"use_private_ptr_resolvers_title": "පෞද්. ප්රතිවර්ත ව.නා.ප. පිළිවිසඳු භාවිතය",
|
||||
"check_dhcp_servers": "ග.ධා.වි.කෙ. සේවාදායක පරීක්ෂා කරන්න",
|
||||
@@ -102,6 +102,7 @@
|
||||
"stats_malware_phishing": "අවහිර කළ ද්වේශාංග/තතුබෑම්",
|
||||
"stats_adult": "අවහිර කළ වැඩිහිටි වියමන අඩවි",
|
||||
"stats_query_domain": "ප්රචලිත විමසන ලද වසම්",
|
||||
"for_last_24_hours": "පසුගිය පැය 24 සඳහා",
|
||||
"for_last_days": "පසුගිය දවස් {{count}} සඳහා",
|
||||
"for_last_days_plural": "පසුගිය දවස් {{count}} සඳහා",
|
||||
"stats_disabled": "සංඛ්යාලේඛන අබල කර ඇත. එය <0>සැකසුම් පිටුවෙන්</0> සබල කළ හැකිය.",
|
||||
@@ -114,15 +115,13 @@
|
||||
"general_statistics": "පොදු සංඛ්යාලේඛන",
|
||||
"number_of_dns_query_days": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||
"number_of_dns_query_days_plural": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||
"number_of_dns_query_hours": "පසුගිය පැය {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||
"number_of_dns_query_hours_plural": "පසුගිය පැය {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||
"number_of_dns_query_24_hours": "පසුගිය පැය 24 සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන",
|
||||
"number_of_dns_query_blocked_24_hours": "දැන්වීම් වාරණ පෙරහන් සහ සත්කාරක වාරණ ලැයිස්තු මගින් අවහිර කළ ව.නා.ප. ඉල්ලීම් ගණන",
|
||||
"number_of_dns_query_blocked_24_hours_by_sec": "ඇඩ්ගාර්ඩ් පිරික්සුම් ආරක්ෂණ ඒකකය මගින් අවහිර කළ ව.නා.ප. ඉල්ලීම් ගණන",
|
||||
"number_of_dns_query_blocked_24_hours_adult": "අවහිර කළ වැඩිහිටි වියමන අඩවි ගණන",
|
||||
"enforced_save_search": "ආරක්ෂිත සෙවීම බලාත්මක කළ",
|
||||
"number_of_dns_query_to_safe_search": "ආරක්ෂිත සෙවීම බලාත්මක කළ සෙවුම් යන්ත්ර සඳහා ව.නා.ප. ඉල්ලීම් ගණන",
|
||||
"average_processing_time": "සාමාන්ය සැකසුම් කාලය",
|
||||
"response_time": "ප්රතිචාර කාලය",
|
||||
"average_processing_time_hint": "ව.නා.ප. ඉල්ලීමක් සැකසීමේ සාමාන්ය කාලය මිලි තත්පර වලින්",
|
||||
"block_domain_use_filters_and_hosts": "පෙරහන් හා සත්කාරක ගොනු භාවිතයෙන් වසම් අවහිර කරන්න",
|
||||
"filters_block_toggle_hint": "ඔබට අවහිර කිරීමේ නීති <a>පෙරහන්</a> තුළ පිහිටුවිය හැකිය.",
|
||||
@@ -131,7 +130,7 @@
|
||||
"use_adguard_parental": "ඇඩ්ගාර්ඩ් දෙමාපිය පාලන වියමන සේවාව භාවිතා කරන්න",
|
||||
"use_adguard_parental_hint": "වසමේ වැඩිහිටියන්ට අදාල කරුණු අඩංගු දැයි ඇඩ්ගාර්ඩ් හෝම් විසින් පරීක්ෂා කරනු ඇත. එය පිරික්සුම් ආරක්ෂණ වියමන සේවාව මෙන් රහස්යතා හිතකාමී යෙ.ක්ර. අ.මු. (API) භාවිතා කරයි.",
|
||||
"enforce_safe_search": "ආරක්ෂිත සෙවුම භාවිතා කරන්න",
|
||||
"enforce_save_search_hint": "ඇඩ්ගාර්ඩ් හෝම් පහත සෙවුම් යන්ත්ර තුළ ආරක්ෂිත සෙවුම බලාත්මක කරනු ඇත: ගූගල්, යූටියුබ්, බින්ග්, ඩක්ඩක්ගෝ, එකොසියා, යාන්ඩෙක්ස් සහ පික්සාබේ.",
|
||||
"enforce_save_search_hint": "ඇඩ්ගාර්ඩ් හෝම් පහත සෙවුම් යන්ත්ර තුළ ආරක්ෂිත සෙවුම බලාත්මක කරනු ඇත: ගූගල්, යූටියුබ්, බින්ග්, ඩක්ඩක්ගෝ, යාන්ඩෙක්ස් සහ පික්සාබේ.",
|
||||
"no_servers_specified": "සේවාදායක කිසිවක් නිශ්චිතව දක්වා නැත",
|
||||
"general_settings": "පොදු සැකසුම්",
|
||||
"dns_settings": "ව.නා.ප. සැකසුම්",
|
||||
@@ -197,14 +196,12 @@
|
||||
"example_comment_hash": "# එසේම අදහස් දැක්වීමක්.",
|
||||
"example_regex_meaning": "නිශ්චිතව දක්වා ඇති නිත්ය වාක්යවිධියට ගැළපෙන වසම් වෙත ප්රවේශය අවහිර කරයි.",
|
||||
"example_upstream_regular": "සාමාන්ය ව.නා.ප. (UDP හරහා);",
|
||||
"example_upstream_regular_port": "සාමාන්ය ව.නා.ප. (UDP හරහා, තොට සමඟ);",
|
||||
"example_upstream_udp": "සාමාන්ය ව.නා.ප. (UDP, සත්කාරක-නම හරහා);",
|
||||
"example_upstream_dot": "සංකේතිත <0>TLS-මගින්-ව.නා.ප.</0>;",
|
||||
"example_upstream_doh": "සංකේතිත <0>HTTPS-මගින්-ව.නා.ප.</0>;",
|
||||
"example_upstream_doq": "සංකේතිත <0>QUIC-මගින්-ව.නා.ප.</0>;",
|
||||
"example_upstream_sdns": "<1>DNSCrypt</1> හෝ <2>HTTPS-මගින්-ව.නා.ප.</2> පිළිවිසඳු සඳහා <0>ව.නා.ප. මුද්දර</0>;",
|
||||
"example_upstream_tcp": "සාමාන්ය ව.නා.ප. (TCP/ස.පා.කෙ. හරහා);",
|
||||
"example_upstream_tcp_port": "සාමාන්ය ව.නා.ප. (TCP හරහා, තොට සමඟ);",
|
||||
"example_upstream_tcp_hostname": "සාමාන්ය ව.නා.ප. (ස.පා.කෙ., සත්කාරක-නම හරහා);",
|
||||
"all_lists_up_to_date_toast": "සියළුම ලැයිස්තු දැනටමත් යාවත්කාලීනයි",
|
||||
"dns_test_ok_toast": "සඳහන් කළ ව.නා.ප. සේවාදායක නිවැරදිව ක්රියා කරයි",
|
||||
@@ -278,7 +275,6 @@
|
||||
"edns_use_custom_ip": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. යොදාගන්න",
|
||||
"edns_use_custom_ip_desc": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. භාවිතයට ඉඩදෙන්න",
|
||||
"rate_limit_desc": "එක් අනුග්රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.",
|
||||
"rate_limit_whitelist_placeholder": "පේළියකට අ.ජා.කෙ. ලිපිනය බැගින් ලියන්න",
|
||||
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
||||
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
||||
"blocking_mode_default": "පොදු: දැන්වීම් අවහිර කරන ආකාරයේ නීතියක් මගින් අවහිර කළ විට REFUSED සමඟ ප්රතිචාර දක්වයි; /etc/host-style ආකාරයේ නීතියක් මගින් අවහිර කළ විට නීතියේ දක්වා ඇති අ.ජා.කෙ. ලිපිනය සමඟ ප්රතිචාර දක්වයි",
|
||||
@@ -509,8 +505,8 @@
|
||||
"statistics_enable": "සංඛ්යාලේඛන සබල කරන්න",
|
||||
"ignore_domains": "නොසලකන වසම් (පේළියකට එක බැගින්)",
|
||||
"ignore_domains_title": "නොසලකන වසම්",
|
||||
"ignore_domains_desc_stats": "මෙම නීති වලට ගැළපෙන විමසුම් සංඛ්යාලේඛනයට නොලියැවෙයි",
|
||||
"ignore_domains_desc_query": "විමසුම් සටහනට මෙම නීති වලට ගැළපෙන විමසුම් නොලියැවෙයි",
|
||||
"ignore_domains_desc_stats": "සංඛ්යාලේඛනයෙහි මෙම වසම් සඳහා විමසුම් නොලියැවෙයි",
|
||||
"ignore_domains_desc_query": "විමසුම් සටහනෙහි මෙම වසම් සඳහා විමසුම් නොලියැවෙයි",
|
||||
"interval_hours": "පැය {{count}}",
|
||||
"interval_hours_plural": "පැය {{count}}",
|
||||
"filters_configuration": "පෙරහන් වින්යාසය",
|
||||
@@ -619,8 +615,8 @@
|
||||
"use_saved_key": "පෙර සුරැකි යතුර භාවිතා කරන්න",
|
||||
"parental_control": "දෙමාපිය පාලනය",
|
||||
"safe_browsing": "ආරක්ෂිත පිරික්සුම",
|
||||
"served_from_cache_label": "නිහිතයෙන් සැපයිණි",
|
||||
"form_error_password_length": "මුරපදය අකුරු {{min}} සහ {{value}} ක් අතර විය යුතුය",
|
||||
"served_from_cache": "{{value}} <i>(නිහිතයෙන් ගැනිණි)</i>",
|
||||
"form_error_password_length": "මුරපදය අවම වශයෙන් අකුරු {{value}} ක් දිගු විය යුතුමයි",
|
||||
"anonymizer_notification": "<0>සටහන:</0> අ.ජා.කෙ. නිර්නාමිකකරණය සබලයි. ඔබට එය <1>පොදු සැකසුම්</1> හරහා අබල කිරීමට හැකිය .",
|
||||
"confirm_dns_cache_clear": "ඔබට ව.නා.ප. නිහිතය හිස් කිරීමට වුවමනාද?",
|
||||
"cache_cleared": "ව.නා.ප. නිහිතය හිස් කෙරිණි",
|
||||
@@ -650,7 +646,6 @@
|
||||
"log_and_stats_section_label": "විමසුම් සටහන හා සංඛ්යාලේඛන",
|
||||
"ignore_query_log": "විමසුම් සටහනට මෙම අනුග්රාහකය යොදන්න එපා",
|
||||
"ignore_statistics": "සංඛ්යාලේඛනයට මෙම අනුග්රාහකය යොදන්න එපා",
|
||||
"schedule_services": "සේවා අවහිර විරාමය",
|
||||
"schedule_invalid_select": "ආරම්භක වේලාව අවසන් වේලාවට කලින් විය යුතුය",
|
||||
"schedule_select_days": "දවස් තෝරන්න",
|
||||
"schedule_timezone": "වේලා කලාපයක් තෝරන්න",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Používať paralelné dopyty na zrýchlenie súčasným dopytovaním všetkých upstream serverov súčasne.",
|
||||
"parallel_requests": "Paralelné dopyty",
|
||||
"load_balancing": "Vyrovnávanie záťaže",
|
||||
"load_balancing_desc": "Dopytuje sa súčasne len jeden upstream server. AdGuard Home používa vážený náhodný algoritmus na výber serverov s najnižším počtom neúspešných vyhľadávaní a najnižším priemerným časom vyhľadávania.",
|
||||
"load_balancing_desc": "Dopytovať len jeden server v danom čase. AdGuard Home použije na výber servera vážený náhodný algoritmus, aby sa najrýchlejší server používal častejšie.",
|
||||
"bootstrap_dns": "Bootstrap DNS servery",
|
||||
"bootstrap_dns_desc": "IP adresy serverov DNS používaných na rozlíšenie IP adries prekladačov DoH/DoT, ktoré zadáte ako upstream. Komentáre nie sú povolené.",
|
||||
"fallback_dns_title": "Záložné servery DNS",
|
||||
"fallback_dns_desc": "Zoznam záložných serverov DNS, ktoré sa používajú, keď nadradený servery DNS neodpovedajú. Syntax je rovnaká ako v hlavnom poli vyššie.",
|
||||
"fallback_dns_placeholder": "Zadajte jeden záložný server DNS na riadok",
|
||||
"local_ptr_title": "Súkromné reverzné DNS servery",
|
||||
"local_ptr_desc": "Servery DNS, ktoré používa AdGuard Home na súkromné dopyty PTR, SOA a NS. Dopyt sa považuje za súkromný, ak požaduje doménu ARPA obsahujúcu podsieť v rozsahu súkromnej IP adresy (napríklad „192.168.12.34“) a pochádza od klienta so súkromnou IP adresou. Ak nie je nastavené, použijú sa predvolené DNS resolvery Vášho operačného systému, okrem AdGuard Home IP adries.",
|
||||
"local_ptr_desc": "DNS servery, ktoré AdGuard Home používa pre miestne PTR dopyty. Tieto servery sa používajú na rozlíšenie názvov hostiteľov klientov so súkromnými adresami IP, napríklad \"192.168.12.34\", pomocou reverzného DNS. Ak nie je nastavené inak, AdGuard Home použije adresy predvolených prekladačov DNS Vášho operačného systému okrem adries samotného AdGuard Home.",
|
||||
"local_ptr_default_resolver": "V predvolenom nastavení používa AdGuard Home nasledujúce reverzné DNS prekladače: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home nemohol určiť vhodné súkromné reverzné DNS prekladače pre tento systém.",
|
||||
"local_ptr_placeholder": "Na každý riadok zadajte IP adresu jedného servera",
|
||||
"resolve_clients_title": "Povoliť spätný preklad IP adries klientov",
|
||||
"resolve_clients_desc": "Reverzne rozlišuje adresy IP klientov na ich názvy hostiteľov odosielaním PTR dopytov príslušným prekladačom (súkromné DNS servery pre miestnych klientov, servery typu upstream pre klientov s verejnými IP adresami).",
|
||||
"use_private_ptr_resolvers_title": "Použiť súkromné reverzné DNS resolvery",
|
||||
"use_private_ptr_resolvers_desc": "Riešenie dopytov PTR, SOA a NS pre domény ARPA obsahujúce súkromné IP adresy prostredníctvom súkromných upstream serverov, DHCP, /etc/hosts atď. Ak je vypnuté, AdGuard Home bude na všetky takéto dopyty odpovedať pomocou NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Realizuje reverzné vyhľadávanie DNS pre lokálne adresy pomocou týchto upstream serverov. Ak je funkcia vypnutá, Adguard Home reaguje s NXDOMAIN na všetky takéto PTR dopyty okrem klientov známych z DHCP, /etc/hosts, a tak ďalej.",
|
||||
"check_dhcp_servers": "Skontrolovať DHCP servery",
|
||||
"save_config": "Uložiť konfiguráciu",
|
||||
"enabled_dhcp": "DHCP server zapnutý",
|
||||
@@ -89,7 +89,7 @@
|
||||
"form_enter_hostname": "Zadajte meno hostiteľa",
|
||||
"error_details": "Podrobnosti chyby",
|
||||
"response_details": "Podrobnosti odpovede",
|
||||
"request_details": "Podrobnosti dopytu",
|
||||
"request_details": "Podrobnosti požiadavky",
|
||||
"client_details": "Podrobnosti klienta",
|
||||
"details": "Podrobnosti",
|
||||
"back": "Naspäť",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Použiť AdGuard službu Rodičovská kontrola",
|
||||
"use_adguard_parental_hint": "AdGuard Home skontroluje, či doména obsahuje materiály pre dospelých. Používa rovnaké API priateľské k ochrane osobných údajov ako služba Bezpečného prehliadania.",
|
||||
"enforce_safe_search": "Používať bezpečné vyhľadávanie",
|
||||
"enforce_save_search_hint": "AdGuard Home vynúti bezpečné vyhľadávanie v nasledujúcich vyhľadávačoch: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home vynucuje bezpečné vyhľadávanie v nasledujúcich vyhľadávačoch: Google, YouTube, Bing, DuckDuckGo, Yandex a Pixabay.",
|
||||
"no_servers_specified": "Neboli špecifikované žiadne servery",
|
||||
"general_settings": "Všeobecné nastavenia",
|
||||
"dns_settings": "Nastavenia DNS",
|
||||
@@ -308,7 +308,7 @@
|
||||
"form_enter_rate_limit": "Zadajte rýchlostný limit",
|
||||
"rate_limit": "Rýchlostný limit",
|
||||
"edns_enable": "Povoliť klientsku podsiete EDNS",
|
||||
"edns_cs_desc": "Pridáva možnosť EDNS Client Subnet (ECS) do upstream dopytov a zapíše hodnoty odoslané klientami do denníka dopytov.",
|
||||
"edns_cs_desc": "Pridáva možnosť EDNS Client Subnet (ECS) do upstream požiadaviek a zapíše hodnoty odoslané klientmi do denníka dopytov.",
|
||||
"edns_use_custom_ip": "Použiť vlastnú IP adresu pre EDNS",
|
||||
"edns_use_custom_ip_desc": "Povoliť používanie vlastnej IP adresy pre EDNS",
|
||||
"rate_limit_desc": "Počet požiadaviek za sekundu, ktoré môže jeden klient vykonať. Nastavenie na hodnotu 0 znamená neobmedzene.",
|
||||
@@ -480,11 +480,11 @@
|
||||
"access_title": "Nastavenia prístupu",
|
||||
"access_desc": "Tu môžete konfigurovať pravidlá prístupu pre server DNS AdGuard Home.",
|
||||
"access_allowed_title": "Povolení klienti",
|
||||
"access_allowed_desc": "Zoznam CIDR, IP adries alebo <a>ClientID</a>. Ak tento zoznam obsahuje položky, AdGuard Home bude akceptovať dopyty iba od týchto klientov.",
|
||||
"access_allowed_desc": "Zoznam CIDR, IP adries alebo <a>ClientID</a>. Ak tento zoznam obsahuje položky, AdGuard Home bude akceptovať požiadavky iba od týchto klientov.",
|
||||
"access_disallowed_title": "Nepovolení klienti",
|
||||
"access_disallowed_desc": "Zoznam CIDR, IP adries alebo <a>ClientID</a>. Ak tento zoznam obsahuje položky, AdGuard Home zruší dopyty od týchto klientov. Toto pole sa ignoruje, ak sú v poli Povolení klienti položky.",
|
||||
"access_disallowed_desc": "Zoznam CIDR, IP adries alebo <a>ClientID</a>. Ak tento zoznam obsahuje položky, AdGuard Home zruší požiadavky od týchto klientov. Toto pole sa ignoruje, ak sú v poli Povolení klienti položky.",
|
||||
"access_blocked_title": "Nepovolené domény",
|
||||
"access_blocked_desc": "Nesmie byť zamieňaná s filtrami. AdGuard Home zruší DNS dopyty, ktoré sa zhodujú s týmito doménami, a tieto dopyty sa nezobrazia ani v denníku dopytov. Môžete určiť presné názvy domén, zástupné znaky alebo pravidlá filtrácie URL adries, napr. \"example.org\", \"*.example.org\" alebo ||example.org^\" zodpovedajúcim spôsobom.",
|
||||
"access_blocked_desc": "Nesmie byť zamieňaná s filtrami. AdGuard Home zruší DNS dopyty, ktoré sa zhodujú s týmito doménami, a tieto dopyty sa nezobrazia ani v denníku dopytov. Môžete určiť presné názvy domén, zástupné znaky alebo pravidlá filtrovania URL adries, napr. \"example.org\", \"*.example.org\" alebo ||example.org^\" zodpovedajúcim spôsobom.",
|
||||
"access_settings_saved": "Nastavenia prístupu úspešne uložené",
|
||||
"updates_checked": "K dispozícii je nová verzia aplikácie AdGuard Home\n",
|
||||
"updates_version_equal": "AdGuard Home je aktuálny",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"load_balancing_desc": "Fråga en uppströmsserver åt gången. AdGuard Home använder sin viktade slumpmässiga algoritm för att välja server så att den snabbaste servern används oftare.",
|
||||
"bootstrap_dns": "Bootstrap-DNS-servrar",
|
||||
"bootstrap_dns_desc": "IP-adresser för DNS-servrar som används för att lösa IP-adresser för de DoH/DoT-resolvers som du anger som uppströms. Kommentarer är inte tillåtna.",
|
||||
"fallback_dns_title": "Reserv DNS-servrar",
|
||||
"fallback_dns_title": "Reserv-DNS-servrar",
|
||||
"fallback_dns_desc": "Lista över reserv-DNS-servrar som används när uppströms DNS-servrar inte svarar. Syntaxen är densamma som i huvuduppströmsfältet ovan.",
|
||||
"fallback_dns_placeholder": "Ange en reserv-DNS-server per rad",
|
||||
"local_ptr_title": "Privata omvända DNS-servrar",
|
||||
@@ -141,8 +141,8 @@
|
||||
"number_of_dns_query_blocked_24_hours": "Antalet DNS-förfrågningar som blockerades av annonsfilter och värdens blockeringsklistor",
|
||||
"number_of_dns_query_blocked_24_hours_by_sec": "Antalet DNS-förfrågningar som blockerades av AdGuards modul för surfsäkerhet",
|
||||
"number_of_dns_query_blocked_24_hours_adult": "Antalet vuxensajter som blockerats",
|
||||
"enforced_save_search": "Genomdrev SafeSearch",
|
||||
"number_of_dns_query_to_safe_search": "Antalet DNS-förfrågningar till sökmotorer för vilka SafeSearch genomdrevs",
|
||||
"enforced_save_search": "Aktivering av Säker surf",
|
||||
"number_of_dns_query_to_safe_search": "Antalet DNS-förfrågningar mot sökmotorer där Säker surf tvingats",
|
||||
"average_processing_time": "Genomsnittlig processtid",
|
||||
"average_upstream_response_time": "Genomsnittlig svarstid uppströmsserver",
|
||||
"response_time": "Svarstid",
|
||||
@@ -153,7 +153,7 @@
|
||||
"use_adguard_browsing_sec_hint": "AdGuard Home kommer att kontrollera om en domän är blockerad av webbservicen surfsäkerhet. Med en integritetsvänlig metod görs en API-lookup för att kontrollera: endast ett kort prefix i domännamnet SHA256 hash skickas till servern.",
|
||||
"use_adguard_parental": "Använda AdGuards webbservice för föräldrakontroll",
|
||||
"use_adguard_parental_hint": "AdGuard Home kommer att kontrollera domäner för innehåll av vuxenmaterial . Samma integritetsvänliga metod för API-lookup som tillämpas i webbservicens surfsäkerhet används.",
|
||||
"enforce_safe_search": "Använd SafeSearch",
|
||||
"enforce_safe_search": "Använd säker webbsökning",
|
||||
"enforce_save_search_hint": "AdGuard Home kommer tvinga säker surf på följande sökmotorer: Google, Youtube, Bing, DuckDuckGo, Yandex, Pixabay.",
|
||||
"no_servers_specified": "Inga servrar angivna",
|
||||
"general_settings": "Allmänna inställningar",
|
||||
@@ -461,7 +461,7 @@
|
||||
"form_enter_mac": "Skriv in MAC",
|
||||
"form_enter_id": "Ange identifierare",
|
||||
"form_add_id": "Lägg till identifierare",
|
||||
"form_client_name": "Ange klientnamn",
|
||||
"form_client_name": "Skriv in klientnamn",
|
||||
"name": "Namn",
|
||||
"client_name": "Klient {{id}}",
|
||||
"client_global_settings": "Använda globala inställningar",
|
||||
@@ -657,7 +657,7 @@
|
||||
"cache_optimistic": "Optimistisk cachning",
|
||||
"cache_optimistic_desc": "Få AdGuard Home att svara från cachen även när posterna har gått ut och försök även uppdatera dem.",
|
||||
"filter_category_general": "Allmänt",
|
||||
"filter_category_security": "Säkerhet",
|
||||
"filter_category_security": "säkerhet",
|
||||
"filter_category_regional": "Regional",
|
||||
"filter_category_other": "Övrigt",
|
||||
"filter_category_general_desc": "Listor som blockerar spårning och reklam på de flesta enheterna",
|
||||
@@ -674,6 +674,7 @@
|
||||
"use_saved_key": "Använd den tidigare sparade nyckeln",
|
||||
"parental_control": "Föräldrakontroll",
|
||||
"safe_browsing": "Säker surfning",
|
||||
"served_from_cache": "{{value}} <i>(levereras från cache)</i>",
|
||||
"form_error_password_length": "Lösenordet måste vara {{min}} till {{max}} tecken långt",
|
||||
"anonymizer_notification": "<0>Observera:</0> IP-anonymisering är aktiverad. Du kan inaktivera den i <1>Allmänna inställningar</1>.",
|
||||
"confirm_dns_cache_clear": "Är du säker på att du vill rensa DNS-cache?",
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
"settings": "การตั้งค่า",
|
||||
"filters": "ตัวกรอง",
|
||||
"query_log": "บันทึกการสืบค้น",
|
||||
"nothing_found": "ไม่พบอะไร",
|
||||
"faq": "คำถามที่พบบ่อย",
|
||||
"version": "รุ่น",
|
||||
"address": "ที่อยู่",
|
||||
@@ -350,7 +349,7 @@
|
||||
"statistics_configuration": "การกำหนดค่าสถิติ",
|
||||
"statistics_retention": "การเก็บรักษาสถิติ",
|
||||
"statistics_retention_desc": "หากคุณลดค่าช่วงเวลาข้อมูลบางอย่างจะหายไป",
|
||||
"statistics_clear": "ล้างสถิติ",
|
||||
"statistics_clear": " ล้างค่าสถิติ",
|
||||
"statistics_clear_confirm": "คุณแน่ใจหรือไม่ว่าต้องการล้างสถิติ?",
|
||||
"statistics_retention_confirm": "คุณแน่ใจหรือไม่ว่าต้องการเปลี่ยนการเก็บรักษาสถิติ? หากคุณลดค่าช่วงเวลา ข้อมูลบางอย่างจะหายไป",
|
||||
"statistics_cleared": "สถิติได้ถูกล้างเรียบร้อยแล้ว",
|
||||
@@ -391,13 +390,10 @@
|
||||
"check_title": "ตรวจสอบการกรอง",
|
||||
"check_desc": "ตรวจสอบว่าชื่อโฮสต์ถูกกรอง",
|
||||
"form_enter_host": "ป้อนชื่อโฮสต์",
|
||||
"show_blocked_responses": "ปิดกั้นแล้ว",
|
||||
"show_whitelisted_responses": "รายการที่อนุญาต",
|
||||
"show_processed_responses": "ประมวลผลแล้ว",
|
||||
"show_processed_responses": "การประมวลผล",
|
||||
"blocked_adult_websites": "ถูกปิดกั้นโดยการควบคุมของผู้ปกครอง",
|
||||
"safe_search": "ค้นหาอย่างปลอดภัย",
|
||||
"blocklist": "บัญชีดำ",
|
||||
"allowed": "รายการที่อนุญาต",
|
||||
"filter_category_other": "อื่น ๆ",
|
||||
"parental_control": "ควบคุมโดยผู้ปกครอง",
|
||||
"sunday_short": "อาทิตย์",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Tüm üst sunucuları eş zamanlı sorgulayarak çözümlemeyi hızlandırmak için paralel sorgular kullanın.",
|
||||
"parallel_requests": "Paralel istekler",
|
||||
"load_balancing": "Yük dengeleme",
|
||||
"load_balancing_desc": "Aynı anda bir üst kaynak sunucusunu sorgulayın. AdGuard Home, en düşük başarısız arama sayısına ve en düşük ortalama arama süresine sahip sunucuları seçmek için ağırlıklı rastgele bir algoritma kullanır.",
|
||||
"load_balancing_desc": "Her seferde bir üst sunucuyu sorgulayın. AdGuard Home, sunucuyu seçmek için ağırlıklı rastgele algoritmasını kullanır, böylece en hızlı sunucu daha sık kullanılır.",
|
||||
"bootstrap_dns": "DNS Önyükleme sunucuları",
|
||||
"bootstrap_dns_desc": "Üst kaynak olarak belirttiğiniz DoH/DoT çözümleyicilerin IP adreslerini çözümlemek için kullanılan DNS sunucularının IP adresleri. Yorumlara izin verilmez.",
|
||||
"fallback_dns_title": "Yedek DNS sunucuları",
|
||||
"fallback_dns_desc": "Yukarı akış DNS sunucuları yanıt vermediğinde kullanılan yedek DNS sunucularının listesi. Söz dizimi yukarıdaki ana üst kaynak alanıyla aynıdır.",
|
||||
"fallback_dns_placeholder": "Her satıra bir yedek DNS sunucusu girin",
|
||||
"local_ptr_title": "Özel ters DNS sunucuları",
|
||||
"local_ptr_desc": "AdGuard Home tarafından özel PTR, SOA ve NS istekleri için kullanılan DNS sunucuları. Bir istek, özel IP aralıkları (\"192.168.12.34\" gibi) içinde bir alt ağ içeren bir ARPA alan adı ister ve özel IP adresine sahip bir istemciden gelirse özel olarak kabul edilir. Ayarlanmadığı durumda AdGuard Home, IP adresleri dışında işletim sisteminizin varsayılan DNS çözümleyicileri kullanılır.",
|
||||
"local_ptr_desc": "AdGuard Home'un yerel PTR sorguları için kullandığı DNS sunucuları. Bu sunucular, rDNS kullanarak, örneğin \"192.168.12.34\" gibi özel IP aralıklarındaki adresler için PTR isteklerini çözmek için kullanılır. Ayarlanmadığı durumda AdGuard Home, işletim sisteminizin varsayılan DNS çözümleme adreslerini kullanır.",
|
||||
"local_ptr_default_resolver": "AdGuard Home, varsayılan olarak aşağıdaki ters DNS çözümleyicilerini kullanır: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home, bu sistem için uygun olan özel ters DNS çözümleyicilerini belirleyemedi.",
|
||||
"local_ptr_placeholder": "Her satıra bir IP adresi girin",
|
||||
"resolve_clients_title": "İstemcilerin IP adreslerinin ters çözümlenmesini etkinleştir",
|
||||
"resolve_clients_desc": "Karşılık gelen çözümleyicilere (yerel istemciler için özel DNS sunucuları, genel IP adresleri olan istemciler için üst sunucuları) PTR sorguları göndererek istemcilerin IP adreslerini ana makine adlarının tersine çözün.",
|
||||
"use_private_ptr_resolvers_title": "Özel ters DNS çözümleyicileri kullan",
|
||||
"use_private_ptr_resolvers_desc": "Özel üst kaynak sunucuları, DHCP, /etc/hosts, vb. aracılığıyla özel IP adresleri içeren ARPA alan adları için PTR, SOA ve NS isteklerini çözümleyin. Devre dışı bırakılırsa, AdGuard Home bu tür tüm isteklere NXDOMAIN ile yanıt verir.",
|
||||
"use_private_ptr_resolvers_desc": "Bu üst kaynak sunucularını kullanarak yerel olarak sunulan adresler için ters DNS aramaları yapın. Devre dışı bırakılırsa, AdGuard Home, DHCP, /etc/hosts, vb. tarafından bilinen istemciler dışında bu tür tüm PTR isteklerine NXDOMAIN ile yanıt verir.",
|
||||
"check_dhcp_servers": "DHCP sunucularını denetle",
|
||||
"save_config": "Yapılandırmayı kaydet",
|
||||
"enabled_dhcp": "DHCP sunucusu etkinleştirildi",
|
||||
@@ -68,7 +68,7 @@
|
||||
"ip": "IP",
|
||||
"dhcp_table_hostname": "Ana makine Adı",
|
||||
"dhcp_table_expires": "Bitiş tarihi",
|
||||
"dhcp_warning": "DHCP sunucusunu yine de etkinleştirmek istiyorsanız, ağınızda başka aktif DHCP sunucusu olmadığından emin olun, aksi takdirde ağa bağlı cihazların internet bağlantısı kesilebilir!",
|
||||
"dhcp_warning": "DHCP sunucusunu yine de etkinleştirmek istiyorsanız, ağınızda başka aktif DHCP sunucusu olmadığından emin olun, aksi takdirde ağa bağlı cihazların İnternet bağlantısı kesilebilir!",
|
||||
"dhcp_error": "AdGuard Home, ağda başka bir etkin DHCP sunucusu olup olmadığını belirleyemedi",
|
||||
"dhcp_static_ip_error": "DHCP sunucusunu kullanmak için sabit bir IP adresi ayarlanmalıdır. AdGuard Home, bu ağ arayüzünün sabit bir IP adresi kullanılarak yapılandırılıp yapılandırılmadığını belirleyemedi. Lütfen sabit IP adresini elle ayarlayın.",
|
||||
"dhcp_dynamic_ip_found": "Sisteminiz, <0>{{interfaceName}}</0> arayüzü için dinamik IP adresi yapılandırması kullanıyor. DHCP sunucusunu kullanmak için sabit bir IP adresi ayarlanmalıdır. Geçerli olan IP adresiniz <0>{{ipAddress}}</0>. \"DHCP sunucusunu etkinleştir\" düğmesine basarsanız, AdGuard Home bu IP adresini otomatik bir şekilde sabit olarak ayarlayacaktır.",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "AdGuard ebeveyn denetimi web hizmetini kullan",
|
||||
"use_adguard_parental_hint": "AdGuard Home, alan adının yetişkin içerik bulundurup bulundurmadığını kontrol eder. Gezinti koruması web hizmeti ile kullandığımız aynı gizlilik dostu API'yi kullanır.",
|
||||
"enforce_safe_search": "Güvenli Aramayı kullan",
|
||||
"enforce_save_search_hint": "AdGuard Home, şu arama motorlarında güvenli aramayı uygular: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home, şu arama motorlarında güvenli aramayı uygular: Google, YouTube, Bing, DuckDuckGo, Yandex ve Pixabay.",
|
||||
"no_servers_specified": "Sunucu belirtilmedi",
|
||||
"general_settings": "Genel ayarlar",
|
||||
"dns_settings": "DNS ayarları",
|
||||
@@ -476,7 +476,7 @@
|
||||
"client_confirm_delete": "\"{{key}}\" istemcisini silmek istediğinizden emin misiniz?",
|
||||
"list_confirm_delete": "Bu listeyi silmek istediğinizden emin misiniz?",
|
||||
"auto_clients_title": "Çalışma zamanı istemcileri",
|
||||
"auto_clients_desc": "AdGuard Home'u kullanan veya kullanabilecek cihazların IP adresleri hakkında bilgiler. Bu bilgiler, hosts dosyaları, ters DNS, vb. dâhil olmak üzere çeşitli kaynaklardan toplanır.",
|
||||
"auto_clients_desc": "AdGuard Home'u kullanan veya kullanabilecek cihazların IP adresleri hakkında bilgiler. Bu bilgiler, hosts dosyaları, ters DNS, vb. dahil olmak üzere çeşitli kaynaklardan toplanır.",
|
||||
"access_title": "Erişim ayarları",
|
||||
"access_desc": "AdGuard Home DNS sunucusu için erişim kurallarını buradan yapılandırabilirsiniz",
|
||||
"access_allowed_title": "İzin verilen istemciler",
|
||||
@@ -603,7 +603,7 @@
|
||||
"autofix_warning_list": "Bu görevleri gerçekleştirir: <0>Sistem DNSStubListener'ı devre dışı bırakın</0> <0>DNS sunucusu adresini 127.0.0.1 olarak ayarlayın</0> <0>/etc/resolv.conf'un sembolik bağlantı hedefini /run/systemd/resolve/resolv.conf ile değiştirin<0> <0>DNSStubListener'ı durdurun (systemd çözümlenmiş hizmeti yeniden yükleyin)</0>",
|
||||
"autofix_warning_result": "Sonuç olarak, sisteminizden gelen tüm DNS istekleri varsayılan olarak AdGuard Home tarafından işlenecektir.",
|
||||
"tags_title": "Etiketler",
|
||||
"tags_desc": "İstemciye karşılık gelen etiketleri seçebilirsiniz. Etiketleri daha kesin olarak uygulamak için filtreleme kurallarına dâhil edin. <0>Daha fazla bilgi edinin</0>.",
|
||||
"tags_desc": "İstemciye karşılık gelen etiketleri seçebilirsiniz. Etiketleri daha kesin olarak uygulamak için filtreleme kurallarına dahil edin. <0>Daha fazla bilgi edinin</0>.",
|
||||
"form_select_tags": "İstemci etiketlerini seçin",
|
||||
"check_title": "Filtrelemeyi denetleyin",
|
||||
"check_desc": "Ana makine adının filtreleme durumunu kontrol edin.",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"resolve_clients_title": "Увімкнути зворотне вирішення IP-адрес клієнтів",
|
||||
"resolve_clients_desc": "Визначати доменні імена клієнтів за допомогою PTR-запитів до відповідних серверів — приватних DNS-серверів для локальних клієнтів та upstream-серверів для клієнтів з публічними IP-адресами.",
|
||||
"use_private_ptr_resolvers_title": "Використовувати приватні зворотні DNS-резолвери",
|
||||
"use_private_ptr_resolvers_desc": "Розвʼязувати запити PTR, SOA та NS для доменів ARPA, що містять приватні IP-адреси, через приватні вихідні сервери, DHCP, /etc/hosts тощо. Якщо вимкнено, AdGuard Home відповідатиме на всі такі запити з NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Надсилати зворотні DNS-запити до вказаних серверів для клієнтів, що обслуговуються локально. Якщо вимкнено, AdGuard Home буде відповідати NXDOMAIN на всі такі PTR-запити, окрім запитів про клієнтів, що уже відомі завдяки DHCP, /etc/hosts тощо.",
|
||||
"check_dhcp_servers": "Перевірити DHCP-сервери",
|
||||
"save_config": "Зберегти конфігурацію",
|
||||
"enabled_dhcp": "DHCP-сервер увімкнено",
|
||||
@@ -68,7 +68,7 @@
|
||||
"ip": "IP",
|
||||
"dhcp_table_hostname": "Назва вузла",
|
||||
"dhcp_table_expires": "Закінчується",
|
||||
"dhcp_warning": "Якщо ви однаково хочете увімкнути DHCP-сервер, переконайтеся, що у вашій мережі немає інших активних DHCP-серверів. Інакше, це може порушити роботу інтернету на підʼєднаних пристроях!",
|
||||
"dhcp_warning": "Якщо ви однаково хочете увімкнути DHCP-сервер, переконайтеся, що у вашій мережі немає інших активних DHCP-серверів. Інакше, це може порушити роботу інтернету на під'єднаних пристроях!",
|
||||
"dhcp_error": "AdGuard Home не зміг визначити, чи є в мережі інший DHCP-сервер",
|
||||
"dhcp_static_ip_error": "Для використання DHCP-сервера необхідно встановити статичну IP-адресу. Нам не вдалося визначити, чи цей мережевий інтерфейс налаштовано для використання статичної IP-адреси. Встановіть статичну IP-адресу вручну.",
|
||||
"dhcp_dynamic_ip_found": "Ваша система використовує конфігурацію з динамічною IP-адресою для інтерфейсу <0>{{interfaceName}}</0>. Для використання DHCP-сервера необхідно встановити статичну IP-адресу. Ваша поточна IP-адреса <0>{{ipAddress}}</0>. Ми автоматично встановимо цю IP-адресу як статичну, якщо ви натиснете кнопку «Увімкнути DHCP-сервер».",
|
||||
@@ -343,10 +343,10 @@
|
||||
"known_tracker": "Відомі трекери",
|
||||
"install_welcome_title": "Вітаємо в AdGuard Home!",
|
||||
"install_welcome_desc": "AdGuard Home — це мережевий DNS-сервер, що блокує рекламу та відстеження. Його мета — надати вам контроль над усією мережею та всіма пристроями в ній без потреби використання програми на стороні клієнта.",
|
||||
"install_settings_title": "Вебінтерфейс адміністратора",
|
||||
"install_settings_title": "Веб-інтерфейс адміністратора",
|
||||
"install_settings_listen": "Мережевий інтерфейс",
|
||||
"install_settings_port": "Порт",
|
||||
"install_settings_interface_link": "Вебінтерфейс адміністратора AdGuard Home буде доступний за такими адресами:",
|
||||
"install_settings_interface_link": "Веб-інтерфейс адміністратора AdGuard Home буде доступний за такими адресами:",
|
||||
"form_error_port": "Уведіть правильне значення порту",
|
||||
"install_settings_dns": "DNS-сервер",
|
||||
"install_settings_dns_desc": "Вам потрібно буде налаштувати свої пристрої або маршрутизатор для використання DNS-сервера за такими адресами:",
|
||||
@@ -364,7 +364,7 @@
|
||||
"install_submit_title": "Вітаємо!",
|
||||
"install_submit_desc": "Процедура налаштування завершена і тепер все готово, аби почати користуватися AdGuard Home.",
|
||||
"install_devices_router": "Роутер",
|
||||
"install_devices_router_desc": "Це налаштування буде автоматично охоплювати всі пристрої, що підʼєднано до домашнього маршрутизатора. Вам не потрібно буде налаштовувати кожен з них вручну.",
|
||||
"install_devices_router_desc": "Це налаштування буде автоматично охоплювати всі пристрої, що під'єднано до домашнього маршрутизатора. Вам не потрібно буде налаштовувати кожен з них вручну.",
|
||||
"install_devices_address": "DNS-сервер AdGuard Home прослуховує наступні адреси",
|
||||
"install_devices_router_list_1": "Відкрийте налаштування маршрутизатора. Зазвичай ви можете отримати до нього доступ із браузера за допомогою URL-адреси, наприклад, http://192.168.0.1/ або http://192.168.1.1/. Можливо, треба буде ввести пароль. Якщо ви його не знаєте, часто можна скинути пароль, натиснувши кнопку на самому маршрутизаторі. Для деяких маршрутизаторів потрібна спеціальна програма, яка в такому випадку повинна бути вже встановлена на вашому комп’ютері чи телефоні.",
|
||||
"install_devices_router_list_2": "Знайдіть налаштування DHCP/DNS. Шукайте літери DNS поруч із полем, в яке можна ввести два або три набори чисел, кожен з яких розбитий на чотири групи від однієї до трьох цифр.",
|
||||
@@ -448,7 +448,7 @@
|
||||
"manual_update": "Щоб оновити самостійно, <a>виконайте ці кроки</a>.",
|
||||
"processing_update": "Зачекайте будь ласка, AdGuard Home оновлюється",
|
||||
"clients_title": "Постійні клієнти",
|
||||
"clients_desc": "Налаштуйте пристрої, які підʼєднано до AdGuard Home",
|
||||
"clients_desc": "Налаштуйте пристрої, під'єднані до AdGuard Home",
|
||||
"settings_global": "Загальні",
|
||||
"settings_custom": "Власні",
|
||||
"table_client": "Клієнт",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "Sử dụng truy vấn song song để tăng tốc độ giải quyết bằng cách truy vấn đồng thời tất cả các máy chủ ngược tuyến",
|
||||
"parallel_requests": "Yêu cầu song song",
|
||||
"load_balancing": "Cân bằng tải",
|
||||
"load_balancing_desc": "Truy vấn một máy chủ thượng nguồn tại một thời điểm. AdGuard Home sử dụng thuật toán ngẫu nhiên có trọng số để chọn máy chủ có số lần tìm kiếm không thành công thấp nhất và thời gian tìm kiếm trung bình thấp nhất.",
|
||||
"load_balancing_desc": "Chỉ truy xuất một máy chủ trong cùng thời điểm. AdGuard Home sẽ sử dụng thuật toán trọng số ngẫu nhiên để chọn một máy chủ nhanh nhất và sử dụng máy chủ đó thường xuyên hơn.",
|
||||
"bootstrap_dns": "Máy chủ DNS Bootstrap",
|
||||
"bootstrap_dns_desc": "Địa chỉ IP của máy chủ DNS được sử dụng để phân giải địa chỉ IP của trình phân giải DoH/DoT mà bạn chỉ định làm thượng nguồn. Bình luận không được phép.",
|
||||
"fallback_dns_title": "Máy chủ DNS dự phòng",
|
||||
"fallback_dns_desc": "Danh sách máy chủ DNS dự phòng được sử dụng khi máy chủ DNS ngược tuyến không phản hồi. Cú pháp tương tự như trong trường ngược dòng chính ở trên.",
|
||||
"fallback_dns_placeholder": "Nhập một máy chủ DNS dự phòng trên mỗi dòng",
|
||||
"local_ptr_title": "Máy chủ DNS riêng tư",
|
||||
"local_ptr_desc": "Máy chủ DNS được AdGuard Home sử dụng cho các yêu cầu PTR, SOA và NS riêng tư. Một yêu cầu được coi là riêng tư nếu nó yêu cầu một miền ARPA chứa một mạng con trong phạm vi IP riêng tư (chẳng hạn như \"192.168.12.34\") và đến từ một máy khách có địa chỉ IP riêng tư. Nếu không được thiết lập, các trình phân giải DNS mặc định của hệ điều hành của bạn sẽ được sử dụng, ngoại trừ các địa chỉ IP của AdGuard Home.",
|
||||
"local_ptr_desc": "Máy chủ DNS hoặc các máy chủ mà AdGuard Home sẽ sử dụng cho các truy vấn về tài nguyên được phân phối cục bộ. Ví dụ: máy chủ này sẽ được sử dụng để phân giải tên máy khách của máy khách cho các máy khách có địa chỉ IP riêng. Nếu không được cài đặt, AdGuard Home sẽ tự động sử dụng trình phân giải DNS mặc định của bạn.",
|
||||
"local_ptr_default_resolver": "Theo mặc định, AdGuard Home sử dụng các hệ thống phân giải tên miền ngược sau: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home không thể xác định hệ thống phân giải tên miền ngược riêng phù hợp cho hệ thống này.",
|
||||
"local_ptr_placeholder": "Nhập một địa chỉ IP trên mỗi dòng",
|
||||
"resolve_clients_title": "Kích hoạt cho phép phân giải ngược về địa chỉ IP của máy khách",
|
||||
"resolve_clients_desc": "Nếu được bật, AdGuard Home sẽ cố gắng phân giải ngược lại địa chỉ IP của khách hàng thành tên máy chủ của họ bằng cách gửi các truy vấn PTR tới trình phân giải tương ứng (máy chủ DNS riêng cho máy khách cục bộ, máy chủ ngược dòng cho máy khách có địa chỉ IP công cộng).",
|
||||
"use_private_ptr_resolvers_title": "Sử dụng trình rDNS riêng tư",
|
||||
"use_private_ptr_resolvers_desc": "Giải quyết các yêu cầu PTR, SOA và NS cho các miền ARPA chứa địa chỉ IP riêng thông qua máy chủ thượng nguồn riêng, DHCP, /etc/hosts, v. v. Nếu bị vô hiệu hóa, AdGuard Home sẽ phản hồi tất cả các yêu cầu đó bằng NXDOMAIN.",
|
||||
"use_private_ptr_resolvers_desc": "Thực hiện tra cứu ngược DNS cho các địa chỉ được phân phối cục bộ bằng cách sử dụng các máy chủ nguồn. Nếu bị vô hiệu hóa, AdGuard Home sẽ phản hồi với NXDOMAIN cho tất cả các yêu cầu PTR ngoại trừ các ứng dụng khách được biết đến bởi DHCP, / etc / hosts, v. v.",
|
||||
"check_dhcp_servers": "Kiểm tra máy chủ DHCP",
|
||||
"save_config": "Lưu thiết lập",
|
||||
"enabled_dhcp": "Máy chủ DHCP đã kích hoạt",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "Sử dụng dịch vụ quản lý của phụ huynh AdGuard",
|
||||
"use_adguard_parental_hint": "AdGuard Home sẽ kiểm tra nếu tên miền chứa từ khoá người lớn. Tính năng sử dụng API thân thiện với quyền riêng tư tương tự với dịch vụ bảo vệ duyệt web",
|
||||
"enforce_safe_search": "Bắt buộc tìm kiếm an toàn",
|
||||
"enforce_save_search_hint": "AdGuard Home sẽ thực thi tìm kiếm an toàn trong các công cụ tìm kiếm sau: Google, YouTube, Bing, DuckDuckGo, Ecosia, Yandex, Pixabay.",
|
||||
"enforce_save_search_hint": "AdGuard Home có thể bắt buộc tìm kiếm an toàn với các dịch vụ tìm kiếm: Google, Youtube, Bing, Yandex.",
|
||||
"no_servers_specified": "Không có máy chủ nào được liệt kê",
|
||||
"general_settings": "Cài đặt chung",
|
||||
"dns_settings": "Cài đặt DNS",
|
||||
@@ -425,9 +425,6 @@
|
||||
"encryption_hostnames": "Tên máy chủ",
|
||||
"encryption_reset": "Bạn có chắc chắn muốn đặt lại cài đặt mã hóa?",
|
||||
"encryption_warning": "Cảnh báo",
|
||||
"encryption_plain_dns_enable": "Kích hoạt DNS đơn giản",
|
||||
"encryption_plain_dns_desc": "DNS đơn giản được bật theo mặc định. Bạn có thể vô hiệu hóa nó để buộc tất cả các thiết bị sử dụng DNS được mã hóa. Để thực hiện việc này, bạn phải kích hoạt ít nhất một giao thức DNS được mã hóa",
|
||||
"encryption_plain_dns_error": "Để tắt DNS đơn giản, hãy bật ít nhất một giao thức DNS được mã hóa",
|
||||
"topline_expiring_certificate": "Chứng chỉ SSL của bạn sắp hết hạn. Cập nhật <0>Cài đặt mã hóa</0>.",
|
||||
"topline_expired_certificate": "Chứng chỉ SSL của bạn đã hết hạn. Cập nhật <0>Cài đặt mã hóa</0>.",
|
||||
"form_error_port_range": "Nhập giá trị cổng trong phạm vi 80-65535",
|
||||
@@ -678,7 +675,7 @@
|
||||
"use_saved_key": "Sử dụng khóa đã lưu trước đó",
|
||||
"parental_control": "Quản lý của phụ huynh",
|
||||
"safe_browsing": "Duyệt web an toàn",
|
||||
"served_from_cache_label": "Được phục vụ từ bộ nhớ đệm",
|
||||
"served_from_cache": "{{value}} <i>(được phục vụ từ bộ nhớ cache)</i>",
|
||||
"form_error_password_length": "Mật khẩu phải dài từ {{min}} đến {{max}} ký tự",
|
||||
"anonymizer_notification": "<0> Lưu ý:</0> Tính năng ẩn danh IP được bật. Bạn có thể tắt nó trong <1> Cài đặt chung</1>.",
|
||||
"confirm_dns_cache_clear": "Bạn có chắc chắn muốn xóa bộ đệm ẩn DNS không?",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "使用并行请求以同时查询所有上游服务器来加快解析速度。",
|
||||
"parallel_requests": "并行请求",
|
||||
"load_balancing": "负载均衡",
|
||||
"load_balancing_desc": "一次查询一台服务器。AdGuard Home 使用加权随机算法来选择具有最少失败查找和最低平均查找时间的服务器。",
|
||||
"load_balancing_desc": "一次查询一台服务器。AdGuard Home 将使用加权随机算法来选择服务器,以便更常使用最快的服务器。",
|
||||
"bootstrap_dns": "Bootstrap DNS 服务器",
|
||||
"bootstrap_dns_desc": "DNS 服务器的 IP 地址,用于解析指定为上游的 DoH/DoT 解析器的 IP 地址。不允许添加注释。",
|
||||
"fallback_dns_title": "后备 DNS 服务器",
|
||||
"fallback_dns_desc": "当上游 DNS 服务器没有响应时使用的后备 DNS 服务器列表。语法与上面的「主要上游」字段相同。",
|
||||
"fallback_dns_placeholder": "每行输入一个后备 DNS 服务器",
|
||||
"local_ptr_title": "私人反向 DNS 服务器",
|
||||
"local_ptr_desc": "AdGuard Home 用于私人 PTR、SOA 和 NS 请求的 DNS 服务器。如果请求的 ARPA 域名包含私有 IP 范围内的子网(如 \"192.168.12.34\"),且请求来自具有私有 IP 地址的客户端,该请求被视为私有请求。如果未设置,将使用操作系统的默认 DNS 解析器,AdGuard Home IP 地址除外。",
|
||||
"local_ptr_desc": "AdGuard Home 用于本地 PTR 查询的 DNS 服务器。这些服务器将使用反向 DNS 解析具有私人 IP 地址的客户机的主机名,比如 \"192.168.12.34\"。如果没有设置,除非是 AdGuard Home 里设置的地址,AdGuard Home 都将自动使用您的操作系统的默认 DNS 解析器。",
|
||||
"local_ptr_default_resolver": "AdGuard Home 默认使用下列反向 DNS 解析器: {{ip}}",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home 无法为这个系统确定合适的私人反向 DNS 解析器。",
|
||||
"local_ptr_placeholder": "每行输入一个 IP 地址",
|
||||
"resolve_clients_title": "启用客户端的 IP 地址的反向解析",
|
||||
"resolve_clients_desc": "通过发送 PTR 查询到对应的解析器 (本地客户端的私人 DNS 服务器,公共 IP 客户端的上游服务器) 将 IP 地址反向解析成其客户端主机名。",
|
||||
"use_private_ptr_resolvers_title": "使用私人反向 DNS 解析器",
|
||||
"use_private_ptr_resolvers_desc": "使用私有上游服务器、DHCP、/etc/hosts 等解决包含私有 IP 地址的 ARPA 域名的 PTR、SOA 和 NS 请求。如果禁用,AdGuard Home 将以 NXDOMAIN 回应所有此类请求。",
|
||||
"use_private_ptr_resolvers_desc": "使用这些上游服务器对本地服务的地址执行反向 DNS 查找。 如果禁用,则 AdGuard Home 会以 NXDOMAIN 响应所有此类 PTR 请求,从 DHCP、/etc/hosts 等获知的客户端除外。",
|
||||
"check_dhcp_servers": "检查 DHCP 服务器",
|
||||
"save_config": "保存配置",
|
||||
"enabled_dhcp": "DHCP 服务器已启用",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "使用 AdGuard 【家长控制】服务",
|
||||
"use_adguard_parental_hint": "AdGuard Home 将使用与浏览安全服务相同的隐私性强的 API 来检查域名指向的网站是否包含成人内容。",
|
||||
"enforce_safe_search": "使用安全搜索",
|
||||
"enforce_save_search_hint": "AdGuard Home 将会在下列搜索引擎中强制启用安全搜索:Google、YouTube、Bing、DuckDuckGo、Ecosia、Yandex、Pixabay。",
|
||||
"enforce_save_search_hint": "AdGuard Home 对以下搜索引擎可强制启用安全搜索:Google、YouTube、Bing、DuckDuckGo、Yandex、Pixabay。",
|
||||
"no_servers_specified": "未找到指定的服务器",
|
||||
"general_settings": "常规设置",
|
||||
"dns_settings": "DNS 设置",
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
"upstream_parallel": "透過同時地查詢所有上游的伺服器,使用並行的查詢以加速解析。",
|
||||
"parallel_requests": "並行的請求",
|
||||
"load_balancing": "負載平衡",
|
||||
"load_balancing_desc": "一次查詢一台伺服器。AdGuard Home 使用加權隨機演算法來選擇具有最少失敗查詢和最低平均查詢時間的伺服器。",
|
||||
"load_balancing_desc": "每次查詢一個上游伺服器。AdGuard Home 使用它的加權隨機的演算法來選擇伺服器,以便最快的伺服器被更常使用。",
|
||||
"bootstrap_dns": "自我啟動(Bootstrap)DNS 伺服器",
|
||||
"bootstrap_dns_desc": "DNS 伺服器的 IP 位址,用於解析您指定為上游伺服器的 DoH/DoT 解析器的 IP 位址。不允許註釋。",
|
||||
"fallback_dns_title": "應變 DNS 伺服器",
|
||||
"fallback_dns_desc": "當上游 DNS 伺服器未回覆時被使用的應變 DNS 伺服器之清單。此語法與在上面主要上游欄位中的相同。",
|
||||
"fallback_dns_placeholder": "每行輸入一個應變 DNS 伺服器",
|
||||
"local_ptr_title": "私人反向的 DNS 伺服器",
|
||||
"local_ptr_desc": "AdGuard Home 使用的 DNS 伺服器用於私人 PTR、SOA 和 NS 請求。如果請求要求包含私人 IP 範圍內的子網域的 ARPA 網域(例如 \"192.168.12.34\"),並來自具有私人 IP 位址的用戶端,該請求被視為私人。如果未設定,將使用您的作業系統的預設 DNS 解析器,但不包括 AdGuard Home 的 IP 位址。",
|
||||
"local_ptr_desc": "AdGuard Home 用於區域指標(PTR)查詢之 DNS 伺服器。這些伺服器被用於解析有關在私人 IP 範圍的位址之區域指標查詢,例如,\"192.168.12.34\",使用反向的 DNS。如果未被設定,AdGuard Home 使用您的作業系統之預設 DNS 解析器的位址。",
|
||||
"local_ptr_default_resolver": "預設下,AdGuard Home 使用以下反向的 DNS 解析器:{{ip}}。",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home 無法為此系統決定合適的私人反向的 DNS 解析器。",
|
||||
"local_ptr_placeholder": "每行輸入一個 IP 位址",
|
||||
"resolve_clients_title": "啟用用戶端的 IP 位址之反向的解析",
|
||||
"resolve_clients_desc": "透過傳送指標(PTR)查詢到對應的解析器(私人 DNS 伺服器供區域的用戶端,上游的伺服器供有公共 IP 位址的用戶端),反向地解析用戶端的 IP 位址變為它們的主機名稱。",
|
||||
"use_private_ptr_resolvers_title": "使用私人反向的 DNS 解析器",
|
||||
"use_private_ptr_resolvers_desc": "通過私人上游伺服器、DHCP、/etc/hosts 等等,對包含私人 IP 位址的 ARPA 網域解析 PTR、SOA 和 NS 請求。如果被禁用,AdGuard Home 將對所有此類的請求以 NXDOMAIN 回覆。",
|
||||
"use_private_ptr_resolvers_desc": "對於正使用這些上游伺服器之區域服務的位址執行反向的 DNS 查找。如果被禁用,除已知來自 DHCP、/etc/hosts 等等的用戶端之外,AdGuard Home 對於所有此類的區域指標(PTR)請求以 NXDOMAIN 回覆。",
|
||||
"check_dhcp_servers": "檢查動態主機設定協定(DHCP)伺服器",
|
||||
"save_config": "儲存配置",
|
||||
"enabled_dhcp": "動態主機設定協定(DHCP)伺服器被啟用",
|
||||
@@ -154,7 +154,7 @@
|
||||
"use_adguard_parental": "使用 AdGuard 家長控制之網路服務",
|
||||
"use_adguard_parental_hint": "AdGuard Home 將檢查網域是否包含成人資料。它使用如同瀏覽安全網路服務一樣之對隱私友好的應用程式介面(API)。",
|
||||
"enforce_safe_search": "使用安全搜尋",
|
||||
"enforce_save_search_hint": "AdGuard Home 將在下列的搜尋引擎:Google、YouTube、Bing、DuckDuckGo、Ecosia、Yandex 和 Pixabay 中強制執行安全搜尋。",
|
||||
"enforce_save_search_hint": "AdGuard Home 將在下列的搜尋引擎:Google、YouTube、Bing、DuckDuckGo、Yandex 和 Pixabay 中強制執行安全搜尋。",
|
||||
"no_servers_specified": "無已明確指定的伺服器",
|
||||
"general_settings": "一般設定",
|
||||
"dns_settings": "DNS 設定",
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
import { sortIp, countClientsStatistics, findAddressType, subnetMaskToBitMask } from '../helpers/helpers';
|
||||
import {
|
||||
sortIp,
|
||||
countClientsStatistics,
|
||||
findAddressType,
|
||||
subnetMaskToBitMask,
|
||||
} from '../helpers/helpers';
|
||||
import { ADDRESS_TYPES } from '../helpers/constants';
|
||||
|
||||
describe('sortIp', () => {
|
||||
describe('ipv4', () => {
|
||||
test('one octet differ', () => {
|
||||
const arr = ['127.0.2.0', '127.0.3.0', '127.0.1.0'];
|
||||
const sortedArr = ['127.0.1.0', '127.0.2.0', '127.0.3.0'];
|
||||
|
||||
const arr = [
|
||||
'127.0.2.0',
|
||||
'127.0.3.0',
|
||||
'127.0.1.0',
|
||||
];
|
||||
const sortedArr = [
|
||||
'127.0.1.0',
|
||||
'127.0.2.0',
|
||||
'127.0.3.0',
|
||||
];
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
|
||||
test('few octets differ', () => {
|
||||
const arr = [
|
||||
'192.168.11.10',
|
||||
@@ -47,7 +58,6 @@ describe('sortIp', () => {
|
||||
'192.168.11.10',
|
||||
'192.168.11.11',
|
||||
];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
|
||||
// Example from issue https://github.com/AdguardTeam/AdGuardHome/issues/1778#issuecomment-640937599
|
||||
@@ -73,26 +83,36 @@ describe('sortIp', () => {
|
||||
'192.168.2.200',
|
||||
'192.168.3.1',
|
||||
];
|
||||
|
||||
expect(arr2.sort(sortIp)).toStrictEqual(sortedArr2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ipv6', () => {
|
||||
test('only long form', () => {
|
||||
const arr = ['2001:db8:11a3:9d7:0:0:0:2', '2001:db8:11a3:9d7:0:0:0:3', '2001:db8:11a3:9d7:0:0:0:1'];
|
||||
const sortedArr = ['2001:db8:11a3:9d7:0:0:0:1', '2001:db8:11a3:9d7:0:0:0:2', '2001:db8:11a3:9d7:0:0:0:3'];
|
||||
|
||||
const arr = [
|
||||
'2001:db8:11a3:9d7:0:0:0:2',
|
||||
'2001:db8:11a3:9d7:0:0:0:3',
|
||||
'2001:db8:11a3:9d7:0:0:0:1',
|
||||
];
|
||||
const sortedArr = [
|
||||
'2001:db8:11a3:9d7:0:0:0:1',
|
||||
'2001:db8:11a3:9d7:0:0:0:2',
|
||||
'2001:db8:11a3:9d7:0:0:0:3',
|
||||
];
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
|
||||
test('only short form', () => {
|
||||
const arr = ['2001:db8::', '2001:db7::', '2001:db9::'];
|
||||
const sortedArr = ['2001:db7::', '2001:db8::', '2001:db9::'];
|
||||
|
||||
const arr = [
|
||||
'2001:db8::',
|
||||
'2001:db7::',
|
||||
'2001:db9::',
|
||||
];
|
||||
const sortedArr = [
|
||||
'2001:db7::',
|
||||
'2001:db8::',
|
||||
'2001:db9::',
|
||||
];
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
|
||||
test('long and short forms', () => {
|
||||
const arr = [
|
||||
'2001:db8::',
|
||||
@@ -110,11 +130,9 @@ describe('sortIp', () => {
|
||||
'2001:db7:11a3:9d7:0:0:0:2',
|
||||
'2001:db8::',
|
||||
];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ipv4 and ipv6', () => {
|
||||
test('ipv6 long form', () => {
|
||||
const arr = [
|
||||
@@ -133,10 +151,8 @@ describe('sortIp', () => {
|
||||
'2001:db8:11a3:9d7:0:0:0:2',
|
||||
'2001:db8:11a3:9d7:0:0:0:3',
|
||||
];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
|
||||
test('ipv6 short form', () => {
|
||||
const arr = [
|
||||
'2001:db8:11a3:9d7::1',
|
||||
@@ -154,10 +170,8 @@ describe('sortIp', () => {
|
||||
'2001:db8:11a3:9d7::2',
|
||||
'2001:db8:11a3:9d7::3',
|
||||
];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
|
||||
test('ipv6 long and short forms', () => {
|
||||
const arr = [
|
||||
'2001:db8:11a3:9d7::1',
|
||||
@@ -175,10 +189,8 @@ describe('sortIp', () => {
|
||||
'2001:db8:11a3:9d7:0:0:0:2',
|
||||
'2001:db8:11a3:9d7::3',
|
||||
];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
|
||||
test('always put ipv4 before ipv6', () => {
|
||||
const arr = [
|
||||
'::1',
|
||||
@@ -198,26 +210,40 @@ describe('sortIp', () => {
|
||||
'2001:db8:11a3:9d7::1',
|
||||
'2001:db8:11a3:9d7:0:0:0:2',
|
||||
];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cidr', () => {
|
||||
test('only ipv4 cidr', () => {
|
||||
const arr = ['192.168.0.1/9', '192.168.0.1/7', '192.168.0.1/8'];
|
||||
const sortedArr = ['192.168.0.1/7', '192.168.0.1/8', '192.168.0.1/9'];
|
||||
|
||||
const arr = [
|
||||
'192.168.0.1/9',
|
||||
'192.168.0.1/7',
|
||||
'192.168.0.1/8',
|
||||
];
|
||||
const sortedArr = [
|
||||
'192.168.0.1/7',
|
||||
'192.168.0.1/8',
|
||||
'192.168.0.1/9',
|
||||
];
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
|
||||
test('ipv4 and cidr ipv4', () => {
|
||||
const arr = ['192.168.0.1/9', '192.168.0.1', '192.168.0.1/32', '192.168.0.1/7', '192.168.0.1/8'];
|
||||
const sortedArr = ['192.168.0.1/7', '192.168.0.1/8', '192.168.0.1/9', '192.168.0.1/32', '192.168.0.1'];
|
||||
|
||||
const arr = [
|
||||
'192.168.0.1/9',
|
||||
'192.168.0.1',
|
||||
'192.168.0.1/32',
|
||||
'192.168.0.1/7',
|
||||
'192.168.0.1/8',
|
||||
];
|
||||
const sortedArr = [
|
||||
'192.168.0.1/7',
|
||||
'192.168.0.1/8',
|
||||
'192.168.0.1/9',
|
||||
'192.168.0.1/32',
|
||||
'192.168.0.1',
|
||||
];
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
|
||||
test('only ipv6 cidr', () => {
|
||||
const arr = [
|
||||
'2001:db8:11a3:9d7::1/32',
|
||||
@@ -231,10 +257,8 @@ describe('sortIp', () => {
|
||||
'2001:db8:11a3:9d7::1/64',
|
||||
'2001:db8:11a3:9d7::1/128',
|
||||
];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
|
||||
test('ipv6 and cidr ipv6', () => {
|
||||
const arr = [
|
||||
'2001:db8:11a3:9d7::1/32',
|
||||
@@ -250,11 +274,9 @@ describe('sortIp', () => {
|
||||
'2001:db8:11a3:9d7::1/128',
|
||||
'2001:db8:11a3:9d7::1',
|
||||
];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid input', () => {
|
||||
const originalWarn = console.warn;
|
||||
|
||||
@@ -269,29 +291,21 @@ describe('sortIp', () => {
|
||||
|
||||
test('invalid strings', () => {
|
||||
const arr = ['invalid ip', 'invalid cidr'];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(arr);
|
||||
});
|
||||
|
||||
test('invalid ip', () => {
|
||||
const arr = ['127.0.0.2.', '.127.0.0.1.', '.2001:db8:11a3:9d7:0:0:0:0'];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(arr);
|
||||
});
|
||||
|
||||
test('invalid cidr', () => {
|
||||
const arr = ['127.0.0.2/33', '2001:db8:11a3:9d7:0:0:0:0/129'];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(arr);
|
||||
});
|
||||
|
||||
test('valid and invalid ip', () => {
|
||||
const arr = ['127.0.0.4.', '127.0.0.1', '.127.0.0.3', '127.0.0.2'];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(arr);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mixed', () => {
|
||||
test('ipv4, ipv6 in short and long forms and cidr', () => {
|
||||
const arr = [
|
||||
@@ -340,7 +354,6 @@ describe('sortIp', () => {
|
||||
'2001:db8:11a3:9d7:0:0:0:1',
|
||||
'2001:db8:11a3:9d7:0:0:0:2',
|
||||
];
|
||||
|
||||
expect(arr.sort(sortIp)).toStrictEqual(sortedArr);
|
||||
});
|
||||
});
|
||||
@@ -350,11 +363,9 @@ describe('findAddressType', () => {
|
||||
describe('ip', () => {
|
||||
expect(findAddressType('127.0.0.1')).toStrictEqual(ADDRESS_TYPES.IP);
|
||||
});
|
||||
|
||||
describe('cidr', () => {
|
||||
expect(findAddressType('127.0.0.1/8')).toStrictEqual(ADDRESS_TYPES.CIDR);
|
||||
});
|
||||
|
||||
describe('mac', () => {
|
||||
expect(findAddressType('00:1B:44:11:3A:B7')).toStrictEqual(ADDRESS_TYPES.UNKNOWN);
|
||||
});
|
||||
@@ -362,59 +373,42 @@ describe('findAddressType', () => {
|
||||
|
||||
describe('countClientsStatistics', () => {
|
||||
test('single ip', () => {
|
||||
expect(
|
||||
countClientsStatistics(['127.0.0.1'], {
|
||||
'127.0.0.1': 1,
|
||||
}),
|
||||
).toStrictEqual(1);
|
||||
expect(countClientsStatistics(['127.0.0.1'], {
|
||||
'127.0.0.1': 1,
|
||||
})).toStrictEqual(1);
|
||||
});
|
||||
|
||||
test('multiple ip', () => {
|
||||
expect(
|
||||
countClientsStatistics(['127.0.0.1', '127.0.0.2'], {
|
||||
'127.0.0.1': 1,
|
||||
'127.0.0.2': 2,
|
||||
}),
|
||||
).toStrictEqual(1 + 2);
|
||||
expect(countClientsStatistics(['127.0.0.1', '127.0.0.2'], {
|
||||
'127.0.0.1': 1,
|
||||
'127.0.0.2': 2,
|
||||
})).toStrictEqual(1 + 2);
|
||||
});
|
||||
|
||||
test('cidr', () => {
|
||||
expect(
|
||||
countClientsStatistics(['127.0.0.0/8'], {
|
||||
'127.0.0.1': 1,
|
||||
'127.0.0.2': 2,
|
||||
}),
|
||||
).toStrictEqual(1 + 2);
|
||||
expect(countClientsStatistics(['127.0.0.0/8'], {
|
||||
'127.0.0.1': 1,
|
||||
'127.0.0.2': 2,
|
||||
})).toStrictEqual(1 + 2);
|
||||
});
|
||||
|
||||
test('cidr and multiple ip', () => {
|
||||
expect(
|
||||
countClientsStatistics(['1.1.1.1', '2.2.2.2', '3.3.3.0/24'], {
|
||||
'1.1.1.1': 1,
|
||||
'2.2.2.2': 2,
|
||||
'3.3.3.3': 3,
|
||||
}),
|
||||
).toStrictEqual(1 + 2 + 3);
|
||||
expect(countClientsStatistics(['1.1.1.1', '2.2.2.2', '3.3.3.0/24'], {
|
||||
'1.1.1.1': 1,
|
||||
'2.2.2.2': 2,
|
||||
'3.3.3.3': 3,
|
||||
})).toStrictEqual(1 + 2 + 3);
|
||||
});
|
||||
|
||||
test('mac', () => {
|
||||
expect(
|
||||
countClientsStatistics(['00:1B:44:11:3A:B7', '2.2.2.2', '3.3.3.0/24'], {
|
||||
'1.1.1.1': 1,
|
||||
'2.2.2.2': 2,
|
||||
'3.3.3.3': 3,
|
||||
}),
|
||||
).toStrictEqual(2 + 3);
|
||||
expect(countClientsStatistics(['00:1B:44:11:3A:B7', '2.2.2.2', '3.3.3.0/24'], {
|
||||
'1.1.1.1': 1,
|
||||
'2.2.2.2': 2,
|
||||
'3.3.3.3': 3,
|
||||
})).toStrictEqual(2 + 3);
|
||||
});
|
||||
|
||||
test('not found', () => {
|
||||
expect(
|
||||
countClientsStatistics(['4.4.4.4', '5.5.5.5', '6.6.6.6'], {
|
||||
'1.1.1.1': 1,
|
||||
'2.2.2.2': 2,
|
||||
'3.3.3.3': 3,
|
||||
}),
|
||||
).toStrictEqual(0);
|
||||
expect(countClientsStatistics(['4.4.4.4', '5.5.5.5', '6.6.6.6'], {
|
||||
'1.1.1.1': 1,
|
||||
'2.2.2.2': 2,
|
||||
'3.3.3.3': 3,
|
||||
})).toStrictEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -457,12 +451,10 @@ describe('subnetMaskToBitMask', () => {
|
||||
|
||||
test('correct for all subnetMasks', () => {
|
||||
expect(
|
||||
subnetMasks
|
||||
.map((subnetMask) => {
|
||||
const bitmask = subnetMaskToBitMask(subnetMask);
|
||||
return subnetMasks[bitmask] === subnetMask;
|
||||
})
|
||||
.every((res) => res === true),
|
||||
subnetMasks.map((subnetMask) => {
|
||||
const bitmask = subnetMaskToBitMask(subnetMask);
|
||||
return subnetMasks[bitmask] === subnetMask;
|
||||
}).every((res) => res === true),
|
||||
).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -3,14 +3,13 @@ import i18next from 'i18next';
|
||||
|
||||
import apiClient from '../api/Api';
|
||||
import { addErrorToast, addSuccessToast } from './toasts';
|
||||
|
||||
import { splitByNewLine } from '../helpers/helpers';
|
||||
|
||||
export const getAccessListRequest = createAction('GET_ACCESS_LIST_REQUEST');
|
||||
export const getAccessListFailure = createAction('GET_ACCESS_LIST_FAILURE');
|
||||
export const getAccessListSuccess = createAction('GET_ACCESS_LIST_SUCCESS');
|
||||
|
||||
export const getAccessList = () => async (dispatch: any) => {
|
||||
export const getAccessList = () => async (dispatch) => {
|
||||
dispatch(getAccessListRequest());
|
||||
try {
|
||||
const data = await apiClient.getAccessList();
|
||||
@@ -25,7 +24,7 @@ export const setAccessListRequest = createAction('SET_ACCESS_LIST_REQUEST');
|
||||
export const setAccessListFailure = createAction('SET_ACCESS_LIST_FAILURE');
|
||||
export const setAccessListSuccess = createAction('SET_ACCESS_LIST_SUCCESS');
|
||||
|
||||
export const setAccessList = (config: any) => async (dispatch: any) => {
|
||||
export const setAccessList = (config) => async (dispatch) => {
|
||||
dispatch(setAccessListRequest());
|
||||
try {
|
||||
const { allowed_clients, disallowed_clients, blocked_hosts } = config;
|
||||
@@ -49,7 +48,7 @@ export const toggleClientBlockRequest = createAction('TOGGLE_CLIENT_BLOCK_REQUES
|
||||
export const toggleClientBlockFailure = createAction('TOGGLE_CLIENT_BLOCK_FAILURE');
|
||||
export const toggleClientBlockSuccess = createAction('TOGGLE_CLIENT_BLOCK_SUCCESS');
|
||||
|
||||
export const toggleClientBlock = (ip: any, disallowed: any, disallowed_rule: any) => async (dispatch: any) => {
|
||||
export const toggleClientBlock = (ip, disallowed, disallowed_rule) => async (dispatch) => {
|
||||
dispatch(toggleClientBlockRequest());
|
||||
try {
|
||||
const accessList = await apiClient.getAccessList();
|
||||
@@ -61,10 +60,12 @@ export const toggleClientBlock = (ip: any, disallowed: any, disallowed_rule: any
|
||||
if (!disallowed_rule) {
|
||||
allowed_clients = allowed_clients.concat(ip);
|
||||
} else {
|
||||
disallowed_clients = disallowed_clients.filter((client: any) => client !== disallowed_rule);
|
||||
disallowed_clients = disallowed_clients
|
||||
.filter((client) => client !== disallowed_rule);
|
||||
}
|
||||
} else if (allowed_clients.length > 1) {
|
||||
allowed_clients = allowed_clients.filter((client: any) => client !== disallowed_rule);
|
||||
allowed_clients = allowed_clients
|
||||
.filter((client) => client !== disallowed_rule);
|
||||
} else {
|
||||
disallowed_clients = disallowed_clients.concat(ip);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import { createAction } from 'redux-actions';
|
||||
import i18next from 'i18next';
|
||||
import apiClient from '../api/Api';
|
||||
|
||||
import { getClients } from './index';
|
||||
import { addErrorToast, addSuccessToast } from './toasts';
|
||||
|
||||
@@ -11,7 +10,7 @@ export const addClientRequest = createAction('ADD_CLIENT_REQUEST');
|
||||
export const addClientFailure = createAction('ADD_CLIENT_FAILURE');
|
||||
export const addClientSuccess = createAction('ADD_CLIENT_SUCCESS');
|
||||
|
||||
export const addClient = (config: any) => async (dispatch: any) => {
|
||||
export const addClient = (config) => async (dispatch) => {
|
||||
dispatch(addClientRequest());
|
||||
try {
|
||||
await apiClient.addClient(config);
|
||||
@@ -29,7 +28,7 @@ export const deleteClientRequest = createAction('DELETE_CLIENT_REQUEST');
|
||||
export const deleteClientFailure = createAction('DELETE_CLIENT_FAILURE');
|
||||
export const deleteClientSuccess = createAction('DELETE_CLIENT_SUCCESS');
|
||||
|
||||
export const deleteClient = (config: any) => async (dispatch: any) => {
|
||||
export const deleteClient = (config) => async (dispatch) => {
|
||||
dispatch(deleteClientRequest());
|
||||
try {
|
||||
await apiClient.deleteClient(config);
|
||||
@@ -46,7 +45,7 @@ export const updateClientRequest = createAction('UPDATE_CLIENT_REQUEST');
|
||||
export const updateClientFailure = createAction('UPDATE_CLIENT_FAILURE');
|
||||
export const updateClientSuccess = createAction('UPDATE_CLIENT_SUCCESS');
|
||||
|
||||
export const updateClient = (config: any, name: any) => async (dispatch: any) => {
|
||||
export const updateClient = (config, name) => async (dispatch) => {
|
||||
dispatch(updateClientRequest());
|
||||
try {
|
||||
const data = { name, data: { ...config } };
|
||||
@@ -2,7 +2,6 @@ import { createAction } from 'redux-actions';
|
||||
import i18next from 'i18next';
|
||||
|
||||
import apiClient from '../api/Api';
|
||||
|
||||
import { splitByNewLine } from '../helpers/helpers';
|
||||
import { addErrorToast, addSuccessToast } from './toasts';
|
||||
|
||||
@@ -10,7 +9,7 @@ export const getDnsConfigRequest = createAction('GET_DNS_CONFIG_REQUEST');
|
||||
export const getDnsConfigFailure = createAction('GET_DNS_CONFIG_FAILURE');
|
||||
export const getDnsConfigSuccess = createAction('GET_DNS_CONFIG_SUCCESS');
|
||||
|
||||
export const getDnsConfig = () => async (dispatch: any) => {
|
||||
export const getDnsConfig = () => async (dispatch) => {
|
||||
dispatch(getDnsConfigRequest());
|
||||
try {
|
||||
const data = await apiClient.getDnsConfig();
|
||||
@@ -25,7 +24,7 @@ export const clearDnsCacheRequest = createAction('CLEAR_DNS_CACHE_REQUEST');
|
||||
export const clearDnsCacheFailure = createAction('CLEAR_DNS_CACHE_FAILURE');
|
||||
export const clearDnsCacheSuccess = createAction('CLEAR_DNS_CACHE_SUCCESS');
|
||||
|
||||
export const clearDnsCache = () => async (dispatch: any) => {
|
||||
export const clearDnsCache = () => async (dispatch) => {
|
||||
dispatch(clearDnsCacheRequest());
|
||||
try {
|
||||
const data = await apiClient.clearCache();
|
||||
@@ -41,7 +40,7 @@ export const setDnsConfigRequest = createAction('SET_DNS_CONFIG_REQUEST');
|
||||
export const setDnsConfigFailure = createAction('SET_DNS_CONFIG_FAILURE');
|
||||
export const setDnsConfigSuccess = createAction('SET_DNS_CONFIG_SUCCESS');
|
||||
|
||||
export const setDnsConfig = (config: any) => async (dispatch: any) => {
|
||||
export const setDnsConfig = (config) => async (dispatch) => {
|
||||
dispatch(setDnsConfigRequest());
|
||||
try {
|
||||
const data = { ...config };
|
||||
@@ -1,6 +1,5 @@
|
||||
import { createAction } from 'redux-actions';
|
||||
import apiClient from '../api/Api';
|
||||
|
||||
import { redirectToCurrentProtocol } from '../helpers/helpers';
|
||||
import { addErrorToast, addSuccessToast } from './toasts';
|
||||
|
||||
@@ -8,7 +7,7 @@ export const getTlsStatusRequest = createAction('GET_TLS_STATUS_REQUEST');
|
||||
export const getTlsStatusFailure = createAction('GET_TLS_STATUS_FAILURE');
|
||||
export const getTlsStatusSuccess = createAction('GET_TLS_STATUS_SUCCESS');
|
||||
|
||||
export const getTlsStatus = () => async (dispatch: any) => {
|
||||
export const getTlsStatus = () => async (dispatch) => {
|
||||
dispatch(getTlsStatusRequest());
|
||||
try {
|
||||
const status = await apiClient.getTlsStatus();
|
||||
@@ -27,7 +26,7 @@ export const setTlsConfigFailure = createAction('SET_TLS_CONFIG_FAILURE');
|
||||
export const setTlsConfigSuccess = createAction('SET_TLS_CONFIG_SUCCESS');
|
||||
export const dnsStatusSuccess = createAction('DNS_STATUS_SUCCESS');
|
||||
|
||||
export const setTlsConfig = (config: any) => async (dispatch: any, getState: any) => {
|
||||
export const setTlsConfig = (config) => async (dispatch, getState) => {
|
||||
dispatch(setTlsConfigRequest());
|
||||
try {
|
||||
const { httpPort } = getState().dashboard;
|
||||
@@ -68,7 +67,7 @@ export const validateTlsConfigRequest = createAction('VALIDATE_TLS_CONFIG_REQUES
|
||||
export const validateTlsConfigFailure = createAction('VALIDATE_TLS_CONFIG_FAILURE');
|
||||
export const validateTlsConfigSuccess = createAction('VALIDATE_TLS_CONFIG_SUCCESS');
|
||||
|
||||
export const validateTlsConfig = (config: any) => async (dispatch: any) => {
|
||||
export const validateTlsConfig = (config) => async (dispatch) => {
|
||||
dispatch(validateTlsConfigRequest());
|
||||
try {
|
||||
const values = { ...config };
|
||||
@@ -13,7 +13,7 @@ export const getFilteringStatusRequest = createAction('GET_FILTERING_STATUS_REQU
|
||||
export const getFilteringStatusFailure = createAction('GET_FILTERING_STATUS_FAILURE');
|
||||
export const getFilteringStatusSuccess = createAction('GET_FILTERING_STATUS_SUCCESS');
|
||||
|
||||
export const getFilteringStatus = () => async (dispatch: any) => {
|
||||
export const getFilteringStatus = () => async (dispatch) => {
|
||||
dispatch(getFilteringStatusRequest());
|
||||
try {
|
||||
const status = await apiClient.getFilteringStatus();
|
||||
@@ -28,7 +28,7 @@ export const setRulesRequest = createAction('SET_RULES_REQUEST');
|
||||
export const setRulesFailure = createAction('SET_RULES_FAILURE');
|
||||
export const setRulesSuccess = createAction('SET_RULES_SUCCESS');
|
||||
|
||||
export const setRules = (rules: any) => async (dispatch: any) => {
|
||||
export const setRules = (rules) => async (dispatch) => {
|
||||
dispatch(setRulesRequest());
|
||||
try {
|
||||
const normalizedRules = {
|
||||
@@ -47,91 +47,83 @@ export const addFilterRequest = createAction('ADD_FILTER_REQUEST');
|
||||
export const addFilterFailure = createAction('ADD_FILTER_FAILURE');
|
||||
export const addFilterSuccess = createAction('ADD_FILTER_SUCCESS');
|
||||
|
||||
export const addFilter =
|
||||
(url: any, name: any, whitelist = false) =>
|
||||
async (dispatch: any, getState: any) => {
|
||||
dispatch(addFilterRequest());
|
||||
try {
|
||||
await apiClient.addFilter({ url, name, whitelist });
|
||||
dispatch(addFilterSuccess(url));
|
||||
if (getState().filtering.isModalOpen) {
|
||||
dispatch(toggleFilteringModal());
|
||||
}
|
||||
dispatch(addSuccessToast('filter_added_successfully'));
|
||||
dispatch(getFilteringStatus());
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(addFilterFailure());
|
||||
export const addFilter = (url, name, whitelist = false) => async (dispatch, getState) => {
|
||||
dispatch(addFilterRequest());
|
||||
try {
|
||||
await apiClient.addFilter({ url, name, whitelist });
|
||||
dispatch(addFilterSuccess(url));
|
||||
if (getState().filtering.isModalOpen) {
|
||||
dispatch(toggleFilteringModal());
|
||||
}
|
||||
};
|
||||
dispatch(addSuccessToast('filter_added_successfully'));
|
||||
dispatch(getFilteringStatus());
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(addFilterFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const removeFilterRequest = createAction('REMOVE_FILTER_REQUEST');
|
||||
export const removeFilterFailure = createAction('REMOVE_FILTER_FAILURE');
|
||||
export const removeFilterSuccess = createAction('REMOVE_FILTER_SUCCESS');
|
||||
|
||||
export const removeFilter =
|
||||
(url: any, whitelist = false) =>
|
||||
async (dispatch: any, getState: any) => {
|
||||
dispatch(removeFilterRequest());
|
||||
try {
|
||||
await apiClient.removeFilter({ url, whitelist });
|
||||
dispatch(removeFilterSuccess(url));
|
||||
if (getState().filtering.isModalOpen) {
|
||||
dispatch(toggleFilteringModal());
|
||||
}
|
||||
dispatch(addSuccessToast('filter_removed_successfully'));
|
||||
dispatch(getFilteringStatus());
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(removeFilterFailure());
|
||||
export const removeFilter = (url, whitelist = false) => async (dispatch, getState) => {
|
||||
dispatch(removeFilterRequest());
|
||||
try {
|
||||
await apiClient.removeFilter({ url, whitelist });
|
||||
dispatch(removeFilterSuccess(url));
|
||||
if (getState().filtering.isModalOpen) {
|
||||
dispatch(toggleFilteringModal());
|
||||
}
|
||||
};
|
||||
dispatch(addSuccessToast('filter_removed_successfully'));
|
||||
dispatch(getFilteringStatus());
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(removeFilterFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const toggleFilterRequest = createAction('FILTER_TOGGLE_REQUEST');
|
||||
export const toggleFilterFailure = createAction('FILTER_TOGGLE_FAILURE');
|
||||
export const toggleFilterSuccess = createAction('FILTER_TOGGLE_SUCCESS');
|
||||
|
||||
export const toggleFilterStatus =
|
||||
(url: any, data: any, whitelist = false) =>
|
||||
async (dispatch: any) => {
|
||||
dispatch(toggleFilterRequest());
|
||||
try {
|
||||
await apiClient.setFilterUrl({ url, data, whitelist });
|
||||
dispatch(toggleFilterSuccess(url));
|
||||
dispatch(getFilteringStatus());
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(toggleFilterFailure());
|
||||
}
|
||||
};
|
||||
export const toggleFilterStatus = (url, data, whitelist = false) => async (dispatch) => {
|
||||
dispatch(toggleFilterRequest());
|
||||
try {
|
||||
await apiClient.setFilterUrl({ url, data, whitelist });
|
||||
dispatch(toggleFilterSuccess(url));
|
||||
dispatch(getFilteringStatus());
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(toggleFilterFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const editFilterRequest = createAction('EDIT_FILTER_REQUEST');
|
||||
export const editFilterFailure = createAction('EDIT_FILTER_FAILURE');
|
||||
export const editFilterSuccess = createAction('EDIT_FILTER_SUCCESS');
|
||||
|
||||
export const editFilter =
|
||||
(url: any, data: any, whitelist = false) =>
|
||||
async (dispatch: any, getState: any) => {
|
||||
dispatch(editFilterRequest());
|
||||
try {
|
||||
await apiClient.setFilterUrl({ url, data, whitelist });
|
||||
dispatch(editFilterSuccess(url));
|
||||
if (getState().filtering.isModalOpen) {
|
||||
dispatch(toggleFilteringModal());
|
||||
}
|
||||
dispatch(addSuccessToast('filter_updated'));
|
||||
dispatch(getFilteringStatus());
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(editFilterFailure());
|
||||
export const editFilter = (url, data, whitelist = false) => async (dispatch, getState) => {
|
||||
dispatch(editFilterRequest());
|
||||
try {
|
||||
await apiClient.setFilterUrl({ url, data, whitelist });
|
||||
dispatch(editFilterSuccess(url));
|
||||
if (getState().filtering.isModalOpen) {
|
||||
dispatch(toggleFilteringModal());
|
||||
}
|
||||
};
|
||||
dispatch(addSuccessToast('filter_updated'));
|
||||
dispatch(getFilteringStatus());
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(editFilterFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const refreshFiltersRequest = createAction('FILTERING_REFRESH_REQUEST');
|
||||
export const refreshFiltersFailure = createAction('FILTERING_REFRESH_FAILURE');
|
||||
export const refreshFiltersSuccess = createAction('FILTERING_REFRESH_SUCCESS');
|
||||
|
||||
export const refreshFilters = (config: any) => async (dispatch: any) => {
|
||||
export const refreshFilters = (config) => async (dispatch) => {
|
||||
dispatch(refreshFiltersRequest());
|
||||
dispatch(showLoading());
|
||||
try {
|
||||
@@ -158,7 +150,7 @@ export const setFiltersConfigRequest = createAction('SET_FILTERS_CONFIG_REQUEST'
|
||||
export const setFiltersConfigFailure = createAction('SET_FILTERS_CONFIG_FAILURE');
|
||||
export const setFiltersConfigSuccess = createAction('SET_FILTERS_CONFIG_SUCCESS');
|
||||
|
||||
export const setFiltersConfig = (config: any) => async (dispatch: any, getState: any) => {
|
||||
export const setFiltersConfig = (config) => async (dispatch, getState) => {
|
||||
dispatch(setFiltersConfigRequest());
|
||||
try {
|
||||
const { enabled } = config;
|
||||
@@ -188,18 +180,16 @@ export const checkHostSuccess = createAction('CHECK_HOST_SUCCESS');
|
||||
* @param {string} host.name
|
||||
* @returns {undefined}
|
||||
*/
|
||||
export const checkHost = (host: any) => async (dispatch: any) => {
|
||||
export const checkHost = (host) => async (dispatch) => {
|
||||
dispatch(checkHostRequest());
|
||||
try {
|
||||
const data = await apiClient.checkHost(host);
|
||||
const { name: hostname } = host;
|
||||
|
||||
dispatch(
|
||||
checkHostSuccess({
|
||||
hostname,
|
||||
...data,
|
||||
}),
|
||||
);
|
||||
dispatch(checkHostSuccess({
|
||||
hostname,
|
||||
...data,
|
||||
}));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(checkHostFailure());
|
||||
@@ -38,7 +38,7 @@ export const showSettingsFailure = createAction('SETTINGS_FAILURE_SHOW');
|
||||
* @param {*} status: boolean | SafeSearchConfig
|
||||
* @returns
|
||||
*/
|
||||
export const toggleSetting = (settingKey: any, status: any) => async (dispatch: any) => {
|
||||
export const toggleSetting = (settingKey, status) => async (dispatch) => {
|
||||
let successMessage = '';
|
||||
try {
|
||||
switch (settingKey) {
|
||||
@@ -80,58 +80,64 @@ export const initSettingsRequest = createAction('SETTINGS_INIT_REQUEST');
|
||||
export const initSettingsFailure = createAction('SETTINGS_INIT_FAILURE');
|
||||
export const initSettingsSuccess = createAction('SETTINGS_INIT_SUCCESS');
|
||||
|
||||
export const initSettings =
|
||||
(
|
||||
settingsList = {
|
||||
safebrowsing: {},
|
||||
parental: {},
|
||||
},
|
||||
) =>
|
||||
async (dispatch: any) => {
|
||||
dispatch(initSettingsRequest());
|
||||
try {
|
||||
const safebrowsingStatus = await apiClient.getSafebrowsingStatus();
|
||||
const parentalStatus = await apiClient.getParentalStatus();
|
||||
const safesearchStatus = await apiClient.getSafesearchStatus();
|
||||
const { safebrowsing, parental } = settingsList;
|
||||
const newSettingsList = {
|
||||
safebrowsing: {
|
||||
...safebrowsing,
|
||||
enabled: safebrowsingStatus.enabled,
|
||||
},
|
||||
parental: {
|
||||
...parental,
|
||||
enabled: parentalStatus.enabled,
|
||||
},
|
||||
safesearch: {
|
||||
...safesearchStatus,
|
||||
},
|
||||
};
|
||||
dispatch(initSettingsSuccess({ settingsList: newSettingsList }));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(initSettingsFailure());
|
||||
}
|
||||
};
|
||||
export const initSettings = (settingsList = {
|
||||
safebrowsing: {}, parental: {},
|
||||
}) => async (dispatch) => {
|
||||
dispatch(initSettingsRequest());
|
||||
try {
|
||||
const safebrowsingStatus = await apiClient.getSafebrowsingStatus();
|
||||
const parentalStatus = await apiClient.getParentalStatus();
|
||||
const safesearchStatus = await apiClient.getSafesearchStatus();
|
||||
const {
|
||||
safebrowsing,
|
||||
parental,
|
||||
} = settingsList;
|
||||
const newSettingsList = {
|
||||
safebrowsing: {
|
||||
...safebrowsing,
|
||||
enabled: safebrowsingStatus.enabled,
|
||||
},
|
||||
parental: {
|
||||
...parental,
|
||||
enabled: parentalStatus.enabled,
|
||||
},
|
||||
safesearch: {
|
||||
...safesearchStatus,
|
||||
},
|
||||
};
|
||||
dispatch(initSettingsSuccess({ settingsList: newSettingsList }));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(initSettingsFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const toggleProtectionRequest = createAction('TOGGLE_PROTECTION_REQUEST');
|
||||
export const toggleProtectionFailure = createAction('TOGGLE_PROTECTION_FAILURE');
|
||||
export const toggleProtectionSuccess = createAction('TOGGLE_PROTECTION_SUCCESS');
|
||||
|
||||
const getDisabledMessage = (time: any) => {
|
||||
const getDisabledMessage = (time) => {
|
||||
switch (time) {
|
||||
case DISABLE_PROTECTION_TIMINGS.HALF_MINUTE:
|
||||
return i18next.t('disable_notify_for_seconds', {
|
||||
count: msToSeconds(DISABLE_PROTECTION_TIMINGS.HALF_MINUTE),
|
||||
});
|
||||
return i18next.t(
|
||||
'disable_notify_for_seconds',
|
||||
{ count: msToSeconds(DISABLE_PROTECTION_TIMINGS.HALF_MINUTE) },
|
||||
);
|
||||
case DISABLE_PROTECTION_TIMINGS.MINUTE:
|
||||
return i18next.t('disable_notify_for_minutes', { count: msToMinutes(DISABLE_PROTECTION_TIMINGS.MINUTE) });
|
||||
return i18next.t(
|
||||
'disable_notify_for_minutes',
|
||||
{ count: msToMinutes(DISABLE_PROTECTION_TIMINGS.MINUTE) },
|
||||
);
|
||||
case DISABLE_PROTECTION_TIMINGS.TEN_MINUTES:
|
||||
return i18next.t('disable_notify_for_minutes', {
|
||||
count: msToMinutes(DISABLE_PROTECTION_TIMINGS.TEN_MINUTES),
|
||||
});
|
||||
return i18next.t(
|
||||
'disable_notify_for_minutes',
|
||||
{ count: msToMinutes(DISABLE_PROTECTION_TIMINGS.TEN_MINUTES) },
|
||||
);
|
||||
case DISABLE_PROTECTION_TIMINGS.HOUR:
|
||||
return i18next.t('disable_notify_for_hours', { count: msToHours(DISABLE_PROTECTION_TIMINGS.HOUR) });
|
||||
return i18next.t(
|
||||
'disable_notify_for_hours',
|
||||
{ count: msToHours(DISABLE_PROTECTION_TIMINGS.HOUR) },
|
||||
);
|
||||
case DISABLE_PROTECTION_TIMINGS.TOMORROW:
|
||||
return i18next.t('disable_notify_until_tomorrow');
|
||||
default:
|
||||
@@ -139,24 +145,22 @@ const getDisabledMessage = (time: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const toggleProtection =
|
||||
(status: any, time = null) =>
|
||||
async (dispatch: any) => {
|
||||
dispatch(toggleProtectionRequest());
|
||||
try {
|
||||
const successMessage = status ? getDisabledMessage(time) : 'enabled_protection';
|
||||
await apiClient.setProtection({ enabled: !status, duration: time });
|
||||
dispatch(addSuccessToast(successMessage));
|
||||
dispatch(toggleProtectionSuccess({ disabledDuration: time }));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(toggleProtectionFailure());
|
||||
}
|
||||
};
|
||||
export const toggleProtection = (status, time = null) => async (dispatch) => {
|
||||
dispatch(toggleProtectionRequest());
|
||||
try {
|
||||
const successMessage = status ? getDisabledMessage(time) : 'enabled_protection';
|
||||
await apiClient.setProtection({ enabled: !status, duration: time });
|
||||
dispatch(addSuccessToast(successMessage));
|
||||
dispatch(toggleProtectionSuccess({ disabledDuration: time }));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(toggleProtectionFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const setDisableDurationTime = createAction('SET_DISABLED_DURATION_TIME');
|
||||
|
||||
export const setProtectionTimerTime = (updatedTime: any) => async (dispatch: any) => {
|
||||
export const setProtectionTimerTime = (updatedTime) => async (dispatch) => {
|
||||
dispatch(setDisableDurationTime({ timeToEnableProtection: updatedTime }));
|
||||
};
|
||||
|
||||
@@ -164,42 +168,40 @@ export const getVersionRequest = createAction('GET_VERSION_REQUEST');
|
||||
export const getVersionFailure = createAction('GET_VERSION_FAILURE');
|
||||
export const getVersionSuccess = createAction('GET_VERSION_SUCCESS');
|
||||
|
||||
export const getVersion =
|
||||
(recheck = false) =>
|
||||
async (dispatch: any, getState: any) => {
|
||||
dispatch(getVersionRequest());
|
||||
try {
|
||||
const data = await apiClient.getGlobalVersion({ recheck_now: recheck });
|
||||
dispatch(getVersionSuccess(data));
|
||||
export const getVersion = (recheck = false) => async (dispatch, getState) => {
|
||||
dispatch(getVersionRequest());
|
||||
try {
|
||||
const data = await apiClient.getGlobalVersion({ recheck_now: recheck });
|
||||
dispatch(getVersionSuccess(data));
|
||||
|
||||
if (recheck) {
|
||||
const { dnsVersion } = getState().dashboard;
|
||||
const currentVersion = dnsVersion === 'undefined' ? 0 : dnsVersion;
|
||||
if (recheck) {
|
||||
const { dnsVersion } = getState().dashboard;
|
||||
const currentVersion = dnsVersion === 'undefined' ? 0 : dnsVersion;
|
||||
|
||||
if (data && !areEqualVersions(currentVersion, data.new_version)) {
|
||||
dispatch(addSuccessToast('updates_checked'));
|
||||
} else {
|
||||
dispatch(addSuccessToast('updates_version_equal'));
|
||||
}
|
||||
if (data && !areEqualVersions(currentVersion, data.new_version)) {
|
||||
dispatch(addSuccessToast('updates_checked'));
|
||||
} else {
|
||||
dispatch(addSuccessToast('updates_version_equal'));
|
||||
}
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error: 'version_request_error' }));
|
||||
dispatch(getVersionFailure());
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error: 'version_request_error' }));
|
||||
dispatch(getVersionFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const getUpdateRequest = createAction('GET_UPDATE_REQUEST');
|
||||
export const getUpdateFailure = createAction('GET_UPDATE_FAILURE');
|
||||
export const getUpdateSuccess = createAction('GET_UPDATE_SUCCESS');
|
||||
|
||||
const checkStatus = async (handleRequestSuccess: any, handleRequestError: any, attempts = 60) => {
|
||||
const checkStatus = async (handleRequestSuccess, handleRequestError, attempts = 60) => {
|
||||
let timeout;
|
||||
|
||||
if (attempts === 0) {
|
||||
handleRequestError();
|
||||
}
|
||||
|
||||
const rmTimeout = (t: any) => t && clearTimeout(t);
|
||||
const rmTimeout = (t) => t && clearTimeout(t);
|
||||
|
||||
try {
|
||||
const response = await axios.get(`${apiClient.baseUrl}/status`);
|
||||
@@ -218,18 +220,25 @@ const checkStatus = async (handleRequestSuccess: any, handleRequestError: any, a
|
||||
}
|
||||
} catch (error) {
|
||||
rmTimeout(timeout);
|
||||
timeout = setTimeout(checkStatus, CHECK_TIMEOUT, handleRequestSuccess, handleRequestError, attempts - 1);
|
||||
timeout = setTimeout(
|
||||
checkStatus,
|
||||
CHECK_TIMEOUT,
|
||||
handleRequestSuccess,
|
||||
handleRequestError,
|
||||
attempts - 1,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const getUpdate = () => async (dispatch: any, getState: any) => {
|
||||
export const getUpdate = () => async (dispatch, getState) => {
|
||||
const { dnsVersion } = getState().dashboard;
|
||||
|
||||
dispatch(getUpdateRequest());
|
||||
const handleRequestError = () => {
|
||||
const options = {
|
||||
components: {
|
||||
a: <a href={MANUAL_UPDATE_LINK} target="_blank" rel="noopener noreferrer" />,
|
||||
a: <a href={MANUAL_UPDATE_LINK} target="_blank"
|
||||
rel="noopener noreferrer" />,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -237,13 +246,12 @@ export const getUpdate = () => async (dispatch: any, getState: any) => {
|
||||
dispatch(getUpdateFailure());
|
||||
};
|
||||
|
||||
const handleRequestSuccess = (response: any) => {
|
||||
const handleRequestSuccess = (response) => {
|
||||
const responseVersion = response.data?.version;
|
||||
|
||||
if (dnsVersion !== responseVersion) {
|
||||
dispatch(getUpdateSuccess());
|
||||
|
||||
window.location.reload();
|
||||
window.location.reload(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -259,20 +267,18 @@ export const getClientsRequest = createAction('GET_CLIENTS_REQUEST');
|
||||
export const getClientsFailure = createAction('GET_CLIENTS_FAILURE');
|
||||
export const getClientsSuccess = createAction('GET_CLIENTS_SUCCESS');
|
||||
|
||||
export const getClients = () => async (dispatch: any) => {
|
||||
export const getClients = () => async (dispatch) => {
|
||||
dispatch(getClientsRequest());
|
||||
try {
|
||||
const data = await apiClient.getClients();
|
||||
const sortedClients = data.clients && sortClients(data.clients);
|
||||
const sortedAutoClients = data.auto_clients && sortClients(data.auto_clients);
|
||||
|
||||
dispatch(
|
||||
getClientsSuccess({
|
||||
clients: sortedClients || [],
|
||||
autoClients: sortedAutoClients || [],
|
||||
supportedTags: data.supported_tags || [],
|
||||
}),
|
||||
);
|
||||
dispatch(getClientsSuccess({
|
||||
clients: sortedClients || [],
|
||||
autoClients: sortedAutoClients || [],
|
||||
supportedTags: data.supported_tags || [],
|
||||
}));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(getClientsFailure());
|
||||
@@ -283,7 +289,7 @@ export const getProfileRequest = createAction('GET_PROFILE_REQUEST');
|
||||
export const getProfileFailure = createAction('GET_PROFILE_FAILURE');
|
||||
export const getProfileSuccess = createAction('GET_PROFILE_SUCCESS');
|
||||
|
||||
export const getProfile = () => async (dispatch: any) => {
|
||||
export const getProfile = () => async (dispatch) => {
|
||||
dispatch(getProfileRequest());
|
||||
try {
|
||||
const profile = await apiClient.getProfile();
|
||||
@@ -299,17 +305,16 @@ export const dnsStatusFailure = createAction('DNS_STATUS_FAILURE');
|
||||
export const dnsStatusSuccess = createAction('DNS_STATUS_SUCCESS');
|
||||
export const setDnsRunningStatus = createAction('SET_DNS_RUNNING_STATUS');
|
||||
|
||||
export const getDnsStatus = () => async (dispatch: any) => {
|
||||
export const getDnsStatus = () => async (dispatch) => {
|
||||
dispatch(dnsStatusRequest());
|
||||
|
||||
const handleRequestError = () => {
|
||||
dispatch(addErrorToast({ error: 'dns_status_error' }));
|
||||
dispatch(dnsStatusFailure());
|
||||
|
||||
window.location.reload();
|
||||
window.location.reload(true);
|
||||
};
|
||||
|
||||
const handleRequestSuccess = (response: any) => {
|
||||
const handleRequestSuccess = (response) => {
|
||||
const dnsStatus = response.data;
|
||||
if (dnsStatus.protection_disabled_duration === 0) {
|
||||
dnsStatus.protection_disabled_duration = null;
|
||||
@@ -337,17 +342,16 @@ export const timerStatusRequest = createAction('TIMER_STATUS_REQUEST');
|
||||
export const timerStatusFailure = createAction('TIMER_STATUS_FAILURE');
|
||||
export const timerStatusSuccess = createAction('TIMER_STATUS_SUCCESS');
|
||||
|
||||
export const getTimerStatus = () => async (dispatch: any) => {
|
||||
export const getTimerStatus = () => async (dispatch) => {
|
||||
dispatch(timerStatusRequest());
|
||||
|
||||
const handleRequestError = () => {
|
||||
dispatch(addErrorToast({ error: 'dns_status_error' }));
|
||||
dispatch(dnsStatusFailure());
|
||||
|
||||
window.location.reload();
|
||||
window.location.reload(true);
|
||||
};
|
||||
|
||||
const handleRequestSuccess = (response: any) => {
|
||||
const handleRequestSuccess = (response) => {
|
||||
const dnsStatus = response.data;
|
||||
if (dnsStatus.protection_disabled_duration === 0) {
|
||||
dnsStatus.protection_disabled_duration = null;
|
||||
@@ -372,26 +376,30 @@ export const testUpstreamRequest = createAction('TEST_UPSTREAM_REQUEST');
|
||||
export const testUpstreamFailure = createAction('TEST_UPSTREAM_FAILURE');
|
||||
export const testUpstreamSuccess = createAction('TEST_UPSTREAM_SUCCESS');
|
||||
|
||||
export const testUpstream =
|
||||
({ bootstrap_dns, upstream_dns, local_ptr_upstreams, fallback_dns }: any, upstream_dns_file: any) =>
|
||||
async (dispatch: any) => {
|
||||
dispatch(testUpstreamRequest());
|
||||
try {
|
||||
const removeComments = compose(filterOutComments, splitByNewLine);
|
||||
export const testUpstream = (
|
||||
{
|
||||
bootstrap_dns,
|
||||
upstream_dns,
|
||||
local_ptr_upstreams,
|
||||
fallback_dns,
|
||||
}, upstream_dns_file,
|
||||
) => async (dispatch) => {
|
||||
dispatch(testUpstreamRequest());
|
||||
try {
|
||||
const removeComments = compose(filterOutComments, splitByNewLine);
|
||||
|
||||
const config = {
|
||||
bootstrap_dns: splitByNewLine(bootstrap_dns),
|
||||
private_upstream: splitByNewLine(local_ptr_upstreams),
|
||||
fallback_dns: splitByNewLine(fallback_dns),
|
||||
...(upstream_dns_file
|
||||
? null
|
||||
: {
|
||||
upstream_dns: removeComments(upstream_dns),
|
||||
}),
|
||||
};
|
||||
const config = {
|
||||
bootstrap_dns: splitByNewLine(bootstrap_dns),
|
||||
private_upstream: splitByNewLine(local_ptr_upstreams),
|
||||
fallback_dns: splitByNewLine(fallback_dns),
|
||||
...(upstream_dns_file ? null : {
|
||||
upstream_dns: removeComments(upstream_dns),
|
||||
}),
|
||||
};
|
||||
|
||||
const upstreamResponse = await apiClient.testUpstream(config);
|
||||
const testMessages = Object.keys(upstreamResponse).map((key) => {
|
||||
const upstreamResponse = await apiClient.testUpstream(config);
|
||||
const testMessages = Object.keys(upstreamResponse)
|
||||
.map((key) => {
|
||||
const message = upstreamResponse[key];
|
||||
if (message.startsWith('WARNING:')) {
|
||||
dispatch(addErrorToast({ error: i18next.t('dns_test_warning_toast', { key }) }));
|
||||
@@ -399,54 +407,46 @@ export const testUpstream =
|
||||
const info = message.substring(0, message.indexOf(':'));
|
||||
const [sectionKey, line] = info.split(' ');
|
||||
const section = i18next.t(sectionKey);
|
||||
dispatch(
|
||||
addErrorToast({
|
||||
error: i18next.t('dns_test_parsing_error_toast', {
|
||||
section,
|
||||
line,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
dispatch(addErrorToast({ error: i18next.t('dns_test_parsing_error_toast', { section, line }) }));
|
||||
} else if (message !== 'OK') {
|
||||
dispatch(addErrorToast({ error: i18next.t('dns_test_not_ok_toast', { key }) }));
|
||||
}
|
||||
return message;
|
||||
});
|
||||
|
||||
if (testMessages.every((message) => message === 'OK' || message.startsWith('WARNING:'))) {
|
||||
dispatch(addSuccessToast('dns_test_ok_toast'));
|
||||
}
|
||||
|
||||
dispatch(testUpstreamSuccess());
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(testUpstreamFailure());
|
||||
if (testMessages.every((message) => message === 'OK' || message.startsWith('WARNING:'))) {
|
||||
dispatch(addSuccessToast('dns_test_ok_toast'));
|
||||
}
|
||||
};
|
||||
|
||||
export const testUpstreamWithFormValues = () => async (dispatch: any, getState: any) => {
|
||||
dispatch(testUpstreamSuccess());
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(testUpstreamFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const testUpstreamWithFormValues = () => async (dispatch, getState) => {
|
||||
const { upstream_dns_file } = getState().dnsConfig;
|
||||
const { bootstrap_dns, upstream_dns, local_ptr_upstreams, fallback_dns } =
|
||||
getState().form[FORM_NAME.UPSTREAM].values;
|
||||
const {
|
||||
bootstrap_dns,
|
||||
upstream_dns,
|
||||
local_ptr_upstreams,
|
||||
fallback_dns,
|
||||
} = getState().form[FORM_NAME.UPSTREAM].values;
|
||||
|
||||
return dispatch(
|
||||
testUpstream(
|
||||
{
|
||||
bootstrap_dns,
|
||||
upstream_dns,
|
||||
local_ptr_upstreams,
|
||||
fallback_dns,
|
||||
},
|
||||
upstream_dns_file,
|
||||
),
|
||||
);
|
||||
return dispatch(testUpstream({
|
||||
bootstrap_dns,
|
||||
upstream_dns,
|
||||
local_ptr_upstreams,
|
||||
fallback_dns,
|
||||
}, upstream_dns_file));
|
||||
};
|
||||
|
||||
export const changeLanguageRequest = createAction('CHANGE_LANGUAGE_REQUEST');
|
||||
export const changeLanguageFailure = createAction('CHANGE_LANGUAGE_FAILURE');
|
||||
export const changeLanguageSuccess = createAction('CHANGE_LANGUAGE_SUCCESS');
|
||||
|
||||
export const changeLanguage = (lang: any) => async (dispatch: any) => {
|
||||
export const changeLanguage = (lang) => async (dispatch) => {
|
||||
dispatch(changeLanguageRequest());
|
||||
try {
|
||||
await apiClient.changeLanguage({ language: lang });
|
||||
@@ -461,7 +461,7 @@ export const changeThemeRequest = createAction('CHANGE_THEME_REQUEST');
|
||||
export const changeThemeFailure = createAction('CHANGE_THEME_FAILURE');
|
||||
export const changeThemeSuccess = createAction('CHANGE_THEME_SUCCESS');
|
||||
|
||||
export const changeTheme = (theme: any) => async (dispatch: any) => {
|
||||
export const changeTheme = (theme) => async (dispatch) => {
|
||||
dispatch(changeThemeRequest());
|
||||
try {
|
||||
await apiClient.changeTheme({ theme });
|
||||
@@ -476,7 +476,7 @@ export const getDhcpStatusRequest = createAction('GET_DHCP_STATUS_REQUEST');
|
||||
export const getDhcpStatusSuccess = createAction('GET_DHCP_STATUS_SUCCESS');
|
||||
export const getDhcpStatusFailure = createAction('GET_DHCP_STATUS_FAILURE');
|
||||
|
||||
export const getDhcpStatus = () => async (dispatch: any) => {
|
||||
export const getDhcpStatus = () => async (dispatch) => {
|
||||
dispatch(getDhcpStatusRequest());
|
||||
try {
|
||||
const globalStatus = await apiClient.getGlobalStatus();
|
||||
@@ -497,7 +497,7 @@ export const getDhcpInterfacesRequest = createAction('GET_DHCP_INTERFACES_REQUES
|
||||
export const getDhcpInterfacesSuccess = createAction('GET_DHCP_INTERFACES_SUCCESS');
|
||||
export const getDhcpInterfacesFailure = createAction('GET_DHCP_INTERFACES_FAILURE');
|
||||
|
||||
export const getDhcpInterfaces = () => async (dispatch: any) => {
|
||||
export const getDhcpInterfaces = () => async (dispatch) => {
|
||||
dispatch(getDhcpInterfacesRequest());
|
||||
try {
|
||||
const interfaces = await apiClient.getDhcpInterfaces();
|
||||
@@ -512,7 +512,7 @@ export const findActiveDhcpRequest = createAction('FIND_ACTIVE_DHCP_REQUEST');
|
||||
export const findActiveDhcpSuccess = createAction('FIND_ACTIVE_DHCP_SUCCESS');
|
||||
export const findActiveDhcpFailure = createAction('FIND_ACTIVE_DHCP_FAILURE');
|
||||
|
||||
export const findActiveDhcp = (name: any) => async (dispatch: any, getState: any) => {
|
||||
export const findActiveDhcp = (name) => async (dispatch, getState) => {
|
||||
dispatch(findActiveDhcpRequest());
|
||||
try {
|
||||
const req = {
|
||||
@@ -559,12 +559,12 @@ export const findActiveDhcp = (name: any) => async (dispatch: any, getState: any
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(hasV4Interface && v4.other_server.found === STATUS_RESPONSE.YES) ||
|
||||
(hasV6Interface && v6.other_server.found === STATUS_RESPONSE.YES)
|
||||
) {
|
||||
if ((hasV4Interface && v4.other_server.found === STATUS_RESPONSE.YES)
|
||||
|| (hasV6Interface && v6.other_server.found === STATUS_RESPONSE.YES)) {
|
||||
dispatch(addErrorToast({ error: 'dhcp_found' }));
|
||||
} else if (hasV4Interface && v4.static_ip.static === STATUS_RESPONSE.NO && v4.static_ip.ip && interface_name) {
|
||||
} else if (hasV4Interface && v4.static_ip.static === STATUS_RESPONSE.NO
|
||||
&& v4.static_ip.ip
|
||||
&& interface_name) {
|
||||
const warning = i18next.t('dhcp_dynamic_ip_found', {
|
||||
interfaceName: interface_name,
|
||||
ipAddress: v4.static_ip.ip,
|
||||
@@ -587,7 +587,7 @@ export const setDhcpConfigRequest = createAction('SET_DHCP_CONFIG_REQUEST');
|
||||
export const setDhcpConfigSuccess = createAction('SET_DHCP_CONFIG_SUCCESS');
|
||||
export const setDhcpConfigFailure = createAction('SET_DHCP_CONFIG_FAILURE');
|
||||
|
||||
export const setDhcpConfig = (values: any) => async (dispatch: any) => {
|
||||
export const setDhcpConfig = (values) => async (dispatch) => {
|
||||
dispatch(setDhcpConfigRequest());
|
||||
try {
|
||||
await apiClient.setDhcpConfig(values);
|
||||
@@ -603,7 +603,7 @@ export const toggleDhcpRequest = createAction('TOGGLE_DHCP_REQUEST');
|
||||
export const toggleDhcpFailure = createAction('TOGGLE_DHCP_FAILURE');
|
||||
export const toggleDhcpSuccess = createAction('TOGGLE_DHCP_SUCCESS');
|
||||
|
||||
export const toggleDhcp = (values: any) => async (dispatch: any) => {
|
||||
export const toggleDhcp = (values) => async (dispatch) => {
|
||||
dispatch(toggleDhcpRequest());
|
||||
let config = {
|
||||
...values,
|
||||
@@ -633,7 +633,7 @@ export const resetDhcpRequest = createAction('RESET_DHCP_REQUEST');
|
||||
export const resetDhcpSuccess = createAction('RESET_DHCP_SUCCESS');
|
||||
export const resetDhcpFailure = createAction('RESET_DHCP_FAILURE');
|
||||
|
||||
export const resetDhcp = () => async (dispatch: any) => {
|
||||
export const resetDhcp = () => async (dispatch) => {
|
||||
dispatch(resetDhcpRequest());
|
||||
try {
|
||||
const status = await apiClient.resetDhcp();
|
||||
@@ -649,7 +649,7 @@ export const resetDhcpLeasesRequest = createAction('RESET_DHCP_LEASES_REQUEST');
|
||||
export const resetDhcpLeasesSuccess = createAction('RESET_DHCP_LEASES_SUCCESS');
|
||||
export const resetDhcpLeasesFailure = createAction('RESET_DHCP_LEASES_FAILURE');
|
||||
|
||||
export const resetDhcpLeases = () => async (dispatch: any) => {
|
||||
export const resetDhcpLeases = () => async (dispatch) => {
|
||||
dispatch(resetDhcpLeasesRequest());
|
||||
try {
|
||||
const status = await apiClient.resetDhcpLeases();
|
||||
@@ -667,7 +667,7 @@ export const addStaticLeaseRequest = createAction('ADD_STATIC_LEASE_REQUEST');
|
||||
export const addStaticLeaseFailure = createAction('ADD_STATIC_LEASE_FAILURE');
|
||||
export const addStaticLeaseSuccess = createAction('ADD_STATIC_LEASE_SUCCESS');
|
||||
|
||||
export const addStaticLease = (config: any) => async (dispatch: any) => {
|
||||
export const addStaticLease = (config) => async (dispatch) => {
|
||||
dispatch(addStaticLeaseRequest());
|
||||
try {
|
||||
const name = config.hostname || config.ip;
|
||||
@@ -686,7 +686,7 @@ export const removeStaticLeaseRequest = createAction('REMOVE_STATIC_LEASE_REQUES
|
||||
export const removeStaticLeaseFailure = createAction('REMOVE_STATIC_LEASE_FAILURE');
|
||||
export const removeStaticLeaseSuccess = createAction('REMOVE_STATIC_LEASE_SUCCESS');
|
||||
|
||||
export const removeStaticLease = (config: any) => async (dispatch: any) => {
|
||||
export const removeStaticLease = (config) => async (dispatch) => {
|
||||
dispatch(removeStaticLeaseRequest());
|
||||
try {
|
||||
const name = config.hostname || config.ip;
|
||||
@@ -703,7 +703,7 @@ export const updateStaticLeaseRequest = createAction('UPDATE_STATIC_LEASE_REQUES
|
||||
export const updateStaticLeaseFailure = createAction('UPDATE_STATIC_LEASE_FAILURE');
|
||||
export const updateStaticLeaseSuccess = createAction('UPDATE_STATIC_LEASE_SUCCESS');
|
||||
|
||||
export const updateStaticLease = (config: any) => async (dispatch: any) => {
|
||||
export const updateStaticLease = (config) => async (dispatch) => {
|
||||
dispatch(updateStaticLeaseRequest());
|
||||
try {
|
||||
await apiClient.updateStaticLease(config);
|
||||
@@ -719,42 +719,42 @@ export const updateStaticLease = (config: any) => async (dispatch: any) => {
|
||||
|
||||
export const removeToast = createAction('REMOVE_TOAST');
|
||||
|
||||
export const toggleBlocking =
|
||||
(type: any, domain: any, baseRule?: string, baseUnblocking?: string) => async (dispatch: any, getState: any) => {
|
||||
const baseBlockingRule = baseRule || `||${domain}^$important`;
|
||||
const baseUnblockingRule = baseUnblocking || `@@${baseBlockingRule}`;
|
||||
const { userRules } = getState().filtering;
|
||||
export const toggleBlocking = (
|
||||
type, domain, baseRule, baseUnblocking,
|
||||
) => async (dispatch, getState) => {
|
||||
const baseBlockingRule = baseRule || `||${domain}^$important`;
|
||||
const baseUnblockingRule = baseUnblocking || `@@${baseBlockingRule}`;
|
||||
const { userRules } = getState().filtering;
|
||||
|
||||
const lineEnding = !endsWith(userRules, '\n') ? '\n' : '';
|
||||
const lineEnding = !endsWith(userRules, '\n') ? '\n' : '';
|
||||
|
||||
const blockingRule = type === BLOCK_ACTIONS.BLOCK ? baseUnblockingRule : baseBlockingRule;
|
||||
const unblockingRule = type === BLOCK_ACTIONS.BLOCK ? baseBlockingRule : baseUnblockingRule;
|
||||
const preparedBlockingRule = new RegExp(`(^|\n)${escapeRegExp(blockingRule)}($|\n)`);
|
||||
const preparedUnblockingRule = new RegExp(`(^|\n)${escapeRegExp(unblockingRule)}($|\n)`);
|
||||
const blockingRule = type === BLOCK_ACTIONS.BLOCK ? baseUnblockingRule : baseBlockingRule;
|
||||
const unblockingRule = type === BLOCK_ACTIONS.BLOCK ? baseBlockingRule : baseUnblockingRule;
|
||||
const preparedBlockingRule = new RegExp(`(^|\n)${escapeRegExp(blockingRule)}($|\n)`);
|
||||
const preparedUnblockingRule = new RegExp(`(^|\n)${escapeRegExp(unblockingRule)}($|\n)`);
|
||||
|
||||
const matchPreparedBlockingRule = userRules.match(preparedBlockingRule);
|
||||
const matchPreparedUnblockingRule = userRules.match(preparedUnblockingRule);
|
||||
const matchPreparedBlockingRule = userRules.match(preparedBlockingRule);
|
||||
const matchPreparedUnblockingRule = userRules.match(preparedUnblockingRule);
|
||||
|
||||
if (matchPreparedBlockingRule) {
|
||||
await dispatch(setRules(userRules.replace(`${blockingRule}`, '')));
|
||||
dispatch(addSuccessToast(i18next.t('rule_removed_from_custom_filtering_toast', { rule: blockingRule })));
|
||||
} else if (!matchPreparedUnblockingRule) {
|
||||
await dispatch(setRules(`${userRules}${lineEnding}${unblockingRule}\n`));
|
||||
dispatch(addSuccessToast(i18next.t('rule_added_to_custom_filtering_toast', { rule: unblockingRule })));
|
||||
} else if (matchPreparedUnblockingRule) {
|
||||
dispatch(addSuccessToast(i18next.t('rule_added_to_custom_filtering_toast', { rule: unblockingRule })));
|
||||
return;
|
||||
} else if (!matchPreparedBlockingRule) {
|
||||
dispatch(addSuccessToast(i18next.t('rule_removed_from_custom_filtering_toast', { rule: blockingRule })));
|
||||
return;
|
||||
}
|
||||
if (matchPreparedBlockingRule) {
|
||||
await dispatch(setRules(userRules.replace(`${blockingRule}`, '')));
|
||||
dispatch(addSuccessToast(i18next.t('rule_removed_from_custom_filtering_toast', { rule: blockingRule })));
|
||||
} else if (!matchPreparedUnblockingRule) {
|
||||
await dispatch(setRules(`${userRules}${lineEnding}${unblockingRule}\n`));
|
||||
dispatch(addSuccessToast(i18next.t('rule_added_to_custom_filtering_toast', { rule: unblockingRule })));
|
||||
} else if (matchPreparedUnblockingRule) {
|
||||
dispatch(addSuccessToast(i18next.t('rule_added_to_custom_filtering_toast', { rule: unblockingRule })));
|
||||
return;
|
||||
} else if (!matchPreparedBlockingRule) {
|
||||
dispatch(addSuccessToast(i18next.t('rule_removed_from_custom_filtering_toast', { rule: blockingRule })));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(getFilteringStatus());
|
||||
};
|
||||
dispatch(getFilteringStatus());
|
||||
};
|
||||
|
||||
export const toggleBlockingForClient = (type: any, domain: any, client: any) => {
|
||||
const escapedClientName = client
|
||||
.replace(/'/g, "\\'")
|
||||
export const toggleBlockingForClient = (type, domain, client) => {
|
||||
const escapedClientName = client.replace(/'/g, '\\\'')
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/,/g, '\\,')
|
||||
.replace(/\|/g, '\\|');
|
||||
@@ -9,7 +9,7 @@ export const getDefaultAddressesRequest = createAction('GET_DEFAULT_ADDRESSES_RE
|
||||
export const getDefaultAddressesFailure = createAction('GET_DEFAULT_ADDRESSES_FAILURE');
|
||||
export const getDefaultAddressesSuccess = createAction('GET_DEFAULT_ADDRESSES_SUCCESS');
|
||||
|
||||
export const getDefaultAddresses = () => async (dispatch: any) => {
|
||||
export const getDefaultAddresses = () => async (dispatch) => {
|
||||
dispatch(getDefaultAddressesRequest());
|
||||
try {
|
||||
const addresses = await apiClient.getDefaultAddresses();
|
||||
@@ -24,10 +24,13 @@ export const setAllSettingsRequest = createAction('SET_ALL_SETTINGS_REQUEST');
|
||||
export const setAllSettingsFailure = createAction('SET_ALL_SETTINGS_FAILURE');
|
||||
export const setAllSettingsSuccess = createAction('SET_ALL_SETTINGS_SUCCESS');
|
||||
|
||||
export const setAllSettings = (values: any) => async (dispatch: any) => {
|
||||
export const setAllSettings = (values) => async (dispatch) => {
|
||||
dispatch(setAllSettingsRequest());
|
||||
try {
|
||||
const { confirm_password, ...config } = values;
|
||||
const {
|
||||
confirm_password,
|
||||
...config
|
||||
} = values;
|
||||
|
||||
await apiClient.setAllSettings(config);
|
||||
dispatch(setAllSettingsSuccess());
|
||||
@@ -44,7 +47,7 @@ export const checkConfigRequest = createAction('CHECK_CONFIG_REQUEST');
|
||||
export const checkConfigFailure = createAction('CHECK_CONFIG_FAILURE');
|
||||
export const checkConfigSuccess = createAction('CHECK_CONFIG_SUCCESS');
|
||||
|
||||
export const checkConfig = (values: any) => async (dispatch: any) => {
|
||||
export const checkConfig = (values) => async (dispatch) => {
|
||||
dispatch(checkConfigRequest());
|
||||
try {
|
||||
const check = await apiClient.checkConfig(values);
|
||||
@@ -8,12 +8,12 @@ export const processLoginRequest = createAction('PROCESS_LOGIN_REQUEST');
|
||||
export const processLoginFailure = createAction('PROCESS_LOGIN_FAILURE');
|
||||
export const processLoginSuccess = createAction('PROCESS_LOGIN_SUCCESS');
|
||||
|
||||
export const processLogin = (values: any) => async (dispatch: any) => {
|
||||
export const processLogin = (values) => async (dispatch) => {
|
||||
dispatch(processLoginRequest());
|
||||
try {
|
||||
await apiClient.login(values);
|
||||
const dashboardUrl =
|
||||
window.location.origin + window.location.pathname.replace(HTML_PAGES.LOGIN, HTML_PAGES.MAIN);
|
||||
const dashboardUrl = window.location.origin
|
||||
+ window.location.pathname.replace(HTML_PAGES.LOGIN, HTML_PAGES.MAIN);
|
||||
window.location.replace(dashboardUrl);
|
||||
dispatch(processLoginSuccess());
|
||||
} catch (error) {
|
||||
@@ -1,12 +1,13 @@
|
||||
import { createAction } from 'redux-actions';
|
||||
|
||||
import apiClient from '../api/Api';
|
||||
|
||||
import { normalizeLogs } from '../helpers/helpers';
|
||||
import { DEFAULT_LOGS_FILTER, FORM_NAME, QUERY_LOGS_PAGE_LIMIT } from '../helpers/constants';
|
||||
import {
|
||||
DEFAULT_LOGS_FILTER, FORM_NAME, QUERY_LOGS_PAGE_LIMIT,
|
||||
} from '../helpers/constants';
|
||||
import { addErrorToast, addSuccessToast } from './toasts';
|
||||
|
||||
const getLogsWithParams = async (config: any) => {
|
||||
const getLogsWithParams = async (config) => {
|
||||
const { older_than, filter, ...values } = config;
|
||||
const rawLogs = await apiClient.getQueryLog({
|
||||
...filter,
|
||||
@@ -27,20 +28,20 @@ export const getAdditionalLogsRequest = createAction('GET_ADDITIONAL_LOGS_REQUES
|
||||
export const getAdditionalLogsFailure = createAction('GET_ADDITIONAL_LOGS_FAILURE');
|
||||
export const getAdditionalLogsSuccess = createAction('GET_ADDITIONAL_LOGS_SUCCESS');
|
||||
|
||||
const shortPollQueryLogs = async (data: any, filter: any, dispatch: any, getState: any, total?: any) => {
|
||||
const shortPollQueryLogs = async (data, filter, dispatch, getState, total) => {
|
||||
const { logs, oldest } = data;
|
||||
const totalData = total || { logs };
|
||||
|
||||
const queryForm = getState().form[FORM_NAME.LOGS_FILTER];
|
||||
const currentQuery = queryForm && queryForm.values.search;
|
||||
const previousQuery = filter?.search;
|
||||
const isQueryTheSame =
|
||||
typeof previousQuery === 'string' && typeof currentQuery === 'string' && previousQuery === currentQuery;
|
||||
const isQueryTheSame = typeof previousQuery === 'string'
|
||||
&& typeof currentQuery === 'string'
|
||||
&& previousQuery === currentQuery;
|
||||
|
||||
const isShortPollingNeeded =
|
||||
(logs.length < QUERY_LOGS_PAGE_LIMIT || totalData.logs.length < QUERY_LOGS_PAGE_LIMIT) &&
|
||||
oldest !== '' &&
|
||||
isQueryTheSame;
|
||||
const isShortPollingNeeded = (logs.length < QUERY_LOGS_PAGE_LIMIT
|
||||
|| totalData.logs.length < QUERY_LOGS_PAGE_LIMIT)
|
||||
&& oldest !== '' && isQueryTheSame;
|
||||
|
||||
if (isShortPollingNeeded) {
|
||||
dispatch(getAdditionalLogsRequest());
|
||||
@@ -74,24 +75,22 @@ export const getLogsRequest = createAction('GET_LOGS_REQUEST');
|
||||
export const getLogsFailure = createAction('GET_LOGS_FAILURE');
|
||||
export const getLogsSuccess = createAction('GET_LOGS_SUCCESS');
|
||||
|
||||
export const updateLogs = () => async (dispatch: any, getState: any) => {
|
||||
export const updateLogs = () => async (dispatch, getState) => {
|
||||
try {
|
||||
const { logs, oldest, older_than } = getState().queryLogs;
|
||||
|
||||
dispatch(
|
||||
getLogsSuccess({
|
||||
logs,
|
||||
oldest,
|
||||
older_than,
|
||||
}),
|
||||
);
|
||||
dispatch(getLogsSuccess({
|
||||
logs,
|
||||
oldest,
|
||||
older_than,
|
||||
}));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(getLogsFailure(error));
|
||||
}
|
||||
};
|
||||
|
||||
export const getLogs = () => async (dispatch: any, getState: any) => {
|
||||
export const getLogs = () => async (dispatch, getState) => {
|
||||
dispatch(getLogsRequest());
|
||||
try {
|
||||
const { isFiltered, filter, oldest } = getState().queryLogs;
|
||||
@@ -122,29 +121,26 @@ export const setLogsFilterRequest = createAction('SET_LOGS_FILTER_REQUEST');
|
||||
* @param {string} filter.response_status 'QUERY' field of RESPONSE_FILTER object
|
||||
* @returns function
|
||||
*/
|
||||
export const setLogsFilter = (filter: any) => setLogsFilterRequest(filter);
|
||||
export const setLogsFilter = (filter) => setLogsFilterRequest(filter);
|
||||
|
||||
export const setFilteredLogsRequest = createAction('SET_FILTERED_LOGS_REQUEST');
|
||||
export const setFilteredLogsFailure = createAction('SET_FILTERED_LOGS_FAILURE');
|
||||
export const setFilteredLogsSuccess = createAction('SET_FILTERED_LOGS_SUCCESS');
|
||||
|
||||
export const setFilteredLogs = (filter?: any) => async (dispatch: any, getState: any) => {
|
||||
export const setFilteredLogs = (filter) => async (dispatch, getState) => {
|
||||
dispatch(setFilteredLogsRequest());
|
||||
try {
|
||||
const data = await getLogsWithParams({
|
||||
older_than: '',
|
||||
filter,
|
||||
});
|
||||
|
||||
const additionalData = await shortPollQueryLogs(data, filter, dispatch, getState);
|
||||
const updatedData = additionalData.logs ? { ...data, ...additionalData } : data;
|
||||
|
||||
dispatch(
|
||||
setFilteredLogsSuccess({
|
||||
...updatedData,
|
||||
filter,
|
||||
}),
|
||||
);
|
||||
dispatch(setFilteredLogsSuccess({
|
||||
...updatedData,
|
||||
filter,
|
||||
}));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(setFilteredLogsFailure(error));
|
||||
@@ -153,7 +149,7 @@ export const setFilteredLogs = (filter?: any) => async (dispatch: any, getState:
|
||||
|
||||
export const resetFilteredLogs = () => setFilteredLogs(DEFAULT_LOGS_FILTER);
|
||||
|
||||
export const refreshFilteredLogs = () => async (dispatch: any, getState: any) => {
|
||||
export const refreshFilteredLogs = () => async (dispatch, getState) => {
|
||||
const { filter } = getState().queryLogs;
|
||||
await dispatch(setFilteredLogs(filter));
|
||||
};
|
||||
@@ -162,7 +158,7 @@ export const clearLogsRequest = createAction('CLEAR_LOGS_REQUEST');
|
||||
export const clearLogsFailure = createAction('CLEAR_LOGS_FAILURE');
|
||||
export const clearLogsSuccess = createAction('CLEAR_LOGS_SUCCESS');
|
||||
|
||||
export const clearLogs = () => async (dispatch: any) => {
|
||||
export const clearLogs = () => async (dispatch) => {
|
||||
dispatch(clearLogsRequest());
|
||||
try {
|
||||
await apiClient.clearQueryLog();
|
||||
@@ -178,7 +174,7 @@ export const getLogsConfigRequest = createAction('GET_LOGS_CONFIG_REQUEST');
|
||||
export const getLogsConfigFailure = createAction('GET_LOGS_CONFIG_FAILURE');
|
||||
export const getLogsConfigSuccess = createAction('GET_LOGS_CONFIG_SUCCESS');
|
||||
|
||||
export const getLogsConfig = () => async (dispatch: any) => {
|
||||
export const getLogsConfig = () => async (dispatch) => {
|
||||
dispatch(getLogsConfigRequest());
|
||||
try {
|
||||
const data = await apiClient.getQueryLogConfig();
|
||||
@@ -193,7 +189,7 @@ export const setLogsConfigRequest = createAction('SET_LOGS_CONFIG_REQUEST');
|
||||
export const setLogsConfigFailure = createAction('SET_LOGS_CONFIG_FAILURE');
|
||||
export const setLogsConfigSuccess = createAction('SET_LOGS_CONFIG_SUCCESS');
|
||||
|
||||
export const setLogsConfig = (config: any) => async (dispatch: any) => {
|
||||
export const setLogsConfig = (config) => async (dispatch) => {
|
||||
dispatch(setLogsConfigRequest());
|
||||
try {
|
||||
await apiClient.setQueryLogConfig(config);
|
||||
@@ -9,7 +9,7 @@ export const getRewritesListRequest = createAction('GET_REWRITES_LIST_REQUEST');
|
||||
export const getRewritesListFailure = createAction('GET_REWRITES_LIST_FAILURE');
|
||||
export const getRewritesListSuccess = createAction('GET_REWRITES_LIST_SUCCESS');
|
||||
|
||||
export const getRewritesList = () => async (dispatch: any) => {
|
||||
export const getRewritesList = () => async (dispatch) => {
|
||||
dispatch(getRewritesListRequest());
|
||||
try {
|
||||
const data = await apiClient.getRewritesList();
|
||||
@@ -24,7 +24,7 @@ export const addRewriteRequest = createAction('ADD_REWRITE_REQUEST');
|
||||
export const addRewriteFailure = createAction('ADD_REWRITE_FAILURE');
|
||||
export const addRewriteSuccess = createAction('ADD_REWRITE_SUCCESS');
|
||||
|
||||
export const addRewrite = (config: any) => async (dispatch: any) => {
|
||||
export const addRewrite = (config) => async (dispatch) => {
|
||||
dispatch(addRewriteRequest());
|
||||
try {
|
||||
await apiClient.addRewrite(config);
|
||||
@@ -47,7 +47,7 @@ export const updateRewriteSuccess = createAction('UPDATE_REWRITE_SUCCESS');
|
||||
* @param {string} config.target - current DNS rewrite value
|
||||
* @param {string} config.update - updated DNS rewrite value
|
||||
*/
|
||||
export const updateRewrite = (config: any) => async (dispatch: any) => {
|
||||
export const updateRewrite = (config) => async (dispatch) => {
|
||||
dispatch(updateRewriteRequest());
|
||||
try {
|
||||
await apiClient.updateRewrite(config);
|
||||
@@ -65,7 +65,7 @@ export const deleteRewriteRequest = createAction('DELETE_REWRITE_REQUEST');
|
||||
export const deleteRewriteFailure = createAction('DELETE_REWRITE_FAILURE');
|
||||
export const deleteRewriteSuccess = createAction('DELETE_REWRITE_SUCCESS');
|
||||
|
||||
export const deleteRewrite = (config: any) => async (dispatch: any) => {
|
||||
export const deleteRewrite = (config) => async (dispatch) => {
|
||||
dispatch(deleteRewriteRequest());
|
||||
try {
|
||||
await apiClient.deleteRewrite(config);
|
||||
@@ -6,7 +6,7 @@ export const getBlockedServicesRequest = createAction('GET_BLOCKED_SERVICES_REQU
|
||||
export const getBlockedServicesFailure = createAction('GET_BLOCKED_SERVICES_FAILURE');
|
||||
export const getBlockedServicesSuccess = createAction('GET_BLOCKED_SERVICES_SUCCESS');
|
||||
|
||||
export const getBlockedServices = () => async (dispatch: any) => {
|
||||
export const getBlockedServices = () => async (dispatch) => {
|
||||
dispatch(getBlockedServicesRequest());
|
||||
try {
|
||||
const data = await apiClient.getBlockedServices();
|
||||
@@ -21,7 +21,7 @@ export const getAllBlockedServicesRequest = createAction('GET_ALL_BLOCKED_SERVIC
|
||||
export const getAllBlockedServicesFailure = createAction('GET_ALL_BLOCKED_SERVICES_FAILURE');
|
||||
export const getAllBlockedServicesSuccess = createAction('GET_ALL_BLOCKED_SERVICES_SUCCESS');
|
||||
|
||||
export const getAllBlockedServices = () => async (dispatch: any) => {
|
||||
export const getAllBlockedServices = () => async (dispatch) => {
|
||||
dispatch(getAllBlockedServicesRequest());
|
||||
try {
|
||||
const data = await apiClient.getAllBlockedServices();
|
||||
@@ -36,7 +36,7 @@ export const updateBlockedServicesRequest = createAction('UPDATE_BLOCKED_SERVICE
|
||||
export const updateBlockedServicesFailure = createAction('UPDATE_BLOCKED_SERVICES_FAILURE');
|
||||
export const updateBlockedServicesSuccess = createAction('UPDATE_BLOCKED_SERVICES_SUCCESS');
|
||||
|
||||
export const updateBlockedServices = (values: any) => async (dispatch: any) => {
|
||||
export const updateBlockedServices = (values) => async (dispatch) => {
|
||||
dispatch(updateBlockedServicesRequest());
|
||||
try {
|
||||
await apiClient.updateBlockedServices(values);
|
||||
@@ -1,14 +1,16 @@
|
||||
import { createAction } from 'redux-actions';
|
||||
|
||||
import apiClient from '../api/Api';
|
||||
import { normalizeTopStats, secondsToMilliseconds, getParamsForClientsSearch, addClientInfo } from '../helpers/helpers';
|
||||
import {
|
||||
normalizeTopStats, secondsToMilliseconds, getParamsForClientsSearch, addClientInfo,
|
||||
} from '../helpers/helpers';
|
||||
import { addErrorToast, addSuccessToast } from './toasts';
|
||||
|
||||
export const getStatsConfigRequest = createAction('GET_STATS_CONFIG_REQUEST');
|
||||
export const getStatsConfigFailure = createAction('GET_STATS_CONFIG_FAILURE');
|
||||
export const getStatsConfigSuccess = createAction('GET_STATS_CONFIG_SUCCESS');
|
||||
|
||||
export const getStatsConfig = () => async (dispatch: any) => {
|
||||
export const getStatsConfig = () => async (dispatch) => {
|
||||
dispatch(getStatsConfigRequest());
|
||||
try {
|
||||
const data = await apiClient.getStatsConfig();
|
||||
@@ -23,7 +25,7 @@ export const setStatsConfigRequest = createAction('SET_STATS_CONFIG_REQUEST');
|
||||
export const setStatsConfigFailure = createAction('SET_STATS_CONFIG_FAILURE');
|
||||
export const setStatsConfigSuccess = createAction('SET_STATS_CONFIG_SUCCESS');
|
||||
|
||||
export const setStatsConfig = (config: any) => async (dispatch: any) => {
|
||||
export const setStatsConfig = (config) => async (dispatch) => {
|
||||
dispatch(setStatsConfigRequest());
|
||||
try {
|
||||
await apiClient.setStatsConfig(config);
|
||||
@@ -39,14 +41,13 @@ export const getStatsRequest = createAction('GET_STATS_REQUEST');
|
||||
export const getStatsFailure = createAction('GET_STATS_FAILURE');
|
||||
export const getStatsSuccess = createAction('GET_STATS_SUCCESS');
|
||||
|
||||
export const getStats = () => async (dispatch: any) => {
|
||||
export const getStats = () => async (dispatch) => {
|
||||
dispatch(getStatsRequest());
|
||||
try {
|
||||
const stats = await apiClient.getStats();
|
||||
const normalizedTopClients = normalizeTopStats(stats.top_clients);
|
||||
|
||||
const clientsParams = getParamsForClientsSearch(normalizedTopClients, 'name');
|
||||
const clients = await apiClient.searchClients(clientsParams);
|
||||
const clients = await apiClient.findClients(clientsParams);
|
||||
const topClientsWithInfo = addClientInfo(normalizedTopClients, clients, 'name');
|
||||
|
||||
const normalizedStats = {
|
||||
@@ -70,7 +71,7 @@ export const resetStatsRequest = createAction('RESET_STATS_REQUEST');
|
||||
export const resetStatsFailure = createAction('RESET_STATS_FAILURE');
|
||||
export const resetStatsSuccess = createAction('RESET_STATS_SUCCESS');
|
||||
|
||||
export const resetStats = () => async (dispatch: any) => {
|
||||
export const resetStats = () => async (dispatch) => {
|
||||
dispatch(getStatsRequest());
|
||||
try {
|
||||
await apiClient.resetStats();
|
||||
@@ -1,16 +1,17 @@
|
||||
import axios from 'axios';
|
||||
|
||||
import { BASE_URL } from '../../constants';
|
||||
|
||||
import { getPathWithQueryString } from '../helpers/helpers';
|
||||
import { QUERY_LOGS_PAGE_LIMIT, HTML_PAGES, R_PATH_LAST_PART, THEMES } from '../helpers/constants';
|
||||
import {
|
||||
QUERY_LOGS_PAGE_LIMIT, HTML_PAGES, R_PATH_LAST_PART, THEMES,
|
||||
} from '../helpers/constants';
|
||||
import { BASE_URL } from '../../constants';
|
||||
import i18n from '../i18n';
|
||||
import { LANGUAGES } from '../helpers/twosky';
|
||||
|
||||
class Api {
|
||||
baseUrl = BASE_URL;
|
||||
|
||||
async makeRequest(path: any, method = 'POST', config: any = {}) {
|
||||
async makeRequest(path, method = 'POST', config) {
|
||||
const url = `${this.baseUrl}/${path}`;
|
||||
|
||||
const axiosConfig = config || {};
|
||||
@@ -28,26 +29,26 @@ class Api {
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
const errorPath = url;
|
||||
|
||||
if (error.response) {
|
||||
const { pathname } = document.location;
|
||||
const shouldRedirect = pathname !== HTML_PAGES.LOGIN && pathname !== HTML_PAGES.INSTALL;
|
||||
const shouldRedirect = pathname !== HTML_PAGES.LOGIN
|
||||
&& pathname !== HTML_PAGES.INSTALL;
|
||||
|
||||
if (error.response.status === 403 && shouldRedirect) {
|
||||
const loginPageUrl = window.location.href.replace(R_PATH_LAST_PART, HTML_PAGES.LOGIN);
|
||||
const loginPageUrl = window.location.href
|
||||
.replace(R_PATH_LAST_PART, HTML_PAGES.LOGIN);
|
||||
window.location.replace(loginPageUrl);
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new Error(`${errorPath} | ${error.response.data} | ${error.response.status}`);
|
||||
}
|
||||
|
||||
throw new Error(`${errorPath} | ${error.message || error}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Global methods
|
||||
GLOBAL_STATUS = { path: 'status', method: 'GET' };
|
||||
GLOBAL_STATUS = { path: 'status', method: 'GET' }
|
||||
|
||||
GLOBAL_TEST_UPSTREAM_DNS = { path: 'test_upstream_dns', method: 'POST' };
|
||||
|
||||
@@ -57,11 +58,10 @@ class Api {
|
||||
|
||||
getGlobalStatus() {
|
||||
const { path, method } = this.GLOBAL_STATUS;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
testUpstream(servers: any) {
|
||||
testUpstream(servers) {
|
||||
const { path, method } = this.GLOBAL_TEST_UPSTREAM_DNS;
|
||||
const config = {
|
||||
data: servers,
|
||||
@@ -69,7 +69,7 @@ class Api {
|
||||
return this.makeRequest(path, method, config);
|
||||
}
|
||||
|
||||
getGlobalVersion(data: any) {
|
||||
getGlobalVersion(data) {
|
||||
const { path, method } = this.GLOBAL_VERSION;
|
||||
const config = {
|
||||
data,
|
||||
@@ -79,7 +79,6 @@ class Api {
|
||||
|
||||
getUpdate() {
|
||||
const { path, method } = this.GLOBAL_UPDATE;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
@@ -102,11 +101,10 @@ class Api {
|
||||
|
||||
getFilteringStatus() {
|
||||
const { path, method } = this.FILTERING_STATUS;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
refreshFilters(config: any) {
|
||||
refreshFilters(config) {
|
||||
const { path, method } = this.FILTERING_REFRESH;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -115,7 +113,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
addFilter(config: any) {
|
||||
addFilter(config) {
|
||||
const { path, method } = this.FILTERING_ADD_FILTER;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -124,7 +122,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
removeFilter(config: any) {
|
||||
removeFilter(config) {
|
||||
const { path, method } = this.FILTERING_REMOVE_FILTER;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -133,7 +131,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
setRules(rules: any) {
|
||||
setRules(rules) {
|
||||
const { path, method } = this.FILTERING_SET_RULES;
|
||||
const parameters = {
|
||||
data: rules,
|
||||
@@ -141,7 +139,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
setFiltersConfig(config: any) {
|
||||
setFiltersConfig(config) {
|
||||
const { path, method } = this.FILTERING_CONFIG;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -149,7 +147,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
setFilterUrl(config: any) {
|
||||
setFilterUrl(config) {
|
||||
const { path, method } = this.FILTERING_SET_URL;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -157,10 +155,9 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
checkHost(params: any) {
|
||||
checkHost(params) {
|
||||
const { path, method } = this.FILTERING_CHECK_HOST;
|
||||
const url = getPathWithQueryString(path, params);
|
||||
|
||||
return this.makeRequest(url, method);
|
||||
}
|
||||
|
||||
@@ -173,19 +170,16 @@ class Api {
|
||||
|
||||
getParentalStatus() {
|
||||
const { path, method } = this.PARENTAL_STATUS;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
enableParentalControl() {
|
||||
const { path, method } = this.PARENTAL_ENABLE;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
disableParentalControl() {
|
||||
const { path, method } = this.PARENTAL_DISABLE;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
@@ -198,19 +192,16 @@ class Api {
|
||||
|
||||
getSafebrowsingStatus() {
|
||||
const { path, method } = this.SAFEBROWSING_STATUS;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
enableSafebrowsing() {
|
||||
const { path, method } = this.SAFEBROWSING_ENABLE;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
disableSafebrowsing() {
|
||||
const { path, method } = this.SAFEBROWSING_DISABLE;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
@@ -221,7 +212,6 @@ class Api {
|
||||
|
||||
getSafesearchStatus() {
|
||||
const { path, method } = this.SAFESEARCH_STATUS;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
@@ -238,7 +228,7 @@ class Api {
|
||||
* @param {*} data - SafeSearchConfig
|
||||
* @returns 200 ok
|
||||
*/
|
||||
updateSafesearch(data: any) {
|
||||
updateSafesearch(data) {
|
||||
const { path, method } = this.SAFESEARCH_UPDATE;
|
||||
return this.makeRequest(path, method, { data });
|
||||
}
|
||||
@@ -255,7 +245,7 @@ class Api {
|
||||
|
||||
// Language
|
||||
|
||||
async changeLanguage(config: any) {
|
||||
async changeLanguage(config) {
|
||||
const profile = await this.getProfile();
|
||||
profile.language = config.language;
|
||||
|
||||
@@ -264,7 +254,7 @@ class Api {
|
||||
|
||||
// Theme
|
||||
|
||||
async changeTheme(config: any) {
|
||||
async changeTheme(config) {
|
||||
const profile = await this.getProfile();
|
||||
profile.theme = config.theme;
|
||||
|
||||
@@ -292,17 +282,15 @@ class Api {
|
||||
|
||||
getDhcpStatus() {
|
||||
const { path, method } = this.DHCP_STATUS;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
getDhcpInterfaces() {
|
||||
const { path, method } = this.DHCP_INTERFACES;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setDhcpConfig(config: any) {
|
||||
setDhcpConfig(config) {
|
||||
const { path, method } = this.DHCP_SET_CONFIG;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -310,7 +298,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
findActiveDhcp(req: any) {
|
||||
findActiveDhcp(req) {
|
||||
const { path, method } = this.DHCP_FIND_ACTIVE;
|
||||
const parameters = {
|
||||
data: req,
|
||||
@@ -318,7 +306,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
addStaticLease(config: any) {
|
||||
addStaticLease(config) {
|
||||
const { path, method } = this.DHCP_ADD_STATIC_LEASE;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -326,7 +314,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
removeStaticLease(config: any) {
|
||||
removeStaticLease(config) {
|
||||
const { path, method } = this.DHCP_REMOVE_STATIC_LEASE;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -334,7 +322,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
updateStaticLease(config: any) {
|
||||
updateStaticLease(config) {
|
||||
const { path, method } = this.DHCP_UPDATE_STATIC_LEASE;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -344,13 +332,11 @@ class Api {
|
||||
|
||||
resetDhcp() {
|
||||
const { path, method } = this.DHCP_RESET;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
resetDhcpLeases() {
|
||||
const { path, method } = this.DHCP_LEASES_RESET;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
@@ -363,11 +349,10 @@ class Api {
|
||||
|
||||
getDefaultAddresses() {
|
||||
const { path, method } = this.INSTALL_GET_ADDRESSES;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setAllSettings(config: any) {
|
||||
setAllSettings(config) {
|
||||
const { path, method } = this.INSTALL_CONFIGURE;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -375,7 +360,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
checkConfig(config: any) {
|
||||
checkConfig(config) {
|
||||
const { path, method } = this.INSTALL_CHECK_CONFIG;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -392,11 +377,10 @@ class Api {
|
||||
|
||||
getTlsStatus() {
|
||||
const { path, method } = this.TLS_STATUS;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setTlsConfig(config: any) {
|
||||
setTlsConfig(config) {
|
||||
const { path, method } = this.TLS_CONFIG;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -404,7 +388,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
validateTlsConfig(config: any) {
|
||||
validateTlsConfig(config) {
|
||||
const { path, method } = this.TLS_VALIDATE;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -415,7 +399,7 @@ class Api {
|
||||
// Per-client settings
|
||||
GET_CLIENTS = { path: 'clients', method: 'GET' };
|
||||
|
||||
SEARCH_CLIENTS = { path: 'clients/search', method: 'POST' };
|
||||
FIND_CLIENTS = { path: 'clients/find', method: 'GET' };
|
||||
|
||||
ADD_CLIENT = { path: 'clients/add', method: 'POST' };
|
||||
|
||||
@@ -425,11 +409,10 @@ class Api {
|
||||
|
||||
getClients() {
|
||||
const { path, method } = this.GET_CLIENTS;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
addClient(config: any) {
|
||||
addClient(config) {
|
||||
const { path, method } = this.ADD_CLIENT;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -437,7 +420,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
deleteClient(config: any) {
|
||||
deleteClient(config) {
|
||||
const { path, method } = this.DELETE_CLIENT;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -445,7 +428,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
updateClient(config: any) {
|
||||
updateClient(config) {
|
||||
const { path, method } = this.UPDATE_CLIENT;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -453,12 +436,10 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
searchClients(config: any) {
|
||||
const { path, method } = this.SEARCH_CLIENTS;
|
||||
const parameters = {
|
||||
data: config,
|
||||
};
|
||||
return this.makeRequest(path, method, parameters);
|
||||
findClients(params) {
|
||||
const { path, method } = this.FIND_CLIENTS;
|
||||
const url = getPathWithQueryString(path, params);
|
||||
return this.makeRequest(url, method);
|
||||
}
|
||||
|
||||
// DNS access settings
|
||||
@@ -468,11 +449,10 @@ class Api {
|
||||
|
||||
getAccessList() {
|
||||
const { path, method } = this.ACCESS_LIST;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setAccessList(config: any) {
|
||||
setAccessList(config) {
|
||||
const { path, method } = this.ACCESS_SET;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -491,11 +471,10 @@ class Api {
|
||||
|
||||
getRewritesList() {
|
||||
const { path, method } = this.REWRITES_LIST;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
addRewrite(config: any) {
|
||||
addRewrite(config) {
|
||||
const { path, method } = this.REWRITE_ADD;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -503,7 +482,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
updateRewrite(config: any) {
|
||||
updateRewrite(config) {
|
||||
const { path, method } = this.REWRITE_UPDATE;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -511,7 +490,7 @@ class Api {
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
deleteRewrite(config: any) {
|
||||
deleteRewrite(config) {
|
||||
const { path, method } = this.REWRITE_DELETE;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -528,17 +507,15 @@ class Api {
|
||||
|
||||
getAllBlockedServices() {
|
||||
const { path, method } = this.BLOCKED_SERVICES_ALL;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
getBlockedServices() {
|
||||
const { path, method } = this.BLOCKED_SERVICES_GET;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
updateBlockedServices(config: any) {
|
||||
updateBlockedServices(config) {
|
||||
const { path, method } = this.BLOCKED_SERVICES_UPDATE;
|
||||
const parameters = {
|
||||
data: config,
|
||||
@@ -557,17 +534,15 @@ class Api {
|
||||
|
||||
getStats() {
|
||||
const { path, method } = this.GET_STATS;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
getStatsConfig() {
|
||||
const { path, method } = this.GET_STATS_CONFIG;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setStatsConfig(data: any) {
|
||||
setStatsConfig(data) {
|
||||
const { path, method } = this.UPDATE_STATS_CONFIG;
|
||||
const config = {
|
||||
data,
|
||||
@@ -577,7 +552,6 @@ class Api {
|
||||
|
||||
resetStats() {
|
||||
const { path, method } = this.STATS_RESET;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
@@ -590,22 +564,20 @@ class Api {
|
||||
|
||||
QUERY_LOG_CLEAR = { path: 'querylog_clear', method: 'POST' };
|
||||
|
||||
getQueryLog(params: any) {
|
||||
getQueryLog(params) {
|
||||
const { path, method } = this.GET_QUERY_LOG;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
params.limit = QUERY_LOGS_PAGE_LIMIT;
|
||||
const url = getPathWithQueryString(path, params);
|
||||
|
||||
return this.makeRequest(url, method);
|
||||
}
|
||||
|
||||
getQueryLogConfig() {
|
||||
const { path, method } = this.GET_QUERY_LOG_CONFIG;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setQueryLogConfig(data: any) {
|
||||
setQueryLogConfig(data) {
|
||||
const { path, method } = this.UPDATE_QUERY_LOG_CONFIG;
|
||||
const config = {
|
||||
data,
|
||||
@@ -615,14 +587,13 @@ class Api {
|
||||
|
||||
clearQueryLog() {
|
||||
const { path, method } = this.QUERY_LOG_CLEAR;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
// Login
|
||||
LOGIN = { path: 'login', method: 'POST' };
|
||||
|
||||
login(data: any) {
|
||||
login(data) {
|
||||
const { path, method } = this.LOGIN;
|
||||
const config = {
|
||||
data,
|
||||
@@ -637,11 +608,10 @@ class Api {
|
||||
|
||||
getProfile() {
|
||||
const { path, method } = this.GET_PROFILE;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setProfile(data: any) {
|
||||
setProfile(data) {
|
||||
const theme = data.theme ? data.theme : THEMES.auto;
|
||||
const defaultLanguage = i18n.language ? i18n.language : LANGUAGES.en;
|
||||
const language = data.language ? data.language : defaultLanguage;
|
||||
@@ -659,11 +629,10 @@ class Api {
|
||||
|
||||
getDnsConfig() {
|
||||
const { path, method } = this.GET_DNS_CONFIG;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setDnsConfig(data: any) {
|
||||
setDnsConfig(data) {
|
||||
const { path, method } = this.SET_DNS_CONFIG;
|
||||
const config = {
|
||||
data,
|
||||
@@ -673,7 +642,7 @@ class Api {
|
||||
|
||||
SET_PROTECTION = { path: 'protection', method: 'POST' };
|
||||
|
||||
setProtection(data: any) {
|
||||
setProtection(data) {
|
||||
const { enabled, duration } = data;
|
||||
const { path, method } = this.SET_PROTECTION;
|
||||
|
||||
@@ -685,7 +654,6 @@ class Api {
|
||||
|
||||
clearCache() {
|
||||
const { path, method } = this.CLEAR_CACHE;
|
||||
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@
|
||||
--btn-success-bgcolor: #5eba00;
|
||||
--form-disabled-bgcolor: #f8f9fa;
|
||||
--form-disabled-color: #495057;
|
||||
--rt-nodata-bgcolor: rgba(255, 255, 255, 0.8);
|
||||
--rt-nodata-color: rgba(0, 0, 0, 0.5);
|
||||
--rt-nodata-bgcolor: rgba(255,255,255,0.8);
|
||||
--rt-nodata-color: rgba(0,0,0,0.5);
|
||||
--modal-overlay-bgcolor: rgba(255, 255, 255, 0.75);
|
||||
--logs__table-bgcolor: #fff;
|
||||
--logs__row--blue-bgcolor: #e5effd;
|
||||
@@ -28,7 +28,7 @@
|
||||
--gray-d8: #d8d8d8;
|
||||
--gray-f3: #f3f3f3;
|
||||
--loading-bg: rgba(255, 255, 255, 0.48);
|
||||
--font-family-monospace: Monaco, Menlo, 'Ubuntu Mono', Consolas, source-code-pro, monospace;
|
||||
--font-family-monospace: Monaco, Menlo, "Ubuntu Mono", Consolas, source-code-pro, monospace;
|
||||
--font-size-disable-autozoom: 1rem;
|
||||
--alert-message-color: #24426c;
|
||||
--alert-message-border: #cbdbf2;
|
||||
@@ -37,7 +37,7 @@
|
||||
--radio-bg: #ffffff;
|
||||
}
|
||||
|
||||
[data-theme='dark'] {
|
||||
[data-theme="dark"] {
|
||||
--black: #ffffff;
|
||||
--bgcolor: #131313;
|
||||
--mcolor: #e6e6e6;
|
||||
@@ -74,14 +74,12 @@
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||||
}
|
||||
|
||||
/* Disable Auto Zoom in Input - Safari on iPhone https://stackoverflow.com/a/6394497 */
|
||||
@media screen and (max-width: 767px) {
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
input, select, textarea {
|
||||
font-size: var(--font-size-disable-autozoom);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { HashRouter, Route } from 'react-router-dom';
|
||||
import LoadingBar from 'react-redux-loading-bar';
|
||||
import { hot } from 'react-hot-loader/root';
|
||||
@@ -10,6 +9,8 @@ import '../ui/ReactTable.css';
|
||||
import './index.css';
|
||||
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import propTypes from 'prop-types';
|
||||
import Toasts from '../Toasts';
|
||||
import Footer from '../ui/Footer';
|
||||
import Status from '../ui/Status';
|
||||
@@ -18,14 +19,15 @@ import UpdateOverlay from '../ui/UpdateOverlay';
|
||||
import EncryptionTopline from '../ui/EncryptionTopline';
|
||||
import Icons from '../ui/Icons';
|
||||
import i18n from '../../i18n';
|
||||
|
||||
import Loading from '../ui/Loading';
|
||||
import { FILTERS_URLS, MENU_URLS, SETTINGS_URLS, THEMES } from '../../helpers/constants';
|
||||
|
||||
import {
|
||||
FILTERS_URLS,
|
||||
MENU_URLS,
|
||||
SETTINGS_URLS,
|
||||
THEMES,
|
||||
} from '../../helpers/constants';
|
||||
import { getLogsUrlParams, setHtmlLangAttr, setUITheme } from '../../helpers/helpers';
|
||||
|
||||
import Header from '../Header';
|
||||
|
||||
import { changeLanguage, getDnsStatus, getTimerStatus } from '../../actions';
|
||||
|
||||
import Dashboard from '../../containers/Dashboard';
|
||||
@@ -33,19 +35,15 @@ import SetupGuide from '../../containers/SetupGuide';
|
||||
import Settings from '../../containers/Settings';
|
||||
import Dns from '../../containers/Dns';
|
||||
import Encryption from '../../containers/Encryption';
|
||||
|
||||
import Dhcp from '../Settings/Dhcp';
|
||||
import Clients from '../../containers/Clients';
|
||||
import DnsBlocklist from '../../containers/DnsBlocklist';
|
||||
import DnsAllowlist from '../../containers/DnsAllowlist';
|
||||
import DnsRewrites from '../../containers/DnsRewrites';
|
||||
import CustomRules from '../../containers/CustomRules';
|
||||
|
||||
import Services from '../Filters/Services';
|
||||
|
||||
import Logs from '../Logs';
|
||||
import ProtectionTimer from '../ProtectionTimer';
|
||||
import { RootState } from '../../initialState';
|
||||
|
||||
const ROUTES = [
|
||||
{
|
||||
@@ -103,17 +101,26 @@ const ROUTES = [
|
||||
},
|
||||
];
|
||||
|
||||
const renderRoute = ({ path, component, exact }, idx) => <Route
|
||||
key={idx}
|
||||
exact={exact}
|
||||
path={path}
|
||||
component={component}
|
||||
/>;
|
||||
|
||||
const App = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { language, isCoreRunning, isUpdateAvailable, processing, theme } = useSelector<
|
||||
RootState,
|
||||
RootState['dashboard']
|
||||
>((state) => state.dashboard, shallowEqual);
|
||||
const {
|
||||
language,
|
||||
isCoreRunning,
|
||||
isUpdateAvailable,
|
||||
processing,
|
||||
theme,
|
||||
} = useSelector((state) => state.dashboard, shallowEqual);
|
||||
|
||||
const { processing: processingEncryption } = useSelector<RootState, RootState['encryption']>(
|
||||
(state) => state.encryption,
|
||||
shallowEqual,
|
||||
);
|
||||
const { processing: processingEncryption } = useSelector((
|
||||
state,
|
||||
) => state.encryption, shallowEqual);
|
||||
|
||||
const updateAvailable = isCoreRunning && isUpdateAvailable;
|
||||
|
||||
@@ -150,7 +157,7 @@ const App = () => {
|
||||
setLanguage();
|
||||
}, [language]);
|
||||
|
||||
const handleAutoTheme = (e: any, accountTheme: any) => {
|
||||
const handleAutoTheme = (e, accountTheme) => {
|
||||
if (accountTheme !== THEMES.auto) {
|
||||
return;
|
||||
}
|
||||
@@ -188,50 +195,35 @@ const App = () => {
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
return (
|
||||
<HashRouter hashType="noslash">
|
||||
{updateAvailable && (
|
||||
<>
|
||||
<UpdateTopline />
|
||||
return <HashRouter hashType="noslash">
|
||||
{updateAvailable && <>
|
||||
<UpdateTopline />
|
||||
<UpdateOverlay />
|
||||
</>}
|
||||
{!processingEncryption && <EncryptionTopline />}
|
||||
<LoadingBar className="loading-bar" updateTime={1000} />
|
||||
<Header />
|
||||
<ProtectionTimer />
|
||||
<div className="container container--wrap pb-5 pt-5">
|
||||
{processing && <Loading />}
|
||||
{!isCoreRunning && <div className="row row-cards">
|
||||
<div className="col-lg-12">
|
||||
<Status reloadPage={reloadPage} message="dns_start" />
|
||||
<Loading />
|
||||
</div>
|
||||
</div>}
|
||||
{!processing && isCoreRunning && ROUTES.map(renderRoute)}
|
||||
</div>
|
||||
<Footer />
|
||||
<Toasts />
|
||||
<Icons />
|
||||
</HashRouter>;
|
||||
};
|
||||
|
||||
<UpdateOverlay />
|
||||
</>
|
||||
)}
|
||||
|
||||
{!processingEncryption && <EncryptionTopline />}
|
||||
|
||||
<LoadingBar className="loading-bar" updateTime={1000} />
|
||||
|
||||
<Header />
|
||||
|
||||
<ProtectionTimer />
|
||||
|
||||
<div className="container container--wrap pb-5 pt-5">
|
||||
{processing && <Loading />}
|
||||
|
||||
{!isCoreRunning && (
|
||||
<div className="row row-cards">
|
||||
<div className="col-lg-12">
|
||||
<Status reloadPage={reloadPage} message="dns_start" />
|
||||
|
||||
<Loading />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!processing &&
|
||||
isCoreRunning &&
|
||||
ROUTES.map((route, index) => (
|
||||
<Route key={index} exact={route.exact} path={route.path} component={route.component} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
|
||||
<Toasts />
|
||||
|
||||
<Icons />
|
||||
</HashRouter>
|
||||
);
|
||||
renderRoute.propTypes = {
|
||||
path: propTypes.oneOfType([propTypes.string, propTypes.arrayOf(propTypes.string)]).isRequired,
|
||||
component: propTypes.element.isRequired,
|
||||
exact: propTypes.bool,
|
||||
};
|
||||
|
||||
export default hot(App);
|
||||
@@ -1,37 +1,25 @@
|
||||
import React from 'react';
|
||||
|
||||
// @ts-expect-error FIXME: update react-table
|
||||
import ReactTable from 'react-table';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTranslation, Trans } from 'react-i18next';
|
||||
|
||||
import { TFunction } from 'i18next';
|
||||
import Card from '../ui/Card';
|
||||
|
||||
import Cell from '../ui/Cell';
|
||||
|
||||
import DomainCell from './DomainCell';
|
||||
|
||||
import { getPercent } from '../../helpers/helpers';
|
||||
import { DASHBOARD_TABLES_DEFAULT_PAGE_SIZE, STATUS_COLORS, TABLES_MIN_ROWS } from '../../helpers/constants';
|
||||
|
||||
const CountCell = (totalBlocked: any) =>
|
||||
function cell(row: any) {
|
||||
const { value } = row;
|
||||
const percent = getPercent(totalBlocked, value);
|
||||
const CountCell = (totalBlocked) => function cell(row) {
|
||||
const { value } = row;
|
||||
const percent = getPercent(totalBlocked, value);
|
||||
|
||||
return <Cell value={value} percent={percent} color={STATUS_COLORS.red} search={row.original.domain} />;
|
||||
};
|
||||
|
||||
interface BlockedDomainsProps {
|
||||
topBlockedDomains: unknown[];
|
||||
blockedFiltering: number;
|
||||
replacedSafebrowsing: number;
|
||||
replacedSafesearch: number;
|
||||
replacedParental: number;
|
||||
refreshButton: React.ReactNode;
|
||||
subtitle: string;
|
||||
t: TFunction;
|
||||
}
|
||||
return <Cell value={value}
|
||||
percent={percent}
|
||||
color={STATUS_COLORS.red}
|
||||
search={row.original.domain}
|
||||
/>;
|
||||
};
|
||||
|
||||
const BlockedDomains = ({
|
||||
t,
|
||||
@@ -42,13 +30,20 @@ const BlockedDomains = ({
|
||||
replacedSafebrowsing,
|
||||
replacedParental,
|
||||
replacedSafesearch,
|
||||
}: BlockedDomainsProps) => {
|
||||
const totalBlocked = blockedFiltering + replacedSafebrowsing + replacedParental + replacedSafesearch;
|
||||
}) => {
|
||||
const totalBlocked = (
|
||||
blockedFiltering + replacedSafebrowsing + replacedParental + replacedSafesearch
|
||||
);
|
||||
|
||||
return (
|
||||
<Card title={t('top_blocked_domains')} subtitle={subtitle} bodyType="card-table" refresh={refreshButton}>
|
||||
<Card
|
||||
title={t('top_blocked_domains')}
|
||||
subtitle={subtitle}
|
||||
bodyType="card-table"
|
||||
refresh={refreshButton}
|
||||
>
|
||||
<ReactTable
|
||||
data={topBlockedDomains.map(({ name: domain, count }: any) => ({
|
||||
data={topBlockedDomains.map(({ name: domain, count }) => ({
|
||||
domain,
|
||||
count,
|
||||
}))}
|
||||
@@ -75,4 +70,15 @@ const BlockedDomains = ({
|
||||
);
|
||||
};
|
||||
|
||||
BlockedDomains.propTypes = {
|
||||
topBlockedDomains: PropTypes.array.isRequired,
|
||||
blockedFiltering: PropTypes.number.isRequired,
|
||||
replacedSafebrowsing: PropTypes.number.isRequired,
|
||||
replacedSafesearch: PropTypes.number.isRequired,
|
||||
replacedParental: PropTypes.number.isRequired,
|
||||
refreshButton: PropTypes.node.isRequired,
|
||||
subtitle: PropTypes.string.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(BlockedDomains);
|
||||
@@ -1,12 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
// @ts-expect-error FIXME: update react-table
|
||||
import ReactTable from 'react-table';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import Card from '../ui/Card';
|
||||
import Cell from '../ui/Cell';
|
||||
|
||||
@@ -18,14 +16,11 @@ import {
|
||||
TABLES_MIN_ROWS,
|
||||
} from '../../helpers/constants';
|
||||
import { toggleClientBlock } from '../../actions/access';
|
||||
|
||||
import { renderFormattedClientCell } from '../../helpers/renderFormattedClientCell';
|
||||
import { getStats } from '../../actions/stats';
|
||||
|
||||
import IconTooltip from '../Logs/Cells/IconTooltip';
|
||||
import { RootState } from '../../initialState';
|
||||
|
||||
const getClientsPercentColor = (percent: any) => {
|
||||
const getClientsPercentColor = (percent) => {
|
||||
if (percent > 50) {
|
||||
return STATUS_COLORS.green;
|
||||
}
|
||||
@@ -35,13 +30,9 @@ const getClientsPercentColor = (percent: any) => {
|
||||
return STATUS_COLORS.red;
|
||||
};
|
||||
|
||||
const CountCell = (row: any) => {
|
||||
const {
|
||||
value,
|
||||
original: { ip },
|
||||
} = row;
|
||||
|
||||
const numDnsQueries = useSelector<RootState>((state) => state.stats.numDnsQueries, shallowEqual);
|
||||
const CountCell = (row) => {
|
||||
const { value, original: { ip } } = row;
|
||||
const numDnsQueries = useSelector((state) => state.stats.numDnsQueries, shallowEqual);
|
||||
|
||||
const percent = getPercent(numDnsQueries, value);
|
||||
const percentColor = getClientsPercentColor(percent);
|
||||
@@ -49,29 +40,22 @@ const CountCell = (row: any) => {
|
||||
return <Cell value={value} percent={percent} color={percentColor} search={ip} />;
|
||||
};
|
||||
|
||||
const renderBlockingButton = (ip: any, disallowed: any, disallowed_rule: any) => {
|
||||
const renderBlockingButton = (ip, disallowed, disallowed_rule) => {
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const processingSet = useSelector<RootState, RootState['access']['processingSet']>(
|
||||
(state) => state.access.processingSet,
|
||||
);
|
||||
|
||||
const allowedClients = useSelector<RootState, RootState['access']['allowed_clients']>(
|
||||
(state) => state.access.allowed_clients,
|
||||
shallowEqual,
|
||||
);
|
||||
const processingSet = useSelector((state) => state.access.processingSet);
|
||||
const allowedСlients = useSelector((state) => state.access.allowed_clients, shallowEqual);
|
||||
|
||||
const [isOptionsOpened, setOptionsOpened] = useState(false);
|
||||
|
||||
const toggleClientStatus = async (ip: any, disallowed: any, disallowed_rule: any) => {
|
||||
const toggleClientStatus = async (ip, disallowed, disallowed_rule) => {
|
||||
let confirmMessage;
|
||||
|
||||
if (disallowed) {
|
||||
confirmMessage = t('client_confirm_unblock', { ip: disallowed_rule || ip });
|
||||
} else {
|
||||
confirmMessage = `${t('adg_will_drop_dns_queries')} ${t('client_confirm_block', { ip })}`;
|
||||
if (allowedClients.length > 0) {
|
||||
if (allowedСlients.length > 0) {
|
||||
confirmMessage = confirmMessage.concat(`\n\n${t('filter_allowlist', { disallowed_rule })}`);
|
||||
}
|
||||
}
|
||||
@@ -89,11 +73,15 @@ const renderBlockingButton = (ip: any, disallowed: any, disallowed_rule: any) =>
|
||||
|
||||
const text = disallowed ? BLOCK_ACTIONS.UNBLOCK : BLOCK_ACTIONS.BLOCK;
|
||||
|
||||
const lastRuleInAllowlist = !disallowed && allowedClients === disallowed_rule;
|
||||
const lastRuleInAllowlist = !disallowed && allowedСlients === disallowed_rule;
|
||||
const disabled = processingSet || lastRuleInAllowlist;
|
||||
return (
|
||||
<div className="table__action">
|
||||
<button type="button" className="btn btn-icon btn-sm px-0" onClick={() => setOptionsOpened(true)}>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-sm px-0"
|
||||
onClick={() => setOptionsOpened(true)}
|
||||
>
|
||||
<svg className="icon24 icon--lightgray button-action__icon">
|
||||
<use xlinkHref="#bullets" />
|
||||
</svg>
|
||||
@@ -104,18 +92,16 @@ const renderBlockingButton = (ip: any, disallowed: any, disallowed_rule: any) =>
|
||||
tooltipClass="button-action--arrow-option-container"
|
||||
xlinkHref="bullets"
|
||||
triggerClass="btn btn-icon btn-sm px-0 button-action__hidden-trigger"
|
||||
content={
|
||||
content={(
|
||||
<button
|
||||
className={classNames(
|
||||
'button-action--arrow-option px-4 py-1',
|
||||
disallowed ? 'bg--green' : 'bg--danger',
|
||||
)}
|
||||
className={classNames('button-action--arrow-option px-4 py-1', disallowed ? 'bg--green' : 'bg--danger')}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
title={lastRuleInAllowlist ? t('last_rule_in_allowlist', { disallowed_rule }) : ''}>
|
||||
title={lastRuleInAllowlist ? t('last_rule_in_allowlist', { disallowed_rule }) : ''}
|
||||
>
|
||||
<Trans>{text}</Trans>
|
||||
</button>
|
||||
}
|
||||
)}
|
||||
placement="bottom-end"
|
||||
trigger="click"
|
||||
onVisibilityChange={setOptionsOpened}
|
||||
@@ -127,42 +113,35 @@ const renderBlockingButton = (ip: any, disallowed: any, disallowed_rule: any) =>
|
||||
);
|
||||
};
|
||||
|
||||
const ClientCell = (row: any) => {
|
||||
const {
|
||||
value,
|
||||
original: {
|
||||
info,
|
||||
info: { disallowed, disallowed_rule },
|
||||
},
|
||||
} = row;
|
||||
const ClientCell = (row) => {
|
||||
const { value, original: { info, info: { disallowed, disallowed_rule } } } = row;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="logs__row logs__row--overflow logs__row--column d-flex align-items-center">
|
||||
{renderFormattedClientCell(value, info, true)}
|
||||
{renderBlockingButton(value, disallowed, disallowed_rule)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
return <>
|
||||
<div className="logs__row logs__row--overflow logs__row--column d-flex align-items-center">
|
||||
{renderFormattedClientCell(value, info, true)}
|
||||
{renderBlockingButton(value, disallowed, disallowed_rule)}
|
||||
</div>
|
||||
</>;
|
||||
};
|
||||
|
||||
interface ClientsProps {
|
||||
refreshButton: React.ReactNode;
|
||||
subtitle: string;
|
||||
}
|
||||
|
||||
const Clients = ({ refreshButton, subtitle }: ClientsProps) => {
|
||||
const Clients = ({
|
||||
refreshButton,
|
||||
subtitle,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const topClients = useSelector<RootState, RootState['stats']['topClients']>(
|
||||
(state) => state.stats.topClients,
|
||||
shallowEqual,
|
||||
);
|
||||
const topClients = useSelector((state) => state.stats.topClients, shallowEqual);
|
||||
|
||||
return (
|
||||
<Card title={t('top_clients')} subtitle={subtitle} bodyType="card-table" refresh={refreshButton}>
|
||||
<Card
|
||||
title={t('top_clients')}
|
||||
subtitle={subtitle}
|
||||
bodyType="card-table"
|
||||
refresh={refreshButton}
|
||||
>
|
||||
<ReactTable
|
||||
data={topClients.map(({ name: ip, count, info, blocked }: any) => ({
|
||||
data={topClients.map(({
|
||||
name: ip, count, info, blocked,
|
||||
}) => ({
|
||||
ip,
|
||||
count,
|
||||
info,
|
||||
@@ -188,14 +167,12 @@ const Clients = ({ refreshButton, subtitle }: ClientsProps) => {
|
||||
minRows={TABLES_MIN_ROWS}
|
||||
defaultPageSize={DASHBOARD_TABLES_DEFAULT_PAGE_SIZE}
|
||||
className="-highlight card-table-overflow--limited clients__table"
|
||||
getTrProps={(_state: any, rowInfo: any) => {
|
||||
getTrProps={(_state, rowInfo) => {
|
||||
if (!rowInfo) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const {
|
||||
info: { disallowed },
|
||||
} = rowInfo.original;
|
||||
const { info: { disallowed } } = rowInfo.original;
|
||||
|
||||
return disallowed ? { className: 'logs__row--red' } : {};
|
||||
}}
|
||||
@@ -204,4 +181,9 @@ const Clients = ({ refreshButton, subtitle }: ClientsProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
Clients.propTypes = {
|
||||
refreshButton: PropTypes.node.isRequired,
|
||||
subtitle: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default Clients;
|
||||
@@ -1,52 +1,41 @@
|
||||
import React from 'react';
|
||||
import propTypes from 'prop-types';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import round from 'lodash/round';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
|
||||
import Card from '../ui/Card';
|
||||
|
||||
import { formatNumber, msToDays, msToHours } from '../../helpers/helpers';
|
||||
|
||||
import LogsSearchLink from '../ui/LogsSearchLink';
|
||||
import { RESPONSE_FILTER, TIME_UNITS } from '../../helpers/constants';
|
||||
|
||||
import Tooltip from '../ui/Tooltip';
|
||||
import { RootState } from '../../initialState';
|
||||
|
||||
interface RowProps {
|
||||
label: string;
|
||||
count: string;
|
||||
response_status?: string;
|
||||
tooltipTitle: string;
|
||||
translationComponents?: React.ReactElement[];
|
||||
}
|
||||
|
||||
const Row = ({ label, count, response_status, tooltipTitle, translationComponents }: RowProps) => {
|
||||
const content = response_status ? (
|
||||
<LogsSearchLink response_status={response_status}>{count}</LogsSearchLink>
|
||||
) : (
|
||||
count
|
||||
);
|
||||
const Row = ({
|
||||
label, count, response_status, tooltipTitle, translationComponents,
|
||||
}) => {
|
||||
const content = response_status
|
||||
? <LogsSearchLink response_status={response_status}>{formatNumber(count)}</LogsSearchLink>
|
||||
: count;
|
||||
|
||||
return (
|
||||
<div className="counters__row" key={label}>
|
||||
<div className="counters__column">
|
||||
<span className="counters__title">
|
||||
<Trans components={translationComponents}>{label}</Trans>
|
||||
<Trans components={translationComponents}>
|
||||
{label}
|
||||
</Trans>
|
||||
</span>
|
||||
|
||||
<span className="counters__tooltip">
|
||||
<Tooltip
|
||||
content={tooltipTitle}
|
||||
placement="top"
|
||||
className="tooltip-container tooltip-custom--narrow text-center">
|
||||
className="tooltip-container tooltip-custom--narrow text-center"
|
||||
>
|
||||
<svg className="icons icon--20 icon--lightgray ml-2">
|
||||
<use xlinkHref="#question" />
|
||||
</svg>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="counters__column counters__column--value">
|
||||
<strong>{content}</strong>
|
||||
</div>
|
||||
@@ -54,12 +43,7 @@ const Row = ({ label, count, response_status, tooltipTitle, translationComponent
|
||||
);
|
||||
};
|
||||
|
||||
interface CountersProps {
|
||||
refreshButton: React.ReactNode;
|
||||
subtitle: string;
|
||||
}
|
||||
|
||||
const Counters = ({ refreshButton, subtitle }: CountersProps) => {
|
||||
const Counters = ({ refreshButton, subtitle }) => {
|
||||
const {
|
||||
interval,
|
||||
numDnsQueries,
|
||||
@@ -69,67 +53,77 @@ const Counters = ({ refreshButton, subtitle }: CountersProps) => {
|
||||
numReplacedSafesearch,
|
||||
avgProcessingTime,
|
||||
timeUnits,
|
||||
} = useSelector<RootState, RootState['stats']>((state) => state.stats, shallowEqual);
|
||||
} = useSelector((state) => state.stats, shallowEqual);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const dnsQueryTooltip =
|
||||
timeUnits === TIME_UNITS.HOURS
|
||||
? t('number_of_dns_query_hours', { count: msToHours(interval) })
|
||||
: t('number_of_dns_query_days', { count: msToDays(interval) });
|
||||
const dnsQueryTooltip = timeUnits === TIME_UNITS.HOURS
|
||||
? t('number_of_dns_query_hours', { count: msToHours(interval) })
|
||||
: t('number_of_dns_query_days', { count: msToDays(interval) });
|
||||
|
||||
const rows: RowProps[] = [
|
||||
const rows = [
|
||||
{
|
||||
label: 'dns_query',
|
||||
count: formatNumber(numDnsQueries),
|
||||
count: numDnsQueries,
|
||||
tooltipTitle: dnsQueryTooltip,
|
||||
response_status: RESPONSE_FILTER.ALL.QUERY,
|
||||
},
|
||||
{
|
||||
label: 'blocked_by',
|
||||
count: formatNumber(numBlockedFiltering),
|
||||
count: numBlockedFiltering,
|
||||
tooltipTitle: 'number_of_dns_query_blocked_24_hours',
|
||||
response_status: RESPONSE_FILTER.BLOCKED.QUERY,
|
||||
|
||||
translationComponents: [
|
||||
<a href="#filters" key="0">
|
||||
link
|
||||
</a>,
|
||||
],
|
||||
translationComponents: [<a href="#filters" key="0">link</a>],
|
||||
},
|
||||
{
|
||||
label: 'stats_malware_phishing',
|
||||
count: formatNumber(numReplacedSafebrowsing),
|
||||
count: numReplacedSafebrowsing,
|
||||
tooltipTitle: 'number_of_dns_query_blocked_24_hours_by_sec',
|
||||
response_status: RESPONSE_FILTER.BLOCKED_THREATS.QUERY,
|
||||
},
|
||||
{
|
||||
label: 'stats_adult',
|
||||
count: formatNumber(numReplacedParental),
|
||||
count: numReplacedParental,
|
||||
tooltipTitle: 'number_of_dns_query_blocked_24_hours_adult',
|
||||
response_status: RESPONSE_FILTER.BLOCKED_ADULT_WEBSITES.QUERY,
|
||||
},
|
||||
{
|
||||
label: 'enforced_save_search',
|
||||
count: formatNumber(numReplacedSafesearch),
|
||||
count: numReplacedSafesearch,
|
||||
tooltipTitle: 'number_of_dns_query_to_safe_search',
|
||||
response_status: RESPONSE_FILTER.SAFE_SEARCH.QUERY,
|
||||
},
|
||||
{
|
||||
label: 'average_processing_time',
|
||||
count: avgProcessingTime ? `${round(avgProcessingTime)} ms` : '0',
|
||||
count: avgProcessingTime ? `${round(avgProcessingTime)} ms` : 0,
|
||||
tooltipTitle: 'average_processing_time_hint',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Card title={t('general_statistics')} subtitle={subtitle} bodyType="card-table" refresh={refreshButton}>
|
||||
<Card
|
||||
title={t('general_statistics')}
|
||||
subtitle={subtitle}
|
||||
bodyType="card-table"
|
||||
refresh={refreshButton}
|
||||
>
|
||||
<div className="counters">
|
||||
{rows.map((row, index) => {
|
||||
return <Row {...row} key={index} />;
|
||||
})}
|
||||
{rows.map(Row)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
Row.propTypes = {
|
||||
label: propTypes.string.isRequired,
|
||||
count: propTypes.string.isRequired,
|
||||
response_status: propTypes.string,
|
||||
tooltipTitle: propTypes.string.isRequired,
|
||||
translationComponents: propTypes.arrayOf(propTypes.element),
|
||||
};
|
||||
|
||||
Counters.propTypes = {
|
||||
refreshButton: propTypes.node.isRequired,
|
||||
subtitle: propTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default Counters;
|
||||
77
client/src/components/Dashboard/DomainCell.js
Normal file
77
client/src/components/Dashboard/DomainCell.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { Trans } from 'react-i18next';
|
||||
import { getSourceData, getTrackerData } from '../../helpers/trackers/trackers';
|
||||
import Tooltip from '../ui/Tooltip';
|
||||
import { captitalizeWords } from '../../helpers/helpers';
|
||||
|
||||
const renderLabel = (value) => <strong><Trans>{value}</Trans></strong>;
|
||||
|
||||
const renderLink = ({ url, name }) => <a
|
||||
className="tooltip-custom__content-link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={url}
|
||||
>
|
||||
<strong>{name}</strong>
|
||||
</a>;
|
||||
|
||||
const getTrackerInfo = (trackerData) => [{
|
||||
key: 'name_table_header',
|
||||
value: trackerData,
|
||||
render: renderLink,
|
||||
},
|
||||
{
|
||||
key: 'category_label',
|
||||
value: captitalizeWords(trackerData.category),
|
||||
render: renderLabel,
|
||||
},
|
||||
{
|
||||
key: 'source_label',
|
||||
value: getSourceData(trackerData),
|
||||
render: renderLink,
|
||||
}];
|
||||
|
||||
const DomainCell = ({ value }) => {
|
||||
const trackerData = getTrackerData(value);
|
||||
|
||||
const content = trackerData && <div className="popover__list">
|
||||
<div className="tooltip-custom__content-title mb-1">
|
||||
<Trans>found_in_known_domain_db</Trans>
|
||||
</div>
|
||||
{getTrackerInfo(trackerData)
|
||||
.map(({ key, value, render }) => <div
|
||||
key={key}
|
||||
className="tooltip-custom__content-item"
|
||||
>
|
||||
<Trans>{key}</Trans>: {render(value)}
|
||||
</div>)}
|
||||
</div>;
|
||||
|
||||
return (
|
||||
<div className="logs__row">
|
||||
<div className="logs__text" title={value}>
|
||||
{value}
|
||||
</div>
|
||||
{trackerData
|
||||
&& <Tooltip content={content} placement="top"
|
||||
className="tooltip-container tooltip-custom--wide">
|
||||
<svg className="icons icon--24 icon--green ml-1">
|
||||
<use xlinkHref="#privacy" />
|
||||
</svg>
|
||||
</Tooltip>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
DomainCell.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
renderLink.propTypes = {
|
||||
url: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DomainCell;
|
||||
@@ -1,81 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Trans } from 'react-i18next';
|
||||
import { getSourceData, getTrackerData } from '../../helpers/trackers/trackers';
|
||||
|
||||
import Tooltip from '../ui/Tooltip';
|
||||
|
||||
import { captitalizeWords } from '../../helpers/helpers';
|
||||
|
||||
const renderLabel = (value: any) => (
|
||||
<strong>
|
||||
<Trans>{value}</Trans>
|
||||
</strong>
|
||||
);
|
||||
|
||||
interface renderLinkProps {
|
||||
url: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const renderLink = ({ url, name }: renderLinkProps) => (
|
||||
<a className="tooltip-custom__content-link" target="_blank" rel="noopener noreferrer" href={url}>
|
||||
<strong>{name}</strong>
|
||||
</a>
|
||||
);
|
||||
|
||||
const getTrackerInfo = (trackerData: any) => [
|
||||
{
|
||||
key: 'name_table_header',
|
||||
value: trackerData,
|
||||
render: renderLink,
|
||||
},
|
||||
{
|
||||
key: 'category_label',
|
||||
value: captitalizeWords(trackerData.category),
|
||||
render: renderLabel,
|
||||
},
|
||||
{
|
||||
key: 'source_label',
|
||||
value: getSourceData(trackerData),
|
||||
render: renderLink,
|
||||
},
|
||||
];
|
||||
|
||||
interface DomainCellProps {
|
||||
value: string;
|
||||
}
|
||||
|
||||
const DomainCell = ({ value }: DomainCellProps) => {
|
||||
const trackerData = getTrackerData(value);
|
||||
|
||||
const content = trackerData && (
|
||||
<div className="popover__list">
|
||||
<div className="tooltip-custom__content-title mb-1">
|
||||
<Trans>found_in_known_domain_db</Trans>
|
||||
</div>
|
||||
{getTrackerInfo(trackerData).map(({ key, value, render }) => (
|
||||
<div key={key} className="tooltip-custom__content-item">
|
||||
<Trans>{key}</Trans>: {render(value)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="logs__row">
|
||||
<div className="logs__text" title={value}>
|
||||
{value}
|
||||
</div>
|
||||
{trackerData && (
|
||||
<Tooltip content={content} placement="top" className="tooltip-container tooltip-custom--wide">
|
||||
<svg className="icons icon--24 icon--green ml-1">
|
||||
<use xlinkHref="#privacy" />
|
||||
</svg>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DomainCell;
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
// @ts-expect-error FIXME: update react-table
|
||||
import ReactTable from 'react-table';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTranslation, Trans } from 'react-i18next';
|
||||
|
||||
import Card from '../ui/Card';
|
||||
@@ -9,10 +8,9 @@ import Cell from '../ui/Cell';
|
||||
import DomainCell from './DomainCell';
|
||||
|
||||
import { DASHBOARD_TABLES_DEFAULT_PAGE_SIZE, STATUS_COLORS, TABLES_MIN_ROWS } from '../../helpers/constants';
|
||||
|
||||
import { getPercent } from '../../helpers/helpers';
|
||||
|
||||
const getQueriedPercentColor = (percent: any) => {
|
||||
const getQueriedPercentColor = (percent) => {
|
||||
if (percent > 10) {
|
||||
return STATUS_COLORS.red;
|
||||
}
|
||||
@@ -22,27 +20,26 @@ const getQueriedPercentColor = (percent: any) => {
|
||||
return STATUS_COLORS.green;
|
||||
};
|
||||
|
||||
const countCell = (dnsQueries: any) =>
|
||||
function cell(row: any) {
|
||||
const { value } = row;
|
||||
const percent = getPercent(dnsQueries, value);
|
||||
const percentColor = getQueriedPercentColor(percent);
|
||||
const countCell = (dnsQueries) => function cell(row) {
|
||||
const { value } = row;
|
||||
const percent = getPercent(dnsQueries, value);
|
||||
const percentColor = getQueriedPercentColor(percent);
|
||||
|
||||
return <Cell value={value} percent={percent} color={percentColor} search={row.original.domain} />;
|
||||
};
|
||||
return <Cell value={value} percent={percent} color={percentColor}
|
||||
search={row.original.domain} />;
|
||||
};
|
||||
|
||||
interface QueriedDomainsProps {
|
||||
topQueriedDomains: unknown[];
|
||||
dnsQueries: number;
|
||||
refreshButton: React.ReactNode;
|
||||
subtitle: string;
|
||||
t: (...args: unknown[]) => string;
|
||||
}
|
||||
|
||||
const QueriedDomains = ({ t, refreshButton, topQueriedDomains, subtitle, dnsQueries }: QueriedDomainsProps) => (
|
||||
<Card title={t('stats_query_domain')} subtitle={subtitle} bodyType="card-table" refresh={refreshButton}>
|
||||
const QueriedDomains = ({
|
||||
t, refreshButton, topQueriedDomains, subtitle, dnsQueries,
|
||||
}) => (
|
||||
<Card
|
||||
title={t('stats_query_domain')}
|
||||
subtitle={subtitle}
|
||||
bodyType="card-table"
|
||||
refresh={refreshButton}
|
||||
>
|
||||
<ReactTable
|
||||
data={topQueriedDomains.map(({ name: domain, count }: any) => ({
|
||||
data={topQueriedDomains.map(({ name: domain, count }) => ({
|
||||
domain,
|
||||
count,
|
||||
}))}
|
||||
@@ -68,4 +65,12 @@ const QueriedDomains = ({ t, refreshButton, topQueriedDomains, subtitle, dnsQuer
|
||||
</Card>
|
||||
);
|
||||
|
||||
QueriedDomains.propTypes = {
|
||||
topQueriedDomains: PropTypes.array.isRequired,
|
||||
dnsQueries: PropTypes.number.isRequired,
|
||||
refreshButton: PropTypes.node.isRequired,
|
||||
subtitle: PropTypes.string.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(QueriedDomains);
|
||||
@@ -1,27 +1,15 @@
|
||||
import React from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { withTranslation, Trans } from 'react-i18next';
|
||||
|
||||
import StatsCard from './StatsCard';
|
||||
|
||||
import { getPercent, normalizeHistory } from '../../helpers/helpers';
|
||||
import { RESPONSE_FILTER } from '../../helpers/constants';
|
||||
|
||||
const getNormalizedHistory = (data: any, interval: any, id: any) => [{ data: normalizeHistory(data), id }];
|
||||
|
||||
interface StatisticsProps {
|
||||
interval: number;
|
||||
dnsQueries: number[];
|
||||
blockedFiltering: unknown[];
|
||||
replacedSafebrowsing: unknown[];
|
||||
replacedParental: unknown[];
|
||||
numDnsQueries: number;
|
||||
numBlockedFiltering: number;
|
||||
numReplacedSafebrowsing: number;
|
||||
numReplacedParental: number;
|
||||
refreshButton: React.ReactNode;
|
||||
}
|
||||
const getNormalizedHistory = (data, interval, id) => [
|
||||
{ data: normalizeHistory(data, interval), id },
|
||||
];
|
||||
|
||||
const Statistics = ({
|
||||
interval,
|
||||
@@ -33,68 +21,61 @@ const Statistics = ({
|
||||
numBlockedFiltering,
|
||||
numReplacedSafebrowsing,
|
||||
numReplacedParental,
|
||||
}: StatisticsProps) => (
|
||||
}) => (
|
||||
<div className="row">
|
||||
<div className="col-sm-6 col-lg-3">
|
||||
<StatsCard
|
||||
total={numDnsQueries}
|
||||
lineData={getNormalizedHistory(dnsQueries, interval, 'dnsQuery')}
|
||||
title={
|
||||
<Link to="logs">
|
||||
<Trans>dns_query</Trans>
|
||||
</Link>
|
||||
}
|
||||
title={<Link to="logs"><Trans>dns_query</Trans></Link>}
|
||||
color="blue"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6 col-lg-3">
|
||||
<StatsCard
|
||||
total={numBlockedFiltering}
|
||||
lineData={getNormalizedHistory(blockedFiltering, interval, 'blockedFiltering')}
|
||||
percent={getPercent(numDnsQueries, numBlockedFiltering)}
|
||||
title={
|
||||
<Trans
|
||||
components={[
|
||||
<Link to={`logs?response_status=${RESPONSE_FILTER.BLOCKED.QUERY}`} key="0">
|
||||
link
|
||||
</Link>,
|
||||
]}>
|
||||
blocked_by
|
||||
</Trans>
|
||||
}
|
||||
title={<Trans components={[<Link to={`logs?response_status=${RESPONSE_FILTER.BLOCKED.QUERY}`} key="0">link</Link>]}>blocked_by</Trans>}
|
||||
color="red"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6 col-lg-3">
|
||||
<StatsCard
|
||||
total={numReplacedSafebrowsing}
|
||||
lineData={getNormalizedHistory(replacedSafebrowsing, interval, 'replacedSafebrowsing')}
|
||||
lineData={getNormalizedHistory(
|
||||
replacedSafebrowsing,
|
||||
interval,
|
||||
'replacedSafebrowsing',
|
||||
)}
|
||||
percent={getPercent(numDnsQueries, numReplacedSafebrowsing)}
|
||||
title={
|
||||
<Link to={`logs?response_status=${RESPONSE_FILTER.BLOCKED_THREATS.QUERY}`}>
|
||||
<Trans>stats_malware_phishing</Trans>
|
||||
</Link>
|
||||
}
|
||||
title={<Link to={`logs?response_status=${RESPONSE_FILTER.BLOCKED_THREATS.QUERY}`}><Trans>stats_malware_phishing</Trans></Link>}
|
||||
color="green"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-sm-6 col-lg-3">
|
||||
<StatsCard
|
||||
total={numReplacedParental}
|
||||
lineData={getNormalizedHistory(replacedParental, interval, 'replacedParental')}
|
||||
percent={getPercent(numDnsQueries, numReplacedParental)}
|
||||
title={
|
||||
<Link to={`logs?response_status=${RESPONSE_FILTER.BLOCKED_ADULT_WEBSITES.QUERY}`}>
|
||||
<Trans>stats_adult</Trans>
|
||||
</Link>
|
||||
}
|
||||
title={<Link to={`logs?response_status=${RESPONSE_FILTER.BLOCKED_ADULT_WEBSITES.QUERY}`}><Trans>stats_adult</Trans></Link>}
|
||||
color="yellow"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Statistics.propTypes = {
|
||||
interval: PropTypes.number.isRequired,
|
||||
dnsQueries: PropTypes.array.isRequired,
|
||||
blockedFiltering: PropTypes.array.isRequired,
|
||||
replacedSafebrowsing: PropTypes.array.isRequired,
|
||||
replacedParental: PropTypes.array.isRequired,
|
||||
numDnsQueries: PropTypes.number.isRequired,
|
||||
numBlockedFiltering: PropTypes.number.isRequired,
|
||||
numReplacedSafebrowsing: PropTypes.number.isRequired,
|
||||
numReplacedParental: PropTypes.number.isRequired,
|
||||
refreshButton: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(Statistics);
|
||||
@@ -1,34 +1,38 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { STATUS_COLORS } from '../../helpers/constants';
|
||||
|
||||
import { formatNumber } from '../../helpers/helpers';
|
||||
|
||||
import Card from '../ui/Card';
|
||||
|
||||
import Line from '../ui/Line';
|
||||
|
||||
interface StatsCardProps {
|
||||
total: number;
|
||||
lineData: unknown[];
|
||||
title: object;
|
||||
color: string;
|
||||
percent?: number;
|
||||
}
|
||||
|
||||
const StatsCard = ({ total, lineData, percent, title, color }: StatsCardProps) => (
|
||||
const StatsCard = ({
|
||||
total, lineData, percent, title, color,
|
||||
}) => (
|
||||
<Card type="card--full" bodyType="card-wrap">
|
||||
<div className="card-body-stats">
|
||||
<div className={`card-value card-value-stats text-${color}`}>{formatNumber(total)}</div>
|
||||
|
||||
<div className={`card-value card-value-stats text-${color}`}>
|
||||
{formatNumber(total)}
|
||||
</div>
|
||||
<div className="card-title-stats">{title}</div>
|
||||
</div>
|
||||
{percent >= 0 && <div className={`card-value card-value-percent text-${color}`}>{percent}</div>}
|
||||
|
||||
{percent >= 0 && (
|
||||
<div className={`card-value card-value-percent text-${color}`}>
|
||||
{percent}
|
||||
</div>
|
||||
)}
|
||||
<div className="card-chart-bg">
|
||||
<Line data={lineData} color={STATUS_COLORS[color]} />
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
|
||||
StatsCard.propTypes = {
|
||||
total: PropTypes.number.isRequired,
|
||||
lineData: PropTypes.array.isRequired,
|
||||
title: PropTypes.object.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
percent: PropTypes.number,
|
||||
};
|
||||
|
||||
export default StatsCard;
|
||||
@@ -1,48 +1,50 @@
|
||||
import React from 'react';
|
||||
|
||||
// @ts-expect-error FIXME: update react-table
|
||||
import ReactTable from 'react-table';
|
||||
import PropTypes from 'prop-types';
|
||||
import round from 'lodash/round';
|
||||
import { withTranslation, Trans } from 'react-i18next';
|
||||
|
||||
import { TFunction } from 'i18next';
|
||||
import Card from '../ui/Card';
|
||||
|
||||
import DomainCell from './DomainCell';
|
||||
import { DASHBOARD_TABLES_DEFAULT_PAGE_SIZE, TABLES_MIN_ROWS } from '../../helpers/constants';
|
||||
import { formatNumber } from '../../helpers/helpers';
|
||||
|
||||
interface TimeCellProps {
|
||||
value?: string | number;
|
||||
}
|
||||
|
||||
const TimeCell = ({ value }: TimeCellProps) => {
|
||||
const TimeCell = ({ value }) => {
|
||||
if (!value) {
|
||||
return '–';
|
||||
}
|
||||
|
||||
const valueInMilliseconds = formatNumber(round(Number(value) * 1000));
|
||||
const valueInMilliseconds = round(value * 1000);
|
||||
|
||||
return (
|
||||
<div className="logs__row o-hidden">
|
||||
<span className="logs__text logs__text--full" title={valueInMilliseconds.toString()}>
|
||||
<span className="logs__text logs__text--full" title={valueInMilliseconds}>
|
||||
{valueInMilliseconds} ms
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface UpstreamAvgTimeProps {
|
||||
topUpstreamsAvgTime: { name: string; count: number }[];
|
||||
refreshButton: React.ReactNode;
|
||||
subtitle: string;
|
||||
t: TFunction;
|
||||
}
|
||||
TimeCell.propTypes = {
|
||||
value: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]),
|
||||
};
|
||||
|
||||
const UpstreamAvgTime = ({ t, refreshButton, topUpstreamsAvgTime, subtitle }: UpstreamAvgTimeProps) => (
|
||||
<Card title={t('average_upstream_response_time')} subtitle={subtitle} bodyType="card-table" refresh={refreshButton}>
|
||||
const UpstreamAvgTime = ({
|
||||
t,
|
||||
refreshButton,
|
||||
topUpstreamsAvgTime,
|
||||
subtitle,
|
||||
}) => (
|
||||
<Card
|
||||
title={t('average_upstream_response_time')}
|
||||
subtitle={subtitle}
|
||||
bodyType="card-table"
|
||||
refresh={refreshButton}
|
||||
>
|
||||
<ReactTable
|
||||
data={topUpstreamsAvgTime.map(({ name: domain, count }: { name: string; count: number }) => ({
|
||||
data={topUpstreamsAvgTime.map(({ name: domain, count }) => ({
|
||||
domain,
|
||||
count,
|
||||
}))}
|
||||
@@ -68,4 +70,11 @@ const UpstreamAvgTime = ({ t, refreshButton, topUpstreamsAvgTime, subtitle }: Up
|
||||
</Card>
|
||||
);
|
||||
|
||||
UpstreamAvgTime.propTypes = {
|
||||
topUpstreamsAvgTime: PropTypes.array.isRequired,
|
||||
refreshButton: PropTypes.node.isRequired,
|
||||
subtitle: PropTypes.string.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(UpstreamAvgTime);
|
||||
@@ -1,47 +1,51 @@
|
||||
import React from 'react';
|
||||
|
||||
// @ts-expect-error FIXME: update react-table
|
||||
import ReactTable from 'react-table';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTranslation, Trans } from 'react-i18next';
|
||||
|
||||
import { TFunction } from 'i18next';
|
||||
import Card from '../ui/Card';
|
||||
|
||||
import Cell from '../ui/Cell';
|
||||
|
||||
import DomainCell from './DomainCell';
|
||||
|
||||
import { getPercent } from '../../helpers/helpers';
|
||||
import { DASHBOARD_TABLES_DEFAULT_PAGE_SIZE, STATUS_COLORS, TABLES_MIN_ROWS } from '../../helpers/constants';
|
||||
|
||||
const CountCell = (totalBlocked: any) =>
|
||||
function cell(row: any) {
|
||||
const CountCell = (totalBlocked) => (
|
||||
function cell(row) {
|
||||
const { value } = row;
|
||||
const percent = getPercent(totalBlocked, value);
|
||||
|
||||
return <Cell value={value} percent={percent} color={STATUS_COLORS.green} />;
|
||||
};
|
||||
return (
|
||||
<Cell
|
||||
value={value}
|
||||
percent={percent}
|
||||
color={STATUS_COLORS.green}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const getTotalUpstreamRequests = (stats: any) => {
|
||||
const getTotalUpstreamRequests = (stats) => {
|
||||
let total = 0;
|
||||
stats.forEach(({ count }: any) => {
|
||||
total += count;
|
||||
});
|
||||
stats.forEach(({ count }) => { total += count; });
|
||||
|
||||
return total;
|
||||
};
|
||||
|
||||
interface UpstreamResponsesProps {
|
||||
topUpstreamsResponses: { name: string; count: number }[];
|
||||
refreshButton: React.ReactNode;
|
||||
subtitle: string;
|
||||
t: TFunction;
|
||||
}
|
||||
|
||||
const UpstreamResponses = ({ t, refreshButton, topUpstreamsResponses, subtitle }: UpstreamResponsesProps) => (
|
||||
<Card title={t('top_upstreams')} subtitle={subtitle} bodyType="card-table" refresh={refreshButton}>
|
||||
const UpstreamResponses = ({
|
||||
t,
|
||||
refreshButton,
|
||||
topUpstreamsResponses,
|
||||
subtitle,
|
||||
}) => (
|
||||
<Card
|
||||
title={t('top_upstreams')}
|
||||
subtitle={subtitle}
|
||||
bodyType="card-table"
|
||||
refresh={refreshButton}
|
||||
>
|
||||
<ReactTable
|
||||
data={topUpstreamsResponses.map(({ name: domain, count }: { name: string; count: number }) => ({
|
||||
data={topUpstreamsResponses.map(({ name: domain, count }) => ({
|
||||
domain,
|
||||
count,
|
||||
}))}
|
||||
@@ -67,4 +71,11 @@ const UpstreamResponses = ({ t, refreshButton, topUpstreamsResponses, subtitle }
|
||||
</Card>
|
||||
);
|
||||
|
||||
UpstreamResponses.propTypes = {
|
||||
topUpstreamsResponses: PropTypes.array.isRequired,
|
||||
refreshButton: PropTypes.node.isRequired,
|
||||
subtitle: PropTypes.string.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(UpstreamResponses);
|
||||
276
client/src/components/Dashboard/index.js
Normal file
276
client/src/components/Dashboard/index.js
Normal file
@@ -0,0 +1,276 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { HashLink as Link } from 'react-router-hash-link';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import Statistics from './Statistics';
|
||||
import Counters from './Counters';
|
||||
import Clients from './Clients';
|
||||
import QueriedDomains from './QueriedDomains';
|
||||
import BlockedDomains from './BlockedDomains';
|
||||
import {
|
||||
DISABLE_PROTECTION_TIMINGS,
|
||||
ONE_SECOND_IN_MS,
|
||||
SETTINGS_URLS,
|
||||
TIME_UNITS,
|
||||
} from '../../helpers/constants';
|
||||
import {
|
||||
msToSeconds,
|
||||
msToMinutes,
|
||||
msToHours,
|
||||
msToDays,
|
||||
} from '../../helpers/helpers';
|
||||
|
||||
import PageTitle from '../ui/PageTitle';
|
||||
import Loading from '../ui/Loading';
|
||||
import './Dashboard.css';
|
||||
import Dropdown from '../ui/Dropdown';
|
||||
import UpstreamResponses from './UpstreamResponses';
|
||||
import UpstreamAvgTime from './UpstreamAvgTime';
|
||||
|
||||
const Dashboard = ({
|
||||
getAccessList,
|
||||
getStats,
|
||||
getStatsConfig,
|
||||
dashboard,
|
||||
dashboard: { protectionEnabled, processingProtection, protectionDisabledDuration },
|
||||
toggleProtection,
|
||||
stats,
|
||||
access,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getAllStats = () => {
|
||||
getAccessList();
|
||||
getStats();
|
||||
getStatsConfig();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getAllStats();
|
||||
}, []);
|
||||
const getSubtitle = () => {
|
||||
if (!stats.enabled) {
|
||||
return t('stats_disabled_short');
|
||||
}
|
||||
|
||||
const msIn7Days = 604800000;
|
||||
|
||||
if (stats.timeUnits === TIME_UNITS.HOURS && stats.interval === msIn7Days) {
|
||||
return t('for_last_days', { count: msToDays(stats.interval) });
|
||||
}
|
||||
|
||||
return stats.timeUnits === TIME_UNITS.HOURS
|
||||
? t('for_last_hours', { count: msToHours(stats.interval) })
|
||||
: t('for_last_days', { count: msToDays(stats.interval) });
|
||||
};
|
||||
|
||||
const buttonClass = classNames('btn btn-sm dashboard-protection-button', {
|
||||
'btn-gray': protectionEnabled,
|
||||
'btn-success': !protectionEnabled,
|
||||
});
|
||||
|
||||
const refreshButton = <button
|
||||
type="button"
|
||||
className="btn btn-icon btn-outline-primary btn-sm"
|
||||
title={t('refresh_btn')}
|
||||
onClick={() => getAllStats()}
|
||||
>
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#refresh" />
|
||||
</svg>
|
||||
</button>;
|
||||
|
||||
const statsProcessing = stats.processingStats
|
||||
|| stats.processingGetConfig
|
||||
|| access.processing;
|
||||
|
||||
const subtitle = getSubtitle();
|
||||
|
||||
const DISABLE_PROTECTION_ITEMS = [
|
||||
{
|
||||
text: t('disable_for_seconds', { count: msToSeconds(DISABLE_PROTECTION_TIMINGS.HALF_MINUTE) }),
|
||||
disableTime: DISABLE_PROTECTION_TIMINGS.HALF_MINUTE,
|
||||
},
|
||||
{
|
||||
text: t('disable_for_minutes', { count: msToMinutes(DISABLE_PROTECTION_TIMINGS.MINUTE) }),
|
||||
disableTime: DISABLE_PROTECTION_TIMINGS.MINUTE,
|
||||
},
|
||||
{
|
||||
text: t('disable_for_minutes', { count: msToMinutes(DISABLE_PROTECTION_TIMINGS.TEN_MINUTES) }),
|
||||
disableTime: DISABLE_PROTECTION_TIMINGS.TEN_MINUTES,
|
||||
},
|
||||
{
|
||||
text: t('disable_for_hours', { count: msToHours(DISABLE_PROTECTION_TIMINGS.HOUR) }),
|
||||
disableTime: DISABLE_PROTECTION_TIMINGS.HOUR,
|
||||
},
|
||||
{
|
||||
text: t('disable_until_tomorrow'),
|
||||
disableTime: DISABLE_PROTECTION_TIMINGS.TOMORROW,
|
||||
},
|
||||
];
|
||||
|
||||
const getDisableProtectionItems = () => (
|
||||
Object.values(DISABLE_PROTECTION_ITEMS)
|
||||
.map((item, index) => (
|
||||
<div
|
||||
key={`disable_timings_${index}`}
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
toggleProtection(protectionEnabled, item.disableTime - ONE_SECOND_IN_MS);
|
||||
}}
|
||||
>
|
||||
{item.text}
|
||||
</div>
|
||||
))
|
||||
);
|
||||
|
||||
const getRemaningTimeText = (milliseconds) => {
|
||||
if (!milliseconds) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const date = new Date(milliseconds);
|
||||
const hh = date.getUTCHours();
|
||||
const mm = `0${date.getUTCMinutes()}`.slice(-2);
|
||||
const ss = `0${date.getUTCSeconds()}`.slice(-2);
|
||||
const formattedHH = `0${hh}`.slice(-2);
|
||||
|
||||
return hh ? `${formattedHH}:${mm}:${ss}` : `${mm}:${ss}`;
|
||||
};
|
||||
|
||||
const getProtectionBtnText = (status) => (status ? t('disable_protection') : t('enable_protection'));
|
||||
|
||||
return <>
|
||||
<PageTitle title={t('dashboard')} containerClass="page-title--dashboard">
|
||||
<div className="page-title__protection">
|
||||
<button
|
||||
type="button"
|
||||
className={buttonClass}
|
||||
onClick={() => {
|
||||
toggleProtection(protectionEnabled);
|
||||
}}
|
||||
disabled={processingProtection}
|
||||
>
|
||||
{protectionDisabledDuration
|
||||
? `${t('enable_protection_timer')} ${getRemaningTimeText(protectionDisabledDuration)}`
|
||||
: getProtectionBtnText(protectionEnabled)
|
||||
}
|
||||
</button>
|
||||
|
||||
{protectionEnabled && <Dropdown
|
||||
label=""
|
||||
baseClassName="dropdown-protection"
|
||||
icon="arrow-down"
|
||||
controlClassName="dropdown-protection__toggle"
|
||||
menuClassName="dropdown-menu dropdown-menu-arrow dropdown-menu--protection"
|
||||
>
|
||||
{getDisableProtectionItems()}
|
||||
</Dropdown>}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-primary btn-sm"
|
||||
onClick={getAllStats}
|
||||
>
|
||||
<Trans>refresh_statics</Trans>
|
||||
</button>
|
||||
</PageTitle>
|
||||
{statsProcessing && <Loading />}
|
||||
{!statsProcessing && <div className="row row-cards dashboard">
|
||||
<div className="col-lg-12">
|
||||
{stats.interval === 0 && (
|
||||
<div className="alert alert-warning" role="alert">
|
||||
<Trans components={[
|
||||
<Link
|
||||
to={`${SETTINGS_URLS.settings}#stats-config`}
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</Link>,
|
||||
]}>
|
||||
stats_disabled
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
<Statistics
|
||||
interval={msToDays(stats.interval)}
|
||||
dnsQueries={stats.dnsQueries}
|
||||
blockedFiltering={stats.blockedFiltering}
|
||||
replacedSafebrowsing={stats.replacedSafebrowsing}
|
||||
replacedParental={stats.replacedParental}
|
||||
numDnsQueries={stats.numDnsQueries}
|
||||
numBlockedFiltering={stats.numBlockedFiltering}
|
||||
numReplacedSafebrowsing={stats.numReplacedSafebrowsing}
|
||||
numReplacedParental={stats.numReplacedParental}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<Counters
|
||||
subtitle={subtitle}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<Clients
|
||||
subtitle={subtitle}
|
||||
dnsQueries={stats.numDnsQueries}
|
||||
topClients={stats.topClients}
|
||||
clients={dashboard.clients}
|
||||
autoClients={dashboard.autoClients}
|
||||
refreshButton={refreshButton}
|
||||
processingAccessSet={access.processingSet}
|
||||
disallowedClients={access.disallowed_clients}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<QueriedDomains
|
||||
subtitle={subtitle}
|
||||
dnsQueries={stats.numDnsQueries}
|
||||
topQueriedDomains={stats.topQueriedDomains}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<BlockedDomains
|
||||
subtitle={subtitle}
|
||||
topBlockedDomains={stats.topBlockedDomains}
|
||||
blockedFiltering={stats.numBlockedFiltering}
|
||||
replacedSafebrowsing={stats.numReplacedSafebrowsing}
|
||||
replacedSafesearch={stats.numReplacedSafesearch}
|
||||
replacedParental={stats.numReplacedParental}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<UpstreamResponses
|
||||
subtitle={subtitle}
|
||||
topUpstreamsResponses={stats.topUpstreamsResponses}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<UpstreamAvgTime
|
||||
subtitle={subtitle}
|
||||
topUpstreamsAvgTime={stats.topUpstreamsAvgTime}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
</div>}
|
||||
</>;
|
||||
};
|
||||
|
||||
Dashboard.propTypes = {
|
||||
dashboard: PropTypes.object.isRequired,
|
||||
stats: PropTypes.object.isRequired,
|
||||
access: PropTypes.object.isRequired,
|
||||
getStats: PropTypes.func.isRequired,
|
||||
getStatsConfig: PropTypes.func.isRequired,
|
||||
toggleProtection: PropTypes.func.isRequired,
|
||||
getClients: PropTypes.func.isRequired,
|
||||
getAccessList: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
@@ -1,260 +0,0 @@
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { HashLink as Link } from 'react-router-hash-link';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import Statistics from './Statistics';
|
||||
import Counters from './Counters';
|
||||
import Clients from './Clients';
|
||||
import QueriedDomains from './QueriedDomains';
|
||||
import BlockedDomains from './BlockedDomains';
|
||||
import { DISABLE_PROTECTION_TIMINGS, ONE_SECOND_IN_MS, SETTINGS_URLS, TIME_UNITS } from '../../helpers/constants';
|
||||
import { msToSeconds, msToMinutes, msToHours, msToDays } from '../../helpers/helpers';
|
||||
|
||||
import PageTitle from '../ui/PageTitle';
|
||||
|
||||
import Loading from '../ui/Loading';
|
||||
import './Dashboard.css';
|
||||
|
||||
import Dropdown from '../ui/Dropdown';
|
||||
import UpstreamResponses from './UpstreamResponses';
|
||||
|
||||
import UpstreamAvgTime from './UpstreamAvgTime';
|
||||
import { AccessData, DashboardData, StatsData } from '../../initialState';
|
||||
|
||||
interface DashboardProps {
|
||||
dashboard: DashboardData;
|
||||
stats: StatsData;
|
||||
access: AccessData;
|
||||
getStats: (...args: unknown[]) => unknown;
|
||||
getStatsConfig: (...args: unknown[]) => unknown;
|
||||
toggleProtection: (...args: unknown[]) => unknown;
|
||||
getClients: (...args: unknown[]) => unknown;
|
||||
getAccessList: () => (dispatch: any) => void;
|
||||
}
|
||||
|
||||
const Dashboard = ({
|
||||
getAccessList,
|
||||
getStats,
|
||||
getStatsConfig,
|
||||
dashboard: { protectionEnabled, processingProtection, protectionDisabledDuration },
|
||||
toggleProtection,
|
||||
stats,
|
||||
access,
|
||||
}: DashboardProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getAllStats = () => {
|
||||
getAccessList();
|
||||
getStats();
|
||||
getStatsConfig();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getAllStats();
|
||||
}, []);
|
||||
const getSubtitle = () => {
|
||||
if (!stats.enabled) {
|
||||
return t('stats_disabled_short');
|
||||
}
|
||||
|
||||
const msIn7Days = 604800000;
|
||||
|
||||
if (stats.timeUnits === TIME_UNITS.HOURS && stats.interval === msIn7Days) {
|
||||
return t('for_last_days', { count: msToDays(stats.interval) });
|
||||
}
|
||||
|
||||
return stats.timeUnits === TIME_UNITS.HOURS
|
||||
? t('for_last_hours', { count: msToHours(stats.interval) })
|
||||
: t('for_last_days', { count: msToDays(stats.interval) });
|
||||
};
|
||||
|
||||
const buttonClass = classNames('btn btn-sm dashboard-protection-button', {
|
||||
'btn-gray': protectionEnabled,
|
||||
'btn-success': !protectionEnabled,
|
||||
});
|
||||
|
||||
const refreshButton = (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-outline-primary btn-sm"
|
||||
title={t('refresh_btn')}
|
||||
onClick={() => getAllStats()}>
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#refresh" />
|
||||
</svg>
|
||||
</button>
|
||||
);
|
||||
|
||||
const statsProcessing = stats.processingStats || stats.processingGetConfig || access.processing;
|
||||
|
||||
const subtitle = getSubtitle();
|
||||
|
||||
const DISABLE_PROTECTION_ITEMS = [
|
||||
{
|
||||
text: t('disable_for_seconds', { count: msToSeconds(DISABLE_PROTECTION_TIMINGS.HALF_MINUTE) }),
|
||||
disableTime: DISABLE_PROTECTION_TIMINGS.HALF_MINUTE,
|
||||
},
|
||||
{
|
||||
text: t('disable_for_minutes', { count: msToMinutes(DISABLE_PROTECTION_TIMINGS.MINUTE) }),
|
||||
disableTime: DISABLE_PROTECTION_TIMINGS.MINUTE,
|
||||
},
|
||||
{
|
||||
text: t('disable_for_minutes', { count: msToMinutes(DISABLE_PROTECTION_TIMINGS.TEN_MINUTES) }),
|
||||
disableTime: DISABLE_PROTECTION_TIMINGS.TEN_MINUTES,
|
||||
},
|
||||
{
|
||||
text: t('disable_for_hours', { count: msToHours(DISABLE_PROTECTION_TIMINGS.HOUR) }),
|
||||
disableTime: DISABLE_PROTECTION_TIMINGS.HOUR,
|
||||
},
|
||||
{
|
||||
text: t('disable_until_tomorrow'),
|
||||
disableTime: DISABLE_PROTECTION_TIMINGS.TOMORROW,
|
||||
},
|
||||
];
|
||||
|
||||
const getDisableProtectionItems = () =>
|
||||
Object.values(DISABLE_PROTECTION_ITEMS).map((item: any, index: any) => (
|
||||
<div
|
||||
key={`disable_timings_${index}`}
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
toggleProtection(protectionEnabled, item.disableTime - ONE_SECOND_IN_MS);
|
||||
}}>
|
||||
{item.text}
|
||||
</div>
|
||||
));
|
||||
|
||||
const getRemaningTimeText = (milliseconds: any) => {
|
||||
if (!milliseconds) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const date = new Date(milliseconds);
|
||||
const hh = date.getUTCHours();
|
||||
const mm = `0${date.getUTCMinutes()}`.slice(-2);
|
||||
const ss = `0${date.getUTCSeconds()}`.slice(-2);
|
||||
const formattedHH = `0${hh}`.slice(-2);
|
||||
|
||||
return hh ? `${formattedHH}:${mm}:${ss}` : `${mm}:${ss}`;
|
||||
};
|
||||
|
||||
const getProtectionBtnText = (status: any) => (status ? t('disable_protection') : t('enable_protection'));
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={t('dashboard')} containerClass="page-title--dashboard">
|
||||
<div className="page-title__protection">
|
||||
<button
|
||||
type="button"
|
||||
className={buttonClass}
|
||||
onClick={() => {
|
||||
toggleProtection(protectionEnabled);
|
||||
}}
|
||||
disabled={processingProtection}>
|
||||
{protectionDisabledDuration
|
||||
? `${t('enable_protection_timer', { time: getRemaningTimeText(protectionDisabledDuration) })}`
|
||||
: getProtectionBtnText(protectionEnabled)}
|
||||
</button>
|
||||
|
||||
{protectionEnabled && (
|
||||
<Dropdown
|
||||
label=""
|
||||
baseClassName="dropdown-protection"
|
||||
icon="arrow-down"
|
||||
controlClassName="dropdown-protection__toggle"
|
||||
menuClassName="dropdown-menu dropdown-menu-arrow dropdown-menu--protection">
|
||||
{getDisableProtectionItems()}
|
||||
</Dropdown>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button type="button" className="btn btn-outline-primary btn-sm" onClick={getAllStats}>
|
||||
<Trans>refresh_statics</Trans>
|
||||
</button>
|
||||
</PageTitle>
|
||||
|
||||
{statsProcessing && <Loading />}
|
||||
|
||||
{!statsProcessing && (
|
||||
<div className="row row-cards dashboard">
|
||||
<div className="col-lg-12">
|
||||
{stats.interval === 0 && (
|
||||
<div className="alert alert-warning" role="alert">
|
||||
<Trans
|
||||
components={[
|
||||
<Link to={`${SETTINGS_URLS.settings}#stats-config`} key="0">
|
||||
link
|
||||
</Link>,
|
||||
]}>
|
||||
stats_disabled
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Statistics
|
||||
interval={msToDays(stats.interval)}
|
||||
dnsQueries={stats.dnsQueries}
|
||||
blockedFiltering={stats.blockedFiltering}
|
||||
replacedSafebrowsing={stats.replacedSafebrowsing}
|
||||
replacedParental={stats.replacedParental}
|
||||
numDnsQueries={stats.numDnsQueries}
|
||||
numBlockedFiltering={stats.numBlockedFiltering}
|
||||
numReplacedSafebrowsing={stats.numReplacedSafebrowsing}
|
||||
numReplacedParental={stats.numReplacedParental}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-lg-6">
|
||||
<Counters subtitle={subtitle} refreshButton={refreshButton} />
|
||||
</div>
|
||||
|
||||
<div className="col-lg-6">
|
||||
<Clients subtitle={subtitle} refreshButton={refreshButton} />
|
||||
</div>
|
||||
|
||||
<div className="col-lg-6">
|
||||
<QueriedDomains
|
||||
subtitle={subtitle}
|
||||
dnsQueries={stats.numDnsQueries}
|
||||
topQueriedDomains={stats.topQueriedDomains}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-lg-6">
|
||||
<BlockedDomains
|
||||
subtitle={subtitle}
|
||||
topBlockedDomains={stats.topBlockedDomains}
|
||||
blockedFiltering={stats.numBlockedFiltering}
|
||||
replacedSafebrowsing={stats.numReplacedSafebrowsing}
|
||||
replacedSafesearch={stats.numReplacedSafesearch}
|
||||
replacedParental={stats.numReplacedParental}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-lg-6">
|
||||
<UpstreamResponses
|
||||
subtitle={subtitle}
|
||||
topUpstreamsResponses={stats.topUpstreamsResponses}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-lg-6">
|
||||
<UpstreamAvgTime
|
||||
subtitle={subtitle}
|
||||
topUpstreamsAvgTime={stats.topUpstreamsAvgTime}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
32
client/src/components/Filters/Actions.js
Normal file
32
client/src/components/Filters/Actions.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTranslation, Trans } from 'react-i18next';
|
||||
|
||||
const Actions = ({
|
||||
handleAdd, handleRefresh, processingRefreshFilters, whitelist,
|
||||
}) => <div className="card-actions">
|
||||
<button
|
||||
className="btn btn-success btn-standard mr-2 btn-large mb-2"
|
||||
type="submit"
|
||||
onClick={handleAdd}
|
||||
>
|
||||
{whitelist ? <Trans>add_allowlist</Trans> : <Trans>add_blocklist</Trans>}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-primary btn-standard mb-2"
|
||||
type="submit"
|
||||
onClick={handleRefresh}
|
||||
disabled={processingRefreshFilters}
|
||||
>
|
||||
<Trans>check_updates_btn</Trans>
|
||||
</button>
|
||||
</div>;
|
||||
|
||||
Actions.propTypes = {
|
||||
handleAdd: PropTypes.func.isRequired,
|
||||
handleRefresh: PropTypes.func.isRequired,
|
||||
processingRefreshFilters: PropTypes.bool.isRequired,
|
||||
whitelist: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default withTranslation()(Actions);
|
||||
@@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import { withTranslation, Trans } from 'react-i18next';
|
||||
|
||||
interface ActionsProps {
|
||||
handleAdd: (...args: unknown[]) => unknown;
|
||||
handleRefresh: (...args: unknown[]) => unknown;
|
||||
processingRefreshFilters: boolean;
|
||||
whitelist?: boolean;
|
||||
}
|
||||
|
||||
const Actions = ({ handleAdd, handleRefresh, processingRefreshFilters, whitelist }: ActionsProps) => (
|
||||
<div className="card-actions">
|
||||
<button className="btn btn-success btn-standard mr-2 btn-large mb-2" type="submit" onClick={handleAdd}>
|
||||
{whitelist ? <Trans>add_allowlist</Trans> : <Trans>add_blocklist</Trans>}
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="btn btn-primary btn-standard mb-2"
|
||||
type="submit"
|
||||
onClick={handleRefresh}
|
||||
disabled={processingRefreshFilters}>
|
||||
<Trans>check_updates_btn</Trans>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default withTranslation()(Actions);
|
||||
@@ -15,12 +15,10 @@ import {
|
||||
getRulesToFilterList,
|
||||
} from '../../../helpers/helpers';
|
||||
import { BLOCK_ACTIONS, FILTERED, FILTERED_STATUS } from '../../../helpers/constants';
|
||||
|
||||
import { toggleBlocking } from '../../../actions';
|
||||
import { RootState } from '../../../initialState';
|
||||
|
||||
const renderBlockingButton = (isFiltered: any, domain: any) => {
|
||||
const processingRules = useSelector((state: RootState) => state.filtering.processingRules);
|
||||
const renderBlockingButton = (isFiltered, domain) => {
|
||||
const processingRules = useSelector((state) => state.filtering.processingRules);
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -30,32 +28,28 @@ const renderBlockingButton = (isFiltered: any, domain: any) => {
|
||||
await dispatch(toggleBlocking(buttonType, domain));
|
||||
};
|
||||
|
||||
const buttonClass = classNames(
|
||||
'mt-3 button-action button-action--main button-action--active button-action--small',
|
||||
{
|
||||
'button-action--unblock': isFiltered,
|
||||
},
|
||||
);
|
||||
const buttonClass = classNames('mt-3 button-action button-action--main button-action--active button-action--small', {
|
||||
'button-action--unblock': isFiltered,
|
||||
});
|
||||
|
||||
return (
|
||||
<button type="button" className={buttonClass} onClick={onClick} disabled={processingRules}>
|
||||
return <button type="button"
|
||||
className={buttonClass}
|
||||
onClick={onClick}
|
||||
disabled={processingRules}
|
||||
>
|
||||
{t(buttonType)}
|
||||
</button>
|
||||
);
|
||||
</button>;
|
||||
};
|
||||
|
||||
const getTitle = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const filters = useSelector((state: RootState) => state.filtering.filters, shallowEqual);
|
||||
const filters = useSelector((state) => state.filtering.filters, shallowEqual);
|
||||
const whitelistFilters = useSelector((state) => state.filtering.whitelistFilters, shallowEqual);
|
||||
const rules = useSelector((state) => state.filtering.check.rules, shallowEqual);
|
||||
const reason = useSelector((state) => state.filtering.check.reason);
|
||||
|
||||
const whitelistFilters = useSelector((state: RootState) => state.filtering.whitelistFilters, shallowEqual);
|
||||
|
||||
const rules = useSelector((state: RootState) => state.filtering.check.rules, shallowEqual);
|
||||
|
||||
const reason = useSelector((state: RootState) => state.filtering.check.reason);
|
||||
|
||||
const getReasonFiltered = (reason: any) => {
|
||||
const getReasonFiltered = (reason) => {
|
||||
const filterKey = reason.replace(FILTERED, '');
|
||||
return i18next.t('query_log_filtered', { filter: filterKey });
|
||||
};
|
||||
@@ -77,23 +71,24 @@ const getTitle = () => {
|
||||
return REASON_TO_TITLE_MAP[reason];
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>{t('check_reason', { reason })}</div>
|
||||
|
||||
<div>
|
||||
{t('rule_label')}:
|
||||
{ruleAndFilterNames}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
return <>
|
||||
<div>{t('check_reason', { reason })}</div>
|
||||
<div>
|
||||
{t('rule_label')}:
|
||||
|
||||
{ruleAndFilterNames}
|
||||
</div>
|
||||
</>;
|
||||
};
|
||||
|
||||
const Info = () => {
|
||||
const { hostname, reason, service_name, cname, ip_addrs } = useSelector(
|
||||
(state: RootState) => state.filtering.check,
|
||||
shallowEqual,
|
||||
);
|
||||
const {
|
||||
hostname,
|
||||
reason,
|
||||
service_name,
|
||||
cname,
|
||||
ip_addrs,
|
||||
} = useSelector((state) => state.filtering.check, shallowEqual);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const title = getTitle();
|
||||
@@ -104,29 +99,23 @@ const Info = () => {
|
||||
'logs__row--green': checkWhiteList(reason),
|
||||
});
|
||||
|
||||
const onlyFiltered = checkSafeSearch(reason) || checkSafeBrowsing(reason) || checkParental(reason);
|
||||
const onlyFiltered = checkSafeSearch(reason)
|
||||
|| checkSafeBrowsing(reason)
|
||||
|| checkParental(reason);
|
||||
|
||||
const isFiltered = checkFiltered(reason);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div>
|
||||
<strong>{hostname}</strong>
|
||||
</div>
|
||||
|
||||
<div>{title}</div>
|
||||
{!onlyFiltered && (
|
||||
<>
|
||||
{service_name && <div>{t('check_service', { service: service_name })}</div>}
|
||||
|
||||
{cname && <div>{t('check_cname', { cname })}</div>}
|
||||
|
||||
{ip_addrs && <div>{t('check_ip', { ip: ip_addrs.join(', ') })}</div>}
|
||||
{renderBlockingButton(isFiltered, hostname)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
return <div className={className}>
|
||||
<div><strong>{hostname}</strong></div>
|
||||
<div>{title}</div>
|
||||
{!onlyFiltered
|
||||
&& <>
|
||||
{service_name && <div>{t('check_service', { service: service_name })}</div>}
|
||||
{cname && <div>{t('check_cname', { cname })}</div>}
|
||||
{ip_addrs && <div>{t('check_ip', { ip: ip_addrs.join(', ') })}</div>}
|
||||
{renderBlockingButton(isFiltered, hostname)}
|
||||
</>}
|
||||
</div>;
|
||||
};
|
||||
|
||||
export default Info;
|
||||
66
client/src/components/Filters/Check/index.js
Normal file
66
client/src/components/Filters/Check/index.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Card from '../../ui/Card';
|
||||
import { renderInputField } from '../../../helpers/form';
|
||||
import Info from './Info';
|
||||
import { FORM_NAME } from '../../../helpers/constants';
|
||||
|
||||
const Check = (props) => {
|
||||
const {
|
||||
pristine,
|
||||
invalid,
|
||||
handleSubmit,
|
||||
} = props;
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const processingCheck = useSelector((state) => state.filtering.processingCheck);
|
||||
const hostname = useSelector((state) => state.filtering.check.hostname);
|
||||
|
||||
return <Card
|
||||
title={t('check_title')}
|
||||
subtitle={t('check_desc')}
|
||||
>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="row">
|
||||
<div className="col-12 col-md-6">
|
||||
<div className="input-group">
|
||||
<Field
|
||||
id="name"
|
||||
name="name"
|
||||
component={renderInputField}
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder={t('form_enter_host')}
|
||||
/>
|
||||
<span className="input-group-append">
|
||||
<button
|
||||
className="btn btn-success btn-standard btn-large"
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
disabled={pristine || invalid || processingCheck}
|
||||
>
|
||||
{t('check')}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
{hostname && <>
|
||||
<hr />
|
||||
<Info />
|
||||
</>}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Card>;
|
||||
};
|
||||
|
||||
Check.propTypes = {
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
pristine: PropTypes.bool.isRequired,
|
||||
invalid: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default reduxForm({ form: FORM_NAME.DOMAIN_CHECK })(Check);
|
||||
@@ -1,70 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import Card from '../../ui/Card';
|
||||
|
||||
import { renderInputField } from '../../../helpers/form';
|
||||
|
||||
import Info from './Info';
|
||||
import { FORM_NAME } from '../../../helpers/constants';
|
||||
import { RootState } from '../../../initialState';
|
||||
|
||||
interface CheckProps {
|
||||
handleSubmit: (...args: unknown[]) => string;
|
||||
pristine: boolean;
|
||||
invalid: boolean;
|
||||
}
|
||||
|
||||
const Check = (props: CheckProps) => {
|
||||
const { pristine, invalid, handleSubmit } = props;
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const processingCheck = useSelector((state: RootState) => state.filtering.processingCheck);
|
||||
|
||||
const hostname = useSelector((state: RootState) => state.filtering.check.hostname);
|
||||
|
||||
return (
|
||||
<Card title={t('check_title')} subtitle={t('check_desc')}>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="row">
|
||||
<div className="col-12 col-md-6">
|
||||
<div className="input-group">
|
||||
<Field
|
||||
id="name"
|
||||
name="name"
|
||||
component={renderInputField}
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder={t('form_enter_host')}
|
||||
/>
|
||||
|
||||
<span className="input-group-append">
|
||||
<button
|
||||
className="btn btn-success btn-standard btn-large"
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
disabled={pristine || invalid || processingCheck}>
|
||||
{t('check')}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{hostname && (
|
||||
<>
|
||||
<hr />
|
||||
|
||||
<Info />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default reduxForm({ form: FORM_NAME.DOMAIN_CHECK })(Check);
|
||||
@@ -1,46 +1,32 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
|
||||
import Card from '../ui/Card';
|
||||
|
||||
import PageTitle from '../ui/PageTitle';
|
||||
|
||||
import Examples from './Examples';
|
||||
|
||||
import Check from './Check';
|
||||
|
||||
import { getTextareaCommentsHighlight, syncScroll } from '../../helpers/highlightTextareaComments';
|
||||
import { COMMENT_LINE_DEFAULT_TOKEN } from '../../helpers/constants';
|
||||
import '../ui/texareaCommentsHighlight.css';
|
||||
import { FilteringData } from '../../initialState';
|
||||
|
||||
interface CustomRulesProps {
|
||||
filtering: FilteringData;
|
||||
setRules: (...args: unknown[]) => unknown;
|
||||
checkHost: (...args: unknown[]) => string;
|
||||
getFilteringStatus: (...args: unknown[]) => unknown;
|
||||
handleRulesChange: (...args: unknown[]) => unknown;
|
||||
t: (...args: unknown[]) => string;
|
||||
}
|
||||
|
||||
class CustomRules extends Component<CustomRulesProps> {
|
||||
class CustomRules extends Component {
|
||||
ref = React.createRef();
|
||||
|
||||
componentDidMount() {
|
||||
this.props.getFilteringStatus();
|
||||
}
|
||||
|
||||
handleChange = (e: any) => {
|
||||
handleChange = (e) => {
|
||||
const { value } = e.currentTarget;
|
||||
this.handleRulesChange(value);
|
||||
};
|
||||
|
||||
handleSubmit = (e: any) => {
|
||||
handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
this.handleRulesSubmit();
|
||||
};
|
||||
|
||||
handleRulesChange = (value: any) => {
|
||||
handleRulesChange = (value) => {
|
||||
this.props.handleRulesChange({ userRules: value });
|
||||
};
|
||||
|
||||
@@ -48,22 +34,23 @@ class CustomRules extends Component<CustomRulesProps> {
|
||||
this.props.setRules(this.props.filtering.userRules);
|
||||
};
|
||||
|
||||
handleCheck = (values: any) => {
|
||||
handleCheck = (values) => {
|
||||
this.props.checkHost(values);
|
||||
};
|
||||
|
||||
onScroll = (e: any) => syncScroll(e, this.ref);
|
||||
onScroll = (e) => syncScroll(e, this.ref)
|
||||
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
filtering: { userRules },
|
||||
filtering: {
|
||||
userRules,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={t('custom_filtering_rules')} />
|
||||
|
||||
<Card subtitle={t('custom_filter_rules_hint')}>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className="text-edit-container mb-4">
|
||||
@@ -73,31 +60,39 @@ class CustomRules extends Component<CustomRulesProps> {
|
||||
onChange={this.handleChange}
|
||||
onScroll={this.onScroll}
|
||||
/>
|
||||
{getTextareaCommentsHighlight(this.ref, userRules, [
|
||||
COMMENT_LINE_DEFAULT_TOKEN,
|
||||
'!',
|
||||
])}
|
||||
{getTextareaCommentsHighlight(
|
||||
this.ref,
|
||||
userRules,
|
||||
undefined,
|
||||
[COMMENT_LINE_DEFAULT_TOKEN, '!'],
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="card-actions">
|
||||
<button
|
||||
className="btn btn-success btn-standard btn-large"
|
||||
type="submit"
|
||||
onClick={this.handleSubmit}>
|
||||
onClick={this.handleSubmit}
|
||||
>
|
||||
<Trans>apply_btn</Trans>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<hr />
|
||||
|
||||
<Examples />
|
||||
</Card>
|
||||
|
||||
<Check onSubmit={this.handleCheck} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CustomRules.propTypes = {
|
||||
filtering: PropTypes.object.isRequired,
|
||||
setRules: PropTypes.func.isRequired,
|
||||
checkHost: PropTypes.func.isRequired,
|
||||
getFilteringStatus: PropTypes.func.isRequired,
|
||||
handleRulesChange: PropTypes.func.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(CustomRules);
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
|
||||
import PageTitle from '../ui/PageTitle';
|
||||
@@ -8,41 +9,15 @@ import Actions from './Actions';
|
||||
import Table from './Table';
|
||||
|
||||
import { MODAL_TYPE } from '../../helpers/constants';
|
||||
|
||||
import { getCurrentFilter } from '../../helpers/helpers';
|
||||
|
||||
interface DnsAllowlistProps {
|
||||
getFilteringStatus: (...args: unknown[]) => unknown;
|
||||
filtering: {
|
||||
modalType: string;
|
||||
modalFilterUrl: string;
|
||||
isModalOpen: boolean;
|
||||
isFilterAdded: boolean;
|
||||
processingRefreshFilters: boolean;
|
||||
processingRemoveFilter: boolean;
|
||||
processingAddFilter: boolean;
|
||||
processingConfigFilter: boolean;
|
||||
processingFilters: boolean;
|
||||
whitelistFilters: any[];
|
||||
};
|
||||
removeFilter: (...args: unknown[]) => unknown;
|
||||
toggleFilterStatus: (...args: unknown[]) => unknown;
|
||||
addFilter: (...args: unknown[]) => unknown;
|
||||
toggleFilteringModal: (...args: unknown[]) => unknown;
|
||||
handleRulesChange: (...args: unknown[]) => unknown;
|
||||
refreshFilters: (...args: unknown[]) => unknown;
|
||||
editFilter: (...args: unknown[]) => unknown;
|
||||
t: (...args: unknown[]) => string;
|
||||
}
|
||||
|
||||
class DnsAllowlist extends Component<DnsAllowlistProps> {
|
||||
class DnsAllowlist extends Component {
|
||||
componentDidMount() {
|
||||
this.props.getFilteringStatus();
|
||||
}
|
||||
|
||||
handleSubmit = (values: any) => {
|
||||
handleSubmit = (values) => {
|
||||
const { name, url } = values;
|
||||
|
||||
const { filtering } = this.props;
|
||||
const whitelist = true;
|
||||
|
||||
@@ -53,17 +28,15 @@ class DnsAllowlist extends Component<DnsAllowlistProps> {
|
||||
}
|
||||
};
|
||||
|
||||
handleDelete = (url: any) => {
|
||||
handleDelete = (url) => {
|
||||
if (window.confirm(this.props.t('list_confirm_delete'))) {
|
||||
const whitelist = true;
|
||||
|
||||
this.props.removeFilter(url, whitelist);
|
||||
}
|
||||
};
|
||||
|
||||
toggleFilter = (url: any, data: any) => {
|
||||
toggleFilter = (url, data) => {
|
||||
const whitelist = true;
|
||||
|
||||
this.props.toggleFilterStatus(url, data, whitelist);
|
||||
};
|
||||
|
||||
@@ -80,6 +53,7 @@ class DnsAllowlist extends Component<DnsAllowlistProps> {
|
||||
t,
|
||||
toggleFilteringModal,
|
||||
addFilter,
|
||||
toggleFilterStatus,
|
||||
filtering: {
|
||||
whitelistFilters,
|
||||
isModalOpen,
|
||||
@@ -94,18 +68,19 @@ class DnsAllowlist extends Component<DnsAllowlistProps> {
|
||||
},
|
||||
} = this.props;
|
||||
const currentFilterData = getCurrentFilter(modalFilterUrl, whitelistFilters);
|
||||
const loading =
|
||||
processingConfigFilter ||
|
||||
processingFilters ||
|
||||
processingAddFilter ||
|
||||
processingRemoveFilter ||
|
||||
processingRefreshFilters;
|
||||
|
||||
const loading = processingConfigFilter
|
||||
|| processingFilters
|
||||
|| processingAddFilter
|
||||
|| processingRemoveFilter
|
||||
|| processingRefreshFilters;
|
||||
const whitelist = true;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={t('dns_allowlists')} subtitle={t('dns_allowlists_desc')} />
|
||||
<PageTitle
|
||||
title={t('dns_allowlists')}
|
||||
subtitle={t('dns_allowlists_desc')}
|
||||
/>
|
||||
<div className="content">
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
@@ -115,11 +90,11 @@ class DnsAllowlist extends Component<DnsAllowlistProps> {
|
||||
loading={loading}
|
||||
processingConfigFilter={processingConfigFilter}
|
||||
toggleFilteringModal={toggleFilteringModal}
|
||||
toggleFilterStatus={toggleFilterStatus}
|
||||
handleDelete={this.handleDelete}
|
||||
toggleFilter={this.toggleFilter}
|
||||
whitelist={whitelist}
|
||||
/>
|
||||
|
||||
<Actions
|
||||
handleAdd={this.openAddFiltersModal}
|
||||
handleRefresh={this.handleRefresh}
|
||||
@@ -130,7 +105,6 @@ class DnsAllowlist extends Component<DnsAllowlistProps> {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
filters={whitelistFilters}
|
||||
isOpen={isModalOpen}
|
||||
@@ -149,4 +123,17 @@ class DnsAllowlist extends Component<DnsAllowlistProps> {
|
||||
}
|
||||
}
|
||||
|
||||
DnsAllowlist.propTypes = {
|
||||
getFilteringStatus: PropTypes.func.isRequired,
|
||||
filtering: PropTypes.object.isRequired,
|
||||
removeFilter: PropTypes.func.isRequired,
|
||||
toggleFilterStatus: PropTypes.func.isRequired,
|
||||
addFilter: PropTypes.func.isRequired,
|
||||
toggleFilteringModal: PropTypes.func.isRequired,
|
||||
handleRulesChange: PropTypes.func.isRequired,
|
||||
refreshFilters: PropTypes.func.isRequired,
|
||||
editFilter: PropTypes.func.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(DnsAllowlist);
|
||||
@@ -1,38 +1,27 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
|
||||
import PageTitle from '../ui/PageTitle';
|
||||
|
||||
import Card from '../ui/Card';
|
||||
import Modal from './Modal';
|
||||
import Actions from './Actions';
|
||||
|
||||
import Table from './Table';
|
||||
import { MODAL_TYPE } from '../../helpers/constants';
|
||||
|
||||
import { getCurrentFilter } from '../../helpers/helpers';
|
||||
import {
|
||||
getCurrentFilter,
|
||||
} from '../../helpers/helpers';
|
||||
|
||||
import filtersCatalog from '../../helpers/filters/filters';
|
||||
import { FilteringData } from '../../initialState';
|
||||
|
||||
interface DnsBlocklistProps {
|
||||
getFilteringStatus: (...args: unknown[]) => unknown;
|
||||
filtering: FilteringData;
|
||||
removeFilter: (...args: unknown[]) => unknown;
|
||||
toggleFilterStatus: (...args: unknown[]) => unknown;
|
||||
addFilter: (...args: unknown[]) => unknown;
|
||||
toggleFilteringModal: (...args: unknown[]) => unknown;
|
||||
handleRulesChange: (...args: unknown[]) => unknown;
|
||||
refreshFilters: (...args: unknown[]) => unknown;
|
||||
editFilter: (...args: unknown[]) => unknown;
|
||||
t: (...args: unknown[]) => string;
|
||||
}
|
||||
|
||||
class DnsBlocklist extends Component<DnsBlocklistProps> {
|
||||
class DnsBlocklist extends Component {
|
||||
componentDidMount() {
|
||||
this.props.getFilteringStatus();
|
||||
}
|
||||
|
||||
handleSubmit = (values: any) => {
|
||||
handleSubmit = (values) => {
|
||||
const { modalFilterUrl, modalType } = this.props.filtering;
|
||||
|
||||
switch (modalType) {
|
||||
@@ -41,25 +30,23 @@ class DnsBlocklist extends Component<DnsBlocklistProps> {
|
||||
break;
|
||||
case MODAL_TYPE.ADD_FILTERS: {
|
||||
const { name, url } = values;
|
||||
|
||||
this.props.addFilter(url, name);
|
||||
break;
|
||||
}
|
||||
case MODAL_TYPE.CHOOSE_FILTERING_LIST: {
|
||||
const changedValues = Object.entries(values)?.reduce((acc: any, [key, value]) => {
|
||||
const changedValues = Object.entries(values)?.reduce((acc, [key, value]) => {
|
||||
if (value && key in filtersCatalog.filters) {
|
||||
acc[key] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
Object.keys(changedValues).forEach((fieldName) => {
|
||||
// filterId is actually in the field name
|
||||
|
||||
const { source, name } = filtersCatalog.filters[fieldName];
|
||||
|
||||
this.props.addFilter(source, name);
|
||||
});
|
||||
Object.keys(changedValues)
|
||||
.forEach((fieldName) => {
|
||||
// filterId is actually in the field name
|
||||
const { source, name } = filtersCatalog.filters[fieldName];
|
||||
this.props.addFilter(source, name);
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -67,13 +54,13 @@ class DnsBlocklist extends Component<DnsBlocklistProps> {
|
||||
}
|
||||
};
|
||||
|
||||
handleDelete = (url: any) => {
|
||||
handleDelete = (url) => {
|
||||
if (window.confirm(this.props.t('list_confirm_delete'))) {
|
||||
this.props.removeFilter(url);
|
||||
}
|
||||
};
|
||||
|
||||
toggleFilter = (url: any, data: any) => {
|
||||
toggleFilter = (url, data) => {
|
||||
this.props.toggleFilterStatus(url, data);
|
||||
};
|
||||
|
||||
@@ -88,11 +75,8 @@ class DnsBlocklist extends Component<DnsBlocklistProps> {
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
|
||||
toggleFilteringModal,
|
||||
|
||||
addFilter,
|
||||
|
||||
filtering: {
|
||||
filters,
|
||||
isModalOpen,
|
||||
@@ -107,17 +91,18 @@ class DnsBlocklist extends Component<DnsBlocklistProps> {
|
||||
},
|
||||
} = this.props;
|
||||
const currentFilterData = getCurrentFilter(modalFilterUrl, filters);
|
||||
const loading =
|
||||
processingConfigFilter ||
|
||||
processingFilters ||
|
||||
processingAddFilter ||
|
||||
processingRemoveFilter ||
|
||||
processingRefreshFilters;
|
||||
const loading = processingConfigFilter
|
||||
|| processingFilters
|
||||
|| processingAddFilter
|
||||
|| processingRemoveFilter
|
||||
|| processingRefreshFilters;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={t('dns_blocklists')} subtitle={t('dns_blocklists_desc')} />
|
||||
|
||||
<PageTitle
|
||||
title={t('dns_blocklists')}
|
||||
subtitle={t('dns_blocklists_desc')}
|
||||
/>
|
||||
<div className="content">
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
@@ -130,7 +115,6 @@ class DnsBlocklist extends Component<DnsBlocklistProps> {
|
||||
handleDelete={this.handleDelete}
|
||||
toggleFilter={this.toggleFilter}
|
||||
/>
|
||||
|
||||
<Actions
|
||||
handleAdd={this.openSelectTypeModal}
|
||||
handleRefresh={this.handleRefresh}
|
||||
@@ -140,7 +124,6 @@ class DnsBlocklist extends Component<DnsBlocklistProps> {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
filtersCatalog={filtersCatalog}
|
||||
filters={filters}
|
||||
@@ -159,4 +142,17 @@ class DnsBlocklist extends Component<DnsBlocklistProps> {
|
||||
}
|
||||
}
|
||||
|
||||
DnsBlocklist.propTypes = {
|
||||
getFilteringStatus: PropTypes.func.isRequired,
|
||||
filtering: PropTypes.object.isRequired,
|
||||
removeFilter: PropTypes.func.isRequired,
|
||||
toggleFilterStatus: PropTypes.func.isRequired,
|
||||
addFilter: PropTypes.func.isRequired,
|
||||
toggleFilteringModal: PropTypes.func.isRequired,
|
||||
handleRulesChange: PropTypes.func.isRequired,
|
||||
refreshFilters: PropTypes.func.isRequired,
|
||||
editFilter: PropTypes.func.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(DnsBlocklist);
|
||||
@@ -7,37 +7,31 @@ const Examples = () => (
|
||||
<Trans>examples_title</Trans>:
|
||||
<ol className="leading-loose">
|
||||
<li>
|
||||
<code>||example.org^</code>:<Trans>example_meaning_filter_block</Trans>
|
||||
<code>||example.org^</code>:
|
||||
<Trans>example_meaning_filter_block</Trans>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code> @@||example.org^</code>:<Trans>example_meaning_filter_whitelist</Trans>
|
||||
<code> @@||example.org^</code>:
|
||||
<Trans>example_meaning_filter_whitelist</Trans>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>127.0.0.1 example.org</code>:<Trans>example_meaning_host_block</Trans>
|
||||
<code>127.0.0.1 example.org</code>:
|
||||
<Trans>example_meaning_host_block</Trans>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>
|
||||
<Trans>example_comment</Trans>
|
||||
</code>
|
||||
:<Trans>example_comment_meaning</Trans>
|
||||
<code><Trans>example_comment</Trans></code>:
|
||||
<Trans>example_comment_meaning</Trans>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>
|
||||
<Trans>example_comment_hash</Trans>
|
||||
</code>
|
||||
:<Trans>example_comment_meaning</Trans>
|
||||
<code><Trans>example_comment_hash</Trans></code>:
|
||||
<Trans>example_comment_meaning</Trans>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>/REGEX/</code>:<Trans>example_regex_meaning</Trans>
|
||||
<code>/REGEX/</code>:
|
||||
<Trans>example_regex_meaning</Trans>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<p className="mt-1">
|
||||
<Trans
|
||||
components={[
|
||||
@@ -45,10 +39,12 @@ const Examples = () => (
|
||||
href="https://link.adtidy.org/forward.html?action=dns_kb_filtering_syntax&from=ui&app=home"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="0">
|
||||
key="0"
|
||||
>
|
||||
link
|
||||
</a>,
|
||||
]}>
|
||||
]}
|
||||
>
|
||||
filtering_rules_learn_more
|
||||
</Trans>
|
||||
</p>
|
||||
191
client/src/components/Filters/Form.js
Normal file
191
client/src/components/Filters/Form.js
Normal file
@@ -0,0 +1,191 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import flow from 'lodash/flow';
|
||||
import classNames from 'classnames';
|
||||
import { validatePath, validateRequiredValue } from '../../helpers/validators';
|
||||
import { CheckboxField, renderInputField } from '../../helpers/form';
|
||||
import { MODAL_OPEN_TIMEOUT, MODAL_TYPE, FORM_NAME } from '../../helpers/constants';
|
||||
import filtersCatalog from '../../helpers/filters/filters';
|
||||
|
||||
const getIconsData = (homepage, source) => ([
|
||||
{
|
||||
iconName: 'dashboard',
|
||||
href: homepage,
|
||||
className: 'ml-1',
|
||||
},
|
||||
{
|
||||
iconName: 'info',
|
||||
href: source,
|
||||
},
|
||||
]);
|
||||
|
||||
const renderIcons = (iconsData) => iconsData.map(({
|
||||
iconName,
|
||||
href,
|
||||
className = '',
|
||||
}) => <a key={iconName} href={href} target="_blank" rel="noopener noreferrer"
|
||||
className={classNames('d-flex align-items-center', className)}
|
||||
>
|
||||
<svg className="icon icon--15 mr-1 icon--gray">
|
||||
<use xlinkHref={`#${iconName}`} />
|
||||
</svg>
|
||||
</a>);
|
||||
|
||||
const renderCheckboxField = (
|
||||
props,
|
||||
) => <CheckboxField
|
||||
{...props}
|
||||
input={{
|
||||
...props.input,
|
||||
checked: props.disabled || props.input.checked,
|
||||
}}
|
||||
/>;
|
||||
|
||||
renderCheckboxField.propTypes = {
|
||||
// https://redux-form.com/8.3.0/docs/api/field.md/#props
|
||||
input: PropTypes.object.isRequired,
|
||||
disabled: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const renderFilters = ({ categories, filters }, selectedSources, t) => Object.keys(categories)
|
||||
.map((categoryId) => {
|
||||
const category = categories[categoryId];
|
||||
const categoryFilters = [];
|
||||
Object.keys(filters)
|
||||
.sort()
|
||||
.forEach((key) => {
|
||||
const filter = filters[key];
|
||||
filter.id = key;
|
||||
if (filter.categoryId === categoryId) {
|
||||
categoryFilters.push(filter);
|
||||
}
|
||||
});
|
||||
|
||||
return <div key={category.name} className="modal-body__item">
|
||||
<h6 className="font-weight-bold mb-1">{t(category.name)}</h6>
|
||||
<p className="mb-3">{t(category.description)}</p>
|
||||
{categoryFilters.map((filter) => {
|
||||
const { homepage, source, name } = filter;
|
||||
|
||||
const isSelected = Object.prototype.hasOwnProperty.call(selectedSources, source);
|
||||
|
||||
const iconsData = getIconsData(homepage, source);
|
||||
|
||||
return <div key={name} className="d-flex align-items-center pb-1">
|
||||
<Field
|
||||
name={filter.id}
|
||||
type="checkbox"
|
||||
component={renderCheckboxField}
|
||||
placeholder={t(name)}
|
||||
disabled={isSelected}
|
||||
/>
|
||||
{renderIcons(iconsData)}
|
||||
</div>;
|
||||
})}
|
||||
</div>;
|
||||
});
|
||||
|
||||
const Form = (props) => {
|
||||
const {
|
||||
t,
|
||||
closeModal,
|
||||
handleSubmit,
|
||||
processingAddFilter,
|
||||
processingConfigFilter,
|
||||
whitelist,
|
||||
modalType,
|
||||
toggleFilteringModal,
|
||||
selectedSources,
|
||||
} = props;
|
||||
|
||||
const openModal = (modalType, timeout = MODAL_OPEN_TIMEOUT) => {
|
||||
toggleFilteringModal();
|
||||
setTimeout(() => toggleFilteringModal({ type: modalType }), timeout);
|
||||
};
|
||||
|
||||
const openFilteringListModal = () => openModal(MODAL_TYPE.CHOOSE_FILTERING_LIST);
|
||||
|
||||
const openAddFiltersModal = () => openModal(MODAL_TYPE.ADD_FILTERS);
|
||||
|
||||
return <form onSubmit={handleSubmit}>
|
||||
<div className="modal-body modal-body--filters">
|
||||
{modalType === MODAL_TYPE.SELECT_MODAL_TYPE
|
||||
&& <div className="d-flex justify-content-around">
|
||||
<button onClick={openFilteringListModal}
|
||||
className="btn btn-success btn-standard mr-2 btn-large">
|
||||
{t('choose_from_list')}
|
||||
</button>
|
||||
<button onClick={openAddFiltersModal} className="btn btn-primary btn-standard">
|
||||
{t('add_custom_list')}
|
||||
</button>
|
||||
</div>}
|
||||
{modalType === MODAL_TYPE.CHOOSE_FILTERING_LIST
|
||||
&& renderFilters(filtersCatalog, selectedSources, t)}
|
||||
{modalType !== MODAL_TYPE.CHOOSE_FILTERING_LIST
|
||||
&& modalType !== MODAL_TYPE.SELECT_MODAL_TYPE
|
||||
&& <>
|
||||
<div className="form__group">
|
||||
<Field
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
component={renderInputField}
|
||||
className="form-control"
|
||||
placeholder={t('enter_name_hint')}
|
||||
normalizeOnBlur={(data) => data.trim()}
|
||||
/>
|
||||
</div>
|
||||
<div className="form__group">
|
||||
<Field
|
||||
id="url"
|
||||
name="url"
|
||||
type="text"
|
||||
component={renderInputField}
|
||||
className="form-control"
|
||||
placeholder={t('enter_url_or_path_hint')}
|
||||
validate={[validateRequiredValue, validatePath]}
|
||||
normalizeOnBlur={(data) => data.trim()}
|
||||
/>
|
||||
</div>
|
||||
<div className="form__description">
|
||||
{whitelist ? t('enter_valid_allowlist') : t('enter_valid_blocklist')}
|
||||
</div>
|
||||
</>}
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary"
|
||||
onClick={closeModal}
|
||||
>
|
||||
{t('cancel_btn')}
|
||||
</button>
|
||||
{modalType !== MODAL_TYPE.SELECT_MODAL_TYPE && <button
|
||||
type="submit"
|
||||
className="btn btn-success"
|
||||
disabled={processingAddFilter || processingConfigFilter}
|
||||
>
|
||||
{t('save_btn')}
|
||||
</button>}
|
||||
</div>
|
||||
</form>;
|
||||
};
|
||||
|
||||
Form.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
closeModal: PropTypes.func.isRequired,
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
processingAddFilter: PropTypes.bool.isRequired,
|
||||
processingConfigFilter: PropTypes.bool.isRequired,
|
||||
whitelist: PropTypes.bool,
|
||||
modalType: PropTypes.string.isRequired,
|
||||
toggleFilteringModal: PropTypes.func.isRequired,
|
||||
selectedSources: PropTypes.object,
|
||||
};
|
||||
|
||||
export default flow([
|
||||
withTranslation(),
|
||||
reduxForm({ form: FORM_NAME.FILTER }),
|
||||
])(Form);
|
||||
@@ -1,208 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import flow from 'lodash/flow';
|
||||
import classNames from 'classnames';
|
||||
import { validatePath, validateRequiredValue } from '../../helpers/validators';
|
||||
|
||||
import { CheckboxField, renderInputField } from '../../helpers/form';
|
||||
import { MODAL_OPEN_TIMEOUT, MODAL_TYPE, FORM_NAME } from '../../helpers/constants';
|
||||
import filtersCatalog from '../../helpers/filters/filters';
|
||||
|
||||
const getIconsData = (homepage: any, source: any) => [
|
||||
{
|
||||
iconName: 'dashboard',
|
||||
href: homepage,
|
||||
className: 'ml-1',
|
||||
},
|
||||
{
|
||||
iconName: 'info',
|
||||
href: source,
|
||||
},
|
||||
];
|
||||
|
||||
const renderIcons = (iconsData: any) =>
|
||||
iconsData.map(({ iconName, href, className = '' }: any) => (
|
||||
<a
|
||||
key={iconName}
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={classNames('d-flex align-items-center', className)}>
|
||||
<svg className="icon icon--15 mr-1 icon--gray">
|
||||
<use xlinkHref={`#${iconName}`} />
|
||||
</svg>
|
||||
</a>
|
||||
));
|
||||
|
||||
interface renderCheckboxFieldProps {
|
||||
// https://redux-form.com/8.3.0/docs/api/field.md/#props
|
||||
input: {
|
||||
name: string;
|
||||
value: string;
|
||||
checked: boolean;
|
||||
onChange: (...args: unknown[]) => unknown;
|
||||
};
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
const renderCheckboxField = (props: renderCheckboxFieldProps) => (
|
||||
<CheckboxField
|
||||
{...props}
|
||||
meta={{ touched: false, error: null }}
|
||||
input={{
|
||||
...props.input,
|
||||
checked: props.disabled || props.input.checked,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderFilters = ({ categories, filters }: any, selectedSources: any, t: any) =>
|
||||
Object.keys(categories).map((categoryId) => {
|
||||
const category = categories[categoryId];
|
||||
const categoryFilters: any = [];
|
||||
Object.keys(filters)
|
||||
.sort()
|
||||
.forEach((key) => {
|
||||
const filter = filters[key];
|
||||
filter.id = key;
|
||||
if (filter.categoryId === categoryId) {
|
||||
categoryFilters.push(filter);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div key={category.name} className="modal-body__item">
|
||||
<h6 className="font-weight-bold mb-1">{t(category.name)}</h6>
|
||||
|
||||
<p className="mb-3">{t(category.description)}</p>
|
||||
|
||||
{categoryFilters.map((filter) => {
|
||||
const { homepage, source, name } = filter;
|
||||
|
||||
const isSelected = Object.prototype.hasOwnProperty.call(selectedSources, source);
|
||||
|
||||
const iconsData = getIconsData(homepage, source);
|
||||
|
||||
return (
|
||||
<div key={name} className="d-flex align-items-center pb-1">
|
||||
<Field
|
||||
name={filter.id}
|
||||
type="checkbox"
|
||||
component={renderCheckboxField}
|
||||
placeholder={t(name)}
|
||||
disabled={isSelected}
|
||||
/>
|
||||
{renderIcons(iconsData)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
interface FormProps {
|
||||
t: (...args: unknown[]) => string;
|
||||
closeModal: (...args: unknown[]) => unknown;
|
||||
handleSubmit: (...args: unknown[]) => string;
|
||||
processingAddFilter: boolean;
|
||||
processingConfigFilter: boolean;
|
||||
whitelist?: boolean;
|
||||
modalType: string;
|
||||
toggleFilteringModal: (...args: unknown[]) => unknown;
|
||||
selectedSources?: object;
|
||||
}
|
||||
|
||||
const Form = (props: FormProps) => {
|
||||
const {
|
||||
t,
|
||||
closeModal,
|
||||
handleSubmit,
|
||||
processingAddFilter,
|
||||
processingConfigFilter,
|
||||
whitelist,
|
||||
modalType,
|
||||
toggleFilteringModal,
|
||||
selectedSources,
|
||||
} = props;
|
||||
|
||||
const openModal = (modalType: any, timeout = MODAL_OPEN_TIMEOUT) => {
|
||||
toggleFilteringModal();
|
||||
setTimeout(() => toggleFilteringModal({ type: modalType }), timeout);
|
||||
};
|
||||
|
||||
const openFilteringListModal = () => openModal(MODAL_TYPE.CHOOSE_FILTERING_LIST);
|
||||
|
||||
const openAddFiltersModal = () => openModal(MODAL_TYPE.ADD_FILTERS);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="modal-body modal-body--filters">
|
||||
{modalType === MODAL_TYPE.SELECT_MODAL_TYPE && (
|
||||
<div className="d-flex justify-content-around">
|
||||
<button
|
||||
onClick={openFilteringListModal}
|
||||
className="btn btn-success btn-standard mr-2 btn-large">
|
||||
{t('choose_from_list')}
|
||||
</button>
|
||||
|
||||
<button onClick={openAddFiltersModal} className="btn btn-primary btn-standard">
|
||||
{t('add_custom_list')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{modalType === MODAL_TYPE.CHOOSE_FILTERING_LIST && renderFilters(filtersCatalog, selectedSources, t)}
|
||||
{modalType !== MODAL_TYPE.CHOOSE_FILTERING_LIST && modalType !== MODAL_TYPE.SELECT_MODAL_TYPE && (
|
||||
<>
|
||||
<div className="form__group">
|
||||
<Field
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
component={renderInputField}
|
||||
className="form-control"
|
||||
placeholder={t('enter_name_hint')}
|
||||
normalizeOnBlur={(data: any) => data.trim()}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form__group">
|
||||
<Field
|
||||
id="url"
|
||||
name="url"
|
||||
type="text"
|
||||
component={renderInputField}
|
||||
className="form-control"
|
||||
placeholder={t('enter_url_or_path_hint')}
|
||||
validate={[validateRequiredValue, validatePath]}
|
||||
normalizeOnBlur={(data: any) => data.trim()}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form__description">
|
||||
{whitelist ? t('enter_valid_allowlist') : t('enter_valid_blocklist')}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn btn-secondary" onClick={closeModal}>
|
||||
{t('cancel_btn')}
|
||||
</button>
|
||||
|
||||
{modalType !== MODAL_TYPE.SELECT_MODAL_TYPE && (
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-success"
|
||||
disabled={processingAddFilter || processingConfigFilter}>
|
||||
{t('save_btn')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default flow([withTranslation(), reduxForm({ form: FORM_NAME.FILTER })])(Form);
|
||||
@@ -1,13 +1,11 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactModal from 'react-modal';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
|
||||
import { MODAL_TYPE } from '../../helpers/constants';
|
||||
|
||||
import Form from './Form';
|
||||
import '../ui/Modal.css';
|
||||
|
||||
import { getMap } from '../../helpers/helpers';
|
||||
|
||||
ReactModal.setAppElement('#root');
|
||||
@@ -27,7 +25,7 @@ const MODAL_TYPE_TO_TITLE_TYPE_MAP = {
|
||||
* @returns {'new_allowlist' | 'edit_allowlist' | 'choose_allowlist' |
|
||||
* 'new_blocklist' | 'edit_blocklist' | 'choose_blocklist' | null}
|
||||
*/
|
||||
const getTitle = (modalType: any, whitelist: any) => {
|
||||
const getTitle = (modalType, whitelist) => {
|
||||
const titleType = MODAL_TYPE_TO_TITLE_TYPE_MAP[modalType];
|
||||
if (!titleType) {
|
||||
return null;
|
||||
@@ -35,39 +33,19 @@ const getTitle = (modalType: any, whitelist: any) => {
|
||||
return `${titleType}_${whitelist ? 'allowlist' : 'blocklist'}`;
|
||||
};
|
||||
|
||||
const getSelectedValues = (filters: any, catalogSourcesToIdMap: any) =>
|
||||
filters.reduce(
|
||||
(acc: any, { url }: any) => {
|
||||
if (Object.prototype.hasOwnProperty.call(catalogSourcesToIdMap, url)) {
|
||||
const fieldId = `filter${catalogSourcesToIdMap[url]}`;
|
||||
acc.selectedFilterIds[fieldId] = true;
|
||||
acc.selectedSources[url] = true;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
selectedFilterIds: {},
|
||||
selectedSources: {},
|
||||
},
|
||||
);
|
||||
const getSelectedValues = (filters, catalogSourcesToIdMap) => filters.reduce((acc, { url }) => {
|
||||
if (Object.prototype.hasOwnProperty.call(catalogSourcesToIdMap, url)) {
|
||||
const fieldId = `filter${catalogSourcesToIdMap[url]}`;
|
||||
acc.selectedFilterIds[fieldId] = true;
|
||||
acc.selectedSources[url] = true;
|
||||
}
|
||||
return acc;
|
||||
}, {
|
||||
selectedFilterIds: {},
|
||||
selectedSources: {},
|
||||
});
|
||||
|
||||
interface ModalProps {
|
||||
toggleFilteringModal: (...args: unknown[]) => unknown;
|
||||
isOpen: boolean;
|
||||
addFilter: (...args: unknown[]) => unknown;
|
||||
isFilterAdded: boolean;
|
||||
processingAddFilter: boolean;
|
||||
processingConfigFilter: boolean;
|
||||
handleSubmit: (values: any) => void;
|
||||
modalType: string;
|
||||
currentFilterData: object;
|
||||
t: (...args: unknown[]) => string;
|
||||
whitelist?: boolean;
|
||||
filters: unknown[];
|
||||
filtersCatalog?: any;
|
||||
}
|
||||
|
||||
class Modal extends Component<ModalProps> {
|
||||
class Modal extends Component {
|
||||
closeModal = () => {
|
||||
this.props.toggleFilteringModal();
|
||||
};
|
||||
@@ -75,25 +53,15 @@ class Modal extends Component<ModalProps> {
|
||||
render() {
|
||||
const {
|
||||
isOpen,
|
||||
|
||||
processingAddFilter,
|
||||
|
||||
processingConfigFilter,
|
||||
|
||||
handleSubmit,
|
||||
|
||||
modalType,
|
||||
|
||||
currentFilterData,
|
||||
|
||||
whitelist,
|
||||
|
||||
toggleFilteringModal,
|
||||
|
||||
filters,
|
||||
|
||||
t,
|
||||
|
||||
filtersCatalog,
|
||||
} = this.props;
|
||||
|
||||
@@ -122,16 +90,15 @@ class Modal extends Component<ModalProps> {
|
||||
className="Modal__Bootstrap modal-dialog modal-dialog-centered"
|
||||
closeTimeoutMS={0}
|
||||
isOpen={isOpen}
|
||||
onRequestClose={this.closeModal}>
|
||||
onRequestClose={this.closeModal}
|
||||
>
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
{title && <h4 className="modal-title">{title}</h4>}
|
||||
|
||||
<button type="button" className="close" onClick={this.closeModal}>
|
||||
<span className="sr-only">Close</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Form
|
||||
selectedSources={selectedSources}
|
||||
initialValues={initialValues}
|
||||
@@ -149,4 +116,20 @@ class Modal extends Component<ModalProps> {
|
||||
}
|
||||
}
|
||||
|
||||
Modal.propTypes = {
|
||||
toggleFilteringModal: PropTypes.func.isRequired,
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
addFilter: PropTypes.func.isRequired,
|
||||
isFilterAdded: PropTypes.bool.isRequired,
|
||||
processingAddFilter: PropTypes.bool.isRequired,
|
||||
processingConfigFilter: PropTypes.bool.isRequired,
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
modalType: PropTypes.string.isRequired,
|
||||
currentFilterData: PropTypes.object.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
whitelist: PropTypes.bool,
|
||||
filters: PropTypes.array.isRequired,
|
||||
filtersCatalog: PropTypes.object,
|
||||
};
|
||||
|
||||
export default withTranslation()(Modal);
|
||||
@@ -1,26 +1,22 @@
|
||||
import React from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import flow from 'lodash/flow';
|
||||
|
||||
import { renderInputField } from '../../../helpers/form';
|
||||
import { validateAnswer, validateDomain, validateRequiredValue } from '../../../helpers/validators';
|
||||
import { FORM_NAME } from '../../../helpers/constants';
|
||||
|
||||
interface FormProps {
|
||||
pristine: boolean;
|
||||
handleSubmit: (...args: unknown[]) => string;
|
||||
reset: (...args: unknown[]) => string;
|
||||
toggleRewritesModal: (...args: unknown[]) => unknown;
|
||||
submitting: boolean;
|
||||
processingAdd: boolean;
|
||||
t: (...args: unknown[]) => string;
|
||||
initialValues?: object;
|
||||
}
|
||||
|
||||
const Form = (props: FormProps) => {
|
||||
const { t, handleSubmit, reset, pristine, submitting, toggleRewritesModal, processingAdd } = props;
|
||||
const Form = (props) => {
|
||||
const {
|
||||
t,
|
||||
handleSubmit,
|
||||
reset,
|
||||
pristine,
|
||||
submitting,
|
||||
toggleRewritesModal,
|
||||
processingAdd,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
@@ -39,19 +35,22 @@ const Form = (props: FormProps) => {
|
||||
validate={[validateRequiredValue, validateDomain]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Trans>examples_title</Trans>:
|
||||
<ol className="leading-loose">
|
||||
<li>
|
||||
<code>example.org</code> – <Trans>example_rewrite_domain</Trans>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>*.example.org</code> –
|
||||
<span>
|
||||
<Trans components={[<code key="0">text</code>]}>example_rewrite_wildcard</Trans>
|
||||
<Trans components={[<code key="0">text</code>]}>
|
||||
example_rewrite_wildcard
|
||||
</Trans>
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div className="form__group">
|
||||
<Field
|
||||
id="answer"
|
||||
@@ -64,15 +63,14 @@ const Form = (props: FormProps) => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
{['rewrite_ip_address', 'rewrite_domain_name', 'rewrite_A', 'rewrite_AAAA'].map((str) => (
|
||||
<li key={str}>
|
||||
<Trans components={[<code key="0">text</code>]}>{str}</Trans>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<ul>{['rewrite_ip_address',
|
||||
'rewrite_domain_name',
|
||||
'rewrite_A',
|
||||
'rewrite_AAAA']
|
||||
.map((str) => <li key={str}>
|
||||
<Trans components={[<code key="0">text</code>]}>{str}</Trans>
|
||||
</li>)
|
||||
}</ul>
|
||||
<div className="modal-footer">
|
||||
<div className="btn-list">
|
||||
<button
|
||||
@@ -82,14 +80,15 @@ const Form = (props: FormProps) => {
|
||||
onClick={() => {
|
||||
reset();
|
||||
toggleRewritesModal();
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<Trans>cancel_btn</Trans>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-success btn-standard"
|
||||
disabled={submitting || pristine || processingAdd}>
|
||||
disabled={submitting || pristine || processingAdd}
|
||||
>
|
||||
<Trans>save_btn</Trans>
|
||||
</button>
|
||||
</div>
|
||||
@@ -98,6 +97,17 @@ const Form = (props: FormProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
Form.propTypes = {
|
||||
pristine: PropTypes.bool.isRequired,
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
reset: PropTypes.func.isRequired,
|
||||
toggleRewritesModal: PropTypes.func.isRequired,
|
||||
submitting: PropTypes.bool.isRequired,
|
||||
processingAdd: PropTypes.bool.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
initialValues: PropTypes.object,
|
||||
};
|
||||
|
||||
export default flow([
|
||||
withTranslation(),
|
||||
reduxForm({
|
||||
@@ -1,23 +1,12 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
|
||||
import ReactModal from 'react-modal';
|
||||
|
||||
import { MODAL_TYPE } from '../../../helpers/constants';
|
||||
|
||||
import Form from './Form';
|
||||
|
||||
interface ModalProps {
|
||||
isModalOpen: boolean;
|
||||
handleSubmit: (values: any) => void;
|
||||
toggleRewritesModal: (...args: unknown[]) => unknown;
|
||||
processingAdd: boolean;
|
||||
processingDelete: boolean;
|
||||
modalType: string;
|
||||
currentRewrite?: object;
|
||||
}
|
||||
|
||||
const Modal = (props: ModalProps) => {
|
||||
const Modal = (props) => {
|
||||
const {
|
||||
isModalOpen,
|
||||
handleSubmit,
|
||||
@@ -33,7 +22,8 @@ const Modal = (props: ModalProps) => {
|
||||
className="Modal__Bootstrap modal-dialog modal-dialog-centered"
|
||||
closeTimeoutMS={0}
|
||||
isOpen={isModalOpen}
|
||||
onRequestClose={() => toggleRewritesModal()}>
|
||||
onRequestClose={() => toggleRewritesModal()}
|
||||
>
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h4 className="modal-title">
|
||||
@@ -43,12 +33,10 @@ const Modal = (props: ModalProps) => {
|
||||
<Trans>rewrite_add</Trans>
|
||||
)}
|
||||
</h4>
|
||||
|
||||
<button type="button" className="close" onClick={() => toggleRewritesModal()}>
|
||||
<span className="sr-only">Close</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Form
|
||||
initialValues={{ ...currentRewrite }}
|
||||
onSubmit={handleSubmit}
|
||||
@@ -61,4 +49,14 @@ const Modal = (props: ModalProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
Modal.propTypes = {
|
||||
isModalOpen: PropTypes.bool.isRequired,
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
toggleRewritesModal: PropTypes.func.isRequired,
|
||||
processingAdd: PropTypes.bool.isRequired,
|
||||
processingDelete: PropTypes.bool.isRequired,
|
||||
modalType: PropTypes.string.isRequired,
|
||||
currentRewrite: PropTypes.object,
|
||||
};
|
||||
|
||||
export default withTranslation()(Modal);
|
||||
@@ -1,26 +1,13 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
// @ts-expect-error FIXME: update react-table
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactTable from 'react-table';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
|
||||
import { sortIp } from '../../../helpers/helpers';
|
||||
import { MODAL_TYPE, TABLES_MIN_ROWS } from '../../../helpers/constants';
|
||||
import { LocalStorageHelper, LOCAL_STORAGE_KEYS } from '../../../helpers/localStorageHelper';
|
||||
|
||||
interface TableProps {
|
||||
t: (...args: unknown[]) => string;
|
||||
list: unknown[];
|
||||
processing: boolean;
|
||||
processingAdd: boolean;
|
||||
processingDelete: boolean;
|
||||
processingUpdate: boolean;
|
||||
handleDelete: (...args: unknown[]) => unknown;
|
||||
toggleRewritesModal: (...args: unknown[]) => unknown;
|
||||
}
|
||||
|
||||
class Table extends Component<TableProps> {
|
||||
cellWrap = ({ value }: any) => (
|
||||
class Table extends Component {
|
||||
cellWrap = ({ value }) => (
|
||||
<div className="logs__row o-hidden">
|
||||
<span className="logs__text" title={value}>
|
||||
{value}
|
||||
@@ -46,7 +33,7 @@ class Table extends Component<TableProps> {
|
||||
maxWidth: 100,
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
Cell: (value: any) => {
|
||||
Cell: (value) => {
|
||||
const currentRewrite = {
|
||||
answer: value.row.answer,
|
||||
domain: value.row.domain,
|
||||
@@ -64,7 +51,8 @@ class Table extends Component<TableProps> {
|
||||
});
|
||||
}}
|
||||
disabled={this.props.processingUpdate}
|
||||
title={this.props.t('edit_table_action')}>
|
||||
title={this.props.t('edit_table_action')}
|
||||
>
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#edit" />
|
||||
</svg>
|
||||
@@ -74,7 +62,8 @@ class Table extends Component<TableProps> {
|
||||
type="button"
|
||||
className="btn btn-icon btn-outline-secondary btn-sm"
|
||||
onClick={() => this.props.handleDelete(currentRewrite)}
|
||||
title={this.props.t('delete_table_action')}>
|
||||
title={this.props.t('delete_table_action')}
|
||||
>
|
||||
<svg className="icons">
|
||||
<use xlinkHref="#delete" />
|
||||
</svg>
|
||||
@@ -86,7 +75,9 @@ class Table extends Component<TableProps> {
|
||||
];
|
||||
|
||||
render() {
|
||||
const { t, list, processing, processingAdd, processingDelete } = this.props;
|
||||
const {
|
||||
t, list, processing, processingAdd, processingDelete,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ReactTable
|
||||
@@ -96,9 +87,7 @@ class Table extends Component<TableProps> {
|
||||
className="-striped -highlight card-table-overflow"
|
||||
showPagination
|
||||
defaultPageSize={LocalStorageHelper.getItem(LOCAL_STORAGE_KEYS.REWRITES_PAGE_SIZE) || 10}
|
||||
onPageSizeChange={(size: any) =>
|
||||
LocalStorageHelper.setItem(LOCAL_STORAGE_KEYS.REWRITES_PAGE_SIZE, size)
|
||||
}
|
||||
onPageSizeChange={(size) => LocalStorageHelper.setItem(LOCAL_STORAGE_KEYS.REWRITES_PAGE_SIZE, size)}
|
||||
minRows={TABLES_MIN_ROWS}
|
||||
ofText="/"
|
||||
previousText={t('previous_btn')}
|
||||
@@ -112,4 +101,15 @@ class Table extends Component<TableProps> {
|
||||
}
|
||||
}
|
||||
|
||||
Table.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
list: PropTypes.array.isRequired,
|
||||
processing: PropTypes.bool.isRequired,
|
||||
processingAdd: PropTypes.bool.isRequired,
|
||||
processingDelete: PropTypes.bool.isRequired,
|
||||
processingUpdate: PropTypes.bool.isRequired,
|
||||
handleDelete: PropTypes.func.isRequired,
|
||||
toggleRewritesModal: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(Table);
|
||||
@@ -1,39 +1,26 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
|
||||
import Table from './Table';
|
||||
|
||||
import Modal from './Modal';
|
||||
|
||||
import Card from '../../ui/Card';
|
||||
|
||||
import PageTitle from '../../ui/PageTitle';
|
||||
import { MODAL_TYPE } from '../../../helpers/constants';
|
||||
import { RewritesData } from '../../../initialState';
|
||||
|
||||
interface RewritesProps {
|
||||
t: (...args: unknown[]) => string;
|
||||
getRewritesList: () => (dispatch: any) => void;
|
||||
toggleRewritesModal: (...args: unknown[]) => unknown;
|
||||
addRewrite: (...args: unknown[]) => unknown;
|
||||
deleteRewrite: (...args: unknown[]) => unknown;
|
||||
updateRewrite: (...args: unknown[]) => unknown;
|
||||
rewrites: RewritesData;
|
||||
}
|
||||
|
||||
class Rewrites extends Component<RewritesProps> {
|
||||
class Rewrites extends Component {
|
||||
componentDidMount() {
|
||||
this.props.getRewritesList();
|
||||
}
|
||||
|
||||
handleDelete = (values: any) => {
|
||||
handleDelete = (values) => {
|
||||
// eslint-disable-next-line no-alert
|
||||
if (window.confirm(this.props.t('rewrite_confirm_delete', { key: values.domain }))) {
|
||||
this.props.deleteRewrite(values);
|
||||
}
|
||||
};
|
||||
|
||||
handleSubmit = (values: any) => {
|
||||
handleSubmit = (values) => {
|
||||
const { modalType, currentRewrite } = this.props.rewrites;
|
||||
|
||||
if (modalType === MODAL_TYPE.EDIT_REWRITE && currentRewrite) {
|
||||
@@ -49,9 +36,7 @@ class Rewrites extends Component<RewritesProps> {
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
|
||||
rewrites,
|
||||
|
||||
toggleRewritesModal,
|
||||
} = this.props;
|
||||
|
||||
@@ -68,9 +53,14 @@ class Rewrites extends Component<RewritesProps> {
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageTitle title={t('dns_rewrites')} subtitle={t('rewrite_desc')} />
|
||||
|
||||
<Card id="rewrites" bodyType="card-body box-body--settings">
|
||||
<PageTitle
|
||||
title={t('dns_rewrites')}
|
||||
subtitle={t('rewrite_desc')}
|
||||
/>
|
||||
<Card
|
||||
id="rewrites"
|
||||
bodyType="card-body box-body--settings"
|
||||
>
|
||||
<Fragment>
|
||||
<Table
|
||||
list={list}
|
||||
@@ -86,7 +76,8 @@ class Rewrites extends Component<RewritesProps> {
|
||||
type="button"
|
||||
className="btn btn-success btn-standard mt-3"
|
||||
onClick={() => toggleRewritesModal({ type: MODAL_TYPE.ADD_REWRITE })}
|
||||
disabled={processingAdd}>
|
||||
disabled={processingAdd}
|
||||
>
|
||||
<Trans>rewrite_add</Trans>
|
||||
</button>
|
||||
|
||||
@@ -97,6 +88,7 @@ class Rewrites extends Component<RewritesProps> {
|
||||
handleSubmit={this.handleSubmit}
|
||||
processingAdd={processingAdd}
|
||||
processingDelete={processingDelete}
|
||||
processingUpdate={processingUpdate}
|
||||
currentRewrite={currentRewrite}
|
||||
/>
|
||||
</Fragment>
|
||||
@@ -106,4 +98,14 @@ class Rewrites extends Component<RewritesProps> {
|
||||
}
|
||||
}
|
||||
|
||||
Rewrites.propTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
getRewritesList: PropTypes.func.isRequired,
|
||||
toggleRewritesModal: PropTypes.func.isRequired,
|
||||
addRewrite: PropTypes.func.isRequired,
|
||||
deleteRewrite: PropTypes.func.isRequired,
|
||||
updateRewrite: PropTypes.func.isRequired,
|
||||
rewrites: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(Rewrites);
|
||||
@@ -1,27 +1,23 @@
|
||||
import React from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import flow from 'lodash/flow';
|
||||
|
||||
import { toggleAllServices } from '../../../helpers/helpers';
|
||||
|
||||
import { renderServiceField } from '../../../helpers/form';
|
||||
import { FORM_NAME } from '../../../helpers/constants';
|
||||
|
||||
interface FormProps {
|
||||
blockedServices: unknown[];
|
||||
pristine: boolean;
|
||||
handleSubmit: (...args: unknown[]) => string;
|
||||
change: (...args: unknown[]) => unknown;
|
||||
submitting: boolean;
|
||||
processing: boolean;
|
||||
processingSet: boolean;
|
||||
t: (...args: unknown[]) => string;
|
||||
}
|
||||
|
||||
const Form = (props: FormProps) => {
|
||||
const { blockedServices, handleSubmit, change, pristine, submitting, processing, processingSet } = props;
|
||||
const Form = (props) => {
|
||||
const {
|
||||
blockedServices,
|
||||
handleSubmit,
|
||||
change,
|
||||
pristine,
|
||||
submitting,
|
||||
processing,
|
||||
processingSet,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
@@ -32,24 +28,24 @@ const Form = (props: FormProps) => {
|
||||
type="button"
|
||||
className="btn btn-secondary btn-block"
|
||||
disabled={processing || processingSet}
|
||||
onClick={() => toggleAllServices(blockedServices, change, true)}>
|
||||
onClick={() => toggleAllServices(blockedServices, change, true)}
|
||||
>
|
||||
<Trans>block_all</Trans>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="col-6">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary btn-block"
|
||||
disabled={processing || processingSet}
|
||||
onClick={() => toggleAllServices(blockedServices, change, false)}>
|
||||
onClick={() => toggleAllServices(blockedServices, change, false)}
|
||||
>
|
||||
<Trans>unblock_all</Trans>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="services">
|
||||
{blockedServices.map((service: any) => (
|
||||
{blockedServices.map((service) => (
|
||||
<Field
|
||||
key={service.id}
|
||||
icon={service.icon_svg}
|
||||
@@ -67,7 +63,8 @@ const Form = (props: FormProps) => {
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-success btn-standard btn-large"
|
||||
disabled={submitting || pristine || processing || processingSet}>
|
||||
disabled={submitting || pristine || processing || processingSet}
|
||||
>
|
||||
<Trans>save_btn</Trans>
|
||||
</button>
|
||||
</div>
|
||||
@@ -75,6 +72,17 @@ const Form = (props: FormProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
Form.propTypes = {
|
||||
blockedServices: PropTypes.array.isRequired,
|
||||
pristine: PropTypes.bool.isRequired,
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
change: PropTypes.func.isRequired,
|
||||
submitting: PropTypes.bool.isRequired,
|
||||
processing: PropTypes.bool.isRequired,
|
||||
processingSet: PropTypes.bool.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default flow([
|
||||
withTranslation(),
|
||||
reduxForm({
|
||||
@@ -1,12 +1,10 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ReactModal from 'react-modal';
|
||||
|
||||
import { Timezone } from './Timezone';
|
||||
|
||||
import { TimeSelect } from './TimeSelect';
|
||||
|
||||
import { TimePeriod } from './TimePeriod';
|
||||
import { getFullDayName, getShortDayName } from './helpers';
|
||||
import { LOCAL_TIMEZONE_VALUE } from '../../../../helpers/constants';
|
||||
@@ -16,26 +14,21 @@ export const DAYS_OF_WEEK = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
|
||||
const INITIAL_START_TIME_MS = 0;
|
||||
const INITIAL_END_TIME_MS = 86340000;
|
||||
|
||||
interface ModalProps {
|
||||
schedule: {
|
||||
time_zone: string;
|
||||
};
|
||||
currentDay?: string;
|
||||
isOpen: boolean;
|
||||
onClose: (...args: unknown[]) => unknown;
|
||||
onSubmit: (values: any) => void;
|
||||
}
|
||||
|
||||
export const Modal = ({ isOpen, currentDay, schedule, onClose, onSubmit }: ModalProps) => {
|
||||
export const Modal = ({
|
||||
isOpen,
|
||||
currentDay,
|
||||
schedule,
|
||||
onClose,
|
||||
onSubmit,
|
||||
}) => {
|
||||
const [t] = useTranslation();
|
||||
|
||||
const intialTimezone =
|
||||
schedule.time_zone === LOCAL_TIMEZONE_VALUE
|
||||
? Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
: schedule.time_zone;
|
||||
const intialTimezone = schedule.time_zone === LOCAL_TIMEZONE_VALUE
|
||||
? Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
: schedule.time_zone;
|
||||
|
||||
const [timezone, setTimezone] = useState(intialTimezone);
|
||||
const [days, setDays] = useState<Set<string>>(new Set());
|
||||
const [days, setDays] = useState(new Set());
|
||||
|
||||
const [startTime, setStartTime] = useState(INITIAL_START_TIME_MS);
|
||||
const [endTime, setEndTime] = useState(INITIAL_END_TIME_MS);
|
||||
@@ -60,7 +53,7 @@ export const Modal = ({ isOpen, currentDay, schedule, onClose, onSubmit }: Modal
|
||||
}
|
||||
}, [startTime, endTime]);
|
||||
|
||||
const addDays = (day: any) => {
|
||||
const addDays = (day) => {
|
||||
const newDays = new Set(days);
|
||||
|
||||
if (newDays.has(day)) {
|
||||
@@ -72,11 +65,11 @@ export const Modal = ({ isOpen, currentDay, schedule, onClose, onSubmit }: Modal
|
||||
setDays(newDays);
|
||||
};
|
||||
|
||||
const activeDay = (day: any) => {
|
||||
const activeDay = (day) => {
|
||||
return days.has(day);
|
||||
};
|
||||
|
||||
const onFormSubmit = (e: any) => {
|
||||
const onFormSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const newSchedule = schedule;
|
||||
@@ -100,19 +93,23 @@ export const Modal = ({ isOpen, currentDay, schedule, onClose, onSubmit }: Modal
|
||||
className="Modal__Bootstrap modal-dialog modal-dialog-centered modal-dialog--schedule"
|
||||
closeTimeoutMS={0}
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onClose}>
|
||||
onRequestClose={onClose}
|
||||
>
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h4 className="modal-title">{currentDay ? t('schedule_edit') : t('schedule_new')}</h4>
|
||||
|
||||
<h4 className="modal-title">
|
||||
{currentDay ? t('schedule_edit') : t('schedule_new')}
|
||||
</h4>
|
||||
<button type="button" className="close" onClick={onClose}>
|
||||
<span className="sr-only">Close</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form onSubmit={onFormSubmit}>
|
||||
<div className="modal-body">
|
||||
<Timezone timezone={timezone} setTimezone={setTimezone} />
|
||||
<Timezone
|
||||
timezone={timezone}
|
||||
setTimezone={setTimezone}
|
||||
/>
|
||||
|
||||
<div className="schedule__days">
|
||||
{DAYS_OF_WEEK.map((day) => (
|
||||
@@ -121,7 +118,8 @@ export const Modal = ({ isOpen, currentDay, schedule, onClose, onSubmit }: Modal
|
||||
key={day}
|
||||
className="btn schedule__button-day"
|
||||
data-active={activeDay(day)}
|
||||
onClick={() => addDays(day)}>
|
||||
onClick={() => addDays(day)}
|
||||
>
|
||||
{getShortDayName(t, day)}
|
||||
</button>
|
||||
))}
|
||||
@@ -129,52 +127,69 @@ export const Modal = ({ isOpen, currentDay, schedule, onClose, onSubmit }: Modal
|
||||
|
||||
<div className="schedule__time-wrap">
|
||||
<div className="schedule__time-row">
|
||||
<TimeSelect value={startTime} onChange={(v) => setStartTime(v)} />
|
||||
<TimeSelect
|
||||
value={startTime}
|
||||
onChange={(v) => setStartTime(v)}
|
||||
/>
|
||||
|
||||
<TimeSelect value={endTime} onChange={(v) => setEndTime(v)} />
|
||||
<TimeSelect
|
||||
value={endTime}
|
||||
onChange={(v) => setEndTime(v)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{wrongPeriod && <div className="schedule__error">{t('schedule_invalid_select')}</div>}
|
||||
{wrongPeriod && (
|
||||
<div className="schedule__error">
|
||||
{t('schedule_invalid_select')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="schedule__info">
|
||||
<div className="schedule__info-title">{t('schedule_modal_time_off')}</div>
|
||||
|
||||
<div className="schedule__info-title">
|
||||
{t('schedule_modal_time_off')}
|
||||
</div>
|
||||
<div className="schedule__info-row">
|
||||
<svg className="icons schedule__info-icon">
|
||||
<use xlinkHref="#calendar" />
|
||||
</svg>
|
||||
{days.size ? (
|
||||
Array.from(days)
|
||||
.map((day) => getFullDayName(t, day))
|
||||
.join(', ')
|
||||
Array.from(days).map((day) => getFullDayName(t, day)).join(', ')
|
||||
) : (
|
||||
<span>—</span>
|
||||
<span>
|
||||
—
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="schedule__info-row">
|
||||
<svg className="icons schedule__info-icon">
|
||||
<use xlinkHref="#watch" />
|
||||
</svg>
|
||||
{wrongPeriod ? (
|
||||
<span>—</span>
|
||||
<span>
|
||||
—
|
||||
</span>
|
||||
) : (
|
||||
<TimePeriod startTimeMs={startTime} endTimeMs={endTime} />
|
||||
<TimePeriod
|
||||
startTimeMs={startTime}
|
||||
endTimeMs={endTime}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="schedule__notice">{t('schedule_modal_description')}</div>
|
||||
<div className="schedule__notice">
|
||||
{t('schedule_modal_description')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="modal-footer">
|
||||
<div className="btn-list">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-success btn-standard"
|
||||
disabled={days.size === 0 || wrongPeriod}
|
||||
onClick={onFormSubmit}>
|
||||
onClick={onFormSubmit}
|
||||
>
|
||||
{currentDay ? t('schedule_save') : t('schedule_add')}
|
||||
</button>
|
||||
</div>
|
||||
@@ -184,3 +199,11 @@ export const Modal = ({ isOpen, currentDay, schedule, onClose, onSubmit }: Modal
|
||||
</ReactModal>
|
||||
);
|
||||
};
|
||||
|
||||
Modal.propTypes = {
|
||||
schedule: PropTypes.object.isRequired,
|
||||
currentDay: PropTypes.string,
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user