mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
v26.10.1 (#1599)
* feat: AI translations at release, 7 new languages and regional fallback * fix: proper plural forms for count strings and full translations * fix: plural forms for selected, hidden and active counts * fix: synced plugin updates failing on desktop and server-only plugins shown as stopped * fix: restore rounded corners on app icons and favicon * feat: desktop app auto updates with automatic, ask first or never modes * feat: community and custom plugin registries * feat: plugin guide for AI tools in the SDK with a lint check * fix: keep the terminal WebSocket open past nginx's 60s default (#1588) * chore: update changelog * feat: show plugin download counts only and stop CI builds inflating them * feat: hide installed plugins in the browse tab by default * chore: pin bundled plugins to latest releases * chore: update translations * fix: focusing a saved password field and saving no longer erases it * fix: tell desktop users when their 2.8 data needs 2.9 first * fix: point windows update info at the x64 installer * fix: keep desktop client tunnel sockets alive behind proxies * chore: pin bundled plugins to latest releases * fix: cover client tunnel keepalive in the c2s runtime tests * fix: typing after opening a host no longer goes to the host search * fix: accept tab and = separators in SSH config import (#1598) * chore: update changelog * chore: drop plugin versions from core changelog * chore: update translations * chore: lint, format, and bump version to 26.10.1 --------- Co-authored-by: Darnel Hunter <68697450+innotelinc@users.noreply.github.com> Co-authored-by: Iain <Iain1970@protonmail.com>
This commit is contained in:
174 files changed
+94334
-39995
No files matched your search
@@ -221,6 +221,8 @@ export interface PluginSummary {
|
||||
enabled: boolean;
|
||||
/** enabled | disabled | blocked | failed, or the loader's live state. */
|
||||
state: string;
|
||||
/** A linked desktop leaves this plugin to its server. */
|
||||
runsOnServer?: boolean;
|
||||
contributes: PluginContributions | null;
|
||||
/** Lucide icon name from the manifest. */
|
||||
icon?: string;
|
||||
@@ -289,8 +291,14 @@ export interface RegistryPluginVersion {
|
||||
size: number;
|
||||
}
|
||||
|
||||
export type RegistryTier = "official" | "community" | "custom";
|
||||
|
||||
export interface RegistryPluginEntry {
|
||||
id: string;
|
||||
/** Which registry this entry comes from. */
|
||||
registryId?: string;
|
||||
registryName?: string;
|
||||
tier?: RegistryTier;
|
||||
name: string;
|
||||
description: string;
|
||||
author: string;
|
||||
@@ -313,9 +321,18 @@ export interface RegistryPluginEntry {
|
||||
pinnedVersion: string | null;
|
||||
autoUpdate: boolean;
|
||||
bundled: boolean;
|
||||
/** Active installs when known, release downloads otherwise. */
|
||||
installCount: number | null;
|
||||
installCountSource: string | null;
|
||||
/** How often the release files were downloaded, from the registry. */
|
||||
downloads: number | null;
|
||||
}
|
||||
|
||||
export interface RegistryListingSource {
|
||||
id: string;
|
||||
name: string;
|
||||
tier: RegistryTier;
|
||||
url: string;
|
||||
lastCheckedAt: string | null;
|
||||
error: string | null;
|
||||
plugins: number;
|
||||
}
|
||||
|
||||
export interface RegistryListing {
|
||||
@@ -325,6 +342,7 @@ export interface RegistryListing {
|
||||
lastCheckedAt: string | null;
|
||||
error: string | null;
|
||||
};
|
||||
registries?: RegistryListingSource[];
|
||||
managedByServer: boolean;
|
||||
plugins: RegistryPluginEntry[];
|
||||
}
|
||||
@@ -373,7 +391,7 @@ export async function getPluginRegistry(
|
||||
/** `capabilities` is exactly what the consent prompt showed. */
|
||||
export async function installPlugin(
|
||||
pluginId: string,
|
||||
options: { version?: string; capabilities: string[] },
|
||||
options: { version?: string; capabilities: string[]; registryId?: string },
|
||||
): Promise<{ id: string; version: string; state: string }> {
|
||||
try {
|
||||
const response = await rbacApi.post(
|
||||
@@ -405,6 +423,61 @@ export async function updatePlugin(
|
||||
}
|
||||
}
|
||||
|
||||
export interface CustomRegistryInfo {
|
||||
id: string;
|
||||
name: string;
|
||||
url: string;
|
||||
keyId: string;
|
||||
enabled: boolean;
|
||||
addedAt: string;
|
||||
}
|
||||
|
||||
export interface RegistriesState {
|
||||
managedByServer: boolean;
|
||||
official: { id: string; url: string };
|
||||
community: { id: string; url: string; enabled: boolean };
|
||||
custom: CustomRegistryInfo[];
|
||||
}
|
||||
|
||||
export interface RegistryPreview {
|
||||
id: string;
|
||||
name: string;
|
||||
url: string;
|
||||
keyId: string;
|
||||
plugins: number;
|
||||
}
|
||||
|
||||
export async function getRegistries(): Promise<RegistriesState> {
|
||||
const response = await rbacApi.get("/plugins/registries");
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function previewRegistry(url: string): Promise<RegistryPreview> {
|
||||
const response = await rbacApi.post("/plugins/registries/preview", { url });
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function addRegistry(
|
||||
url: string,
|
||||
keyId: string,
|
||||
): Promise<CustomRegistryInfo> {
|
||||
const response = await rbacApi.post("/plugins/registries", { url, keyId });
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function setRegistryEnabled(
|
||||
id: string,
|
||||
enabled: boolean,
|
||||
): Promise<void> {
|
||||
await rbacApi.patch(`/plugins/registries/${encodeURIComponent(id)}`, {
|
||||
enabled,
|
||||
});
|
||||
}
|
||||
|
||||
export async function removeRegistry(id: string): Promise<void> {
|
||||
await rbacApi.delete(`/plugins/registries/${encodeURIComponent(id)}`);
|
||||
}
|
||||
|
||||
export async function updateAllPlugins(): Promise<UpdateAllResult> {
|
||||
try {
|
||||
const response = await rbacApi.post("/plugins/update-all");
|
||||
|
||||
Reference in new issue
Block a user