release-2.6.0 (#1085)

* fix: general bug fixes

* fix: general qol additions

* ci(deps): bump actions/setup-node in the github-actions group (#1068)

Bumps the github-actions group with 1 update: [actions/setup-node](https://github.com/actions/setup-node).


Updates `actions/setup-node` from 6 to 7
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump the dev-patch-updates group with 28 updates (#1069)

Bumps the dev-patch-updates group with 28 updates:

| Package | From | To |
| --- | --- | --- |
| [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.5.2` | `2.5.4` |
| [@codemirror/view](https://github.com/codemirror/view) | `6.43.5` | `6.43.6` |
| [@radix-ui/react-accordion](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/accordion) | `1.2.15` | `1.2.17` |
| [@radix-ui/react-alert-dialog](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/alert-dialog) | `1.1.18` | `1.1.20` |
| [@radix-ui/react-checkbox](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/checkbox) | `1.3.6` | `1.3.8` |
| [@radix-ui/react-dialog](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/dialog) | `1.1.18` | `1.1.20` |
| [@radix-ui/react-dropdown-menu](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/dropdown-menu) | `2.1.19` | `2.1.21` |
| [@radix-ui/react-label](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/label) | `2.1.11` | `2.1.12` |
| [@radix-ui/react-popover](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/popover) | `1.1.18` | `1.1.20` |
| [@radix-ui/react-progress](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/progress) | `1.1.11` | `1.1.13` |
| [@radix-ui/react-scroll-area](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/scroll-area) | `1.2.13` | `1.2.15` |
| [@radix-ui/react-select](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/select) | `2.3.2` | `2.3.4` |
| [@radix-ui/react-separator](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/separator) | `1.1.11` | `1.1.12` |
| [@radix-ui/react-slider](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/slider) | `1.4.2` | `1.4.4` |
| [@radix-ui/react-switch](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/switch) | `1.3.2` | `1.3.4` |
| [@radix-ui/react-tabs](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/tabs) | `1.1.16` | `1.1.18` |
| [@radix-ui/react-tooltip](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/tooltip) | `1.2.11` | `1.2.13` |
| [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) | `4.3.2` | `4.3.3` |
| [@uiw/codemirror-extensions-langs](https://github.com/uiwjs/react-codemirror) | `4.25.10` | `4.25.11` |
| [@uiw/codemirror-theme-github](https://github.com/uiwjs/react-codemirror) | `4.25.10` | `4.25.11` |
| [@uiw/react-codemirror](https://github.com/uiwjs/react-codemirror) | `4.25.10` | `4.25.11` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `4.1.9` | `4.1.10` |
| [@vitest/ui](https://github.com/vitest-dev/vitest/tree/HEAD/packages/ui) | `4.1.9` | `4.1.10` |
| [i18next](https://github.com/i18next/i18next) | `26.3.4` | `26.3.6` |
| [radix-ui](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/radix-ui) | `1.6.1` | `1.6.3` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.0.8` | `17.0.10` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.3.2` | `4.3.3` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.9` | `4.1.10` |


Updates `@biomejs/biome` from 2.5.2 to 2.5.4
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.4/packages/@biomejs/biome)

Updates `@codemirror/view` from 6.43.5 to 6.43.6
- [Changelog](https://github.com/codemirror/view/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/view/commits)

Updates `@radix-ui/react-accordion` from 1.2.15 to 1.2.17
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/accordion/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/accordion)

Updates `@radix-ui/react-alert-dialog` from 1.1.18 to 1.1.20
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/alert-dialog/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/alert-dialog)

Updates `@radix-ui/react-checkbox` from 1.3.6 to 1.3.8
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/checkbox/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/checkbox)

Updates `@radix-ui/react-dialog` from 1.1.18 to 1.1.20
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/dialog/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/dialog)

Updates `@radix-ui/react-dropdown-menu` from 2.1.19 to 2.1.21
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/dropdown-menu/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/dropdown-menu)

Updates `@radix-ui/react-label` from 2.1.11 to 2.1.12
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/label/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/label)

Updates `@radix-ui/react-popover` from 1.1.18 to 1.1.20
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/popover/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/popover)

Updates `@radix-ui/react-progress` from 1.1.11 to 1.1.13
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/progress/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/progress)

Updates `@radix-ui/react-scroll-area` from 1.2.13 to 1.2.15
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/scroll-area/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/scroll-area)

Updates `@radix-ui/react-select` from 2.3.2 to 2.3.4
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/select/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/select)

Updates `@radix-ui/react-separator` from 1.1.11 to 1.1.12
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/separator/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/separator)

Updates `@radix-ui/react-slider` from 1.4.2 to 1.4.4
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/slider/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/slider)

Updates `@radix-ui/react-switch` from 1.3.2 to 1.3.4
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/switch/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/switch)

Updates `@radix-ui/react-tabs` from 1.1.16 to 1.1.18
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/tabs/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/tabs)

