Compare commits
35
Commits
v0.2.0
..
4b030cd7d2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b030cd7d2 | ||
|
|
b80fff7609 | ||
|
|
a6558576ab | ||
|
|
5ef796671f | ||
|
|
20b5c6e798 | ||
|
|
08eca1aac4 | ||
|
|
2ce736e10f | ||
|
|
8f8e77242b | ||
|
|
cf2cc9f8ed | ||
|
|
b616243d48 | ||
|
|
fd8bb16d40 | ||
|
|
ed9ed59de9 | ||
|
|
56038b7a7e | ||
|
|
8227024076 | ||
|
|
7a8465b7fb | ||
|
|
518f8cfe36 | ||
|
|
29e0ae9d48 | ||
|
|
82c07ad81a | ||
|
|
1fe24d22ed | ||
|
|
aaeb7636a1 | ||
|
|
1df9c2f00c | ||
|
|
d6ba6270c5 | ||
|
|
c5931c723f | ||
|
|
8cc8189820 | ||
|
|
dbf98d598d | ||
|
|
dbe8f2fb68 | ||
|
|
595d73a41d | ||
|
|
af5f65f166 | ||
|
|
4c72cdab29 | ||
|
|
5b3aa3bf37 | ||
|
|
f3dd13d831 | ||
|
|
4596b93bb6 | ||
|
|
adc061ae26 | ||
|
|
d84902c111 | ||
|
|
5be8e31483 |
@@ -0,0 +1,32 @@
|
|||||||
|
## [0.4.0] - 2026-10-09
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Added more themes
|
||||||
|
- Added Minimize to System Tray While Monitor Is Running. Closes #6.
|
||||||
|
- Added Desktop Notifications While Minimized. This Will Send Notifications to the Desktop if a Host Status Changes While It’s Minimized to the System Tray. Closes #12.
|
||||||
|
## [0.3.0] - 2026-10-08
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Added Auto Labeling to Montior Tab. When sending hosts from the scan tab, it will bring their hostnames over to the label section. When adding a one off host to the montior tab, it will auto query it's hostname. You can also edit labels by double clicking. Closes #3
|
||||||
|
- Added Always on Top Toggle. Closes #5
|
||||||
|
- Added New Theme
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Status Colors on Monitor tab now reflect status of host. Closes #7
|
||||||
|
- Removed unused function.
|
||||||
|
- Fixed Screen Refresh Bug on Monitor Tab. Now When You Go To Change a Label While the Monitor Is Running. The Page Stops Refreshing Until You’re Done Changing the Name. This Is To Prevent Your Text Box From Being Deselected When the Table Refreshes.
|
||||||
|
## [0.2.0] - 2026-09-24
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Added changelog
|
||||||
|
- Added Themes
|
||||||
|
- Added Virtual Scrolling. This allows us to scan a whole /16 subnet without overloading the UI or using a lot of RAM.
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Fixed updater to only check for newer version using proper semver checking. Before it only checked if the current in use version was different than what was available.
|
||||||
|
## [0.1.0] - 2026-09-23
|
||||||
+1
-1
@@ -625,7 +625,7 @@ state the exclusion of warranty; and each file should have at least
|
|||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
Argus, an all in one network utility
|
Argus, an all in one network utility
|
||||||
Copyright (C) 2026 Jamse Brotosky
|
Copyright (C) 2026 James Brotosky
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
cd src-tauri && cargo clean
|
||||||
|
cargo clippy --fix --all-targets --allow-dirty
|
||||||
|
cargo fmt
|
||||||
|
cargo tauri build
|
||||||
|
cargo tauri build --runner cargo-xwin --target x86_64-pc-windows-msvc
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
# git-cliff ~ configuration file
|
||||||
|
# https://git-cliff.org/docs/configuration
|
||||||
|
|
||||||
|
|
||||||
|
[changelog]
|
||||||
|
# A Tera template to be rendered for each release in the changelog.
|
||||||
|
# See https://keats.github.io/tera/docs/#introduction
|
||||||
|
body = """
|
||||||
|
{% if version %}\
|
||||||
|
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||||
|
{% else %}\
|
||||||
|
## [unreleased]
|
||||||
|
{% endif %}\
|
||||||
|
{% for group, commits in commits | group_by(attribute="group") %}
|
||||||
|
### {{ group | striptags | trim | upper_first }}
|
||||||
|
{% for commit in commits %}
|
||||||
|
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
|
||||||
|
{% if commit.breaking %}[**breaking**] {% endif %}\
|
||||||
|
{{ commit.message | upper_first }}\
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
"""
|
||||||
|
# Remove leading and trailing whitespaces from the changelog's body.
|
||||||
|
trim = true
|
||||||
|
# Render body even when there are no releases to process.
|
||||||
|
render_always = true
|
||||||
|
# An array of regex based postprocessors to modify the changelog.
|
||||||
|
postprocessors = [
|
||||||
|
# Replace the placeholder <REPO> with a URL.
|
||||||
|
#{ pattern = '<REPO>', replace = "https://github.com/orhun/git-cliff" },
|
||||||
|
]
|
||||||
|
# render body even when there are no releases to process
|
||||||
|
# render_always = true
|
||||||
|
# output file path
|
||||||
|
# output = "test.md"
|
||||||
|
|
||||||
|
[git]
|
||||||
|
# Parse commits according to the conventional commits specification.
|
||||||
|
# See https://www.conventionalcommits.org
|
||||||
|
conventional_commits = true
|
||||||
|
# Exclude commits that do not match the conventional commits specification.
|
||||||
|
filter_unconventional = true
|
||||||
|
# Require all commits to be conventional.
|
||||||
|
# Takes precedence over filter_unconventional.
|
||||||
|
require_conventional = false
|
||||||
|
# Split commits on newlines, treating each line as an individual commit.
|
||||||
|
split_commits = false
|
||||||
|
# An array of regex based parsers to modify commit messages prior to further processing.
|
||||||
|
commit_preprocessors = [
|
||||||
|
# Replace issue numbers with link templates to be updated in `changelog.postprocessors`.
|
||||||
|
#{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"},
|
||||||
|
# Check spelling of the commit message using https://github.com/crate-ci/typos.
|
||||||
|
# If the spelling is incorrect, it will be fixed automatically.
|
||||||
|
#{ pattern = '.*', replace_command = 'typos --write-changes -' },
|
||||||
|
]
|
||||||
|
# Prevent commits that are breaking from being excluded by commit parsers.
|
||||||
|
protect_breaking_commits = false
|
||||||
|
# An array of regex based parsers for extracting data from the commit message.
|
||||||
|
# Assigns commits to groups.
|
||||||
|
# Optionally sets the commit's scope and can decide to exclude commits from further processing.
|
||||||
|
commit_parsers = [
|
||||||
|
{ message = "^feat", group = "<!-- 0 -->🚀 Features" },
|
||||||
|
{ message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" },
|
||||||
|
{ message = "^doc", group = "<!-- 3 -->📚 Documentation" },
|
||||||
|
{ message = "^perf", group = "<!-- 4 -->⚡ Performance" },
|
||||||
|
{ message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
|
||||||
|
{ message = "^style", group = "<!-- 5 -->🎨 Styling" },
|
||||||
|
{ message = "^test", group = "<!-- 6 -->🧪 Testing" },
|
||||||
|
{ message = "^chore\\(release\\): prepare for", skip = true },
|
||||||
|
{ message = "^chore\\(deps.*\\)", skip = true },
|
||||||
|
{ message = "^chore\\(pr\\)", skip = true },
|
||||||
|
{ message = "^chore\\(pull\\)", skip = true },
|
||||||
|
{ message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" },
|
||||||
|
{ body = ".*security", group = "<!-- 8 -->🛡️ Security" },
|
||||||
|
{ message = "^revert", group = "<!-- 9 -->◀️ Revert" },
|
||||||
|
{ message = ".*", group = "<!-- 10 -->💼 Other" },
|
||||||
|
]
|
||||||
|
# Exclude commits that are not matched by any commit parser.
|
||||||
|
filter_commits = false
|
||||||
|
# Fail on a commit that is not matched by any commit parser.
|
||||||
|
fail_on_unmatched_commit = false
|
||||||
|
# An array of link parsers for extracting external references, and turning them into URLs, using regex.
|
||||||
|
link_parsers = []
|
||||||
|
# Include only the tags that belong to the current branch.
|
||||||
|
use_branch_tags = false
|
||||||
|
# Order releases topologically instead of chronologically.
|
||||||
|
topo_order = false
|
||||||
|
# Order commits topologically instead of chronologically.
|
||||||
|
topo_order_commits = true
|
||||||
|
# Order of commits in each group/release within the changelog.
|
||||||
|
# Allowed values: newest, oldest
|
||||||
|
sort_commits = "oldest"
|
||||||
|
# Process submodules commits
|
||||||
|
recurse_submodules = false
|
||||||
Generated
+224
-186
@@ -19,15 +19,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloc-no-stdlib"
|
name = "alloc-no-stdlib"
|
||||||
version = "2.0.4"
|
version = "3.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
|
checksum = "c2fb6cfd47bf496ff64095c20eaba0c201404ee38714d4142fcfa1dc334fcc7a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloc-stdlib"
|
name = "alloc-stdlib"
|
||||||
version = "0.2.4"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195"
|
checksum = "0b5c1865780388bfa186411ab5f247819487fc4864c6e9c3106611fa347586e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloc-no-stdlib",
|
"alloc-no-stdlib",
|
||||||
]
|
]
|
||||||
@@ -49,7 +49,7 @@ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "argus"
|
name = "argus"
|
||||||
version = "0.1.0"
|
version = "0.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"csv",
|
"csv",
|
||||||
"dns-lookup",
|
"dns-lookup",
|
||||||
@@ -58,13 +58,17 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"open",
|
"open",
|
||||||
"ping-async",
|
"ping-async",
|
||||||
|
"pulldown-cmark",
|
||||||
"reqwest 0.12.28",
|
"reqwest 0.12.28",
|
||||||
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
"tauri-plugin-dialog",
|
"tauri-plugin-dialog",
|
||||||
|
"tauri-plugin-notification",
|
||||||
"tauri-plugin-opener",
|
"tauri-plugin-opener",
|
||||||
|
"tauri-plugin-single-instance",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
@@ -317,9 +321,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "brotli"
|
name = "brotli"
|
||||||
version = "8.0.4"
|
version = "9.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3"
|
checksum = "f8b851b75c23ca7873623d612fe49bd1989aeb03d08fb9432187eb253d3d4c6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloc-no-stdlib",
|
"alloc-no-stdlib",
|
||||||
"alloc-stdlib",
|
"alloc-stdlib",
|
||||||
@@ -328,9 +332,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "brotli-decompressor"
|
name = "brotli-decompressor"
|
||||||
version = "5.0.3"
|
version = "6.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583"
|
checksum = "941cd9bd4ddab83cb46fa5a2d428f1c857b24ac78cb876cf7beb710840934bd7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloc-no-stdlib",
|
"alloc-no-stdlib",
|
||||||
"alloc-stdlib",
|
"alloc-stdlib",
|
||||||
@@ -431,12 +435,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cargo_toml"
|
name = "cargo_toml"
|
||||||
version = "0.22.3"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77"
|
checksum = "82f4b26e751e711a5302649417f2da046dce6391b2ea30a4820f37462314f0b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"toml 0.9.12+spec-1.1.0",
|
"toml 1.1.6+spec-1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -457,13 +462,13 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfb"
|
name = "cfb"
|
||||||
version = "0.7.3"
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f"
|
checksum = "a347dcabdae9c31b0825fd6a8bed285ec9c2acb89c47827126d52fa4f59cece3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
|
||||||
"fnv",
|
"fnv",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"web-time",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -624,9 +629,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.36.0"
|
version = "0.37.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2"
|
checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cssparser-macros",
|
"cssparser-macros",
|
||||||
"dtoa-short",
|
"dtoa-short",
|
||||||
@@ -637,12 +642,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser-macros"
|
name = "cssparser-macros"
|
||||||
version = "0.6.1"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
checksum = "d045de693cb712d0b22c6a64be5b953f67b3ce00ab5ad3dd5d8b441886ab8e1a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.119",
|
"syn 3.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -668,19 +673,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctor"
|
name = "ctor"
|
||||||
version = "0.8.0"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98"
|
checksum = "914a755b7c2d4af2bdcff7ce1739e2db9a1b81a9b07123d8015786ae03c0980d"
|
||||||
dependencies = [
|
|
||||||
"ctor-proc-macro",
|
|
||||||
"dtor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ctor-proc-macro"
|
|
||||||
version = "0.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
@@ -800,9 +795,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "6.0.0"
|
version = "7.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs-sys",
|
"dirs-sys",
|
||||||
]
|
]
|
||||||
@@ -879,9 +874,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dom_query"
|
name = "dom_query"
|
||||||
version = "0.27.0"
|
version = "0.28.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89"
|
checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-set",
|
"bit-set",
|
||||||
"cssparser",
|
"cssparser",
|
||||||
@@ -916,21 +911,6 @@ dependencies = [
|
|||||||
"dtoa",
|
"dtoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dtor"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4"
|
|
||||||
dependencies = [
|
|
||||||
"dtor-proc-macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dtor-proc-macro"
|
|
||||||
version = "0.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dunce"
|
name = "dunce"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@@ -1367,6 +1347,15 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getopts"
|
||||||
|
version = "0.2.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@@ -1606,9 +1595,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "html5ever"
|
name = "html5ever"
|
||||||
version = "0.38.0"
|
version = "0.39.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2"
|
checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"markup5ever",
|
"markup5ever",
|
||||||
@@ -1899,9 +1888,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "infer"
|
name = "infer"
|
||||||
version = "0.19.0"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7"
|
checksum = "f4200d433cbd5178df7797c9c2e75b348b728e39631cf14520d1e2fc424201f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfb",
|
"cfb",
|
||||||
]
|
]
|
||||||
@@ -2089,21 +2078,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "json-patch"
|
name = "json-patch"
|
||||||
version = "3.0.1"
|
version = "4.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08"
|
checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jsonptr",
|
"jsonptr",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror 1.0.69",
|
"thiserror 2.0.20",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonptr"
|
name = "jsonptr"
|
||||||
version = "0.6.3"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70"
|
checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -2111,13 +2100,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "keyboard-types"
|
name = "keyboard-types"
|
||||||
version = "0.7.0"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
|
checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.2",
|
"bitflags 2.13.2",
|
||||||
"serde",
|
"serde",
|
||||||
"unicode-segmentation",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2212,10 +2200,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
|
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markup5ever"
|
name = "mac-notification-sys"
|
||||||
version = "0.38.0"
|
version = "0.6.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862"
|
checksum = "fd604973958ddcc11b561193c0fb96ba146506ef2f231ef2e7c35fd2cbc9beca"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"log",
|
||||||
|
"objc2",
|
||||||
|
"objc2-foundation",
|
||||||
|
"time",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markup5ever"
|
||||||
|
version = "0.39.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"tendril",
|
"tendril",
|
||||||
@@ -2285,9 +2287,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "muda"
|
name = "muda"
|
||||||
version = "0.19.3"
|
version = "0.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878"
|
checksum = "cca139e57da4383727f189e43e66e84fa372347027fc996f9f1a007ec0a37996"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"dpi",
|
"dpi",
|
||||||
@@ -2363,6 +2365,12 @@ dependencies = [
|
|||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndk-context"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk-sys"
|
name = "ndk-sys"
|
||||||
version = "0.6.0+11769913"
|
version = "0.6.0+11769913"
|
||||||
@@ -2378,6 +2386,20 @@ version = "1.0.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "notify-rust"
|
||||||
|
version = "4.18.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4587364a9a0074333429b3df75a30a205340c56a536ca3eb6ca0e59b87bbf8af"
|
||||||
|
dependencies = [
|
||||||
|
"futures-lite",
|
||||||
|
"log",
|
||||||
|
"mac-notification-sys",
|
||||||
|
"serde",
|
||||||
|
"tauri-winrt-notification",
|
||||||
|
"zbus",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.50.3"
|
version = "0.50.3"
|
||||||
@@ -2445,6 +2467,7 @@ dependencies = [
|
|||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
|
"objc2-quartz-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3006,6 +3029,25 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pulldown-cmark"
|
||||||
|
version = "0.13.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.2",
|
||||||
|
"getopts",
|
||||||
|
"memchr",
|
||||||
|
"pulldown-cmark-escape",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pulldown-cmark-escape"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
@@ -3424,9 +3466,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selectors"
|
name = "selectors"
|
||||||
version = "0.36.1"
|
version = "0.38.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c"
|
checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.2",
|
"bitflags 2.13.2",
|
||||||
"cssparser",
|
"cssparser",
|
||||||
@@ -3893,9 +3935,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tao"
|
name = "tao"
|
||||||
version = "0.35.3"
|
version = "0.37.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9"
|
checksum = "f37f381f4e048e6cdf038b5705f8cf14ad108279d46eb968140a7b291aba9400"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.2",
|
"bitflags 2.13.2",
|
||||||
"block2",
|
"block2",
|
||||||
@@ -3913,20 +3955,20 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk",
|
||||||
|
"ndk-context",
|
||||||
"ndk-sys",
|
"ndk-sys",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
"once_cell",
|
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"tao-macros",
|
"tao-macros",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"url",
|
"url",
|
||||||
"windows 0.61.3",
|
"windows 0.62.2",
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.62.2",
|
||||||
"windows-version",
|
"windows-version",
|
||||||
"x11-dl",
|
"x11-dl",
|
||||||
]
|
]
|
||||||
@@ -3950,9 +3992,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri"
|
name = "tauri"
|
||||||
version = "2.11.6"
|
version = "2.12.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6fa5bacdb9bbad5954af3d1bd6cf6ae9192cab1b2e270f4a07f904610b9e85f4"
|
checksum = "d061d042ccd2df9c9f1508c1e63d835278c0a4c8801eb41764080e51f2eaaf34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -3996,14 +4038,14 @@ dependencies = [
|
|||||||
"webkit2gtk",
|
"webkit2gtk",
|
||||||
"webview2-com",
|
"webview2-com",
|
||||||
"window-vibrancy",
|
"window-vibrancy",
|
||||||
"windows 0.61.3",
|
"windows 0.62.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-build"
|
name = "tauri-build"
|
||||||
version = "2.6.3"
|
version = "2.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632"
|
checksum = "59563ca5b331fd97f27ee9672ec8d36d33bb3c9e2c9f6710a1a5687256052e45"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cargo_toml",
|
"cargo_toml",
|
||||||
@@ -4022,16 +4064,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-codegen"
|
name = "tauri-codegen"
|
||||||
version = "2.6.3"
|
version = "2.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5"
|
checksum = "e50213e463086ecc283d7e9f51c30cc0fd304ad457425158018be26dbf0d0a80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"brotli",
|
"brotli",
|
||||||
"ico",
|
"ico",
|
||||||
"json-patch",
|
"json-patch",
|
||||||
"plist",
|
"plist",
|
||||||
"png 0.17.16",
|
"png 0.18.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"semver",
|
"semver",
|
||||||
@@ -4049,9 +4091,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-macros"
|
name = "tauri-macros"
|
||||||
version = "2.6.3"
|
version = "2.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45"
|
checksum = "8129fb43bb6e0d6b73ad3315cd172beaab17cd28899c594b1b32c80edbbfd99c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -4063,9 +4105,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin"
|
name = "tauri-plugin"
|
||||||
version = "2.6.3"
|
version = "2.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020"
|
checksum = "1140cf34a3b3b836a13103dcab17f18831d5cc3534cbd435dc01a5c6daa65aa2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"glob",
|
"glob",
|
||||||
@@ -4119,6 +4161,25 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-notification"
|
||||||
|
version = "2.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "533770889abb60a0407d5a32096182f0e6463f5a3dfaa675be94580aa14070e1"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"notify-rust",
|
||||||
|
"rand",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_repr",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
"thiserror 2.0.20",
|
||||||
|
"time",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-opener"
|
name = "tauri-plugin-opener"
|
||||||
version = "2.5.5"
|
version = "2.5.5"
|
||||||
@@ -4142,10 +4203,26 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime"
|
name = "tauri-plugin-single-instance"
|
||||||
version = "2.11.3"
|
version = "2.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8"
|
checksum = "db817fe9295e19b7d8357e900af31edb93703dd9fb6de524b007b47b6afc63b0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tauri",
|
||||||
|
"thiserror 2.0.20",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
"zbus",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-runtime"
|
||||||
|
version = "2.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2a57a2a9b8c8b7fc00d35b510fe808ded7f9f1b44fc1cdda6aee38632ea5413"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cookie",
|
"cookie",
|
||||||
"dpi",
|
"dpi",
|
||||||
@@ -4163,14 +4240,14 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
"webkit2gtk",
|
"webkit2gtk",
|
||||||
"webview2-com",
|
"webview2-com",
|
||||||
"windows 0.61.3",
|
"windows 0.62.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime-wry"
|
name = "tauri-runtime-wry"
|
||||||
version = "2.11.4"
|
version = "2.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f"
|
checksum = "7f9e7e0c9f80a5130773cfabb6df4dc924518fb1b2c923726966804634b57d22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
@@ -4188,15 +4265,15 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
"webkit2gtk",
|
"webkit2gtk",
|
||||||
"webview2-com",
|
"webview2-com",
|
||||||
"windows 0.61.3",
|
"windows 0.62.2",
|
||||||
"wry",
|
"wry",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-utils"
|
name = "tauri-utils"
|
||||||
version = "2.9.3"
|
version = "2.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887"
|
checksum = "2ff55a614843b9a3f010f211df637c94df2607175b8d0f6e0f4a7c19e18621ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"brotli",
|
"brotli",
|
||||||
@@ -4241,6 +4318,17 @@ dependencies = [
|
|||||||
"toml 1.1.6+spec-1.1.0",
|
"toml 1.1.6+spec-1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-winrt-notification"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f37a6c354fd28fc9e322ed9bd47e3959576dad28c9d58ea1cf888cce1c7ccb36"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror 2.0.20",
|
||||||
|
"windows 0.62.2",
|
||||||
|
"windows-version",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.27.0"
|
version = "3.27.0"
|
||||||
@@ -4432,21 +4520,6 @@ dependencies = [
|
|||||||
"toml_edit 0.20.2",
|
"toml_edit 0.20.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml"
|
|
||||||
version = "0.9.12+spec-1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
|
|
||||||
dependencies = [
|
|
||||||
"indexmap 2.14.2",
|
|
||||||
"serde_core",
|
|
||||||
"serde_spanned 1.1.1",
|
|
||||||
"toml_datetime 0.7.5+spec-1.1.0",
|
|
||||||
"toml_parser",
|
|
||||||
"toml_writer",
|
|
||||||
"winnow 0.7.15",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "1.1.6+spec-1.1.0"
|
version = "1.1.6+spec-1.1.0"
|
||||||
@@ -4471,15 +4544,6 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml_datetime"
|
|
||||||
version = "0.7.5+spec-1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
|
|
||||||
dependencies = [
|
|
||||||
"serde_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "1.1.1+spec-1.1.0"
|
version = "1.1.1+spec-1.1.0"
|
||||||
@@ -4648,9 +4712,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tray-icon"
|
name = "tray-icon"
|
||||||
version = "0.24.2"
|
version = "0.25.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e"
|
checksum = "b2b9c52859a94554803ccd4a24b98f74148ebc73b90676d783f3490b1bff9d72"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"dirs",
|
"dirs",
|
||||||
@@ -4698,45 +4762,10 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unic-char-property"
|
name = "unicase"
|
||||||
version = "0.9.0"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
|
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||||
dependencies = [
|
|
||||||
"unic-char-range",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unic-char-range"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unic-common"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unic-ucd-ident"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987"
|
|
||||||
dependencies = [
|
|
||||||
"unic-char-property",
|
|
||||||
"unic-char-range",
|
|
||||||
"unic-ucd-version",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unic-ucd-version"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
|
|
||||||
dependencies = [
|
|
||||||
"unic-common",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
@@ -4750,6 +4779,12 @@ version = "1.13.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -4771,13 +4806,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urlpattern"
|
name = "urlpattern"
|
||||||
version = "0.3.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d"
|
checksum = "df16f50ef4cc145211879a3867ba757076b25dfee812040dcb0658bd9ae7904b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"icu_properties",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"unic-ucd-ident",
|
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4955,6 +4990,16 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-time"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web_atoms"
|
name = "web_atoms"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
@@ -5013,16 +5058,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webview2-com"
|
name = "webview2-com"
|
||||||
version = "0.38.2"
|
version = "0.39.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a"
|
checksum = "3f89fca7a704cee10dcb3654c1dbb8941d1783132f1917358af75bec37a7d7e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"webview2-com-macros",
|
"webview2-com-macros",
|
||||||
"webview2-com-sys",
|
"webview2-com-sys",
|
||||||
"windows 0.61.3",
|
"windows 0.62.2",
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.62.2",
|
||||||
"windows-implement",
|
|
||||||
"windows-interface",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5038,13 +5081,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webview2-com-sys"
|
name = "webview2-com-sys"
|
||||||
version = "0.38.2"
|
version = "0.39.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c"
|
checksum = "b3a07132775117d6065853d9d1178157b8c90e228de47129d6bce2c7edebedfb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror 2.0.20",
|
"thiserror 2.0.20",
|
||||||
"windows 0.61.3",
|
"windows 0.62.2",
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.62.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5080,16 +5123,17 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "window-vibrancy"
|
name = "window-vibrancy"
|
||||||
version = "0.6.0"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c"
|
checksum = "111e51caca442cafd9bab396628ac4d814880eaea4e63dfd76a12e9f342b5580"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
|
"objc2-quartz-core",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.61.2",
|
||||||
"windows-version",
|
"windows-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5552,12 +5596,6 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winnow"
|
|
||||||
version = "0.7.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@@ -5591,9 +5629,9 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wry"
|
name = "wry"
|
||||||
version = "0.55.1"
|
version = "0.57.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514"
|
checksum = "a819957a01b3119af85e638a38d242af76dbc87d130dca67bfd0441072e21ff0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"block2",
|
"block2",
|
||||||
@@ -5627,8 +5665,8 @@ dependencies = [
|
|||||||
"webkit2gtk",
|
"webkit2gtk",
|
||||||
"webkit2gtk-sys",
|
"webkit2gtk-sys",
|
||||||
"webview2-com",
|
"webview2-com",
|
||||||
"windows 0.61.3",
|
"windows 0.62.2",
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.62.2",
|
||||||
"windows-version",
|
"windows-version",
|
||||||
"x11-dl",
|
"x11-dl",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "argus"
|
name = "argus"
|
||||||
version = "0.1.0"
|
version = "0.4.0"
|
||||||
description = "An All in One Network Utility"
|
description = "An All in One Network Utility"
|
||||||
authors = ["James Brotosky <james.brotosky@racooncity.org"]
|
authors = ["James Brotosky <james.brotosky@racooncity.org"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -18,7 +18,8 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
|||||||
tauri-build = { version = "2", features = [] }
|
tauri-build = { version = "2", features = [] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tauri = { version = "2", features = [] }
|
tauri = { version = "2", features = ["tray-icon"] }
|
||||||
|
tauri-plugin-single-instance = "2"
|
||||||
tauri-plugin-opener = "2"
|
tauri-plugin-opener = "2"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
@@ -33,6 +34,9 @@ csv = "1"
|
|||||||
open = "5.4.4"
|
open = "5.4.4"
|
||||||
reqwest = { version = "0.12", features = ["json"] }
|
reqwest = { version = "0.12", features = ["json"] }
|
||||||
libc = "0.2.189"
|
libc = "0.2.189"
|
||||||
|
pulldown-cmark = { version = "0.13.4", features = ["html"] }
|
||||||
|
semver = "1.0.28"
|
||||||
|
tauri-plugin-notification = "2.5.1"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
is_elevated = "0.1"
|
is_elevated = "0.1"
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
"permissions": [
|
"permissions": [
|
||||||
"core:default",
|
"core:default",
|
||||||
"opener:default",
|
"opener:default",
|
||||||
"dialog:default"
|
"dialog:default",
|
||||||
|
"core:window:allow-set-always-on-top",
|
||||||
|
"notification:default",
|
||||||
|
"core:window:allow-is-visible"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
use pulldown_cmark::{html, Options, Parser};
|
||||||
|
|
||||||
|
const CHANGELOG_MD: &str = include_str!("../../../CHANGELOG.md");
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_changelog() -> Result<String, String> {
|
||||||
|
let options =
|
||||||
|
Options::ENABLE_HEADING_ATTRIBUTES | Options::ENABLE_STRIKETHROUGH | Options::ENABLE_TABLES;
|
||||||
|
|
||||||
|
let parser = Parser::new_ext(CHANGELOG_MD, options);
|
||||||
|
let mut html_output = String::new();
|
||||||
|
html::push_html(&mut html_output, parser);
|
||||||
|
|
||||||
|
Ok(html_output)
|
||||||
|
}
|
||||||
@@ -11,8 +11,7 @@ pub struct ExportRequest {
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn export_csv(request: ExportRequest) -> Result<(), String> {
|
pub async fn export_csv(request: ExportRequest) -> Result<(), String> {
|
||||||
let file = File::create(&request.path)
|
let file = File::create(&request.path).map_err(|e| format!("Failed to create file: {}", e))?;
|
||||||
.map_err(|e| format!("Failed to create file: {}", e))?;
|
|
||||||
|
|
||||||
let mut writer = csv::Writer::from_writer(file);
|
let mut writer = csv::Writer::from_writer(file);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod actions;
|
pub mod actions;
|
||||||
|
pub mod changelog;
|
||||||
pub mod export;
|
pub mod export;
|
||||||
pub mod monitor;
|
pub mod monitor;
|
||||||
pub mod nmap;
|
pub mod nmap;
|
||||||
|
|||||||
@@ -180,3 +180,24 @@ pub async fn monitor_stop() -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn monitor_update_label(ip: String, label: String) -> Result<(), String> {
|
||||||
|
let parsed: IpAddr = ip.parse().map_err(|e| format!("Invalid IP: {}", e))?;
|
||||||
|
let state = get_monitor();
|
||||||
|
let mut guard = state.lock().await;
|
||||||
|
if let Some(entry) = guard.entries.get_mut(&parsed) {
|
||||||
|
entry.label = if label.is_empty() { None } else { Some(label) };
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn monitor_resolve_host(ip: String) -> Result<Option<String>, String> {
|
||||||
|
let parsed: IpAddr = ip.parse().map_err(|e| format!("Invalid IP: {}", e))?;
|
||||||
|
Ok(crate::net::dns::reverse_lookup(parsed).await)
|
||||||
|
}
|
||||||
|
pub fn is_monitor_running() -> bool {
|
||||||
|
let state = get_monitor();
|
||||||
|
let guard = state.blocking_lock();
|
||||||
|
guard.running
|
||||||
|
}
|
||||||
@@ -40,7 +40,16 @@ pub async fn start_scan(app: AppHandle, config: ScanConfig) -> Result<(), String
|
|||||||
let port_timeout_ms = config.port_timeout_ms.unwrap_or(1000);
|
let port_timeout_ms = config.port_timeout_ms.unwrap_or(1000);
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
ping_sweep(&app, &ips, timeout_ms, cancel, port_scan, ports, port_timeout_ms).await;
|
ping_sweep(
|
||||||
|
&app,
|
||||||
|
&ips,
|
||||||
|
timeout_ms,
|
||||||
|
cancel,
|
||||||
|
port_scan,
|
||||||
|
ports,
|
||||||
|
port_timeout_ms,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,3 +60,4 @@ pub async fn run_traceroute(app: AppHandle, ip: String) -> Result<(), String> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::AppHandle;
|
use tauri::AppHandle;
|
||||||
|
|
||||||
const UPDATE_URL: &str = "https://git.racooncity.org/api/v1/repos/mysticmomba/argus/releases/latest";
|
const UPDATE_URL: &str =
|
||||||
|
"https://git.racooncity.org/api/v1/repos/mysticmomba/argus/releases/latest";
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct UpdateInfo {
|
pub struct UpdateInfo {
|
||||||
@@ -29,10 +30,7 @@ pub async fn check_for_update(app: AppHandle) -> Result<Option<UpdateInfo>, Stri
|
|||||||
.as_str()
|
.as_str()
|
||||||
.ok_or_else(|| "No tag_name in response".to_string())?;
|
.ok_or_else(|| "No tag_name in response".to_string())?;
|
||||||
|
|
||||||
let html_url = body["html_url"]
|
let html_url = body["html_url"].as_str().unwrap_or("").to_string();
|
||||||
.as_str()
|
|
||||||
.unwrap_or("")
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let notes = body["body"]
|
let notes = body["body"]
|
||||||
.as_str()
|
.as_str()
|
||||||
@@ -42,7 +40,12 @@ pub async fn check_for_update(app: AppHandle) -> Result<Option<UpdateInfo>, Stri
|
|||||||
let remote_version = tag.strip_prefix('v').unwrap_or(tag);
|
let remote_version = tag.strip_prefix('v').unwrap_or(tag);
|
||||||
let current = app.package_info().version.to_string();
|
let current = app.package_info().version.to_string();
|
||||||
|
|
||||||
if remote_version != current {
|
let remote_semver = semver::Version::parse(remote_version)
|
||||||
|
.map_err(|e| format!("Invalid remote version '{}': {}", remote_version, e))?;
|
||||||
|
let current_semver = semver::Version::parse(¤t)
|
||||||
|
.map_err(|e| format!("Invalid current version '{}': {}", current, e))?;
|
||||||
|
|
||||||
|
if remote_semver > current_semver {
|
||||||
Ok(Some(UpdateInfo {
|
Ok(Some(UpdateInfo {
|
||||||
version: remote_version.to_string(),
|
version: remote_version.to_string(),
|
||||||
url: html_url,
|
url: html_url,
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ mod models;
|
|||||||
mod net;
|
mod net;
|
||||||
mod scanner;
|
mod scanner;
|
||||||
|
|
||||||
|
use tauri::Manager;
|
||||||
|
use tauri::menu::{Menu, MenuItem};
|
||||||
|
use tauri::tray::TrayIconBuilder;
|
||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
@@ -13,8 +17,64 @@ pub fn run() {
|
|||||||
.init();
|
.init();
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
|
||||||
|
if let Some(window) = app.get_webview_window("main") {
|
||||||
|
let _ = window.show();
|
||||||
|
let _ = window.set_focus();
|
||||||
|
}
|
||||||
|
}))
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
|
.plugin(tauri_plugin_notification::init())
|
||||||
|
.setup(|app| {
|
||||||
|
let show = MenuItem::with_id(app, "show", "Show Argus", true, None::<&str>)?;
|
||||||
|
let quit = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?;
|
||||||
|
let menu = Menu::with_items(app, &[&show, &quit])?;
|
||||||
|
|
||||||
|
let _tray = TrayIconBuilder::new()
|
||||||
|
.icon(app.default_window_icon().unwrap().clone())
|
||||||
|
.tooltip("Argus - Network Scanner")
|
||||||
|
.menu(&menu)
|
||||||
|
.show_menu_on_left_click(false)
|
||||||
|
.on_menu_event(|app, event| match event.id.as_ref() {
|
||||||
|
"show" => {
|
||||||
|
if let Some(window) = app.get_webview_window("main") {
|
||||||
|
let _ = window.show();
|
||||||
|
let _ = window.set_focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"quit" => {
|
||||||
|
app.exit(0);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
})
|
||||||
|
.on_tray_icon_event(|tray, event| {
|
||||||
|
if let tauri::tray::TrayIconEvent::DoubleClick { .. } = event {
|
||||||
|
if let Some(window) = tray.app_handle().get_webview_window("main") {
|
||||||
|
let _ = window.show();
|
||||||
|
let _ = window.set_focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build(app)?;
|
||||||
|
|
||||||
|
// Hide to tray when monitor is running
|
||||||
|
let app_handle = app.handle().clone();
|
||||||
|
if let Some(window) = app.get_webview_window("main") {
|
||||||
|
window.on_window_event(move |event| {
|
||||||
|
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
|
||||||
|
if commands::monitor::is_monitor_running() {
|
||||||
|
api.prevent_close();
|
||||||
|
if let Some(win) = app_handle.get_webview_window("main") {
|
||||||
|
let _ = win.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
commands::scan::start_scan,
|
commands::scan::start_scan,
|
||||||
commands::scan::stop_scan,
|
commands::scan::stop_scan,
|
||||||
@@ -31,6 +91,9 @@ pub fn run() {
|
|||||||
commands::monitor::monitor_stop,
|
commands::monitor::monitor_stop,
|
||||||
commands::updater::check_for_update,
|
commands::updater::check_for_update,
|
||||||
commands::actions::check_privileges,
|
commands::actions::check_privileges,
|
||||||
|
commands::changelog::get_changelog,
|
||||||
|
commands::monitor::monitor_update_label,
|
||||||
|
commands::monitor::monitor_resolve_host
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ pub enum HostStatus {
|
|||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
Filtered,
|
Filtered,
|
||||||
Unknown
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -42,7 +42,7 @@ pub struct PortResult {
|
|||||||
pub struct NetbiosInfo {
|
pub struct NetbiosInfo {
|
||||||
pub computer_name: Option<String>,
|
pub computer_name: Option<String>,
|
||||||
pub workgroup: Option<String>,
|
pub workgroup: Option<String>,
|
||||||
pub mac_from_netbios: Option<String>
|
pub mac_from_netbios: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use tokio::task::JoinSet;
|
|
||||||
|
|
||||||
/// Perform reverse DNS lookup on a single IP.
|
/// Perform reverse DNS lookup on a single IP.
|
||||||
/// Returns the hostname if found, None otherwise.
|
/// Returns the hostname if found, None otherwise.
|
||||||
pub async fn reverse_lookup(ip: IpAddr) -> Option<String> {
|
pub async fn reverse_lookup(ip: IpAddr) -> Option<String> {
|
||||||
let result = tokio::task::spawn_blocking(move || {
|
let result = tokio::task::spawn_blocking(move || dns_lookup::lookup_addr(&ip)).await;
|
||||||
dns_lookup::lookup_addr(&ip)
|
|
||||||
}).await;
|
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(Ok(hostname)) => {
|
Ok(Ok(hostname)) => {
|
||||||
@@ -19,32 +16,3 @@ pub async fn reverse_lookup(ip: IpAddr) -> Option<String> {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform reverse DNS lookups on a batch of IPs concurrently.
|
|
||||||
/// Returns a Vec of (IpAddr, Option<hostname>) pairs.
|
|
||||||
pub async fn reverse_lookup_batch(
|
|
||||||
ips: &[IpAddr],
|
|
||||||
max_concurrent: usize,
|
|
||||||
) -> Vec<(IpAddr, Option<String>)> {
|
|
||||||
let mut results = Vec::with_capacity(ips.len());
|
|
||||||
|
|
||||||
for chunk in ips.chunks(max_concurrent) {
|
|
||||||
let mut join_set = JoinSet::new();
|
|
||||||
|
|
||||||
for &ip in chunk {
|
|
||||||
join_set.spawn(async move {
|
|
||||||
let hostname = reverse_lookup(ip).await;
|
|
||||||
(ip, hostname)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(result) = join_set.join_next().await {
|
|
||||||
match result {
|
|
||||||
Ok(pair) => results.push(pair),
|
|
||||||
Err(e) => tracing::warn!("DNS lookup task panicked: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results
|
|
||||||
}
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
pub mod range;
|
|
||||||
pub mod dns;
|
pub mod dns;
|
||||||
|
pub mod range;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
|
pub mod netbios;
|
||||||
pub mod ping;
|
pub mod ping;
|
||||||
pub mod ports;
|
pub mod ports;
|
||||||
pub mod netbios;
|
|
||||||
@@ -91,8 +91,7 @@ pub async fn ping_sweep(
|
|||||||
let nb_fut = query_netbios(enriched.ip, 500);
|
let nb_fut = query_netbios(enriched.ip, 500);
|
||||||
|
|
||||||
if port_scan {
|
if port_scan {
|
||||||
let scan_ports = ports2
|
let scan_ports = ports2.unwrap_or_else(|| DEFAULT_PORTS.to_vec());
|
||||||
.unwrap_or_else(|| DEFAULT_PORTS.to_vec());
|
|
||||||
let (nb_result, port_results) = tokio::join!(
|
let (nb_result, port_results) = tokio::join!(
|
||||||
nb_fut,
|
nb_fut,
|
||||||
scan_host_ports(enriched.ip, &scan_ports, port_timeout_ms)
|
scan_host_ports(enriched.ip, &scan_ports, port_timeout_ms)
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ fn service_name(port: u16) -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const DEFAULT_PORTS: &[u16] = &[
|
pub const DEFAULT_PORTS: &[u16] = &[
|
||||||
21, 22, 23, 25, 53, 80, 110, 111, 135, 139, 143,
|
21, 22, 23, 25, 53, 80, 110, 111, 135, 139, 143, 443, 445, 993, 995, 1433, 1521, 3306, 3389,
|
||||||
443, 445, 993, 995, 1433, 1521, 3306, 3389,
|
|
||||||
5432, 5900, 5985, 5986, 8080, 8088, 8443,
|
5432, 5900, 5985, 5986, 8080, 8088, 8443,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -96,7 +95,10 @@ async fn grab_banner(mut stream: TcpStream, port: u16) -> Option<String> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(data) = probe {
|
if let Some(data) = probe {
|
||||||
if timeout(banner_timeout, stream.write_all(data)).await.is_err() {
|
if timeout(banner_timeout, stream.write_all(data))
|
||||||
|
.await
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,8 +109,15 @@ async fn grab_banner(mut stream: TcpStream, port: u16) -> Option<String> {
|
|||||||
Ok(Ok(n)) if n > 0 => {
|
Ok(Ok(n)) if n > 0 => {
|
||||||
buf.truncate(n);
|
buf.truncate(n);
|
||||||
// Strip to printable ASCII, replace control chars
|
// Strip to printable ASCII, replace control chars
|
||||||
let banner: String = buf.iter()
|
let banner: String = buf
|
||||||
.map(|&b| if b >= 0x20 && b < 0x7f { b as char } else { ' ' })
|
.iter()
|
||||||
|
.map(|&b| {
|
||||||
|
if (0x20..0x7f).contains(&b) {
|
||||||
|
b as char
|
||||||
|
} else {
|
||||||
|
' '
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let banner = banner.trim().to_string();
|
let banner = banner.trim().to_string();
|
||||||
if banner.is_empty() {
|
if banner.is_empty() {
|
||||||
@@ -124,11 +133,7 @@ async fn grab_banner(mut stream: TcpStream, port: u16) -> Option<String> {
|
|||||||
|
|
||||||
const MAX_PORT_CONCURRENT: usize = 64;
|
const MAX_PORT_CONCURRENT: usize = 64;
|
||||||
|
|
||||||
pub async fn scan_host_ports(
|
pub async fn scan_host_ports(ip: IpAddr, ports: &[u16], timeout_ms: u64) -> Vec<PortResult> {
|
||||||
ip: IpAddr,
|
|
||||||
ports: &[u16],
|
|
||||||
timeout_ms: u64,
|
|
||||||
) -> Vec<PortResult> {
|
|
||||||
let mut results = Vec::with_capacity(ports.len());
|
let mut results = Vec::with_capacity(ports.len());
|
||||||
|
|
||||||
for chunk in ports.chunks(MAX_PORT_CONCURRENT) {
|
for chunk in ports.chunks(MAX_PORT_CONCURRENT) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "argus",
|
"productName": "argus",
|
||||||
"version": "0.1.0",
|
"version": "0.4.0",
|
||||||
"identifier": "io.argus.app",
|
"identifier": "io.argus.app",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../src"
|
"frontendDist": "../src"
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"withGlobalTauri": true,
|
"withGlobalTauri": true,
|
||||||
"windows": [
|
"windows": [
|
||||||
{
|
{
|
||||||
"title": "argus",
|
"title": "Argus",
|
||||||
"width": 800,
|
"width": 800,
|
||||||
"height": 600
|
"height": 600
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
"bundle": {
|
"bundle": {
|
||||||
"active": true,
|
"active": true,
|
||||||
"targets": "all",
|
"targets": "all",
|
||||||
|
"copyright": "Copyright \u00A9 2026 James Brotosky. Licensed under AGPLv3. All rights reserved.",
|
||||||
"windows": {
|
"windows": {
|
||||||
"webviewInstallMode": {
|
"webviewInstallMode": {
|
||||||
"type": "embedBootstrapper"
|
"type": "embedBootstrapper"
|
||||||
|
|||||||
+29
-1
@@ -199,6 +199,24 @@
|
|||||||
<!-- Status Bar -->
|
<!-- Status Bar -->
|
||||||
<div id="status-bar">
|
<div id="status-bar">
|
||||||
<span class="status-bar-item" id="status-bar-version">Argus</span>
|
<span class="status-bar-item" id="status-bar-version">Argus</span>
|
||||||
|
<button id="btn-changelog" class="status-bar-btn">Changelog</button>
|
||||||
|
<label class="toggle-label status-bar-toggle">
|
||||||
|
<input type="checkbox" id="chk-always-on-top" />
|
||||||
|
<span>Always on Top</span>
|
||||||
|
</label>
|
||||||
|
<select id="theme-picker" class="theme-picker">
|
||||||
|
<option value="cyber">Cyber</option>
|
||||||
|
<option value="midnight">Midnight</option>
|
||||||
|
<option value="dracula">Dracula</option>
|
||||||
|
<option value="nord">Nord</option>
|
||||||
|
<option value="solarized">Solarized Dark</option>
|
||||||
|
<option value="mocha">Catppuccin Mocha</option>
|
||||||
|
<option value="onedark">One Dark</option>
|
||||||
|
<option value="rosepine">Rosé Pine</option>
|
||||||
|
<option value="rosepine-moon">Rosé Pine Moon</option>
|
||||||
|
<option value="tokyonight">Tokyo Night</option>
|
||||||
|
<option value="iceberg">Iceberg</option>
|
||||||
|
</select>
|
||||||
<span class="status-bar-item" id="privilege-status">unprivileged</span>
|
<span class="status-bar-item" id="privilege-status">unprivileged</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -212,6 +230,16 @@
|
|||||||
<div id="traceroute-output" class="traceroute-output"></div>
|
<div id="traceroute-output" class="traceroute-output"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Changelog Modal -->
|
||||||
|
<div id="changelog-modal" class="modal-overlay">
|
||||||
|
<div class="modal-panel" style="width: 700px;">
|
||||||
|
<div class="modal-header">
|
||||||
|
<span class="modal-title">Changelog</span>
|
||||||
|
<button id="changelog-close" class="modal-close">×</button>
|
||||||
|
</div>
|
||||||
|
<div id="changelog-content" class="changelog-content"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Context Menu -->
|
<!-- Context Menu -->
|
||||||
<div id="context-menu" class="context-menu" hidden>
|
<div id="context-menu" class="context-menu" hidden>
|
||||||
<button class="ctx-item" data-action="copy-ip">Copy IP</button>
|
<button class="ctx-item" data-action="copy-ip">Copy IP</button>
|
||||||
@@ -225,7 +253,7 @@
|
|||||||
<button class="ctx-item" data-action="send-monitor">Send to Monitor</button>
|
<button class="ctx-item" data-action="send-monitor">Send to Monitor</button>
|
||||||
<button class="ctx-item" data-action="send-nmap">Send to Nmap</button>
|
<button class="ctx-item" data-action="send-nmap">Send to Nmap</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="crt-overlay"></div>
|
||||||
<script src="main.js"></script>
|
<script src="main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
+320
-27
@@ -1,12 +1,104 @@
|
|||||||
const { invoke } = window.__TAURI__.core;
|
const { invoke } = window.__TAURI__.core;
|
||||||
const { listen } = window.__TAURI__.event;
|
const { listen } = window.__TAURI__.event;
|
||||||
|
var theme = (() => {
|
||||||
|
var STORAGE_KEY = 'argus-theme';
|
||||||
|
|
||||||
|
function get() {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(STORAGE_KEY) || 'cyber';
|
||||||
|
} catch (e) {
|
||||||
|
return 'cyber';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function set(name) {
|
||||||
|
if (name === 'cyber') {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
} else {
|
||||||
|
document.documentElement.setAttribute('data-theme', name);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
localStorage.setItem(STORAGE_KEY, name);
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
var HACKER_KEY = 'argus-hacker-unlocked';
|
||||||
|
|
||||||
|
function isHackerUnlocked() {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(HACKER_KEY) === 'true';
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unlockHacker() {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(HACKER_KEY, 'true');
|
||||||
|
} catch (e) { }
|
||||||
|
addHackerOption();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addHackerOption() {
|
||||||
|
var picker = document.getElementById('theme-picker');
|
||||||
|
if (!picker.querySelector('option[value="hacker"]')) {
|
||||||
|
var opt = document.createElement('option');
|
||||||
|
opt.value = 'hacker';
|
||||||
|
opt.textContent = '\u2588 H4CK3R';
|
||||||
|
picker.appendChild(opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
var saved = get();
|
||||||
|
set(saved);
|
||||||
|
|
||||||
|
// Add hacker option if previously unlocked
|
||||||
|
if (isHackerUnlocked()) {
|
||||||
|
addHackerOption();
|
||||||
|
}
|
||||||
|
|
||||||
|
var picker = document.getElementById('theme-picker');
|
||||||
|
picker.value = saved;
|
||||||
|
picker.addEventListener('change', function () {
|
||||||
|
set(picker.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Easter egg: listen on the scan input
|
||||||
|
var scanInput = document.getElementById('ip-range-input');
|
||||||
|
scanInput.addEventListener('input', function () {
|
||||||
|
var val = scanInput.value.toLowerCase().trim();
|
||||||
|
if (val === 'all your base are belong to us') {
|
||||||
|
if (!isHackerUnlocked()) {
|
||||||
|
unlockHacker();
|
||||||
|
set('hacker');
|
||||||
|
picker.value = 'hacker';
|
||||||
|
scanInput.value = '';
|
||||||
|
console.log('%c> ACCESS GRANTED', 'color: #00ff41; font-size: 20px; font-family: monospace;');
|
||||||
|
console.log('%c> HACKER THEME UNLOCKED', 'color: #00ff41; font-size: 14px; font-family: monospace;');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply immediately (before DOMContentLoaded) to prevent flash
|
||||||
|
set(get());
|
||||||
|
|
||||||
|
return { init };
|
||||||
|
})();
|
||||||
const table = (() => {
|
const table = (() => {
|
||||||
|
var dirty = false;
|
||||||
|
var flushTimer = null;
|
||||||
|
var ipIndex = {};
|
||||||
let data = [];
|
let data = [];
|
||||||
let filtered = [];
|
let filtered = [];
|
||||||
let sortKey = 'ip';
|
let sortKey = 'ip';
|
||||||
let sortDir = 'asc';
|
let sortDir = 'asc';
|
||||||
let filterText = '';
|
let filterText = '';
|
||||||
let checkedIps = new Set();
|
let checkedIps = new Set();
|
||||||
|
var ROW_HEIGHT = 32;
|
||||||
|
var BUFFER_ROWS = 20;
|
||||||
|
var scrollContainer = null;
|
||||||
|
|
||||||
function ipToNum(ip) {
|
function ipToNum(ip) {
|
||||||
const parts = String(ip).split('.');
|
const parts = String(ip).split('.');
|
||||||
@@ -155,20 +247,61 @@ const table = (() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
const tbody = document.getElementById('results-body');
|
var tbody = document.getElementById('results-body');
|
||||||
const count = document.getElementById('host-count');
|
var count = document.getElementById('host-count');
|
||||||
if (!tbody) return;
|
if (!tbody) return;
|
||||||
|
|
||||||
expandedIp = null;
|
expandedIp = null;
|
||||||
|
|
||||||
const rows = filtered.map((host) => {
|
if (!scrollContainer) {
|
||||||
const ip = host.ip;
|
scrollContainer = document.getElementById('results-table-container');
|
||||||
const status = host.status || 'Unknown';
|
scrollContainer.addEventListener('scroll', onScroll);
|
||||||
const cls = 'status-' + status.toLowerCase();
|
}
|
||||||
const rtt = host.ping ? host.ping.rtt_ms.toFixed(1) : '-';
|
|
||||||
const hostname = host.hostname || '-';
|
|
||||||
|
|
||||||
const isChecked = checkedIps.has(ip) ? 'checked' : '';
|
renderVisible();
|
||||||
return '<tr data-ip="' + ip + '">'
|
|
||||||
|
if (count) {
|
||||||
|
var up = data.filter(function (h) { return h.status === 'Up'; }).length;
|
||||||
|
count.textContent = up + ' up / ' + data.length + ' total';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (columns && columns.apply) columns.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderVisible() {
|
||||||
|
var tbody = document.getElementById('results-body');
|
||||||
|
if (!tbody || !scrollContainer) return;
|
||||||
|
|
||||||
|
var totalRows = filtered.length;
|
||||||
|
var viewHeight = scrollContainer.clientHeight;
|
||||||
|
var scrollTop = scrollContainer.scrollTop;
|
||||||
|
var headerHeight = 36;
|
||||||
|
|
||||||
|
var startIdx = Math.max(0, Math.floor((scrollTop - headerHeight) / ROW_HEIGHT) - BUFFER_ROWS);
|
||||||
|
var visibleCount = Math.ceil(viewHeight / ROW_HEIGHT) + (BUFFER_ROWS * 2);
|
||||||
|
var endIdx = Math.min(totalRows, startIdx + visibleCount);
|
||||||
|
|
||||||
|
var topSpace = startIdx * ROW_HEIGHT;
|
||||||
|
var bottomSpace = (totalRows - endIdx) * ROW_HEIGHT;
|
||||||
|
|
||||||
|
var colCount = document.querySelectorAll('#results-table th').length;
|
||||||
|
|
||||||
|
var html = '';
|
||||||
|
|
||||||
|
if (topSpace > 0) {
|
||||||
|
html += '<tr class="virtual-spacer"><td colspan="' + colCount + '" style="height:' + topSpace + 'px"></td></tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = startIdx; i < endIdx; i++) {
|
||||||
|
var host = filtered[i];
|
||||||
|
var ip = host.ip;
|
||||||
|
var status = host.status || 'Unknown';
|
||||||
|
var cls = 'status-' + status.toLowerCase();
|
||||||
|
var rtt = host.ping ? host.ping.rtt_ms.toFixed(1) : '-';
|
||||||
|
var hostname = host.hostname || '-';
|
||||||
|
var isChecked = checkedIps.has(ip) ? 'checked' : '';
|
||||||
|
|
||||||
|
html += '<tr data-ip="' + ip + '">'
|
||||||
+ '<td class="col-check"><input type="checkbox" class="row-check" ' + isChecked + ' /></td>'
|
+ '<td class="col-check"><input type="checkbox" class="row-check" ' + isChecked + ' /></td>'
|
||||||
+ '<td>' + ip + '</td>'
|
+ '<td>' + ip + '</td>'
|
||||||
+ '<td class="' + cls + '">' + status + '</td>'
|
+ '<td class="' + cls + '">' + status + '</td>'
|
||||||
@@ -176,24 +309,43 @@ const table = (() => {
|
|||||||
+ '<td>' + hostname + '</td>'
|
+ '<td>' + hostname + '</td>'
|
||||||
+ '<td class="ports-cell">' + formatPorts(host) + '</td>'
|
+ '<td class="ports-cell">' + formatPorts(host) + '</td>'
|
||||||
+ '</tr>';
|
+ '</tr>';
|
||||||
});
|
|
||||||
|
|
||||||
tbody.innerHTML = rows.join('');
|
|
||||||
|
|
||||||
if (count) {
|
|
||||||
const up = data.filter((h) => h.status === 'Up').length;
|
|
||||||
count.textContent = up + ' up / ' + data.length + ' total';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bottomSpace > 0) {
|
||||||
|
html += '<tr class="virtual-spacer"><td colspan="' + colCount + '" style="height:' + bottomSpace + 'px"></td></tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
var scrollTimeout = null;
|
||||||
|
function onScroll() {
|
||||||
|
if (scrollTimeout) return;
|
||||||
|
scrollTimeout = requestAnimationFrame(function () {
|
||||||
|
scrollTimeout = null;
|
||||||
|
renderVisible();
|
||||||
if (columns && columns.apply) columns.apply();
|
if (columns && columns.apply) columns.apply();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function upsert(host) {
|
function upsert(host) {
|
||||||
const idx = data.findIndex((h) => h.ip === host.ip);
|
var idx = data.findIndex(function (h) { return h.ip === host.ip; });
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
data[idx] = host;
|
data[idx] = host;
|
||||||
} else {
|
} else {
|
||||||
|
ipIndex[host.ip] = data.length;
|
||||||
data.push(host);
|
data.push(host);
|
||||||
}
|
}
|
||||||
|
dirty = true;
|
||||||
|
if (!flushTimer) {
|
||||||
|
flushTimer = setTimeout(flush, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function flush() {
|
||||||
|
flushTimer = null;
|
||||||
|
if (!dirty) return;
|
||||||
|
dirty = false;
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +353,7 @@ const table = (() => {
|
|||||||
data = [];
|
data = [];
|
||||||
filtered = [];
|
filtered = [];
|
||||||
checkedIps.clear();
|
checkedIps.clear();
|
||||||
|
ipIndex = {};
|
||||||
document.getElementById('check-all').checked = false;
|
document.getElementById('check-all').checked = false;
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
@@ -504,7 +657,7 @@ const sender = (() => {
|
|||||||
if (action.startsWith('nmap')) {
|
if (action.startsWith('nmap')) {
|
||||||
nmapTab.setTarget(hosts.map((h) => String(h.ip)));
|
nmapTab.setTarget(hosts.map((h) => String(h.ip)));
|
||||||
} else if (action.startsWith('monitor')) {
|
} else if (action.startsWith('monitor')) {
|
||||||
monitorTab.setTargets(hosts.map(function (h) { return String(h.ip); }));
|
monitorTab.setTargets(hosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelectorAll('.send-menu').forEach((m) => m.hidden = true);
|
document.querySelectorAll('.send-menu').forEach((m) => m.hidden = true);
|
||||||
@@ -570,7 +723,8 @@ const ctxMenu = (() => {
|
|||||||
traceroute.run(ip);
|
traceroute.run(ip);
|
||||||
break;
|
break;
|
||||||
case 'send-monitor':
|
case 'send-monitor':
|
||||||
monitorTab.setTargets([ip]);
|
var monHost = table.getAll().find(function (h) { return String(h.ip) === ip; });
|
||||||
|
monitorTab.setTargets(monHost ? [monHost] : [ip]);
|
||||||
break;
|
break;
|
||||||
case 'send-nmap':
|
case 'send-nmap':
|
||||||
nmapTab.setTarget([ip]);
|
nmapTab.setTarget([ip]);
|
||||||
@@ -821,7 +975,7 @@ const nmapTab = (() => {
|
|||||||
const monitorTab = (() => {
|
const monitorTab = (() => {
|
||||||
let running = false;
|
let running = false;
|
||||||
let entries = {};
|
let entries = {};
|
||||||
|
var editingLabel = false;
|
||||||
var els = {
|
var els = {
|
||||||
input: () => document.getElementById('monitor-input'),
|
input: () => document.getElementById('monitor-input'),
|
||||||
interval: () => document.getElementById('monitor-interval'),
|
interval: () => document.getElementById('monitor-interval'),
|
||||||
@@ -832,6 +986,26 @@ const monitorTab = (() => {
|
|||||||
body: () => document.getElementById('monitor-body'),
|
body: () => document.getElementById('monitor-body'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var reminderInterval = null;
|
||||||
|
|
||||||
|
async function notify(title, body) {
|
||||||
|
try {
|
||||||
|
var current = window.__TAURI__.window.getCurrentWindow();
|
||||||
|
var visible = await current.isVisible();
|
||||||
|
if (visible) return;
|
||||||
|
|
||||||
|
var notif = window.__TAURI__.notification;
|
||||||
|
var granted = await notif.isPermissionGranted();
|
||||||
|
if (!granted) {
|
||||||
|
var perm = await notif.requestPermission();
|
||||||
|
if (perm !== 'granted') return;
|
||||||
|
}
|
||||||
|
notif.sendNotification({ title: title, body: body });
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Notification error:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setRunning(active) {
|
function setRunning(active) {
|
||||||
running = active;
|
running = active;
|
||||||
els.btnStart().disabled = active;
|
els.btnStart().disabled = active;
|
||||||
@@ -847,6 +1021,7 @@ const monitorTab = (() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
|
if (editingLabel) return;
|
||||||
var body = els.body();
|
var body = els.body();
|
||||||
var ips = Object.keys(entries).sort();
|
var ips = Object.keys(entries).sort();
|
||||||
|
|
||||||
@@ -862,7 +1037,7 @@ const monitorTab = (() => {
|
|||||||
|
|
||||||
return '<tr data-ip="' + ip + '">'
|
return '<tr data-ip="' + ip + '">'
|
||||||
+ '<td>' + ip + '</td>'
|
+ '<td>' + ip + '</td>'
|
||||||
+ '<td>' + label + '</td>'
|
+ '<td class="editable-label" data-ip="' + ip + '">' + label + '</td>'
|
||||||
+ '<td class="' + statusClass + '">' + e.status + '</td>'
|
+ '<td class="' + statusClass + '">' + e.status + '</td>'
|
||||||
+ '<td>' + lastRtt + '</td>'
|
+ '<td>' + lastRtt + '</td>'
|
||||||
+ '<td>' + minRtt + '</td>'
|
+ '<td>' + minRtt + '</td>'
|
||||||
@@ -889,6 +1064,16 @@ const monitorTab = (() => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await invoke('monitor_add_hosts', { hosts: hosts });
|
await invoke('monitor_add_hosts', { hosts: hosts });
|
||||||
|
|
||||||
|
for (var i = 0; i < hosts.length; i++) {
|
||||||
|
try {
|
||||||
|
var hostname = await invoke('monitor_resolve_host', { ip: hosts[i].ip });
|
||||||
|
if (hostname) {
|
||||||
|
await invoke('monitor_update_label', { ip: hosts[i].ip, label: hostname });
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
var updated = await invoke('monitor_get_entries');
|
var updated = await invoke('monitor_get_entries');
|
||||||
entries = {};
|
entries = {};
|
||||||
updated.forEach(function (e) { entries[e.ip] = e; });
|
updated.forEach(function (e) { entries[e.ip] = e; });
|
||||||
@@ -917,6 +1102,14 @@ const monitorTab = (() => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await invoke('monitor_start', { intervalMs: interval });
|
await invoke('monitor_start', { intervalMs: interval });
|
||||||
|
|
||||||
|
// Start 15-minute reminder
|
||||||
|
if (reminderInterval) clearInterval(reminderInterval);
|
||||||
|
reminderInterval = setInterval(function () {
|
||||||
|
var count = Object.keys(entries).length;
|
||||||
|
notify('Argus Monitor Active',
|
||||||
|
'The monitor is still running with ' + count + ' hosts. Close the monitor to stop pinging.');
|
||||||
|
}, 15 * 60 * 1000);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Monitor start error:', err);
|
console.error('Monitor start error:', err);
|
||||||
setRunning(false);
|
setRunning(false);
|
||||||
@@ -929,6 +1122,10 @@ const monitorTab = (() => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Monitor stop error:', err);
|
console.error('Monitor stop error:', err);
|
||||||
}
|
}
|
||||||
|
if (reminderInterval) {
|
||||||
|
clearInterval(reminderInterval);
|
||||||
|
reminderInterval = null;
|
||||||
|
}
|
||||||
setRunning(false);
|
setRunning(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,9 +1140,20 @@ const monitorTab = (() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTargets(ips) {
|
function setTargets(hosts) {
|
||||||
els.input().value = ips.join(', ');
|
var items = hosts.map(function (h) {
|
||||||
// Switch to monitor tab
|
if (typeof h === 'string') return { ip: h, label: null };
|
||||||
|
return { ip: String(h.ip), label: h.hostname || null };
|
||||||
|
});
|
||||||
|
|
||||||
|
invoke('monitor_add_hosts', { hosts: items }).then(function () {
|
||||||
|
return invoke('monitor_get_entries');
|
||||||
|
}).then(function (updated) {
|
||||||
|
entries = {};
|
||||||
|
updated.forEach(function (e) { entries[e.ip] = e; });
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
|
||||||
document.querySelectorAll('.tab').forEach(function (t) { t.classList.remove('active'); });
|
document.querySelectorAll('.tab').forEach(function (t) { t.classList.remove('active'); });
|
||||||
document.querySelectorAll('.view').forEach(function (v) { v.classList.remove('active'); });
|
document.querySelectorAll('.view').forEach(function (v) { v.classList.remove('active'); });
|
||||||
document.querySelector('[data-tab="monitor"]').classList.add('active');
|
document.querySelector('[data-tab="monitor"]').classList.add('active');
|
||||||
@@ -961,7 +1169,13 @@ const monitorTab = (() => {
|
|||||||
|
|
||||||
await listen('monitor:state-change', function (e) {
|
await listen('monitor:state-change', function (e) {
|
||||||
var data = e.payload;
|
var data = e.payload;
|
||||||
console.log('State change:', data.ip, data.old, '->', data.new);
|
console.log('State change:', data.ip, data.old, '->', data['new']);
|
||||||
|
var label = entries[data.ip] ? (entries[data.ip].label || data.ip) : data.ip;
|
||||||
|
if (data['new'] === 'Down') {
|
||||||
|
notify('Host Down', label + ' (' + data.ip + ') is no longer responding');
|
||||||
|
} else if (data['new'] === 'Up' && data.old === 'Down') {
|
||||||
|
notify('Host Recovered', label + ' (' + data.ip + ') is back online');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -980,6 +1194,41 @@ const monitorTab = (() => {
|
|||||||
var btn = e.target.closest('.btn-remove');
|
var btn = e.target.closest('.btn-remove');
|
||||||
if (btn) removeHost(btn.dataset.ip);
|
if (btn) removeHost(btn.dataset.ip);
|
||||||
});
|
});
|
||||||
|
els.body().addEventListener('dblclick', function (e) {
|
||||||
|
var cell = e.target.closest('.editable-label');
|
||||||
|
if (!cell) return;
|
||||||
|
var ip = cell.dataset.ip;
|
||||||
|
var currentLabel = cell.textContent === '-' ? '' : cell.textContent;
|
||||||
|
editingLabel = true;
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.type = 'text';
|
||||||
|
input.value = currentLabel;
|
||||||
|
input.className = 'label-edit-input';
|
||||||
|
cell.textContent = '';
|
||||||
|
cell.appendChild(input);
|
||||||
|
input.focus();
|
||||||
|
input.select();
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
var newLabel = input.value.trim();
|
||||||
|
editingLabel = false;
|
||||||
|
invoke('monitor_update_label', { ip: ip, label: newLabel }).then(function () {
|
||||||
|
return invoke('monitor_get_entries');
|
||||||
|
}).then(function (updated) {
|
||||||
|
entries = {};
|
||||||
|
updated.forEach(function (e) { entries[e.ip] = e; });
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
input.addEventListener('blur', save);
|
||||||
|
input.addEventListener('keydown', function (ev) {
|
||||||
|
if (ev.key === 'Enter') save();
|
||||||
|
if (ev.key === 'Escape')
|
||||||
|
editingLabel = false;
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
setupListeners();
|
setupListeners();
|
||||||
}
|
}
|
||||||
@@ -992,7 +1241,6 @@ var updater = (() => {
|
|||||||
var msg = document.getElementById('update-message');
|
var msg = document.getElementById('update-message');
|
||||||
var link = document.getElementById('update-link');
|
var link = document.getElementById('update-link');
|
||||||
var text = 'Argus v' + info.version + ' is available.';
|
var text = 'Argus v' + info.version + ' is available.';
|
||||||
if (info.notes) text += ' ' + info.notes;
|
|
||||||
msg.textContent = text;
|
msg.textContent = text;
|
||||||
link.href = info.url;
|
link.href = info.url;
|
||||||
link.addEventListener('click', function (e) {
|
link.addEventListener('click', function (e) {
|
||||||
@@ -1022,6 +1270,42 @@ var updater = (() => {
|
|||||||
|
|
||||||
return { init };
|
return { init };
|
||||||
})();
|
})();
|
||||||
|
var changelog = (() => {
|
||||||
|
var modal = function () { return document.getElementById('changelog-modal'); };
|
||||||
|
var loaded = false;
|
||||||
|
|
||||||
|
async function open() {
|
||||||
|
modal().classList.add('visible');
|
||||||
|
if (!loaded) {
|
||||||
|
try {
|
||||||
|
var html = await invoke('get_changelog');
|
||||||
|
document.getElementById('changelog-content').innerHTML = html;
|
||||||
|
loaded = true;
|
||||||
|
} catch (err) {
|
||||||
|
document.getElementById('changelog-content').textContent = 'Failed to load changelog.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
modal().classList.remove('visible');
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
document.getElementById('btn-changelog').addEventListener('click', open);
|
||||||
|
document.getElementById('changelog-close').addEventListener('click', close);
|
||||||
|
|
||||||
|
modal().addEventListener('click', function (e) {
|
||||||
|
if (e.target === modal()) close();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Escape' && modal().classList.contains('visible')) close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { init };
|
||||||
|
})();
|
||||||
window.addEventListener('DOMContentLoaded', () => {
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
// Tab switching
|
// Tab switching
|
||||||
document.querySelectorAll('.tab').forEach((tab) => {
|
document.querySelectorAll('.tab').forEach((tab) => {
|
||||||
@@ -1054,6 +1338,15 @@ window.addEventListener('DOMContentLoaded', () => {
|
|||||||
nmapTab.init();
|
nmapTab.init();
|
||||||
monitorTab.init();
|
monitorTab.init();
|
||||||
updater.init();
|
updater.init();
|
||||||
|
changelog.init();
|
||||||
|
theme.init();
|
||||||
|
// Always on top toggle
|
||||||
|
document.getElementById('chk-always-on-top').addEventListener('change', function (e) {
|
||||||
|
if (window.__TAURI__ && window.__TAURI__.window) {
|
||||||
|
var current = window.__TAURI__.window.getCurrentWindow();
|
||||||
|
current.setAlwaysOnTop(e.target.checked);
|
||||||
|
}
|
||||||
|
});
|
||||||
document.getElementById('btn-export-all').addEventListener('click', exporter.csvAll);
|
document.getElementById('btn-export-all').addEventListener('click', exporter.csvAll);
|
||||||
document.getElementById('btn-export-up').addEventListener('click', exporter.csvUp);
|
document.getElementById('btn-export-up').addEventListener('click', exporter.csvUp);
|
||||||
console.log('[Argus] Ready');
|
console.log('[Argus] Ready');
|
||||||
|
|||||||
+620
-3
@@ -409,6 +409,7 @@ body {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#results-table tbody tr {
|
#results-table tbody tr {
|
||||||
@@ -428,6 +429,15 @@ body {
|
|||||||
box-shadow: inset 3px 0 0 var(--cyan);
|
box-shadow: inset 3px 0 0 var(--cyan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.virtual-spacer {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.virtual-spacer td {
|
||||||
|
padding: 0 !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== Status Colors ===== */
|
/* ===== Status Colors ===== */
|
||||||
|
|
||||||
.status-up {
|
.status-up {
|
||||||
@@ -1136,17 +1146,17 @@ body {
|
|||||||
text-shadow: 0 0 6px var(--status-up-glow);
|
text-shadow: 0 0 6px var(--status-up-glow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.monitor-status-Down {
|
#monitor-table .monitor-status-Down {
|
||||||
color: var(--status-down);
|
color: var(--status-down);
|
||||||
text-shadow: 0 0 6px var(--status-down-glow);
|
text-shadow: 0 0 6px var(--status-down-glow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.monitor-status-Degraded {
|
#monitor-table .monitor-status-Degraded {
|
||||||
color: var(--status-filtered);
|
color: var(--status-filtered);
|
||||||
text-shadow: 0 0 6px var(--status-filtered-glow);
|
text-shadow: 0 0 6px var(--status-filtered-glow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.monitor-status-Unknown {
|
#monitor-table .monitor-status-Unknown {
|
||||||
color: var(--status-unknown);
|
color: var(--status-unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1260,3 +1270,610 @@ body {
|
|||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== Changelog ===== */
|
||||||
|
|
||||||
|
.changelog-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 20px 24px;
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.7;
|
||||||
|
color: var(--text-primary);
|
||||||
|
max-height: 70vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.changelog-content h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
color: var(--cyan);
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.changelog-content h2 {
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--cyan);
|
||||||
|
margin: 24px 0 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.changelog-content h3 {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin: 16px 0 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.changelog-content ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.changelog-content li {
|
||||||
|
margin: 4px 0;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.changelog-content code {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 2px 5px;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 2px;
|
||||||
|
color: var(--cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
.changelog-content a {
|
||||||
|
color: var(--cyan);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.changelog-content a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-picker {
|
||||||
|
padding: 1px 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
color: var(--text-muted);
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-picker:hover {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border-color: var(--border-bright);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-picker option {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: Midnight ===== */
|
||||||
|
|
||||||
|
:root[data-theme="midnight"] {
|
||||||
|
--bg-primary: #000000;
|
||||||
|
--bg-secondary: #0a0a0a;
|
||||||
|
--bg-tertiary: #141414;
|
||||||
|
--bg-hover: #1e1e1e;
|
||||||
|
--bg-active: #282828;
|
||||||
|
--border: #1a1a1a;
|
||||||
|
--border-bright: #2a2a2a;
|
||||||
|
|
||||||
|
--text-primary: #e0e0e0;
|
||||||
|
--text-secondary: #808080;
|
||||||
|
--text-muted: #4a4a4a;
|
||||||
|
|
||||||
|
--cyan: #00bfff;
|
||||||
|
--cyan-hover: #009ed9;
|
||||||
|
--cyan-dim: rgba(0, 191, 255, 0.08);
|
||||||
|
--cyan-glow: rgba(0, 191, 255, 0.25);
|
||||||
|
--cyan-subtle: rgba(0, 191, 255, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: Dracula ===== */
|
||||||
|
|
||||||
|
:root[data-theme="dracula"] {
|
||||||
|
--bg-primary: #282a36;
|
||||||
|
--bg-secondary: #21222c;
|
||||||
|
--bg-tertiary: #2d2f3d;
|
||||||
|
--bg-hover: #44475a;
|
||||||
|
--bg-active: #4e5166;
|
||||||
|
--border: #44475a;
|
||||||
|
--border-bright: #555869;
|
||||||
|
|
||||||
|
--text-primary: #f8f8f2;
|
||||||
|
--text-secondary: #6272a4;
|
||||||
|
--text-muted: #4d5b86;
|
||||||
|
|
||||||
|
--cyan: #bd93f9;
|
||||||
|
--cyan-hover: #a87cee;
|
||||||
|
--cyan-dim: rgba(189, 147, 249, 0.08);
|
||||||
|
--cyan-glow: rgba(189, 147, 249, 0.25);
|
||||||
|
--cyan-subtle: rgba(189, 147, 249, 0.03);
|
||||||
|
|
||||||
|
--status-up: #50fa7b;
|
||||||
|
--status-up-glow: rgba(80, 250, 123, 0.15);
|
||||||
|
--status-down: #ff5555;
|
||||||
|
--status-down-glow: rgba(255, 85, 85, 0.15);
|
||||||
|
--status-filtered: #f1fa8c;
|
||||||
|
--status-filtered-glow: rgba(241, 250, 140, 0.15);
|
||||||
|
--status-unknown: #6272a4;
|
||||||
|
|
||||||
|
--danger: #ff5555;
|
||||||
|
--danger-hover: #e64545;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: Nord ===== */
|
||||||
|
|
||||||
|
:root[data-theme="nord"] {
|
||||||
|
--bg-primary: #2e3440;
|
||||||
|
--bg-secondary: #3b4252;
|
||||||
|
--bg-tertiary: #434c5e;
|
||||||
|
--bg-hover: #4c566a;
|
||||||
|
--bg-active: #556070;
|
||||||
|
--border: #3b4252;
|
||||||
|
--border-bright: #4c566a;
|
||||||
|
|
||||||
|
--text-primary: #eceff4;
|
||||||
|
--text-secondary: #d8dee9;
|
||||||
|
--text-muted: #616e88;
|
||||||
|
|
||||||
|
--cyan: #88c0d0;
|
||||||
|
--cyan-hover: #7bb4c4;
|
||||||
|
--cyan-dim: rgba(136, 192, 208, 0.08);
|
||||||
|
--cyan-glow: rgba(136, 192, 208, 0.25);
|
||||||
|
--cyan-subtle: rgba(136, 192, 208, 0.03);
|
||||||
|
|
||||||
|
--status-up: #a3be8c;
|
||||||
|
--status-up-glow: rgba(163, 190, 140, 0.15);
|
||||||
|
--status-down: #bf616a;
|
||||||
|
--status-down-glow: rgba(191, 97, 106, 0.15);
|
||||||
|
--status-filtered: #ebcb8b;
|
||||||
|
--status-filtered-glow: rgba(235, 203, 139, 0.15);
|
||||||
|
--status-unknown: #616e88;
|
||||||
|
|
||||||
|
--danger: #bf616a;
|
||||||
|
--danger-hover: #a9545c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: Solarized Dark ===== */
|
||||||
|
|
||||||
|
:root[data-theme="solarized"] {
|
||||||
|
--bg-primary: #002b36;
|
||||||
|
--bg-secondary: #073642;
|
||||||
|
--bg-tertiary: #0a3f4c;
|
||||||
|
--bg-hover: #124a56;
|
||||||
|
--bg-active: #1a5560;
|
||||||
|
--border: #0d4450;
|
||||||
|
--border-bright: #1a5c6a;
|
||||||
|
|
||||||
|
--text-primary: #cb4b16;
|
||||||
|
--text-secondary: #839496;
|
||||||
|
--text-muted: #586e75;
|
||||||
|
|
||||||
|
--cyan: #2aa198;
|
||||||
|
--cyan-hover: #25908a;
|
||||||
|
--cyan-dim: rgba(42, 161, 152, 0.1);
|
||||||
|
--cyan-glow: rgba(42, 161, 152, 0.25);
|
||||||
|
--cyan-subtle: rgba(42, 161, 152, 0.03);
|
||||||
|
|
||||||
|
--status-up: #859900;
|
||||||
|
--status-up-glow: rgba(133, 153, 0, 0.15);
|
||||||
|
--status-down: #dc322f;
|
||||||
|
--status-down-glow: rgba(220, 50, 47, 0.15);
|
||||||
|
--status-filtered: #b58900;
|
||||||
|
--status-filtered-glow: rgba(181, 137, 0, 0.15);
|
||||||
|
--status-unknown: #586e75;
|
||||||
|
|
||||||
|
--danger: #dc322f;
|
||||||
|
--danger-hover: #c62825;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: Catppuccin Mocha ===== */
|
||||||
|
|
||||||
|
:root[data-theme="mocha"] {
|
||||||
|
--bg-primary: #1e1e2e;
|
||||||
|
--bg-secondary: #181825;
|
||||||
|
--bg-tertiary: #313244;
|
||||||
|
--bg-hover: #45475a;
|
||||||
|
--bg-active: #585b70;
|
||||||
|
--border: #313244;
|
||||||
|
--border-bright: #45475a;
|
||||||
|
|
||||||
|
--text-primary: #94e2d5;
|
||||||
|
--text-secondary: #a6adc8;
|
||||||
|
--text-muted: #6c7086;
|
||||||
|
|
||||||
|
--cyan: #b4befe;
|
||||||
|
--cyan-hover: #7ba4eb;
|
||||||
|
--cyan-dim: rgba(137, 180, 250, 0.08);
|
||||||
|
--cyan-glow: rgba(137, 180, 250, 0.2);
|
||||||
|
--cyan-subtle: rgba(137, 180, 250, 0.03);
|
||||||
|
|
||||||
|
--status-up: #a6e3a1;
|
||||||
|
--status-up-glow: rgba(166, 227, 161, 0.15);
|
||||||
|
--status-down: #f38ba8;
|
||||||
|
--status-down-glow: rgba(243, 139, 168, 0.15);
|
||||||
|
--status-filtered: #f9e2af;
|
||||||
|
--status-filtered-glow: rgba(249, 226, 175, 0.15);
|
||||||
|
--status-unknown: #6c7086;
|
||||||
|
|
||||||
|
--danger: #f38ba8;
|
||||||
|
--danger-hover: #e57a97;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="mocha"] .toolbar-circuit {
|
||||||
|
filter: hue-rotate(40deg) saturate(0.6) brightness(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="mocha"] .port-tag {
|
||||||
|
background: rgba(30, 102, 245, 0.1);
|
||||||
|
border-color: rgba(30, 102, 245, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="mocha"] #privilege-status::before {
|
||||||
|
background: var(--status-up);
|
||||||
|
box-shadow: 0 0 4px rgba(64, 160, 43, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="mocha"] ::-webkit-scrollbar-track {
|
||||||
|
background: var(--bg-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="mocha"] ::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--border-bright);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: One Dark ===== */
|
||||||
|
|
||||||
|
:root[data-theme="onedark"] {
|
||||||
|
--bg-primary: #282c34;
|
||||||
|
--bg-secondary: #21252b;
|
||||||
|
--bg-tertiary: #2c313a;
|
||||||
|
--bg-hover: #3e4451;
|
||||||
|
--bg-active: #4b5263;
|
||||||
|
--border: #3e4451;
|
||||||
|
--border-bright: #4b5263;
|
||||||
|
|
||||||
|
--text-primary: #abb2bf;
|
||||||
|
--text-secondary: #848b98;
|
||||||
|
--text-muted: #5c6370;
|
||||||
|
|
||||||
|
--cyan: #61afef;
|
||||||
|
--cyan-hover: #519fdf;
|
||||||
|
--cyan-dim: rgba(97, 175, 239, 0.08);
|
||||||
|
--cyan-glow: rgba(97, 175, 239, 0.2);
|
||||||
|
--cyan-subtle: rgba(97, 175, 239, 0.03);
|
||||||
|
|
||||||
|
--status-up: #98c379;
|
||||||
|
--status-up-glow: rgba(152, 195, 121, 0.15);
|
||||||
|
--status-down: #e06c75;
|
||||||
|
--status-down-glow: rgba(224, 108, 117, 0.15);
|
||||||
|
--status-filtered: #e5c07b;
|
||||||
|
--status-filtered-glow: rgba(229, 192, 123, 0.15);
|
||||||
|
--status-unknown: #5c6370;
|
||||||
|
|
||||||
|
--danger: #e06c75;
|
||||||
|
--danger-hover: #d05f68;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="onedark"] .toolbar-circuit {
|
||||||
|
filter: hue-rotate(30deg) saturate(0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: Rosé Pine ===== */
|
||||||
|
|
||||||
|
:root[data-theme="rosepine"] {
|
||||||
|
--bg-primary: #191724;
|
||||||
|
--bg-secondary: #1f1d2e;
|
||||||
|
--bg-tertiary: #26233a;
|
||||||
|
--bg-hover: #403d52;
|
||||||
|
--bg-active: #524f67;
|
||||||
|
--border: #26233a;
|
||||||
|
--border-bright: #403d52;
|
||||||
|
|
||||||
|
--text-primary: #31748f;
|
||||||
|
--text-secondary: #908caa;
|
||||||
|
--text-muted: #6e6a86;
|
||||||
|
|
||||||
|
--cyan: #c4a7e7;
|
||||||
|
--cyan-hover: #b498d7;
|
||||||
|
--cyan-dim: rgba(196, 167, 231, 0.08);
|
||||||
|
--cyan-glow: rgba(196, 167, 231, 0.2);
|
||||||
|
--cyan-subtle: rgba(196, 167, 231, 0.03);
|
||||||
|
|
||||||
|
--status-up: #9ccfd8;
|
||||||
|
--status-up-glow: rgba(156, 207, 216, 0.15);
|
||||||
|
--status-down: #eb6f92;
|
||||||
|
--status-down-glow: rgba(235, 111, 146, 0.15);
|
||||||
|
--status-filtered: #f6c177;
|
||||||
|
--status-filtered-glow: rgba(246, 193, 119, 0.15);
|
||||||
|
--status-unknown: #6e6a86;
|
||||||
|
|
||||||
|
--danger: #eb6f92;
|
||||||
|
--danger-hover: #db5f82;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="rosepine"] .toolbar-circuit {
|
||||||
|
filter: hue-rotate(80deg) saturate(0.5) brightness(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: Rosé Pine Moon ===== */
|
||||||
|
|
||||||
|
:root[data-theme="rosepine-moon"] {
|
||||||
|
--bg-primary: #232136;
|
||||||
|
--bg-secondary: #2a273f;
|
||||||
|
--bg-tertiary: #393552;
|
||||||
|
--bg-hover: #44415a;
|
||||||
|
--bg-active: #56526e;
|
||||||
|
--border: #393552;
|
||||||
|
--border-bright: #44415a;
|
||||||
|
|
||||||
|
--text-primary: #9ccfd8;
|
||||||
|
--text-secondary: #908caa;
|
||||||
|
--text-muted: #6e6a86;
|
||||||
|
|
||||||
|
--cyan: #c4a7e7;
|
||||||
|
--cyan-hover: #b498d7;
|
||||||
|
--cyan-dim: rgba(196, 167, 231, 0.08);
|
||||||
|
--cyan-glow: rgba(196, 167, 231, 0.2);
|
||||||
|
--cyan-subtle: rgba(196, 167, 231, 0.03);
|
||||||
|
|
||||||
|
--status-up: #9ccfd8;
|
||||||
|
--status-up-glow: rgba(156, 207, 216, 0.15);
|
||||||
|
--status-down: #eb6f92;
|
||||||
|
--status-down-glow: rgba(235, 111, 146, 0.15);
|
||||||
|
--status-filtered: #f6c177;
|
||||||
|
--status-filtered-glow: rgba(246, 193, 119, 0.15);
|
||||||
|
--status-unknown: #6e6a86;
|
||||||
|
|
||||||
|
--danger: #eb6f92;
|
||||||
|
--danger-hover: #db5f82;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="rosepine-moon"] .toolbar-circuit {
|
||||||
|
filter: hue-rotate(80deg) saturate(0.5) brightness(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: Tokyo Night ===== */
|
||||||
|
|
||||||
|
:root[data-theme="tokyonight"] {
|
||||||
|
--bg-primary: #1a1b26;
|
||||||
|
--bg-secondary: #16161e;
|
||||||
|
--bg-tertiary: #1f2335;
|
||||||
|
--bg-hover: #292e42;
|
||||||
|
--bg-active: #33384d;
|
||||||
|
--border: #1f2335;
|
||||||
|
--border-bright: #292e42;
|
||||||
|
|
||||||
|
--text-primary: #bb9af7;
|
||||||
|
--text-secondary: #a9b1d6;
|
||||||
|
--text-muted: #565f89;
|
||||||
|
|
||||||
|
--cyan: #7aa2f7;
|
||||||
|
--cyan-hover: #6a92e7;
|
||||||
|
--cyan-dim: rgba(122, 162, 247, 0.08);
|
||||||
|
--cyan-glow: rgba(122, 162, 247, 0.2);
|
||||||
|
--cyan-subtle: rgba(122, 162, 247, 0.03);
|
||||||
|
|
||||||
|
--status-up: #9ece6a;
|
||||||
|
--status-up-glow: rgba(158, 206, 106, 0.15);
|
||||||
|
--status-down: #f7768e;
|
||||||
|
--status-down-glow: rgba(247, 118, 142, 0.15);
|
||||||
|
--status-filtered: #e0af68;
|
||||||
|
--status-filtered-glow: rgba(224, 175, 104, 0.15);
|
||||||
|
--status-unknown: #565f89;
|
||||||
|
|
||||||
|
--danger: #f7768e;
|
||||||
|
--danger-hover: #e7667e;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="tokyonight"] .toolbar-circuit {
|
||||||
|
filter: hue-rotate(40deg) saturate(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: Iceberg ===== */
|
||||||
|
|
||||||
|
:root[data-theme="iceberg"] {
|
||||||
|
--bg-primary: #161821;
|
||||||
|
--bg-secondary: #1e2132;
|
||||||
|
--bg-tertiary: #252837;
|
||||||
|
--bg-hover: #33374c;
|
||||||
|
--bg-active: #3d4259;
|
||||||
|
--border: #252837;
|
||||||
|
--border-bright: #33374c;
|
||||||
|
|
||||||
|
--text-primary: #c6c8d1;
|
||||||
|
--text-secondary: #818596;
|
||||||
|
--text-muted: #444b71;
|
||||||
|
|
||||||
|
--cyan: #84a0c6;
|
||||||
|
--cyan-hover: #7490b6;
|
||||||
|
--cyan-dim: rgba(132, 160, 198, 0.08);
|
||||||
|
--cyan-glow: rgba(132, 160, 198, 0.2);
|
||||||
|
--cyan-subtle: rgba(132, 160, 198, 0.03);
|
||||||
|
|
||||||
|
--status-up: #b4be82;
|
||||||
|
--status-up-glow: rgba(180, 190, 130, 0.15);
|
||||||
|
--status-down: #e27878;
|
||||||
|
--status-down-glow: rgba(226, 120, 120, 0.15);
|
||||||
|
--status-filtered: #e2a478;
|
||||||
|
--status-filtered-glow: rgba(226, 164, 120, 0.15);
|
||||||
|
--status-unknown: #444b71;
|
||||||
|
|
||||||
|
--danger: #e27878;
|
||||||
|
--danger-hover: #d26868;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="iceberg"] .toolbar-circuit {
|
||||||
|
filter: hue-rotate(30deg) saturate(0.4) brightness(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Theme: Hacker (Easter Egg) ===== */
|
||||||
|
|
||||||
|
:root[data-theme="hacker"] {
|
||||||
|
--bg-primary: #000000;
|
||||||
|
--bg-secondary: #0a0a0a;
|
||||||
|
--bg-tertiary: #0d0d0d;
|
||||||
|
--bg-hover: #1a1a1a;
|
||||||
|
--bg-active: #222222;
|
||||||
|
--border: #0a3a0a;
|
||||||
|
--border-bright: #0f4f0f;
|
||||||
|
|
||||||
|
--text-primary: #00ff41;
|
||||||
|
--text-secondary: #00cc33;
|
||||||
|
--text-muted: #006b1d;
|
||||||
|
|
||||||
|
--cyan: #00ff41;
|
||||||
|
--cyan-hover: #00dd38;
|
||||||
|
--cyan-dim: rgba(0, 255, 65, 0.06);
|
||||||
|
--cyan-glow: rgba(0, 255, 65, 0.3);
|
||||||
|
--cyan-subtle: rgba(0, 255, 65, 0.02);
|
||||||
|
|
||||||
|
--status-up: #00ff41;
|
||||||
|
--status-up-glow: rgba(0, 255, 65, 0.2);
|
||||||
|
--status-down: #ff0040;
|
||||||
|
--status-down-glow: rgba(255, 0, 64, 0.2);
|
||||||
|
--status-filtered: #ffff00;
|
||||||
|
--status-filtered-glow: rgba(255, 255, 0, 0.15);
|
||||||
|
--status-unknown: #006b1d;
|
||||||
|
|
||||||
|
--danger: #ff0040;
|
||||||
|
--danger-hover: #dd0038;
|
||||||
|
|
||||||
|
--font-mono: "Courier New", "Lucida Console", monospace;
|
||||||
|
--font-sans: "Courier New", "Lucida Console", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="hacker"] .toolbar-circuit {
|
||||||
|
filter: hue-rotate(-60deg) saturate(3) brightness(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="hacker"] body {
|
||||||
|
font-family: "Courier New", "Lucida Console", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="hacker"] .app-title {
|
||||||
|
letter-spacing: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="hacker"] .btn-primary {
|
||||||
|
text-shadow: 0 0 8px rgba(0, 255, 65, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="hacker"] #results-table td,
|
||||||
|
:root[data-theme="hacker"] #monitor-table td {
|
||||||
|
text-shadow: 0 0 3px rgba(0, 255, 65, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
#crt-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="hacker"] #crt-overlay {
|
||||||
|
display: block;
|
||||||
|
background:
|
||||||
|
repeating-linear-gradient(0deg,
|
||||||
|
rgba(0, 0, 0, 0.5) 0px,
|
||||||
|
rgba(0, 0, 0, 0.5) 1px,
|
||||||
|
transparent 1px,
|
||||||
|
transparent 4px),
|
||||||
|
linear-gradient(180deg,
|
||||||
|
transparent 0%,
|
||||||
|
rgba(0, 255, 65, 0.09) 50%,
|
||||||
|
transparent 100%);
|
||||||
|
animation: crt-flicker 3s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes crt-flicker {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
5% {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
opacity: 0.95;
|
||||||
|
}
|
||||||
|
|
||||||
|
45% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
85% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Circuit art theme tinting ===== */
|
||||||
|
|
||||||
|
:root[data-theme="dracula"] .toolbar-circuit {
|
||||||
|
filter: hue-rotate(70deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="nord"] .toolbar-circuit {
|
||||||
|
filter: hue-rotate(20deg) saturate(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="solarized"] .toolbar-circuit {
|
||||||
|
filter: hue-rotate(160deg) saturate(0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="midnight"] .toolbar-circuit {
|
||||||
|
filter: brightness(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-label {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-label:hover {
|
||||||
|
background: var(--cyan-dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-edit-input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 2px 6px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border: 1px solid var(--cyan);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-bar-toggle {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-bar-toggle input:checked+span {
|
||||||
|
color: var(--cyan);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user