feat: shared tile grid for plugin pages and many-tile dashboard cards (SDK 1.0.26)

This commit is contained in:
LukeGus committed 2026-11-04 15:29:46 -06:00
1 parent 1c4fa52de3
commit 9613b787a7
22 files changed
+1997 -7

No files matched your search

+10
View File
@@ -1,5 +1,15 @@
# Changelog
## 1.0.26
Plugin API 1.15.0.
### Added
- `/ui` exports `TileGrid`, `TileFrame` and `TilePicker`, the 12 column tile grid the dashboard, the host page and Host Metrics share, plus `appendTile`, `flowTiles`, `removeTile`, `sanitizeTiles` and the `TileSlot` type
- `registerDashboardCard` takes `entries`, so one card can be placed many times with its own `config`, and `defaultSize` for the grid
- Dashboard cards get `config`, `setConfig` and `editMode`
## 1.0.25
Plugin API 1.14.0.
+7 -1
View File
@@ -1,6 +1,6 @@
# Termix plugin guide
SDK 1.0.25 | Plugin API 1.14.0
SDK 1.0.26 | Plugin API 1.15.0
This guide is for anyone, person or AI coding tool, building a Termix plugin. It ships inside
`@termix-ssh/plugin-sdk`, so the copy in your `node_modules` always matches the SDK you have installed.
@@ -768,6 +768,12 @@ exports with props is `ui.api.txt` in the Termix repo
`PanePrompt` for small prompts.
- Every tab or panel sits in `PanelShell`. Lists use `PanelList` and `ListRow`, add with `AddButton`,
forms end with `FormFooter`, empty lists show `EmptyState`.
- Tile pages use `TileGrid` with `TileFrame` around each tile and `TilePicker` beside it while editing. Slots are
`{ id, x, y, w, h }` on 12 columns (`h` null for the natural height); save them where your plugin keeps
preferences and run saved ones through `sanitizeTiles`. Add with `appendTile`. Needs Termix 26.11.1.
- A dashboard card with `entries` can be placed many times: each entry has a title, a group and a `config` the
card gets back as `config` (save changes with `setConfig`, keep it small). Operations Center uses this for
status and action tiles.
- Card grids use `DataView` with `ViewToggle`. Pass `columns` and `onColumns` to `ViewToggle` and the same
value as `size` to `DataView`, so users can pick Auto (as many as fit) or a fixed number of cards per
row. `usePluginPanelView` keeps the choice as `columns`. Older Termix versions ignore both props.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@termix-ssh/plugin-sdk",
"version": "1.0.25",
"version": "1.0.26",
"description": "The contract between Termix core and a plugin: types, the capability catalog and the manifest schema.",
"license": "Apache-2.0",
"repository": {
+27
View File
@@ -799,6 +799,26 @@ export interface KeybindingDefaultContribution {
export interface DashboardCardProps {
isVisible: boolean;
shell: ShellApi;
/** This tile's settings, for cards with `entries`. Empty otherwise. Core 26.11.1+. */
config?: Record<string, unknown>;
/** Saves this tile's settings. Keep it small, it is stored in one line. */
setConfig?: (config: Record<string, unknown>) => void;
/** True while the user is arranging the dashboard. */
editMode?: boolean;
}
/** One tile a card with `entries` offers in the dashboard's add list. */
export interface DashboardCardEntry {
/** Stable within the card, used to mark entries already placed. */
key: string;
title: string;
description?: string;
/** Group heading in the add list. Defaults to the card title. */
group?: string;
kind?: "card" | "chart" | "signal" | "action" | "resource" | "session";
/** Passed back as `config`. */
config: Record<string, unknown>;
defaultSize?: { w: number; h?: number | null };
}
export interface DashboardCardContribution {
@@ -813,6 +833,13 @@ export interface DashboardCardContribution {
* edge, for a strip of numbers. Defaults to "framed".
*/
frame?: "framed" | "bare";
/** Size on the 12 column dashboard grid when added. Core 26.11.1+. */
defaultSize?: { w: number; h?: number | null };
/**
* Lets the card be placed many times, once per entry, each with its own
* `config`. Titles come back already translated. Core 26.11.1+.
*/
entries?: (language: string) => Promise<DashboardCardEntry[]>;
component: ComponentType<DashboardCardProps>;
}
+1 -1
View File
@@ -42,7 +42,7 @@ export {
* "^1.2" needs 1.2 or later). engine.termix is checked against the core
* version by the server.
*/
export const PLUGIN_API_VERSION = "1.14.0";
export const PLUGIN_API_VERSION = "1.15.0";
/** The API major, the default engine.api for a new plugin. */
export const SUPPORTED_PLUGIN_API_VERSION = String(
+12
View File
@@ -291,6 +291,7 @@ SurfaceKind (type): SurfaceKind
SurfaceScope (value): ({ kind, onEditingChange, onClose, className, children, }: { kind?: SurfaceKind; onClose?: () => void; onEditingChange?: (editing: EditingWidth) => void; className?: string; children: ReactNode; }) => Element
Switch (value): ({ className, ...props }: SwitchProps & RefAttributes<HTMLButtonElement>) => Element
SwitchRow (value): ({ label, description, badge, checked, onChange, disabled, defaultKey, rowId, }: { label: string; description?: ReactNode; badge?: string; checked: boolean; onChange: (value: boolean) => void; disabled?: boolean; defaultKey?: string; rowId?: string; }) => Element
TILE_COLUMNS (value): 12
TOTPDialog (value): ({ isOpen, prompt, mode, waiting, onSubmit, onCancel, backgroundColor, }: TOTPDialogProps) => Element
Tab (type): Tab
TabShellCallbacks (type): TabShellCallbacks
@@ -305,6 +306,13 @@ TextField (value): ({ label, value, onChange, placeholder, hint, error, aside, d
Textarea (value): ForwardRefExoticComponent<TextareaProps & RefAttributes<HTMLTextAreaElement>>
TextareaProps (type): TextareaProps
ThemeId (type): string
TileFrame (value): ({ title, icon, actions, bare, onTitleClick, className, bodyClassName, children, }: { title?: ReactNode; icon?: ReactNode; actions?: ReactNode; bare?: boolean; onTitleClick?: () => void; className?: string; bodyClassName?: string; children: ReactNode; }) => Element
TileGrid (value): ({ slots, editMode, renderTile, tileLabel, onChange, onSettings, gap, stackBelow, minColumns, minHeight, empty, className, }: TileGridProps) => Element
TileGridProps (type): TileGridProps
TileKind (type): TileKind
TilePicker (value): ({ entries, onAdd, onClose, className, }: { entries: TilePickerEntry[]; onAdd: (entry: TilePickerEntry) => void; onClose?: () => void; className?: string; }) => Element
TilePickerEntry (type): TilePickerEntry
TileSlot (type): TileSlot
TlsStatus (type): TlsStatus
ToolsTab (type): ToolsTab
Tooltip (value): ({ ...props }: TooltipProps) => Element
@@ -341,6 +349,7 @@ adminGetUserHosts (value): (targetUserId: string) => Promise<Host[]>
adminResetUserPassword (value): (userId: string, newPassword: string, confirmDataWipe?: boolean) => Promise<{ message: string; dataWiped?: boolean; }>
adminUpdateUserCredential (value): (targetUserId: string, credentialId: number, credentialData: Record<string, unknown>) => Promise<Record<string, unknown>>
adminUpdateUserHost (value): (targetUserId: string, hostId: number, hostData: HostData) => Promise<Host>
appendTile (value): (slots: TileSlot[], tile: { id: string; w?: number; h?: number; }) => TileSlot[]
applyAccentColor (value): (colorValue: string) => void
applyFontSize (value): (id: FontSizeId) => void
applyPresetSideEffects (value): (preset: "simple" | "balanced" | "advanced") => Promise<void>
@@ -384,6 +393,7 @@ endSplitDrag (value): (commit: boolean) => void
filterPaletteItems (value): (items: PaletteItemDef[], query: string, showWhenEmpty?: boolean) => PaletteItemDef[]
findCoreHostDefault (value): (key: string) => CoreHostDefault
findMatchingKeybinding (value): (e: KeyboardEvent, bindings: CustomKeybinding[]) => CustomKeybinding
flowTiles (value): (tiles: { id: string; w: number; h?: number; }[], rowHeight?: number) => TileSlot[]
getActiveSessions (value): () => Promise<ActiveSessionInfo[]>
getAdaptiveResourceBudget (value): (kind: AdaptiveTaskKind) => AdaptiveResourceBudget
getApiKeys (value): () => Promise<{ apiKeys: ApiKey[]; }>
@@ -514,6 +524,7 @@ releaseUrlFrom (value): (info: VersionInfo) => string
rem (value): (px: number) => string
removeAdminStatus (value): (userId: string) => Promise<Record<string, unknown>>
removeRoleFromUser (value): (userId: string, roleId: number) => Promise<{ success: boolean; }>
removeTile (value): (slots: TileSlot[], id: string) => TileSlot[]
renameCredentialFolder (value): (oldName: string, newName: string) => Promise<Record<string, unknown>>
renameFolder (value): (oldName: string, newName: string) => Promise<Record<string, unknown>>
reorderCredentials (value): (positions: { id: number; sortOrder: number; }[]) => Promise<{ updated: number; }>
@@ -543,6 +554,7 @@ runHostAction (value): (action: HostActionDef, host: Host, shell: TabShellCallba
runVisibleInterval (value): (tick: () => void, intervalMs: number) => () => void
sanitizeCredentialSidebarPreferences (value): (input: unknown) => CredentialSidebarPreferences
sanitizeHostSidebarPreferences (value): (input: unknown) => HostSidebarPreferences
sanitizeTiles (value): (value: unknown, min?: number) => TileSlot[]
saveCredentialSidebarPreferences (value): (preferences: CredentialSidebarPreferences) => Promise<void>
saveHostDefaultsLevel (value): (target: HostDefaultsTarget, change: HostDefaultsChange) => Promise<{ changedHosts?: number; jobId?: string; }>
saveHostSidebarPreferences (value): (preferences: HostSidebarPreferences) => Promise<void>