release-2.9.1 (#1557)

* fix(sso): send the PKCE verifier for GitHub login (#1534)

* fix(remote-desktop): clip cursor overflow without disabling zoom (#1535)

* test(remote-desktop): preserve sessions beyond one hour (#1536)

* fix(hosts): expose controls for overflowing editor tabs (#1537)

* fix(hosts): expose controls for overflowing editor tabs

* test(hosts): mock resize observation in admin panel tests

* fix(status): skip TCP probes while host sessions are active (#1538)

* fix(database): batch session activity persistence (#1539)

* docs(api): describe cookie and API key authentication (#1540)

* fix(snippets): repair missing note column on SQLite upgrades (#1541)

* fix(docker): retain stored SSH credential association (#1543)

* fix(file-manager): render transfer toasts without plugin hooks (#1546)

* feat(hosts): keep compact row actions inline (#1547)

* fix(auth): allow retrying unavailable second-factor interfaces (#1549)

* fix(auth): reject unresolved legacy identity provisioning (#1550)

* fix(desktop): ship the plugin SDK inside Mac App Store builds (#1551)

* fix(tmux): pass full session info to the terminal's session picker (#1552)

The tmux.sessions service reduced detected sessions to bare names, but the
picker reads session.name, so every entry rendered blank and selecting one
sent an empty name, which created a new session instead of attaching.

* fix(ssh): read force keyboard-interactive as a boolean when resolving hosts (#1553)

The column holds the text "true"/"false", and the resolver passed it
through as-is. The string "false" is truthy, so the password provider
treated every saved host as forced keyboard-interactive and left the
password out. Jump hops are built straight from the resolved host, so a
password hop whose server doesn't offer keyboard-interactive failed with
"All configured authentication methods failed".

* fix(database): batch database saves for bulk host writes (#1554)

* fix(database): yield to the event loop between database saves

Each SQLite save serializes and encrypts the whole database into new
buffers, which V8 only releases once the event loop turns. Boot
migrations and bulk host import write plugin settings per host and per
key in an awaited loop, so hundreds of full copies piled up and the
container ran out of memory.

* fix(database): save once per bulk host write instead of once per row

On SQLite every repository write force-saves the whole database. Boot
plugin data migrations, host defaults materialization and the bulk
host routes write one row per host per setting, so they serialized and
encrypted the full database hundreds of times in a row.

DatabaseSaveTrigger.batched wraps a function so force saves made while
it runs collapse into a single save when it finishes. Nested scopes fold
into the outer one, and work that outlives its scope saves normally.

* feat(hosts): add instance-wide predefined tag suggestions (#1548)

* feat(hosts): add shared predefined tag suggestions

* style(hosts): format tag catalog routes

* test(database): advance fake timers past the save yield (#1555)

* fix(i18n): complete Simplified Chinese core and plugin translations (#1542)

* fix(i18n): complete Chinese onboarding and navigation labels

* fix(i18n): translate remaining Chinese core and plugin interfaces

* fix(i18n): translate host editor tab overflow controls

* fix(i18n): use consistent Chinese fleet terminology

* fix(i18n): localize hardcoded controls and plugin views

* fix(i18n): translate built-in homepage widget catalog

* test(homepage): follow translated timezone placeholder

* fix(i18n): translate plugin-provided homepage widgets

* fix(i18n): localize feature settings section titles

* fix: 2.8 oidc accounts unable to sign in after upgrading (#1381)

* fix: plugins losing the saved ssh login when copying a host (#1391)

* fix: fleets, proxmox and automations not getting the host sudo password

* fix: host imports running a defaults pass and metrics restart per host (#1384)

* fix: high cpu from status probes and full database saves on every sample (#1300)

* fix: user data export freezing the server (#1393)

* fix: op:// secret references rejected as ssh keys on credentials (#1394)

* fix: slow file deletes from the trash lookups on every delete (#1390)

* fix: add openapi docs and error handling to host tag routes

* test: compare download stream buffers directly so it stops timing out

* chore: drop em dash from host row comment

* chore: update release notes for 2.9.1

* fix: restore space to add host tags and redesign predefined tags editor

* fix: host key silently accepted when the host is missing from the database (#1397)

* fix: clearer host login failed status label and fix its translations (#1396)

* chore: add host key and status label fixes to release notes

* fix: sso and ldap provider dialogs overflowing the screen and using mismatched toggles

* chore: increment ver

* fix(audit): store plugin entries with no acting user as a null user_id (#1556)

Plugin audit entries written outside a request used the literal "system"
as user_id. That column references users.id, so the insert was refused
(Postgres logs it as an FK violation) and the entry was silently dropped.
Write null instead and keep "system" / plugin:<id> in username.

* chore: add sso/ldap dialog and audit log fixes to release notes

* fix: tunnels and host settings missing from shared hosts on desktop

* fix: remote desktop logins missing from shared hosts on desktop

* fix: simplify host status to online/offline and keep it live without a refresh

* chore: sync Crowdin translations for 2.9.1

---------

Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
This commit is contained in:
Luke GustafsonandZacharyZcR authored and GitHub committed 2026-10-04 15:11:41 -05:00
1 parent 5786eaccbb
commit 6b708106e1
912 files changed
+14220 -2200

No files matched your search

+38 -81
View File
@@ -1,6 +1,6 @@
<!-- SUMMARY --> <!-- SUMMARY -->
A new plugin system powering every feature, a dedicated sync page with more control over what syncs, one inbox for all alerts, a redesigned split screen, admin, user and folder host defaults, host maintenance mode, and a large batch of file manager, terminal, and remote desktop fixes. A patch for 2.9.0 that fixes OIDC sign-in after upgrading, Docker and Host Metrics logins, memory and CPU use, file downloads, tmux sessions, user data export and more. Also adds predefined host tags.
<!-- /SUMMARY --> <!-- /SUMMARY -->
@@ -12,90 +12,47 @@ https://youtu.be/lngaePO96tM
<!-- UPDATE_LOG --> <!-- UPDATE_LOG -->
- Rebuilt Termix around a plugin system, with features like the terminal, file manager, tunnels, Docker, Proxmox, remote desktop, metrics, automations, AI and every login method now shipped as signed plugins on a shared SDK - Added predefined host tags that admins can set, with suggestions in the host editor
- Moved desktop sync to its own page in the sidebar, with options to choose what syncs, keep single hosts or folders on the device only, and resolve conflicts - Kept compact host row actions on the same line as the host name
- Added a recent servers list when linking the desktop app - Added a reload button when a sign-in verification method fails to load
- Combined all alerts into one inbox with popups, Termix announcements and a new email channel - Admins can now merge a duplicate SSO account made by 2.9.0 back into the original account
- Redesigned split screen with free-form panes and a pane picker - Hosts behind the same jump hosts now share one connection for status checks
- Redesigned host defaults so they can be set at the admin, user or folder level and are inherited by hosts unless overridden - Simplified host status to just online or offline, removing the "last login failed" state
- Added per-host maintenance mode and recurring schedules to automations - Host status now updates every 15 seconds without a page refresh, and status checks run every 30 seconds by default
- Added optional auto reconnect for dropped SSH sessions and a button to reconnect all disconnected terminal tabs - Completed the Simplified Chinese translation
- Added a duplicate tab action and a reconnect session keybinding - Documented cookie and API key sign-in in the API docs
- Added a host click setting to either focus an existing tab or always open a new one
- Added keyboard type-ahead search to the host list
- Added tighter compact host rows with inline tags
- Added an option to show tab numbers
- Added an option to hide folder paths above nested folders
- Added a list of the fixed app shortcuts to the keyboard shortcuts screen
- Added terminal toolbar position, start state and fade settings per host
- Added a host setting to turn off password prompt auto-fill
- Added the option to apply a saved custom theme in connection defaults
- Added FortiToken push 2FA support for SSH
- Added a unified multi-host tmux monitor view and a per-host tmux mouse toggle
- Added fleet sharing
- Added a list view to Docker management and support for the OrbStack Docker socket on macOS
- Added network graph sync between the desktop app and the server
- Added homepage canvas layout sync across devices
- Added RDP display zoom controls
- Added an option to skip the move to trash confirmation in the file manager
- Made the file manager open in the remote login directory by default
- Added add host and copy IP actions for Tailscale devices
- Added inline credential sharing in the sidebar, matching host sharing
- Made the Windows desktop shortcut optional in the installer
- Redesigned the snippets panel to match the host list
- Redesigned the session log player controls
- Host status now shows online once the port answers and only warns when a login fails
- Faster SFTP downloads
- Faster UI loading with less jitter and lag across tabs, the dashboard and the network graph
<!-- /UPDATE_LOG --> <!-- /UPDATE_LOG -->
<!-- BUG_FIXES --> <!-- BUG_FIXES -->
- TOTP not being prompted for jump hosts in the terminal, file manager, metrics and client tunnels - OIDC accounts from 2.8 not being able to sign in, or getting a new empty account, after upgrading
- SSH host names resolving to IPv6 when IPv4 was available - Downloading a file in the file manager turning the whole screen black
- Host key updates not syncing between devices - tmux sessions not resuming and new sessions being created instead
- Host metrics returning 404 on the first connect - Connections through two or more jump hosts failing
- Host metrics using too much CPU on the backend - Docker and Host Metrics failing to sign in while the terminal worked
- Host metrics showing image and firmware filesystems - Fleets, Proxmox and automations not getting the host sudo password
- Sudo password not auto-filling - Server running out of memory on start and when importing hosts
- Tunnels failing with shared credentials - High CPU use after the app was first opened
- Imported jump host references breaking - User data export freezing the server
- Hard to read terminal selection with the light theme - 1Password and other secret references being rejected as SSH keys
- Terminal input arriving out of order with local echo on - Slow file deletes in the file manager
- Terminal image uploads failing when the image library was unavailable - Mac App Store app failing to start its local server
- File manager saves failing or corrupting files, with no sudo prompt on protected files - Snippets failing to sync on older databases
- Sending a single file between servers failing - GitHub sign in failing
- Disk usage showing the wrong mount or not refreshing with the directory - RDP showing scrollbars and jittering near the edges
- File uploads not cancelling and continuing to write on the server - Status checks triggering Fail2Ban bans while a session was open
- Ctrl/Cmd+F file search not working in the file manager - Too many database writes from session activity
- File drops from the OS not working over existing rows - Host editor tabs being hidden when they did not fit
- No download progress in file viewers - SSH host keys being accepted without a check when the host was missing from the database
- Text in Markdown previews not being selectable - Host status only updating after a full page refresh
- Inline rename, compact mode and narrow list layout issues in the file manager - Every host showing offline right after signing in
- Remote desktop not using the host's saved guacd endpoint - Host status flipping between online and offline on refresh or after one dropped packet
- Remote desktop asking for clipboard access unprompted - Hosts showing "last login failed" when they connected fine
- Remote desktop keys staying held after switching windows - Hosts behind a jump host staying offline after the jump connection dropped
- Session share links on desktop pointing at the local app instead of the server - Host status being wiped in the desktop app when the host list failed to load
- Shared terminal sizes and participant presence not syncing in session sharing - Tunnels, remote desktop logins and other host settings missing from shared hosts in the desktop app
- Meeting guests not being shown to members, and guests seeing the full roster - SSO and LDAP provider dialogs overflowing the screen and using mismatched toggles
- Session sharing not handing over cleanly after a takeover - Plugin audit log entries failing to save when no user was signed in
- AI responses getting cut off mid stream
- AI provider settings not syncing to linked devices
- Proxmox guest sync and startup snippet sync not working
- LDAP logins losing the bind DN from the directory
- Homepage service checks failing for allowed private addresses
- Sidebar search showing overlapping hosts when grouped by tags
- Sidebar rows not resizing after changing density, and compact rows hiding host addresses
- Split screen layouts failing to create over plain HTTP
- Double Shift opening the command palette by accident
- Fleet detail buttons overflowing the sidebar
- Recent activity cutting off host names too early
- Docker container logs using the wrong background color
- Version number missing on desktop when the server was offline
- Desktop app not starting reliably, not quitting with active connections, and the Linux tray icon failing to load
- Mac App Store builds being blocked by the single instance lock
- Untranslated text in toasts and other parts of the UI
- Several dependency security advisories
<!-- /BUG_FIXES --> <!-- /BUG_FIXES -->
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "termix", "name": "termix",
"version": "2.9.0", "version": "2.9.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "termix", "name": "termix",
"version": "2.9.0", "version": "2.9.1",
"hasInstallScript": true, "hasInstallScript": true,
"workspaces": [ "workspaces": [
"packages/*", "packages/*",
+1 -1
View File
@@ -5,7 +5,7 @@
"packages/*", "packages/*",
"plugins/*" "plugins/*"
], ],
"version": "2.9.0", "version": "2.9.1",
"description": "Self-hosted SSH and remote desktop management.", "description": "Self-hosted SSH and remote desktop management.",
"author": "Karmaa", "author": "Karmaa",
"main": "electron/main.cjs", "main": "electron/main.cjs",
+12 -4
View File
@@ -840,19 +840,24 @@ export interface PluginHosts {
status: PluginHostStatusApi; status: PluginHostStatusApi;
} }
/** online: a login worked. reachable: the port answers. offline: it does not. */ /**
* online: the port answers, a session is open or a login worked. offline: the
* port does not answer. "reachable" is no longer sent and stays only so older
* plugins still type check.
*/
export type PluginHostStatus = "online" | "reachable" | "offline"; export type PluginHostStatus = "online" | "reachable" | "offline";
export interface PluginHostStatusEntry { export interface PluginHostStatusEntry {
status: PluginHostStatus; status: PluginHostStatus;
lastChecked: string; lastChecked: string;
/** @deprecated No longer sent. */
reason?: "host_key_changed"; reason?: "host_key_changed";
} }
/** /**
* Core checks every host with status checks on by opening a TCP connection to * Core checks every host with status checks on by opening a TCP connection to
* it. A plugin that logs in to hosts tells core how that went, which is what * it. A plugin that logs in to hosts can report a working login, which marks
* turns "reachable" into "online". * the host online right away.
*/ */
export interface PluginHostStatusApi { export interface PluginHostStatusApi {
/** /**
@@ -862,7 +867,10 @@ export interface PluginHostStatusApi {
get: (hostId: number) => Promise<PluginHostStatusEntry | null>; get: (hostId: number) => Promise<PluginHostStatusEntry | null>;
/** Checks the host now unless core checked it recently. */ /** Checks the host now unless core checked it recently. */
check: (hostId: number) => Promise<PluginHostStatusEntry | null>; check: (hostId: number) => Promise<PluginHostStatusEntry | null>;
/** Reports a login attempt. Not audited: pollers call it every sample. */ /**
* Reports a login attempt. Only a working login changes the status; a
* failed one is ignored. Not audited: pollers call it every sample.
*/
reportLogin: ( reportLogin: (
hostId: number, hostId: number,
outcome: { ok: boolean; hostKeyChanged?: boolean }, outcome: { ok: boolean; hostKeyChanged?: boolean },
+5 -3
View File
@@ -76,7 +76,7 @@ export interface PluginHostRecord {
quickConnectSavable?: boolean; quickConnectSavable?: boolean;
/** Assigned when a host is opened in a tab; tells duplicate tabs apart. */ /** Assigned when a host is opened in a tab; tells duplicate tabs apart. */
instanceId?: string; instanceId?: string;
/** Core's status: "online" once a login worked. */ /** Core's status: "online" when the host answers. */
status?: "online" | "reachable" | "offline" | "unknown"; status?: "online" | "reachable" | "offline" | "unknown";
online?: boolean; online?: boolean;
/** Someone else owns this host and shared it with the user. */ /** Someone else owns this host and shared it with the user. */
@@ -1134,11 +1134,13 @@ export interface ActivityTargetInfo {
} }
/** /**
* Core's status for a host, the one behind the host list's dot. online: a * Core's status for a host, the one behind the host list's dot. online: the
* login worked. reachable: the port answers. unknown: not checked yet. * port answers. offline: it does not. unknown: not checked yet. "reachable"
* is no longer sent and stays only so older plugins still type check.
*/ */
export interface HostStatusInfo { export interface HostStatusInfo {
status: "online" | "reachable" | "offline" | "unknown"; status: "online" | "reachable" | "offline" | "unknown";
/** @deprecated No longer sent. */
reason?: "host_key_changed"; reason?: "host_key_changed";
} }
+15 -9
View File
@@ -30,6 +30,20 @@ function copyPluginSdk(resourcesDir, sdkDir = path.join(repoRoot, "packages", "p
exports.copyPluginSdk = copyPluginSdk; exports.copyPluginSdk = copyPluginSdk;
/** Mac App Store builds report "mas", not "darwin", but are still .app bundles. */
function resourcesDirFor({ electronPlatformName, appOutDir, packager }) {
return ["darwin", "mas"].includes(electronPlatformName)
? path.join(
appOutDir,
`${packager.appInfo.productFilename}.app`,
"Contents",
"Resources",
)
: path.join(appOutDir, "resources");
}
exports.resourcesDirFor = resourcesDirFor;
exports.default = async function afterPack(context) { exports.default = async function afterPack(context) {
const { targets, appOutDir } = context; const { targets, appOutDir } = context;
@@ -39,15 +53,7 @@ exports.default = async function afterPack(context) {
fs.writeFileSync(markerPath, ""); fs.writeFileSync(markerPath, "");
} }
const resourcesDir = const resourcesDir = resourcesDirFor(context);
context.electronPlatformName === "darwin"
? path.join(
appOutDir,
`${context.packager.appInfo.productFilename}.app`,
"Contents",
"Resources",
)
: path.join(appOutDir, "resources");
copyPluginSdk(resourcesDir); copyPluginSdk(resourcesDir);
+3
View File
@@ -54,5 +54,8 @@
"request": "Request certificate now", "request": "Request certificate now",
"requesting": "Requesting certificate...", "requesting": "Requesting certificate...",
"issued": "Certificate issued and installed" "issued": "Certificate issued and installed"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Versoek nou 'n sertifikaat", "request": "Versoek nou 'n sertifikaat",
"requesting": "Versoek sertifikaat...", "requesting": "Versoek sertifikaat...",
"issued": "Sertifikaat uitgereik en geïnstalleer" "issued": "Sertifikaat uitgereik en geïnstalleer"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "اطلب الشهادة الآن", "request": "اطلب الشهادة الآن",
"requesting": "جارٍ طلب الشهادة...", "requesting": "جارٍ طلب الشهادة...",
"issued": "تم إصدار الشهادة وتركيبها" "issued": "تم إصدار الشهادة وتركيبها"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Заявете сертификат сега", "request": "Заявете сертификат сега",
"requesting": "Заявка за сертификат...", "requesting": "Заявка за сертификат...",
"issued": "Сертификат издаден и инсталиран" "issued": "Сертификат издаден и инсталиран"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "এখনই সার্টিফিকেটের জন্য অনুরোধ করুন", "request": "এখনই সার্টিফিকেটের জন্য অনুরোধ করুন",
"requesting": "সার্টিফিকেটের জন্য অনুরোধ...", "requesting": "সার্টিফিকেটের জন্য অনুরোধ...",
"issued": "সার্টিফিকেট ইস্যু এবং ইনস্টল করা হয়েছে" "issued": "সার্টিফিকেট ইস্যু এবং ইনস্টল করা হয়েছে"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Sol·licita el certificat ara", "request": "Sol·licita el certificat ara",
"requesting": "Sol·licitant certificat...", "requesting": "Sol·licitant certificat...",
"issued": "Certificat emès i instal·lat" "issued": "Certificat emès i instal·lat"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Vyžádejte si certifikát nyní", "request": "Vyžádejte si certifikát nyní",
"requesting": "Žádost o certifikát...", "requesting": "Žádost o certifikát...",
"issued": "Certifikát vydán a nainstalován" "issued": "Certifikát vydán a nainstalován"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Anmod om certifikat nu", "request": "Anmod om certifikat nu",
"requesting": "Anmoder om certifikat...", "requesting": "Anmoder om certifikat...",
"issued": "Certifikat udstedt og installeret" "issued": "Certifikat udstedt og installeret"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Zertifikat jetzt anfordern", "request": "Zertifikat jetzt anfordern",
"requesting": "Zertifikat wird angefordert...", "requesting": "Zertifikat wird angefordert...",
"issued": "Zertifikat ausgestellt und installiert" "issued": "Zertifikat ausgestellt und installiert"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Ζητήστε πιστοποιητικό τώρα", "request": "Ζητήστε πιστοποιητικό τώρα",
"requesting": "Αίτημα πιστοποιητικού...", "requesting": "Αίτημα πιστοποιητικού...",
"issued": "Έκδοση και εγκατάσταση πιστοποιητικού" "issued": "Έκδοση και εγκατάσταση πιστοποιητικού"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Solicita tu certificado ahora", "request": "Solicita tu certificado ahora",
"requesting": "Solicitando certificado...", "requesting": "Solicitando certificado...",
"issued": "Certificado emitido e instalado" "issued": "Certificado emitido e instalado"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Pyydä todistus nyt", "request": "Pyydä todistus nyt",
"requesting": "Pyydetään varmennetta...", "requesting": "Pyydetään varmennetta...",
"issued": "Sertifikaatti myönnetty ja asennettu" "issued": "Sertifikaatti myönnetty ja asennettu"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Demandez votre certificat dès maintenant", "request": "Demandez votre certificat dès maintenant",
"requesting": "Demande de certificat en cours...", "requesting": "Demande de certificat en cours...",
"issued": "Certificat délivré et installé" "issued": "Certificat délivré et installé"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "בקשת תעודה עכשיו", "request": "בקשת תעודה עכשיו",
"requesting": "מבקש תעודה...", "requesting": "מבקש תעודה...",
"issued": "תעודה הונפקה והותקנה" "issued": "תעודה הונפקה והותקנה"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "अभी प्रमाणपत्र का अनुरोध करें", "request": "अभी प्रमाणपत्र का अनुरोध करें",
"requesting": "प्रमाणपत्र अनुरोध किया जा रहा है...", "requesting": "प्रमाणपत्र अनुरोध किया जा रहा है...",
"issued": "प्रमाणपत्र जारी और स्थापित किया गया" "issued": "प्रमाणपत्र जारी और स्थापित किया गया"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Igényeljen tanúsítványt most", "request": "Igényeljen tanúsítványt most",
"requesting": "Tanúsítvány kérése...", "requesting": "Tanúsítvány kérése...",
"issued": "Tanúsítvány kiállítva és telepítve" "issued": "Tanúsítvány kiállítva és telepítve"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Ajukan sertifikat sekarang", "request": "Ajukan sertifikat sekarang",
"requesting": "Meminta sertifikat...", "requesting": "Meminta sertifikat...",
"issued": "Sertifikat telah diterbitkan dan dipasang." "issued": "Sertifikat telah diterbitkan dan dipasang."
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Richiedi subito il certificato", "request": "Richiedi subito il certificato",
"requesting": "Richiesta certificato in corso...", "requesting": "Richiesta certificato in corso...",
"issued": "Certificato rilasciato e installato" "issued": "Certificato rilasciato e installato"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "今すぐ証明書を申請する", "request": "今すぐ証明書を申請する",
"requesting": "証明書をリクエスト中...", "requesting": "証明書をリクエスト中...",
"issued": "証明書が発行され、インストールされました。" "issued": "証明書が発行され、インストールされました。"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "지금 인증서를 요청하세요", "request": "지금 인증서를 요청하세요",
"requesting": "인증서 요청 중...", "requesting": "인증서 요청 중...",
"issued": "인증서가 발급 및 설치되었습니다." "issued": "인증서가 발급 및 설치되었습니다."
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Vraag nu uw certificaat aan", "request": "Vraag nu uw certificaat aan",
"requesting": "Certificaat aanvragen...", "requesting": "Certificaat aanvragen...",
"issued": "Certificaat afgegeven en geïnstalleerd" "issued": "Certificaat afgegeven en geïnstalleerd"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Be om sertifikat nå", "request": "Be om sertifikat nå",
"requesting": "Ber om sertifikat...", "requesting": "Ber om sertifikat...",
"issued": "Sertifikat utstedt og installert" "issued": "Sertifikat utstedt og installert"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Złóż wniosek o certyfikat już teraz", "request": "Złóż wniosek o certyfikat już teraz",
"requesting": "Żądanie certyfikatu...", "requesting": "Żądanie certyfikatu...",
"issued": "Certyfikat wydany i zainstalowany" "issued": "Certyfikat wydany i zainstalowany"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Solicite o certificado agora", "request": "Solicite o certificado agora",
"requesting": "Solicitar certificado...", "requesting": "Solicitar certificado...",
"issued": "Certificado emitido e instalado." "issued": "Certificado emitido e instalado."
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Solicite já o certificado", "request": "Solicite já o certificado",
"requesting": "A solicitar certificado...", "requesting": "A solicitar certificado...",
"issued": "Certificado emitido e instalado." "issued": "Certificado emitido e instalado."
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Solicitați certificatul acum", "request": "Solicitați certificatul acum",
"requesting": "Se solicită certificatul...", "requesting": "Se solicită certificatul...",
"issued": "Certificat emis și instalat" "issued": "Certificat emis și instalat"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Запросить сертификат сейчас", "request": "Запросить сертификат сейчас",
"requesting": "Запрос сертификата...", "requesting": "Запрос сертификата...",
"issued": "Сертификат выдан и установлен." "issued": "Сертификат выдан и установлен."
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Затражите сертификат сада", "request": "Затражите сертификат сада",
"requesting": "Захтева се сертификат...", "requesting": "Захтева се сертификат...",
"issued": "Сертификат издат и инсталиран" "issued": "Сертификат издат и инсталиран"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Begär certifikat nu", "request": "Begär certifikat nu",
"requesting": "Begär certifikat...", "requesting": "Begär certifikat...",
"issued": "Certifikat utfärdat och installerat" "issued": "Certifikat utfärdat och installerat"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "ขอใบรับรองตอนนี้", "request": "ขอใบรับรองตอนนี้",
"requesting": "ขอใบรับรอง...", "requesting": "ขอใบรับรอง...",
"issued": "ออกและติดตั้งใบรับรองแล้ว" "issued": "ออกและติดตั้งใบรับรองแล้ว"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Şimdi sertifika talep edin", "request": "Şimdi sertifika talep edin",
"requesting": "Sertifika isteniyor...", "requesting": "Sertifika isteniyor...",
"issued": "Sertifika düzenlendi ve kuruldu." "issued": "Sertifika düzenlendi ve kuruldu."
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Замовити сертифікат зараз", "request": "Замовити сертифікат зараз",
"requesting": "Запит сертифіката...", "requesting": "Запит сертифіката...",
"issued": "Сертифікат видано та встановлено" "issued": "Сертифікат видано та встановлено"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "Yêu cầu chứng chỉ ngay bây giờ", "request": "Yêu cầu chứng chỉ ngay bây giờ",
"requesting": "Đang yêu cầu chứng chỉ...", "requesting": "Đang yêu cầu chứng chỉ...",
"issued": "Giấy chứng nhận đã được cấp và cài đặt" "issued": "Giấy chứng nhận đã được cấp và cài đặt"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "立即申请证书", "request": "立即申请证书",
"requesting": "正在请求证书...", "requesting": "正在请求证书...",
"issued": "证书已颁发并安装" "issued": "证书已颁发并安装"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
@@ -54,5 +54,8 @@
"request": "立即申請證書", "request": "立即申請證書",
"requesting": "請求憑證中...", "requesting": "請求憑證中...",
"issued": "證書已頒發並安裝" "issued": "證書已頒發並安裝"
},
"plugin": {
"name": "ACME Certificates"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "View docs" "docsLink": "View docs"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Bekyk dokumente" "docsLink": "Bekyk dokumente"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "عرض المستندات" "docsLink": "عرض المستندات"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Преглед на документи" "docsLink": "Преглед на документи"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "নথি দেখুন" "docsLink": "নথি দেখুন"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Veure documents" "docsLink": "Veure documents"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Zobrazit dokumenty" "docsLink": "Zobrazit dokumenty"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Se dokumenter" "docsLink": "Se dokumenter"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Dokumentation anzeigen" "docsLink": "Dokumentation anzeigen"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Προβολή εγγράφων" "docsLink": "Προβολή εγγράφων"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Ver documentación" "docsLink": "Ver documentación"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Näytä dokumentit" "docsLink": "Näytä dokumentit"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Voir la documentation" "docsLink": "Voir la documentation"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "הצג מסמכים" "docsLink": "הצג מסמכים"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "दस्तावेज़ देखें" "docsLink": "दस्तावेज़ देखें"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Dokumentumok megtekintése" "docsLink": "Dokumentumok megtekintése"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Lihat dokumen" "docsLink": "Lihat dokumen"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Visualizza documentazione" "docsLink": "Visualizza documentazione"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "ドキュメントを表示" "docsLink": "ドキュメントを表示"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "문서 보기" "docsLink": "문서 보기"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Documenten bekijken" "docsLink": "Documenten bekijken"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Vis dokumenter" "docsLink": "Vis dokumenter"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Zobacz dokumentację" "docsLink": "Zobacz dokumentację"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Documentação" "docsLink": "Documentação"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Ver documentação" "docsLink": "Ver documentação"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Vizualizați documentele" "docsLink": "Vizualizați documentele"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Документация" "docsLink": "Документация"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Прикажи документе" "docsLink": "Прикажи документе"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Visa dokument" "docsLink": "Visa dokument"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "ดูเอกสาร" "docsLink": "ดูเอกสาร"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Dokümanları görüntüle" "docsLink": "Dokümanları görüntüle"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Переглянути документи" "docsLink": "Переглянути документи"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "Xem tài liệu" "docsLink": "Xem tài liệu"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "查看文档" "docsLink": "查看文档"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -115,5 +115,8 @@
}, },
"hosts": { "hosts": {
"docsLink": "檢視文件" "docsLink": "檢視文件"
},
"plugin": {
"name": "AI Assistant"
} }
} }
+3
View File
@@ -168,5 +168,8 @@
"showRead": "Show read alerts", "showRead": "Show read alerts",
"allClear": "All clear", "allClear": "All clear",
"loading": "Loading..." "loading": "Loading..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Wys leeswaarskuwings", "showRead": "Wys leeswaarskuwings",
"allClear": "Alles duidelik", "allClear": "Alles duidelik",
"loading": "Laai tans..." "loading": "Laai tans..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "عرض تنبيهات القراءة", "showRead": "عرض تنبيهات القراءة",
"allClear": "كل شيء طبيعي", "allClear": "كل شيء طبيعي",
"loading": "جارٍ التحميل..." "loading": "جارٍ التحميل..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Показване на известия за четене", "showRead": "Показване на известия за четене",
"allClear": "Всичко е чисто", "allClear": "Всичко е чисто",
"loading": "Зареждане..." "loading": "Зареждане..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "পঠিত সতর্কতা দেখান", "showRead": "পঠিত সতর্কতা দেখান",
"allClear": "সব পরিষ্কার", "allClear": "সব পরিষ্কার",
"loading": "লোড হচ্ছে..." "loading": "লোড হচ্ছে..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Mostra les alertes de lectura", "showRead": "Mostra les alertes de lectura",
"allClear": "Tot clar", "allClear": "Tot clar",
"loading": "S'està carregant..." "loading": "S'està carregant..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Zobrazit upozornění na přečtení", "showRead": "Zobrazit upozornění na přečtení",
"allClear": "Všechno čisté", "allClear": "Všechno čisté",
"loading": "Načítání..." "loading": "Načítání..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Vis læseadvarsler", "showRead": "Vis læseadvarsler",
"allClear": "Alt klart", "allClear": "Alt klart",
"loading": "Indlæser..." "loading": "Indlæser..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Lesebenachrichtigungen anzeigen", "showRead": "Lesebenachrichtigungen anzeigen",
"allClear": "Alles in Ordnung", "allClear": "Alles in Ordnung",
"loading": "Laden..." "loading": "Laden..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Εμφάνιση ειδοποιήσεων ανάγνωσης", "showRead": "Εμφάνιση ειδοποιήσεων ανάγνωσης",
"allClear": "Ορίζοντας είναι σαφής", "allClear": "Ορίζοντας είναι σαφής",
"loading": "Φόρτωση..." "loading": "Φόρτωση..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Mostrar alertas de lectura", "showRead": "Mostrar alertas de lectura",
"allClear": "Todo correcto", "allClear": "Todo correcto",
"loading": "Cargando..." "loading": "Cargando..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Näytä lukuilmoitukset", "showRead": "Näytä lukuilmoitukset",
"allClear": "Kaikki selvää", "allClear": "Kaikki selvää",
"loading": "Ladataan..." "loading": "Ladataan..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Afficher les alertes de lecture", "showRead": "Afficher les alertes de lecture",
"allClear": "Aucune alerte", "allClear": "Aucune alerte",
"loading": "Chargement..." "loading": "Chargement..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "הצג התראות קריאה", "showRead": "הצג התראות קריאה",
"allClear": "הכל ברור", "allClear": "הכל ברור",
"loading": "טְעִינָה..." "loading": "טְעִינָה..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "पढ़े जाने के अलर्ट दिखाएँ", "showRead": "पढ़े जाने के अलर्ट दिखाएँ",
"allClear": "सब ठीक है", "allClear": "सब ठीक है",
"loading": "लोड हो रहा है..." "loading": "लोड हो रहा है..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Olvasási értesítések megjelenítése", "showRead": "Olvasási értesítések megjelenítése",
"allClear": "Minden tiszta", "allClear": "Minden tiszta",
"loading": "Terhelés..." "loading": "Terhelés..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Tampilkan pemberitahuan telah dibaca", "showRead": "Tampilkan pemberitahuan telah dibaca",
"allClear": "Semuanya aman.", "allClear": "Semuanya aman.",
"loading": "Memuat..." "loading": "Memuat..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Mostra gli avvisi di lettura", "showRead": "Mostra gli avvisi di lettura",
"allClear": "Tutto a posto", "allClear": "Tutto a posto",
"loading": "Caricamento in corso..." "loading": "Caricamento in corso..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "既読通知を表示する", "showRead": "既読通知を表示する",
"allClear": "すべて正常", "allClear": "すべて正常",
"loading": "読み込み中..." "loading": "読み込み中..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "읽음 알림 표시", "showRead": "읽음 알림 표시",
"allClear": "모두 정상", "allClear": "모두 정상",
"loading": "로딩 중..." "loading": "로딩 중..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Leeswaarschuwingen weergeven", "showRead": "Leeswaarschuwingen weergeven",
"allClear": "Alles in orde", "allClear": "Alles in orde",
"loading": "Laden..." "loading": "Laden..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Vis lesevarsler", "showRead": "Vis lesevarsler",
"allClear": "Alt klart", "allClear": "Alt klart",
"loading": "Laster..." "loading": "Laster..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Pokaż alerty odczytu", "showRead": "Pokaż alerty odczytu",
"allClear": "Bez alertów", "allClear": "Bez alertów",
"loading": "Ładowanie..." "loading": "Ładowanie..."
},
"plugin": {
"name": "Alerts"
} }
} }
@@ -168,5 +168,8 @@
"showRead": "Mostrar alertas de leitura", "showRead": "Mostrar alertas de leitura",
"allClear": "Tudo certo", "allClear": "Tudo certo",
"loading": "Carregando..." "loading": "Carregando..."
},
"plugin": {
"name": "Alerts"
} }
} }
Loaded 100 of 912 files, more files were not shown because too many files have changed in this diff. Show more