Updates `@radix-ui/react-tooltip` from 1.2.11 to 1.2.13
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/tooltip/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/tooltip)

Updates `@tailwindcss/vite` from 4.3.2 to 4.3.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/@tailwindcss-vite)

Updates `@uiw/codemirror-extensions-langs` from 4.25.10 to 4.25.11
- [Release notes](https://github.com/uiwjs/react-codemirror/releases)
- [Commits](https://github.com/uiwjs/react-codemirror/compare/v4.25.10...v4.25.11)

Updates `@uiw/codemirror-theme-github` from 4.25.10 to 4.25.11
- [Release notes](https://github.com/uiwjs/react-codemirror/releases)
- [Commits](https://github.com/uiwjs/react-codemirror/compare/v4.25.10...v4.25.11)

Updates `@uiw/react-codemirror` from 4.25.10 to 4.25.11
- [Release notes](https://github.com/uiwjs/react-codemirror/releases)
- [Commits](https://github.com/uiwjs/react-codemirror/compare/v4.25.10...v4.25.11)

Updates `@vitest/coverage-v8` from 4.1.9 to 4.1.10
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/coverage-v8)

Updates `@vitest/ui` from 4.1.9 to 4.1.10
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/ui)

Updates `i18next` from 26.3.4 to 26.3.6
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.3.4...v26.3.6)

Updates `radix-ui` from 1.6.1 to 1.6.3
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/radix-ui/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/radix-ui)

Updates `react-i18next` from 17.0.8 to 17.0.10
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.0.8...v17.0.10)

Updates `tailwindcss` from 4.3.2 to 4.3.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/tailwindcss)

