@termix-ssh/plugin-sdk 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/cli/commands/changelog.mjs +25 -0
- package/cli/commands/dev.mjs +158 -0
- package/cli/commands/validate.mjs +16 -24
- package/cli/index.mjs +8 -0
- package/cli/lib/tmxplug.mjs +1 -1
- package/dist/backend.d.ts +6 -2
- package/dist/changelog.d.ts +67 -0
- package/dist/changelog.js +195 -0
- package/dist/frontend.d.ts +67 -1
- package/dist/host/{chunk-XGWE7BTJ.js → chunk-3KG44G55.js} +6 -1
- package/dist/host/{chunk-XH5NXL6Y.js → chunk-7GL25GFS.js} +8013 -7606
- package/dist/host/{chunk-F3SDZDDG.js → chunk-COGRSHKO.js} +17 -2
- package/dist/host/{linked-server-FZGWQW32.js → linked-server-BD573BEG.js} +1 -1
- package/dist/host/{rbac-api-6KDMBVDZ.js → rbac-api-7GHDJLU4.js} +1 -1
- package/dist/host/testing-host.js +38 -5
- package/dist/host/types/src/types/credential-sidebar-preferences.d.ts +12 -1
- package/dist/host/types/src/types/host-sidebar-preferences.d.ts +18 -1
- package/dist/host/types/src/types/onboarding.d.ts +29 -0
- package/dist/host/types/src/types/plugin-onboarding.d.ts +39 -0
- package/dist/host/types/src/types/ui-preferences.d.ts +13 -4
- package/dist/host/types/src/types/ui-types.d.ts +1 -1
- package/dist/host/types/src/ui/api/plugins-api.d.ts +194 -0
- package/dist/host/types/src/ui/components/connection/ConnectionLogPanel.d.ts +2 -1
- package/dist/host/types/src/ui/components/connection/ConnectionScreen.d.ts +5 -5
- package/dist/host/types/src/ui/components/list-kit.d.ts +102 -0
- package/dist/host/types/src/ui/components/panel-layout.d.ts +6 -1
- package/dist/host/types/src/ui/components/surface/surface-scope.d.ts +5 -1
- package/dist/host/types/src/ui/contexts/UiPreferencesContext.d.ts +15 -2
- package/dist/host/types/src/ui/hooks/use-permissions.d.ts +2 -0
- package/dist/host/types/src/ui/lib/embedded-frame.d.ts +14 -0
- package/dist/host/types/src/ui/onboarding/onboarding-registry.d.ts +49 -0
- package/dist/host/types/src/ui/plugin-host/sdk-ui.d.ts +1 -0
- package/dist/host/types/src/ui/plugins/open-plugins.d.ts +5 -0
- package/dist/host/types/src/ui/sidebar/host-contributions.d.ts +2 -0
- package/dist/host/types/src/ui/sidebar/rail-items.d.ts +10 -0
- package/dist/host/ui.js +982 -698
- package/dist/host/{use-permissions-NULZL43J.js → use-permissions-SKWXHWDJ.js} +3 -1
- package/dist/manifest.d.ts +10 -2
- package/dist/manifest.js +46 -1
- package/dist/testing/setup.js +8 -0
- package/dist/testing.d.ts +12 -0
- package/dist/vitest-preset.d.ts +3 -0
- package/dist/vitest-preset.js +6 -0
- package/package.json +5 -2
- package/schema/manifest.schema.json +6 -1
- package/cli/lib/changelog.mjs +0 -126
- package/schema/changelog.schema.json +0 -67
|
@@ -4759,6 +4759,18 @@ async function buildOriginWsUrl({
|
|
|
4759
4759
|
};
|
|
4760
4760
|
}
|
|
4761
4761
|
|
|
4762
|
+
// src/types/onboarding.ts
|
|
4763
|
+
var LEGACY_SEEN = Object.freeze({
|
|
4764
|
+
plugins: 1,
|
|
4765
|
+
"desktop-sync": 1,
|
|
4766
|
+
preset: 1,
|
|
4767
|
+
appearance: 1,
|
|
4768
|
+
security: 1
|
|
4769
|
+
});
|
|
4770
|
+
function pluginStepKey(pluginId, id) {
|
|
4771
|
+
return `${pluginId}:${id}`;
|
|
4772
|
+
}
|
|
4773
|
+
|
|
4762
4774
|
// src/types/ui-preferences.ts
|
|
4763
4775
|
var SIMPLE_RAIL_VISIBLE = ["hosts", "credentials", "connections"];
|
|
4764
4776
|
var CORE_HIDEABLE_RAIL_VIEWS = [
|
|
@@ -4870,6 +4882,7 @@ var AREA_SPECS = {
|
|
|
4870
4882
|
},
|
|
4871
4883
|
rail: {
|
|
4872
4884
|
hiddenTabs: { kind: "stringArray" },
|
|
4885
|
+
order: { kind: "stringArray" },
|
|
4873
4886
|
hidePluginItems: { kind: "bool" }
|
|
4874
4887
|
},
|
|
4875
4888
|
dashboard: {
|
|
@@ -5024,7 +5037,7 @@ async function updateRole(roleId, roleData) {
|
|
|
5024
5037
|
try {
|
|
5025
5038
|
const response = await rbacApi.put(`/rbac/roles/${roleId}`, roleData);
|
|
5026
5039
|
if (roleData.permissions) {
|
|
5027
|
-
const { notifyPermissionsChanged } = await import("./use-permissions-
|
|
5040
|
+
const { notifyPermissionsChanged } = await import("./use-permissions-SKWXHWDJ.js");
|
|
5028
5041
|
notifyPermissionsChanged();
|
|
5029
5042
|
}
|
|
5030
5043
|
return response.data;
|
|
@@ -5574,7 +5587,7 @@ function createRemoteOriginApiInstance(path) {
|
|
|
5574
5587
|
});
|
|
5575
5588
|
instance.interceptors.request.use(
|
|
5576
5589
|
async (config) => {
|
|
5577
|
-
const { getLinkedSession: getLinkedSession2 } = await import("./linked-server-
|
|
5590
|
+
const { getLinkedSession: getLinkedSession2 } = await import("./linked-server-BD573BEG.js");
|
|
5578
5591
|
const linked = await getLinkedSession2();
|
|
5579
5592
|
config.baseURL = linked ? `${linked.serverUrl}${path}` : "http://no-server-configured";
|
|
5580
5593
|
if (config.headers.set) {
|
|
@@ -5926,6 +5939,7 @@ function notifySyncChanged() {
|
|
|
5926
5939
|
}
|
|
5927
5940
|
|
|
5928
5941
|
export {
|
|
5942
|
+
getPluginStoreState,
|
|
5929
5943
|
usePluginStore,
|
|
5930
5944
|
setPluginSummaries,
|
|
5931
5945
|
markPluginsSettled,
|
|
@@ -5957,6 +5971,7 @@ export {
|
|
|
5957
5971
|
notifySyncChanged,
|
|
5958
5972
|
resolveConnectionOrigin,
|
|
5959
5973
|
buildOriginWsUrl,
|
|
5974
|
+
pluginStepKey,
|
|
5960
5975
|
PRESETS,
|
|
5961
5976
|
hydrateLocalSharedHostAuth,
|
|
5962
5977
|
resolveRemoteHostId,
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
listSettingsComponents,
|
|
33
33
|
loadPaletteGroup,
|
|
34
34
|
notifyShellReady,
|
|
35
|
+
onboardingSteps,
|
|
35
36
|
registeredDashboardCardList,
|
|
36
37
|
resetShellBridge,
|
|
37
38
|
setPluginApiForTesting,
|
|
@@ -39,16 +40,16 @@ import {
|
|
|
39
40
|
setShellCallbacks,
|
|
40
41
|
setShellHosts,
|
|
41
42
|
setShellLayoutProvider
|
|
42
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-7GL25GFS.js";
|
|
43
44
|
import {
|
|
44
45
|
setPermissionsForTesting
|
|
45
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-3KG44G55.js";
|
|
46
47
|
import {
|
|
47
48
|
getTabType,
|
|
48
49
|
listTabTypes,
|
|
49
50
|
setFrontendState,
|
|
50
51
|
setPluginSummaries
|
|
51
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-COGRSHKO.js";
|
|
52
53
|
import "./chunk-YC2MAKSP.js";
|
|
53
54
|
|
|
54
55
|
// src/ui/plugin-host/testing-host.tsx
|
|
@@ -61,7 +62,8 @@ var CORE_UNSAVED = /* @__PURE__ */ new Set([
|
|
|
61
62
|
"settings",
|
|
62
63
|
"user-profile",
|
|
63
64
|
"admin-settings",
|
|
64
|
-
"split-screen"
|
|
65
|
+
"split-screen",
|
|
66
|
+
"plugins"
|
|
65
67
|
]);
|
|
66
68
|
function isUnregisteredPluginTabType(type) {
|
|
67
69
|
return !CORE_UNSAVED.has(type) && !getTabType(type);
|
|
@@ -191,6 +193,7 @@ async function renderPlugin(plugin, options = {}) {
|
|
|
191
193
|
setFrontendState(pluginId, "active");
|
|
192
194
|
if (options.ready) notifyShellReady();
|
|
193
195
|
const mine = (items) => items.filter((item) => item.pluginId === pluginId);
|
|
196
|
+
const unprefixed = (items) => mine(items).map((item) => item.id.slice(pluginId.length + 1));
|
|
194
197
|
const tabRecord = (type, host) => ({
|
|
195
198
|
id: `${type}-test`,
|
|
196
199
|
instanceId: `${type}-test`,
|
|
@@ -230,7 +233,8 @@ async function renderPlugin(plugin, options = {}) {
|
|
|
230
233
|
secondFactors: () => mine(listSecondFactorUIs()).map((factor) => factor.id),
|
|
231
234
|
paletteGroups: () => mine(listPaletteGroups()).map((group) => group.id),
|
|
232
235
|
keybindingActions: () => mine(listKeybindingActions()).map((action) => action.id),
|
|
233
|
-
keybindingDefaults: () => mine(listKeybindingDefaults()).map((binding) => binding.id)
|
|
236
|
+
keybindingDefaults: () => mine(listKeybindingDefaults()).map((binding) => binding.id),
|
|
237
|
+
onboardingSteps: () => unprefixed(onboardingSteps.list())
|
|
234
238
|
},
|
|
235
239
|
async loadPaletteGroup(id) {
|
|
236
240
|
const group = listPaletteGroups().find((entry) => entry.id === id) ?? missing("a palette group", id);
|
|
@@ -303,6 +307,35 @@ async function renderPlugin(plugin, options = {}) {
|
|
|
303
307
|
if (!Component) missing(`an extension "${component}" component`, id);
|
|
304
308
|
return wrap(/* @__PURE__ */ jsx(Component, { ...props }));
|
|
305
309
|
},
|
|
310
|
+
renderOnboardingStep(id, props = {}) {
|
|
311
|
+
const step = onboardingSteps.get(`${pluginId}:${id}`) ?? missing("an onboarding step", id);
|
|
312
|
+
const Component = step.Component;
|
|
313
|
+
let canContinue = true;
|
|
314
|
+
let beforeNext = null;
|
|
315
|
+
const element = wrap(
|
|
316
|
+
/* @__PURE__ */ jsx(
|
|
317
|
+
Component,
|
|
318
|
+
{
|
|
319
|
+
mode: "full",
|
|
320
|
+
isAdmin: true,
|
|
321
|
+
isDesktop: false,
|
|
322
|
+
shellReady: false,
|
|
323
|
+
setCanContinue: (ok) => {
|
|
324
|
+
canContinue = ok;
|
|
325
|
+
},
|
|
326
|
+
setBeforeNext: (fn) => {
|
|
327
|
+
beforeNext = fn;
|
|
328
|
+
},
|
|
329
|
+
...props
|
|
330
|
+
}
|
|
331
|
+
)
|
|
332
|
+
);
|
|
333
|
+
return {
|
|
334
|
+
element,
|
|
335
|
+
canContinue: () => canContinue,
|
|
336
|
+
next: async () => beforeNext ? await beforeNext() : true
|
|
337
|
+
};
|
|
338
|
+
},
|
|
306
339
|
renderDashboardCard(id) {
|
|
307
340
|
const card = getRegisteredDashboardCard(id) ?? missing("a card", id);
|
|
308
341
|
const Component = card.component;
|
|
@@ -19,7 +19,18 @@ export interface CredentialSidebarFilterState {
|
|
|
19
19
|
type: string[];
|
|
20
20
|
tags: string[];
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
/** Which parts of a credential row are shown. */
|
|
23
|
+
export interface CredentialRowFields {
|
|
24
|
+
showUsername: boolean;
|
|
25
|
+
/** The "3h" count of hosts using it. */
|
|
26
|
+
showUsageCount: boolean;
|
|
27
|
+
showTypeBadge: boolean;
|
|
28
|
+
showPinIcon: boolean;
|
|
29
|
+
showSharedBadge: boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare const CREDENTIAL_ROW_FIELD_KEYS: (keyof CredentialRowFields)[];
|
|
32
|
+
export declare function defaultCredentialRowFields(): CredentialRowFields;
|
|
33
|
+
export interface CredentialSidebarDisplayPreferences extends CredentialRowFields {
|
|
23
34
|
density: CredentialDensity;
|
|
24
35
|
showTags: boolean;
|
|
25
36
|
trayTrigger: CredentialTrayTrigger;
|
|
@@ -29,7 +29,19 @@ export interface HostSidebarFilterState {
|
|
|
29
29
|
features: string[];
|
|
30
30
|
tags: string[];
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
/** Which parts of a host row are shown. */
|
|
33
|
+
export interface HostRowFields {
|
|
34
|
+
showAddress: boolean;
|
|
35
|
+
showUsername: boolean;
|
|
36
|
+
showPort: boolean;
|
|
37
|
+
showPinIcon: boolean;
|
|
38
|
+
showSharedBadge: boolean;
|
|
39
|
+
/** Badges plugins add next to the name. */
|
|
40
|
+
showBadges: boolean;
|
|
41
|
+
}
|
|
42
|
+
export declare const HOST_ROW_FIELD_KEYS: (keyof HostRowFields)[];
|
|
43
|
+
export declare function defaultHostRowFields(): HostRowFields;
|
|
44
|
+
export interface HostSidebarDisplayPreferences extends HostRowFields {
|
|
33
45
|
density: HostDensity;
|
|
34
46
|
showTags: boolean;
|
|
35
47
|
trayTrigger: HostTrayTrigger;
|
|
@@ -39,6 +51,11 @@ export interface HostSidebarDisplayPreferences {
|
|
|
39
51
|
/** When false, nested folders hide the parent-path breadcrumb before their name. */
|
|
40
52
|
showFolderPaths: boolean;
|
|
41
53
|
hostClickBehavior: HostClickBehavior;
|
|
54
|
+
/**
|
|
55
|
+
* Host action id to whether it shows in the row's connect bar. An action
|
|
56
|
+
* missing here follows its own default. Every action stays in the menu.
|
|
57
|
+
*/
|
|
58
|
+
barActions: Record<string, boolean>;
|
|
42
59
|
}
|
|
43
60
|
export interface HostSidebarPreferences {
|
|
44
61
|
version: number;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Onboarding step bookkeeping, shared by the frontend and the ui-preferences
|
|
3
|
+
* route. Dependency-free for the backend's NodeNext build.
|
|
4
|
+
*
|
|
5
|
+
* Each step has a key and a version. A user's `seen` map records the highest
|
|
6
|
+
* version of each step they have been shown, so bumping one step's version
|
|
7
|
+
* shows that step again (and only that step) to everyone who saw it before.
|
|
8
|
+
* Plugin steps are keyed `<pluginId>:<id>`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CORE_ONBOARDING_STEPS: {
|
|
11
|
+
readonly plugins: 1;
|
|
12
|
+
readonly "desktop-sync": 1;
|
|
13
|
+
readonly preset: 1;
|
|
14
|
+
readonly appearance: 1;
|
|
15
|
+
readonly security: 1;
|
|
16
|
+
};
|
|
17
|
+
export type CoreOnboardingStepKey = keyof typeof CORE_ONBOARDING_STEPS;
|
|
18
|
+
/**
|
|
19
|
+
* What a user who finished the old single-version onboarding counts as
|
|
20
|
+
* having seen. Frozen on purpose: a later bump in CORE_ONBOARDING_STEPS must
|
|
21
|
+
* still show the bumped step to these users.
|
|
22
|
+
*/
|
|
23
|
+
export declare const LEGACY_SEEN: Readonly<Record<string, number>>;
|
|
24
|
+
export declare const MAX_SEEN_ENTRIES = 500;
|
|
25
|
+
export declare function pluginStepKey(pluginId: string, id: string): string;
|
|
26
|
+
export declare function isValidSeenEntry(key: string, version: unknown): boolean;
|
|
27
|
+
export declare function sanitizeSeen(input: unknown): Record<string, number>;
|
|
28
|
+
/** Per-key max, so a stale tab never lowers what another tab recorded. */
|
|
29
|
+
export declare function mergeSeen(a: Record<string, number> | undefined, b: Record<string, number> | undefined): Record<string, number>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The onboarding plugin picker: what the admin chose for each plugin, and the
|
|
3
|
+
* dependency rules that keep the result loadable. Shared by the picker (to
|
|
4
|
+
* show "kept because X needs it" live) and the backend apply route.
|
|
5
|
+
*/
|
|
6
|
+
export type PluginChoice = "enabled" | "disabled" | "remove";
|
|
7
|
+
export declare const PLUGIN_CHOICES: readonly PluginChoice[];
|
|
8
|
+
export interface ChoicePlugin {
|
|
9
|
+
id: string;
|
|
10
|
+
/** Hard dependencies (plugin ids). */
|
|
11
|
+
dependencies: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface ChoiceAdjustment {
|
|
14
|
+
id: string;
|
|
15
|
+
from: PluginChoice;
|
|
16
|
+
to: PluginChoice;
|
|
17
|
+
/** The plugins whose choice forced this one up. */
|
|
18
|
+
requiredBy: string[];
|
|
19
|
+
}
|
|
20
|
+
export declare function isPluginChoice(value: unknown): value is PluginChoice;
|
|
21
|
+
/**
|
|
22
|
+
* Raise choices until every plugin's dependencies can serve it: an enabled
|
|
23
|
+
* plugin needs its dependencies enabled, and a kept but disabled plugin
|
|
24
|
+
* needs them at least kept. Ids missing from `choices` stay as they are and
|
|
25
|
+
* are never adjusted.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolvePluginChoices(plugins: ChoicePlugin[], choices: Record<string, PluginChoice>): {
|
|
28
|
+
choices: Record<string, PluginChoice>;
|
|
29
|
+
adjustments: ChoiceAdjustment[];
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The order to apply resolved choices in: enable dependencies first, and
|
|
33
|
+
* disable or remove dependents first.
|
|
34
|
+
*/
|
|
35
|
+
export declare function applyOrder(plugins: ChoicePlugin[], resolved: Record<string, PluginChoice>): {
|
|
36
|
+
enable: string[];
|
|
37
|
+
disable: string[];
|
|
38
|
+
remove: string[];
|
|
39
|
+
};
|
|
@@ -17,8 +17,6 @@
|
|
|
17
17
|
*/
|
|
18
18
|
/** 2: the docker and host metrics areas moved to their plugins. */
|
|
19
19
|
export declare const UI_PREFERENCES_VERSION = 3;
|
|
20
|
-
/** Bump when onboarding gains steps existing users should be shown again. */
|
|
21
|
-
export declare const UI_ONBOARDING_VERSION = 2;
|
|
22
20
|
export type UiPreset = "simple" | "balanced" | "advanced" | "custom";
|
|
23
21
|
export type UiAreaKey = "chrome" | "hostList" | "credentialList" | "rail" | "dashboard" | "hostEditor";
|
|
24
22
|
export type UiDensity = "comfortable" | "compact";
|
|
@@ -50,6 +48,8 @@ export interface UiRailPreferences {
|
|
|
50
48
|
* items are only known at runtime, so the preset cannot list them.
|
|
51
49
|
*/
|
|
52
50
|
hidePluginItems?: boolean;
|
|
51
|
+
/** Rail item ids in the user's order. Items not listed keep their place. */
|
|
52
|
+
order?: string[];
|
|
53
53
|
}
|
|
54
54
|
export interface UiDashboardPreferences {
|
|
55
55
|
enabledCards: string[];
|
|
@@ -73,10 +73,17 @@ export type UiOverrides = {
|
|
|
73
73
|
[key: UiPluginAreaKey]: Record<string, unknown>;
|
|
74
74
|
};
|
|
75
75
|
export interface UiOnboardingState {
|
|
76
|
-
/**
|
|
77
|
-
|
|
76
|
+
/** Step key to the highest version of that step the user was shown. */
|
|
77
|
+
seen: Record<string, number>;
|
|
78
|
+
/** When the first full run finished. Null means it never has. */
|
|
78
79
|
completedAt: string | null;
|
|
79
80
|
skipped: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Set for users carried over from the old single-version onboarding. The
|
|
83
|
+
* client marks every plugin step that exists right now as seen without
|
|
84
|
+
* showing it, then clears this.
|
|
85
|
+
*/
|
|
86
|
+
baselinePending: boolean;
|
|
80
87
|
}
|
|
81
88
|
export interface UiPreferences {
|
|
82
89
|
version: number;
|
|
@@ -87,6 +94,8 @@ export interface UiPreferences {
|
|
|
87
94
|
export declare const PRESETS: Record<Exclude<UiPreset, "custom">, UiAreaPreferences>;
|
|
88
95
|
export declare const UI_AREA_KEYS: UiAreaKey[];
|
|
89
96
|
export declare function sanitizeUiOverrides(input: unknown): UiOverrides;
|
|
97
|
+
export declare function defaultOnboardingState(): UiOnboardingState;
|
|
98
|
+
export declare function sanitizeOnboarding(input: unknown): UiOnboardingState;
|
|
90
99
|
export declare function defaultUiPreferences(): UiPreferences;
|
|
91
100
|
export declare function sanitizeUiPreferences(input: unknown): UiPreferences;
|
|
92
101
|
/**
|
|
@@ -128,7 +128,7 @@ export type HostFolder = {
|
|
|
128
128
|
localOnly?: boolean;
|
|
129
129
|
};
|
|
130
130
|
/** Core's own tab types. Plugins register theirs at runtime. */
|
|
131
|
-
type KnownTabType = "dashboard" | "host-manager" | "settings" | "user-profile" | "admin-settings" | "split-screen";
|
|
131
|
+
type KnownTabType = "dashboard" | "host-manager" | "settings" | "user-profile" | "admin-settings" | "split-screen" | "plugins";
|
|
132
132
|
/**
|
|
133
133
|
* TabType covers every built-in tab plus any plugin-contributed tab id.
|
|
134
134
|
* `string & {}` (rather than plain `string`) keeps IDE autocomplete
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { ChoiceAdjustment, PluginChoice } from "../../types/plugin-onboarding";
|
|
2
|
+
import type { ChangelogRelease, ReleaseNotes } from "@termix-ssh/plugin-sdk/changelog";
|
|
3
|
+
export type { PluginChoice };
|
|
1
4
|
export interface PluginTabContribution {
|
|
2
5
|
id: string;
|
|
3
6
|
titleKey: string;
|
|
@@ -124,5 +127,196 @@ export interface PluginSummary {
|
|
|
124
127
|
http: string[];
|
|
125
128
|
ws: string[];
|
|
126
129
|
};
|
|
130
|
+
registryId?: string | null;
|
|
131
|
+
autoUpdate?: boolean;
|
|
132
|
+
pinnedVersion?: string | null;
|
|
133
|
+
description?: string;
|
|
134
|
+
author?: string;
|
|
135
|
+
repository?: string;
|
|
136
|
+
/** A YouTube video id from the manifest. Admins only. */
|
|
137
|
+
videoId?: string;
|
|
138
|
+
signedBy?: string | null;
|
|
127
139
|
}
|
|
128
140
|
export declare function getPlugins(): Promise<PluginSummary[]>;
|
|
141
|
+
/** Fired after any change to installed plugins; the loader resyncs on it. */
|
|
142
|
+
export declare const PLUGINS_CHANGED_EVENT = "termix:plugins-changed";
|
|
143
|
+
export interface RegistryPluginVersion {
|
|
144
|
+
version: string;
|
|
145
|
+
compatible: boolean;
|
|
146
|
+
capabilities: string[];
|
|
147
|
+
publishedAt?: string;
|
|
148
|
+
releaseNotesUrl?: string;
|
|
149
|
+
notes?: ReleaseNotes;
|
|
150
|
+
size: number;
|
|
151
|
+
}
|
|
152
|
+
export interface RegistryPluginEntry {
|
|
153
|
+
id: string;
|
|
154
|
+
name: string;
|
|
155
|
+
description: string;
|
|
156
|
+
author: string;
|
|
157
|
+
category: string;
|
|
158
|
+
repository?: string;
|
|
159
|
+
icon?: string;
|
|
160
|
+
videoId?: string;
|
|
161
|
+
versions: RegistryPluginVersion[];
|
|
162
|
+
latestVersion: string | null;
|
|
163
|
+
installed: boolean;
|
|
164
|
+
installedVersion: string | null;
|
|
165
|
+
updateAvailable: boolean;
|
|
166
|
+
addedCapabilities: string[];
|
|
167
|
+
pinnedVersion: string | null;
|
|
168
|
+
autoUpdate: boolean;
|
|
169
|
+
bundled: boolean;
|
|
170
|
+
/** Active installs when known, release downloads otherwise. */
|
|
171
|
+
installCount: number | null;
|
|
172
|
+
installCountSource: string | null;
|
|
173
|
+
}
|
|
174
|
+
export interface RegistryListing {
|
|
175
|
+
registry: {
|
|
176
|
+
id: string;
|
|
177
|
+
url: string;
|
|
178
|
+
lastCheckedAt: string | null;
|
|
179
|
+
error: string | null;
|
|
180
|
+
};
|
|
181
|
+
managedByServer: boolean;
|
|
182
|
+
plugins: RegistryPluginEntry[];
|
|
183
|
+
}
|
|
184
|
+
export interface PluginStateChange {
|
|
185
|
+
id: string;
|
|
186
|
+
enabled: boolean;
|
|
187
|
+
enable: string[];
|
|
188
|
+
disable: string[];
|
|
189
|
+
missing: string[];
|
|
190
|
+
state?: string;
|
|
191
|
+
}
|
|
192
|
+
export interface PluginDataSummary {
|
|
193
|
+
id: string;
|
|
194
|
+
tables: Array<{
|
|
195
|
+
name: string;
|
|
196
|
+
rows: number | null;
|
|
197
|
+
}>;
|
|
198
|
+
kvKeys: number;
|
|
199
|
+
settings: {
|
|
200
|
+
admin: number;
|
|
201
|
+
user: number;
|
|
202
|
+
host: number;
|
|
203
|
+
secret: number;
|
|
204
|
+
};
|
|
205
|
+
migrations: Array<{
|
|
206
|
+
id: string;
|
|
207
|
+
appliedAt: string | null;
|
|
208
|
+
}>;
|
|
209
|
+
grants: Array<{
|
|
210
|
+
capability: string;
|
|
211
|
+
source: string;
|
|
212
|
+
grantedAt: string | null;
|
|
213
|
+
}>;
|
|
214
|
+
filesBytes: number;
|
|
215
|
+
}
|
|
216
|
+
export interface UpdateAllResult {
|
|
217
|
+
updated: Array<{
|
|
218
|
+
id: string;
|
|
219
|
+
version: string;
|
|
220
|
+
}>;
|
|
221
|
+
needsReview: Array<{
|
|
222
|
+
id: string;
|
|
223
|
+
capabilities: string[];
|
|
224
|
+
}>;
|
|
225
|
+
failed: Array<{
|
|
226
|
+
id: string;
|
|
227
|
+
error: string;
|
|
228
|
+
}>;
|
|
229
|
+
}
|
|
230
|
+
export declare function getPluginRegistry(refresh?: boolean): Promise<RegistryListing>;
|
|
231
|
+
/** `capabilities` is exactly what the consent prompt showed. */
|
|
232
|
+
export declare function installPlugin(pluginId: string, options: {
|
|
233
|
+
version?: string;
|
|
234
|
+
capabilities: string[];
|
|
235
|
+
}): Promise<{
|
|
236
|
+
id: string;
|
|
237
|
+
version: string;
|
|
238
|
+
state: string;
|
|
239
|
+
}>;
|
|
240
|
+
export declare function updatePlugin(pluginId: string, options?: {
|
|
241
|
+
version?: string;
|
|
242
|
+
acceptCapabilities?: boolean;
|
|
243
|
+
capabilities?: string[];
|
|
244
|
+
}): Promise<{
|
|
245
|
+
id: string;
|
|
246
|
+
version: string;
|
|
247
|
+
state: string;
|
|
248
|
+
}>;
|
|
249
|
+
export declare function updateAllPlugins(): Promise<UpdateAllResult>;
|
|
250
|
+
export declare function uninstallPlugin(pluginId: string): Promise<void>;
|
|
251
|
+
export declare function previewPluginState(pluginId: string, enabled: boolean): Promise<PluginStateChange>;
|
|
252
|
+
export declare function setPluginState(pluginId: string, enabled: boolean): Promise<PluginStateChange>;
|
|
253
|
+
export declare function retryPlugin(pluginId: string): Promise<void>;
|
|
254
|
+
export declare function setPluginOptions(pluginId: string, options: {
|
|
255
|
+
autoUpdate?: boolean;
|
|
256
|
+
pinned?: boolean;
|
|
257
|
+
}): Promise<{
|
|
258
|
+
autoUpdate: boolean;
|
|
259
|
+
pinnedVersion: string | null;
|
|
260
|
+
}>;
|
|
261
|
+
export declare function getPluginData(pluginId: string): Promise<PluginDataSummary>;
|
|
262
|
+
export declare function getPluginChangelog(pluginId: string): Promise<ChangelogRelease[]>;
|
|
263
|
+
export declare function deletePluginData(pluginId: string): Promise<void>;
|
|
264
|
+
export interface DeveloperModeState {
|
|
265
|
+
enabled: boolean;
|
|
266
|
+
/** TERMIX_REQUIRE_SIGNED_PLUGINS blocks file installs even in developer mode. */
|
|
267
|
+
signedOnly: boolean;
|
|
268
|
+
}
|
|
269
|
+
export declare function getDeveloperMode(): Promise<DeveloperModeState>;
|
|
270
|
+
/** Fired after developer mode changes; detail is the new value. */
|
|
271
|
+
export declare const DEVELOPER_MODE_CHANGED_EVENT = "termix:plugin-developer-mode";
|
|
272
|
+
export declare function setDeveloperMode(enabled: boolean): Promise<void>;
|
|
273
|
+
export interface PluginUploadPreview {
|
|
274
|
+
token: string;
|
|
275
|
+
id: string;
|
|
276
|
+
name: string;
|
|
277
|
+
version: string;
|
|
278
|
+
description: string;
|
|
279
|
+
author: string;
|
|
280
|
+
capabilities: string[];
|
|
281
|
+
replaces: string | null;
|
|
282
|
+
}
|
|
283
|
+
export declare function uploadPlugin(file: Blob): Promise<PluginUploadPreview>;
|
|
284
|
+
export declare function installUploadedPlugin(token: string, capabilities: string[]): Promise<{
|
|
285
|
+
id: string;
|
|
286
|
+
version: string;
|
|
287
|
+
state: string;
|
|
288
|
+
}>;
|
|
289
|
+
export interface OnboardingPluginInfo {
|
|
290
|
+
id: string;
|
|
291
|
+
name: string;
|
|
292
|
+
description: string;
|
|
293
|
+
icon: string | null;
|
|
294
|
+
category: string;
|
|
295
|
+
version: string;
|
|
296
|
+
source: "bundled" | "user";
|
|
297
|
+
state: string;
|
|
298
|
+
dependencies: string[];
|
|
299
|
+
recommended: boolean;
|
|
300
|
+
consent: boolean;
|
|
301
|
+
}
|
|
302
|
+
export interface OnboardingPluginList {
|
|
303
|
+
pending: boolean;
|
|
304
|
+
/** On an upgrade the picker starts from what is on, not the defaults. */
|
|
305
|
+
reason: "fresh" | "upgrade" | null;
|
|
306
|
+
managedByLinkedServer: boolean;
|
|
307
|
+
plugins: OnboardingPluginInfo[];
|
|
308
|
+
}
|
|
309
|
+
export interface OnboardingApplyResult {
|
|
310
|
+
resolved: Record<string, PluginChoice>;
|
|
311
|
+
adjustments: ChoiceAdjustment[];
|
|
312
|
+
enabled: string[];
|
|
313
|
+
disabled: string[];
|
|
314
|
+
removed: string[];
|
|
315
|
+
failed: {
|
|
316
|
+
id: string;
|
|
317
|
+
error: string;
|
|
318
|
+
code?: string;
|
|
319
|
+
}[];
|
|
320
|
+
}
|
|
321
|
+
export declare function getOnboardingPlugins(): Promise<OnboardingPluginList>;
|
|
322
|
+
export declare function applyOnboardingPlugins(choices: Record<string, PluginChoice>): Promise<OnboardingApplyResult>;
|
|
@@ -2,8 +2,9 @@ interface ConnectionLogPanelProps {
|
|
|
2
2
|
isConnecting: boolean;
|
|
3
3
|
isConnected: boolean;
|
|
4
4
|
hasConnectionError: boolean;
|
|
5
|
+
/** Kept for older callers. The log always sits at the bottom. */
|
|
5
6
|
position?: "top" | "bottom";
|
|
6
7
|
className?: string;
|
|
7
8
|
}
|
|
8
|
-
export declare function ConnectionLogPanel({ isConnecting, isConnected, hasConnectionError,
|
|
9
|
+
export declare function ConnectionLogPanel({ isConnecting, isConnected, hasConnectionError, className, }: ConnectionLogPanelProps): import("react").JSX.Element;
|
|
9
10
|
export {};
|
|
@@ -12,9 +12,7 @@ export interface ConnectionScreenProps {
|
|
|
12
12
|
message?: string;
|
|
13
13
|
/** Second line under the headline, usually user@host:port. */
|
|
14
14
|
detail?: string;
|
|
15
|
-
/**
|
|
16
|
-
errorMessage?: string;
|
|
17
|
-
/** The reason it failed, shown under the headline. */
|
|
15
|
+
/** The reason it failed. Falls back to the last error in the log. */
|
|
18
16
|
errorDetail?: string | null;
|
|
19
17
|
/** Shown instead of a failure when the feature cannot run here. */
|
|
20
18
|
unavailable?: ConnectionUnavailable | null;
|
|
@@ -23,12 +21,14 @@ export interface ConnectionScreenProps {
|
|
|
23
21
|
maxAttempts?: number;
|
|
24
22
|
nextRetryInMs?: number | null;
|
|
25
23
|
onManualRetry?: () => void;
|
|
26
|
-
|
|
24
|
+
/** Headline when it was up and dropped. */
|
|
27
25
|
disconnectedMessage?: string;
|
|
26
|
+
/** Overrides closing the tab this sits in. False hides the button. */
|
|
27
|
+
onClose?: (() => void) | false;
|
|
28
28
|
extraActions?: React.ReactNode;
|
|
29
29
|
logPosition?: "top" | "bottom";
|
|
30
30
|
emptyState?: React.ReactNode;
|
|
31
31
|
className?: string;
|
|
32
32
|
}
|
|
33
33
|
/** The one screen every connection shows until it is up. */
|
|
34
|
-
export declare function ConnectionScreen({ status, message, detail,
|
|
34
|
+
export declare function ConnectionScreen({ status, message, detail, errorDetail, unavailable, backgroundColor, attempt, maxAttempts, nextRetryInMs, onManualRetry, disconnectedMessage, onClose, extraActions, logPosition, emptyState, className, }: ConnectionScreenProps): React.JSX.Element;
|