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": "ห่วงโซ่ Jump Host",
"portKnocking": "การเคาะพอร์ต",
"addKnock": "เพิ่มพอร์ต",
@@ -650,6 +690,11 @@
"delayAfterMs": "เวลาหน่วงหลังจาก (มิลลิวินาที)",
"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": "ต้องมีการตรวจสอบสิทธิ์แบบพุช",
"mfaMenuPlaceholder": "กรุณาป้อนคำตอบของคุณ",
"mfaWaitingApproval": "กำลังรอการอนุมัติบนอุปกรณ์ของคุณ...",
"mfaSendRequest": "ส่งคำขอ",
"warpgateAuthRequired": "ต้องยืนยันตัวตนผ่านวาร์ปเกต",
"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": "รักษา Termix ให้คงอยู่ต่อไป",
"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": "โอไอดีซี",
@@ -3379,6 +3591,7 @@
"pageUp": "พีจีอัพ",
"pageDown": "พีจีดีเอ็น",
"delete": "เดล",
"paste": "แปะ",
"editQuickKeys": "แก้ไขปุ่มลัด",
"quickKeysTitle": "ปุ่มลัด",
"quickKeysDesc": "แตะ × เพื่อลบ รองรับได้สูงสุด 8 ตัวอักษร",