Updates `vitest` from 4.1.9 to 4.1.10
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/vitest)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.5.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@codemirror/view"
  dependency-version: 6.43.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-accordion"
  dependency-version: 1.2.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-alert-dialog"
  dependency-version: 1.1.20
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-checkbox"
  dependency-version: 1.3.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-dialog"
  dependency-version: 1.1.20
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-dropdown-menu"
  dependency-version: 2.1.21
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-label"
  dependency-version: 2.1.12
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-popover"
  dependency-version: 1.1.20
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-progress"
  dependency-version: 1.1.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-scroll-area"
  dependency-version: 1.2.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-select"
  dependency-version: 2.3.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-separator"
  dependency-version: 1.1.12
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-slider"
  dependency-version: 1.4.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-switch"
  dependency-version: 1.3.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-tabs"
  dependency-version: 1.1.18
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-tooltip"
  dependency-version: 1.2.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@tailwindcss/vite"
  dependency-version: 4.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@uiw/codemirror-extensions-langs"
  dependency-version: 4.25.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@uiw/codemirror-theme-github"
  dependency-version: 4.25.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@uiw/react-codemirror"
  dependency-version: 4.25.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@vitest/ui"
  dependency-version: 4.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: i18next
  dependency-version: 26.3.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: radix-ui
  dependency-version: 1.6.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: react-i18next
  dependency-version: 17.0.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: tailwindcss
  dependency-version: 4.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: vitest
  dependency-version: 4.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump ws in the prod-patch-updates group (#1071)

Bumps the prod-patch-updates group with 1 update: [ws](https://github.com/websockets/ws).


Updates `ws` from 8.21.0 to 8.21.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.21.0...8.21.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.21.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump the major-updates group with 2 updates (#1072)

Bumps the major-updates group with 2 updates: [nanoid](https://github.com/ai/nanoid) and [typescript](https://github.com/microsoft/TypeScript).


Updates `nanoid` from 5.1.16 to 6.0.0
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.1.16...6.0.0)

Updates `typescript` from 6.0.3 to 7.0.2
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](https://github.com/microsoft/TypeScript/commits)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: major-updates
- dependency-name: typescript
  dependency-version: 7.0.2
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: major-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: general qol additions and new analytics/telemetrics feature

* fix: incorrect version sent to posthog

* feat: add multiplayer/shared sessions for terminal and guacd

* feat: rework Electron desktop app to run standalone-first with optional two-way sync to a remote Termix server

* Fix Guacamole tab visibility lifecycle (#1074)

Co-authored-by: default-student <default-student@github.com>
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* fix(alerts): send channel config as object payload instead of JSON string (#1075)

* fix tmux-monitor tailscale issue (#1076)

* Initial plan

* fix(tmux-monitor): explicitly handle tailscale auth in PanePreview hostConfig

For Tailscale-auth hosts the pane-preview attach path was building the
Terminal hostConfig with only the generic spread of host fields.  This
could omit or mismap auth-critical details and trigger a plain TCP/SSH
reachability path that doesn't work with Tailscale-only SSH endpoints.

The fix branches on `host.authType === "tailscale"` and:
- Carries `authType: "tailscale"` explicitly so the backend always selects
  the Tailscale-aware PTY path regardless of how the host object evolves.
- Derives `port` from `host.sshPort ?? host.port` so Tailscale SSH
  endpoints on a non-default SSH port are reached correctly.
- Leaves all non-tailscale auth types on the unchanged code path.

Reattach (bumping instanceId + attachNonce) continues to work because
terminalHostConfig is recomputed on every render with the latest
instanceIdRef.current value.

* refactor(tmux-monitor): simplify tailscale port logic with extracted variable

Address code review feedback: extract resolvedPort into a local variable
to avoid the duplicated `host.sshPort ?? host.port` expression that was
assigned to both `port` and `sshPort`.  Restructure as an if/else block
instead of an IIFE for readability.

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* chore: run prettier

* chore: update beta release text

* fix: cant update credential of an RDP host

* feat: add custom key shortcuts

* feat: add support for MFA over SSH

* fix: Invalid websocket frame causing code 10006 crash triggering restart loop

* fix(net): correct SSRF blocklist false-positive blocking all outbound IPv4 (#1079)

* fix: correct IPv4-mapped-IPv6 blocklist entry blocking all outbound IPv4

::ffff:0:0/96 in the IPv6 blocklist matches every IPv4 address once
mapped, since Node's BlockList compares addresses in their mapped form
internally regardless of the declared family. This caused
safeOutboundFetch to reject all IPv4-resolved destinations as private,
breaking outbound requests (e.g. ntfy/webhook notifications) whenever
DNS resolved to IPv4. Replaced with individual mapped ranges mirroring
the existing IPv4 blocklist.

* test: cover isBlockedAddress and link the Node BlockList citation

Exports isBlockedAddress so its family-crossing behavior around
IPv4-mapped-IPv6 addresses can actually be asserted, instead of relying
on manual container debugging to notice a regression. Also swaps the
prior "Node's BlockList compares addresses in mapped form" comment for
one citing the documented example in the Node docs
(https://nodejs.org/api/net.html#class-netblocklist), since that
behavior isn't otherwise obvious from the addSubnet/check call sites.

Related: Termix-SSH/Support#1024

* refactor: derive IPv6 mirror from IPv4 list, split DNS error messages

Two follow-ups from review:

- The IPv6 blocklist previously hand-duplicated each IPv4 range as its
  IPv4-mapped-IPv6 equivalent. Nothing enforced the two stayed in sync,
  which is exactly how the original bug (a mismatched ::ffff:0:0/96
  entry blocking all IPv4) was introduced in the first place. Now
  derived from a single blockedIpv4Ranges list in one loop.

- The connect.lookup hook threw the same "Private destinations are not
  allowed" for both an empty DNS result and an actually-blocked address.
  An empty result is a resolution failure, not a privacy decision, and
  conflating the two is the same kind of opaque-error problem that made
  this bug slow to diagnose in production. Split into distinct messages.

Also extracted the lookup hook itself (createDnsLookupHook) so it can be
unit-tested against a fake resolver directly, instead of only through a
real fetch()/Agent call — the bug lived entirely in this callback, and
undici wraps any error thrown here as a generic "fetch failed" TypeError,
which is why isolating it matters for testability.

---------

Co-authored-by: brennanneoh <497569+brennanneoh@users.noreply.github.com>

* fix(ssh): do not offer chacha20-poly1305 without the native ssh2 binding (#1081)

The availability probe treated a working OpenSSL "chacha20" cipher as proof
that chacha20-poly1305@openssh.com is usable. It is not: ssh2 pure-JS
chacha20-poly1305 corrupts the transport, so the peer aborts the KEX
("incomplete message [preauth]") and the connection times out. Easy to hit
on jump-host connections whose target sshd negotiates chacha20-poly1305
first.

Only trust the native binding (sshcrypto.node); otherwise leave the cipher
disabled so filterCiphers() drops it and AES-GCM is negotiated instead.

Co-authored-by: XtraLarge <>

* fix: add Swiss German server layout (#1078)

* chore: update release notes

* feat: continue improving desktop app 2-way sync with logic fixes and a migration dialog

* fix: dekstop app showing auth form without syncing

* feat: create desktop auto sessions for existing setups

* feat: add electron backend killing

* fix: electron login and session related bugs and updated readme for v2.6.0

* chore: finalize release notes

* fix: click to expand hosts including extra bottom margin

* fix: desktop auth modal failing to log users in

* fix: desktop app failing to sync

* fix: reverse proxy causing sync error

* chore: lint, format, and bump version to 2.6.0

* chore: sync Crowdin translations for 2.6.0

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: L.H. <117188168+default-student@users.noreply.github.com>
Co-authored-by: default-student <default-student@github.com>
Co-authored-by: Brad Baker <xyzulu@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Brennan Neoh <brennanneoh@users.noreply.github.com>
Co-authored-by: brennanneoh <497569+brennanneoh@users.noreply.github.com>
Co-authored-by: XtraLarge <eMail@WilliWerres.de>
Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
This commit is contained in:
232 files changed
+50585 -32016

No files matched your search

+216 -3
View File
@@ -389,6 +389,45 @@
"noSavedServers": "Няма запазени сървъри",
"removeServer": "Премахване"
},
"migrationNotice": {
"title": "Termix Desktop вече работи самостоятелно",
"body1": "Това приложение се свързваше директно с вашия Termix сървър. То е преработено, за да работи напълно самостоятелно, съхранявайки хостове и идентификационни данни локално, така че да продължи да работи офлайн. Двупосочната синхронизация със самостоятелно хостван Termix сървър вече е по избор.",
"body2": "Вашите съществуващи хостове и идентификационни данни все още са на {{url}}. Включете отдалечената синхронизация и се свържете отново с този сървър, за да ги върнете и да поддържате синхронизирани занапред.",
"dismiss": "Не сега",
"setUpSync": "Настройване на отдалечена синхронизация"
},
"remoteSync": {
"title": "Дистанционна синхронизация",
"description": "По желание свържете това настолно приложение към самостоятелно хостван Termix сървър, за да синхронизирате вашите хостове, идентификационни данни и фрагменти на различни устройства. Приложението винаги работи напълно офлайн, независимо дали се свързвате или не.",
"notConnected": "Няма връзка",
"connected": "Свързан",
"connectedTo": "Свързано с {{url}}",
"lastSynced": "Последна синхронизация {{time}}",
"neverSynced": "Никога не е синхронизирано",
"syncError": "Грешка при синхронизиране: {{message}}",
"needsReauth": "Входът е изтекъл",
"connectButton": "Свързване със сървъра",
"disconnectButton": "Изключване",
"syncNowButton": "Синхронизирай сега",
"syncing": "Синхронизиране...",
"serverUrl": "URL адрес на сървъра",
"enterServerUrl": "Моля, въведете URL адрес на сървъра",
"mustIncludeProtocol": "URL адресът на сървъра трябва да започва с http:// или https://",
"connectionTestFailed": "Не можа да се свърже със сървър на Termix на този URL адрес",
"allowInvalidCertificate": "Разрешаване на невалиден сертификат",
"allowInvalidCertificateDesc": "Използвайте само за надеждни самостоятелно хоствани сървъри със самоподписани или IP-адресни сертификати.",
"savedServers": "Запазени сървъри",
"removeServer": "Премахване",
"continueButton": "Продължи",
"cancelButton": "Отказ",
"signInTitle": "Влезте в {{url}}",
"originTitle": "Произход на връзката",
"originDescription": "Изберете откъде произлизат SSH връзките по подразбиране. Това може да се промени за всеки хост.",
"originLocal": "Това устройство (локална мрежа)",
"originRemote": "Отдалечен сървър",
"bannerReconnect": "Свържете се отново",
"bannerMessage": "Дистанционната синхронизация изисква повторно удостоверяване"
},
"versionCheck": {
"error": "Грешка при проверка на версията",
"checkFailed": "Проверката за актуализации не бе успешна",
@@ -602,6 +641,7 @@
"overrideCredentialUsername": "Замяна на потребителско име за идентификационни данни",
"overrideCredentialUsernameDesc": "Използвайте посоченото по-горе потребителско име вместо потребителското име от идентификационните данни",
"oidcUsernameHint": "Използвайте $oidc.preferred_username, за да заместите вашето OIDC потребителско име.",
"tailscaleUsernameHint": "Това трябва да е Unix потребител, чиято самоличност на Tailscale е предоставена в SSH ACL на tailnet, не е задължително root.",
"jumpHostChain": "Верига за прескачане на хост",
"portKnocking": "Порт Нокинг",
"addKnock": "Добавяне на порт",
@@ -650,6 +690,11 @@
"delayAfterMs": "Закъснение след (ms)",
"useSocks5Proxy": "Използвайте SOCKS5 прокси",
"useSocks5ProxyDesc": "Маршрутизиране на връзката през прокси сървър",
"connectionOrigin": "Произход на връзката",
"connectionOriginDesc": "Откъде произлиза SSH връзката на този хост. Заменя глобалната настройка по подразбиране на настолното приложение.",
"connectionOriginDefault": "Използвай по подразбиране",
"connectionOriginLocal": "Това устройство (локална мрежа)",
"connectionOriginRemote": "Отдалечен сървър",
"proxyHost": "Прокси хост",
"proxyPort": "Прокси порт",
"proxyUsername": "Потребителско име на прокси",
@@ -762,6 +807,14 @@
"customThemeBrightCyan": "Ярко циан",
"customThemeBrightWhite": "Ярко бяло",
"customThemeResetTooltip": "Възстановяване на фабричните настройки",
"savedThemesLabel": "Запазени теми",
"saveAsGlobalTheme": "Запазване като глобална тема",
"saveGlobalThemeNamePrompt": "Въведете име за тази тема",
"saveGlobalThemeSuccess": "Темата е запазена",
"saveGlobalThemeError": "Запазването на темата не бе успешно",
"applyGlobalThemeTooltip": "Приложете тази тема",
"deleteGlobalThemeTooltip": "Изтрий тази тема",
"noSavedThemes": "Все още няма запазени теми",
"syntaxHighlightingLabel": "Подчертаване на синтаксиса",
"syntaxHighlightingDesc": "Оцветяване на изхода на терминала (грешки, пътища, IP адреси, времеви отпечатъци)",
"syntaxHighlightingCategories": "Маркирайте категориите",
@@ -791,6 +844,8 @@
"enableAutoTmuxDesc": "Автоматично стартиране или прикачване към tmux сесия",
"enableSessionLogging": "Записване на сесии",
"enableSessionLoggingDesc": "Записване на изхода от терминалната сесия за по-късен преглед",
"allowSessionSharing": "Разрешаване на споделяне на сесия",
"allowSessionSharingDesc": "Позволете споделянето на сесиите на живо на този хост чрез линк или с други потребители",
"enableCommandHistory": "История на командите",
"enableCommandHistoryDesc": "Запис на команди, изпълнявани в този терминал, за история и автоматично довършване",
"linkClickBehaviorLabel": "Поведение при кликване върху връзки",
@@ -895,6 +950,7 @@
"proxmoxResultImported": "{{count}} импортирано",
"proxmoxResultUpdated": "{{count}} актуализирано",
"proxmoxResultFailed": "{{count}} неуспешно",
"proxmoxResultSkippedNoIp": "{{count}} пропуснато (не е намерен IP адрес)",
"proxmoxImportComplete": "Импортирането на Proxmox е завършено: {{summary}}",
"proxmoxDiscoveryFailed": "Откриването не беше успешно",
"proxmoxImportFailed": "Импортирането не бе успешно",
@@ -961,6 +1017,9 @@
"failedToSaveCredential": "Запазването на идентификационните данни не бе успешно",
"credentialNameRequired": "Моля, въведете име за идентификационните данни",
"credentialAuthRequired": "Добавете парола, SSH ключ или и двете",
"createCredentialFromHostBtn": "Създаване на идентификационни данни",
"createCredentialFromHostTitle": "Създаване на идентификационни данни от хост",
"createCredentialFromHostDesc": "Създайте запис за многократна употреба и споделяне на идентификационни данни, предварително попълнен с текущото потребителско име, парола и/или SSH ключ на този хост.",
"backToHosts": "Обратно към Домакини",
"backToCredentials": "Обратно към удостоверенията",
"pinned": "Закачено",
@@ -1000,6 +1059,9 @@
"folderNestingHint": "Използвайте / за разделяне на нивата и създаване на вложени папки.",
"folderColor": "Цвят",
"folderIcon": "Икона",
"folderCredential": "Пълномощия",
"folderCredentialNone": "Няма присвоени идентификационни данни",
"folderCredentialHint": "Хостовете в тази папка, които използват удостоверяване „Съхранени идентификационни данни“, без да са избрани собствени идентификационни данни, ще наследят тези.",
"folderPreview": "Преглед",
"folderNameFallback": "Неозаглавена папка",
"createFolderButton": "Създаване на папка",
@@ -1181,6 +1243,10 @@
"filterTagsGroup": "Етикети",
"shareHost": "Споделяне на хост",
"shareHostTitle": "Споделяне: {{name}}",
"shareFolder": "Споделяне на папка",
"shareFolderTitle": "Споделяне на папка: {{name}}",
"folderSharedSuccessfully": "Споделени {{count}} хост(ове) в папка",
"failedToShareFolder": "Споделянето на папката не бе успешно",
"sharing": {
"loadError": "Зареждането на данните за споделяне не бе успешно. Моля, опитайте отново.",
"shareWithSection": "Сподели с",
@@ -1221,6 +1287,7 @@
"shareWithCount": "Споделяне ({{count}})",
"currentAccess": "Текущ достъп",
"noAccessEntries": "Този хост все още не е споделен",
"folderShareSummary": "Споделени {{shared}} от {{total}} хост(ове) в тази папка",
"grantedBy": "Предоставено от",
"expires": "Изтича",
"expired": "Изтекъл",
@@ -1242,6 +1309,8 @@
"authMethod": "Метод за удостоверяване",
"authTypeDirect": "Директно",
"authTypeCredential": "Пълномощия",
"authTypeNone": "Няма",
"authTypeNoneDesc": "Не се съхраняват идентификационни данни. Ще бъдете подканени да въведете потребителско име и парола всеки път, когато се свържете; те не се запазват.",
"selectCredential": "Изберете идентификационен номер...",
"connectionSettings": "Настройки за връзка",
"displaySettings": "Настройки на дисплея",
@@ -1259,6 +1328,7 @@
"rdpPort": "RDP порт",
"username": "Потребителско име",
"password": "Парола",
"passwordSaved": "Паролата е запазена, въведете, за да я промените",
"domain": "Домейн",
"securityMode": "Режим на сигурност",
"colorDepth": "Дълбочина на цвета",
@@ -1424,7 +1494,60 @@
"expiresIn": "Изтича след {{duration}}",
"search": "Търсене на връзки...",
"noSearchResults": "Няма връзки, които да отговарят на търсенето ви",
"rename": "Преименуване на сесия"
"rename": "Преименуване на сесия",
"sectionSharedWithMe": "Споделено с мен",
"sharedBy": "Споделено от {{username}}",
"join": "Присъединете се",
"sharedSessionLabel": "{{hostName}} (споделено)"
},
"sessionSharing": {
"guestView": {
"loading": "Свързване със споделена сесия...",
"linkInvalid": "Този линк за споделяне е невалиден, изтекъл или е отменен",
"rateLimited": "Твърде много опити, моля опитайте отново скоро",
"sessionEnded": "Тази сесия приключи",
"readOnlyBadge": "Само преглед"
},
"modalTitle": "Споделяне на сесия",
"shareButton": "Споделяне",
"notReadyToShare": "Сесията все още не е готова за споделяне",
"modeTab": {
"link": "Връзка",
"user": "Потребител"
},
"linkModeDescription": "Всеки с този линк може да се присъедини, не е необходим акаунт.",
"userModeDescription": "Споделете с конкретен потребител, който вече има достъп до този хост. Ако все още няма достъп, първо споделете хоста с него или използвайте връзка. След като бъде споделена, сесията се показва в раздела му „Връзки“.",
"permissionLevel": {
"label": "Ниво на разрешение",
"readOnly": "Само за четене",
"readOnlyDescription": "Може да гледа сесията на живо, но не може да пише или да взаимодейства.",
"readWrite": "Четене и запис",
"readWriteDescription": "Може да пише и да взаимодейства със сесията точно като собственика."
},
"expiryLabel": "Изтичане на срока на валидност на връзката",
"createLinkButton": "Създаване на връзка",
"createShareButton": "Споделяне с потребителя",
"searchUsersPlaceholder": "Търсене на потребители...",
"noUsersFound": "Не са намерени потребители",
"linkCreated": "Линкът за споделяне е създаден",
"linkCopied": "Връзката е копирана в буферната памет",
"copyLink": "Копиране на връзката",
"shareCreated": "Сесията е споделена. Тя ще се покаже в раздела им „Връзки“.",
"shareFailed": "Създаването на споделено съдържание не бе успешно",
"userLacksHostAccess": "Тозият потребител все още няма достъп до този хост. Първо споделете хоста с него или използвайте линк.",
"activeShares": "Активни акции",
"noActiveShares": "Няма активни споделяния за тази сесия",
"revoke": "Отмяна",
"revokeConfirmTitle": "Да се отмени ли това споделяне?",
"revokeConfirmDescription": "Всеки, който използва това споделяне, ще загуби достъп незабавно.",
"revoked": "Акцията е отменена",
"revokeFailed": "Неуспешно отменяне на споделянето",
"joinCount": "{{count}} присъединяване",
"joinCount_other": "{{count}} се присъединява",
"expiresAt": "Изтича {{date}}",
"linkShareBadge": "Връзка",
"userShareBadge": "Потребител: {{username}}",
"loadSharesFailed": "Зареждането на активните споделяния не бе успешно"
},
"guacamole": {
"connecting": "Свързване към сесия {{type}}...",
@@ -1436,6 +1559,9 @@
"reconnect": "Свържете се отново",
"retry": "Опитай отново",
"guacdUnavailable": "Услугата за отдалечен работен плот (guacd) не е налична. Моля, уверете се, че guacd работи, е достъпна и е конфигурирана правилно в администраторските настройки.",
"credentialPromptTitle": "Въведете RDP идентификационни данни",
"credentialPromptDescription": "Този хост е настроен да изисква идентификационни данни при свързване. Те се използват само за тази сесия и не се запазват.",
"connect": "Свържете се",
"ctrlAltDel": "Ctrl+Alt+Del",
"toolbar": {
"ctrlAltDel": "Ctrl+Alt+Del",
@@ -1461,7 +1587,9 @@
"reconnect": "Сесия за повторно свързване",
"collapse": "Свиване на лентата с инструменти",
"expand": "Разгъване на лентата с инструменти",
"dragHandle": "Плъзнете, за да препозиционирате"
"dragHandle": "Плъзнете, за да препозиционирате",
"switchToTrackpad": "Превключване в режим на тракпад (плъзнете, за да преместите курсора, докоснете, за да щракнете)",
"switchToTouch": "Превключване към режим на докосване (докоснете директно там, където искате да щракнете)"
}
},
"terminal": {
@@ -1508,6 +1636,11 @@
"totpRequired": "Изисква се двуфакторно удостоверяване",
"totpCodeLabel": "Код за потвърждение",
"totpVerify": "Проверка",
"mfaPromptRequired": "Изисква се удостоверяване",
"mfaPushRequired": "Изисква се удостоверяване чрез push",
"mfaMenuPlaceholder": "Въведете отговора си",
"mfaWaitingApproval": "Чака се одобрение на вашето устройство...",
"mfaSendRequest": "Изпрати заявка",
"warpgateAuthRequired": "Изисква се удостоверяване на Warpgate",
"warpgateSecurityKey": "Ключ за сигурност",
"warpgateAuthUrl": "URL адрес за удостоверяване",
@@ -2277,7 +2410,8 @@
"resetCodeRateLimited": "Ограничена скорост: Твърде много опити за потвърждение. Моля, опитайте отново по-късно.",
"resetCodeRateLimitedWithTime": "Ограничена скорост: Твърде много опити за потвърждение. Моля, изчакайте {{time}} секунди, преди да опитате отново.",
"authTokenSaveFailed": "Запазването на токена за удостоверяване не бе успешно",
"failedToLoadServer": "Зареждането на сървъра не бе успешно"
"failedToLoadServer": "Зареждането на сървъра не бе успешно",
"remoteServerRequired": "Изисква се отдалечен сървър. Свържете се с отдалечен сървър в „Настройки“, за да използвате този тип връзка."
},
"messages": {
"registrationDisabled": "Регистрацията на нов акаунт в момента е деактивирана от администратор. Моля, влезте или се свържете с администратор.",
@@ -2644,6 +2778,17 @@
"sslSaveFailed": "Запазването на настройките за SSL не бе успешно",
"sslRequiresDomain": "Домейнът и имейлът са задължителни",
"sslInfoNote": "След издаване на сертификат, активирайте SSL в променливите на средата (ENABLE_SSL=true) и рестартирайте Termix.",
"sslManualOption": "Ръководство (сертификат за качване)",
"sslManualCert": "Сертификат (PEM)",
"sslManualCertPlaceholder": "-----ЗАПОЧВАНЕ НА СЕРТИФИКАТ-----",
"sslManualKey": "Частен ключ (PEM)",
"sslManualKeyPlaceholder": "-----ЗАПОЧВАНЕ НА ЛИЧЕН КЛЮЧ-----",
"sslManualDesc": "Поставете съществуващия си сертификат и частен ключ, включително пълната верига, ако се изисква от вашия CA.",
"sslManualUpload": "Сертификат за качване и инсталиране",
"sslManualUploadLoading": "Качване на сертификат...",
"sslManualUploadSuccess": "Сертификатът е качен и инсталиран успешно",
"sslManualUploadFailed": "Качването на сертификата не бе успешно",
"sslManualRequiresFields": "Изискват се сертификат и частен ключ",
"auditLogTotal": "{{total}} общо записи",
"auditLogEmpty": "Няма намерени записи в журнала за одит",
"auditLogSuccess": "Успех",
@@ -2672,6 +2817,12 @@
"commandHistoryEnabled": "История на командите",
"commandHistoryEnabledDesc": "Разрешаване на записване на историята на командите. Когато е деактивирано, историята не се запазва, независимо от настройките за всеки хост.",
"updateCommandHistoryFailed": "Актуализирането на настройката за историята на командите не бе успешно",
"analyticsEnabled": "Споделяне на анонимни статистически данни за употреба",
"analyticsEnabledDesc": "Изпраща анонимен дневен брой потребители, хостове и използване на функции, за да помогне за подобряването на Termix. Никога не се включват лични данни или подробности за връзката.",
"updateAnalyticsFailed": "Актуализирането на настройката за анализ не бе успешно",
"sessionSharingGloballyEnabled": "Разрешаване на споделяне на сесия",
"sessionSharingGloballyEnabledDesc": "Разрешава споделянето на сесии на живо на терминал, RDP, VNC и Telnet в целия екземпляр. Заменя всяко превключвател за споделяне на хост, когато е деактивиран.",
"updateSessionSharingFailed": "Актуализирането на настройката за споделяне на сесията не бе успешно",
"sessionTimeout": "Време за изчакване на сесията",
"hours": "часове",
"sessionTimeoutRange": "Мин. 1 ч. · Макс. 720 ч.",
@@ -3119,6 +3270,47 @@
"executionSuccess": "Успех",
"executionFailed": "Неуспешно"
},
"keybindings": {
"title": "Клавишни комбинации",
"description": "Персонализирайте клавишните комбинации за копиране, поставяне и управление на терминала или обвържете клавишите за изпращане на текст или изпълнение на фрагмент.",
"defaultsHeading": "Вградени преки пътища",
"customHeading": "Персонализирани преки пътища",
"addBinding": "Добавяне на пряк път",
"addBindingTitle": "Добавяне на пряк път",
"editBindingTitle": "Редактиране на пряк път",
"loading": "Зареждане...",
"noCustomBindings": "Все още няма персонализирани преки пътища",
"defaultBadge": "По подразбиране",
"customizedBadge": "Персонализирано",
"customize": "Персонализиране",
"resetToDefault": "Възстановяване на фабричните настройки",
"resetAllToDefaults": "Възстановяване на всички настройки по подразбиране",
"close": "Затвори",
"cancel": "Отказ",
"saveBinding": "Запазване на пряк път",
"saveError": "Запазването на клавишните комбинации не бе успешно",
"pressKeysToRecord": "Комбинация от клавиши",
"pressKeysPlaceholder": "Щракнете и натиснете клавиши",
"recording": "Натиснете клавишите...",
"comboRequiredError": "Първо натиснете клавишна комбинация",
"textRequiredError": "Въведете текста за изпращане",
"controlCodeRequiredError": "Въведете една буква за контролния код",
"snippetRequiredError": "Изберете фрагмент",
"conflictWarning": "Тази комбинация вече е свързана с {{combo}}. Запазването ще доведе до задействане и на двете.",
"actionLabel": "Действие",
"actionCopy": "Копиране на селекцията",
"actionPaste": "Паста",
"actionSendControlCode": "Изпрати сигнал Ctrl+буква",
"actionSendText": "Изпращане на текст",
"actionRunSnippet": "Изпълнете съществуващия фрагмент",
"controlCodeLabel": "Писмо",
"textLabel": "Текст за изпращане",
"appendEnterLabel": "Натиснете Enter след изпращане",
"snippetLabel": "Фрагмент",
"selectSnippetPlaceholder": "Изберете фрагмент",
"orphanedSnippetWarning": "фрагмент не е намерен",
"clipboardPermissionNote": "Може да поиска разрешение за достъп до клипборда при първото използване в някои браузъри."
},
"userProfile": {
"donateTitle": "Пази Термикс жив",
"donateDescription": "Termix е безплатен, самостоятелно хостван и изграден само от няколко души в свободното им време. Ако ви е спестил време или пари, дарението от крипто помага да продължи да функционира.",
@@ -3134,6 +3326,7 @@
"sectionAppearance": "Външен вид",
"sectionSecurity": "Сигурност",
"sectionApiKeys": "API ключове",
"sectionData": "Данни",
"sectionC2sTunnels": "Тунели C2S",
"usernameLabel": "Потребителско име",
"roleLabel": "Роля",
@@ -3162,6 +3355,9 @@
"settingsTerminal": "Терминал",
"commandAutocomplete": "Автоматично довършване на команди",
"commandAutocompleteDesc": "Показване на автоматично довършване при въвеждане",
"keyboardShortcuts": "Клавишни комбинации",
"keyboardShortcutsDescription": "Персонализиране на клавишните комбинации за копиране, поставяне и команди в терминала",
"manageShortcuts": "Управление",
"terminalLinkBehavior": "Щракване върху връзката на терминала",
"terminalLinkBehaviorDesc": "Поведение по подразбиране при кликване върху връзки в терминала",
"historyTracking": "Проследяване на историята",
@@ -3228,6 +3424,22 @@
"apiKeyUsageHint": "Включете ключа си в",
"apiKeyUsageHintHeader": "заглавка.",
"apiKeyPermissionsHint": "Ключовете наследяват разрешенията на потребителя, който ги е създал.",
"exportData": "Експортиране на моите данни",
"exportDataDesc": "Изтеглете резервно копие на вашите хостове, идентификационни данни и настройки, за да ги прехвърлите на друго устройство",
"export": "Експорт",
"exporting": "Експортиране...",
"importData": "Импортиране на моите данни",
"importDataDesc": "Възстановете вашите хостове, идентификационни данни и настройки от .sqlite архивен файл",
"importDataSelected": "Избрано: {{name}}",
"selectFile": "Изберете файл",
"changeFile": "Промяна",
"import": "Внос",
"importing": "Импортиране...",
"exportSuccess": "Данните са експортирани успешно",
"exportFailed": "Експортирането на данни не бе успешно",
"importSelectFile": "Моля, първо изберете файл",
"importCompleted": "Импортирането е завършено: {{total}} елемента са импортирани, {{skipped}} са пропуснати",
"importFailed": "Импортирането не бе успешно: {{error}}",
"roleUser": "Потребител",
"authMethodDual": "Двойно удостоверяване",
"authMethodOidc": "OIDC",
@@ -3379,6 +3591,7 @@
"pageUp": "PgUp",
"pageDown": "PgDn",
"delete": "Дел",
"paste": "Паста",
"editQuickKeys": "Редактиране на бързи клавиши",
"quickKeysTitle": "Бързи клавиши",
"quickKeysDesc": "Докоснете × за премахване. Поддържа до 8 знака.",