Compare commits
170 Commits
4728-cap-c
...
3389-query
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94458c5658 | ||
|
|
123ca87388 | ||
|
|
994906fbd4 | ||
|
|
06d465b0d1 | ||
|
|
ca313521dc | ||
|
|
2902f030be | ||
|
|
371261b2c6 | ||
|
|
d26c480d03 | ||
|
|
b6d00f774b | ||
|
|
6fea435d89 | ||
|
|
05706bd7ea | ||
|
|
d3ada9881a | ||
|
|
7309a53356 | ||
|
|
00327757e1 | ||
|
|
5f0e53ded7 | ||
|
|
5cd4ce766d | ||
|
|
e695fd9885 | ||
|
|
15b937d68b | ||
|
|
681c604c22 | ||
|
|
c43053e7d2 | ||
|
|
86e25944b3 | ||
|
|
fd7260f6de | ||
|
|
9fda7bfd34 | ||
|
|
826b314f19 | ||
|
|
156c199bbb | ||
|
|
040596f3a0 | ||
|
|
fde082af44 | ||
|
|
329e144b4f | ||
|
|
367b319f10 | ||
|
|
d6fe0bd740 | ||
|
|
ae7bd79a6c | ||
|
|
c591e46254 | ||
|
|
66d9ea7cca | ||
|
|
dafc785845 | ||
|
|
e9b17891bb | ||
|
|
0211424191 | ||
|
|
0b27f048a7 | ||
|
|
649454e77b | ||
|
|
ca22d8524d | ||
|
|
07f4f0474c | ||
|
|
8813e135b6 | ||
|
|
f4f2c11eb9 | ||
|
|
ea8d634f65 | ||
|
|
0fec990bcf | ||
|
|
a7680a593a | ||
|
|
cbc7985e75 | ||
|
|
941eb1dd73 | ||
|
|
fc64e0089e | ||
|
|
24b41100c3 | ||
|
|
b72a3d01b8 | ||
|
|
0393e41096 | ||
|
|
c77b2a0ce5 | ||
|
|
db52f7a3ac | ||
|
|
381f2f651d | ||
|
|
620b51e3ea | ||
|
|
757ddb06f8 | ||
|
|
d6043e2352 | ||
|
|
aeec9a86e2 | ||
|
|
584182e264 | ||
|
|
96cd512d32 | ||
|
|
11898a3f73 | ||
|
|
a91a257b15 | ||
|
|
76a74b271b | ||
|
|
1842f7d888 | ||
|
|
4afd39b22f | ||
|
|
e43ba17884 | ||
|
|
6d402dc86c | ||
|
|
18acdf9b09 | ||
|
|
5da7751463 | ||
|
|
7631ca4ab3 | ||
|
|
c6d4f2317e | ||
|
|
0ea224a9e4 | ||
|
|
d78a3edb22 | ||
|
|
bbbdea2635 | ||
|
|
6c8d89a4da | ||
|
|
f082312e49 | ||
|
|
ea03d1af93 | ||
|
|
67d8b7df90 | ||
|
|
b23ea0a690 | ||
|
|
a186b5c436 | ||
|
|
6da7392345 | ||
|
|
c1924a8b8a | ||
|
|
0376afb38e | ||
|
|
230d7b8c17 | ||
|
|
950ecb1f5e | ||
|
|
9e14d5f99f | ||
|
|
89bf3721b5 | ||
|
|
15bba281ee | ||
|
|
f9fe3172c4 | ||
|
|
5d5a729569 | ||
|
|
b1120221c7 | ||
|
|
f553eee842 | ||
|
|
61b4043775 | ||
|
|
a55cbbe79c | ||
|
|
10bffd89c9 | ||
|
|
91ecbede7d | ||
|
|
27dbb427a1 | ||
|
|
195300f56e | ||
|
|
2a0d062947 | ||
|
|
3575aa0570 | ||
|
|
f191cb07a5 | ||
|
|
1731ce9c63 | ||
|
|
2eb3bf6ea5 | ||
|
|
a0349b6c7e | ||
|
|
da9008aba3 | ||
|
|
c576d5059e | ||
|
|
487675b9ad | ||
|
|
132ec556dc | ||
|
|
d58772f177 | ||
|
|
0df32601bb | ||
|
|
fb7b8bba6a | ||
|
|
d859a33787 | ||
|
|
67c9abe119 | ||
|
|
2409282d51 | ||
|
|
9c48e96939 | ||
|
|
0bc3ef89ea | ||
|
|
8de994d077 | ||
|
|
59a8265e31 | ||
|
|
bea39934bd | ||
|
|
df61741f60 | ||
|
|
143616ca6e | ||
|
|
306c1983a2 | ||
|
|
194ead3479 | ||
|
|
c3edab4387 | ||
|
|
f736d85e6e | ||
|
|
1daabb97e5 | ||
|
|
dd2095e05d | ||
|
|
a0205a54ec | ||
|
|
48431f8b86 | ||
|
|
9f7a582dbc | ||
|
|
2b5e4850d0 | ||
|
|
c6706445c9 | ||
|
|
595484e0b3 | ||
|
|
a2053526c3 | ||
|
|
e616429d44 | ||
|
|
622181b88f | ||
|
|
1011b8f93d | ||
|
|
6b265c6488 | ||
|
|
c11a52d60c | ||
|
|
f23a0d4753 | ||
|
|
057804a459 | ||
|
|
012e5beb51 | ||
|
|
ae653f166f | ||
|
|
51b72a4cd8 | ||
|
|
f13dc59bfa | ||
|
|
bb226434f8 | ||
|
|
a772212d05 | ||
|
|
bb80a7c215 | ||
|
|
386add033b | ||
|
|
304f2ba2cc | ||
|
|
3a0b27e7e8 | ||
|
|
76a513cdaf | ||
|
|
ff9b24ad69 | ||
|
|
20531de760 | ||
|
|
91dee0986b | ||
|
|
a556ce8fb8 | ||
|
|
6f6ced33c1 | ||
|
|
be43ce1760 | ||
|
|
4d295a384b | ||
|
|
eb0d7d39d9 | ||
|
|
6575c068b8 | ||
|
|
3378d1c103 | ||
|
|
a50a8abb45 | ||
|
|
ff04b2a7d3 | ||
|
|
ec19a85ed0 | ||
|
|
b89105e3b5 | ||
|
|
137d280032 | ||
|
|
4baa6e6990 | ||
|
|
b8d55eaffe | ||
|
|
b31bab591d |
130
.github/ISSUE_TEMPLATE/bug.yml
vendored
130
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -10,52 +10,58 @@
|
||||
- 'label': >
|
||||
I have checked the
|
||||
[Wiki](https://github.com/AdguardTeam/AdGuardHome/wiki) and
|
||||
[Discussions](https://github.com/AdguardTeam/AdGuardHome/discussions)
|
||||
[Discussions](https://github.com/AdguardTeam/AdGuardHome/discussions/categories/q-a)
|
||||
and found no answer
|
||||
'required': true
|
||||
- 'label': >
|
||||
I have searched other issues and found no duplicates
|
||||
'required': true
|
||||
- 'label': >
|
||||
I want to report a bug and not ask a question
|
||||
I want to report a bug and not [ask a question or ask for
|
||||
help](https://github.com/AdguardTeam/AdGuardHome/discussions/categories/q-a)
|
||||
'required': true
|
||||
- 'label': >
|
||||
I have set up AdGuard Home correctly and [configured clients to
|
||||
use it](https://github.com/AdguardTeam/AdGuardHome/wiki/Clients).
|
||||
(Use the
|
||||
[Discussions](https://github.com/AdguardTeam/AdGuardHome/discussions/categories/q-a)
|
||||
for help with installing and configuring clients.)
|
||||
'required': true
|
||||
'id': 'prerequisites'
|
||||
'type': 'checkboxes'
|
||||
- 'attributes':
|
||||
'description': 'On which operating system type does the issue occur?'
|
||||
'label': 'Operating system type'
|
||||
'description': 'On which Platform does the issue occur?'
|
||||
'label': 'Platform (OS and CPU architecture)'
|
||||
'options':
|
||||
- 'FreeBSD'
|
||||
- 'Linux, OpenWrt'
|
||||
- 'Linux, Other (please mention the version in the description)'
|
||||
- 'macOS (aka Darwin)'
|
||||
- 'OpenBSD'
|
||||
- 'Windows'
|
||||
- 'Other (please mention in the description)'
|
||||
- 'Darwin (aka macOS)/AMD64 (aka x86_64)'
|
||||
- 'Darwin (aka macOS)/ARM64'
|
||||
- 'FreeBSD/386'
|
||||
- 'FreeBSD/AMD64 (aka x86_64)'
|
||||
- 'FreeBSD/ARM64'
|
||||
- 'FreeBSD/ARMv5'
|
||||
- 'FreeBSD/ARMv6'
|
||||
- 'FreeBSD/ARMv7'
|
||||
- 'Linux/386'
|
||||
- 'Linux/AMD64 (aka x86_64)'
|
||||
- 'Linux/ARM64'
|
||||
- 'Linux/ARMv5'
|
||||
- 'Linux/ARMv6'
|
||||
- 'Linux/ARMv7'
|
||||
- 'Linux/MIPS LE'
|
||||
- 'Linux/MIPS'
|
||||
- 'Linux/MIPS64 LE'
|
||||
- 'Linux/MIPS64'
|
||||
- 'Linux/PPC64 LE'
|
||||
- 'OpenBSD/AMD64 (aka x86_64)'
|
||||
- 'OpenBSD/ARM64'
|
||||
- 'Windows/386'
|
||||
- 'Windows/AMD64 (aka x86_64)'
|
||||
- 'Windows/ARM64'
|
||||
- 'Custom (please mention in the description)'
|
||||
'id': 'os'
|
||||
'type': 'dropdown'
|
||||
'validations':
|
||||
'required': true
|
||||
- 'attributes':
|
||||
'description': 'On which CPU architecture does the issue occur?'
|
||||
'label': 'CPU architecture'
|
||||
'options':
|
||||
- 'AMD64'
|
||||
- 'x86'
|
||||
- '64-bit ARM'
|
||||
- 'ARMv5'
|
||||
- 'ARMv6'
|
||||
- 'ARMv7'
|
||||
- '64-bit MIPS'
|
||||
- '64-bit MIPS LE'
|
||||
- '32-bit MIPS'
|
||||
- '32-bit MIPS LE'
|
||||
- '64-bit PowerPC LE'
|
||||
- 'Other (please mention in the description)'
|
||||
'id': 'arch'
|
||||
'type': 'dropdown'
|
||||
'validations':
|
||||
'required': true
|
||||
- 'attributes':
|
||||
'description': 'How did you install AdGuard Home?'
|
||||
'label': 'Installation'
|
||||
@@ -63,7 +69,7 @@
|
||||
- 'GitHub releases or script from README'
|
||||
- 'Docker'
|
||||
- 'Snapcraft'
|
||||
- 'Custom port'
|
||||
- 'Custom package (OpenWrt, HomeAssistant, etc; please mention in the description)'
|
||||
- 'Other (please mention in the description)'
|
||||
'id': 'install'
|
||||
'type': 'dropdown'
|
||||
@@ -89,21 +95,55 @@
|
||||
'validations':
|
||||
'required': true
|
||||
- 'attributes':
|
||||
'description': 'Please describe the bug'
|
||||
'label': 'Description'
|
||||
'description': >
|
||||
Please describe what you did. An `nslookup` or a `dig` command is
|
||||
the best way. For crashes, please provide a full failure log.
|
||||
'label': 'Action'
|
||||
'value': |
|
||||
#### What did you do?
|
||||
|
||||
#### Expected result
|
||||
|
||||
#### Actual result
|
||||
|
||||
#### Screenshots (if applicable)
|
||||
|
||||
#### Additional information
|
||||
'id': 'description'
|
||||
```sh
|
||||
nslookup -debug -type=a 'www.example.com' '$YOUR_AGH_ADDRESS'
|
||||
```
|
||||
'id': 'failing_action'
|
||||
'type': 'textarea'
|
||||
'validations':
|
||||
'required': true
|
||||
'description': 'File a bug report'
|
||||
- 'attributes':
|
||||
'description': >
|
||||
What did you expect to see? Please add a description and/or
|
||||
screenshots, if applicable.
|
||||
'label': 'Expected result'
|
||||
'placeholder': >
|
||||
What did you expect to see?
|
||||
'id': 'expected'
|
||||
'type': 'textarea'
|
||||
'validations':
|
||||
'required': true
|
||||
- 'attributes':
|
||||
'description': >
|
||||
What happened instead? Please add a description and/or screenshots,
|
||||
if applicable.
|
||||
'label': 'Actual result'
|
||||
'placeholder': >
|
||||
What did you see instead?
|
||||
'id': 'result'
|
||||
'type': 'textarea'
|
||||
'validations':
|
||||
'required': true
|
||||
- 'attributes':
|
||||
'description': >
|
||||
Please add additional information, such as non-standard OS or port,
|
||||
here. You can also put screenshots here, if applicable. For
|
||||
example, it is better to copy and paste text from a terminal instead
|
||||
of posting a screenshot of the terminal.
|
||||
'label': 'Additional information and/or screenshots'
|
||||
'placeholder': >
|
||||
Additional OS information, screenshots of the UI, etc.
|
||||
'id': 'additional'
|
||||
'type': 'textarea'
|
||||
'validations':
|
||||
'required': false
|
||||
'description': >
|
||||
Open a bug report. Please do not open bug reports for questions or help
|
||||
with configuring clients. If you want to ask for help, use the Discussions
|
||||
section.
|
||||
'name': 'Bug'
|
||||
|
||||
35
.github/ISSUE_TEMPLATE/feature.yml
vendored
35
.github/ISSUE_TEMPLATE/feature.yml
vendored
@@ -23,19 +23,32 @@
|
||||
'id': 'prerequisites'
|
||||
'type': 'checkboxes'
|
||||
- 'attributes':
|
||||
'description': 'Please describe the request'
|
||||
'label': 'Description'
|
||||
'value': |
|
||||
#### What problem are you trying to solve?
|
||||
|
||||
#### Proposed solution
|
||||
|
||||
#### Alternatives considered
|
||||
|
||||
#### Additional information
|
||||
'id': 'description'
|
||||
'description': 'Please describe the problem you are trying to solve'
|
||||
'label': 'The problem'
|
||||
'placeholder': >
|
||||
Please describe the problem you are trying to solve
|
||||
'id': 'problem'
|
||||
'type': 'textarea'
|
||||
'validations':
|
||||
'required': true
|
||||
- 'attributes':
|
||||
'description': 'What feature are you proposing to solve this problem?'
|
||||
'label': 'Proposed solution'
|
||||
'placeholder': >
|
||||
What feature are you proposing to solve this problem?
|
||||
'id': 'proposed_solution'
|
||||
'type': 'textarea'
|
||||
'validations':
|
||||
'required': true
|
||||
- 'attributes':
|
||||
'label': 'Alternatives considered and additional information'
|
||||
'placeholder': >
|
||||
Are there any other ways to solve the problem?
|
||||
'id': 'additional'
|
||||
'type': 'textarea'
|
||||
'validations':
|
||||
'required': false
|
||||
'description': 'Suggest a feature or an enhancement for AdGuard Home'
|
||||
'labels':
|
||||
- 'feature request'
|
||||
'name': 'Feature request or enhancement'
|
||||
|
||||
20
.github/PULL_REQUEST_TEMPLATE
vendored
Normal file
20
.github/PULL_REQUEST_TEMPLATE
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
Before submitting a PR please make sure that:
|
||||
|
||||
1. You have discussed your solution in an issue and have got an
|
||||
approval from a maintainer.
|
||||
|
||||
2. This isn't a localization fix; please send those to our
|
||||
[CrowdIn](https://crowdin.com/project/adguard-applications/en#/adguard-home)
|
||||
page.
|
||||
|
||||
3. Your code follows our
|
||||
[code guidelines](https://github.com/AdguardTeam/CodeGuidelines/blob/master/Go/Go.md).
|
||||
|
||||
Add a short description here. The description should include:
|
||||
|
||||
1. Which issue this PR closes (`Closes #NNNN.`) or updates (`Updates
|
||||
#NNNN.`).
|
||||
|
||||
2. A short description of how the change achieves that.
|
||||
|
||||
Do not forget to remove these instructions.
|
||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -1,7 +1,7 @@
|
||||
'name': 'build'
|
||||
|
||||
'env':
|
||||
'GO_VERSION': '1.18.9'
|
||||
'GO_VERSION': '1.19.10'
|
||||
'NODE_VERSION': '14'
|
||||
|
||||
'on':
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -1,7 +1,7 @@
|
||||
'name': 'lint'
|
||||
|
||||
'env':
|
||||
'GO_VERSION': '1.18.9'
|
||||
'GO_VERSION': '1.19.10'
|
||||
|
||||
'on':
|
||||
'push':
|
||||
|
||||
18
.github/workflows/potential-duplicates.yml
vendored
Normal file
18
.github/workflows/potential-duplicates.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
'name': 'potential-duplicates'
|
||||
'on':
|
||||
'issues':
|
||||
'types':
|
||||
- 'opened'
|
||||
'jobs':
|
||||
'run':
|
||||
'runs-on': 'ubuntu-latest'
|
||||
'steps':
|
||||
- 'uses': 'wow-actions/potential-duplicates@v1'
|
||||
'with':
|
||||
'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}'
|
||||
'state': 'all'
|
||||
'threshold': 0.6
|
||||
'comment': |
|
||||
Potential duplicates: {{#issues}}
|
||||
* [#{{ number }}] {{ title }} ({{ accuracy }}%)
|
||||
{{/issues}}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,7 +21,6 @@
|
||||
/snapcraft_login
|
||||
AdGuardHome*
|
||||
coverage.txt
|
||||
leases.db
|
||||
node_modules/
|
||||
|
||||
!/build/gitkeep
|
||||
|
||||
@@ -399,6 +399,7 @@ Response:
|
||||
"protection_enabled":true,
|
||||
"running":true,
|
||||
"dhcp_available":true,
|
||||
"protection_disabled_duration":0
|
||||
"version":"undefined"
|
||||
}
|
||||
|
||||
|
||||
539
CHANGELOG.md
539
CHANGELOG.md
@@ -14,20 +14,87 @@ and this project adheres to
|
||||
<!--
|
||||
## [v0.108.0] - TBA
|
||||
|
||||
## [v0.107.24] - 2023-02-22 (APPROX.)
|
||||
## [v0.107.33] - 2023-06-28 (APPROX.)
|
||||
|
||||
See also the [v0.107.24 GitHub milestone][ms-v0.107.24].
|
||||
See also the [v0.107.33 GitHub milestone][ms-v0.107.33].
|
||||
|
||||
[ms-v0.107.24]: https://github.com/AdguardTeam/AdGuardHome/milestone/60?closed=1
|
||||
[ms-v0.107.33]: https://github.com/AdguardTeam/AdGuardHome/milestone/68?closed=1
|
||||
|
||||
NOTE: Add new changes BELOW THIS COMMENT.
|
||||
-->
|
||||
|
||||
### Added
|
||||
|
||||
- The new HTTP API, `GET /control/querylog/export`, which can be used to
|
||||
export query log items. See `openapi/openapi.yaml` for the full description
|
||||
([#3389]).
|
||||
- The ability to set inactivity periods for filtering blocked services in the
|
||||
configuration file ([#951]). The UI changes are coming in the upcoming
|
||||
releases.
|
||||
- The ability to edit rewrite rules via `PUT /control/rewrite/update` HTTP API
|
||||
([#1577]).
|
||||
|
||||
### Changed
|
||||
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 20 to 21.
|
||||
|
||||
- Property `dns.blocked_services`, which in schema versions 20 and earlier used
|
||||
to be a list containing ids of blocked services, is now an object containing
|
||||
ids and schedule for blocked services:
|
||||
|
||||
```yaml
|
||||
# BEFORE:
|
||||
'blocked_services':
|
||||
- id_1
|
||||
- id_2
|
||||
|
||||
# AFTER:
|
||||
'blocked_services':
|
||||
'ids':
|
||||
- id_1
|
||||
- id_2
|
||||
'schedule':
|
||||
'time_zone': 'Local'
|
||||
'sun':
|
||||
'start': '0s'
|
||||
'end': '24h'
|
||||
'mon':
|
||||
'start': '10m'
|
||||
'end': '23h30m'
|
||||
'tue':
|
||||
'start': '20m'
|
||||
'end': '23h'
|
||||
'wed':
|
||||
'start': '30m'
|
||||
'end': '22h30m'
|
||||
'thu':
|
||||
'start': '40m'
|
||||
'end': '22h'
|
||||
'fri':
|
||||
'start': '50m'
|
||||
'end': '21h30m'
|
||||
'sat':
|
||||
'start': '1h'
|
||||
'end': '21h'
|
||||
```
|
||||
|
||||
To rollback this change, replace `dns.blocked_services` object with the list
|
||||
of ids of blocked services and change the `schema_version` back to `20`.
|
||||
|
||||
### Fixed
|
||||
|
||||
- The icon for League Of Legends on the Blocked services page ([#5433]).
|
||||
- Queries with the question-section target `.`, for example `NS .`, are now
|
||||
counted in the statistics and correctly shown in the query log ([#5910]).
|
||||
- Safe Search not working with `AAAA` queries for domains that don't have `AAAA`
|
||||
records ([#5913]).
|
||||
|
||||
[#5433]: https://github.com/AdguardTeam/AdGuardHome/issues/5433
|
||||
[#951]: https://github.com/AdguardTeam/AdGuardHome/issues/951
|
||||
[#1577]: https://github.com/AdguardTeam/AdGuardHome/issues/1577
|
||||
[#3389]: https://github.com/AdguardTeam/AdGuardHome/issues/3389
|
||||
[#5910]: https://github.com/AdguardTeam/AdGuardHome/issues/5910
|
||||
[#5913]: https://github.com/AdguardTeam/AdGuardHome/issues/5913
|
||||
|
||||
<!--
|
||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
@@ -35,6 +102,436 @@ NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
|
||||
|
||||
|
||||
## [v0.107.32] - 2023-06-13
|
||||
|
||||
### Fixed
|
||||
|
||||
- DNSCrypt upstream not resetting the client and resolver information on
|
||||
dialing errors ([#5872]).
|
||||
|
||||
|
||||
|
||||
|
||||
## [v0.107.31] - 2023-06-08
|
||||
|
||||
See also the [v0.107.31 GitHub milestone][ms-v0.107.31].
|
||||
|
||||
### Fixed
|
||||
|
||||
- Startup errors on OpenWrt ([#5872]).
|
||||
- Plain-UDP upstreams always falling back to TCP, causing outages and slowdowns
|
||||
([#5873], [#5874]).
|
||||
|
||||
[#5872]: https://github.com/AdguardTeam/AdGuardHome/issues/5872
|
||||
[#5873]: https://github.com/AdguardTeam/AdGuardHome/issues/5873
|
||||
[#5874]: https://github.com/AdguardTeam/AdGuardHome/issues/5874
|
||||
|
||||
[ms-v0.107.31]: https://github.com/AdguardTeam/AdGuardHome/milestone/67?closed=1
|
||||
|
||||
|
||||
|
||||
## [v0.107.30] - 2023-06-07
|
||||
|
||||
See also the [v0.107.30 GitHub milestone][ms-v0.107.30].
|
||||
|
||||
### Security
|
||||
|
||||
- Go version has been updated to prevent the possibility of exploiting the
|
||||
CVE-2023-29402, CVE-2023-29403, and CVE-2023-29404 Go vulnerabilities fixed in
|
||||
[Go 1.19.10][go-1.19.10].
|
||||
|
||||
### Fixed
|
||||
|
||||
- Unquoted IPv6 bind hosts with trailing colons erroneously considered
|
||||
unspecified addresses are now properly validated ([#5752]).
|
||||
|
||||
**NOTE:** the Docker healthcheck script now also doesn't interpret the `""`
|
||||
value as unspecified address.
|
||||
- Incorrect `Content-Type` header value in `POST /control/version.json` and `GET
|
||||
/control/dhcp/interfaces` HTTP APIs ([#5716]).
|
||||
- Provided bootstrap servers are now used to resolve the hostnames of plain
|
||||
UDP/TCP upstream servers.
|
||||
|
||||
[#5716]: https://github.com/AdguardTeam/AdGuardHome/issues/5716
|
||||
|
||||
[go-1.19.10]: https://groups.google.com/g/golang-announce/c/q5135a9d924/m/j0ZoAJOHAwAJ
|
||||
[ms-v0.107.30]: https://github.com/AdguardTeam/AdGuardHome/milestone/66?closed=1
|
||||
|
||||
|
||||
|
||||
## [v0.107.29] - 2023-04-18
|
||||
|
||||
See also the [v0.107.29 GitHub milestone][ms-v0.107.29].
|
||||
|
||||
### Added
|
||||
|
||||
- The ability to exclude client activity from the query log or statistics by
|
||||
editing client's settings on the respective page in the UI ([#1717], [#4299]).
|
||||
|
||||
### Changed
|
||||
|
||||
- Stored DHCP leases moved from `leases.db` to `data/leases.json`. The file
|
||||
format has also been optimized.
|
||||
|
||||
### Fixed
|
||||
|
||||
- The `github.com/mdlayher/raw` dependency has been temporarily returned to
|
||||
support raw connections on Darwin ([#5712]).
|
||||
- Incorrect recording of blocked results as “Blocked by CNAME or IP” in the
|
||||
query log ([#5725]).
|
||||
- All Safe Search services being unchecked by default.
|
||||
- Panic when a DNSCrypt stamp is invalid ([#5721]).
|
||||
|
||||
[#5712]: https://github.com/AdguardTeam/AdGuardHome/issues/5712
|
||||
[#5721]: https://github.com/AdguardTeam/AdGuardHome/issues/5721
|
||||
[#5725]: https://github.com/AdguardTeam/AdGuardHome/issues/5725
|
||||
[#5752]: https://github.com/AdguardTeam/AdGuardHome/issues/5752
|
||||
|
||||
[ms-v0.107.29]: https://github.com/AdguardTeam/AdGuardHome/milestone/65?closed=1
|
||||
|
||||
|
||||
|
||||
## [v0.107.28] - 2023-04-12
|
||||
|
||||
See also the [v0.107.28 GitHub milestone][ms-v0.107.28].
|
||||
|
||||
### Added
|
||||
|
||||
- The ability to exclude client activity from the query log or statistics by
|
||||
using the new properties `ignore_querylog` and `ignore_statistics` of the
|
||||
items of the `clients.persistent` array ([#1717], [#4299]). The UI changes
|
||||
are coming in the upcoming releases.
|
||||
- Better profiling information when `debug_pprof` is set to `true`.
|
||||
- IPv6 support in Safe Search for some services.
|
||||
- The ability to make bootstrap DNS lookups prefer IPv6 addresses to IPv4 ones
|
||||
using the new `dns.bootstrap_prefer_ipv6` configuration file property
|
||||
([#4262]).
|
||||
- Docker container's healthcheck ([#3290]).
|
||||
- The new HTTP API `POST /control/protection`, that updates protection state
|
||||
and adds an optional pause duration ([#1333]). The format of request body
|
||||
is described in `openapi/openapi.yaml`. The duration of this pause could
|
||||
also be set with the property `protection_disabled_until` in the `dns` object
|
||||
of the YAML configuration file.
|
||||
- The ability to create a static DHCP lease from a dynamic one more easily
|
||||
([#3459]).
|
||||
- Two new HTTP APIs, `PUT /control/stats/config/update` and `GET
|
||||
control/stats/config`, which can be used to set and receive the query log
|
||||
configuration. See `openapi/openapi.yaml` for the full description.
|
||||
- Two new HTTP APIs, `PUT /control/querylog/config/update` and `GET
|
||||
control/querylog/config`, which can be used to set and receive the statistics
|
||||
configuration. See `openapi/openapi.yaml` for the full description.
|
||||
- The ability to set custom IP for EDNS Client Subnet by using the DNS-server
|
||||
configuration section on the DNS settings page in the UI ([#1472]).
|
||||
- The ability to manage Safe Search for each service by using the new
|
||||
`safe_search` property ([#1163]).
|
||||
|
||||
### Changed
|
||||
|
||||
- ARPA domain names containing a subnet within private networks now also
|
||||
considered private, behaving closer to [RFC 6761][rfc6761] ([#5567]).
|
||||
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 17 to 20.
|
||||
|
||||
- Property `statistics.interval`, which in schema versions 19 and earlier used
|
||||
to be an integer number of days, is now a string with a human-readable
|
||||
duration:
|
||||
|
||||
```yaml
|
||||
# BEFORE:
|
||||
'statistics':
|
||||
# …
|
||||
'interval': 1
|
||||
|
||||
# AFTER:
|
||||
'statistics':
|
||||
# …
|
||||
'interval': '24h'
|
||||
```
|
||||
|
||||
To rollback this change, convert the property back into days and change the
|
||||
`schema_version` back to `19`.
|
||||
- The `dns.safesearch_enabled` property has been replaced with `safe_search`
|
||||
object containing per-service settings.
|
||||
- The `clients.persistent.safesearch_enabled` property has been replaced with
|
||||
`safe_search` object containing per-service settings.
|
||||
|
||||
```yaml
|
||||
# BEFORE:
|
||||
'safesearch_enabled': true
|
||||
|
||||
# AFTER:
|
||||
'safe_search':
|
||||
'enabled': true
|
||||
'bing': true
|
||||
'duckduckgo': true
|
||||
'google': true
|
||||
'pixabay': true
|
||||
'yandex': true
|
||||
'youtube': true
|
||||
```
|
||||
|
||||
To rollback this change, move the value of `dns.safe_search.enabled` into the
|
||||
`dns.safesearch_enabled`, then remove `dns.safe_search` property. Do the same
|
||||
client's specific `clients.persistent.safesearch` and then change the
|
||||
`schema_version` back to `17`.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- The `POST /control/safesearch/enable` HTTP API is deprecated. Use the new
|
||||
`PUT /control/safesearch/settings` API.
|
||||
- The `POST /control/safesearch/disable` HTTP API is deprecated. Use the new
|
||||
`PUT /control/safesearch/settings` API
|
||||
- The `safesearch_enabled` property is deprecated in the following HTTP APIs:
|
||||
- `GET /control/clients`;
|
||||
- `POST /control/clients/add`;
|
||||
- `POST /control/clients/update`;
|
||||
- `GET /control/clients/find?ip0=...&ip1=...&ip2=...`.
|
||||
|
||||
Check `openapi/openapi.yaml` for more details.
|
||||
- The `GET /control/stats_info` HTTP API; use the new `GET
|
||||
/control/stats/config` API instead.
|
||||
|
||||
**NOTE:** If interval is custom then it will be equal to `90` days for
|
||||
compatibility reasons. See `openapi/openapi.yaml` and `openapi/CHANGELOG.md`.
|
||||
- The `POST /control/stats_config` HTTP API; use the new `PUT
|
||||
/control/stats/config/update` API instead.
|
||||
- The `GET /control/querylog_info` HTTP API; use the new `GET
|
||||
/control/querylog/config` API instead.
|
||||
|
||||
**NOTE:** If interval is custom then it will be equal to `90` days for
|
||||
compatibility reasons. See `openapi/openapi.yaml` and `openapi/CHANGELOG.md`.
|
||||
- The `POST /control/querylog_config` HTTP API; use the new `PUT
|
||||
/control/querylog/config/update` API instead.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Logging of the client's IP address after failed login attempts ([#5701]).
|
||||
|
||||
[#1163]: https://github.com/AdguardTeam/AdGuardHome/issues/1163
|
||||
[#1333]: https://github.com/AdguardTeam/AdGuardHome/issues/1333
|
||||
[#1472]: https://github.com/AdguardTeam/AdGuardHome/issues/1472
|
||||
[#3290]: https://github.com/AdguardTeam/AdGuardHome/issues/3290
|
||||
[#3459]: https://github.com/AdguardTeam/AdGuardHome/issues/3459
|
||||
[#4262]: https://github.com/AdguardTeam/AdGuardHome/issues/4262
|
||||
[#5567]: https://github.com/AdguardTeam/AdGuardHome/issues/5567
|
||||
[#5701]: https://github.com/AdguardTeam/AdGuardHome/issues/5701
|
||||
|
||||
[ms-v0.107.28]: https://github.com/AdguardTeam/AdGuardHome/milestone/64?closed=1
|
||||
[rfc6761]: https://www.rfc-editor.org/rfc/rfc6761
|
||||
|
||||
|
||||
|
||||
|
||||
## [v0.107.27] - 2023-04-05
|
||||
|
||||
See also the [v0.107.27 GitHub milestone][ms-v0.107.27].
|
||||
|
||||
### Security
|
||||
|
||||
- Go version has been updated to prevent the possibility of exploiting the
|
||||
CVE-2023-24534, CVE-2023-24536, CVE-2023-24537, and CVE-2023-24538 Go
|
||||
vulnerabilities fixed in [Go 1.19.8][go-1.19.8].
|
||||
|
||||
### Fixed
|
||||
|
||||
- Query log not showing all filtered queries when the “Filtered” log filter is
|
||||
selected ([#5639]).
|
||||
- Panic in empty hostname in the filter's URL ([#5631]).
|
||||
- Panic caused by empty top-level domain name label in `/etc/hosts` files
|
||||
([#5584]).
|
||||
|
||||
[#5584]: https://github.com/AdguardTeam/AdGuardHome/issues/5584
|
||||
[#5631]: https://github.com/AdguardTeam/AdGuardHome/issues/5631
|
||||
[#5639]: https://github.com/AdguardTeam/AdGuardHome/issues/5639
|
||||
|
||||
[go-1.19.8]: https://groups.google.com/g/golang-announce/c/Xdv6JL9ENs8/m/OV40vnafAwAJ
|
||||
[ms-v0.107.27]: https://github.com/AdguardTeam/AdGuardHome/milestone/63?closed=1
|
||||
|
||||
|
||||
|
||||
## [v0.107.26] - 2023-03-09
|
||||
|
||||
See also the [v0.107.26 GitHub milestone][ms-v0.107.26].
|
||||
|
||||
### Security
|
||||
|
||||
- Go version has been updated to prevent the possibility of exploiting the
|
||||
CVE-2023-24532 Go vulnerability fixed in [Go 1.19.7][go-1.19.7].
|
||||
|
||||
### Added
|
||||
|
||||
- The ability to set custom IP for EDNS Client Subnet by using the new
|
||||
`dns.edns_client_subnet.use_custom` and `dns.edns_client_subnet.custom_ip`
|
||||
properties ([#1472]). The UI changes are coming in the upcoming releases.
|
||||
- The ability to use `dnstype` rules in the disallowed domains list ([#5468]).
|
||||
This allows dropping requests based on their question types.
|
||||
|
||||
### Changed
|
||||
|
||||
#### Configuration Changes
|
||||
|
||||
- Property `edns_client_subnet`, which in schema versions 16 and earlier used
|
||||
to be a part of the `dns` object, is now part of the `dns.edns_client_subnet`
|
||||
object:
|
||||
|
||||
```yaml
|
||||
# BEFORE:
|
||||
'dns':
|
||||
# …
|
||||
'edns_client_subnet': false
|
||||
|
||||
# AFTER:
|
||||
'dns':
|
||||
# …
|
||||
'edns_client_subnet':
|
||||
'enabled': false
|
||||
'use_custom': false
|
||||
'custom_ip': ''
|
||||
```
|
||||
|
||||
To rollback this change, move the value of `dns.edns_client_subnet.enabled`
|
||||
into the `dns.edns_client_subnet`, remove the properties
|
||||
`dns.edns_client_subnet.enabled`, `dns.edns_client_subnet.use_custom`,
|
||||
`dns.edns_client_subnet.custom_ip`, and change the `schema_version` back to
|
||||
`16`.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Obsolete value of the Interface MTU DHCP option is now omitted ([#5281]).
|
||||
- Various dark theme bugs ([#5439], [#5441], [#5442], [#5515]).
|
||||
- Automatic update on MIPS64 and little-endian 32-bit MIPS architectures
|
||||
([#5270], [#5373]).
|
||||
- Requirements to domain names in domain-specific upstream configurations have
|
||||
been relaxed to meet those from [RFC 3696][rfc3696] ([#4884]).
|
||||
- Failing service installation via script on FreeBSD ([#5431]).
|
||||
|
||||
[#1472]: https://github.com/AdguardTeam/AdGuardHome/issues/1472
|
||||
[#4884]: https://github.com/AdguardTeam/AdGuardHome/issues/4884
|
||||
[#5270]: https://github.com/AdguardTeam/AdGuardHome/issues/5270
|
||||
[#5281]: https://github.com/AdguardTeam/AdGuardHome/issues/5281
|
||||
[#5373]: https://github.com/AdguardTeam/AdGuardHome/issues/5373
|
||||
[#5431]: https://github.com/AdguardTeam/AdGuardHome/issues/5431
|
||||
[#5439]: https://github.com/AdguardTeam/AdGuardHome/issues/5439
|
||||
[#5441]: https://github.com/AdguardTeam/AdGuardHome/issues/5441
|
||||
[#5442]: https://github.com/AdguardTeam/AdGuardHome/issues/5442
|
||||
[#5468]: https://github.com/AdguardTeam/AdGuardHome/issues/5468
|
||||
[#5515]: https://github.com/AdguardTeam/AdGuardHome/issues/5515
|
||||
|
||||
[go-1.19.7]: https://groups.google.com/g/golang-announce/c/3-TpUx48iQY
|
||||
[ms-v0.107.26]: https://github.com/AdguardTeam/AdGuardHome/milestone/62?closed=1
|
||||
[rfc3696]: https://datatracker.ietf.org/doc/html/rfc3696
|
||||
|
||||
|
||||
|
||||
## [v0.107.25] - 2023-02-21
|
||||
|
||||
See also the [v0.107.25 GitHub milestone][ms-v0.107.25].
|
||||
|
||||
### Fixed
|
||||
|
||||
- Panic when using unencrypted DNS-over-HTTPS ([#5518]).
|
||||
|
||||
[#5518]: https://github.com/AdguardTeam/AdGuardHome/issues/5518
|
||||
|
||||
[ms-v0.107.25]: https://github.com/AdguardTeam/AdGuardHome/milestone/61?closed=1
|
||||
|
||||
|
||||
|
||||
## [v0.107.24] - 2023-02-15
|
||||
|
||||
See also the [v0.107.24 GitHub milestone][ms-v0.107.24].
|
||||
|
||||
### Security
|
||||
|
||||
- Go version has been updated, both because Go 1.18 has reached end of life an
|
||||
to prevent the possibility of exploiting the Go vulnerabilities fixed in [Go
|
||||
1.19.6][go-1.19.6].
|
||||
|
||||
### Added
|
||||
|
||||
- The ability to disable statistics by using the new `statistics.enabled`
|
||||
property. Previously it was necessary to set the `statistics_interval` to 0,
|
||||
losing the previous value ([#1717], [#4299]).
|
||||
- The ability to exclude domain names from the query log or statistics by using
|
||||
the new `querylog.ignored` or `statistics.ignored` properties ([#1717],
|
||||
[#4299]). The UI changes are coming in the upcoming releases.
|
||||
|
||||
### Changed
|
||||
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 14 to 16.
|
||||
|
||||
- Property `statistics_interval`, which in schema versions 15 and earlier used
|
||||
to be a part of the `dns` object, is now a part of the `statistics` object:
|
||||
|
||||
```yaml
|
||||
# BEFORE:
|
||||
'dns':
|
||||
# …
|
||||
'statistics_interval': 1
|
||||
|
||||
# AFTER:
|
||||
'statistics':
|
||||
# …
|
||||
'interval': 1
|
||||
```
|
||||
|
||||
To rollback this change, move the property back into the `dns` object and
|
||||
change the `schema_version` back to `15`.
|
||||
- The properties `dns.querylog_enabled`, `dns.querylog_file_enabled`,
|
||||
`dns.querylog_interval`, and `dns.querylog_size_memory` have been moved to the
|
||||
new `querylog` object.
|
||||
|
||||
```yaml
|
||||
# BEFORE:
|
||||
'dns':
|
||||
'querylog_enabled': true
|
||||
'querylog_file_enabled': true
|
||||
'querylog_interval': '2160h'
|
||||
'querylog_size_memory': 1000
|
||||
|
||||
# AFTER:
|
||||
'querylog':
|
||||
'enabled': true
|
||||
'file_enabled': true
|
||||
'interval': '2160h'
|
||||
'size_memory': 1000
|
||||
'ignored': []
|
||||
```
|
||||
|
||||
To rollback this change, rename and move properties back into the `dns`
|
||||
object, remove `querylog` object and `querylog.ignored` property, and change
|
||||
the `schema_version` back to `14`.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Go 1.19 support. Future versions will require at least Go 1.20 to build.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Setting the AD (Authenticated Data) flag on responses that have the DO (DNSSEC
|
||||
OK) flag set but not the AD flag ([#5479]).
|
||||
- Client names resolved via reverse DNS not being updated ([#4939]).
|
||||
- The icon for League Of Legends on the Blocked services page ([#5433]).
|
||||
|
||||
### Removed
|
||||
|
||||
- Go 1.18 support, as it has reached end of life.
|
||||
|
||||
[#1717]: https://github.com/AdguardTeam/AdGuardHome/issues/1717
|
||||
[#4299]: https://github.com/AdguardTeam/AdGuardHome/issues/4299
|
||||
[#4939]: https://github.com/AdguardTeam/AdGuardHome/issues/4939
|
||||
[#5433]: https://github.com/AdguardTeam/AdGuardHome/issues/5433
|
||||
[#5479]: https://github.com/AdguardTeam/AdGuardHome/issues/5479
|
||||
|
||||
[go-1.19.6]: https://groups.google.com/g/golang-announce/c/V0aBFqaFs_E
|
||||
[ms-v0.107.24]: https://github.com/AdguardTeam/AdGuardHome/milestone/60?closed=1
|
||||
|
||||
|
||||
|
||||
## [v0.107.23] - 2023-02-01
|
||||
|
||||
See also the [v0.107.23 GitHub milestone][ms-v0.107.23].
|
||||
@@ -42,8 +539,8 @@ See also the [v0.107.23 GitHub milestone][ms-v0.107.23].
|
||||
### Added
|
||||
|
||||
- DNS64 support ([#5117]). The function may be enabled with new `use_dns64`
|
||||
field under `dns` object in the configuration along with `dns64_prefixes`, the
|
||||
set of exclusion prefixes to filter AAAA responses. The Well-Known Prefix
|
||||
property under `dns` object in the configuration along with `dns64_prefixes`,
|
||||
the set of exclusion prefixes to filter AAAA responses. The Well-Known Prefix
|
||||
(`64:ff9b::/96`) is used if no custom prefixes are specified.
|
||||
|
||||
### Fixed
|
||||
@@ -701,7 +1198,7 @@ In this release, the schema version has changed from 12 to 14.
|
||||
hosts: true
|
||||
```
|
||||
|
||||
The value for `clients.runtime_sources.rdns` field is taken from
|
||||
The value for `clients.runtime_sources.rdns` property is taken from
|
||||
`dns.resolve_clients` property. To rollback this change, remove the
|
||||
`runtime_sources` property, move the contents of `persistent` into the
|
||||
`clients` itself, the value of `clients.runtime_sources.rdns` into the
|
||||
@@ -951,7 +1448,7 @@ See also the [v0.107.0 GitHub milestone][ms-v0.107.0].
|
||||
log entries concerning cached responses won't include that information.
|
||||
- Finnish and Ukrainian localizations.
|
||||
- Setting the timeout for IP address pinging in the "Fastest IP address" mode
|
||||
through the new `fastest_timeout` field in the configuration file ([#1992]).
|
||||
through the new `fastest_timeout` property in the configuration file ([#1992]).
|
||||
- Static IP address detection on FreeBSD ([#3289]).
|
||||
- Optimistic cache ([#2145]).
|
||||
- New possible value of `6h` for `querylog_interval` property ([#2504]).
|
||||
@@ -1037,7 +1534,6 @@ In this release, the schema version has changed from 10 to 12.
|
||||
|
||||
To rollback this change, convert the property back into days and change the
|
||||
`schema_version` back to `11`.
|
||||
|
||||
- Property `rlimit_nofile`, which in schema versions 10 and earlier used to be
|
||||
on the top level, is now moved to the new `os` object:
|
||||
|
||||
@@ -1368,7 +1864,7 @@ See also the [v0.105.2 GitHub milestone][ms-v0.105.2].
|
||||
- Inconsistent responses for messages with EDNS0 and AD when DNS caching is
|
||||
enabled ([#2600]).
|
||||
- Incomplete OpenWrt detection ([#2757]).
|
||||
- DHCP lease's `expired` field incorrect time format ([#2692]).
|
||||
- DHCP lease's `expired` property incorrect time format ([#2692]).
|
||||
- Incomplete DNS upstreams validation ([#2674]).
|
||||
- Wrong parsing of DHCP options of the `ip` type ([#2688]).
|
||||
|
||||
@@ -1405,8 +1901,8 @@ See also the [v0.105.1 GitHub milestone][ms-v0.105.1].
|
||||
the machine has a static IP.
|
||||
- Optical issue on custom rules ([#2641]).
|
||||
- Occasional crashes during startup.
|
||||
- The field `"range_start"` in the `GET /control/dhcp/status` HTTP API response
|
||||
is now correctly named again ([#2678]).
|
||||
- The property `"range_start"` in the `GET /control/dhcp/status` HTTP API
|
||||
response is now correctly named again ([#2678]).
|
||||
- DHCPv6 server's `ra_slaac_only` and `ra_allow_slaac` properties aren't reset
|
||||
to `false` on update anymore ([#2653]).
|
||||
- The `Vary` header is now added along with `Access-Control-Allow-Origin` to
|
||||
@@ -1476,7 +1972,7 @@ See also the [v0.105.0 GitHub milestone][ms-v0.105.0].
|
||||
|
||||
- Go 1.14 support. v0.106.0 will require at least Go 1.15 to build.
|
||||
- The `darwin/386` port. It will be removed in v0.106.0.
|
||||
- The `"rule"` and `"filter_id"` fields in `GET /filtering/check_host` and
|
||||
- The `"rule"` and `"filter_id"` property in `GET /filtering/check_host` and
|
||||
`GET /querylog` responses. They will be removed in v0.106.0 ([#2102]).
|
||||
|
||||
### Fixed
|
||||
@@ -1584,11 +2080,20 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
|
||||
|
||||
|
||||
<!--
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.24...HEAD
|
||||
[v0.107.24]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.23...v0.107.24
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.33...HEAD
|
||||
[v0.107.33]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.32...v0.107.33
|
||||
-->
|
||||
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.23...HEAD
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.32...HEAD
|
||||
[v0.107.32]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.31...v0.107.32
|
||||
[v0.107.31]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.30...v0.107.31
|
||||
[v0.107.30]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.29...v0.107.30
|
||||
[v0.107.29]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.28...v0.107.29
|
||||
[v0.107.28]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.27...v0.107.28
|
||||
[v0.107.27]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.26...v0.107.27
|
||||
[v0.107.26]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.25...v0.107.26
|
||||
[v0.107.25]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.24...v0.107.25
|
||||
[v0.107.24]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.23...v0.107.24
|
||||
[v0.107.23]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.22...v0.107.23
|
||||
[v0.107.22]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.21...v0.107.22
|
||||
[v0.107.21]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.20...v0.107.21
|
||||
|
||||
32
Makefile
32
Makefile
@@ -4,17 +4,26 @@
|
||||
# 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: 2
|
||||
|
||||
# Don't name these macros "GO" etc., because GNU Make apparently makes
|
||||
# them exported environment variables with the literal value of
|
||||
# "${GO:-go}" and so on, which is not what we need. Use a dot in the
|
||||
# name to make sure that users don't have an environment variable with
|
||||
# the same name.
|
||||
#
|
||||
# See https://unix.stackexchange.com/q/646255/105635.
|
||||
GO.MACRO = $${GO:-go}
|
||||
VERBOSE.MACRO = $${VERBOSE:-0}
|
||||
|
||||
CHANNEL = development
|
||||
CLIENT_DIR = client
|
||||
COMMIT = $$( git rev-parse --short HEAD )
|
||||
DIST_DIR = dist
|
||||
# Don't name this macro "GO", because GNU Make apparenly makes it an
|
||||
# exported environment variable with the literal value of "${GO:-go}",
|
||||
# which is not what we need. Use a dot in the name to make sure that
|
||||
# users don't have an environment variable with the same name.
|
||||
#
|
||||
# See https://unix.stackexchange.com/q/646255/105635.
|
||||
GO.MACRO = $${GO:-go}
|
||||
GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct
|
||||
GOSUMDB = sum.golang.google.cn
|
||||
GPG_KEY = devteam@adguard.com
|
||||
@@ -25,7 +34,6 @@ NPM_INSTALL_FLAGS = $(NPM_FLAGS) --quiet --no-progress --ignore-engines\
|
||||
--ignore-optional --ignore-platform --ignore-scripts
|
||||
RACE = 0
|
||||
SIGN = 1
|
||||
VERBOSE = 0
|
||||
VERSION = v0.0.0
|
||||
YARN = yarn
|
||||
|
||||
@@ -59,13 +67,13 @@ ENV = env\
|
||||
RACE='$(RACE)'\
|
||||
SIGN='$(SIGN)'\
|
||||
NEXTAPI='$(NEXTAPI)'\
|
||||
VERBOSE='$(VERBOSE)'\
|
||||
VERBOSE="$(VERBOSE.MACRO)"\
|
||||
VERSION='$(VERSION)'\
|
||||
|
||||
# Keep the line above blank.
|
||||
|
||||
# Keep this target first, so that a naked make invocation triggers
|
||||
# a full build.
|
||||
# Keep this target first, so that a naked make invocation triggers a
|
||||
# full build.
|
||||
build: deps quick-build
|
||||
|
||||
quick-build: js-build go-build
|
||||
@@ -119,4 +127,4 @@ go-os-check:
|
||||
openapi-lint: ; cd ./openapi/ && $(YARN) test
|
||||
openapi-show: ; cd ./openapi/ && $(YARN) start
|
||||
|
||||
txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh
|
||||
txt-lint: ; $(ENV) "$(SHELL)" ./scripts/make/txt-lint.sh
|
||||
|
||||
20
README.md
20
README.md
@@ -81,12 +81,24 @@ code.
|
||||
|
||||
### <a href="#automated-install-linux-and-mac" id="automated-install-linux-and-mac" name="automated-install-linux-and-mac">Automated install (Unix)</a>
|
||||
|
||||
Run the following command in your terminal:
|
||||
To install with `curl` run the following command:
|
||||
|
||||
```sh
|
||||
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
|
||||
```
|
||||
|
||||
To install with `wget` run the following command:
|
||||
|
||||
```sh
|
||||
wget --no-verbose -O - https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
|
||||
```
|
||||
|
||||
To install with `fetch` run the following command:
|
||||
|
||||
```sh
|
||||
fetch -o - https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
|
||||
```
|
||||
|
||||
The script also accepts some options:
|
||||
|
||||
* `-c <channel>` to use specified channel;
|
||||
@@ -249,7 +261,7 @@ Run `make init` to prepare the development environment.
|
||||
|
||||
You will need this to build AdGuard Home:
|
||||
|
||||
* [Go](https://golang.org/dl/) v1.18 or later;
|
||||
* [Go](https://golang.org/dl/) v1.19 or later;
|
||||
* [Node.js](https://nodejs.org/en/download/) v10.16.2 or later;
|
||||
* [npm](https://www.npmjs.com/) v6.14 or later;
|
||||
* [yarn](https://yarnpkg.com/) v1.22.5 or later.
|
||||
@@ -454,6 +466,10 @@ bug or implementing the feature.
|
||||
Home](https://github.com/ebrianne/adguard-exporter) by
|
||||
[@ebrianne](https://github.com/ebrianne).
|
||||
|
||||
* [Terminal-based, real-time traffic monitoring and statistics for your AdGuard Home
|
||||
instance](https://github.com/Lissy93/AdGuardian-Term) by
|
||||
[@Lissy93](https://github.com/Lissy93)
|
||||
|
||||
* [AdGuard Home on GLInet
|
||||
routers](https://forum.gl-inet.com/t/adguardhome-on-gl-routers/10664) by
|
||||
[Gl-Inet](https://gl-inet.com/).
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
---
|
||||
!include test.yaml
|
||||
|
||||
---
|
||||
!include release.yaml
|
||||
|
||||
---
|
||||
!include snapcraft.yaml
|
||||
|
||||
---
|
||||
!include test.yaml
|
||||
|
||||
@@ -1,341 +1,290 @@
|
||||
---
|
||||
'version': 2
|
||||
'plan':
|
||||
'project-key': 'AGH'
|
||||
'key': 'AGHBSNAPSPECS'
|
||||
'name': 'AdGuard Home - Build and publish release'
|
||||
'project-key': 'AGH'
|
||||
'key': 'AGHBSNAPSPECS'
|
||||
'name': 'AdGuard Home - Build and publish release'
|
||||
# Make sure to sync any changes with the branch overrides below.
|
||||
'variables':
|
||||
'channel': 'edge'
|
||||
'dockerGo': 'adguard/golang-ubuntu:5.4'
|
||||
'channel': 'edge'
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.7'
|
||||
|
||||
'stages':
|
||||
- 'Build frontend':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Build frontend'
|
||||
- 'Build frontend':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Build frontend'
|
||||
|
||||
- 'Make release':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Make release'
|
||||
- 'Make release':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Make release'
|
||||
|
||||
- 'Make and publish docker':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Make and publish docker'
|
||||
- 'Make and publish docker':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Make and publish docker'
|
||||
|
||||
- 'Publish to static storage':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to static storage'
|
||||
- 'Publish to static storage':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to static storage'
|
||||
|
||||
- 'Publish to Snapstore':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to Snapstore'
|
||||
|
||||
- 'Publish to GitHub Releases':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to GitHub Releases'
|
||||
- 'Publish to GitHub Releases':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to GitHub Releases'
|
||||
|
||||
'Build frontend':
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.YARN_DIR}': '${bamboo.cacheYarn}'
|
||||
'key': 'BF'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.YARN_DIR}': '${bamboo.cacheYarn}'
|
||||
'key': 'BF'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
set -e -f -u -x
|
||||
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "${bamboo.repository.revision.number}"
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "${bamboo.repository.revision.number}"
|
||||
|
||||
make js-deps js-build
|
||||
'artifacts':
|
||||
- 'name': 'AdGuardHome frontend'
|
||||
'pattern': 'build*/**'
|
||||
'shared': true
|
||||
'required': true
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
make js-deps js-build
|
||||
'artifacts':
|
||||
- 'name': 'AdGuardHome frontend'
|
||||
'pattern': 'build/**'
|
||||
'shared': true
|
||||
'required': true
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Make release':
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.GO_CACHE_DIR}': '${bamboo.cacheGo}'
|
||||
'${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}'
|
||||
'key': 'MR'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.GO_CACHE_DIR}': '${bamboo.cacheGo}'
|
||||
'${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}'
|
||||
'key': 'MR'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
set -e -f -u -x
|
||||
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "${bamboo.repository.revision.number}"
|
||||
# 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; }'\
|
||||
| gpg --import --batch --yes
|
||||
# Run the build with the specified channel.
|
||||
echo "${bamboo.gpgSecretKeyPart1}${bamboo.gpgSecretKeyPart2}"\
|
||||
| awk '{ gsub(/\\n/, "\n"); print; }'\
|
||||
| gpg --import --batch --yes
|
||||
|
||||
make\
|
||||
CHANNEL=${bamboo.channel}\
|
||||
GPG_KEY_PASSPHRASE=${bamboo.gpgPassword}\
|
||||
FRONTEND_PREBUILT=1\
|
||||
PARALLELISM=1\
|
||||
VERBOSE=2\
|
||||
build-release
|
||||
# TODO(a.garipov): Use more fine-grained artifact rules.
|
||||
'artifacts':
|
||||
- 'name': 'AdGuardHome dists'
|
||||
'pattern': 'dist/**'
|
||||
'shared': true
|
||||
'required': true
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
make\
|
||||
CHANNEL=${bamboo.channel}\
|
||||
GPG_KEY_PASSPHRASE=${bamboo.gpgPassword}\
|
||||
FRONTEND_PREBUILT=1\
|
||||
PARALLELISM=1\
|
||||
VERBOSE=2\
|
||||
build-release
|
||||
# TODO(a.garipov): Use more fine-grained artifact rules.
|
||||
'artifacts':
|
||||
- 'name': 'AdGuardHome dists'
|
||||
'pattern': 'dist/**'
|
||||
'shared': true
|
||||
'required': true
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Make and publish docker':
|
||||
'key': 'MPD'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
'key': 'MPD'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
set -e -f -u -x
|
||||
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "${bamboo.repository.revision.number}"
|
||||
COMMIT="${bamboo.repository.revision.number}"
|
||||
export COMMIT
|
||||
readonly COMMIT
|
||||
|
||||
# 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 inspect --bootstrap
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "$COMMIT"
|
||||
|
||||
# Login to DockerHub.
|
||||
docker login -u="${bamboo.dockerHubUsername}"\
|
||||
-p="${bamboo.dockerHubPassword}"
|
||||
# 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 inspect --bootstrap
|
||||
|
||||
# Boot the builder.
|
||||
docker buildx inspect --bootstrap
|
||||
# Login to DockerHub.
|
||||
docker login -u="${bamboo.dockerHubUsername}"\
|
||||
-p="${bamboo.dockerHubPassword}"
|
||||
|
||||
# Print Docker info.
|
||||
docker info
|
||||
# Boot the builder.
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
# Prepare and push the build.
|
||||
make\
|
||||
CHANNEL="${bamboo.channel}"\
|
||||
DOCKER_IMAGE_NAME='adguard/adguardhome'\
|
||||
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true"\
|
||||
VERBOSE='1'\
|
||||
build-docker
|
||||
'environment':
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
# Print Docker info.
|
||||
docker info
|
||||
|
||||
# Prepare and push the build.
|
||||
env\
|
||||
CHANNEL="${bamboo.channel}"\
|
||||
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':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Publish to static storage':
|
||||
'key': 'PUB'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'clean'
|
||||
- 'checkout':
|
||||
'repository': 'bamboo-deploy-publisher'
|
||||
'path': 'bamboo-deploy-publisher'
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
'key': 'PUB'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'clean'
|
||||
- 'checkout':
|
||||
'repository': 'bamboo-deploy-publisher'
|
||||
'path': 'bamboo-deploy-publisher'
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
set -e -f -u -x
|
||||
|
||||
cd ./dist/
|
||||
cd ./dist/
|
||||
|
||||
CHANNEL="${bamboo.channel}"
|
||||
export CHANNEL
|
||||
CHANNEL="${bamboo.channel}"
|
||||
export CHANNEL
|
||||
|
||||
../bamboo-deploy-publisher/deploy.sh adguard-home-"$CHANNEL"
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Publish to Snapstore':
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'key': 'PTS'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'clean'
|
||||
- 'checkout':
|
||||
'repository': 'bamboo-deploy-publisher'
|
||||
'path': 'bamboo-deploy-publisher'
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
|
||||
cd ./dist/
|
||||
|
||||
channel="${bamboo.channel}"
|
||||
readonly channel
|
||||
case "$channel"
|
||||
in
|
||||
('release')
|
||||
snapchannel='candidate'
|
||||
;;
|
||||
('beta')
|
||||
snapchannel='beta'
|
||||
;;
|
||||
('edge')
|
||||
snapchannel='edge'
|
||||
;;
|
||||
(*)
|
||||
echo "invalid channel '$channel'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
env\
|
||||
SNAPCRAFT_CHANNEL="$snapchannel"\
|
||||
SNAPCRAFT_EMAIL="${bamboo.snapcraftEmail}"\
|
||||
SNAPCRAFT_MACAROON="${bamboo.snapcraftMacaroonPassword}"\
|
||||
SNAPCRAFT_UBUNTU_DISCHARGE="${bamboo.snapcraftUbuntuDischargePassword}"\
|
||||
../bamboo-deploy-publisher/deploy.sh adguard-home-snap
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
../bamboo-deploy-publisher/deploy.sh adguard-home-"$CHANNEL"
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Publish to GitHub Releases':
|
||||
'key': 'PTGR'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'clean'
|
||||
- 'checkout':
|
||||
'repository': 'bamboo-deploy-publisher'
|
||||
'path': 'bamboo-deploy-publisher'
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
'key': 'PTGR'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'clean'
|
||||
- 'checkout':
|
||||
'repository': 'bamboo-deploy-publisher'
|
||||
'path': 'bamboo-deploy-publisher'
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
set -e -f -u -x
|
||||
|
||||
export CHANNEL="${bamboo.channel}"
|
||||
if [ "$CHANNEL" != 'release' ] && [ "${CHANNEL}" != 'beta' ]
|
||||
then
|
||||
echo "don't publish to GitHub Releases for this channel"
|
||||
channel="${bamboo.channel}"
|
||||
readonly channel
|
||||
|
||||
exit 0
|
||||
fi
|
||||
if [ "$channel" != 'release' ] && [ "${channel}" != 'beta' ]
|
||||
then
|
||||
echo "don't publish to GitHub Releases for this channel"
|
||||
|
||||
cd ./dist/
|
||||
exit 0
|
||||
fi
|
||||
|
||||
env\
|
||||
GITHUB_TOKEN="${bamboo.githubPublicRepoPassword}"\
|
||||
../bamboo-deploy-publisher/deploy.sh adguard-home-github
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
cd ./dist/
|
||||
|
||||
env\
|
||||
GITHUB_TOKEN="${bamboo.githubPublicRepoPassword}"\
|
||||
../bamboo-deploy-publisher/deploy.sh adguard-home-github
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'triggers':
|
||||
# Don't use minute values that end with a zero or a five as these are often used
|
||||
# in CI and so resources during these minutes can be quite busy.
|
||||
- 'cron': '0 42 13 ? * MON-FRI *'
|
||||
# Don't use minute values that end with a zero or a five as these are often
|
||||
# used in CI and so resources during these minutes can be quite busy.
|
||||
- 'cron': '0 42 13 ? * MON-FRI *'
|
||||
'branches':
|
||||
'create': 'manually'
|
||||
'delete':
|
||||
'after-deleted-days': 1
|
||||
'after-inactive-days': 30
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'AdGuard Home - Build and publish release'
|
||||
'link-to-jira': true
|
||||
'create': 'manually'
|
||||
'delete':
|
||||
'after-deleted-days': 1
|
||||
'after-inactive-days': 30
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'AdGuard Home - Build and publish release'
|
||||
'link-to-jira': true
|
||||
|
||||
'notifications':
|
||||
- 'events':
|
||||
- 'plan-completed'
|
||||
'recipients':
|
||||
- 'webhook':
|
||||
'name': 'Build webhook'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo?channel=adguard-qa'
|
||||
- 'events':
|
||||
- 'plan-completed'
|
||||
'recipients':
|
||||
- 'webhook':
|
||||
'name': 'Build webhook'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo?channel=adguard-qa'
|
||||
|
||||
'labels': []
|
||||
'other':
|
||||
'concurrent-build-plugin': 'system-default'
|
||||
'concurrent-build-plugin': 'system-default'
|
||||
|
||||
'branch-overrides':
|
||||
# beta-vX.Y branches are the branches into which the commits that are needed to
|
||||
# release a new patch version are initially cherry-picked.
|
||||
- '^beta-v[0-9]+\.[0-9]+':
|
||||
# Build betas on release branches manually.
|
||||
'triggers': []
|
||||
# Set the default release channel on the release branch to beta, as we may
|
||||
# need to build a few of these.
|
||||
'variables':
|
||||
'channel': 'beta'
|
||||
'dockerGo': 'adguard/golang-ubuntu:5.4'
|
||||
# release-vX.Y.Z branches are the branches from which the actual final release
|
||||
# is built.
|
||||
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
||||
# Disable integration branches for release branches.
|
||||
'branch-config':
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'beta-v0.107'
|
||||
# Build final releases on release branches manually.
|
||||
'triggers': []
|
||||
# Set the default release channel on the final branch to release, as these
|
||||
# are the ones that actually get released.
|
||||
'variables':
|
||||
'channel': 'release'
|
||||
'dockerGo': 'adguard/golang-ubuntu:5.4'
|
||||
# beta-vX.Y branches are the branches into which the commits that are needed
|
||||
# to release a new patch version are initially cherry-picked.
|
||||
- '^beta-v[0-9]+\.[0-9]+':
|
||||
# Build betas on release branches manually.
|
||||
'triggers': []
|
||||
# Set the default release channel on the release branch to beta, as we may
|
||||
# need to build a few of these.
|
||||
'variables':
|
||||
'channel': 'beta'
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.7'
|
||||
# release-vX.Y.Z branches are the branches from which the actual final
|
||||
# release is built.
|
||||
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
||||
# Disable integration branches for release branches.
|
||||
'branch-config':
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'beta-v0.107'
|
||||
# Build final releases on release branches manually.
|
||||
'triggers': []
|
||||
# Set the default release channel on the final branch to release, as these
|
||||
# are the ones that actually get released.
|
||||
'variables':
|
||||
'channel': 'release'
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.7'
|
||||
|
||||
211
bamboo-specs/snapcraft.yaml
Normal file
211
bamboo-specs/snapcraft.yaml
Normal file
@@ -0,0 +1,211 @@
|
||||
---
|
||||
# This part of the release build is separate from the one described in
|
||||
# release.yaml, because the Snapcraft infrastructure is brittle, and timeouts
|
||||
# during logins and uploads often lead to release blocking.
|
||||
'version': 2
|
||||
'plan':
|
||||
'project-key': 'AGH'
|
||||
'key': 'AGHSNAP'
|
||||
'name': 'AdGuard Home - Build and publish Snapcraft release'
|
||||
# Make sure to sync any changes with the branch overrides below.
|
||||
'variables':
|
||||
'channel': 'edge'
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.7'
|
||||
'snapcraftChannel': 'edge'
|
||||
|
||||
'stages':
|
||||
- 'Download release':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Download release'
|
||||
|
||||
- 'Build packages':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Build packages'
|
||||
|
||||
- 'Publish to Snapstore':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to Snapstore'
|
||||
|
||||
# TODO(a.garipov): Consider using the Artifact Downloader Task if it ever learns
|
||||
# about plan branches.
|
||||
'Download release':
|
||||
'artifacts':
|
||||
- 'name': 'i386_binary'
|
||||
'pattern': 'AdGuardHome_i386'
|
||||
'shared': true
|
||||
'required': true
|
||||
- 'name': 'amd64_binary'
|
||||
'pattern': 'AdGuardHome_amd64'
|
||||
'shared': true
|
||||
'required': true
|
||||
- 'name': 'armhf_binary'
|
||||
'pattern': 'AdGuardHome_armhf'
|
||||
'shared': true
|
||||
'required': true
|
||||
- 'name': 'arm64_binary'
|
||||
'pattern': 'AdGuardHome_arm64'
|
||||
'shared': true
|
||||
'required': true
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'key': 'DR'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
|
||||
env\
|
||||
CHANNEL="${bamboo.channel}"\
|
||||
VERBOSE='1'\
|
||||
sh ./scripts/snap/download.sh
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Build packages':
|
||||
'artifact-subscriptions':
|
||||
- 'artifact': 'i386_binary'
|
||||
- 'artifact': 'amd64_binary'
|
||||
- 'artifact': 'armhf_binary'
|
||||
- 'artifact': 'arm64_binary'
|
||||
'artifacts':
|
||||
- 'name': 'i386_snap'
|
||||
'pattern': 'AdGuardHome_i386.snap'
|
||||
'shared': true
|
||||
'required': true
|
||||
- 'name': 'amd64_snap'
|
||||
'pattern': 'AdGuardHome_amd64.snap'
|
||||
'shared': true
|
||||
'required': true
|
||||
- 'name': 'armhf_snap'
|
||||
'pattern': 'AdGuardHome_armhf.snap'
|
||||
'shared': true
|
||||
'required': true
|
||||
- 'name': 'arm64_snap'
|
||||
'pattern': 'AdGuardHome_arm64.snap'
|
||||
'shared': true
|
||||
'required': true
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'key': 'BP'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
|
||||
env\
|
||||
VERBOSE='1'\
|
||||
sh ./scripts/snap/build.sh
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Publish to Snapstore':
|
||||
'artifact-subscriptions':
|
||||
- 'artifact': 'i386_snap'
|
||||
- 'artifact': 'amd64_snap'
|
||||
- 'artifact': 'armhf_snap'
|
||||
- 'artifact': 'arm64_snap'
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'key': 'PTS'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
|
||||
env\
|
||||
SNAPCRAFT_CHANNEL="${bamboo.snapcraftChannel}"\
|
||||
SNAPCRAFT_STORE_CREDENTIALS="${bamboo.snapcraftMacaroonPassword}"\
|
||||
VERBOSE='1'\
|
||||
sh ./scripts/snap/upload.sh
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'triggers':
|
||||
# Don't use minute values that end with a zero or a five as these are often
|
||||
# used in CI and so resources during these minutes can be quite busy.
|
||||
#
|
||||
# NOTE: The time is chosen to be exactly one hour after the main release
|
||||
# build as defined as in release.yaml.
|
||||
- 'cron': '0 42 14 ? * MON-FRI *'
|
||||
'branches':
|
||||
'create': 'manually'
|
||||
'delete':
|
||||
'after-deleted-days': 1
|
||||
'after-inactive-days': 30
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'AdGuard Home - Build and publish Snapcraft release'
|
||||
'link-to-jira': true
|
||||
|
||||
'notifications':
|
||||
- 'events':
|
||||
- 'plan-completed'
|
||||
'recipients':
|
||||
- 'webhook':
|
||||
'name': 'Build webhook'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo?channel=adguard-qa'
|
||||
|
||||
'labels': []
|
||||
'other':
|
||||
'concurrent-build-plugin': 'system-default'
|
||||
|
||||
'branch-overrides':
|
||||
# beta-vX.Y branches are the branches into which the commits that are needed
|
||||
# to release a new patch version are initially cherry-picked.
|
||||
- '^beta-v[0-9]+\.[0-9]+':
|
||||
# Build betas on release branches manually.
|
||||
'triggers': []
|
||||
# Set the default release channel on the release branch to beta, as we may
|
||||
# need to build a few of these.
|
||||
'variables':
|
||||
'channel': 'beta'
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.7'
|
||||
'snapcraftChannel': 'beta'
|
||||
# release-vX.Y.Z branches are the branches from which the actual final
|
||||
# release is built.
|
||||
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
||||
# Disable integration branches for release branches.
|
||||
'branch-config':
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'beta-v0.107'
|
||||
# Build final releases on release branches manually.
|
||||
'triggers': []
|
||||
# Set the default release channel on the final branch to release, as these
|
||||
# are the ones that actually get released.
|
||||
'variables':
|
||||
'channel': 'release'
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.7'
|
||||
'snapcraftChannel': 'candidate'
|
||||
@@ -1,64 +1,64 @@
|
||||
---
|
||||
'version': 2
|
||||
'plan':
|
||||
'project-key': 'AGH'
|
||||
'key': 'AHBRTSPECS'
|
||||
'name': 'AdGuard Home - Build and run tests'
|
||||
'project-key': 'AGH'
|
||||
'key': 'AHBRTSPECS'
|
||||
'name': 'AdGuard Home - Build and run tests'
|
||||
'variables':
|
||||
'dockerGo': 'adguard/golang-ubuntu:5.4'
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.7'
|
||||
|
||||
'stages':
|
||||
- 'Tests':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Test'
|
||||
- 'Tests':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Test'
|
||||
|
||||
'Test':
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.YARN_DIR}': '${bamboo.cacheYarn}'
|
||||
'${system.GO_CACHE_DIR}': '${bamboo.cacheGo}'
|
||||
'${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}'
|
||||
'key': 'TEST'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.YARN_DIR}': '${bamboo.cacheYarn}'
|
||||
'${system.GO_CACHE_DIR}': '${bamboo.cacheGo}'
|
||||
'${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}'
|
||||
'key': 'TEST'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
set -e -f -u -x
|
||||
|
||||
make VERBOSE=1 ci go-tools lint
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
make VERBOSE=1 ci go-tools lint
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'branches':
|
||||
'create': 'for-pull-request'
|
||||
'delete':
|
||||
'after-deleted-days': 1
|
||||
'after-inactive-days': 5
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'AdGuard Home - Build and run tests'
|
||||
'link-to-jira': true
|
||||
'create': 'for-pull-request'
|
||||
'delete':
|
||||
'after-deleted-days': 1
|
||||
'after-inactive-days': 5
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'AdGuard Home - Build and run tests'
|
||||
'link-to-jira': true
|
||||
|
||||
'notifications':
|
||||
- 'events':
|
||||
- 'plan-status-changed'
|
||||
'recipients':
|
||||
- 'webhook':
|
||||
'name': 'Build webhook'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo'
|
||||
- 'events':
|
||||
- 'plan-status-changed'
|
||||
'recipients':
|
||||
- 'webhook':
|
||||
'name': 'Build webhook'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo'
|
||||
|
||||
'labels': []
|
||||
'other':
|
||||
'concurrent-build-plugin': 'system-default'
|
||||
'concurrent-build-plugin': 'system-default'
|
||||
|
||||
2
client/dev.eslintrc
vendored
2
client/dev.eslintrc
vendored
@@ -3,4 +3,4 @@
|
||||
"rules": {
|
||||
"no-debugger":"warn",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,40 @@
|
||||
<link rel="mask-icon" href="assets/safari-pinned-tab.svg" color="#67B279">
|
||||
<link rel="icon" type="image/png" href="assets/favicon.png" sizes="48x48">
|
||||
<title>AdGuard Home</title>
|
||||
<style>
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
[data-theme="DARK"] .wrapper {
|
||||
background-color: #f5f7fb;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<div id="root">
|
||||
<div class="wrapper"></div>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
var LOCAL_STORAGE_THEME_KEY = 'account_theme';
|
||||
var theme = 'light';
|
||||
|
||||
try {
|
||||
theme = window.localStorage.getItem(LOCAL_STORAGE_THEME_KEY);
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
document.body.dataset.theme = theme;
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -17,5 +17,12 @@
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<script>
|
||||
(function() {
|
||||
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
var currentTheme = prefersDark ? 'dark' : 'light';
|
||||
document.body.dataset.theme = currentTheme;
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -635,5 +635,6 @@
|
||||
"parental_control": "الرقابة الابويه",
|
||||
"safe_browsing": "تصفح آمن",
|
||||
"served_from_cache": "{{value}} <i>(يتم تقديمه من ذاكرة التخزين المؤقت)</i>",
|
||||
"form_error_password_length": "يجب أن تتكون كلمة المرور من {{value}} من الأحرف على الأقل"
|
||||
"form_error_password_length": "يجب أن تتكون كلمة المرور من {{value}} من الأحرف على الأقل",
|
||||
"protection_section_label": "الحماية"
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
"dns_allowlists": "Белыя спісы DNS",
|
||||
"dns_blocklists_desc": "AdGuard Home будзе блакаваць дамены з чорных спісаў.",
|
||||
"dns_allowlists_desc": "Дамены з белых спісаў DNS будуць дазволены, нават калі яны знаходзяцца ў любым з чорных спісаў.",
|
||||
"custom_filtering_rules": "Карыстацкія правілы фільтрацыі",
|
||||
"custom_filtering_rules": "Карыстальніцкія правілы фільтрацыі",
|
||||
"encryption_settings": "Налады шыфравання",
|
||||
"dhcp_settings": "Налады DHCP",
|
||||
"upstream_dns": "Upstream DNS-серверы",
|
||||
@@ -247,7 +247,7 @@
|
||||
"loading_table_status": "Загрузка...",
|
||||
"page_table_footer_text": "Старонка",
|
||||
"rows_table_footer_text": "радкоў",
|
||||
"updated_custom_filtering_toast": "Занесены змены ў карыстацкія правілы",
|
||||
"updated_custom_filtering_toast": "Карыстальніцкія правілы паспяхова захаваны",
|
||||
"rule_removed_from_custom_filtering_toast": "Карыстацкае правіла выдалена: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Карыстацкае правіла дададзена: {{rule}}",
|
||||
"query_log_response_status": "Статус: {{value}}",
|
||||
@@ -261,7 +261,7 @@
|
||||
"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-сервера",
|
||||
@@ -356,7 +356,7 @@
|
||||
"install_devices_android_list_5": "Зараз можна змяніць палі «DNS 1» і «DNS 2». Увядзіце ў іх адрасы AdGuard Home.",
|
||||
"install_devices_ios_list_1": "Увайдзіце ў меню налад прылады.",
|
||||
"install_devices_ios_list_2": "Абярыце пункт «Wi-Fi» (для мабільных сетак ручная наладка DNS немагчыма).",
|
||||
"install_devices_ios_list_3": "Націсніце на назву сетцы, да якой прылада падлучана ў дадзены момант.",
|
||||
"install_devices_ios_list_3": "Націсніце на назву актыўнай у дадзены момант сеткі.",
|
||||
"install_devices_ios_list_4": "У поле «DNS» увядзіце ўвядзіце адрасы AdGuard Home.",
|
||||
"get_started": "Паехалі",
|
||||
"next": "Далей",
|
||||
@@ -517,10 +517,10 @@
|
||||
"filter_updated": "Спіс паспяхова абноўлены",
|
||||
"statistics_configuration": "Канфігурацыя статыстыкі",
|
||||
"statistics_retention": "Захаванне статыстыкі",
|
||||
"statistics_retention_desc": "Калі вы зменшыце значэнне інтэрвалу, некаторыя дадзеныя могуць быць згублены",
|
||||
"statistics_retention_desc": "Калі вы паменшыце значэнне інтэрвалу, некаторыя даныя могуць быць страчаны",
|
||||
"statistics_clear": "Ачысціць статыстыку",
|
||||
"statistics_clear_confirm": "Вы ўпэўнены, што хочаце ачысціць статыстыку?",
|
||||
"statistics_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання статыстыкі? Пры скарачэнні інтэрвалу дадзеныя могуць быць згублены",
|
||||
"statistics_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання статыстыкі? Пры памяншэнні інтэрвалу, некаторыя даныя могуць быць страчаны",
|
||||
"statistics_cleared": "Статыстыка паспяхова вычышчана",
|
||||
"statistics_enable": "Уключыць статыстыку",
|
||||
"interval_hours": "{{count}} гадзіна",
|
||||
@@ -568,7 +568,7 @@
|
||||
"check_desc": "Праверыць фільтрацыю імя хаста",
|
||||
"check": "Праверыць",
|
||||
"form_enter_host": "Увядзіце імя хаста",
|
||||
"filtered_custom_rules": "Адфільтраваны з дапамогай карыстацкіх правілаў фільтрацыі",
|
||||
"filtered_custom_rules": "Адфільтраваны з дапамогай карыстальніцкіх правіл фільтрацыі",
|
||||
"choose_from_list": "Абраць са спіса",
|
||||
"add_custom_list": "Дадаць свой спіс",
|
||||
"host_whitelisted": "Хост занесены ў белы спіс",
|
||||
@@ -598,7 +598,7 @@
|
||||
"show_blocked_responses": "Заблакавана",
|
||||
"show_whitelisted_responses": "Белы спіс",
|
||||
"show_processed_responses": "Апрацавана",
|
||||
"blocked_safebrowsing": "Заблакавана згодна базе дадзеных Safe Browsing",
|
||||
"blocked_safebrowsing": "Заблакіравана згодна з базай даных Safe Browsing",
|
||||
"blocked_adult_websites": "Заблакавана Бацькоўскім кантролем",
|
||||
"blocked_threats": "Заблакавана пагроз",
|
||||
"allowed": "Дазволены",
|
||||
@@ -639,8 +639,9 @@
|
||||
"safe_browsing": "Бяспечны інтэрнэт",
|
||||
"served_from_cache": "{{value}} <i>(атрымана з кэша)</i>",
|
||||
"form_error_password_length": "Пароль павінен быць не менш за {{value}} сімвалаў",
|
||||
"anonymizer_notification": "<0>Заўвага:</0> Ананімізацыя IP уключана. Вы можаце адключыць яго ў <1>Агульных наладах</1> .",
|
||||
"anonymizer_notification": "<0>Заўвага:</0> Ананімізацыя IP уключана. Вы можаце адключыць яе ў <1>Агульных наладах</1>.",
|
||||
"confirm_dns_cache_clear": "Вы ўпэўнены, што хочаце ачысціць кэш DNS?",
|
||||
"cache_cleared": "Кэш DNS паспяхова ачышчаны",
|
||||
"clear_cache": "Ачысціць кэш"
|
||||
"clear_cache": "Ачысціць кэш",
|
||||
"protection_section_label": "Ахова"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Zapnutá Rodičovská kontrola",
|
||||
"disabled_safe_search_toast": "Vypnuté bezpečné vyhledávání",
|
||||
"enabled_save_search_toast": "Zapnuté bezpečné vyhledávání",
|
||||
"updated_save_search_toast": "Nastavení Bezpečného vyhledávání aktualizováno",
|
||||
"enabled_table_header": "Zapnuto",
|
||||
"name_table_header": "Název",
|
||||
"list_url_table_header": "Seznam URL",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Protokol dotazů byl úspěšně vymazán",
|
||||
"query_log_updated": "Protokol dotazů byl úspěšně aktualizován",
|
||||
"query_log_clear": "Vymazat protokoly dotazů",
|
||||
"query_log_retention": "Uchování protokolů dotazů",
|
||||
"query_log_retention": "Rotace protokolů dotazů",
|
||||
"query_log_enable": "Povolit protokol",
|
||||
"query_log_configuration": "Konfigurace protokolů",
|
||||
"query_log_disabled": "Protokol dotazu je zakázán a lze jej nakonfigurovat v <0>nastavení</0>",
|
||||
"query_log_strict_search": "Pro striktní vyhledávání použijte dvojité uvozovky",
|
||||
"query_log_retention_confirm": "Opravdu chcete změnit uchovávání protokolu dotazů? Pokud snížíte hodnotu intervalu, některá data budou ztracena",
|
||||
"query_log_retention_confirm": "Opravdu chcete změnit rotaci protokolu dotazů? Pokud snížíte hodnotu intervalu, některá data budou ztracena",
|
||||
"anonymize_client_ip": "Anonymizovat IP klienta",
|
||||
"anonymize_client_ip_desc": "Neukládat úplnou IP adresu klienta do protokolů a statistik",
|
||||
"dns_config": "Konfigurace DNS serveru",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Rychlostní limit",
|
||||
"edns_enable": "Povolit klientskou podsíť EDNS",
|
||||
"edns_cs_desc": "Přidá možnost podsítě klienta EDNS (ECS) do odchozích požadavků a zaznamá hodnoty odeslané klienty do protokolu dotazů.",
|
||||
"edns_use_custom_ip": "Použít vlastní IP pro EDNS",
|
||||
"edns_use_custom_ip_desc": "Povolit použití vlastní IP pro EDNS",
|
||||
"rate_limit_desc": "Počet požadavků za sekundu, které smí jeden klient provádět (0: neomezeno)",
|
||||
"blocking_ipv4_desc": "IP adresa, která se má vrátit v případě blokovaného požadavku typu A",
|
||||
"blocking_ipv6_desc": "IP adresa, která se má vrátit v případě blokovaného požadavku typu AAAA",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Opravdu chcete změnit uchovávání statistik? Pokud snížíte hodnotu intervalu, některá data budou ztracena",
|
||||
"statistics_cleared": "Statistiky úspěšně vyčištěny",
|
||||
"statistics_enable": "Povolit statistiky",
|
||||
"ignore_domains": "Ignorované domény (oddělené novým řádkem)",
|
||||
"ignore_domains_title": "Ignorované domény",
|
||||
"ignore_domains_desc_stats": "Dotazy pro tyto domény se do statistik nezapisují",
|
||||
"ignore_domains_desc_query": "Dotazy pro tyto domény se do záznamu dotazů nezapisují",
|
||||
"interval_hours": "Hodiny: {{count}}",
|
||||
"interval_hours_plural": "Hodiny: {{count}}",
|
||||
"filters_configuration": "Konfigurace filtrů",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Poznámka:</0> Anonymizace IP je zapnuta. Můžete ji vypnout v <1>Obecných nastaveních</1>.",
|
||||
"confirm_dns_cache_clear": "Opravdu chcete vymazat mezipaměť DNS?",
|
||||
"cache_cleared": "Mezipaměť DNS úspěšně vymazána",
|
||||
"clear_cache": "Vymazat mezipaměť"
|
||||
"clear_cache": "Vymazat mezipaměť",
|
||||
"make_static": "Nastavit jako statickou",
|
||||
"theme_auto_desc": "Automatický (podle barevného motivu vašeho zařízení)",
|
||||
"theme_dark_desc": "Tmavý motiv",
|
||||
"theme_light_desc": "Světlý motiv",
|
||||
"disable_for_seconds": "Na {{count}} sek.",
|
||||
"disable_for_seconds_plural": "Na {{count}} sek.",
|
||||
"disable_for_minutes": "Na {{count}} min.",
|
||||
"disable_for_minutes_plural": "Na {{count}} min.",
|
||||
"disable_for_hours": "Na {{count}} hod.",
|
||||
"disable_for_hours_plural": "Na {{count}} hod.",
|
||||
"disable_until_tomorrow": "Do zítřka",
|
||||
"disable_notify_for_seconds": "Vypnout ochranu na {{count}} sek.",
|
||||
"disable_notify_for_seconds_plural": "Vypnout ochranu na {{count}} sek.",
|
||||
"disable_notify_for_minutes": "Vypnout ochranu na {{count}} min.",
|
||||
"disable_notify_for_minutes_plural": "Vypnout ochranu na {{count}} min.",
|
||||
"disable_notify_for_hours": "Vypnout ochranu na {{count}} hod.",
|
||||
"disable_notify_for_hours_plural": "Vypnout ochranu na {{count}} hod.",
|
||||
"disable_notify_until_tomorrow": "Vypnout ochranu do zítřka",
|
||||
"enable_protection_timer": "Ochrana bude zapnuta za {{time}}",
|
||||
"custom_retention_input": "Zadejte retenci v hodinách",
|
||||
"custom_rotation_input": "Zadejte rotaci v hodinách",
|
||||
"protection_section_label": "Ochrana",
|
||||
"log_and_stats_section_label": "Protokol dotazů a statistiky",
|
||||
"ignore_query_log": "Ignorovat tohoto klienta v protokolu dotazů",
|
||||
"ignore_statistics": "Ignorovat tohoto klienta ve statistikách"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Forældrekontrol aktiveret",
|
||||
"disabled_safe_search_toast": "Sikker søgning deaktiveret",
|
||||
"enabled_save_search_toast": "Sikker søgning aktiveret",
|
||||
"updated_save_search_toast": "Sikker søgning opdateret",
|
||||
"enabled_table_header": "Aktiveret",
|
||||
"name_table_header": "Navn",
|
||||
"list_url_table_header": "Liste-URL",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Forespørgselsloggen er blevet ryddet",
|
||||
"query_log_updated": "Forespørgselsloggen er blevet opdateret",
|
||||
"query_log_clear": "Ryd forespørgselslogfiler",
|
||||
"query_log_retention": "Opbevar forespørgselslogger i",
|
||||
"query_log_retention": "Rotation af forespørgselslog",
|
||||
"query_log_enable": "Aktivér log",
|
||||
"query_log_configuration": "Opsætning af logger",
|
||||
"query_log_disabled": "Forespørgselsloggen er deaktiveret og kan opsættes i <0>indstillingerne</0>",
|
||||
"query_log_strict_search": "Brug dobbelt anførselstegn til stringent søgning",
|
||||
"query_log_retention_confirm": "Sikker på, at du vil ændre forespørgselsloggens opbevaringperiode? Mindskes intervalværdien, mistes data",
|
||||
"query_log_retention_confirm": "Sikker på, at forespørgselsloggens rotationstid skal ændres? Mindskes intervalværdien, mistes nogle data",
|
||||
"anonymize_client_ip": "Anonymisér klient-IP",
|
||||
"anonymize_client_ip_desc": "Gem ikke fuld klient IP-adresse i logfiler eller statistikker",
|
||||
"dns_config": "DNS-serveropsætning",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Hyppighedsgrænse",
|
||||
"edns_enable": "Aktivér EDNS-klientundernet",
|
||||
"edns_cs_desc": "Tilføj indstillingen EDNS Client Subnet (ECS) til upstream-forespørgsler og log de af klienterne sendte værdier i forespørgselsloggen.",
|
||||
"edns_use_custom_ip": "Brug tilpasset IP til EDNS",
|
||||
"edns_use_custom_ip_desc": "Tillad brug af tilpasset IP til EDNS",
|
||||
"rate_limit_desc": "Antallet af forespørgsler pr. sekund tilladt pr. klient (værdien 0 = ubegrænset)",
|
||||
"blocking_ipv4_desc": "Returneret IP-adresse for en blokeret A-forespørgsel",
|
||||
"blocking_ipv6_desc": "Returneret IP-adresse for en blokeret AAAA-forespørgsel",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Sikker på, at du vil ændre på statistikbevaring? Mindskes intervalværdien, vil nogle data gå tabt",
|
||||
"statistics_cleared": "Statistikkerne er ryddet",
|
||||
"statistics_enable": "Aktivér statistikker",
|
||||
"ignore_domains": "Ignorerede domæner (adskilt af ny linje)",
|
||||
"ignore_domains_title": "Ignorerede domæner",
|
||||
"ignore_domains_desc_stats": "Forespørgsler til disse domæner opføres ikke i statistikken",
|
||||
"ignore_domains_desc_query": "Forespørgsler til disse domæner opføres ikke i forespørgselsloggen",
|
||||
"interval_hours": "{{count}} time",
|
||||
"interval_hours_plural": "{{count}} timer",
|
||||
"filters_configuration": "Filteropsætninger",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Bemærk:</0> IP-anonymisering er aktiveret. Det kan deaktiveres via <1>Generelle indstillinger</1>.",
|
||||
"confirm_dns_cache_clear": "Sikker på, at DNS-cache skal ryddes?",
|
||||
"cache_cleared": "DNS-cache hermed ryddet",
|
||||
"clear_cache": "Ryd cache"
|
||||
"clear_cache": "Ryd cache",
|
||||
"make_static": "Gør statisk",
|
||||
"theme_auto_desc": "Auto (baseret på enhedens farveskema)",
|
||||
"theme_dark_desc": "Mørkt tema",
|
||||
"theme_light_desc": "Lyst tema",
|
||||
"disable_for_seconds": "I {{count}} sekund",
|
||||
"disable_for_seconds_plural": "I {{count}} sekunder",
|
||||
"disable_for_minutes": "I {{count}} minut",
|
||||
"disable_for_minutes_plural": "I {{count}} minutter",
|
||||
"disable_for_hours": "I {{count}} time",
|
||||
"disable_for_hours_plural": "I {{count}} timer",
|
||||
"disable_until_tomorrow": "Indtil i morgen",
|
||||
"disable_notify_for_seconds": "Deaktivere beskyttelse i {{count}} sekund",
|
||||
"disable_notify_for_seconds_plural": "Deaktivere beskyttelse i {{count}} sekunder",
|
||||
"disable_notify_for_minutes": "Deaktivere beskyttelse i {{count}} minut",
|
||||
"disable_notify_for_minutes_plural": "Deaktivere beskyttelse i {{count}} minutter",
|
||||
"disable_notify_for_hours": "Deaktivere beskyttelse i {{count}} time",
|
||||
"disable_notify_for_hours_plural": "Deaktivere beskyttelse i {{count}} timer",
|
||||
"disable_notify_until_tomorrow": "Deaktiver beskyttelse indtil i morgen",
|
||||
"enable_protection_timer": "Beskyttelse deaktiveres om {{time}}",
|
||||
"custom_retention_input": "Angiv opbevaringstid i timer",
|
||||
"custom_rotation_input": "Angiv rotationstid i timer",
|
||||
"protection_section_label": "Beskyttelse",
|
||||
"log_and_stats_section_label": "Forespørgselslog og statistik",
|
||||
"ignore_query_log": "Ignorér denne klient i forespørgselslog",
|
||||
"ignore_statistics": "Ignorér denne klient i statistik"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Kindersicherung aktiviert",
|
||||
"disabled_safe_search_toast": "Sichere Suche deaktiviert",
|
||||
"enabled_save_search_toast": "Sichere Suche aktiviert",
|
||||
"updated_save_search_toast": "Einstellungen für die sichere Suche aktualisiert",
|
||||
"enabled_table_header": "Aktiviert",
|
||||
"name_table_header": "Name",
|
||||
"list_url_table_header": "Adressliste",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Das Abfrageprotokoll wurde erfolgreich gelöscht",
|
||||
"query_log_updated": "Das Abfrageprotokoll wurde erfolgreich aktualisiert",
|
||||
"query_log_clear": "Abfrageprotokolle leeren",
|
||||
"query_log_retention": "Abfrageprotokolle aufbewahren",
|
||||
"query_log_retention": "Rotation der Abfrageprotokolle",
|
||||
"query_log_enable": "Protokoll aktivieren",
|
||||
"query_log_configuration": "Konfiguration der Protokolle",
|
||||
"query_log_disabled": "Das Abfrageprotokoll ist deaktiviert und kann in den <0>Einstellungen</0> konfiguriert werden.",
|
||||
"query_log_strict_search": "Doppelte Anführungszeichen für die strikte Suche verwenden",
|
||||
"query_log_retention_confirm": "Möchten Sie die Aufbewahrung des Abfrageprotokolls wirklich ändern? Wenn Sie den Zeitabstand verringern, gehen einige Daten verloren.",
|
||||
"query_log_retention_confirm": "Möchten Sie die Abfrageprotokollrotation wirklich ändern? Wenn Sie den Intervallwert verringern, gehen einige Daten verloren",
|
||||
"anonymize_client_ip": "Client-IP anonymisieren",
|
||||
"anonymize_client_ip_desc": "Vollständige IP-Adresse des Clients nicht in Protokollen und Statistiken speichern",
|
||||
"dns_config": "DNS-Serverkonfiguration",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Begrenzungswert",
|
||||
"edns_enable": "EDNS Client Subnetz aktivieren",
|
||||
"edns_cs_desc": "Die Option EDNS Client Subnetz (ECS) zu Upstream-Anfragen hinzufügen und die von Clients gesendeten Werte protokollieren.",
|
||||
"edns_use_custom_ip": "Benutzerdefinierte IP für EDNS verwenden",
|
||||
"edns_use_custom_ip_desc": "Benutzerdefinierte IP für EDNS zulassen",
|
||||
"rate_limit_desc": "Die Anzahl der Anfragen pro Sekunde, die ein einzelner Client stellen darf. Das Setzen auf 0 bedeutet keine Begrenzung.",
|
||||
"blocking_ipv4_desc": "IP-Adresse, die für eine gesperrte A-Anfrage zurückgegeben werden soll",
|
||||
"blocking_ipv6_desc": "IP-Adresse, die für eine gesperrte AAAA-Anfrage zurückgegeben werden soll",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Möchten Sie wirklich die Aufbewahrung der Statistiken ändern? Wenn Sie den Zeitabstand verringern, gehen einige Daten verloren.",
|
||||
"statistics_cleared": "Statistiken wurden erfolgreich gelöscht",
|
||||
"statistics_enable": "Statistiken aktivieren",
|
||||
"ignore_domains": "Ignorierte Domains (durch Zeilenumbruch getrennt)",
|
||||
"ignore_domains_title": "Ignorierte Domains",
|
||||
"ignore_domains_desc_stats": "Abfragen für diese Domains werden nicht in die Statistik aufgenommen",
|
||||
"ignore_domains_desc_query": "Abfragen für diese Domains werden nicht in das Abfrageprotokoll aufgenommen",
|
||||
"interval_hours": "{{count}} Stunde",
|
||||
"interval_hours_plural": "{{count}} Stunden",
|
||||
"filters_configuration": "Filterkonfiguration",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Hinweis:</0> Die IP-Anonymisierung ist aktiviert. Sie können sie in den <1>Allgemeinen Einstellungen</1> deaktivieren.",
|
||||
"confirm_dns_cache_clear": "Möchten Sie den DNS-Cache wirklich leeren?",
|
||||
"cache_cleared": "DNS-Cache erfolgreich geleert",
|
||||
"clear_cache": "Cache leeren"
|
||||
"clear_cache": "Cache leeren",
|
||||
"make_static": "Statisch machen",
|
||||
"theme_auto_desc": "Automatisch (basierend auf dem Farbschema Ihres Geräts)",
|
||||
"theme_dark_desc": "Dunkles Farbschema",
|
||||
"theme_light_desc": "Helles Farbschema",
|
||||
"disable_for_seconds": "Für {{count}} Sekunde",
|
||||
"disable_for_seconds_plural": "Für {{count}} Sekunden",
|
||||
"disable_for_minutes": "Für {{count}} Minute",
|
||||
"disable_for_minutes_plural": "Für {{count}} Minuten",
|
||||
"disable_for_hours": "Für {{count}} Stunde",
|
||||
"disable_for_hours_plural": "Für {{count}} Stunden",
|
||||
"disable_until_tomorrow": "Bis morgen",
|
||||
"disable_notify_for_seconds": "Schutz für {{count}} Sekunde deaktivieren",
|
||||
"disable_notify_for_seconds_plural": "Schutz für {{count}} Sekunden deaktivieren",
|
||||
"disable_notify_for_minutes": "Schutz für {{count}} Minute deaktivieren",
|
||||
"disable_notify_for_minutes_plural": "Schutz für {{count}} Minuten deaktivieren",
|
||||
"disable_notify_for_hours": "Schutz für {{count}} Stunde deaktivieren",
|
||||
"disable_notify_for_hours_plural": "Schutz für {{count}} Stunden deaktivieren",
|
||||
"disable_notify_until_tomorrow": "Schutz bis morgen deaktivieren",
|
||||
"enable_protection_timer": "Der Schutz wird in {{time}} wieder aktiviert",
|
||||
"custom_retention_input": "Rückhaltezeit in Stunden eingeben",
|
||||
"custom_rotation_input": "Rotation in Stunden eingeben",
|
||||
"protection_section_label": "Schutz",
|
||||
"log_and_stats_section_label": "Abfrageprotokoll und Statistik",
|
||||
"ignore_query_log": "Diesen Client im Abfrageprotokoll ignorieren",
|
||||
"ignore_statistics": "Diesen Client in der Statistik ignorieren"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Enabled Parental Control",
|
||||
"disabled_safe_search_toast": "Disabled Safe Search",
|
||||
"enabled_save_search_toast": "Enabled Safe Search",
|
||||
"updated_save_search_toast": "Safe Search settings updated",
|
||||
"enabled_table_header": "Enabled",
|
||||
"name_table_header": "Name",
|
||||
"list_url_table_header": "List URL",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "The query log has been successfully cleared",
|
||||
"query_log_updated": "The query log has been successfully updated",
|
||||
"query_log_clear": "Clear query logs",
|
||||
"query_log_retention": "Query logs retention",
|
||||
"query_log_retention": "Query logs rotation",
|
||||
"query_log_enable": "Enable log",
|
||||
"query_log_configuration": "Logs configuration",
|
||||
"query_log_disabled": "The query log is disabled and can be configured in the <0>settings</0>",
|
||||
"query_log_strict_search": "Use double quotes for strict search",
|
||||
"query_log_retention_confirm": "Are you sure you want to change query log retention? If you decrease the interval value, some data will be lost",
|
||||
"query_log_retention_confirm": "Are you sure you want to change query log rotation? If you decrease the interval value, some data will be lost",
|
||||
"anonymize_client_ip": "Anonymize client IP",
|
||||
"anonymize_client_ip_desc": "Don't save the client's full IP address to logs or statistics",
|
||||
"dns_config": "DNS server configuration",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Rate limit",
|
||||
"edns_enable": "Enable EDNS client subnet",
|
||||
"edns_cs_desc": "Add the EDNS Client Subnet option (ECS) to upstream requests and log the values sent by the clients in the query log.",
|
||||
"edns_use_custom_ip": "Use custom IP for EDNS",
|
||||
"edns_use_custom_ip_desc": "Allow to use custom IP for EDNS",
|
||||
"rate_limit_desc": "The number of requests per second allowed per client. Setting it to 0 means no limit.",
|
||||
"blocking_ipv4_desc": "IP address to be returned for a blocked A request",
|
||||
"blocking_ipv6_desc": "IP address to be returned for a blocked AAAA request",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Are you sure you want to change statistics retention? If you decrease the interval value, some data will be lost",
|
||||
"statistics_cleared": "Statistics successfully cleared",
|
||||
"statistics_enable": "Enable statistics",
|
||||
"ignore_domains": "Ignored domains (separated by newline)",
|
||||
"ignore_domains_title": "Ignored domains",
|
||||
"ignore_domains_desc_stats": "Queries for these domains are not written to the statistics",
|
||||
"ignore_domains_desc_query": "Queries for these domains are not written to the query log",
|
||||
"interval_hours": "{{count}} hour",
|
||||
"interval_hours_plural": "{{count}} hours",
|
||||
"filters_configuration": "Filters configuration",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Note:</0> IP anonymization is enabled. You can disable it in <1>General settings</1>.",
|
||||
"confirm_dns_cache_clear": "Are you sure you want to clear DNS cache?",
|
||||
"cache_cleared": "DNS cache successfully cleared",
|
||||
"clear_cache": "Clear cache"
|
||||
"clear_cache": "Clear cache",
|
||||
"make_static": "Make static",
|
||||
"theme_auto_desc": "Auto (based on the color scheme of your device)",
|
||||
"theme_dark_desc": "Dark theme",
|
||||
"theme_light_desc": "Light theme",
|
||||
"disable_for_seconds": "For {{count}} second",
|
||||
"disable_for_seconds_plural": "For {{count}} seconds",
|
||||
"disable_for_minutes": "For {{count}} minute",
|
||||
"disable_for_minutes_plural": "For {{count}} minutes",
|
||||
"disable_for_hours": "For {{count}} hour",
|
||||
"disable_for_hours_plural": "For {{count}} hours",
|
||||
"disable_until_tomorrow": "Until tomorrow",
|
||||
"disable_notify_for_seconds": "Disable protection for {{count}} second",
|
||||
"disable_notify_for_seconds_plural": "Disable protection for {{count}} seconds",
|
||||
"disable_notify_for_minutes": "Disable protection for {{count}} minute",
|
||||
"disable_notify_for_minutes_plural": "Disable protection for {{count}} minutes",
|
||||
"disable_notify_for_hours": "Disable protection for {{count}} hour",
|
||||
"disable_notify_for_hours_plural": "Disable protection for {{count}} hours",
|
||||
"disable_notify_until_tomorrow": "Disable protection until tomorrow",
|
||||
"enable_protection_timer": "Protection will be enabled in {{time}}",
|
||||
"custom_retention_input": "Enter retention in hours",
|
||||
"custom_rotation_input": "Enter rotation in hours",
|
||||
"protection_section_label": "Protection",
|
||||
"log_and_stats_section_label": "Query log and statistics",
|
||||
"ignore_query_log": "Ignore this client in query log",
|
||||
"ignore_statistics": "Ignore this client in statistics"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Control parental habilitado",
|
||||
"disabled_safe_search_toast": "Búsqueda segura deshabilitada",
|
||||
"enabled_save_search_toast": "Búsqueda segura habilitada",
|
||||
"updated_save_search_toast": "Configuración de búsqueda segura actualizada",
|
||||
"enabled_table_header": "Habilitado",
|
||||
"name_table_header": "Nombre",
|
||||
"list_url_table_header": "URL de la lista",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "El registro de consultas se ha borrado correctamente",
|
||||
"query_log_updated": "El registro de consultas se ha actualizado correctamente",
|
||||
"query_log_clear": "Borrar registros de consultas",
|
||||
"query_log_retention": "Retención de registros de consultas",
|
||||
"query_log_retention": "Rotanción de registros de consultas",
|
||||
"query_log_enable": "Habilitar registro",
|
||||
"query_log_configuration": "Configuración de registros",
|
||||
"query_log_disabled": "El registro de consultas está deshabilitado y se puede configurar en la <0>configuración</0>",
|
||||
"query_log_strict_search": "Usar comillas dobles para una búsqueda estricta",
|
||||
"query_log_retention_confirm": "¿Estás seguro de que deseas cambiar la retención del registro de consultas? Si disminuye el valor del intervalo, se perderán algunos datos",
|
||||
"query_log_retention_confirm": "¿Está seguro de que deseas cambiar la rotación del registro de consultas? Si reduces el valor del intervalo, se perderán algunos datos",
|
||||
"anonymize_client_ip": "Anonimizar IP del cliente",
|
||||
"anonymize_client_ip_desc": "No guarda la dirección IP completa del cliente en registros o estadísticas",
|
||||
"dns_config": "Configuración del servidor DNS",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Límite de cantidad",
|
||||
"edns_enable": "Habilitar subred de cliente EDNS",
|
||||
"edns_cs_desc": "Añade la opción subred de cliente EDNS (ECS) a las peticiones del DNS de subida y registra los valores enviados por los clientes en el registro de consultas.",
|
||||
"edns_use_custom_ip": "Usar IP personalizada para EDNS",
|
||||
"edns_use_custom_ip_desc": "Permitir el uso de IP personalizadas para EDNS",
|
||||
"rate_limit_desc": "Número de peticiones por segundo permitidas por cliente. Establecerlo en 0 significa que no hay límite.",
|
||||
"blocking_ipv4_desc": "Dirección IP devolverá una petición A bloqueada",
|
||||
"blocking_ipv6_desc": "Dirección IP devolverá una petición AAAA bloqueada",
|
||||
@@ -454,7 +457,7 @@
|
||||
"updates_checked": "La nueva versión de AdGuard Home está disponible",
|
||||
"updates_version_equal": "AdGuard Home está actualizado",
|
||||
"check_updates_now": "Buscar actualizaciones ahora",
|
||||
"version_request_error": "La búsqueda de actualizaciones falló. Por favor revisa tu conexión a Internet.",
|
||||
"version_request_error": "Error buscar la actualización. Comprueba tu conexión a Internet.",
|
||||
"dns_privacy": "DNS cifrado",
|
||||
"setup_dns_privacy_1": "<0>DNS mediante TLS:</0> Utiliza la cadena <1>{{address}}</1>.",
|
||||
"setup_dns_privacy_2": "<0>DNS mediante HTTPS:</0> Utiliza la cadena <1>{{address}}</1>.",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "¿Estás seguro de que deseas cambiar la retención de estadísticas? Si disminuye el valor del intervalo, se perderán algunos datos",
|
||||
"statistics_cleared": "Estadísticas borradas correctamente",
|
||||
"statistics_enable": "Habilitar estadísticas",
|
||||
"ignore_domains": "Dominios ignorados (separados por una nueva línea)",
|
||||
"ignore_domains_title": "Dominios ignorados",
|
||||
"ignore_domains_desc_stats": "Las consultas para estos dominios no aparecen en las estadísticas",
|
||||
"ignore_domains_desc_query": "Las consultas para estos dominios no aparecen en el registro de consultas",
|
||||
"interval_hours": "{{count}} hora",
|
||||
"interval_hours_plural": "{{count}} horas",
|
||||
"filters_configuration": "Configuración de filtros",
|
||||
@@ -640,7 +647,32 @@
|
||||
"served_from_cache": "{{value}} <i>(servido desde la caché)</i>",
|
||||
"form_error_password_length": "La contraseña debe tener al menos {{value}} caracteres",
|
||||
"anonymizer_notification": "<0>Nota:</0> La anonimización de IP está habilitada. Puedes deshabilitarla en <1>Configuración general</1>.",
|
||||
"confirm_dns_cache_clear": "¿Estás seguro de que deseas borrar la caché de DNS?",
|
||||
"cache_cleared": "Caché DNS borrado con éxito",
|
||||
"clear_cache": "Borrar caché"
|
||||
"confirm_dns_cache_clear": "¿Estás seguro de que deseas borrar la caché DNS?",
|
||||
"cache_cleared": "Caché DNS borrado correctamente",
|
||||
"clear_cache": "Borrar caché",
|
||||
"make_static": "Hacer estático",
|
||||
"theme_auto_desc": "Automático (basado en el esquema de colores de tu dispositivo)",
|
||||
"theme_dark_desc": "Tema oscuro",
|
||||
"theme_light_desc": "Tema claro",
|
||||
"disable_for_seconds": "Por {{count}} segundo",
|
||||
"disable_for_seconds_plural": "Por {{count}} segundos",
|
||||
"disable_for_minutes": "Por {{count}} minuto",
|
||||
"disable_for_minutes_plural": "Por {{count}} minutos",
|
||||
"disable_for_hours": "Por {{count}} hora",
|
||||
"disable_for_hours_plural": "Por {{count}} horas",
|
||||
"disable_until_tomorrow": "Hasta mañana",
|
||||
"disable_notify_for_seconds": "Desactivar la protección por {{count}} segundo",
|
||||
"disable_notify_for_seconds_plural": "Desactivar la protección por {{count}} segundos",
|
||||
"disable_notify_for_minutes": "Desactivar la protección por {{count}} minuto",
|
||||
"disable_notify_for_minutes_plural": "Desactivar la protección por {{count}} minutos",
|
||||
"disable_notify_for_hours": "Desactivar la protección por {{count}} hora",
|
||||
"disable_notify_for_hours_plural": "Desactivar la protección por {{count}} horas",
|
||||
"disable_notify_until_tomorrow": "Desactivar la protección hasta mañana",
|
||||
"enable_protection_timer": "La protección se activará en {{time}}",
|
||||
"custom_retention_input": "Ingresa la retención en horas",
|
||||
"custom_rotation_input": "Ingresa la rotación en horas",
|
||||
"protection_section_label": "Protección",
|
||||
"log_and_stats_section_label": "Registro de consultas y estadísticas",
|
||||
"ignore_query_log": "Ignorar este cliente en el registro de consultas",
|
||||
"ignore_statistics": "Ignorar este cliente en las estadísticas"
|
||||
}
|
||||
|
||||
@@ -268,6 +268,8 @@
|
||||
"blocking_mode_nxdomain": "NXDOMAIN: پاسخ با کُد NXDOMAIN",
|
||||
"blocking_mode_null_ip": "Null IP: پاسخ با آدرس آی پی صفر(0.0.0.0 برای A; :: برای AAAA)",
|
||||
"blocking_mode_custom_ip": "آی پی دستی: پاسخ با آدرس آی پی دستی تنظیم شده",
|
||||
"theme_light": "پوسته روشن",
|
||||
"theme_dark": "پوسته تیره",
|
||||
"upstream_dns_client_desc": "اگر این فیلد را خالی نگه دارید، AdGuard Home از سرور پیکربندی شده در <0> تنظیماتDNS </0> استفاده می کند.",
|
||||
"tracker_source": "منبع ردیاب",
|
||||
"source_label": "منبع",
|
||||
@@ -567,5 +569,6 @@
|
||||
"use_saved_key": "از کلید ذخیره شده قبلی استفاده کنید",
|
||||
"parental_control": "نظارت والدین",
|
||||
"safe_browsing": "وب گردی اَمن",
|
||||
"form_error_password_length": "رمزعبور باید حداقل {{value}} کاراکتر باشد."
|
||||
"form_error_password_length": "رمزعبور باید حداقل {{value}} کاراکتر باشد.",
|
||||
"protection_section_label": "حفاظت"
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
"bootstrap_dns": "Bootstrap DNS-palvelimet",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS-palvelimia käytetään ylävirroiksi määritettyjen DoH/DoT-resolvereiden IP-osoitteiden selvitykseen.",
|
||||
"local_ptr_title": "Yksityiset käänteiset DNS-palvelimet",
|
||||
"local_ptr_desc": "DNS-palvelimet, joita AdGuard Home käyttää paikallisille PTR-kyselyille. Näitä palvelimia käytetään yksityistä IP-osoitetta käyttävien PTR-kyselyiden osoitteiden, kuten \"192.168.12.34\", selvitykseen käänteisen 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_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äänteisen 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äänteisiä DNS-resolvereita: {{ip}}.",
|
||||
"local_ptr_no_default_resolver": "AdGuard Home ei voinut määrittää tälle järjestelmälle sopivaa yksityistä käänteistä DNS-resolveria.",
|
||||
"local_ptr_placeholder": "Syötä yksi palvelimen 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-kyselyt sopiville resolvereille (yksityiset DNS-palvelimet paikallisille päätelaitteille, lähtevät palvelimet päätelaitteille, joilla on julkiset IP-osoitteet).",
|
||||
"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, lähtevät palvelimet päätelaitteille, joilla on julkiset IP-osoitteet).",
|
||||
"use_private_ptr_resolvers_title": "Käytä yksityisiä käänteisiä DNS-resolvereita",
|
||||
"use_private_ptr_resolvers_desc": "Suorita käänteiset DNS-selvitykset paikallisesti tarjotuille osoitteille käyttäen näitä ylävirran palvelimia. 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",
|
||||
@@ -24,7 +24,7 @@
|
||||
"unavailable_dhcp": "DHCP ei ole käytettävissä",
|
||||
"unavailable_dhcp_desc": "AdGuard Home ei voi suorittaa DHCP-palvelinta käyttöjärjestelmässäsi",
|
||||
"dhcp_title": "DHCP-palvelin (kokeellinen!)",
|
||||
"dhcp_description": "Jos reitittimessäsi ei ole DHCP-asetuksia, voit käyttää AdGuard Homen omaa sisäänrakennettua DHCP-palvelinta.",
|
||||
"dhcp_description": "Jollei reitittimesi tarjoa DHCP-asetuksia, voit käyttää AdGuard Homen omaa sisäänrakennettua DHCP-palvelinta.",
|
||||
"dhcp_enable": "Ota DHCP-palvelin käyttöön",
|
||||
"dhcp_disable": "Poista DHCP-palvelin käytöstä",
|
||||
"dhcp_not_found": "On turvallista ottaa sisäänrakennettu DHCP-palvelin käyttöön, koska AdGuard Home ei havainnut verkossa muita aktiivisia DHCP-palvelimia. Suosittelemme, että varmistat tämän vielä itse, koska automaattinen tunnistus ei ole 100% varma.",
|
||||
@@ -75,7 +75,7 @@
|
||||
"dhcp_add_static_lease": "Lisää kiinteä laina",
|
||||
"dhcp_reset_leases": "Tyhjennä kaikki lainat",
|
||||
"dhcp_reset_leases_confirm": "Haluatko varmasti tyhjentää kaikki lainat?",
|
||||
"dhcp_reset_leases_success": "DHCP-lainat tyhjennettiin",
|
||||
"dhcp_reset_leases_success": "DHCP-lainojen tyhjennys onnistui",
|
||||
"dhcp_reset": "Haluatko varmasti palauttaa DHCP-asetukset?",
|
||||
"country": "Maa",
|
||||
"city": "Kaupunki",
|
||||
@@ -86,7 +86,7 @@
|
||||
"request_details": "Pyynnön tiedot",
|
||||
"client_details": "Päätelaitteen tiedot",
|
||||
"details": "Yksityiskohdat",
|
||||
"back": "Takaisin",
|
||||
"back": "Palaa takaisin",
|
||||
"dashboard": "Tila",
|
||||
"settings": "Asetukset",
|
||||
"filters": "Suodattimet",
|
||||
@@ -146,8 +146,8 @@
|
||||
"no_servers_specified": "Palvelimia ei ole määritetty",
|
||||
"general_settings": "Yleiset asetukset",
|
||||
"dns_settings": "DNS-asetukset",
|
||||
"dns_blocklists": "DNS-estolistat",
|
||||
"dns_allowlists": "DNS-sallittujen listat",
|
||||
"dns_blocklists": "DNS-estot",
|
||||
"dns_allowlists": "DNS-sallinnat",
|
||||
"dns_blocklists_desc": "AdGuard Home estää estolistalla olevat verkkotunnukset.",
|
||||
"dns_allowlists_desc": "DNS-sallittujen listalla olevat verkkotunnukset sallitaan myös silloin, jos ne ovat jollain muulla estolistalla.",
|
||||
"custom_filtering_rules": "Omat suodatussäännöt",
|
||||
@@ -167,10 +167,11 @@
|
||||
"enabled_parental_toast": "Lapsilukko otettiin käyttöön",
|
||||
"disabled_safe_search_toast": "Turvallinen haku poistettiin käytöstä",
|
||||
"enabled_save_search_toast": "Turvallinen haku otettiin käyttöön",
|
||||
"updated_save_search_toast": "Turvallisen haun asetukset päivitettiin",
|
||||
"enabled_table_header": "Käytössä",
|
||||
"name_table_header": "Nimi",
|
||||
"list_url_table_header": "Listan URL",
|
||||
"rules_count_table_header": "Sääntöjä",
|
||||
"rules_count_table_header": "Sääntöjen määrä",
|
||||
"last_time_updated_table_header": "Viimeisin päivitys",
|
||||
"actions_table_header": "Toiminnot",
|
||||
"request_table_header": "Pyyntö",
|
||||
@@ -253,15 +254,15 @@
|
||||
"query_log_response_status": "Tila: {{value}}",
|
||||
"query_log_filtered": "Suodattanut {{filter}}",
|
||||
"query_log_confirm_clear": "Haluatko varmasti tyhjentää pyyntöhistorian?",
|
||||
"query_log_cleared": "Pyyntöhistoria tyhjennettiin",
|
||||
"query_log_updated": "Pyyntöhistoria päivitettiin",
|
||||
"query_log_cleared": "Pyyntöhistorian tyhjennys onnistui",
|
||||
"query_log_updated": "Pyyntöhistorian päivitys onnistui",
|
||||
"query_log_clear": "Tyhjennä pyyntöhistoria",
|
||||
"query_log_retention": "Pyyntöhistorian säilytys",
|
||||
"query_log_retention": "Kyselylokien kierto",
|
||||
"query_log_enable": "Käytä historiaa",
|
||||
"query_log_configuration": "Historian määritys",
|
||||
"query_log_disabled": "Pyyntöhistoria ei ole käytössä. Voit ottaa sen käyttöön <0>asetuksissa</0>",
|
||||
"query_log_strict_search": "Käytä tarkalle haulle lainausmerkkejä",
|
||||
"query_log_retention_confirm": "Haluatko varmasti muuttaa pyyntöhistoriasi säilytysaikaa? Jos lyhennät aikaa, joitakin tietoja menetetään",
|
||||
"query_log_retention_confirm": "Haluatko varmasti muuttaa kyselylokin kiertoa? Jos pienennät intervalliarvoa, osa tiedoista menetetään",
|
||||
"anonymize_client_ip": "Piilota päätelaitteen IP-osoite",
|
||||
"anonymize_client_ip_desc": "Älä tallenna päätelaitteen täydellistä IP-osoitetta historiaan ja tilastoihin.",
|
||||
"dns_config": "DNS-palvelimen määritys",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Pyyntöjen ajoitus",
|
||||
"edns_enable": "Käytä EDNS-päätelaitealivekkoa",
|
||||
"edns_cs_desc": "Lähetä päätelaitteiden aliverkot DNS-palvelimille.",
|
||||
"edns_use_custom_ip": "Käytä omaa IP-osoitetta EDNS:lle",
|
||||
"edns_use_custom_ip_desc": "Salli oman IP-osoitteen käyttö EDNS-mekanismille.",
|
||||
"rate_limit_desc": "Päätelaitteelle sallittu pyyntöjen enimmäismäärä sekunnissa. Arvo 0 tarkoittaa rajatonta.",
|
||||
"blocking_ipv4_desc": "Estettyyn A-pyyntöön palautettava IP-osoite",
|
||||
"blocking_ipv6_desc": "Estettyyn AAAA-pyyntöön palautettava IP-osoite",
|
||||
@@ -297,7 +300,7 @@
|
||||
"blocking_mode_refused": "REFUSED: Vastaa REFUSED-koodilla",
|
||||
"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 itse määritetyllä IP-osoitteella",
|
||||
"blocking_mode_custom_ip": "Mukautettu IP: Vastaa manuaalisesti määritetyllä IP-osoitteella",
|
||||
"theme_auto": "Automaattinen",
|
||||
"theme_light": "Vaalea",
|
||||
"theme_dark": "Tumma",
|
||||
@@ -367,7 +370,7 @@
|
||||
"encryption_config_saved": "Salausasetukset tallennettiin",
|
||||
"encryption_server": "Palvelimen nimi",
|
||||
"encryption_server_enter": "Syötä verkkotunnuksesi",
|
||||
"encryption_server_desc": "Jos määritetty, AdGuard Home tunnistaa ClientID-tunnisteet, vastaa DDR-kyselyihin ja suorittaa yhteyden lisätarkistuksia. Jos ei määritetty, nämä ominaisuudet eivät ole käytössä. On vastattava yhtä varmenteen DNS-nimistä.",
|
||||
"encryption_server_desc": "Jos määritetty, AdGuard Home tunnistaa ClientID-tunnisteet, vastaa DDR-pyyntöihin ja suorittaa yhteyden lisätarkistuksia. Jos ei määritetty, nämä ominaisuudet eivät ole käytössä. On vastattava yhtä varmenteen DNS-nimistä.",
|
||||
"encryption_redirect": "Automaattinen HTTPS-ohjaus",
|
||||
"encryption_redirect_desc": "Jos käytössä, AdGuard Home ohjaa HTTP-osoitteet automaattisesti HTTPS-osoitteisiin.",
|
||||
"encryption_https": "HTTPS-portti",
|
||||
@@ -416,7 +419,7 @@
|
||||
"clients_title": "Pysyvät päätelaitteet",
|
||||
"clients_desc": "Määritä pysyvät AdGuard Homeen yhdistetyt päätelaitetiedot.",
|
||||
"settings_global": "Yleinen",
|
||||
"settings_custom": "Muut aiheet",
|
||||
"settings_custom": "Mukautettu",
|
||||
"table_client": "Asiakas",
|
||||
"table_name": "Nimi",
|
||||
"save_btn": "Tallenna",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Haluatko varmasti muuttaa tilastojen säilytysaikaa? Jos aikaa lyhennetään, joitakin tietoja menetetään.",
|
||||
"statistics_cleared": "Tilastot tyhjennettiin",
|
||||
"statistics_enable": "Ota tilastointi käyttöön",
|
||||
"ignore_domains": "Ohitettavat verkkotunnukset (erotettu rivinvaihdolla)",
|
||||
"ignore_domains_title": "Ohitettavat verkkotunnukset",
|
||||
"ignore_domains_desc_stats": "Näihin verkkotunnuksiin lähetettyjä pyyntöjä ei tallenneta tilastoihin.",
|
||||
"ignore_domains_desc_query": "Näihin verkkotunnuksiin lähetettyjä pyyntöjä ei tallenneta pyyntöhistoriaan.",
|
||||
"interval_hours": "{{count}} tunti",
|
||||
"interval_hours_plural": "{{count}} tuntia",
|
||||
"filters_configuration": "Suodatinten määritys",
|
||||
@@ -620,7 +627,7 @@
|
||||
"cache_optimistic": "Optimistinen välimuisti",
|
||||
"cache_optimistic_desc": "Pakota AdGuard Home vastaamaan välimuistista vaikka tiedot olisivat vanhentuneet. Pyri samalla myös päivittämään tiedot.",
|
||||
"filter_category_general": "Yleiset",
|
||||
"filter_category_security": "Turvallisuus",
|
||||
"filter_category_security": "Tietoturva",
|
||||
"filter_category_regional": "Alueelliset",
|
||||
"filter_category_other": "Muut",
|
||||
"filter_category_general_desc": "Listat, jotka estävät seurannan ja mainokset useimmilla laitteilla",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Huomioi:</0> IP-osoitteen anonymisointi on käytössä. Voit poistaa sen käytöstä <1>Yleisistä asetuksista</1>.",
|
||||
"confirm_dns_cache_clear": "Haluatko varmasti tyhjentää DNS-välimuistin?",
|
||||
"cache_cleared": "DNS-välimuistin tyhjennys onnistui",
|
||||
"clear_cache": "Tyhjennä välimuisti"
|
||||
"clear_cache": "Tyhjennä välimuisti",
|
||||
"make_static": "Tallenna kiinteäksi",
|
||||
"theme_auto_desc": "Automaattinen (seuraa laitteen väriteemaa)",
|
||||
"theme_dark_desc": "Tumma teema",
|
||||
"theme_light_desc": "Vaalea teema",
|
||||
"disable_for_seconds": "{{count}} sekunniksi",
|
||||
"disable_for_seconds_plural": "{{count}} sekunniksi",
|
||||
"disable_for_minutes": "{{count}} minuutiksi",
|
||||
"disable_for_minutes_plural": "{{count}} minuutiksi",
|
||||
"disable_for_hours": "{{count}} tunniksi",
|
||||
"disable_for_hours_plural": "{{count}} tunniksi",
|
||||
"disable_until_tomorrow": "Huomiseen asti",
|
||||
"disable_notify_for_seconds": "Poista suojaus käytöstä {{count}} sekunniksi",
|
||||
"disable_notify_for_seconds_plural": "Poista suojaus käytöstä {{count}} sekunniksi",
|
||||
"disable_notify_for_minutes": "Poista suojaus käytöstä {{count}} minuutiksi",
|
||||
"disable_notify_for_minutes_plural": "Poista suojaus käytöstä {{count}} minuutiksi",
|
||||
"disable_notify_for_hours": "Poista suojaus käytöstä {{count}} tunniksi",
|
||||
"disable_notify_for_hours_plural": "Poista suojaus käytöstä {{count}} tunniksi",
|
||||
"disable_notify_until_tomorrow": "Poista suojaus käytöstä huomiseen asti",
|
||||
"enable_protection_timer": "Suojaus otetaan käyttöön {{time}} kuluttua",
|
||||
"custom_retention_input": "Syötä säilytysaika tunteina",
|
||||
"custom_rotation_input": "Syötä uudistusaika tunteina",
|
||||
"protection_section_label": "Suojaus",
|
||||
"log_and_stats_section_label": "Kyselyhistoria ja tilastot",
|
||||
"ignore_query_log": "Älä huomioi tätä päätettä kyselyhistoriassa",
|
||||
"ignore_statistics": "Älä huomioi tätä päätettä tilastoissa"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Contrôle Parental activé",
|
||||
"disabled_safe_search_toast": "Recherche Sécurisée désactivée",
|
||||
"enabled_save_search_toast": "Recherche Sécurisée activée",
|
||||
"updated_save_search_toast": "Les paramètres de Recherche sécurisée sont mis à jour",
|
||||
"enabled_table_header": "Activé",
|
||||
"name_table_header": "Nom",
|
||||
"list_url_table_header": "URL de la liste",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Le journal des requêtes a été effacé",
|
||||
"query_log_updated": "Le journal des requêtes a été mis à jour",
|
||||
"query_log_clear": "Effacer journal des requêtes",
|
||||
"query_log_retention": "Rétention du journal des requêtes",
|
||||
"query_log_retention": "Rotation des journaux de requêtes",
|
||||
"query_log_enable": "Activer le journal",
|
||||
"query_log_configuration": "Configuration du journal",
|
||||
"query_log_disabled": "Le journal des requêtes est désactivé et peut être configuré dans les <0>paramètres</0>",
|
||||
"query_log_strict_search": "Utilisez les doubles guillemets pour une recherche stricte",
|
||||
"query_log_retention_confirm": "Êtes-vous sûr de vouloir modifier la rétention des journaux de requêtes ? Si vous diminuez la valeur de l'intervalle, certaines données seront perdues",
|
||||
"query_log_retention_confirm": "Êtes-vous sûr de souhaiter modifier la rotation des journaux de requêtes ? Si vous diminuez la valeur de l'intervalle, certaines données seront perdues",
|
||||
"anonymize_client_ip": "Anonymiser l’IP du client",
|
||||
"anonymize_client_ip_desc": "Ne pas enregistrer l’adresse IP complète du client dans les journaux et statistiques",
|
||||
"dns_config": "Configuration du serveur DNS",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Limite de taux",
|
||||
"edns_enable": "Activer le sous-réseau du client EDNS",
|
||||
"edns_cs_desc": "Ajouter l'option du sous-réseau Client EDNS (ECS) au requêtes en amont et enregistrer les valeurs envoyées par les clients dans le journal des requêtes.",
|
||||
"edns_use_custom_ip": "Utiliser une IP personnalisée pour EDNS",
|
||||
"edns_use_custom_ip_desc": "Autoriser l'utilisation d'une adresse IP personnalisée pour EDNS",
|
||||
"rate_limit_desc": "Le nombre de requêtes par seconde qu’un seul client est autorisé à faire. Le réglage 0 fait illimité.",
|
||||
"blocking_ipv4_desc": "Adresse IP à renvoyer pour une demande A bloquée",
|
||||
"blocking_ipv6_desc": "Adresse IP à renvoyer pour une demande AAAA bloquée",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Êtes-vous sûr de vouloir modifier le maintien des statistiques ? Si vous diminuez la valeur de l'intervalle, certaines données seront perdues",
|
||||
"statistics_cleared": "Statistiques effacées",
|
||||
"statistics_enable": "Activer les statistiques",
|
||||
"ignore_domains": "Domaines ignorés (séparés par une nouvelle ligne)",
|
||||
"ignore_domains_title": "Domaines ignorés",
|
||||
"ignore_domains_desc_stats": "Les requêtes pour ces domaines ne sont pas écrites dans les statistiques",
|
||||
"ignore_domains_desc_query": "Les requêtes pour ces domaines ne sont pas écrites dans le journal des requêtes",
|
||||
"interval_hours": "{{count}} heure",
|
||||
"interval_hours_plural": "{{count}} heures",
|
||||
"filters_configuration": "Configuration des filtres",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Note :</0> L'anonymisation IP est activée. Vous pouvez la désactiver dans les <1>paramètres généraux</1>.",
|
||||
"confirm_dns_cache_clear": "Voulez-vous vraiment vider le cache DNS ?",
|
||||
"cache_cleared": "Le cache DNS a été vidé",
|
||||
"clear_cache": "Vider le cache"
|
||||
"clear_cache": "Vider le cache",
|
||||
"make_static": "Rendre statique",
|
||||
"theme_auto_desc": "Auto (en fonction de la palette de couleurs de votre appareil)",
|
||||
"theme_dark_desc": "Thème sombre",
|
||||
"theme_light_desc": "Thème clair",
|
||||
"disable_for_seconds": "Pendant {{count}} seconde",
|
||||
"disable_for_seconds_plural": "Pendant {{count}} secondes",
|
||||
"disable_for_minutes": "Pendant {{count}} minute",
|
||||
"disable_for_minutes_plural": "Pendant {{count}} minutes",
|
||||
"disable_for_hours": "Pendant {{count}} heure",
|
||||
"disable_for_hours_plural": "Pendant {{count}} heures",
|
||||
"disable_until_tomorrow": "Jusqu'à demain",
|
||||
"disable_notify_for_seconds": "Désactiver la protection pendant {{count}} seconde",
|
||||
"disable_notify_for_seconds_plural": "Désactiver la protection pendant {{count}} secondes",
|
||||
"disable_notify_for_minutes": "Désactiver la protection pendant {{count}} minute",
|
||||
"disable_notify_for_minutes_plural": "Désactiver la protection pendant {{count}} minutes",
|
||||
"disable_notify_for_hours": "Désactiver la protection pendant {{count}} heure",
|
||||
"disable_notify_for_hours_plural": "Désactiver la protection pendant {{count}} heures",
|
||||
"disable_notify_until_tomorrow": "Désactiver la protection jusqu'à demain",
|
||||
"enable_protection_timer": "La protection sera activée dans {{time}}",
|
||||
"custom_retention_input": "Saisir la rétention en heures",
|
||||
"custom_rotation_input": "Saisir la rotation en heures",
|
||||
"protection_section_label": "Protection",
|
||||
"log_and_stats_section_label": "Journal des requêtes et statistiques",
|
||||
"ignore_query_log": "Ignorer ce client dans le journal des requêtes",
|
||||
"ignore_statistics": "Ignorer ce client dans les statistiques"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Omogućen roditeljski nadzor",
|
||||
"disabled_safe_search_toast": "Onemogućeno sigurno pretraživanje",
|
||||
"enabled_save_search_toast": "Omogućeno sigurno pretraživanje",
|
||||
"updated_save_search_toast": "Ažurirane postavke sigurnog pretraživanja",
|
||||
"enabled_table_header": "Omogućeno",
|
||||
"name_table_header": "Naziv",
|
||||
"list_url_table_header": "URL popisa",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Zapisnik upita je uspješno uklonjen",
|
||||
"query_log_updated": "Zapisnik upita je uspješno ažuriran",
|
||||
"query_log_clear": "Očisti zapisnik upita",
|
||||
"query_log_retention": "Spremanje zapisnika upita",
|
||||
"query_log_retention": "Rotacija dnevnika upita",
|
||||
"query_log_enable": "Omogući zapise",
|
||||
"query_log_configuration": "Postavke zapisa",
|
||||
"query_log_disabled": "Zapisnik upita je onemogućen i može se postaviti u <0>postavkama</0>",
|
||||
"query_log_strict_search": "Koristite dvostruke navodnike za strogo pretraživanje",
|
||||
"query_log_retention_confirm": "Jeste li sigurni da želite promijeniti zadržavanje zapisnika upita? Ako smanjite vrijednost intervala, neki će podaci biti izgubljeni",
|
||||
"query_log_retention_confirm": "Jeste li sigurni da želite promijeniti rotaciju dnevnika upita? Ako smanjite vrijednost intervala, neki će se podaci izgubiti",
|
||||
"anonymize_client_ip": "Anonimiraj IP klijenta",
|
||||
"anonymize_client_ip_desc": "Ne spremajte cijelu IP adresu klijenta u zapisnike i statistike",
|
||||
"dns_config": "DNS postavke poslužitelja",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Ograničenje",
|
||||
"edns_enable": "Omogući podmrežu klijenta EDNS-a",
|
||||
"edns_cs_desc": "Dodajte opciju EDNS klijentske podmreže (ECS) uzvodnim zahtjevima i zabilježite vrijednosti koje su klijenti poslali u dnevnik upita.",
|
||||
"edns_use_custom_ip": "Koristi prilagođeni IP za EDNS",
|
||||
"edns_use_custom_ip_desc": "Dopusti korištenje prilagođenog IP-a za EDNS",
|
||||
"rate_limit_desc": "Broj zahtjeva u sekundi koji su dopušteni po jednom klijentu. Postavljanje na 0 znači neograničeno.",
|
||||
"blocking_ipv4_desc": "Povratna IP adresa za blokirane A zahtjeve",
|
||||
"blocking_ipv6_desc": "Povratna IP adresa za blokirane AAAA zahtjeve",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Jeste li sigurni da želite promijeniti zadržavanje statistike? Ako smanjite vrijednost intervala, neki će podaci biti izgubljeni",
|
||||
"statistics_cleared": "Statistika je uspješno uklonjenja",
|
||||
"statistics_enable": "Omogući statistiku",
|
||||
"ignore_domains": "Zanemarene domene (odvojene novim retkom)",
|
||||
"ignore_domains_title": "Zanemarene domene",
|
||||
"ignore_domains_desc_stats": "Upiti za ove domene ne upisuju se u statistiku",
|
||||
"ignore_domains_desc_query": "Upiti za te domene nisu zapisani u zapisnik upita",
|
||||
"interval_hours": "{{count}} sata/i",
|
||||
"interval_hours_plural": "{{count}} sata/i",
|
||||
"filters_configuration": "Postavke filtara",
|
||||
@@ -642,5 +649,30 @@
|
||||
"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?",
|
||||
"cache_cleared": "DNS predmemorija je uspješno izbrisana",
|
||||
"clear_cache": "Očisti predmemoriju"
|
||||
"clear_cache": "Očisti predmemoriju",
|
||||
"make_static": "Učini statičnim",
|
||||
"theme_auto_desc": "Automatski (na temelju sheme boja vašeg uređaja)",
|
||||
"theme_dark_desc": "Tamna tema",
|
||||
"theme_light_desc": "Svijetla tema",
|
||||
"disable_for_seconds": "Za {{count}} sekundi",
|
||||
"disable_for_seconds_plural": "Za {{count}} sekundi",
|
||||
"disable_for_minutes": "Za {{count}} minuta",
|
||||
"disable_for_minutes_plural": "Za {{count}} minuta",
|
||||
"disable_for_hours": "Za {{count}} sati",
|
||||
"disable_for_hours_plural": "Za {{count}} sati",
|
||||
"disable_until_tomorrow": "Do sutra",
|
||||
"disable_notify_for_seconds": "Isključi zaštitu na {{count}} sekundi",
|
||||
"disable_notify_for_seconds_plural": "Onemogući zaštitu na {{count}} sekundi",
|
||||
"disable_notify_for_minutes": "Isključi zaštitu na {{count}} minuta",
|
||||
"disable_notify_for_minutes_plural": "Isključi zaštitu na {{count}} minuta",
|
||||
"disable_notify_for_hours": "Isključi zaštitu na {{count}} sati",
|
||||
"disable_notify_for_hours_plural": "Isključi zaštitu na {{count}} sati",
|
||||
"disable_notify_until_tomorrow": "Isključi zaštitu do sutra",
|
||||
"enable_protection_timer": "Zaštita će biti omogućena u {{time}}",
|
||||
"custom_retention_input": "Unesite zadržavanje u satima",
|
||||
"custom_rotation_input": "Unesite rotaciju u satima",
|
||||
"protection_section_label": "Zaštita",
|
||||
"log_and_stats_section_label": "Zapisnik upita i statistika",
|
||||
"ignore_query_log": "Zanemari ovog klijenta u zapisniku upita",
|
||||
"ignore_statistics": "Ignorirajte ovog klijenta u statistici"
|
||||
}
|
||||
|
||||
@@ -642,5 +642,6 @@
|
||||
"anonymizer_notification": "<0>Megjegyzés:</0> Az IP anonimizálás engedélyezve van. Az <1>Általános beállításoknál letilthatja</1> .",
|
||||
"confirm_dns_cache_clear": "Biztos benne, hogy törölni szeretné a DNS-gyorsítótárat?",
|
||||
"cache_cleared": "A DNS gyorsítótár sikeresen törlődött",
|
||||
"clear_cache": "Gyorsítótár törlése"
|
||||
"clear_cache": "Gyorsítótár törlése",
|
||||
"protection_section_label": "Védelem"
|
||||
}
|
||||
|
||||
@@ -641,5 +641,6 @@
|
||||
"anonymizer_notification": "<0>Catatan:</0> Anonimisasi IP diaktifkan. Anda dapat menonaktifkannya di <1>Pengaturan umum</1> .",
|
||||
"confirm_dns_cache_clear": "Apakah Anda yakin ingin menghapus cache DNS?",
|
||||
"cache_cleared": "Cache DNS berhasil dibersihkan",
|
||||
"clear_cache": "Hapus cache"
|
||||
"clear_cache": "Hapus cache",
|
||||
"protection_section_label": "Perlindungan"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Il Controllo Parentale è attivo",
|
||||
"disabled_safe_search_toast": "La Ricerca Sicura è disattivata",
|
||||
"enabled_save_search_toast": "La Ricerca Sicura è attiva",
|
||||
"updated_save_search_toast": "Impostazioni di Safe Search aggiornate",
|
||||
"enabled_table_header": "Attivo",
|
||||
"name_table_header": "Nome",
|
||||
"list_url_table_header": "Elenco URL",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Il registro richieste è stato correttamente cancellato",
|
||||
"query_log_updated": "Il registro richieste è stato correttamente aggiornato",
|
||||
"query_log_clear": "Cancella registri richieste",
|
||||
"query_log_retention": "Conservazione dei registri richieste",
|
||||
"query_log_retention": "Rotazione dei registri richieste",
|
||||
"query_log_enable": "Attiva registro",
|
||||
"query_log_configuration": "Configurazione registri",
|
||||
"query_log_disabled": "Il registro richieste è stato disattivato e può essere configurata dalle <0>impostazioni</0>",
|
||||
"query_log_strict_search": "Utilizzare le doppie virgolette per una ricerca precisa",
|
||||
"query_log_retention_confirm": "Sei sicuro di voler modificare il registro delle richieste? Se il valore di intervallo dovesse diminuire, alcuni dati andranno persi",
|
||||
"query_log_retention_confirm": "Sei sicuro di voler modificare il registro delle richieste? Se si riduce il valore dell'intervallo, alcuni dati andranno persi",
|
||||
"anonymize_client_ip": "Anonimizza client IP",
|
||||
"anonymize_client_ip_desc": "Non salvare l'indirizzo IP completo del client nel registro o nelle statistiche",
|
||||
"dns_config": "Configurazione server DNS",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Limite delle richieste",
|
||||
"edns_enable": "Attiva client di sottorete EDNS",
|
||||
"edns_cs_desc": "Aggiunge l'opzione EDNS Client Subnet (ECS) alle richieste upstream e registra i valori inviati dai client nel registro delle richieste.",
|
||||
"edns_use_custom_ip": "Usa IP personalizzato per EDNS",
|
||||
"edns_use_custom_ip_desc": "Consentire l'uso di un IP personalizzato per EDNS",
|
||||
"rate_limit_desc": "Il numero di richieste al secondo consentite da un singolo client. Impostare questo valore a 0 rimuove le limitazioni.",
|
||||
"blocking_ipv4_desc": "Indirizzo IP per una richiesta DNS IPv4 bloccata",
|
||||
"blocking_ipv6_desc": "Indirizzo IP restituito per una richiesta DNS IPv6 bloccata",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Sei sicuro di voler modificare la conservazione delle statistiche? Se il valore di intervallo dovesse diminuire, alcuni dati andranno persi",
|
||||
"statistics_cleared": "Statistiche azzerate correttamente",
|
||||
"statistics_enable": "Attiva statistiche",
|
||||
"ignore_domains": "Domini ignorati (separati da nuova riga)",
|
||||
"ignore_domains_title": "Domini ignorati",
|
||||
"ignore_domains_desc_stats": "Le richieste per questi domini non vengono scritte nelle statistiche",
|
||||
"ignore_domains_desc_query": "Le richieste per questi domini non vengono scritte nel registro delle richieste",
|
||||
"interval_hours": "{{count}} ora",
|
||||
"interval_hours_plural": "{{count}} ore",
|
||||
"filters_configuration": "Configurazione filtri",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Attenzione:</0> L'anonimizzazione dell'IP è abilitata. Puoi disabilitarla in <1>Impostazioni generali</1>.",
|
||||
"confirm_dns_cache_clear": "Sei sicuro di voler cancellare la cache DNS?",
|
||||
"cache_cleared": "Cache DNS è stata cancellata correttamente",
|
||||
"clear_cache": "Cancella cache"
|
||||
"clear_cache": "Cancella cache",
|
||||
"make_static": "Rendere statico",
|
||||
"theme_auto_desc": "Auto (in base alla combinazione di colori del tuo dispositivo)",
|
||||
"theme_dark_desc": "Tema scuro",
|
||||
"theme_light_desc": "Tema chiaro",
|
||||
"disable_for_seconds": "Per {{count}} secondo",
|
||||
"disable_for_seconds_plural": "Per {{count}} secondi",
|
||||
"disable_for_minutes": "Per {{count}} minuto",
|
||||
"disable_for_minutes_plural": "Per {{count}} minuti",
|
||||
"disable_for_hours": "Per {{count}} ora",
|
||||
"disable_for_hours_plural": "Per {{count}} ore",
|
||||
"disable_until_tomorrow": "Fino a domani",
|
||||
"disable_notify_for_seconds": "Disattiva la protezione per {{count}} secondo",
|
||||
"disable_notify_for_seconds_plural": "Disattiva la protezione per {{count}} secondi",
|
||||
"disable_notify_for_minutes": "Disattiva protezione per {{count}} minuto",
|
||||
"disable_notify_for_minutes_plural": "Disattiva la protezione per {{count}} minuti",
|
||||
"disable_notify_for_hours": "Disattiva la protezione per {{count}} ora",
|
||||
"disable_notify_for_hours_plural": "Disattiva la protezione per {{count}} ore",
|
||||
"disable_notify_until_tomorrow": "Disattiva la protezione fino a domani",
|
||||
"enable_protection_timer": "La protezione verrà attivata in {{time}}",
|
||||
"custom_retention_input": "Inserisci la conservazione in ore",
|
||||
"custom_rotation_input": "Inserisci la rotazione in ore",
|
||||
"protection_section_label": "Protezione",
|
||||
"log_and_stats_section_label": "Registro richieste e statistiche",
|
||||
"ignore_query_log": "Ignora questo client nel registro delle richieste",
|
||||
"ignore_statistics": "Ignora questo cliente nelle statistiche"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "ペアレンタルコントロールが有効になりました",
|
||||
"disabled_safe_search_toast": "セーフサーチが無効になりました",
|
||||
"enabled_save_search_toast": "セーフサーチが有効になりました",
|
||||
"updated_save_search_toast": "セーフ サーチの設定が更新されました。",
|
||||
"enabled_table_header": "有効",
|
||||
"name_table_header": "名称",
|
||||
"list_url_table_header": "URLリスト",
|
||||
@@ -256,12 +257,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サーバ設定",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "頻度制限",
|
||||
"edns_enable": "EDNSクライアントサブネットを有効にする",
|
||||
"edns_cs_desc": "アップストリームリクエストにEDNSクライアントサブネットオプション(ECS)を追加し、クライアントから送信された値をクエリログに記録します。",
|
||||
"edns_use_custom_ip": "EDNSにカスタムIPを使用する",
|
||||
"edns_use_custom_ip_desc": "EDNS に対してカスタム IP の使用を許可します。",
|
||||
"rate_limit_desc": "一つのクライアントに対して許可される1秒あたりのリクエスト数(「0」に設定すると、制限なしになります)",
|
||||
"blocking_ipv4_desc": "ブロックされたAリクエストに対して応答されるIPアドレス",
|
||||
"blocking_ipv6_desc": "ブロックされたAAAAリクエストに対して応答されるIPアドレス",
|
||||
@@ -523,6 +526,10 @@
|
||||
"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": "フィルタ設定",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "【<0>注意</0>】IPの匿名化が有効になっています。 <1>一般設定</1>で無効にできます。",
|
||||
"confirm_dns_cache_clear": "DNS キャッシュをクリアしてもよろしいですか?",
|
||||
"cache_cleared": "DNSキャッシュのクリア完了です。",
|
||||
"clear_cache": "キャッシュをクリアする"
|
||||
"clear_cache": "キャッシュをクリアする",
|
||||
"make_static": "静的(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": "ローテーションを入力してください(時間単位)",
|
||||
"protection_section_label": "AdGuardによる保護",
|
||||
"log_and_stats_section_label": "クエリ・ログと統計情報",
|
||||
"ignore_query_log": "クエリ・ログでこのクライアントを無視する",
|
||||
"ignore_statistics": "統計でこのクライアントを無視する"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "자녀 보호 활성화됨",
|
||||
"disabled_safe_search_toast": "세이프서치 비활성화됨",
|
||||
"enabled_save_search_toast": "세이프서치 활성화됨",
|
||||
"updated_save_search_toast": "세이프서치 설정 업데이트됨",
|
||||
"enabled_table_header": "활성화됨",
|
||||
"name_table_header": "이름",
|
||||
"list_url_table_header": "리스트 URL",
|
||||
@@ -256,12 +257,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 서버 설정",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "한도 제한",
|
||||
"edns_enable": "EDNS 클라이언트 서브넷 활성화",
|
||||
"edns_cs_desc": "업스트림 요청에 EDNS 클라이언트 서브넷 옵션(ECS)을 추가하고 쿼리 로그에 클라이언트가 보낸 값을 기록합니다.",
|
||||
"edns_use_custom_ip": "EDNS에 사용자 지정 IP 사용",
|
||||
"edns_use_custom_ip_desc": "EDNS에 사용자 지정 IP 사용하도록 허용합니다.",
|
||||
"rate_limit_desc": "단일 클라이언트에서 허용 가능한 초 당 요청 생성 숫자 (0: 무제한)",
|
||||
"blocking_ipv4_desc": "차단된 A 요청에 대해서 반환할 IP 주소",
|
||||
"blocking_ipv6_desc": "차단된 AAAA 요청에 대해서 반환할 IP 주소",
|
||||
@@ -523,6 +526,10 @@
|
||||
"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": "필터 구성",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>참고:</0> IP 익명화가 활성화되었습니다. <1>일반 설정</1>에서 비활성화할 수 있습니다.",
|
||||
"confirm_dns_cache_clear": "정말로 DNS 캐시를 지우시겠습니까?",
|
||||
"cache_cleared": "DNS 캐시를 성공적으로 지웠습니다",
|
||||
"clear_cache": "캐시 지우기"
|
||||
"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": "시간 단위로 로테이션 입력",
|
||||
"protection_section_label": "보호",
|
||||
"log_and_stats_section_label": "쿼리 로그 및 통계",
|
||||
"ignore_query_log": "쿼리 로그에서 이 클라이언트 무시",
|
||||
"ignore_statistics": "통계에서 이 클라이언트 무시"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Ingeschakeld Ouderlijk toezicht",
|
||||
"disabled_safe_search_toast": "Uitgeschakeld Veilig zoeken",
|
||||
"enabled_save_search_toast": "Ingeschakeld Veilig zoeken",
|
||||
"updated_save_search_toast": "Safe Search-instellingen bijgewerkt",
|
||||
"enabled_table_header": "Ingeschakeld",
|
||||
"name_table_header": "Naam",
|
||||
"list_url_table_header": "URL lijst",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Het query logboek is succesvol geleegd",
|
||||
"query_log_updated": "Het query logboek is succesvol bijgewerkt",
|
||||
"query_log_clear": "Leeg query logs",
|
||||
"query_log_retention": "Query logs bewaartermijn",
|
||||
"query_log_retention": "Query logs rotatie",
|
||||
"query_log_enable": "Log bestanden inschakelen",
|
||||
"query_log_configuration": "Logbestanden instellingen",
|
||||
"query_log_disabled": "Het query logboek is uitgeschakeld en kan worden geconfigureerd in de <0>instellingen</0>",
|
||||
"query_log_strict_search": "Gebruik dubbele aanhalingstekens voor strikt zoeken",
|
||||
"query_log_retention_confirm": "Weet u zeker dat u de bewaartermijn van het query logboek wilt wijzigen? Als u de intervalwaarde verlaagt, gaan sommige gegevens verloren",
|
||||
"query_log_retention_confirm": "Weet u zeker dat u de rotatie van het querylogboek wilt wijzigen? Als u de intervalwaarde verlaagt, gaan sommige gegevens verloren",
|
||||
"anonymize_client_ip": "Cliënt IP anonimiseren",
|
||||
"anonymize_client_ip_desc": "Het volledige IP-adres van de cliënt niet opnemen in logboeken en statistiekbestanden",
|
||||
"dns_config": "DNS-server configuratie",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Ratio limiet",
|
||||
"edns_enable": "EDNS client subnet inschakelen",
|
||||
"edns_cs_desc": "De EDNS Client Subnet-optie (ECS) toevoegen aan upstream-verzoeken en de waarden die door de clients zijn verzonden registreren in het querylogboek.",
|
||||
"edns_use_custom_ip": "Aangepast IP-adres gebruiken voor EDNS",
|
||||
"edns_use_custom_ip_desc": "Toestaan om aangepast IP-adres voor EDNS te gebruiken",
|
||||
"rate_limit_desc": "Het aantal verzoeken per seconde toegelaten per toestel. 0 betekent onbeperkt.",
|
||||
"blocking_ipv4_desc": "IP-adres dat moet worden teruggegeven voor een geblokkeerd A-verzoek",
|
||||
"blocking_ipv6_desc": "IP-adres dat moet worden teruggegeven voor een geblokkeerd A-verzoek",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Weet u zeker dat u de bewaartermijn van de statistieken wilt wijzigen? Als u de intervalwaarde verlaagt, gaan sommige gegevens verloren",
|
||||
"statistics_cleared": "Statistieken succesvol gewist",
|
||||
"statistics_enable": "Statistieken inschakelen",
|
||||
"ignore_domains": "Genegeerde domeinen (gescheiden door nieuwe regel)",
|
||||
"ignore_domains_title": "Genegeerde domeinen",
|
||||
"ignore_domains_desc_stats": "Zoekopdrachten voor deze domeinen worden niet naar de statistieken geschreven",
|
||||
"ignore_domains_desc_query": "Zoekopdrachten voor deze domeinen worden niet naar het zoeklogboek geschreven",
|
||||
"interval_hours": "{{count}} uur",
|
||||
"interval_hours_plural": "{{count}} uren",
|
||||
"filters_configuration": "Filters instellingen",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Opmerking:</0> IP-anonimisering is ingeschakeld. Je kunt het uitschakelen in <1>Algemene instellingen</1>.",
|
||||
"confirm_dns_cache_clear": "Weet je zeker dat je de DNS-cache wilt wissen?",
|
||||
"cache_cleared": "DNS-cache succesvol gewist",
|
||||
"clear_cache": "Cache wissen"
|
||||
"clear_cache": "Cache wissen",
|
||||
"make_static": "Statisch maken",
|
||||
"theme_auto_desc": "Automatisch (op basis van het kleurenschema van jouw apparaat)",
|
||||
"theme_dark_desc": "Donker thema",
|
||||
"theme_light_desc": "Licht thema",
|
||||
"disable_for_seconds": "Voor {{count}} seconde",
|
||||
"disable_for_seconds_plural": "Voor {{count}} seconden",
|
||||
"disable_for_minutes": "Voor {{count}} minuut",
|
||||
"disable_for_minutes_plural": "Voor {{count}} minuten",
|
||||
"disable_for_hours": "Voor {{count}} uur",
|
||||
"disable_for_hours_plural": "Voor {{count}} uren",
|
||||
"disable_until_tomorrow": "Tot morgen",
|
||||
"disable_notify_for_seconds": "Beveiliging uitschakelen voor {{count}} seconde",
|
||||
"disable_notify_for_seconds_plural": "Beveiliging uitschakelen voor {{count}} seconden",
|
||||
"disable_notify_for_minutes": "Beveiliging uitschakelen voor {{count}} minuut",
|
||||
"disable_notify_for_minutes_plural": "Beveiliging uitschakelen voor {{count}} minuten",
|
||||
"disable_notify_for_hours": "Beveiliging uitschakelen voor {{count}} uur",
|
||||
"disable_notify_for_hours_plural": "Beveiliging uitschakelen voor {{count}} uren",
|
||||
"disable_notify_until_tomorrow": "Beveiliging uitschakelen tot morgen",
|
||||
"enable_protection_timer": "Bescherming wordt ingeschakeld over {{time}}",
|
||||
"custom_retention_input": "Voer retentie in uren in",
|
||||
"custom_rotation_input": "Voer rotatie in uren in",
|
||||
"protection_section_label": "Bescherming",
|
||||
"log_and_stats_section_label": "Aanvragenlogboek en statistieken",
|
||||
"ignore_query_log": "Deze client negeren in het aanvragenlogboek",
|
||||
"ignore_statistics": "Deze client negeren in de statistieken"
|
||||
}
|
||||
|
||||
@@ -281,6 +281,9 @@
|
||||
"blocking_mode_nxdomain": "NXDOMAIN: Svar med NXDOMAIN-koden",
|
||||
"blocking_mode_null_ip": "Null IP: Svar med en 0-IP-adresse (0.0.0.0 for A; :: for AAAA)",
|
||||
"blocking_mode_custom_ip": "Tilpasset IP: Svar med en manuelt valgt IP-adresse",
|
||||
"theme_auto": "Auto",
|
||||
"theme_light": "Lyst tema",
|
||||
"theme_dark": "Mørkt tema",
|
||||
"upstream_dns_client_desc": "Hvis dette feltet holdes tomt, vil AdGuard Home bruke tjenerne som er satt opp i <0>DNS-innstillingene</0>.",
|
||||
"tracker_source": "Sporerkilde",
|
||||
"source_label": "Kilde",
|
||||
@@ -613,5 +616,6 @@
|
||||
"use_saved_key": "Bruk den tidligere lagrede nøkkelen",
|
||||
"parental_control": "Foreldrekontroll",
|
||||
"safe_browsing": "Sikker surfing",
|
||||
"served_from_cache": "{{value}} <i>(formidlet fra mellomlageret)</i>"
|
||||
"served_from_cache": "{{value}} <i>(formidlet fra mellomlageret)</i>",
|
||||
"protection_section_label": "Beskyttelse"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Włączona Kontrola Rodzicielska",
|
||||
"disabled_safe_search_toast": "Wyłączone bezpieczne wyszukiwanie",
|
||||
"enabled_save_search_toast": "Włączone bezpieczne wyszukiwanie",
|
||||
"updated_save_search_toast": "Zaktualizowano ustawienia bezpiecznego wyszukiwania",
|
||||
"enabled_table_header": "Włączone",
|
||||
"name_table_header": "Nazwa",
|
||||
"list_url_table_header": "Adres URL listy",
|
||||
@@ -221,7 +222,7 @@
|
||||
"all_lists_up_to_date_toast": "Wszystkie listy są już aktualne",
|
||||
"updated_upstream_dns_toast": "Serwery nadrzędne zostały pomyślnie zapisane",
|
||||
"dns_test_ok_toast": "Określone serwery DNS działają poprawnie",
|
||||
"dns_test_not_ok_toast": "Serwer \"{{key}}\": nie można go użyć, sprawdź, czy napisałeś go poprawnie",
|
||||
"dns_test_not_ok_toast": "Serwer \"{{key}}\": nie może być użyte, sprawdź, czy zapisano go poprawnie",
|
||||
"dns_test_warning_toast": "Upstream \"{{key}}\" nie odpowiada na zapytania testowe i może nie działać prawidłowo",
|
||||
"unblock": "Odblokuj",
|
||||
"block": "Zablokuj",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Dziennik zapytań został pomyślnie wyczyszczony",
|
||||
"query_log_updated": "Dziennik zapytań został zaktualizowany",
|
||||
"query_log_clear": "Wyczyść dzienniki zapytań",
|
||||
"query_log_retention": "Przechowywanie dzienników zapytań",
|
||||
"query_log_retention": "Rotacja dzienników zapytań",
|
||||
"query_log_enable": "Włącz dziennik",
|
||||
"query_log_configuration": "Konfiguracja dzienników",
|
||||
"query_log_disabled": "Dziennik zapytań jest wyłączony i można go skonfigurować w <0>ustawieniach</0>",
|
||||
"query_log_strict_search": "Używaj podwójnych cudzysłowów do ścisłego wyszukiwania",
|
||||
"query_log_retention_confirm": "Czy na pewno chcesz zmienić sposób przechowywania dziennika zapytań? Jeśli zmniejszysz wartość interwału, niektóre dane zostaną utracone",
|
||||
"query_log_retention_confirm": "Czy na pewno chcesz zmienić rotację dziennika zapytań? Jeśli zmniejszysz wartość interwału, niektóre dane zostaną utracone",
|
||||
"anonymize_client_ip": "Anonimizuj adres IP klienta",
|
||||
"anonymize_client_ip_desc": "Nie zapisuj pełnego adresu IP w dziennikach i statystykach",
|
||||
"dns_config": "Konfiguracja serwera DNS",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Limit ilościowy",
|
||||
"edns_enable": "Włącz podsieć klienta EDNS",
|
||||
"edns_cs_desc": "Dodaj opcję podsieci klienta EDNS (ECS) do żądań nadrzędnych i rejestruj wartości wysyłane przez klientów w dzienniku zapytań.",
|
||||
"edns_use_custom_ip": "Użyj niestandardowego adresu IP dla EDNS",
|
||||
"edns_use_custom_ip_desc": "Zezwól na użycie niestandardowego adresu IP dla EDNS",
|
||||
"rate_limit_desc": "Liczba żądań na sekundę dozwolona na klienta. Ustawienie wartości 0 oznacza brak ograniczeń.",
|
||||
"blocking_ipv4_desc": "Adres IP, który ma zostać zwrócony w przypadku zablokowanego żądania A",
|
||||
"blocking_ipv6_desc": "Adres IP, który ma zostać zwrócony w przypadku zablokowanego żądania AAAA",
|
||||
@@ -343,7 +346,7 @@
|
||||
"install_devices_windows_list_2": "Przejdź do kategorii Sieć i Internet, a następnie do Centrum sieci i udostępniania.",
|
||||
"install_devices_windows_list_3": "W lewym panelu kliknij \"Zmień ustawienia adaptera\".",
|
||||
"install_devices_windows_list_4": "Kliknij prawym przyciskiem myszy aktywne połączenie i wybierz Właściwości.",
|
||||
"install_devices_windows_list_5": "Znajdź na liście \"Protokół internetowy w wersji 4 (TCP/IPv4)\" (lub w przypadku IPv6 \"Protokół internetowy w wersji 6 (TCP/IPv6)\"), zaznacz go i ponownie kliknij na Właściwości.",
|
||||
"install_devices_windows_list_5": "Znajdź na liście \"Protokół internetowy w wersji 4 (TCP/IPv4)\" (lub w przypadku IPv6 \"Protokół internetowy w wersji 6 (TCP/IPv6)\"), zaznacz go i ponownie kliknij Właściwości.",
|
||||
"install_devices_windows_list_6": "Wybierz opcję \"Użyj następujących adresów serwerów DNS\" i wprowadź adresy serwerów AdGuard Home.",
|
||||
"install_devices_macos_list_1": "Kliknij ikonę Apple i przejdź do Preferencje systemowe.",
|
||||
"install_devices_macos_list_2": "Kliknij Sieć.",
|
||||
@@ -393,7 +396,7 @@
|
||||
"encryption_issuer": "Zgłaszający",
|
||||
"encryption_hostnames": "Nazwy hostów",
|
||||
"encryption_reset": "Czy na pewno chcesz zresetować ustawienia szyfrowania?",
|
||||
"encryption_warning": "Uwaga!",
|
||||
"encryption_warning": "Uwaga",
|
||||
"topline_expiring_certificate": "Twój certyfikat SSL wkrótce wygaśnie. Zaktualizuj <0>Ustawienia szyfrowania</0>.",
|
||||
"topline_expired_certificate": "Twój certyfikat SSL wygasł. Zaktualizuj <0>Ustawienia szyfrowania</0>.",
|
||||
"form_error_port_range": "Wpisz numer portu z zakresu 80-65535",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Czy chcesz zmienić sposób przechowania statystyk? Jeżeli obniżysz wartość interwału, niektóre dane będą utracone",
|
||||
"statistics_cleared": "Statystyki zostały pomyślnie wyczyszczone",
|
||||
"statistics_enable": "Włącz statystyki",
|
||||
"ignore_domains": "Ignorowane domeny (każda w nowym wierszu)",
|
||||
"ignore_domains_title": "Ignorowane domeny",
|
||||
"ignore_domains_desc_stats": "Zapytania dla tych domen nie są zapisywane do statystyk",
|
||||
"ignore_domains_desc_query": "Zapytania dla tych domen nie są zapisywane do dziennika",
|
||||
"interval_hours": "{{count}} godzina",
|
||||
"interval_hours_plural": "{{count}} godziny",
|
||||
"filters_configuration": "Konfiguracja filtrów",
|
||||
@@ -535,7 +542,7 @@
|
||||
"password_placeholder": "Wpisz hasło",
|
||||
"sign_in": "Zaloguj się",
|
||||
"sign_out": "Wyloguj się",
|
||||
"forgot_password": "Zapomniałeś hasła?",
|
||||
"forgot_password": "Zapomniano hasła?",
|
||||
"forgot_password_desc": "Wykonaj <0>te kroki</0>, aby utworzyć nowe hasło do konta użytkownika.",
|
||||
"location": "Lokalizacja",
|
||||
"orgname": "Nazwa firmy",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Uwaga:</0> Anonimizacja IP jest włączona. Możesz ją wyłączyć w <1>Ustawieniach ogólnych</1>.",
|
||||
"confirm_dns_cache_clear": "Czy na pewno chcesz wyczyścić pamięć podręczną DNS?",
|
||||
"cache_cleared": "Pamięć podręczna DNS została pomyślnie wyczyszczona",
|
||||
"clear_cache": "Wyczyść pamięć podręczną"
|
||||
"clear_cache": "Wyczyść pamięć podręczną",
|
||||
"make_static": "Ustaw adres statyczny",
|
||||
"theme_auto_desc": "Automatycznie (na podstawie schematu kolorów Twojego urządzenia)",
|
||||
"theme_dark_desc": "Ciemny motyw",
|
||||
"theme_light_desc": "Jasny motyw",
|
||||
"disable_for_seconds": "Na {{count}} sekundę",
|
||||
"disable_for_seconds_plural": "Na {{count}} sekund",
|
||||
"disable_for_minutes": "Na {{count}} minutę",
|
||||
"disable_for_minutes_plural": "Na {{count}} minut",
|
||||
"disable_for_hours": "Na {{count}} godzinę",
|
||||
"disable_for_hours_plural": "Na {{count}} godziny",
|
||||
"disable_until_tomorrow": "Do jutra",
|
||||
"disable_notify_for_seconds": "Wyłącz ochronę na {{count}} sekundę",
|
||||
"disable_notify_for_seconds_plural": "Wyłącz ochronę na {{count}} sekund",
|
||||
"disable_notify_for_minutes": "Wyłącz ochronę na {{count}} minutę",
|
||||
"disable_notify_for_minutes_plural": "Wyłącz ochronę na {{count}} minut",
|
||||
"disable_notify_for_hours": "Wyłącz ochronę na {{count}} godzinę",
|
||||
"disable_notify_for_hours_plural": "Wyłącz ochronę na {{count}} godziny",
|
||||
"disable_notify_until_tomorrow": "Wyłącz ochronę do jutra",
|
||||
"enable_protection_timer": "Ochrona zostanie włączona za {{time}}",
|
||||
"custom_retention_input": "Wprowadź retencję w godzinach",
|
||||
"custom_rotation_input": "Wprowadź rotację w godzinach",
|
||||
"protection_section_label": "Ochrona",
|
||||
"log_and_stats_section_label": "Dziennik zapytań i statystyki",
|
||||
"ignore_query_log": "Zignoruj tego klienta w dzienniku zapytań",
|
||||
"ignore_statistics": "Ignoruj tego klienta w statystykach"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Controle parental ativado",
|
||||
"disabled_safe_search_toast": "Pesquisa segura desativada",
|
||||
"enabled_save_search_toast": "Pesquisa segura ativada",
|
||||
"updated_save_search_toast": "Configurações de Pesquisa Segura atualizadas",
|
||||
"enabled_table_header": "Ativado",
|
||||
"name_table_header": "Nome",
|
||||
"list_url_table_header": "URL da lista",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "O registro de consulta foi limpo com sucesso",
|
||||
"query_log_updated": "O registro da consulta foi atualizado com sucesso",
|
||||
"query_log_clear": "Limpar registros de consulta",
|
||||
"query_log_retention": "Arquivamento de registros de consultas",
|
||||
"query_log_retention": "Rotação de registros de consulta",
|
||||
"query_log_enable": "Ativar registro",
|
||||
"query_log_configuration": "Configuração de registros",
|
||||
"query_log_disabled": "O registro de consulta está desativado e pode ser configurado em <0>configurações</0>",
|
||||
"query_log_strict_search": "Use aspas duplas para uma pesquisa mais criteriosa",
|
||||
"query_log_retention_confirm": "Você tem certeza de que deseja alterar o arquivamento do registro de consulta? Se diminuir o valor de intervalo, alguns dados serão perdidos",
|
||||
"query_log_retention_confirm": "Tem a certeza de que quer alterar a rotação do registo de consulta? Se diminuir o valor do intervalo, alguns dados serão perdidos",
|
||||
"anonymize_client_ip": "Tornar anônimo o IP do cliente",
|
||||
"anonymize_client_ip_desc": "Não salva o endereço de IP completo do cliente em registros ou estatísticas",
|
||||
"dns_config": "Configuração do servidor DNS",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Taxa limite",
|
||||
"edns_enable": "Ativar a sub-rede do cliente EDNS",
|
||||
"edns_cs_desc": "Adicione a opção de sub-rede de cliente EDNS (ECS) às solicitações de servidor DNS primário e registre os valores enviados pelos clientes no registro de consulta.",
|
||||
"edns_use_custom_ip": "Usar IP personalizado para EDNS",
|
||||
"edns_use_custom_ip_desc": "Permitir o uso de IP personalizado para EDNS",
|
||||
"rate_limit_desc": "O número de solicitações por segundo permitidas por cliente. Definir como 0 significa que não há limite.",
|
||||
"blocking_ipv4_desc": "Endereço de IP a ser retornado para uma solicitação bloqueada",
|
||||
"blocking_ipv6_desc": "Endereço de IP a ser retornado para uma solicitação AAAA bloqueada",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Você tem certeza que quer alterar o arquivamento das estatísticas? Se diminuir o valor do intervalo, alguns dados serão perdidos",
|
||||
"statistics_cleared": "As estatísticas foram limpas com sucesso",
|
||||
"statistics_enable": "Ativar estatísticas",
|
||||
"ignore_domains": "Domínios ignorados (separados por nova linha)",
|
||||
"ignore_domains_title": "Domínios ignorados",
|
||||
"ignore_domains_desc_stats": "As consultas para esses domínios não são gravadas nas estatísticas",
|
||||
"ignore_domains_desc_query": "As consultas para esses domínios não são gravadas no registro de consulta",
|
||||
"interval_hours": "{{count}} hora",
|
||||
"interval_hours_plural": "{{count}} horas",
|
||||
"filters_configuration": "Configuração de filtros",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Observação:</0> A anonimização de IP está ativada. Você pode desativá-lo em <1>Configurações gerais</1>.",
|
||||
"confirm_dns_cache_clear": "Tem certeza de que deseja limpar o cache DNS?",
|
||||
"cache_cleared": "Cache DNS limpo com sucesso",
|
||||
"clear_cache": "Limpar cache"
|
||||
"clear_cache": "Limpar cache",
|
||||
"make_static": "Tornar estático",
|
||||
"theme_auto_desc": "Automático (com base no esquema de cores do seu dispositivo)",
|
||||
"theme_dark_desc": "Tema escuro",
|
||||
"theme_light_desc": "Tema claro",
|
||||
"disable_for_seconds": "Por {{count}} segundo",
|
||||
"disable_for_seconds_plural": "Por {{count}} segundos",
|
||||
"disable_for_minutes": "Por {{count}} minuto",
|
||||
"disable_for_minutes_plural": "Por {{count}} minutos",
|
||||
"disable_for_hours": "Por {{count}} hora",
|
||||
"disable_for_hours_plural": "Por {{count}} horas",
|
||||
"disable_until_tomorrow": "Até amanhã",
|
||||
"disable_notify_for_seconds": "Desativar proteção por {{count}} segundo",
|
||||
"disable_notify_for_seconds_plural": "Desativar proteção por {{count}} segundos",
|
||||
"disable_notify_for_minutes": "Desativar proteção por {{count}} minuto",
|
||||
"disable_notify_for_minutes_plural": "Desativar proteção por {{count}} minutos",
|
||||
"disable_notify_for_hours": "Desativar proteção por {{count}} hora",
|
||||
"disable_notify_for_hours_plural": "Desativar proteção por {{count}} horas",
|
||||
"disable_notify_until_tomorrow": "Desativar a proteção até amanhã",
|
||||
"enable_protection_timer": "A proteção será ativada em {{time}}",
|
||||
"custom_retention_input": "Insira a retenção em horas",
|
||||
"custom_rotation_input": "Insira a rotação em horas",
|
||||
"protection_section_label": "Proteção",
|
||||
"log_and_stats_section_label": "Registro de consultas e estatísticas",
|
||||
"ignore_query_log": "Ignorar este cliente no registo de consultas",
|
||||
"ignore_statistics": "Ignorar este cliente nas estatísticas"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Controlo parental ativado",
|
||||
"disabled_safe_search_toast": "Pesquisa segura desativada",
|
||||
"enabled_save_search_toast": "Pesquisa segura ativada",
|
||||
"updated_save_search_toast": "Configurações de pesquisa segura actualizadas",
|
||||
"enabled_table_header": "Ativado",
|
||||
"name_table_header": "Nome",
|
||||
"list_url_table_header": "URL da lista",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "O registo de consulta foi limpo com sucesso",
|
||||
"query_log_updated": "O registo da consulta foi atualizado com sucesso",
|
||||
"query_log_clear": "Limpar registos de consulta",
|
||||
"query_log_retention": "Retenção de registos de consulta",
|
||||
"query_log_retention": "Rotação de registros de consulta",
|
||||
"query_log_enable": "Ativar registo",
|
||||
"query_log_configuration": "Definições do registo",
|
||||
"query_log_disabled": "O registo de consulta está desativado e pode ser configurado em <0>definições</0>",
|
||||
"query_log_strict_search": "Usar aspas duplas para uma pesquisa rigorosa",
|
||||
"query_log_retention_confirm": "Tem a certeza de que deseja alterar a retenção do registo de consulta? Se diminuir o valor do intervalo, alguns dados serão perdidos",
|
||||
"query_log_retention_confirm": "Tem a certeza de que quer alterar a rotação do registo de consulta? Se diminuir o valor do intervalo, alguns dados serão perdidos",
|
||||
"anonymize_client_ip": "Tornar anónimo o IP do cliente",
|
||||
"anonymize_client_ip_desc": "Não gurda o endereço de IP completo do cliente em registo ou estatísticas",
|
||||
"dns_config": "Definição do servidor DNS",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Limite de taxa",
|
||||
"edns_enable": "Ativar a sub-rede do cliente EDNS",
|
||||
"edns_cs_desc": "Adicione a opção de sub-rede de cliente EDNS (ECS) às solicitações de servidor DNS primário e registre os valores enviados pelos clientes no registo de consulta.",
|
||||
"edns_use_custom_ip": "Usar IP personalizado para EDNS",
|
||||
"edns_use_custom_ip_desc": "Permitir a utilização de IP personalizado para EDNS",
|
||||
"rate_limit_desc": "O número de solicitações por segundo permitido por cliente. Configurando para 0 significa sem limite.",
|
||||
"blocking_ipv4_desc": "Endereço IP a ser devolvido para uma solicitação A bloqueada",
|
||||
"blocking_ipv6_desc": "Endereço IP a ser devolvido para uma solicitação AAAA bloqueada",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Tem a certeza que quer alterar a retenção de estatísticas? Se diminuir o valor do intervalo, alguns dados serão perdidos",
|
||||
"statistics_cleared": "As estatísticas foram apagadas com sucesso",
|
||||
"statistics_enable": "Ativar estatísticas",
|
||||
"ignore_domains": "Domínios ignorados (separados por nova linha)",
|
||||
"ignore_domains_title": "Domínios ignorados",
|
||||
"ignore_domains_desc_stats": "As consultas para estes domínios não aparecem nas estatísticas",
|
||||
"ignore_domains_desc_query": "As consultas para estes domínios não aparecem no registo de consultas",
|
||||
"interval_hours": "{{count}} hora",
|
||||
"interval_hours_plural": "{{count}} horas",
|
||||
"filters_configuration": "Definição dos filtros",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Observação:</0> A anonimização de IP está ativada. Você pode desativá-la em <1>Definições gerais</1>.",
|
||||
"confirm_dns_cache_clear": "Tem certeza de que quer limpar a cache DNS?",
|
||||
"cache_cleared": "O cache DNS foi apagado com sucesso",
|
||||
"clear_cache": "Limpar cache"
|
||||
"clear_cache": "Limpar cache",
|
||||
"make_static": "Tornar estático",
|
||||
"theme_auto_desc": "Automático (com base no esquema de cores do seu dispositivo)",
|
||||
"theme_dark_desc": "Tema escuro",
|
||||
"theme_light_desc": "Tema claro",
|
||||
"disable_for_seconds": "Por {{count}} segundo",
|
||||
"disable_for_seconds_plural": "Por {{count}} segundos",
|
||||
"disable_for_minutes": "Por {{count}} minuto",
|
||||
"disable_for_minutes_plural": "Por {{count}} minutos",
|
||||
"disable_for_hours": "Por {{count}} hora",
|
||||
"disable_for_hours_plural": "Por {{count}} horas",
|
||||
"disable_until_tomorrow": "Até amanhã",
|
||||
"disable_notify_for_seconds": "Desativar proteção por {{count}} segundo",
|
||||
"disable_notify_for_seconds_plural": "Desativar proteção por {{count}} segundos",
|
||||
"disable_notify_for_minutes": "Desativar proteção por {{count}} minuto",
|
||||
"disable_notify_for_minutes_plural": "Desativar proteção por {{count}} minutos",
|
||||
"disable_notify_for_hours": "Desativar proteção por {{count}} hora",
|
||||
"disable_notify_for_hours_plural": "Desativar proteção por {{count}} horas",
|
||||
"disable_notify_until_tomorrow": "Desativar a proteção até amanhã",
|
||||
"enable_protection_timer": "A proteção será habilitada em {{time}}",
|
||||
"custom_retention_input": "Insira a retenção em horas",
|
||||
"custom_rotation_input": "Insira a rotação em horas",
|
||||
"protection_section_label": "Proteção",
|
||||
"log_and_stats_section_label": "Log de consulta e estatísticas",
|
||||
"ignore_query_log": "Ignorar este cliente no log de consulta",
|
||||
"ignore_statistics": "Ignorar este cliente nas estatísticas"
|
||||
}
|
||||
|
||||
@@ -642,5 +642,6 @@
|
||||
"anonymizer_notification": "<0>Nota:</0> Anonimizarea IP este activată. Puteți să o dezactivați în <1>Setări generale</1>.",
|
||||
"confirm_dns_cache_clear": "Sunteți sigur că doriți să ștergeți memoria cache DNS?",
|
||||
"cache_cleared": "Cache-ul DNS a fost golit cu succes",
|
||||
"clear_cache": "Goliți memoria cache"
|
||||
"clear_cache": "Goliți memoria cache",
|
||||
"protection_section_label": "Protecție"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Родительский контроль вкл.",
|
||||
"disabled_safe_search_toast": "Безопасный поиск выкл.",
|
||||
"enabled_save_search_toast": "Безопасный поиск вкл.",
|
||||
"updated_save_search_toast": "Настройки безопасного поиска обновлены",
|
||||
"enabled_table_header": "Вкл.",
|
||||
"name_table_header": "Имя",
|
||||
"list_url_table_header": "URL-адрес списка",
|
||||
@@ -256,12 +257,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-сервера",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Rate limit",
|
||||
"edns_enable": "Включить отправку EDNS Client Subnet",
|
||||
"edns_cs_desc": "Добавлять опцию EDNS Client Subnet (ECS) к запросам к upstream-серверам, а также записывать присланные клиентами значения в журнал.",
|
||||
"edns_use_custom_ip": "Использовать указанный IP для EDNS",
|
||||
"edns_use_custom_ip_desc": "Разрешить использовать собственный IP для EDNS",
|
||||
"rate_limit_desc": "Ограничение на количество запросов в секунду для каждого клиента (0 — неограниченно).",
|
||||
"blocking_ipv4_desc": "IP-адрес, возвращаемый при блокировке A-запроса",
|
||||
"blocking_ipv6_desc": "IP-адрес, возвращаемый при блокировке AAAA-запроса",
|
||||
@@ -523,6 +526,10 @@
|
||||
"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": "Настройка фильтров",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Внимание:</0> включена анонимизация IP-адресов. Вы можете отключить её в разделе <1>Основные настройки</1>.",
|
||||
"confirm_dns_cache_clear": "Вы уверены, что хотите очистить кеш DNS?",
|
||||
"cache_cleared": "Кеш DNS успешно очищен",
|
||||
"clear_cache": "Очистить кеш"
|
||||
"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": "Введите частоту ротации в часах",
|
||||
"protection_section_label": "Защита",
|
||||
"log_and_stats_section_label": "Журнал запросов и статистика",
|
||||
"ignore_query_log": "Игнорировать этого клиента в журнале запросов",
|
||||
"ignore_statistics": "Игнорировать этого клиента в статистике"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Zapnutá Rodičovská kontrola",
|
||||
"disabled_safe_search_toast": "Vypnuté Bezpečné vyhľadávanie",
|
||||
"enabled_save_search_toast": "Zapnuté Bezpečné vyhľadávanie",
|
||||
"updated_save_search_toast": "Nastavenia Bezpečného vyhľadávania boli aktualizované",
|
||||
"enabled_table_header": "Zapnuté",
|
||||
"name_table_header": "Meno",
|
||||
"list_url_table_header": "Zoznam URL adries",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Denník dopytov bol úspešne vymazaný",
|
||||
"query_log_updated": "Denník dopytov bol úspešne aktualizovaný",
|
||||
"query_log_clear": "Vymazať denníky dopytov",
|
||||
"query_log_retention": "Obdobie záznamu denníka dopytov",
|
||||
"query_log_retention": "Rotácia denníkov dopytov",
|
||||
"query_log_enable": "Zapnúť denník",
|
||||
"query_log_configuration": "Konfigurácia denníka",
|
||||
"query_log_disabled": "Protokol dopytov je vypnutý a možno ho nakonfigurovať v <0>nastaveniach</0>",
|
||||
"query_log_strict_search": "Na prísne vyhľadávanie použite dvojité úvodzovky",
|
||||
"query_log_retention_confirm": "Naozaj chcete zmeniť uchovávanie denníku dopytov? Ak znížite hodnotu intervalu, niektoré údaje sa stratia",
|
||||
"query_log_retention_confirm": "Naozaj chcete zmeniť rotáciu denníka dopytov? Ak znížite hodnotu intervalu, niektoré údaje sa stratia",
|
||||
"anonymize_client_ip": "Anonymizujte IP klienta",
|
||||
"anonymize_client_ip_desc": "Neukladať úplnú IP adresu klienta do protokolov a štatistík",
|
||||
"dns_config": "Konfigurácia DNS servera",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Rýchlostný limit",
|
||||
"edns_enable": "Povoliť klientsku podsiete EDNS",
|
||||
"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.",
|
||||
"blocking_ipv4_desc": "IP adresa, ktorá sa má vrátiť v prípade blokovanej žiadosti A",
|
||||
"blocking_ipv6_desc": "IP adresa, ktorá sa má vrátiť v prípade blokovanej žiadosti AAAA",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Naozaj chcete zmeniť uchovávanie štatistík? Ak znížite hodnotu intervalu, niektoré údaje sa stratia",
|
||||
"statistics_cleared": "Štatistika bola úspešne vynulovaná",
|
||||
"statistics_enable": "Zapnúť štatistiku",
|
||||
"ignore_domains": "Ignorované domény (oddelené novým riadkom)",
|
||||
"ignore_domains_title": "Ignorované domény",
|
||||
"ignore_domains_desc_stats": "Dopyty pre tieto domény sa nezapisujú do štatistík",
|
||||
"ignore_domains_desc_query": "Dopyty pre tieto domény sa nezapisujú do denníka dopytov",
|
||||
"interval_hours": "{{count}} hodina",
|
||||
"interval_hours_plural": "{{count}} hodín",
|
||||
"filters_configuration": "Konfigurácia filtrov",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Poznámka:</0> Anonymizácia IP je zapnutá. Môžete ju vypnúť vo <1>Všeobecných nastaveniach</1>.",
|
||||
"confirm_dns_cache_clear": "Naozaj chcete vymazať vyrovnávaciu pamäť DNS?",
|
||||
"cache_cleared": "Vyrovnávacia pamäť DNS bola úspešne vymazaná",
|
||||
"clear_cache": "Vymazať vyrovnávaciu pamäť"
|
||||
"clear_cache": "Vymazať vyrovnávaciu pamäť",
|
||||
"make_static": "Vytvárať štatistiku",
|
||||
"theme_auto_desc": "Automaticky (na základe farebnej schémy Vášho zariadenia)",
|
||||
"theme_dark_desc": "Tmavá téma",
|
||||
"theme_light_desc": "Svetlá téma",
|
||||
"disable_for_seconds": "Na {{count}} sekundu",
|
||||
"disable_for_seconds_plural": "Na {{count}} sekúnd",
|
||||
"disable_for_minutes": "Na {{count}} minútu",
|
||||
"disable_for_minutes_plural": "Na {{count}} minút",
|
||||
"disable_for_hours": "Na {{count}} hodinu",
|
||||
"disable_for_hours_plural": "Na {{count}} hodín",
|
||||
"disable_until_tomorrow": "Do zajtra",
|
||||
"disable_notify_for_seconds": "Vypnite ochranu na {{count}} sekundu",
|
||||
"disable_notify_for_seconds_plural": "Vypnite ochranu na {{count}} sekúnd",
|
||||
"disable_notify_for_minutes": "Vypnite ochranu na {{count}} minútu",
|
||||
"disable_notify_for_minutes_plural": "Vypnite ochranu na {{count}} minút",
|
||||
"disable_notify_for_hours": "Vypnite ochranu na {{count}} hodinu",
|
||||
"disable_notify_for_hours_plural": "Vypnite ochranu na {{count}} hodín",
|
||||
"disable_notify_until_tomorrow": "Vypnúť ochranu do zajtra",
|
||||
"enable_protection_timer": "Ochrana bude zapnutá o {{time}}",
|
||||
"custom_retention_input": "Zadajte retenciu v hodinách",
|
||||
"custom_rotation_input": "Zadajte rotáciu v hodinách",
|
||||
"protection_section_label": "Ochrana",
|
||||
"log_and_stats_section_label": "Protokol dopytov a štatistiky",
|
||||
"ignore_query_log": "Ignorovať tohto klienta v denníku dopytov",
|
||||
"ignore_statistics": "Ignorovanie tohto klienta v štatistikách"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Omogočen starševski nadzor",
|
||||
"disabled_safe_search_toast": "Onemogočeno Varno iskanje",
|
||||
"enabled_save_search_toast": "Omogočeno Varno iskanje",
|
||||
"updated_save_search_toast": "Nastavitve varnega iskanja so posodobljene",
|
||||
"enabled_table_header": "Omogočeno",
|
||||
"name_table_header": "Ime",
|
||||
"list_url_table_header": "Seznam URL naslovov",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Dnevnik poizvedb je uspešno izbrisan",
|
||||
"query_log_updated": "Dnevnik poizvedb je bil uspešno posodobljen",
|
||||
"query_log_clear": "Počisti dnevnike poizvedb",
|
||||
"query_log_retention": "Zadrževanje dnevnikov poizvedb",
|
||||
"query_log_retention": "Rotacija dnevnikov poizvedb",
|
||||
"query_log_enable": "Omogoči dnevni",
|
||||
"query_log_configuration": "Konfiguracija dnevnikov",
|
||||
"query_log_disabled": "Dnevnik poizvedb je onemogočen in ga je mogoče konfigurirati v <0>nastavitvah</0>",
|
||||
"query_log_strict_search": "Za strogo iskanje uporabite dvojne narekovaje",
|
||||
"query_log_retention_confirm": "Ali ste prepričani, da želite spremeniti zadrževanje dnevnika poizvedb? Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni",
|
||||
"query_log_retention_confirm": "Ali ste prepričani, da želite spremeniti rotacijo dnevnika poizvedb? Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni",
|
||||
"anonymize_client_ip": "Anonimiziraj odjemalca IP",
|
||||
"anonymize_client_ip_desc": "Ne shrani celotnega naslova IP odjemalca v dnevnikih ali statistiki",
|
||||
"dns_config": "Konfiguracija strežnika DNS",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Omejitev hitrosti",
|
||||
"edns_enable": "Omogoči odjemalsko podomrežje EDNS",
|
||||
"edns_cs_desc": "Dodaj možnost podomrežja odjemalca EDNS (ECS) zahtevam v gorvodnem toku in zabeleži vrednosti, ki jih pošljejo odjemalci, v dnevnik poizvedb.",
|
||||
"edns_use_custom_ip": "Uporabi IP po meri za EDNS",
|
||||
"edns_use_custom_ip_desc": "Dovoli uporabo naslova IP po meri za EDNS",
|
||||
"rate_limit_desc": "Dovoljeno število zahtev na sekundo na odjemalca. Nastavitev na 0 pomeni brez omejitve.",
|
||||
"blocking_ipv4_desc": "IP naslov, ki mora biti vrnjen za onemogočeno zahtevo A",
|
||||
"blocking_ipv6_desc": "IP naslov, ki mora biti vrnjen za onemogočeno zahtevo AAAA",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "Ali ste prepričani, da želite spremeniti zadrževanje statistike? Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni",
|
||||
"statistics_cleared": "Statistika je bila uspešno počiščena",
|
||||
"statistics_enable": "Omogoči statistiko",
|
||||
"ignore_domains": "Prezrte domene (ločene z novo vrstico)",
|
||||
"ignore_domains_title": "Prezrte domene",
|
||||
"ignore_domains_desc_stats": "Poizvedbe za te domene niso zapisane v statistiko",
|
||||
"ignore_domains_desc_query": "Poizvedbe za te domene niso zapisane v dnevnik poizvedb",
|
||||
"interval_hours": "{{count}} ur",
|
||||
"interval_hours_plural": "{{count}} ur",
|
||||
"filters_configuration": "Nastavitve filtrov",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Opomba:</0> Anonimizacija IP je omogočena. Onemogočite ga lahko v <1>Splošnih nastavitvah</1>.",
|
||||
"confirm_dns_cache_clear": "Ali ste prepričani, da želite počistiti predpomnilnik DNS?",
|
||||
"cache_cleared": "Predpomnilnik DNS je bil uspešno počiščen",
|
||||
"clear_cache": "Počisti predpomnilnik"
|
||||
"clear_cache": "Počisti predpomnilnik",
|
||||
"make_static": "Naredi statično",
|
||||
"theme_auto_desc": "Samodejno (glede na barvno shemo vaše naprave)",
|
||||
"theme_dark_desc": "Temna tema",
|
||||
"theme_light_desc": "Svetla tema",
|
||||
"disable_for_seconds": "Za {{count}} sekundo",
|
||||
"disable_for_seconds_plural": "Za {{count}} sekund",
|
||||
"disable_for_minutes": "Za {{count}} minuto",
|
||||
"disable_for_minutes_plural": "Za {{count}} minut",
|
||||
"disable_for_hours": "Za {{count}} uro",
|
||||
"disable_for_hours_plural": "Za {{count}} ur",
|
||||
"disable_until_tomorrow": "Do jutri",
|
||||
"disable_notify_for_seconds": "Onemogoči zaščito za {{count}} sekundo",
|
||||
"disable_notify_for_seconds_plural": "Onemogoči zaščito za {{count}} sekund",
|
||||
"disable_notify_for_minutes": "Onemogoči zaščito za {{count}} minuto",
|
||||
"disable_notify_for_minutes_plural": "Onemogoči zaščito za {{count}} minut",
|
||||
"disable_notify_for_hours": "Onemogoči zaščito za {{count}} uro",
|
||||
"disable_notify_for_hours_plural": "Onemogoči zaščito za {{count}} ur",
|
||||
"disable_notify_until_tomorrow": "Onemogoči zaščito do jutri",
|
||||
"enable_protection_timer": "Zaščita bo omogočena ob {{time}}",
|
||||
"custom_retention_input": "Vnesite zadrževanje v urah",
|
||||
"custom_rotation_input": "Vnesite rotacijo v urah",
|
||||
"protection_section_label": "Zaščita",
|
||||
"log_and_stats_section_label": "Dnevnik poizvedb in statistika",
|
||||
"ignore_query_log": "Ignorirajte tega odjemalca v dnevniku poizvedb",
|
||||
"ignore_statistics": "Ignoriranje tega odjemalca v statistiki"
|
||||
}
|
||||
|
||||
@@ -642,5 +642,6 @@
|
||||
"anonymizer_notification": "<0>Nota:</0> IP prepoznavanje je omogućeno. Možete ga onemogućiti u opštim <1>postavkama</1>.",
|
||||
"confirm_dns_cache_clear": "Želite li zaista da obrišite DNS keš?",
|
||||
"cache_cleared": "DNS keš je uspešno očišćen",
|
||||
"clear_cache": "Obriši keš memoriju"
|
||||
"clear_cache": "Obriši keš memoriju",
|
||||
"protection_section_label": "Zaštita"
|
||||
}
|
||||
|
||||
@@ -523,6 +523,7 @@
|
||||
"statistics_retention_confirm": "Är du säker på att du vill ändra retentionstiden för statistik? Om du minskar intervallet kommer viss data att gå förlorad",
|
||||
"statistics_cleared": "Statistiken har rensats",
|
||||
"statistics_enable": "Aktivera statistik",
|
||||
"ignore_domains_title": "Ignorerade domäner",
|
||||
"interval_hours": "{{count}} timme",
|
||||
"interval_hours_plural": "{{count}} timmar",
|
||||
"filters_configuration": "Filterinställningar",
|
||||
@@ -642,5 +643,14 @@
|
||||
"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?",
|
||||
"cache_cleared": "DNS-cacheminnet har rensats",
|
||||
"clear_cache": "Rensa cache"
|
||||
"clear_cache": "Rensa cache",
|
||||
"theme_dark_desc": "Mörkt tema",
|
||||
"theme_light_desc": "Ljust tema",
|
||||
"disable_for_seconds": "I {{count}} sekund",
|
||||
"disable_for_seconds_plural": "I {{count}} sekunder",
|
||||
"disable_for_minutes": "I {{count}} minut",
|
||||
"disable_for_minutes_plural": "I {{count}} minuter",
|
||||
"disable_for_hours": "I {{count}} timme",
|
||||
"disable_for_hours_plural": "I {{count}} timmar",
|
||||
"disable_until_tomorrow": "Tills imorgon"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Ebeveyn Denetimi etkinleştirildi",
|
||||
"disabled_safe_search_toast": "Güvenli Arama devre dışı bırakıldı",
|
||||
"enabled_save_search_toast": "Güvenli Arama etkinleştirildi",
|
||||
"updated_save_search_toast": "Güvenli Arama ayarları güncellendi",
|
||||
"enabled_table_header": "Etkin",
|
||||
"name_table_header": "Ad",
|
||||
"list_url_table_header": "Liste URL'si",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Sorgu günlüğü başarıyla temizlendi",
|
||||
"query_log_updated": "Sorgu günlüğü başarıyla güncellendi",
|
||||
"query_log_clear": "Sorgu günlüklerini temizle",
|
||||
"query_log_retention": "Sorgu günlüklerini sakla",
|
||||
"query_log_retention": "Sorgu günlükleri rotasyonu",
|
||||
"query_log_enable": "Günlüğü etkinleştir",
|
||||
"query_log_configuration": "Günlük yapılandırması",
|
||||
"query_log_disabled": "Sorgu günlüğü devre dışı bırakıldı, bunu <0>ayarlar</0> kısmından yapılandırılabilirsiniz",
|
||||
"query_log_strict_search": "Tam arama için çift tırnak işareti kullanın",
|
||||
"query_log_retention_confirm": "Sorgu günlüğü saklama süresini değiştirmek istediğinize emin misiniz? Aralık değerini azaltırsanız, bazı veriler kaybolacaktır",
|
||||
"query_log_retention_confirm": "Sorgu günlüğü rotasyonunu değiştirmek istediğinizden emin misiniz? Aralık değerini düşürürseniz, bazı veriler kaybolacaktır.",
|
||||
"anonymize_client_ip": "İstemcinin IP adresini gizle",
|
||||
"anonymize_client_ip_desc": "İstemcinin tam IP adresini günlüklere veya istatistiklere kaydetmeyin",
|
||||
"dns_config": "DNS sunucu yapılandırması",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Sıklık limiti",
|
||||
"edns_enable": "EDNS istemci alt ağını etkinleştir",
|
||||
"edns_cs_desc": "Kaynak yönü isteklerine EDNS İstemci Alt Ağı seçeneğini (ECS) ekleyin ve istemciler tarafından gönderilen değerleri sorgu günlüğüne kaydedin.",
|
||||
"edns_use_custom_ip": "EDNS için özel IP kullan",
|
||||
"edns_use_custom_ip_desc": "EDNS için özel IP kullanımına izin ver",
|
||||
"rate_limit_desc": "İstemci başına izin verilen saniyedeki istek sayısı. 0 olarak ayarlamak, sınır olmadığı anlamına gelir.",
|
||||
"blocking_ipv4_desc": "Engellenen bir A isteği için geri döndürülecek IP adresi",
|
||||
"blocking_ipv6_desc": "Engellenen bir AAAA isteği için geri döndürülecek IP adresi",
|
||||
@@ -410,7 +413,7 @@
|
||||
"fix": "Düzelt",
|
||||
"dns_providers": "Aralarından seçim yapabileceğiniz, bilinen <0>DNS sağlayıcıların listesi</0>.",
|
||||
"update_now": "Şimdi güncelle",
|
||||
"update_failed": "Otomatik güncelleme başarısız oldu. Elle güncellemek için lütfen <a>bu adımları izleyin</a>.",
|
||||
"update_failed": "Otomatik güncellenemedi. Elle güncellemek için lütfen <a>bu adımları izleyin</a>.",
|
||||
"manual_update": "Elle güncellemek için lütfen <a>bu adımları uygulayın</a>.",
|
||||
"processing_update": "Lütfen bekleyin, AdGuard Home güncelleniyor",
|
||||
"clients_title": "Kalıcı istemciler",
|
||||
@@ -449,7 +452,7 @@
|
||||
"access_disallowed_title": "İzin verilmeyen istemciler",
|
||||
"access_disallowed_desc": "CIDR'lerin, IP adreslerinin veya <a>İstemci Kimliklerin</a> listesi. Bu listede girişler varsa, AdGuard Home bu istemcilerden gelen istekleri keser. İzin verilen istemcilerde girişler varsa, bu alan yok sayılır.",
|
||||
"access_blocked_title": "İzin verilmeyen alan adları",
|
||||
"access_blocked_desc": "Bu işlem filtrelerle ilgili değildir. AdGuard Home, bu alan adlarından gelen DNS sorgularını yanıtsız bırakır ve bu sorgular sorgu günlüğünde görünmez. Tam alan adlarını, joker karakterleri veya URL filtre kurallarını belirtebilirsiniz, ör. \"example.org\", \"*.example.org\" veya \"||example.org^\".",
|
||||
"access_blocked_desc": "Bu işlem filtrelerle ilgili değildir. AdGuard Home, bu alan adlarından gelen DNS sorgularını yanıtsız bırakır ve bu sorgular sorgu günlüğünde görünmez. Tam alan adlarını, joker karakterleri veya URL filtre kurallarını belirtebilirsiniz, örn. \"example.org\", \"*.example.org\" veya \"||example.org^\".",
|
||||
"access_settings_saved": "Erişim ayarları başarıyla kaydedildi!",
|
||||
"updates_checked": "AdGuard Home'un yeni bir sürümü mevcut",
|
||||
"updates_version_equal": "AdGuard Home yazılımı güncel durumda",
|
||||
@@ -523,6 +526,10 @@
|
||||
"statistics_retention_confirm": "İstatistik saklama süresini değiştirmek istediğinizden emin misiniz? Aralık değerini azaltırsanız, bazı veriler kaybolacaktır",
|
||||
"statistics_cleared": "İstatistikler başarıyla temizlendi",
|
||||
"statistics_enable": "İstatistikleri etkinleştir",
|
||||
"ignore_domains": "Yok sayılan alan adları (yeni satırla ayrılmış)",
|
||||
"ignore_domains_title": "Yok sayılan alan adları",
|
||||
"ignore_domains_desc_stats": "Bu alan adları için yapılan sorgular istatistiklere yazılmaz",
|
||||
"ignore_domains_desc_query": "Bu alan adları için yapılan sorgular sorgu günlüğüne yazılmaz",
|
||||
"interval_hours": "{{count}} saat",
|
||||
"interval_hours_plural": "{{count}} saat",
|
||||
"filters_configuration": "Filtre yapılandırması",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Not:</0> IP anonimleştirme etkinleştirildi. Bunu <1>Genel ayarlardan</1> devre dışı bırakabilirsiniz.",
|
||||
"confirm_dns_cache_clear": "DNS önbelleğini temizlemek istediğinizden emin misiniz?",
|
||||
"cache_cleared": "DNS önbelleği başarıyla temizlendi",
|
||||
"clear_cache": "Önbelleği temizle"
|
||||
"clear_cache": "Önbelleği temizle",
|
||||
"make_static": "Statik yap",
|
||||
"theme_auto_desc": "Otomatik (cihazınızın renk düzenine göre)",
|
||||
"theme_dark_desc": "Koyu tema",
|
||||
"theme_light_desc": "Açık tema",
|
||||
"disable_for_seconds": "{{count}} saniye için",
|
||||
"disable_for_seconds_plural": "{{count}} saniye için",
|
||||
"disable_for_minutes": "{{count}} dakika için",
|
||||
"disable_for_minutes_plural": "{{count}} dakika için",
|
||||
"disable_for_hours": "{{count}} saat için",
|
||||
"disable_for_hours_plural": "{{count}} saat için",
|
||||
"disable_until_tomorrow": "Yarına kadar",
|
||||
"disable_notify_for_seconds": "Korumayı {{count}} saniyeliğine devre dışı bırak",
|
||||
"disable_notify_for_seconds_plural": "Korumayı {{count}} saniyeliğine devre dışı bırak",
|
||||
"disable_notify_for_minutes": "Korumayı {{count}} dakiklığına devre dışı bırak",
|
||||
"disable_notify_for_minutes_plural": "Korumayı {{count}} dakiklığına devre dışı bırak",
|
||||
"disable_notify_for_hours": "Korumayı {{count}} saatliğine devre dışı bırak",
|
||||
"disable_notify_for_hours_plural": "Korumayı {{count}} saatliğine devre dışı bırak",
|
||||
"disable_notify_until_tomorrow": "Korumayı yarına kadar devre dışı bırak",
|
||||
"enable_protection_timer": "Koruma {{time}} içinde etkinleştirilecektir",
|
||||
"custom_retention_input": "Saklama süresini saat olarak girin",
|
||||
"custom_rotation_input": "Rotasyonu saat cinsinden girin",
|
||||
"protection_section_label": "Koruma",
|
||||
"log_and_stats_section_label": "Sorgu günlüğü ve istatistikler",
|
||||
"ignore_query_log": "Sorgu günlüğünde bu istemciyi yoksay",
|
||||
"ignore_statistics": "İstatistiklerde bu istemciyi yoksay"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "«Батьківський контроль» увімкнено",
|
||||
"disabled_safe_search_toast": "Безпечний пошук вимкнено",
|
||||
"enabled_save_search_toast": "Безпечний пошук увімкнено",
|
||||
"updated_save_search_toast": "Налаштування Безпечного пошуку оновлено",
|
||||
"enabled_table_header": "Увімкнено",
|
||||
"name_table_header": "Назва",
|
||||
"list_url_table_header": "URL списку",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Обмеження швидкості",
|
||||
"edns_enable": "Увімкнути відправку EDNS Client Subnet",
|
||||
"edns_cs_desc": "Додавати параметр EDNS Client Subnet (ECS) до запитів до upstream-серверів, а також записувати в журнал значення, що надсилаються клієнтами.",
|
||||
"edns_use_custom_ip": "Використання користувацької IP-адреси для EDNS",
|
||||
"edns_use_custom_ip_desc": "Дозволити використовувати користувацьку IP-адресу для EDNS",
|
||||
"rate_limit_desc": "Кількість запитів в секунду, які може робити один клієнт. Встановлене значення «0» означатиме необмежену кількість.",
|
||||
"blocking_ipv4_desc": "IP-адреса, яку потрібно видати для заблокованого A запиту",
|
||||
"blocking_ipv6_desc": "IP-адреса, яку потрібно видати для заблокованого АААА запиту",
|
||||
@@ -523,6 +526,10 @@
|
||||
"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": "Конфігурація фільтрів",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>Примітка:</0> IP-анонімізацію ввімкнено. Ви можете вимкнути його в <1>Загальні налаштування</1> .",
|
||||
"confirm_dns_cache_clear": "Ви впевнені, що бажаєте очистити кеш DNS?",
|
||||
"cache_cleared": "Кеш DNS успішно очищено",
|
||||
"clear_cache": "Очистити кеш"
|
||||
"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": "Введіть час в годинах",
|
||||
"protection_section_label": "Захист",
|
||||
"log_and_stats_section_label": "Журнал запитів і статистика",
|
||||
"ignore_query_log": "Ігнорувати цей клієнт у журналі запитів",
|
||||
"ignore_statistics": "Ігноруйте цей клієнт в статистиці"
|
||||
}
|
||||
|
||||
@@ -642,5 +642,6 @@
|
||||
"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?",
|
||||
"cache_cleared": "Đã xóa thành công bộ đệm DNS",
|
||||
"clear_cache": "Xóa bộ nhớ cache"
|
||||
"clear_cache": "Xóa bộ nhớ cache",
|
||||
"protection_section_label": "Sự bảo vệ"
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"resolve_clients_title": "启用客户端的 IP 地址的反向解析",
|
||||
"resolve_clients_desc": "通过发送 PTR 查询到对应的解析器 (本地客户端的私人 DNS 服务器,公共 IP 客户端的上游服务器) 将 IP 地址反向解析成其客户端主机名。",
|
||||
"use_private_ptr_resolvers_title": "使用私人反向 DNS 解析器",
|
||||
"use_private_ptr_resolvers_desc": "使用这些上游服务器对本地服务的地址执行反向 DNS 查找。 如果禁用,则 AdGuard Home会以 NXDOMAIN 响应所有此类PTR请求,从 DHCP、/ etc / hosts 等获知的客户端除外。",
|
||||
"use_private_ptr_resolvers_desc": "使用这些上游服务器对本地服务的地址执行反向 DNS 查找。 如果禁用,则 AdGuard Home 会以 NXDOMAIN 响应所有此类 PTR 请求,从 DHCP、/etc/hosts 等获知的客户端除外。",
|
||||
"check_dhcp_servers": "检查 DHCP 服务器",
|
||||
"save_config": "保存配置",
|
||||
"enabled_dhcp": "DHCP 服务器已启用",
|
||||
@@ -128,7 +128,7 @@
|
||||
"number_of_dns_query_days": "过去 {{count}} 天内处理的 DNS 查询总数",
|
||||
"number_of_dns_query_days_plural": "在过去的 {{count}} 天内处理了多少个 DNS 查询",
|
||||
"number_of_dns_query_24_hours": "过去 24 小时内处理的 DNS 请求总数",
|
||||
"number_of_dns_query_blocked_24_hours": "被广告过滤器和 Hosts 拦截清单阻止的 DNS 请求总数",
|
||||
"number_of_dns_query_blocked_24_hours": "被广告过滤器和 Hosts 黑名单阻止的 DNS 请求总数",
|
||||
"number_of_dns_query_blocked_24_hours_by_sec": "被 AdGuard 安全浏览模块阻止的 DNS 请求总数",
|
||||
"number_of_dns_query_blocked_24_hours_adult": "被阻止的成人网站总数",
|
||||
"enforced_save_search": "强制安全搜索",
|
||||
@@ -146,10 +146,10 @@
|
||||
"no_servers_specified": "未找到指定的服务器",
|
||||
"general_settings": "常规设置",
|
||||
"dns_settings": "DNS 设置",
|
||||
"dns_blocklists": "DNS 拦截列表",
|
||||
"dns_allowlists": "DNS 允许列表",
|
||||
"dns_blocklists": "DNS 黑名单",
|
||||
"dns_allowlists": "DNS 白名单",
|
||||
"dns_blocklists_desc": "AdGuard Home将阻止匹配DNS拦截清单的域名",
|
||||
"dns_allowlists_desc": "来自DNS允许列表的域将被允许,即使它们位于任意阻止列表中也是如此",
|
||||
"dns_allowlists_desc": "来自 DNS 白名单的域名将被允许,即使它们位于任意黑名单中也是如此。",
|
||||
"custom_filtering_rules": "自定义过滤规则",
|
||||
"encryption_settings": "加密设置",
|
||||
"dhcp_settings": "DHCP 设置",
|
||||
@@ -167,33 +167,34 @@
|
||||
"enabled_parental_toast": "家长控制已启用",
|
||||
"disabled_safe_search_toast": "安全搜索已禁用",
|
||||
"enabled_save_search_toast": "安全搜索已启用",
|
||||
"updated_save_search_toast": "安全搜索设置更新成功",
|
||||
"enabled_table_header": "已启用",
|
||||
"name_table_header": "名称",
|
||||
"list_url_table_header": "清单网址",
|
||||
"rules_count_table_header": "规则数",
|
||||
"last_time_updated_table_header": "上次更新时间",
|
||||
"actions_table_header": "活跃状态",
|
||||
"actions_table_header": "操作",
|
||||
"request_table_header": "请求",
|
||||
"edit_table_action": "编辑",
|
||||
"delete_table_action": "删除",
|
||||
"elapsed": "耗时",
|
||||
"filters_and_hosts_hint": "AdGuard Home 可以解析基础的 adblock 规则和 Hosts 语法。",
|
||||
"no_blocklist_added": "未添加阻止列表",
|
||||
"no_whitelist_added": "未添加允许列表",
|
||||
"add_blocklist": "添加阻止列表",
|
||||
"add_allowlist": "添加允许列表",
|
||||
"no_blocklist_added": "未添加黑名单",
|
||||
"no_whitelist_added": "未添加白名单",
|
||||
"add_blocklist": "添加黑名单",
|
||||
"add_allowlist": "添加白名单",
|
||||
"cancel_btn": "取消",
|
||||
"enter_name_hint": "输入名称",
|
||||
"enter_url_or_path_hint": "请输入URL或列表的绝对路径",
|
||||
"check_updates_btn": "检查更新",
|
||||
"new_blocklist": "新封锁清单",
|
||||
"new_allowlist": "新的允许清单",
|
||||
"edit_blocklist": "编辑阻止列表",
|
||||
"edit_allowlist": "编辑允许列表",
|
||||
"choose_blocklist": "选择拦截列表",
|
||||
"choose_allowlist": "选择允许列表",
|
||||
"enter_valid_blocklist": "输入有效的阻止列表URL",
|
||||
"enter_valid_allowlist": "输入有效的允许列表URL",
|
||||
"new_allowlist": "新增白名单",
|
||||
"edit_blocklist": "编辑黑名单",
|
||||
"edit_allowlist": "编辑白名单",
|
||||
"choose_blocklist": "选择黑名单",
|
||||
"choose_allowlist": "选择白名单",
|
||||
"enter_valid_blocklist": "输入有效的黑名单 URL",
|
||||
"enter_valid_allowlist": "输入有效的白名单 URL",
|
||||
"form_error_url_format": "无效的 URL 格式",
|
||||
"form_error_url_or_path_format": "无效的 URL 或列表的绝对路径",
|
||||
"custom_filter_rules": "自定义过滤器规则",
|
||||
@@ -256,12 +257,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 服务配置",
|
||||
@@ -269,9 +270,9 @@
|
||||
"dns_cache_config_desc": "您可以在此处配置 DNS 缓存",
|
||||
"blocking_mode": "拦截模式",
|
||||
"default": "默认",
|
||||
"nxdomain": "无效域名",
|
||||
"nxdomain": "NXDOMAIN",
|
||||
"refused": "REFUSED",
|
||||
"null_ip": "无效 IP",
|
||||
"null_ip": "空 IP",
|
||||
"custom_ip": "自定义 IP",
|
||||
"blocking_ipv4": "拦截 IPv4",
|
||||
"blocking_ipv6": "拦截 IPv6",
|
||||
@@ -290,13 +291,15 @@
|
||||
"rate_limit": "速度限制",
|
||||
"edns_enable": "启用 EDNS 客户端子网",
|
||||
"edns_cs_desc": "在上游请求中加入 EDNS 客户端子网(“EDNS Client Subnet”,即 ECS)选项,并在查询日志中记录客户端发送的数值。",
|
||||
"edns_use_custom_ip": "为 EDNS 使用自定义 IP",
|
||||
"edns_use_custom_ip_desc": "允许为 EDNS 使用自定义 IP",
|
||||
"rate_limit_desc": "每个客户端每秒钟查询次数的限制。设置为 0 意味着不限制。",
|
||||
"blocking_ipv4_desc": "拦截 A 记录请求返回的 IP 地址",
|
||||
"blocking_ipv6_desc": "拦截 AAAA 记录请求返回的 IP 地址",
|
||||
"blocking_mode_default": "默认:被 Adblock 规则拦截时反应为零 IP 地址(A记录:0.0.0.0;AAAA记录:::);被/etc/hosts 规则拦截时反应为规则中指定 IP 地址",
|
||||
"blocking_mode_refused": "REFUSED:以 REFUSED 码响应请求",
|
||||
"blocking_mode_nxdomain": "NXDOMAIN:以NXDOMAIN码响应",
|
||||
"blocking_mode_null_ip": "空IP:以零IP地址响应(A记录 0.0.0.0;AAAA记录 ::)",
|
||||
"blocking_mode_null_ip": "空 IP:以零 IP 地址响应(A 记录 0.0.0.0;AAAA 记录 ::)",
|
||||
"blocking_mode_custom_ip": "自定IP:以手动设置的IP地址响应",
|
||||
"theme_auto": "自动",
|
||||
"theme_light": "浅色主题",
|
||||
@@ -523,6 +526,10 @@
|
||||
"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": "过滤器配置",
|
||||
@@ -605,7 +612,7 @@
|
||||
"filtered": "已过滤",
|
||||
"rewritten": "重写项",
|
||||
"safe_search": "安全搜索",
|
||||
"blocklist": "拦截列表",
|
||||
"blocklist": "黑名单",
|
||||
"milliseconds_abbreviation": "毫秒",
|
||||
"cache_size": "缓存大小",
|
||||
"cache_size_desc": "DNS 缓存大小(单位:字节)。要关闭缓存,请留空。",
|
||||
@@ -626,7 +633,7 @@
|
||||
"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": "点击查看查询",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>注意:</0> IP 匿名化已启用。您可以在<1>常规设置</1>中禁用它。",
|
||||
"confirm_dns_cache_clear": "您确定要清除 DNS 缓存吗?",
|
||||
"cache_cleared": "已成功清除 DNS 缓存",
|
||||
"clear_cache": "清除缓存"
|
||||
"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": "输入旋转时间(小时)",
|
||||
"protection_section_label": "防护",
|
||||
"log_and_stats_section_label": "查询日志和统计数据",
|
||||
"ignore_query_log": "在查询日志中忽略此客户端",
|
||||
"ignore_statistics": "在统计数据中忽略此客户端"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "已啟用家長控制",
|
||||
"disabled_safe_search_toast": "已禁用安全搜尋",
|
||||
"enabled_save_search_toast": "已啟用安全搜尋",
|
||||
"updated_save_search_toast": "安全搜尋設定更新成功",
|
||||
"enabled_table_header": "已啟用",
|
||||
"name_table_header": "名稱",
|
||||
"list_url_table_header": "清單網址",
|
||||
@@ -256,12 +257,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 伺服器配置",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "速率限制",
|
||||
"edns_enable": "啟用對於 DNS 的擴充機制(EDNS)用戶端子網路",
|
||||
"edns_cs_desc": "新增對於 DNS 的擴充機制(EDNS)用戶端子網路選項到上游的請求,並在查詢記錄中記錄由用戶端傳送的數值。",
|
||||
"edns_use_custom_ip": "為 EDNS 使用自訂的 IP",
|
||||
"edns_use_custom_ip_desc": "允許為 EDNS 使用自訂的 IP",
|
||||
"rate_limit_desc": "每個用戶端被允許的每秒請求之數量。設定它為 0 表示無限制。",
|
||||
"blocking_ipv4_desc": "要被返回給已封鎖的 A 請求之 IP 位址",
|
||||
"blocking_ipv6_desc": "要被返回給已封鎖的 AAAA 請求之 IP 位址",
|
||||
@@ -523,6 +526,10 @@
|
||||
"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": "過濾器配置",
|
||||
@@ -642,5 +649,30 @@
|
||||
"anonymizer_notification": "<0>注意:</0>IP 匿名化被啟用。您可在<1>一般設定</1>中禁用它。",
|
||||
"confirm_dns_cache_clear": "您確定您想要清除 DNS 快取嗎?",
|
||||
"cache_cleared": "DNS 快取被成功地清除",
|
||||
"clear_cache": "清除快取"
|
||||
"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": "輸入旋轉時間(小時)",
|
||||
"protection_section_label": "防護",
|
||||
"log_and_stats_section_label": "查詢記錄和統計資料",
|
||||
"ignore_query_log": "在查詢記錄中忽略此用戶端",
|
||||
"ignore_statistics": "在統計資料中忽略此用戶端"
|
||||
}
|
||||
|
||||
@@ -49,6 +49,9 @@ export const setTlsConfig = (config) => async (dispatch, getState) => {
|
||||
|
||||
const dnsStatus = await apiClient.getGlobalStatus();
|
||||
if (dnsStatus) {
|
||||
if (dnsStatus.protection_disabled_duration === 0) {
|
||||
dnsStatus.protection_disabled_duration = null;
|
||||
}
|
||||
dispatch(dnsStatusSuccess(dnsStatus));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,14 @@ import endsWith from 'lodash/endsWith';
|
||||
import escapeRegExp from 'lodash/escapeRegExp';
|
||||
import React from 'react';
|
||||
import { compose } from 'redux';
|
||||
import { splitByNewLine, sortClients, filterOutComments } from '../helpers/helpers';
|
||||
import {
|
||||
splitByNewLine,
|
||||
sortClients,
|
||||
filterOutComments,
|
||||
msToSeconds,
|
||||
msToMinutes,
|
||||
msToHours,
|
||||
} from '../helpers/helpers';
|
||||
import {
|
||||
BLOCK_ACTIONS,
|
||||
CHECK_TIMEOUT,
|
||||
@@ -14,6 +21,7 @@ import {
|
||||
SETTINGS_NAMES,
|
||||
FORM_NAME,
|
||||
MANUAL_UPDATE_LINK,
|
||||
DISABLE_PROTECTION_TIMINGS,
|
||||
} from '../helpers/constants';
|
||||
import { areEqualVersions } from '../helpers/version';
|
||||
import { getTlsStatus } from './encryption';
|
||||
@@ -24,6 +32,12 @@ import { getFilteringStatus, setRules } from './filtering';
|
||||
export const toggleSettingStatus = createAction('SETTING_STATUS_TOGGLE');
|
||||
export const showSettingsFailure = createAction('SETTINGS_FAILURE_SHOW');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} settingKey = SETTINGS_NAMES
|
||||
* @param {*} status: boolean | SafeSearchConfig
|
||||
* @returns
|
||||
*/
|
||||
export const toggleSetting = (settingKey, status) => async (dispatch) => {
|
||||
let successMessage = '';
|
||||
try {
|
||||
@@ -49,14 +63,9 @@ export const toggleSetting = (settingKey, status) => async (dispatch) => {
|
||||
dispatch(toggleSettingStatus({ settingKey }));
|
||||
break;
|
||||
case SETTINGS_NAMES.safesearch:
|
||||
if (status) {
|
||||
successMessage = 'disabled_safe_search_toast';
|
||||
await apiClient.disableSafesearch();
|
||||
} else {
|
||||
successMessage = 'enabled_save_search_toast';
|
||||
await apiClient.enableSafesearch();
|
||||
}
|
||||
dispatch(toggleSettingStatus({ settingKey }));
|
||||
successMessage = 'updated_save_search_toast';
|
||||
await apiClient.updateSafesearch(status);
|
||||
dispatch(toggleSettingStatus({ settingKey, value: status }));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -71,7 +80,9 @@ 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) => async (dispatch) => {
|
||||
export const initSettings = (settingsList = {
|
||||
safebrowsing: {}, parental: {},
|
||||
}) => async (dispatch) => {
|
||||
dispatch(initSettingsRequest());
|
||||
try {
|
||||
const safebrowsingStatus = await apiClient.getSafebrowsingStatus();
|
||||
@@ -80,7 +91,6 @@ export const initSettings = (settingsList) => async (dispatch) => {
|
||||
const {
|
||||
safebrowsing,
|
||||
parental,
|
||||
safesearch,
|
||||
} = settingsList;
|
||||
const newSettingsList = {
|
||||
safebrowsing: {
|
||||
@@ -92,8 +102,7 @@ export const initSettings = (settingsList) => async (dispatch) => {
|
||||
enabled: parentalStatus.enabled,
|
||||
},
|
||||
safesearch: {
|
||||
...safesearch,
|
||||
enabled: safesearchStatus.enabled,
|
||||
...safesearchStatus,
|
||||
},
|
||||
};
|
||||
dispatch(initSettingsSuccess({ settingsList: newSettingsList }));
|
||||
@@ -107,19 +116,54 @@ export const toggleProtectionRequest = createAction('TOGGLE_PROTECTION_REQUEST')
|
||||
export const toggleProtectionFailure = createAction('TOGGLE_PROTECTION_FAILURE');
|
||||
export const toggleProtectionSuccess = createAction('TOGGLE_PROTECTION_SUCCESS');
|
||||
|
||||
export const toggleProtection = (status) => async (dispatch) => {
|
||||
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) },
|
||||
);
|
||||
case 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) },
|
||||
);
|
||||
case 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:
|
||||
return 'disabled_protection';
|
||||
}
|
||||
};
|
||||
|
||||
export const toggleProtection = (status, time = null) => async (dispatch) => {
|
||||
dispatch(toggleProtectionRequest());
|
||||
try {
|
||||
const successMessage = status ? 'disabled_protection' : 'enabled_protection';
|
||||
await apiClient.setDnsConfig({ protection_enabled: !status });
|
||||
const successMessage = status ? getDisabledMessage(time) : 'enabled_protection';
|
||||
await apiClient.setProtection({ enabled: !status, duration: time });
|
||||
dispatch(addSuccessToast(successMessage));
|
||||
dispatch(toggleProtectionSuccess());
|
||||
dispatch(toggleProtectionSuccess({ disabledDuration: time }));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(toggleProtectionFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const setDisableDurationTime = createAction('SET_DISABLED_DURATION_TIME');
|
||||
|
||||
export const setProtectionTimerTime = (updatedTime) => async (dispatch) => {
|
||||
dispatch(setDisableDurationTime({ timeToEnableProtection: updatedTime }));
|
||||
};
|
||||
|
||||
export const getVersionRequest = createAction('GET_VERSION_REQUEST');
|
||||
export const getVersionFailure = createAction('GET_VERSION_FAILURE');
|
||||
export const getVersionSuccess = createAction('GET_VERSION_SUCCESS');
|
||||
@@ -272,6 +316,9 @@ export const getDnsStatus = () => async (dispatch) => {
|
||||
|
||||
const handleRequestSuccess = (response) => {
|
||||
const dnsStatus = response.data;
|
||||
if (dnsStatus.protection_disabled_duration === 0) {
|
||||
dnsStatus.protection_disabled_duration = null;
|
||||
}
|
||||
const { running } = dnsStatus;
|
||||
const runningStatus = dnsStatus && running;
|
||||
if (runningStatus === true) {
|
||||
|
||||
@@ -177,7 +177,7 @@ export const getLogsConfigSuccess = createAction('GET_LOGS_CONFIG_SUCCESS');
|
||||
export const getLogsConfig = () => async (dispatch) => {
|
||||
dispatch(getLogsConfigRequest());
|
||||
try {
|
||||
const data = await apiClient.getQueryLogInfo();
|
||||
const data = await apiClient.getQueryLogConfig();
|
||||
dispatch(getLogsConfigSuccess(data));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
|
||||
@@ -2,21 +2,6 @@ import { createAction } from 'redux-actions';
|
||||
import apiClient from '../api/Api';
|
||||
import { addErrorToast, addSuccessToast } from './toasts';
|
||||
|
||||
export const getBlockedServicesAvailableServicesRequest = createAction('GET_BLOCKED_SERVICES_AVAILABLE_SERVICES_REQUEST');
|
||||
export const getBlockedServicesAvailableServicesFailure = createAction('GET_BLOCKED_SERVICES_AVAILABLE_SERVICES_FAILURE');
|
||||
export const getBlockedServicesAvailableServicesSuccess = createAction('GET_BLOCKED_SERVICES_AVAILABLE_SERVICES_SUCCESS');
|
||||
|
||||
export const getBlockedServicesAvailableServices = () => async (dispatch) => {
|
||||
dispatch(getBlockedServicesAvailableServicesRequest());
|
||||
try {
|
||||
const data = await apiClient.getBlockedServicesAvailableServices();
|
||||
dispatch(getBlockedServicesAvailableServicesSuccess(data));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(getBlockedServicesAvailableServicesFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const getBlockedServicesRequest = createAction('GET_BLOCKED_SERVICES_REQUEST');
|
||||
export const getBlockedServicesFailure = createAction('GET_BLOCKED_SERVICES_FAILURE');
|
||||
export const getBlockedServicesSuccess = createAction('GET_BLOCKED_SERVICES_SUCCESS');
|
||||
|
||||
@@ -13,7 +13,7 @@ export const getStatsConfigSuccess = createAction('GET_STATS_CONFIG_SUCCESS');
|
||||
export const getStatsConfig = () => async (dispatch) => {
|
||||
dispatch(getStatsConfigRequest());
|
||||
try {
|
||||
const data = await apiClient.getStatsInfo();
|
||||
const data = await apiClient.getStatsConfig();
|
||||
dispatch(getStatsConfigSuccess(data));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
|
||||
@@ -208,24 +208,40 @@ class Api {
|
||||
// Safesearch
|
||||
SAFESEARCH_STATUS = { path: 'safesearch/status', method: 'GET' };
|
||||
|
||||
SAFESEARCH_ENABLE = { path: 'safesearch/enable', method: 'POST' };
|
||||
|
||||
SAFESEARCH_DISABLE = { path: 'safesearch/disable', method: 'POST' };
|
||||
SAFESEARCH_UPDATE = { path: 'safesearch/settings', method: 'PUT' };
|
||||
|
||||
getSafesearchStatus() {
|
||||
const { path, method } = this.SAFESEARCH_STATUS;
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
enableSafesearch() {
|
||||
const { path, method } = this.SAFESEARCH_ENABLE;
|
||||
return this.makeRequest(path, method);
|
||||
/**
|
||||
* interface SafeSearchConfig {
|
||||
"enabled": boolean,
|
||||
"bing": boolean,
|
||||
"duckduckgo": boolean,
|
||||
"google": boolean,
|
||||
"pixabay": boolean,
|
||||
"yandex": boolean,
|
||||
"youtube": boolean
|
||||
* }
|
||||
* @param {*} data - SafeSearchConfig
|
||||
* @returns 200 ok
|
||||
*/
|
||||
updateSafesearch(data) {
|
||||
const { path, method } = this.SAFESEARCH_UPDATE;
|
||||
return this.makeRequest(path, method, { data });
|
||||
}
|
||||
|
||||
disableSafesearch() {
|
||||
const { path, method } = this.SAFESEARCH_DISABLE;
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
// enableSafesearch() {
|
||||
// const { path, method } = this.SAFESEARCH_ENABLE;
|
||||
// return this.makeRequest(path, method);
|
||||
// }
|
||||
|
||||
// disableSafesearch() {
|
||||
// const { path, method } = this.SAFESEARCH_DISABLE;
|
||||
// return this.makeRequest(path, method);
|
||||
// }
|
||||
|
||||
// Language
|
||||
|
||||
@@ -463,19 +479,12 @@ class Api {
|
||||
}
|
||||
|
||||
// Blocked services
|
||||
BLOCKED_SERVICES_SERVICES = { path: 'blocked_services/services', method: 'GET' };
|
||||
|
||||
BLOCKED_SERVICES_LIST = { path: 'blocked_services/list', method: 'GET' };
|
||||
|
||||
BLOCKED_SERVICES_SET = { path: 'blocked_services/set', method: 'POST' };
|
||||
|
||||
BLOCKED_SERVICES_ALL = { path: 'blocked_services/all', method: 'GET' };
|
||||
|
||||
getBlockedServicesAvailableServices() {
|
||||
const { path, method } = this.BLOCKED_SERVICES_SERVICES;
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
getAllBlockedServices() {
|
||||
const { path, method } = this.BLOCKED_SERVICES_ALL;
|
||||
return this.makeRequest(path, method);
|
||||
@@ -497,9 +506,9 @@ class Api {
|
||||
// Settings for statistics
|
||||
GET_STATS = { path: 'stats', method: 'GET' };
|
||||
|
||||
STATS_INFO = { path: 'stats_info', method: 'GET' };
|
||||
GET_STATS_CONFIG = { path: 'stats/config', method: 'GET' };
|
||||
|
||||
STATS_CONFIG = { path: 'stats_config', method: 'POST' };
|
||||
UPDATE_STATS_CONFIG = { path: 'stats/config/update', method: 'PUT' };
|
||||
|
||||
STATS_RESET = { path: 'stats_reset', method: 'POST' };
|
||||
|
||||
@@ -508,13 +517,13 @@ class Api {
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
getStatsInfo() {
|
||||
const { path, method } = this.STATS_INFO;
|
||||
getStatsConfig() {
|
||||
const { path, method } = this.GET_STATS_CONFIG;
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setStatsConfig(data) {
|
||||
const { path, method } = this.STATS_CONFIG;
|
||||
const { path, method } = this.UPDATE_STATS_CONFIG;
|
||||
const config = {
|
||||
data,
|
||||
};
|
||||
@@ -529,9 +538,9 @@ class Api {
|
||||
// Query log
|
||||
GET_QUERY_LOG = { path: 'querylog', method: 'GET' };
|
||||
|
||||
QUERY_LOG_CONFIG = { path: 'querylog_config', method: 'POST' };
|
||||
UPDATE_QUERY_LOG_CONFIG = { path: 'querylog/config/update', method: 'PUT' };
|
||||
|
||||
QUERY_LOG_INFO = { path: 'querylog_info', method: 'GET' };
|
||||
GET_QUERY_LOG_CONFIG = { path: 'querylog/config', method: 'GET' };
|
||||
|
||||
QUERY_LOG_CLEAR = { path: 'querylog_clear', method: 'POST' };
|
||||
|
||||
@@ -543,13 +552,13 @@ class Api {
|
||||
return this.makeRequest(url, method);
|
||||
}
|
||||
|
||||
getQueryLogInfo() {
|
||||
const { path, method } = this.QUERY_LOG_INFO;
|
||||
getQueryLogConfig() {
|
||||
const { path, method } = this.GET_QUERY_LOG_CONFIG;
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
setQueryLogConfig(data) {
|
||||
const { path, method } = this.QUERY_LOG_CONFIG;
|
||||
const { path, method } = this.UPDATE_QUERY_LOG_CONFIG;
|
||||
const config = {
|
||||
data,
|
||||
};
|
||||
@@ -611,6 +620,15 @@ class Api {
|
||||
return this.makeRequest(path, method, config);
|
||||
}
|
||||
|
||||
SET_PROTECTION = { path: 'protection', method: 'POST' };
|
||||
|
||||
setProtection(data) {
|
||||
const { enabled, duration } = data;
|
||||
const { path, method } = this.SET_PROTECTION;
|
||||
|
||||
return this.makeRequest(path, method, { data: { enabled, duration } });
|
||||
}
|
||||
|
||||
// Cache
|
||||
CLEAR_CACHE = { path: 'cache_clear', method: 'POST' };
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
--loading-bg: rgba(255, 255, 255, 0.48);
|
||||
--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;
|
||||
--alert-message-bg: #dae5f5;
|
||||
--checkbox-bg: #e2e2e2;
|
||||
--radio-bg: #ffffff;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
@@ -59,6 +64,11 @@
|
||||
--detailed-info-color: #fff;
|
||||
--gray300: #f3f3f3;
|
||||
--loading-bg: #131313;
|
||||
--alert-message-color: #e6e6e6;
|
||||
--alert-message-border: #363648;
|
||||
--alert-message-bg: #363648;
|
||||
--checkbox-bg: #a4a4a4;
|
||||
--radio-bg: #a4a4a4;
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
@@ -43,6 +43,7 @@ import DnsRewrites from '../../containers/DnsRewrites';
|
||||
import CustomRules from '../../containers/CustomRules';
|
||||
import Services from '../Filters/Services';
|
||||
import Logs from '../Logs';
|
||||
import ProtectionTimer from '../ProtectionTimer';
|
||||
|
||||
const ROUTES = [
|
||||
{
|
||||
@@ -164,8 +165,7 @@ const App = () => {
|
||||
}
|
||||
|
||||
const colorSchemeMedia = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const prefersDark = colorSchemeMedia.matches;
|
||||
setUITheme(prefersDark ? THEMES.dark : THEMES.light);
|
||||
setUITheme(theme);
|
||||
|
||||
if (colorSchemeMedia.addEventListener !== undefined) {
|
||||
colorSchemeMedia.addEventListener('change', (e) => {
|
||||
@@ -191,6 +191,7 @@ const App = () => {
|
||||
{!processingEncryption && <EncryptionTopline />}
|
||||
<LoadingBar className="loading-bar" updateTime={1000} />
|
||||
<Header />
|
||||
<ProtectionTimer />
|
||||
<div className="container container--wrap pb-5">
|
||||
{processing && <Loading />}
|
||||
{!isCoreRunning && <div className="row row-cards">
|
||||
|
||||
@@ -29,8 +29,11 @@ const BlockedDomains = ({
|
||||
blockedFiltering,
|
||||
replacedSafebrowsing,
|
||||
replacedParental,
|
||||
replacedSafesearch,
|
||||
}) => {
|
||||
const totalBlocked = blockedFiltering + replacedSafebrowsing + replacedParental;
|
||||
const totalBlocked = (
|
||||
blockedFiltering + replacedSafebrowsing + replacedParental + replacedSafesearch
|
||||
);
|
||||
|
||||
return (
|
||||
<Card
|
||||
@@ -71,6 +74,7 @@ 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,
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
.dashboard-protection-button.btn-gray {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-right-color: #a4a4a4;
|
||||
}
|
||||
|
||||
.stats__table .popover__body {
|
||||
left: -10px;
|
||||
min-width: 270px;
|
||||
@@ -34,20 +40,11 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dashboard-title__button {
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.page-title--dashboard {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.dashboard-title__button {
|
||||
margin: 0.5rem 0;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.counters__row {
|
||||
|
||||
@@ -9,18 +9,25 @@ import Counters from './Counters';
|
||||
import Clients from './Clients';
|
||||
import QueriedDomains from './QueriedDomains';
|
||||
import BlockedDomains from './BlockedDomains';
|
||||
import { SETTINGS_URLS } from '../../helpers/constants';
|
||||
import { DISABLE_PROTECTION_TIMINGS, ONE_SECOND_IN_MS, SETTINGS_URLS } 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';
|
||||
|
||||
const Dashboard = ({
|
||||
getAccessList,
|
||||
getStats,
|
||||
getStatsConfig,
|
||||
dashboard,
|
||||
dashboard: { protectionEnabled, processingProtection },
|
||||
dashboard: { protectionEnabled, processingProtection, protectionDisabledDuration },
|
||||
toggleProtection,
|
||||
stats,
|
||||
access,
|
||||
@@ -36,20 +43,20 @@ const Dashboard = ({
|
||||
useEffect(() => {
|
||||
getAllStats();
|
||||
}, []);
|
||||
|
||||
const getSubtitle = () => {
|
||||
if (stats.interval === 0) {
|
||||
const ONE_DAY = 1;
|
||||
const intervalInDays = msToDays(stats.interval);
|
||||
|
||||
if (intervalInDays < ONE_DAY) {
|
||||
return t('stats_disabled_short');
|
||||
}
|
||||
|
||||
return stats.interval === 1
|
||||
return intervalInDays === ONE_DAY
|
||||
? t('for_last_24_hours')
|
||||
: t('for_last_days', { count: stats.interval });
|
||||
: t('for_last_days', { count: msToDays(stats.interval) });
|
||||
};
|
||||
|
||||
const buttonText = protectionEnabled ? 'disable_protection' : 'enable_protection';
|
||||
|
||||
const buttonClass = classNames('btn btn-sm dashboard-title__button', {
|
||||
const buttonClass = classNames('btn btn-sm dashboard-protection-button', {
|
||||
'btn-gray': protectionEnabled,
|
||||
'btn-success': !protectionEnabled,
|
||||
});
|
||||
@@ -60,7 +67,7 @@ const Dashboard = ({
|
||||
title={t('refresh_btn')}
|
||||
onClick={() => getAllStats()}
|
||||
>
|
||||
<svg className="icons">
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#refresh" />
|
||||
</svg>
|
||||
</button>;
|
||||
@@ -71,16 +78,87 @@ const Dashboard = ({
|
||||
|
||||
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">
|
||||
<button
|
||||
type="button"
|
||||
className={buttonClass}
|
||||
onClick={() => toggleProtection(protectionEnabled)}
|
||||
disabled={processingProtection}
|
||||
>
|
||||
<Trans>{buttonText}</Trans>
|
||||
</button>
|
||||
<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"
|
||||
@@ -107,7 +185,7 @@ const Dashboard = ({
|
||||
</div>
|
||||
)}
|
||||
<Statistics
|
||||
interval={stats.interval}
|
||||
interval={msToDays(stats.interval)}
|
||||
dnsQueries={stats.dnsQueries}
|
||||
blockedFiltering={stats.blockedFiltering}
|
||||
replacedSafebrowsing={stats.replacedSafebrowsing}
|
||||
@@ -151,6 +229,7 @@ const Dashboard = ({
|
||||
topBlockedDomains={stats.topBlockedDomains}
|
||||
blockedFiltering={stats.numBlockedFiltering}
|
||||
replacedSafebrowsing={stats.numReplacedSafebrowsing}
|
||||
replacedSafesearch={stats.numReplacedSafesearch}
|
||||
replacedParental={stats.numReplacedParental}
|
||||
refreshButton={refreshButton}
|
||||
/>
|
||||
|
||||
@@ -12,7 +12,6 @@ import { MODAL_TYPE } from '../../helpers/constants';
|
||||
|
||||
import {
|
||||
getCurrentFilter,
|
||||
getObjDiff,
|
||||
} from '../../helpers/helpers';
|
||||
|
||||
import filtersCatalog from '../../helpers/filters/filters';
|
||||
@@ -22,7 +21,7 @@ class DnsBlocklist extends Component {
|
||||
this.props.getFilteringStatus();
|
||||
}
|
||||
|
||||
handleSubmit = (values, _, { initialValues }) => {
|
||||
handleSubmit = (values) => {
|
||||
const { modalFilterUrl, modalType } = this.props.filtering;
|
||||
|
||||
switch (modalType) {
|
||||
@@ -35,7 +34,12 @@ class DnsBlocklist extends Component {
|
||||
break;
|
||||
}
|
||||
case MODAL_TYPE.CHOOSE_FILTERING_LIST: {
|
||||
const changedValues = getObjDiff(initialValues, values);
|
||||
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) => {
|
||||
|
||||
@@ -100,7 +100,7 @@ class Table extends Component {
|
||||
})
|
||||
}
|
||||
>
|
||||
<svg className="icons">
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#edit" />
|
||||
</svg>
|
||||
</button>
|
||||
@@ -110,7 +110,7 @@ class Table extends Component {
|
||||
onClick={() => handleDelete(url)}
|
||||
title={t('delete_table_action')}
|
||||
>
|
||||
<svg className="icons">
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#delete" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
@@ -162,7 +162,7 @@ const ClientCell = ({
|
||||
{content && (
|
||||
<button className={buttonArrowClass} disabled={processingRules}>
|
||||
<IconTooltip
|
||||
className="h-100"
|
||||
className="icon24"
|
||||
tooltipClass="button-action--arrow-option-container"
|
||||
xlinkHref="chevron-down"
|
||||
triggerClass="button-action--icon"
|
||||
|
||||
@@ -129,7 +129,6 @@ const Form = (props) => {
|
||||
|
||||
const onInputClear = async () => {
|
||||
setIsLoading(true);
|
||||
setDebouncedSearch(DEFAULT_LOGS_FILTER[FORM_NAMES.search]);
|
||||
change(FORM_NAMES.search, DEFAULT_LOGS_FILTER[FORM_NAMES.search]);
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
@@ -106,6 +106,16 @@
|
||||
max-height: 100% !important;
|
||||
}
|
||||
|
||||
.icon24 {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.icon12 {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.cursor--pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -130,6 +140,10 @@
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .form-control--transparent option {
|
||||
background-color: var(--card-bgcolor);
|
||||
}
|
||||
|
||||
.input-group-search {
|
||||
background-color: transparent;
|
||||
position: relative;
|
||||
@@ -307,7 +321,6 @@
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.button-action:active {
|
||||
@@ -400,6 +413,10 @@
|
||||
background-color: var(--logs__row--blue-bgcolor);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .logs__row--blue .logs__text--link {
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.logs__row--green {
|
||||
background-color: var(--green-pale);
|
||||
}
|
||||
|
||||
52
client/src/components/ProtectionTimer/index.js
Normal file
52
client/src/components/ProtectionTimer/index.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { useEffect } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { ONE_SECOND_IN_MS } from '../../helpers/constants';
|
||||
import { setProtectionTimerTime, toggleProtectionSuccess } from '../../actions';
|
||||
|
||||
let interval = null;
|
||||
|
||||
const ProtectionTimer = ({
|
||||
protectionDisabledDuration,
|
||||
toggleProtectionSuccess,
|
||||
setProtectionTimerTime,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
if (protectionDisabledDuration !== null && protectionDisabledDuration < ONE_SECOND_IN_MS) {
|
||||
toggleProtectionSuccess({ disabledDuration: null });
|
||||
}
|
||||
|
||||
if (protectionDisabledDuration) {
|
||||
interval = setInterval(() => {
|
||||
setProtectionTimerTime(protectionDisabledDuration - ONE_SECOND_IN_MS);
|
||||
}, ONE_SECOND_IN_MS);
|
||||
}
|
||||
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [protectionDisabledDuration]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
ProtectionTimer.propTypes = {
|
||||
setProtectionTimerTime: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const { dashboard } = state;
|
||||
const { protectionEnabled, protectionDisabledDuration } = dashboard;
|
||||
return { protectionEnabled, protectionDisabledDuration };
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
toggleProtectionSuccess,
|
||||
setProtectionTimerTime,
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(ProtectionTimer);
|
||||
@@ -7,6 +7,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
import ReactTable from 'react-table';
|
||||
|
||||
import { getAllBlockedServices } from '../../../../actions/services';
|
||||
import { initSettings } from '../../../../actions';
|
||||
import {
|
||||
splitByNewLine,
|
||||
countClientsStatistics,
|
||||
@@ -38,9 +39,13 @@ const ClientsTable = ({
|
||||
const [t] = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const services = useSelector((store) => store?.services);
|
||||
const globalSettings = useSelector((store) => store?.settings.settingsList) || {};
|
||||
|
||||
const { safesearch } = globalSettings;
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(getAllBlockedServices());
|
||||
dispatch(initSettings());
|
||||
}, []);
|
||||
|
||||
const handleFormAdd = (values) => {
|
||||
@@ -107,6 +112,7 @@ const ClientsTable = ({
|
||||
tags: [],
|
||||
use_global_settings: true,
|
||||
use_global_blocked_services: true,
|
||||
safe_search: { ...(safesearch || {}) },
|
||||
};
|
||||
};
|
||||
|
||||
@@ -290,7 +296,7 @@ const ClientsTable = ({
|
||||
disabled={processingUpdating}
|
||||
title={t('edit_table_action')}
|
||||
>
|
||||
<svg className="icons">
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#edit" />
|
||||
</svg>
|
||||
</button>
|
||||
@@ -301,7 +307,7 @@ const ClientsTable = ({
|
||||
disabled={processingDeleting}
|
||||
title={t('delete_table_action')}
|
||||
>
|
||||
<svg className="icons">
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#delete" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
@@ -11,7 +11,7 @@ import Select from 'react-select';
|
||||
import i18n from '../../../i18n';
|
||||
import Tabs from '../../ui/Tabs';
|
||||
import Examples from '../Dns/Upstream/Examples';
|
||||
import { toggleAllServices, trimLinesAndRemoveEmpty } from '../../../helpers/helpers';
|
||||
import { toggleAllServices, trimLinesAndRemoveEmpty, captitalizeWords } from '../../../helpers/helpers';
|
||||
import {
|
||||
renderInputField,
|
||||
renderGroupField,
|
||||
@@ -40,9 +40,16 @@ const settingsCheckboxes = [
|
||||
name: 'parental_enabled',
|
||||
placeholder: 'use_adguard_parental',
|
||||
},
|
||||
];
|
||||
|
||||
const logAndStatsCheckboxes = [
|
||||
{
|
||||
name: 'safesearch_enabled',
|
||||
placeholder: 'enforce_safe_search',
|
||||
name: 'ignore_querylog',
|
||||
placeholder: 'ignore_query_log',
|
||||
},
|
||||
{
|
||||
name: 'ignore_statistics',
|
||||
placeholder: 'ignore_statistics',
|
||||
},
|
||||
];
|
||||
const validate = (values) => {
|
||||
@@ -139,8 +146,12 @@ let Form = (props) => {
|
||||
processingUpdating,
|
||||
invalid,
|
||||
tagsOptions,
|
||||
initialValues,
|
||||
} = props;
|
||||
const services = useSelector((store) => store?.services);
|
||||
const { safe_search } = initialValues;
|
||||
const safeSearchServices = { ...safe_search };
|
||||
delete safeSearchServices.enabled;
|
||||
|
||||
const [activeTabLabel, setActiveTabLabel] = useState('settings');
|
||||
|
||||
@@ -148,6 +159,9 @@ let Form = (props) => {
|
||||
settings: {
|
||||
title: 'settings',
|
||||
component: <div label="settings" title={props.t('main_settings')}>
|
||||
<div className="form__label--bot form__label--bold">
|
||||
{t('protection_section_label')}
|
||||
</div>
|
||||
{settingsCheckboxes.map((setting) => (
|
||||
<div className="form__group" key={setting.name}>
|
||||
<Field
|
||||
@@ -163,6 +177,41 @@ let Form = (props) => {
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<div className="form__group">
|
||||
<Field
|
||||
name="safe_search.enabled"
|
||||
type="checkbox"
|
||||
component={CheckboxField}
|
||||
placeholder={t('enforce_safe_search')}
|
||||
disabled={useGlobalSettings}
|
||||
/>
|
||||
</div>
|
||||
<div className='form__group--inner'>
|
||||
{Object.keys(safeSearchServices).map((searchKey) => (
|
||||
<div key={searchKey}>
|
||||
<Field
|
||||
name={`safe_search.${searchKey}`}
|
||||
type="checkbox"
|
||||
component={CheckboxField}
|
||||
placeholder={captitalizeWords(searchKey)}
|
||||
disabled={useGlobalSettings}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="form__label--bold form__label--top form__label--bot">
|
||||
{t('log_and_stats_section_label')}
|
||||
</div>
|
||||
{logAndStatsCheckboxes.map((setting) => (
|
||||
<div className="form__group" key={setting.name}>
|
||||
<Field
|
||||
name={setting.name}
|
||||
type="checkbox"
|
||||
component={CheckboxField}
|
||||
placeholder={t(setting.placeholder)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>,
|
||||
},
|
||||
block_services: {
|
||||
@@ -358,6 +407,7 @@ Form.propTypes = {
|
||||
processingUpdating: PropTypes.bool.isRequired,
|
||||
invalid: PropTypes.bool.isRequired,
|
||||
tagsOptions: PropTypes.array.isRequired,
|
||||
initialValues: PropTypes.object,
|
||||
};
|
||||
|
||||
const selector = formValueSelector(FORM_NAME.CLIENT);
|
||||
|
||||
@@ -54,6 +54,12 @@
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.service__icon svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: #495057;
|
||||
}
|
||||
|
||||
.service--global .service__icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactTable from 'react-table';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import { LEASES_TABLE_DEFAULT_PAGE_SIZE } from '../../../helpers/constants';
|
||||
import { sortIp } from '../../../helpers/helpers';
|
||||
import { toggleLeaseModal } from '../../../actions';
|
||||
|
||||
class Leases extends Component {
|
||||
cellWrap = ({ value }) => (
|
||||
@@ -14,6 +16,30 @@ class Leases extends Component {
|
||||
</div>
|
||||
);
|
||||
|
||||
convertToStatic = (data) => () => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(toggleLeaseModal(data));
|
||||
}
|
||||
|
||||
makeStatic = ({ row }) => {
|
||||
const { t, disabledLeasesButton } = this.props;
|
||||
return (
|
||||
<div className="logs__row logs__row--center">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-icon--green btn-outline-secondary btn-sm"
|
||||
title={t('make_static')}
|
||||
onClick={this.convertToStatic(row)}
|
||||
disabled={disabledLeasesButton}
|
||||
>
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#plus" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { leases, t } = this.props;
|
||||
return (
|
||||
@@ -23,20 +49,27 @@ class Leases extends Component {
|
||||
{
|
||||
Header: 'MAC',
|
||||
accessor: 'mac',
|
||||
minWidth: 180,
|
||||
Cell: this.cellWrap,
|
||||
}, {
|
||||
Header: 'IP',
|
||||
accessor: 'ip',
|
||||
minWidth: 230,
|
||||
Cell: this.cellWrap,
|
||||
sortMethod: sortIp,
|
||||
}, {
|
||||
Header: <Trans>dhcp_table_hostname</Trans>,
|
||||
accessor: 'hostname',
|
||||
minWidth: 230,
|
||||
Cell: this.cellWrap,
|
||||
}, {
|
||||
Header: <Trans>dhcp_table_expires</Trans>,
|
||||
accessor: 'expires',
|
||||
minWidth: 220,
|
||||
Cell: this.cellWrap,
|
||||
}, {
|
||||
Header: <Trans>actions_table_header</Trans>,
|
||||
Cell: this.makeStatic,
|
||||
},
|
||||
]}
|
||||
pageSize={LEASES_TABLE_DEFAULT_PAGE_SIZE}
|
||||
@@ -53,6 +86,8 @@ class Leases extends Component {
|
||||
Leases.propTypes = {
|
||||
leases: PropTypes.array,
|
||||
t: PropTypes.func,
|
||||
dispatch: PropTypes.func,
|
||||
disabledLeasesButton: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default withTranslation()(Leases);
|
||||
export default withTranslation()(connect(() => ({}), (dispatch) => ({ dispatch }))(Leases));
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
|
||||
|
||||
import { renderInputField, normalizeMac } from '../../../../helpers/form';
|
||||
import {
|
||||
@@ -25,6 +25,7 @@ const Form = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const dynamicLease = useSelector((store) => store.dhcp.leaseModalConfig, shallowEqual);
|
||||
|
||||
const onClick = () => {
|
||||
reset();
|
||||
@@ -87,7 +88,7 @@ const Form = ({
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-success btn-standard"
|
||||
disabled={submitting || pristine || processingAdding}
|
||||
disabled={submitting || processingAdding || (pristine && !dynamicLease)}
|
||||
>
|
||||
<Trans>save_btn</Trans>
|
||||
</button>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import ReactModal from 'react-modal';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import Form from './Form';
|
||||
import { toggleLeaseModal } from '../../../../actions';
|
||||
|
||||
@@ -18,6 +18,9 @@ const Modal = ({
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const toggleModal = () => dispatch(toggleLeaseModal());
|
||||
const leaseInitialData = useSelector(
|
||||
(state) => state.dhcp.leaseModalConfig, shallowEqual,
|
||||
) || {};
|
||||
|
||||
return (
|
||||
<ReactModal
|
||||
@@ -37,9 +40,9 @@ const Modal = ({
|
||||
</div>
|
||||
<Form
|
||||
initialValues={{
|
||||
mac: '',
|
||||
ip: '',
|
||||
hostname: '',
|
||||
mac: leaseInitialData.mac ?? '',
|
||||
ip: leaseInitialData.ip ?? '',
|
||||
hostname: leaseInitialData.hostname ?? '',
|
||||
cidr,
|
||||
rangeStart,
|
||||
rangeEnd,
|
||||
|
||||
@@ -54,17 +54,20 @@ const StaticLeases = ({
|
||||
{
|
||||
Header: 'MAC',
|
||||
accessor: 'mac',
|
||||
minWidth: 180,
|
||||
Cell: cellWrap,
|
||||
},
|
||||
{
|
||||
Header: 'IP',
|
||||
accessor: 'ip',
|
||||
minWidth: 230,
|
||||
sortMethod: sortIp,
|
||||
Cell: cellWrap,
|
||||
},
|
||||
{
|
||||
Header: <Trans>dhcp_table_hostname</Trans>,
|
||||
accessor: 'hostname',
|
||||
minWidth: 230,
|
||||
Cell: cellWrap,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -188,8 +188,8 @@ const Dhcp = () => {
|
||||
|
||||
const inputtedIPv4values = dhcp?.values?.v4?.gateway_ip && dhcp?.values?.v4?.subnet_mask;
|
||||
const isEmptyConfig = !Object.values(dhcp?.values?.v4 ?? {}).some(Boolean);
|
||||
const disabledLeasesButton = dhcp?.syncErrors || interfaces?.syncErrors
|
||||
|| !isInterfaceIncludesIpv4 || isEmptyConfig || processingConfig || !inputtedIPv4values;
|
||||
const disabledLeasesButton = Boolean(dhcp?.syncErrors || interfaces?.syncErrors
|
||||
|| !isInterfaceIncludesIpv4 || isEmptyConfig || processingConfig || !inputtedIPv4values);
|
||||
const cidr = inputtedIPv4values ? `${dhcp?.values?.v4?.gateway_ip}/${subnetMaskToBitMask(dhcp?.values?.v4?.subnet_mask)}` : '';
|
||||
|
||||
return <>
|
||||
@@ -260,7 +260,7 @@ const Dhcp = () => {
|
||||
>
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<Leases leases={leases} />
|
||||
<Leases leases={leases} disabledLeasesButton={disabledLeasesButton}/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>}
|
||||
|
||||
@@ -13,15 +13,11 @@ import {
|
||||
validateIpv4,
|
||||
validateIpv6,
|
||||
validateRequiredValue,
|
||||
validateIp,
|
||||
} from '../../../../helpers/validators';
|
||||
import { BLOCKING_MODES, FORM_NAME, UINT32_RANGE } from '../../../../helpers/constants';
|
||||
|
||||
const checkboxes = [
|
||||
{
|
||||
name: 'edns_cs_enabled',
|
||||
placeholder: 'edns_enable',
|
||||
subtitle: 'edns_cs_desc',
|
||||
},
|
||||
{
|
||||
name: 'dnssec_enabled',
|
||||
placeholder: 'dnssec_enable',
|
||||
@@ -66,6 +62,8 @@ const Form = ({
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
blocking_mode,
|
||||
edns_cs_enabled,
|
||||
edns_cs_use_custom,
|
||||
} = useSelector((state) => state.form[FORM_NAME.BLOCKING_MODE].values ?? {}, shallowEqual);
|
||||
|
||||
return <form onSubmit={handleSubmit}>
|
||||
@@ -92,6 +90,39 @@ const Form = ({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<div className="form__group form__group--settings">
|
||||
<Field
|
||||
name="edns_cs_enabled"
|
||||
type="checkbox"
|
||||
component={CheckboxField}
|
||||
placeholder={t('edns_enable')}
|
||||
disabled={processing}
|
||||
subtitle={t('edns_cs_desc')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 form__group form__group--inner">
|
||||
<div className="form__group ">
|
||||
<Field
|
||||
name="edns_cs_use_custom"
|
||||
type="checkbox"
|
||||
component={CheckboxField}
|
||||
placeholder={t('edns_use_custom_ip')}
|
||||
disabled={processing || !edns_cs_enabled}
|
||||
subtitle={t('edns_use_custom_ip_desc')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{edns_cs_use_custom && (<Field
|
||||
name="edns_cs_custom_ip"
|
||||
component={renderInputField}
|
||||
className="form-control"
|
||||
placeholder={t('form_enter_ip')}
|
||||
validate={[validateIp, validateRequiredValue]}
|
||||
/>)}
|
||||
|
||||
</div>
|
||||
{checkboxes.map(({ name, placeholder, subtitle }) => <div className="col-12" key={name}>
|
||||
<div className="form__group form__group--settings">
|
||||
<Field
|
||||
|
||||
@@ -14,6 +14,8 @@ const Config = () => {
|
||||
blocking_ipv4,
|
||||
blocking_ipv6,
|
||||
edns_cs_enabled,
|
||||
edns_cs_use_custom,
|
||||
edns_cs_custom_ip,
|
||||
dnssec_enabled,
|
||||
disable_ipv6,
|
||||
processingSetConfig,
|
||||
@@ -39,6 +41,8 @@ const Config = () => {
|
||||
edns_cs_enabled,
|
||||
disable_ipv6,
|
||||
dnssec_enabled,
|
||||
edns_cs_use_custom,
|
||||
edns_cs_custom_ip,
|
||||
}}
|
||||
onSubmit={handleFormSubmit}
|
||||
processing={processingSetConfig}
|
||||
|
||||
@@ -1,21 +1,43 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import {
|
||||
change,
|
||||
Field,
|
||||
formValueSelector,
|
||||
reduxForm,
|
||||
} from 'redux-form';
|
||||
import { connect } from 'react-redux';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import flow from 'lodash/flow';
|
||||
|
||||
import { CheckboxField, renderRadioField, toFloatNumber } from '../../../helpers/form';
|
||||
import { FORM_NAME, QUERY_LOG_INTERVALS_DAYS } from '../../../helpers/constants';
|
||||
import {
|
||||
CheckboxField,
|
||||
toFloatNumber,
|
||||
renderTextareaField, renderInputField, renderRadioField,
|
||||
} from '../../../helpers/form';
|
||||
import {
|
||||
FORM_NAME,
|
||||
QUERY_LOG_INTERVALS_DAYS,
|
||||
HOUR,
|
||||
DAY,
|
||||
RETENTION_CUSTOM,
|
||||
RETENTION_CUSTOM_INPUT,
|
||||
RETENTION_RANGE,
|
||||
CUSTOM_INTERVAL,
|
||||
} from '../../../helpers/constants';
|
||||
import '../FormButton.css';
|
||||
|
||||
|
||||
const getIntervalTitle = (interval, t) => {
|
||||
switch (interval) {
|
||||
case 0.25:
|
||||
case RETENTION_CUSTOM:
|
||||
return t('settings_custom');
|
||||
case 6 * HOUR:
|
||||
return t('interval_6_hour');
|
||||
case 1:
|
||||
case DAY:
|
||||
return t('interval_24_hour');
|
||||
default:
|
||||
return t('interval_days', { count: interval });
|
||||
return t('interval_days', { count: interval / DAY });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,11 +54,26 @@ const getIntervalFields = (processing, t, toNumber) => QUERY_LOG_INTERVALS_DAYS.
|
||||
/>
|
||||
));
|
||||
|
||||
const Form = (props) => {
|
||||
let Form = (props) => {
|
||||
const {
|
||||
handleSubmit, submitting, invalid, processing, processingClear, handleClear, t,
|
||||
handleSubmit,
|
||||
submitting,
|
||||
invalid,
|
||||
processing,
|
||||
processingClear,
|
||||
handleClear,
|
||||
t,
|
||||
interval,
|
||||
customInterval,
|
||||
dispatch,
|
||||
} = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (QUERY_LOG_INTERVALS_DAYS.includes(interval)) {
|
||||
dispatch(change(FORM_NAME.LOG_CONFIG, CUSTOM_INTERVAL, null));
|
||||
}
|
||||
}, [interval]);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="form__group form__group--settings">
|
||||
@@ -63,14 +100,66 @@ const Form = (props) => {
|
||||
</label>
|
||||
<div className="form__group form__group--settings">
|
||||
<div className="custom-controls-stacked">
|
||||
<Field
|
||||
key={RETENTION_CUSTOM}
|
||||
name="interval"
|
||||
type="radio"
|
||||
component={renderRadioField}
|
||||
value={QUERY_LOG_INTERVALS_DAYS.includes(interval)
|
||||
? RETENTION_CUSTOM
|
||||
: interval
|
||||
}
|
||||
placeholder={getIntervalTitle(RETENTION_CUSTOM, t)}
|
||||
normalize={toFloatNumber}
|
||||
disabled={processing}
|
||||
/>
|
||||
{!QUERY_LOG_INTERVALS_DAYS.includes(interval) && (
|
||||
<div className="form__group--input">
|
||||
<div className="form__desc form__desc--top">
|
||||
{t('custom_rotation_input')}
|
||||
</div>
|
||||
<Field
|
||||
key={RETENTION_CUSTOM_INPUT}
|
||||
name={CUSTOM_INTERVAL}
|
||||
type="number"
|
||||
className="form-control"
|
||||
component={renderInputField}
|
||||
disabled={processing}
|
||||
normalize={toFloatNumber}
|
||||
min={RETENTION_RANGE.MIN}
|
||||
max={RETENTION_RANGE.MAX}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{getIntervalFields(processing, t, toFloatNumber)}
|
||||
</div>
|
||||
</div>
|
||||
<label className="form__label form__label--with-desc">
|
||||
<Trans>ignore_domains_title</Trans>
|
||||
</label>
|
||||
<div className="form__desc form__desc--top">
|
||||
<Trans>ignore_domains_desc_query</Trans>
|
||||
</div>
|
||||
<div className="form__group form__group--settings">
|
||||
<Field
|
||||
name="ignored"
|
||||
type="textarea"
|
||||
className="form-control form-control--textarea font-monospace text-input"
|
||||
component={renderTextareaField}
|
||||
placeholder={t('ignore_domains')}
|
||||
disabled={processing}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-success btn-standard btn-large"
|
||||
disabled={submitting || invalid || processing}
|
||||
disabled={
|
||||
submitting
|
||||
|| invalid
|
||||
|| processing
|
||||
|| (!QUERY_LOG_INTERVALS_DAYS.includes(interval) && !customInterval)
|
||||
}
|
||||
>
|
||||
<Trans>save_btn</Trans>
|
||||
</button>
|
||||
@@ -95,8 +184,22 @@ Form.propTypes = {
|
||||
processing: PropTypes.bool.isRequired,
|
||||
processingClear: PropTypes.bool.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
interval: PropTypes.number,
|
||||
customInterval: PropTypes.number,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const selector = formValueSelector(FORM_NAME.LOG_CONFIG);
|
||||
|
||||
Form = connect((state) => {
|
||||
const interval = selector(state, 'interval');
|
||||
const customInterval = selector(state, CUSTOM_INTERVAL);
|
||||
return {
|
||||
interval,
|
||||
customInterval,
|
||||
};
|
||||
})(Form);
|
||||
|
||||
export default flow([
|
||||
withTranslation(),
|
||||
reduxForm({ form: FORM_NAME.LOG_CONFIG }),
|
||||
|
||||
@@ -4,19 +4,28 @@ import { withTranslation } from 'react-i18next';
|
||||
|
||||
import Card from '../../ui/Card';
|
||||
import Form from './Form';
|
||||
import { HOUR } from '../../../helpers/constants';
|
||||
|
||||
class LogsConfig extends Component {
|
||||
handleFormSubmit = (values) => {
|
||||
const { t, interval: prevInterval } = this.props;
|
||||
const { interval } = values;
|
||||
const { interval, customInterval, ...rest } = values;
|
||||
|
||||
if (interval !== prevInterval) {
|
||||
const newInterval = customInterval ? customInterval * HOUR : interval;
|
||||
|
||||
const data = {
|
||||
...rest,
|
||||
ignored: values.ignored ? values.ignored.split('\n') : [],
|
||||
interval: newInterval,
|
||||
};
|
||||
|
||||
if (newInterval < prevInterval) {
|
||||
// eslint-disable-next-line no-alert
|
||||
if (window.confirm(t('query_log_retention_confirm'))) {
|
||||
this.props.setLogsConfig(values);
|
||||
this.props.setLogsConfig(data);
|
||||
}
|
||||
} else {
|
||||
this.props.setLogsConfig(values);
|
||||
this.props.setLogsConfig(data);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,7 +39,14 @@ class LogsConfig extends Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
t, enabled, interval, processing, processingClear, anonymize_client_ip,
|
||||
t,
|
||||
enabled,
|
||||
interval,
|
||||
processing,
|
||||
processingClear,
|
||||
anonymize_client_ip,
|
||||
ignored,
|
||||
customInterval,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@@ -44,7 +60,9 @@ class LogsConfig extends Component {
|
||||
initialValues={{
|
||||
enabled,
|
||||
interval,
|
||||
customInterval,
|
||||
anonymize_client_ip,
|
||||
ignored: ignored.join('\n'),
|
||||
}}
|
||||
onSubmit={this.handleFormSubmit}
|
||||
processing={processing}
|
||||
@@ -59,9 +77,11 @@ class LogsConfig extends Component {
|
||||
|
||||
LogsConfig.propTypes = {
|
||||
interval: PropTypes.number.isRequired,
|
||||
customInterval: PropTypes.number,
|
||||
enabled: PropTypes.bool.isRequired,
|
||||
anonymize_client_ip: PropTypes.bool.isRequired,
|
||||
processing: PropTypes.bool.isRequired,
|
||||
ignored: PropTypes.array.isRequired,
|
||||
processingClear: PropTypes.bool.isRequired,
|
||||
setLogsConfig: PropTypes.func.isRequired,
|
||||
clearLogs: PropTypes.func.isRequired,
|
||||
|
||||
@@ -18,10 +18,23 @@
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form__group--input {
|
||||
max-width: 300px;
|
||||
margin: 0 1.5rem 10px;
|
||||
}
|
||||
|
||||
.form__group--checkbox {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.form__group--inner .form__group--checkbox {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.form__group--inner .form__group--checkbox:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form__inline {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
@@ -92,6 +105,14 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form__label--bot {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.form__label--top {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.form__status {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
|
||||
@@ -1,34 +1,63 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import {
|
||||
change, Field, formValueSelector, reduxForm,
|
||||
} from 'redux-form';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import flow from 'lodash/flow';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { renderRadioField, toNumber, CheckboxField } from '../../../helpers/form';
|
||||
import { FORM_NAME, STATS_INTERVALS_DAYS, DISABLED_STATS_INTERVAL } from '../../../helpers/constants';
|
||||
|
||||
import {
|
||||
renderRadioField,
|
||||
toNumber,
|
||||
CheckboxField,
|
||||
renderTextareaField,
|
||||
toFloatNumber,
|
||||
renderInputField,
|
||||
} from '../../../helpers/form';
|
||||
import {
|
||||
FORM_NAME,
|
||||
STATS_INTERVALS_DAYS,
|
||||
DAY,
|
||||
RETENTION_CUSTOM,
|
||||
RETENTION_CUSTOM_INPUT,
|
||||
CUSTOM_INTERVAL,
|
||||
RETENTION_RANGE,
|
||||
} from '../../../helpers/constants';
|
||||
import '../FormButton.css';
|
||||
|
||||
const getIntervalTitle = (interval, t) => {
|
||||
switch (interval) {
|
||||
case 1:
|
||||
const getIntervalTitle = (intervalMs, t) => {
|
||||
switch (intervalMs) {
|
||||
case RETENTION_CUSTOM:
|
||||
return t('settings_custom');
|
||||
case DAY:
|
||||
return t('interval_24_hour');
|
||||
default:
|
||||
return t('interval_days', { count: interval });
|
||||
return t('interval_days', { count: intervalMs / DAY });
|
||||
}
|
||||
};
|
||||
|
||||
const Form = (props) => {
|
||||
let Form = (props) => {
|
||||
const {
|
||||
handleSubmit,
|
||||
change,
|
||||
processing,
|
||||
submitting,
|
||||
invalid,
|
||||
handleReset,
|
||||
processingReset,
|
||||
t,
|
||||
interval,
|
||||
customInterval,
|
||||
dispatch,
|
||||
} = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (STATS_INTERVALS_DAYS.includes(interval)) {
|
||||
dispatch(change(FORM_NAME.STATS_CONFIG, CUSTOM_INTERVAL, null));
|
||||
}
|
||||
}, [interval]);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="form__group form__group--settings">
|
||||
@@ -38,13 +67,6 @@ const Form = (props) => {
|
||||
component={CheckboxField}
|
||||
placeholder={t('statistics_enable')}
|
||||
disabled={processing}
|
||||
onChange={(event) => {
|
||||
if (event.target.checked) {
|
||||
change('interval', STATS_INTERVALS_DAYS[0]);
|
||||
} else {
|
||||
change('interval', DISABLED_STATS_INTERVAL);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<label className="form__label form__label--with-desc">
|
||||
@@ -55,6 +77,37 @@ const Form = (props) => {
|
||||
</div>
|
||||
<div className="form__group form__group--settings mt-2">
|
||||
<div className="custom-controls-stacked">
|
||||
<Field
|
||||
key={RETENTION_CUSTOM}
|
||||
name="interval"
|
||||
type="radio"
|
||||
component={renderRadioField}
|
||||
value={STATS_INTERVALS_DAYS.includes(interval)
|
||||
? RETENTION_CUSTOM
|
||||
: interval
|
||||
}
|
||||
placeholder={getIntervalTitle(RETENTION_CUSTOM, t)}
|
||||
normalize={toFloatNumber}
|
||||
disabled={processing}
|
||||
/>
|
||||
{!STATS_INTERVALS_DAYS.includes(interval) && (
|
||||
<div className="form__group--input">
|
||||
<div className="form__desc form__desc--top">
|
||||
{t('custom_retention_input')}
|
||||
</div>
|
||||
<Field
|
||||
key={RETENTION_CUSTOM_INPUT}
|
||||
name={CUSTOM_INTERVAL}
|
||||
type="number"
|
||||
className="form-control"
|
||||
component={renderInputField}
|
||||
disabled={processing}
|
||||
normalize={toFloatNumber}
|
||||
min={RETENTION_RANGE.MIN}
|
||||
max={RETENTION_RANGE.MAX}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{STATS_INTERVALS_DAYS.map((interval) => (
|
||||
<Field
|
||||
key={interval}
|
||||
@@ -65,20 +118,36 @@ const Form = (props) => {
|
||||
placeholder={getIntervalTitle(interval, t)}
|
||||
normalize={toNumber}
|
||||
disabled={processing}
|
||||
onChange={(event) => {
|
||||
if (event.target.checked) {
|
||||
change('enabled', true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<label className="form__label form__label--with-desc">
|
||||
<Trans>ignore_domains_title</Trans>
|
||||
</label>
|
||||
<div className="form__desc form__desc--top">
|
||||
<Trans>ignore_domains_desc_stats</Trans>
|
||||
</div>
|
||||
<div className="form__group form__group--settings">
|
||||
<Field
|
||||
name="ignored"
|
||||
type="textarea"
|
||||
className="form-control form-control--textarea font-monospace text-input"
|
||||
component={renderTextareaField}
|
||||
placeholder={t('ignore_domains')}
|
||||
disabled={processing}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-success btn-standard btn-large"
|
||||
disabled={submitting || invalid || processing}
|
||||
disabled={
|
||||
submitting
|
||||
|| invalid
|
||||
|| processing
|
||||
|| (!STATS_INTERVALS_DAYS.includes(interval) && !customInterval)
|
||||
}
|
||||
>
|
||||
<Trans>save_btn</Trans>
|
||||
</button>
|
||||
@@ -104,8 +173,22 @@ Form.propTypes = {
|
||||
processing: PropTypes.bool.isRequired,
|
||||
processingReset: PropTypes.bool.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
interval: PropTypes.number,
|
||||
customInterval: PropTypes.number,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const selector = formValueSelector(FORM_NAME.STATS_CONFIG);
|
||||
|
||||
Form = connect((state) => {
|
||||
const interval = selector(state, 'interval');
|
||||
const customInterval = selector(state, CUSTOM_INTERVAL);
|
||||
return {
|
||||
interval,
|
||||
customInterval,
|
||||
};
|
||||
})(Form);
|
||||
|
||||
export default flow([
|
||||
withTranslation(),
|
||||
reduxForm({ form: FORM_NAME.STATS_CONFIG }),
|
||||
|
||||
@@ -4,11 +4,20 @@ import { withTranslation } from 'react-i18next';
|
||||
|
||||
import Card from '../../ui/Card';
|
||||
import Form from './Form';
|
||||
import { HOUR } from '../../../helpers/constants';
|
||||
|
||||
class StatsConfig extends Component {
|
||||
handleFormSubmit = (values) => {
|
||||
handleFormSubmit = ({
|
||||
enabled, interval, ignored, customInterval,
|
||||
}) => {
|
||||
const { t, interval: prevInterval } = this.props;
|
||||
const config = { interval: values.interval };
|
||||
const newInterval = customInterval ? customInterval * HOUR : interval;
|
||||
|
||||
const config = {
|
||||
enabled,
|
||||
interval: newInterval,
|
||||
ignored: ignored ? ignored.split('\n') : [],
|
||||
};
|
||||
|
||||
if (config.interval < prevInterval) {
|
||||
if (window.confirm(t('statistics_retention_confirm'))) {
|
||||
@@ -29,7 +38,13 @@ class StatsConfig extends Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
t, interval, processing, processingReset,
|
||||
t,
|
||||
interval,
|
||||
customInterval,
|
||||
processing,
|
||||
processingReset,
|
||||
ignored,
|
||||
enabled,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@@ -42,7 +57,9 @@ class StatsConfig extends Component {
|
||||
<Form
|
||||
initialValues={{
|
||||
interval,
|
||||
enabled: !!interval,
|
||||
customInterval,
|
||||
enabled,
|
||||
ignored: ignored.join('\n'),
|
||||
}}
|
||||
onSubmit={this.handleFormSubmit}
|
||||
processing={processing}
|
||||
@@ -57,6 +74,9 @@ class StatsConfig extends Component {
|
||||
|
||||
StatsConfig.propTypes = {
|
||||
interval: PropTypes.number.isRequired,
|
||||
customInterval: PropTypes.number,
|
||||
ignored: PropTypes.array.isRequired,
|
||||
enabled: PropTypes.bool.isRequired,
|
||||
processing: PropTypes.bool.isRequired,
|
||||
processingReset: PropTypes.bool.isRequired,
|
||||
setStatsConfig: PropTypes.func.isRequired,
|
||||
|
||||
@@ -10,7 +10,7 @@ import Checkbox from '../ui/Checkbox';
|
||||
import Loading from '../ui/Loading';
|
||||
import PageTitle from '../ui/PageTitle';
|
||||
import Card from '../ui/Card';
|
||||
import { getObjectKeysSorted } from '../../helpers/helpers';
|
||||
import { getObjectKeysSorted, captitalizeWords } from '../../helpers/helpers';
|
||||
import './Settings.css';
|
||||
|
||||
const ORDER_KEY = 'order';
|
||||
@@ -28,12 +28,6 @@ const SETTINGS = {
|
||||
subtitle: 'use_adguard_parental_hint',
|
||||
[ORDER_KEY]: 1,
|
||||
},
|
||||
safesearch: {
|
||||
enabled: false,
|
||||
title: 'enforce_safe_search',
|
||||
subtitle: 'enforce_save_search_hint',
|
||||
[ORDER_KEY]: 2,
|
||||
},
|
||||
};
|
||||
|
||||
class Settings extends Component {
|
||||
@@ -44,7 +38,7 @@ class Settings extends Component {
|
||||
this.props.getFilteringStatus();
|
||||
}
|
||||
|
||||
renderSettings = (settings) => getObjectKeysSorted(settings, ORDER_KEY)
|
||||
renderSettings = (settings) => getObjectKeysSorted(SETTINGS, ORDER_KEY)
|
||||
.map((key) => {
|
||||
const setting = settings[key];
|
||||
const { enabled } = setting;
|
||||
@@ -55,6 +49,35 @@ class Settings extends Component {
|
||||
/>;
|
||||
});
|
||||
|
||||
renderSafeSearch = () => {
|
||||
const { settings: { settingsList: { safesearch } } } = this.props;
|
||||
const { enabled } = safesearch || {};
|
||||
const searches = { ...(safesearch || {}) };
|
||||
delete searches.enabled;
|
||||
return (
|
||||
<>
|
||||
<Checkbox
|
||||
enabled={enabled}
|
||||
title='enforce_safe_search'
|
||||
subtitle='enforce_save_search_hint'
|
||||
handleChange={({ target: { checked: enabled } }) => this.props.toggleSetting('safesearch', { ...safesearch, enabled })}
|
||||
/>
|
||||
<div className='form__group--inner'>
|
||||
{Object.keys(searches).map((searchKey) => (
|
||||
<Checkbox
|
||||
key={searchKey}
|
||||
enabled={searches[searchKey]}
|
||||
title={captitalizeWords(searchKey)}
|
||||
subtitle=''
|
||||
disabled={!safesearch.enabled}
|
||||
handleChange={({ target: { checked } }) => this.props.toggleSetting('safesearch', { ...safesearch, [searchKey]: checked })}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
settings,
|
||||
@@ -92,13 +115,16 @@ class Settings extends Component {
|
||||
setFiltersConfig={setFiltersConfig}
|
||||
/>
|
||||
{this.renderSettings(settings.settingsList)}
|
||||
{this.renderSafeSearch()}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-md-12">
|
||||
<LogsConfig
|
||||
enabled={queryLogs.enabled}
|
||||
ignored={queryLogs.ignored}
|
||||
interval={queryLogs.interval}
|
||||
customInterval={queryLogs.customInterval}
|
||||
anonymize_client_ip={queryLogs.anonymize_client_ip}
|
||||
processing={queryLogs.processingSetConfig}
|
||||
processingClear={queryLogs.processingClear}
|
||||
@@ -109,6 +135,9 @@ class Settings extends Component {
|
||||
<div className="col-md-12">
|
||||
<StatsConfig
|
||||
interval={stats.interval}
|
||||
customInterval={stats.customInterval}
|
||||
ignored={stats.ignored}
|
||||
enabled={stats.enabled}
|
||||
processing={stats.processingSetConfig}
|
||||
processingReset={stats.processingReset}
|
||||
setStatsConfig={setStatsConfig}
|
||||
@@ -139,16 +168,21 @@ Settings.propTypes = {
|
||||
stats: PropTypes.shape({
|
||||
processingGetConfig: PropTypes.bool,
|
||||
interval: PropTypes.number,
|
||||
customInterval: PropTypes.number,
|
||||
enabled: PropTypes.bool,
|
||||
ignored: PropTypes.array,
|
||||
processingSetConfig: PropTypes.bool,
|
||||
processingReset: PropTypes.bool,
|
||||
}),
|
||||
queryLogs: PropTypes.shape({
|
||||
enabled: PropTypes.bool,
|
||||
interval: PropTypes.number,
|
||||
customInterval: PropTypes.number,
|
||||
anonymize_client_ip: PropTypes.bool,
|
||||
processingSetConfig: PropTypes.bool,
|
||||
processingClear: PropTypes.bool,
|
||||
processingGetConfig: PropTypes.bool,
|
||||
ignored: PropTypes.array,
|
||||
}),
|
||||
filtering: PropTypes.shape({
|
||||
interval: PropTypes.number,
|
||||
|
||||
@@ -54,6 +54,11 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.toast__dismiss:hover,
|
||||
.toast__dismiss:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.toast-enter {
|
||||
opacity: 0.01;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
height: 20px;
|
||||
min-width: 20px;
|
||||
margin-right: 10px;
|
||||
background-color: #e2e2e2;
|
||||
background-color: var(--checkbox-bg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 12px 10px;
|
||||
|
||||
@@ -11,13 +11,14 @@ class Checkbox extends Component {
|
||||
subtitle,
|
||||
enabled,
|
||||
handleChange,
|
||||
disabled,
|
||||
t,
|
||||
} = this.props;
|
||||
return (
|
||||
<div className="form__group form__group--checkbox">
|
||||
<label className="checkbox checkbox--settings">
|
||||
<span className="checkbox__marker"/>
|
||||
<input type="checkbox" className="checkbox__input" onChange={handleChange} checked={enabled}/>
|
||||
<input type="checkbox" className="checkbox__input" onChange={handleChange} checked={enabled} disabled={disabled}/>
|
||||
<span className="checkbox__label">
|
||||
<span className="checkbox__label-text">
|
||||
<span className="checkbox__label-title">{ t(title) }</span>
|
||||
@@ -35,6 +36,7 @@ Checkbox.propTypes = {
|
||||
subtitle: PropTypes.string.isRequired,
|
||||
enabled: PropTypes.bool.isRequired,
|
||||
handleChange: PropTypes.func.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
t: PropTypes.func,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.dropdown-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-item.active,
|
||||
.dropdown-item:active {
|
||||
background-color: var(--btn-success-bgcolor);
|
||||
@@ -6,3 +10,55 @@
|
||||
.dropdown-menu {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.dropdown-menu.dropdown-menu--protection {
|
||||
top: calc(100% + 8px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.dropdown-menu.dropdown-menu-arrow.dropdown-menu--protection::before,
|
||||
.dropdown-menu.dropdown-menu-arrow.dropdown-menu--protection::after {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.dropdown-protection {
|
||||
align-self: stretch;
|
||||
width: 26px;
|
||||
display: flex;
|
||||
position: relative;
|
||||
border: 1px solid #868e96;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-left: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-protection__toggle {
|
||||
width: 100%;
|
||||
display: block;
|
||||
position: relative;
|
||||
background-color: #868e96;
|
||||
transition: background-color 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.dropdown-protection__toggle:hover {
|
||||
background-color: #727b84;
|
||||
}
|
||||
|
||||
.dropdown-protection__toggle .nav-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
color: var(--white);
|
||||
transition: 0.15s ease-in-out transform;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.dropdown-protection.show .nav-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
@@ -71,3 +71,38 @@
|
||||
margin: 0 20px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-secondary.footer__theme-button,
|
||||
[data-theme="dark"] .btn-secondary.footer__theme-button {
|
||||
height: 38px;
|
||||
border-color: var(--ctrl-select-bgcolor);
|
||||
}
|
||||
|
||||
.footer__theme-icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: var(--gray-ac);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .footer__theme-icon {
|
||||
color: var(--mcolor);
|
||||
}
|
||||
|
||||
.footer__theme-icon--active,
|
||||
[data-theme="dark"] .footer__theme-icon--active {
|
||||
color: var(--btn-success-bgcolor);
|
||||
}
|
||||
|
||||
.footer__themes {
|
||||
margin: 0 auto 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.footer__themes {
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import classNames from 'classnames';
|
||||
import cn from 'classnames';
|
||||
|
||||
import { REPOSITORY, PRIVACY_POLICY_LINK, THEMES } from '../../helpers/constants';
|
||||
import { LANGUAGES } from '../../helpers/twosky';
|
||||
@@ -33,16 +33,14 @@ const Footer = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const currentTheme = useSelector((state) => (state.dashboard ? state.dashboard.theme : 'auto'));
|
||||
const profileName = useSelector((state) => (state.dashboard ? state.dashboard.name : ''));
|
||||
const currentTheme = useSelector((state) => (
|
||||
state.dashboard ? state.dashboard.theme : THEMES.auto
|
||||
));
|
||||
const profileName = useSelector((state) => (
|
||||
state.dashboard ? state.dashboard.name : ''
|
||||
));
|
||||
const isLoggedIn = profileName !== '';
|
||||
const [currentThemeLocal, setCurrentThemeLocal] = useState('auto');
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoggedIn) {
|
||||
setUITheme(window.matchMedia('(prefers-color-scheme: dark)').matches ? THEMES.dark : THEMES.light);
|
||||
}
|
||||
}, []);
|
||||
const [currentThemeLocal, setCurrentThemeLocal] = useState(THEMES.auto);
|
||||
|
||||
const getYear = () => {
|
||||
const today = new Date();
|
||||
@@ -55,15 +53,13 @@ const Footer = () => {
|
||||
setHtmlLangAttr(value);
|
||||
};
|
||||
|
||||
const onThemeChanged = (event) => {
|
||||
const { value } = event.target;
|
||||
dispatch(changeTheme(value));
|
||||
};
|
||||
|
||||
const onThemeChangedLocal = (event) => {
|
||||
const { value } = event.target;
|
||||
setUITheme(value);
|
||||
setCurrentThemeLocal(value);
|
||||
const onThemeChange = (value) => {
|
||||
if (isLoggedIn) {
|
||||
dispatch(changeTheme(value));
|
||||
} else {
|
||||
setUITheme(value);
|
||||
setCurrentThemeLocal(value);
|
||||
}
|
||||
};
|
||||
|
||||
const renderCopyright = () => <div className="footer__column">
|
||||
@@ -76,41 +72,53 @@ const Footer = () => {
|
||||
const renderLinks = (linksData) => linksData.map(({ name, href, className = '' }) => <a
|
||||
key={name}
|
||||
href={href}
|
||||
className={classNames('footer__link', className)}
|
||||
className={cn('footer__link', className)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t(name)}
|
||||
</a>);
|
||||
|
||||
const themeSelectOptions = () => (
|
||||
Object.values(THEMES)
|
||||
.map((theme) => (
|
||||
<option key={theme} value={theme}>
|
||||
{t(`theme_${theme}`)}
|
||||
</option>
|
||||
))
|
||||
);
|
||||
const renderThemeButtons = () => {
|
||||
const currentValue = isLoggedIn ? currentTheme : currentThemeLocal;
|
||||
|
||||
const renderThemeSelect = () => (
|
||||
<select
|
||||
className="form-control select select--theme"
|
||||
value={currentTheme}
|
||||
onChange={onThemeChanged}
|
||||
>
|
||||
{themeSelectOptions()}
|
||||
</select>
|
||||
);
|
||||
const content = {
|
||||
auto: {
|
||||
desc: t('theme_auto_desc'),
|
||||
icon: '#auto',
|
||||
},
|
||||
dark: {
|
||||
desc: t('theme_dark_desc'),
|
||||
icon: '#dark',
|
||||
},
|
||||
light: {
|
||||
desc: t('theme_light_desc'),
|
||||
icon: '#light',
|
||||
},
|
||||
};
|
||||
|
||||
const renderThemeSelectLocal = () => (
|
||||
<select
|
||||
className="form-control select select--theme"
|
||||
value={currentThemeLocal}
|
||||
onChange={onThemeChangedLocal}
|
||||
>
|
||||
{themeSelectOptions()}
|
||||
</select>
|
||||
);
|
||||
return (
|
||||
Object.values(THEMES)
|
||||
.map((theme) => (
|
||||
<button
|
||||
key={theme}
|
||||
type="button"
|
||||
className="btn btn-sm btn-secondary footer__theme-button"
|
||||
onClick={() => onThemeChange(theme)}
|
||||
title={content[theme].desc}
|
||||
>
|
||||
<svg
|
||||
className={cn(
|
||||
'footer__theme-icon',
|
||||
{ 'footer__theme-icon--active': currentValue === theme },
|
||||
)}
|
||||
>
|
||||
<use xlinkHref={content[theme].icon} />
|
||||
</svg>
|
||||
</button>
|
||||
))
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -121,7 +129,11 @@ const Footer = () => {
|
||||
{renderLinks(linksData)}
|
||||
</div>
|
||||
<div className="footer__column footer__column--theme">
|
||||
{isLoggedIn ? renderThemeSelect() : renderThemeSelectLocal()}
|
||||
<div className="footer__themes">
|
||||
<div className="btn-group">
|
||||
{renderThemeButtons()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="footer__column footer__column--language">
|
||||
<select
|
||||
|
||||
@@ -7,7 +7,6 @@ import { useSelector } from 'react-redux';
|
||||
import { MOBILE_CONFIG_LINKS } from '../../../helpers/constants';
|
||||
|
||||
import Tabs from '../Tabs';
|
||||
import Icons from '../Icons';
|
||||
import MobileConfigForm from './MobileConfigForm';
|
||||
|
||||
const renderLi = ({ label, components }) => <li key={label}>
|
||||
@@ -341,7 +340,6 @@ const Guide = ({ dnsAddresses }) => {
|
||||
>
|
||||
{activeTab}
|
||||
</Tabs>
|
||||
<Icons />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -86,10 +86,10 @@ const Icons = () => (
|
||||
d="m19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1 -2.83 0l-.06-.06a1.65 1.65 0 0 0 -1.82-.33 1.65 1.65 0 0 0 -1 1.51v.17a2 2 0 0 1 -2 2 2 2 0 0 1 -2-2v-.09a1.65 1.65 0 0 0 -1.08-1.51 1.65 1.65 0 0 0 -1.82.33l-.06.06a2 2 0 0 1 -2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0 -1.51-1h-.17a2 2 0 0 1 -2-2 2 2 0 0 1 2-2h.09a1.65 1.65 0 0 0 1.51-1.08 1.65 1.65 0 0 0 -.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33h.08a1.65 1.65 0 0 0 1-1.51v-.17a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0 -.33 1.82v.08a1.65 1.65 0 0 0 1.51 1h.17a2 2 0 0 1 2 2 2 2 0 0 1 -2 2h-.09a1.65 1.65 0 0 0 -1.51 1z" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="refresh" viewBox="0 0 24 24" stroke="currentColor" fill="none"
|
||||
strokeLinecap="round" strokeLinejoin="round" strokeWidth="2">
|
||||
<path d="M23 4v6h-6M1 20v-6h6" />
|
||||
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" />
|
||||
<symbol id="refresh" viewBox="0 0 24 24" stroke="currentColor" fill="none" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2">
|
||||
<polyline points="23 4 23 10 17 10"></polyline>
|
||||
<polyline points="1 20 1 14 7 14"></polyline>
|
||||
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
|
||||
</symbol>
|
||||
|
||||
<symbol id="dns_privacy" viewBox="0 0 30 30" stroke="none" fill="currentColor"
|
||||
@@ -181,6 +181,12 @@ const Icons = () => (
|
||||
</svg>
|
||||
</symbol>
|
||||
|
||||
<symbol id="arrow-down" viewBox="0 0 24 24" fill="currentColor">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" d="M6.2 8.2a.64.64 0 0 1 .94 0L12 13.32l4.86-5.1a.64.64 0 0 1 .94 0c.27.27.27.71 0 .98l-5.33 5.6a.64.64 0 0 1-.94 0L6.2 9.2a.72.72 0 0 1 0-.98Z" clipRule="evenodd"/>
|
||||
</svg>
|
||||
</symbol>
|
||||
|
||||
<symbol id="arrow-right" viewBox="0 0 24 24" stroke="currentColor"
|
||||
strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5">
|
||||
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -198,11 +204,24 @@ const Icons = () => (
|
||||
</svg>
|
||||
</symbol>
|
||||
|
||||
<symbol id="chevron-down" viewBox="0 0 24 24">
|
||||
<symbol id="auto" width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3Z" stroke="currentColor" strokeWidth="1.5" />
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M12 3V21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3Z" fill="currentColor" stroke="currentColor" strokeWidth="1.5" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="dark" width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M3.80737 15.731L3.9895 15.0034C3.71002 14.9335 3.41517 15.0298 3.23088 15.2512C3.0466 15.4727 3.00545 15.7801 3.12501 16.0422L3.80737 15.731ZM14.1926 3.26892L14.3747 2.54137C14.0953 2.47141 13.8004 2.56772 13.6161 2.78917C13.4318 3.01062 13.3907 3.31806 13.5102 3.58018L14.1926 3.26892ZM12 20.2499C8.66479 20.2499 5.79026 18.2708 4.48974 15.4197L3.12501 16.0422C4.66034 19.4081 8.05588 21.7499 12 21.7499V20.2499ZM20.25 11.9999C20.25 16.5563 16.5563 20.2499 12 20.2499V21.7499C17.3848 21.7499 21.75 17.3847 21.75 11.9999H20.25ZM14.0105 3.99647C17.5955 4.89391 20.25 8.13787 20.25 11.9999H21.75C21.75 7.43347 18.6114 3.60193 14.3747 2.54137L14.0105 3.99647ZM13.5102 3.58018C13.9851 4.6211 14.25 5.77857 14.25 6.99995H15.75C15.75 5.5595 15.4371 4.1901 14.875 2.95766L13.5102 3.58018ZM14.25 6.99995C14.25 11.5563 10.5563 15.2499 5.99999 15.2499V16.7499C11.3848 16.7499 15.75 12.3847 15.75 6.99995H14.25ZM5.99999 15.2499C5.30559 15.2499 4.63225 15.1643 3.9895 15.0034L3.62525 16.4585C4.38616 16.649 5.18181 16.7499 5.99999 16.7499V15.2499Z" fill="currentColor" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="light" width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M12 3.75C16.5563 3.75 20.25 7.44365 20.25 12H21.75C21.75 6.61522 17.3848 2.25 12 2.25V3.75ZM20.25 12C20.25 16.5563 16.5563 20.25 12 20.25V21.75C17.3848 21.75 21.75 17.3848 21.75 12H20.25ZM12 20.25C7.44365 20.25 3.75 16.5563 3.75 12H2.25C2.25 17.3848 6.61522 21.75 12 21.75V20.25ZM3.75 12C3.75 7.44365 7.44365 3.75 12 3.75V2.25C6.61522 2.25 2.25 6.61522 2.25 12H3.75Z" fill="currentColor" />
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12C13.9987 10.896 13.104 10.0013 12 10Z" fill="currentColor" />
|
||||
</symbol>
|
||||
|
||||
<symbol id="chevron-down" width="24" height="24" viewBox="0 0 24 24">
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path d="M0 0h24v24H0z" fill="#878787" fillOpacity=".01" />
|
||||
<path stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"
|
||||
d="M8.036 10.93l3.93 4.07 4.068-3.93" />
|
||||
<path stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" d="M8.036 10.93l3.93 4.07 4.068-3.93" />
|
||||
</g>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
@@ -9,11 +9,12 @@ import round from 'lodash/round';
|
||||
import { useSelector } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import './Line.css';
|
||||
import { msToDays } from '../../helpers/helpers';
|
||||
|
||||
const Line = ({
|
||||
data, color = 'black',
|
||||
}) => {
|
||||
const interval = useSelector((state) => state.stats.interval);
|
||||
const interval = msToDays(useSelector((state) => state.stats.interval));
|
||||
|
||||
return <ResponsiveLine
|
||||
enableArea
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
background-color: var(--rt-nodata-bgcolor);
|
||||
}
|
||||
|
||||
.overlay--visible {
|
||||
|
||||
@@ -5047,9 +5047,9 @@ tbody.collapse.show {
|
||||
}
|
||||
|
||||
.alert-primary {
|
||||
color: #24426c;
|
||||
background-color: #dae5f5;
|
||||
border-color: #cbdbf2;
|
||||
color: var(--alert-message-color);
|
||||
background-color: var(--alert-message-bg);
|
||||
border-color: var(--alert-message-border);
|
||||
}
|
||||
|
||||
.alert-primary hr {
|
||||
@@ -5089,9 +5089,9 @@ tbody.collapse.show {
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: #24587e;
|
||||
background-color: #daeefc;
|
||||
border-color: #cbe7fb;
|
||||
color: var(--alert-message-color);
|
||||
background-color: var(--alert-message-bg);
|
||||
border-color: var(--alert-message-border);
|
||||
}
|
||||
|
||||
.alert-info hr {
|
||||
@@ -10216,6 +10216,18 @@ body.fixed-header .page {
|
||||
line-height: 2.5rem;
|
||||
}
|
||||
|
||||
.page-title__protection {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.page-title__protection {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.page-title-icon {
|
||||
color: #9aa0ac;
|
||||
font-size: 1.25rem;
|
||||
@@ -14317,7 +14329,7 @@ textarea[cols] {
|
||||
|
||||
.custom-control-label:before {
|
||||
border: 1px solid rgba(0, 40, 100, 0.12);
|
||||
background-color: #fff;
|
||||
background-color: var(--radio-bg);
|
||||
background-size: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ const Version = () => {
|
||||
disabled={processingVersion}
|
||||
title={t('check_updates_now')}
|
||||
>
|
||||
<svg className="icons">
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#refresh" />
|
||||
</svg>
|
||||
</button>}
|
||||
|
||||
@@ -53,7 +53,7 @@ export const STATUS_COLORS = {
|
||||
export const REPOSITORY = {
|
||||
URL: 'https://github.com/AdguardTeam/AdGuardHome',
|
||||
TRACKERS_DB:
|
||||
'https://github.com/AdguardTeam/AdGuardHome/tree/master/client/src/helpers/trackers/adguard.json',
|
||||
'https://github.com/AdguardTeam/AdGuardHome/tree/master/client/src/helpers/trackers/trackers.json',
|
||||
ISSUES: 'https://github.com/AdguardTeam/AdGuardHome/issues/new/choose',
|
||||
};
|
||||
|
||||
@@ -211,9 +211,20 @@ export const FILTERED = 'Filtered';
|
||||
export const NOT_FILTERED = 'NotFiltered';
|
||||
|
||||
export const DISABLED_STATS_INTERVAL = 0;
|
||||
export const STATS_INTERVALS_DAYS = [1, 7, 30, 90];
|
||||
|
||||
export const QUERY_LOG_INTERVALS_DAYS = [0.25, 1, 7, 30, 90];
|
||||
export const HOUR = 60 * 60 * 1000;
|
||||
|
||||
export const DAY = HOUR * 24;
|
||||
|
||||
export const STATS_INTERVALS_DAYS = [DAY, DAY * 7, DAY * 30, DAY * 90];
|
||||
|
||||
export const QUERY_LOG_INTERVALS_DAYS = [HOUR * 6, DAY, DAY * 7, DAY * 30, DAY * 90];
|
||||
|
||||
export const RETENTION_CUSTOM = 1;
|
||||
|
||||
export const RETENTION_CUSTOM_INPUT = 'custom_retention_input';
|
||||
|
||||
export const CUSTOM_INTERVAL = 'customInterval';
|
||||
|
||||
export const FILTERS_INTERVALS_HOURS = [0, 1, 12, 24, 72, 168];
|
||||
|
||||
@@ -457,6 +468,11 @@ export const UINT32_RANGE = {
|
||||
MAX: 4294967295,
|
||||
};
|
||||
|
||||
export const RETENTION_RANGE = {
|
||||
MIN: 1,
|
||||
MAX: 365 * 24,
|
||||
};
|
||||
|
||||
export const DHCP_VALUES_PLACEHOLDERS = {
|
||||
ipv4: {
|
||||
subnet_mask: '255.255.255.0',
|
||||
@@ -493,6 +509,8 @@ export const TOAST_TYPES = {
|
||||
};
|
||||
|
||||
export const SUCCESS_TOAST_TIMEOUT = 5000;
|
||||
|
||||
export const ONE_SECOND_IN_MS = 1000;
|
||||
export const FAILURE_TOAST_TIMEOUT = 30000;
|
||||
|
||||
export const TOAST_TIMEOUTS = {
|
||||
@@ -521,3 +539,14 @@ export const MOBILE_CONFIG_LINKS = {
|
||||
DOT: 'apple/dot.mobileconfig',
|
||||
DOH: 'apple/doh.mobileconfig',
|
||||
};
|
||||
|
||||
// Timings for disable protection in milliseconds
|
||||
export const DISABLE_PROTECTION_TIMINGS = {
|
||||
HALF_MINUTE: 30 * 1000,
|
||||
MINUTE: 60 * 1000,
|
||||
TEN_MINUTES: 10 * 60 * 1000,
|
||||
HOUR: 60 * 60 * 1000,
|
||||
TOMORROW: 24 * 60 * 60 * 1000,
|
||||
};
|
||||
|
||||
export const LOCAL_STORAGE_THEME_KEY = 'account_theme';
|
||||
|
||||
@@ -100,8 +100,14 @@ export default {
|
||||
"homepage": "https://github.com/DandelionSprout/adfilt",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_13.txt"
|
||||
},
|
||||
"POL_cert_polska_list_of_malicious_domains": {
|
||||
"name": "POL: CERT Polska List of malicious domains",
|
||||
"categoryId": "regional",
|
||||
"homepage": "https://cert.pl/posts/2020/03/ostrzezenia_phishing/",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_41.txt"
|
||||
},
|
||||
"POL_polish_filters_for_pi_hole": {
|
||||
"name": "POL: Polish filters for Pi hole",
|
||||
"name": "POL: Polish filters for Pi-hole",
|
||||
"categoryId": "regional",
|
||||
"homepage": "https://www.certyficate.it/",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_14.txt"
|
||||
@@ -118,6 +124,12 @@ export default {
|
||||
"homepage": "https://github.com/bkrucarci/turk-adlist",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_26.txt"
|
||||
},
|
||||
"TUR_turkish_ad_hosts": {
|
||||
"name": "TUR: Turkish Ad Hosts",
|
||||
"categoryId": "regional",
|
||||
"homepage": "https://github.com/symbuzzer/Turkish-Ad-Hosts",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_40.txt"
|
||||
},
|
||||
"VNM_abpvn": {
|
||||
"name": "VNM: ABPVN List",
|
||||
"categoryId": "regional",
|
||||
@@ -160,12 +172,6 @@ export default {
|
||||
"homepage": "https://github.com/DandelionSprout/adfilt",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_6.txt"
|
||||
},
|
||||
"energized_spark": {
|
||||
"name": "Energized Spark",
|
||||
"categoryId": "general",
|
||||
"homepage": "https://energized.pro/",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_28.txt"
|
||||
},
|
||||
"hagezi_personal": {
|
||||
"name": "HaGeZi Personal Black \u0026 White",
|
||||
"categoryId": "general",
|
||||
@@ -191,13 +197,13 @@ export default {
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_32.txt"
|
||||
},
|
||||
"oisd_basic": {
|
||||
"name": "OISD Blocklist Basic",
|
||||
"name": "OISD Blocklist Small",
|
||||
"categoryId": "general",
|
||||
"homepage": "https://oisd.nl/",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_5.txt"
|
||||
},
|
||||
"oisd_full": {
|
||||
"name": "OISD Blocklist Full",
|
||||
"name": "OISD Blocklist Big",
|
||||
"categoryId": "general",
|
||||
"homepage": "https://oisd.nl/",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_27.txt"
|
||||
@@ -220,6 +226,12 @@ export default {
|
||||
"homepage": "https://github.com/durablenapkin/scamblocklist",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_10.txt"
|
||||
},
|
||||
"shadowwhisperers_malware_list": {
|
||||
"name": "ShadowWhisperer's Malware List",
|
||||
"categoryId": "security",
|
||||
"homepage": "https://github.com/ShadowWhisperer/BlockLists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_42.txt"
|
||||
},
|
||||
"staklerware_indicators_list": {
|
||||
"name": "Stalkerware Indicators List",
|
||||
"categoryId": "security",
|
||||
@@ -241,7 +253,7 @@ export default {
|
||||
"urlhaus_filter_online": {
|
||||
"name": "Malicious URL Blocklist (URLHaus)",
|
||||
"categoryId": "security",
|
||||
"homepage": "https://gitlab.com/malware-filter/urlhaus-filter",
|
||||
"homepage": "https://urlhaus.abuse.ch/",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_11.txt"
|
||||
},
|
||||
"windowsspyblocker_hosts_spy_rules": {
|
||||
|
||||
@@ -25,6 +25,8 @@ import {
|
||||
STANDARD_HTTPS_PORT,
|
||||
STANDARD_WEB_PORT,
|
||||
SPECIAL_FILTER_ID,
|
||||
THEMES,
|
||||
LOCAL_STORAGE_THEME_KEY,
|
||||
} from './constants';
|
||||
|
||||
/**
|
||||
@@ -388,6 +390,12 @@ export const toggleAllServices = (services, change, isSelected) => {
|
||||
services.forEach((service) => change(`blocked_services.${service.id}`, isSelected));
|
||||
};
|
||||
|
||||
export const msToSeconds = (milliseconds) => Math.floor(milliseconds / 1000);
|
||||
|
||||
export const msToMinutes = (milliseconds) => Math.floor(milliseconds / 1000 / 60);
|
||||
|
||||
export const msToHours = (milliseconds) => Math.floor(milliseconds / 1000 / 60 / 60);
|
||||
|
||||
export const secondsToMilliseconds = (seconds) => {
|
||||
if (seconds) {
|
||||
return seconds * 1000;
|
||||
@@ -396,6 +404,8 @@ export const secondsToMilliseconds = (seconds) => {
|
||||
return seconds;
|
||||
};
|
||||
|
||||
export const msToDays = (milliseconds) => Math.floor(milliseconds / 1000 / 60 / 60 / 24);
|
||||
|
||||
export const normalizeRulesTextarea = (text) => text?.replace(/^\n/g, '')
|
||||
.replace(/\n\s*\n/g, '\n');
|
||||
|
||||
@@ -670,13 +680,61 @@ export const setHtmlLangAttr = (language) => {
|
||||
window.document.documentElement.lang = language;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set local storage field
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {string} value
|
||||
*/
|
||||
|
||||
export const setStorageItem = (key, value) => {
|
||||
if (window.localStorage) {
|
||||
window.localStorage.setItem(key, value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get local storage field
|
||||
*
|
||||
* @param {string} key
|
||||
*/
|
||||
|
||||
export const getStorageItem = (key) => (window.localStorage
|
||||
? window.localStorage.getItem(key)
|
||||
: null);
|
||||
|
||||
/**
|
||||
* Set local storage theme field
|
||||
*
|
||||
* @param {string} theme
|
||||
*/
|
||||
|
||||
export const setTheme = (theme) => {
|
||||
setStorageItem(LOCAL_STORAGE_THEME_KEY, theme);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get local storage theme field
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
export const getTheme = () => getStorageItem(LOCAL_STORAGE_THEME_KEY) || THEMES.light;
|
||||
|
||||
/**
|
||||
* Sets UI theme.
|
||||
*
|
||||
* @param theme
|
||||
*/
|
||||
export const setUITheme = (theme) => {
|
||||
document.body.dataset.theme = theme;
|
||||
let currentTheme = theme || getTheme();
|
||||
|
||||
if (currentTheme === THEMES.auto) {
|
||||
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
currentTheme = prefersDark ? THEMES.dark : THEMES.light;
|
||||
}
|
||||
setTheme(currentTheme);
|
||||
document.body.dataset.theme = currentTheme;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
{
|
||||
"timeUpdated": "2021-12-15",
|
||||
"categories": {
|
||||
"0": "audio_video_player",
|
||||
"1": "comments",
|
||||
"2": "customer_interaction",
|
||||
"3": "pornvertising",
|
||||
"4": "advertising",
|
||||
"5": "essential",
|
||||
"6": "site_analytics",
|
||||
"7": "social_media",
|
||||
"8": "misc",
|
||||
"9": "cdn",
|
||||
"10": "hosting",
|
||||
"11": "unknown",
|
||||
"12": "extensions",
|
||||
"13": "email",
|
||||
"14": "consent",
|
||||
"15": "telemetry",
|
||||
"101": "mobile_analytics"
|
||||
},
|
||||
"trackers": {
|
||||
"akamai_technologies": {
|
||||
"name": "Akamai Technologies",
|
||||
"categoryId": 9,
|
||||
"url": "https://www.akamai.com/",
|
||||
"companyId": "akamai"
|
||||
},
|
||||
"apple": {
|
||||
"name": "Apple",
|
||||
"categoryId": 8,
|
||||
"url": "https://www.apple.com/",
|
||||
"companyId": "apple"
|
||||
},
|
||||
"apple_ads": {
|
||||
"name": "Apple Search Ads",
|
||||
"categoryId": 4,
|
||||
"url": "https://searchads.apple.com/",
|
||||
"companyId": "apple"
|
||||
},
|
||||
"facebook_audience": {
|
||||
"name": "Facebook Audience Network",
|
||||
"categoryId": 4,
|
||||
"url": "https://www.facebook.com/business/products/audience-network",
|
||||
"companyId": "facebook"
|
||||
},
|
||||
"crashlytics": {
|
||||
"name": "Crashlytics",
|
||||
"categoryId": 101,
|
||||
"url": "https://crashlytics.com/",
|
||||
"companyId": null
|
||||
},
|
||||
"flurry": {
|
||||
"name": "Flurry",
|
||||
"categoryId": 101,
|
||||
"url": "http://www.flurry.com/",
|
||||
"companyId": "verizon"
|
||||
},
|
||||
"hockeyapp": {
|
||||
"name": "HockeyApp",
|
||||
"categoryId": 101,
|
||||
"url": "https://hockeyapp.net/",
|
||||
"companyId": null
|
||||
},
|
||||
"firebase": {
|
||||
"name": "Firebase",
|
||||
"categoryId": 101,
|
||||
"url": "https://firebase.google.com/",
|
||||
"companyId": "google"
|
||||
},
|
||||
"appsflyer": {
|
||||
"name": "AppsFlyer",
|
||||
"categoryId": 101,
|
||||
"url": "https://www.appsflyer.com/",
|
||||
"companyId": "appsflyer"
|
||||
},
|
||||
"yandex_appmetrica": {
|
||||
"name": "Yandex AppMetrica",
|
||||
"categoryId": 101,
|
||||
"url": "https://appmetrica.yandex.com/",
|
||||
"companyId": "yandex"
|
||||
},
|
||||
"adjust": {
|
||||
"name": "Adjust",
|
||||
"categoryId": 101,
|
||||
"url": "https://www.adjust.com/",
|
||||
"companyId": "adjust"
|
||||
},
|
||||
"branch": {
|
||||
"name": "Branch.io",
|
||||
"categoryId": 101,
|
||||
"url": "https://branch.io/",
|
||||
"companyId": "branch_metrics_inc"
|
||||
},
|
||||
"markmonitor": {
|
||||
"name": "MarkMonitor",
|
||||
"categoryId": 4,
|
||||
"url": "https://www.markmonitor.com/",
|
||||
"companyId": "markmonitor"
|
||||
},
|
||||
"appcenter": {
|
||||
"name": "Microsoft App Center",
|
||||
"categoryId": 5,
|
||||
"url": "https://appcenter.ms/",
|
||||
"companyId": null
|
||||
},
|
||||
"unity_ads": {
|
||||
"name": "Unity Ads",
|
||||
"categoryId": 4,
|
||||
"url": "https://unity.com/solutions/mobile-business/monetize-your-game",
|
||||
"companyId": null
|
||||
},
|
||||
"azure": {
|
||||
"name": "Microsoft Azure",
|
||||
"categoryId": 10,
|
||||
"url": "https://azure.microsoft.com/",
|
||||
"companyId": "microsoft"
|
||||
},
|
||||
"button": {
|
||||
"name": "Button",
|
||||
"categoryId": 4,
|
||||
"url": "https://www.usebutton.com/",
|
||||
"companyId": null
|
||||
},
|
||||
"netflix": {
|
||||
"name": "Netflix",
|
||||
"categoryId": 8,
|
||||
"url": "https://www.netflix.com/",
|
||||
"companyId": null
|
||||
},
|
||||
"mail.ru_banner": {
|
||||
"name": "Mail.Ru Banner Network",
|
||||
"categoryId": 4,
|
||||
"url": "http://mail.ru/",
|
||||
"companyId": "vk"
|
||||
},
|
||||
"mail.ru_counter": {
|
||||
"name": "Mail.Ru Counter",
|
||||
"categoryId": 2,
|
||||
"url": "http://mail.ru/",
|
||||
"companyId": "vk"
|
||||
},
|
||||
"mail.ru_group": {
|
||||
"name": "Mail.Ru Group",
|
||||
"categoryId": 7,
|
||||
"url": "http://mail.ru/",
|
||||
"companyId": "vk"
|
||||
}
|
||||
},
|
||||
"trackerDomains": {
|
||||
"akadns.net": "akamai_technologies",
|
||||
"akamaiedge.net": "akamai_technologies",
|
||||
"apple.com": "apple",
|
||||
"apple.news": "apple",
|
||||
"apple-dns.net": "apple",
|
||||
"aaplimg.com": "apple",
|
||||
"icloud.com": "apple",
|
||||
"mzstatic.com": "apple",
|
||||
"iadsdk.apple.com": "apple_ads",
|
||||
"graph.facebook.com": "facebook_audience",
|
||||
"crashlytics.com": "crashlytics",
|
||||
"flurry.com": "flurry",
|
||||
"hockeyapp.net": "hockeyapp",
|
||||
"app-measurement.com": "firebase",
|
||||
"appsflyer.com": "appsflyer",
|
||||
"appmetrica.yandex.com": "yandex_appmetrica",
|
||||
"adjust.com": "adjust",
|
||||
"mobileapptracking.com": "branch",
|
||||
"edgecastcdn.net": "markmonitor",
|
||||
"appcenter.ms": "appcenter",
|
||||
"unityads.unity3d.com": "unity_ads",
|
||||
"azure.com": "azure",
|
||||
"bttn.io": "button"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import whotracksmeDb from './whotracksme.json';
|
||||
import whotracksmeWebsites from './whotracksme_web.json';
|
||||
import adguardDb from './adguard.json';
|
||||
import trackersDb from './trackers.json';
|
||||
import { REPOSITORY } from '../constants';
|
||||
|
||||
/**
|
||||
@@ -39,6 +38,7 @@ const getWhotracksmeUrl = (trackerId) => {
|
||||
|
||||
/**
|
||||
* Gets the source metadata for the specified tracker
|
||||
*
|
||||
* @param {TrackerData} trackerData tracker data
|
||||
* @returns {source} source metadata or null if no matching tracker found
|
||||
*/
|
||||
@@ -64,14 +64,26 @@ export const getSourceData = (trackerData) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets tracker data in the specified database
|
||||
* Converts the JSON string source into numeric source for AdGuard Home
|
||||
*
|
||||
* @param {TrackerData} trackerData tracker data
|
||||
* @returns {number} source number
|
||||
*/
|
||||
const convertSource = (sourceStr) => {
|
||||
if (!sourceStr || sourceStr !== 'AdGuard') {
|
||||
return sources.WHOTRACKSME;
|
||||
}
|
||||
|
||||
return sources.ADGUARD;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets tracker data from the trackers database
|
||||
*
|
||||
* @param {String} domainName domain name to check
|
||||
* @param {*} trackersDb trackers database
|
||||
* @param {number} source source ID
|
||||
* @returns {TrackerData} tracker data or null if no matching tracker found
|
||||
*/
|
||||
const getTrackerDataFromDb = (domainName, trackersDb, source) => {
|
||||
export const getTrackerData = (domainName) => {
|
||||
if (!domainName) {
|
||||
return null;
|
||||
}
|
||||
@@ -88,7 +100,7 @@ const getTrackerDataFromDb = (domainName, trackersDb, source) => {
|
||||
if (trackerId) {
|
||||
const trackerData = trackersDb.trackers[trackerId];
|
||||
const categoryName = trackersDb.categories[trackerData.categoryId];
|
||||
trackerData.source = source;
|
||||
const source = convertSource(trackerData.source);
|
||||
const sourceData = getSourceData(trackerData);
|
||||
|
||||
return {
|
||||
@@ -105,22 +117,3 @@ const getTrackerDataFromDb = (domainName, trackersDb, source) => {
|
||||
// No tracker found for the specified domain
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets tracker data from the trackers database
|
||||
*
|
||||
* @param {String} domainName domain name to check
|
||||
* @returns {TrackerData} tracker data or null if no matching tracker found
|
||||
*/
|
||||
export const getTrackerData = (domainName) => {
|
||||
if (!domainName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let data = getTrackerDataFromDb(domainName, adguardDb, sources.ADGUARD);
|
||||
if (!data) {
|
||||
data = getTrackerDataFromDb(domainName, whotracksmeDb, sources.WHOTRACKSME);
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user