@termix-ssh/plugin-sdk 1.0.21 → 1.0.22
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/CHANGELOG.md +21 -0
- package/PLUGIN-GUIDE.md +62 -3
- package/cli/commands/build.mjs +55 -36
- package/cli/commands/validate.mjs +4 -0
- package/dist/backend.d.ts +32 -7
- package/dist/frontend.d.ts +7 -0
- package/dist/host/{PluginsTab-HQGSDSHS.js → PluginsTab-CM2B33BD.js} +22 -14
- package/dist/host/chunk-7J4QNGFM.js +345 -0
- package/dist/host/{chunk-A5CULDWV.js → chunk-HQ6NNFSX.js} +109 -1574
- package/dist/host/chunk-I5F2PSMR.js +1526 -0
- package/dist/host/{chunk-FGX27MAA.js → chunk-JRV2HIDK.js} +1 -1
- package/dist/host/{chunk-JFQGI4OD.js → chunk-P26QKKU5.js} +38 -9
- package/dist/host/{chunk-WWFRBU2E.js → chunk-ROB2SH5Q.js} +76 -49
- package/dist/host/chunk-TK3Y437H.js +53 -0
- package/dist/host/{chunk-GTHINW3L.js → chunk-VKNGNEF3.js} +34650 -34968
- package/dist/host/core-classes.json +1 -1
- package/dist/host/frame-host.css +2 -0
- package/dist/host/frame-host.js +242 -0
- package/dist/host/{linked-server-UDSFY3N7.js → linked-server-J5G457OA.js} +1 -1
- package/dist/host/{rbac-api-AAAPMF52.js → rbac-api-PY22W5UY.js} +5 -1
- package/dist/host/testing-host.js +9 -6
- package/dist/host/types/src/types/host-sidebar-preferences.d.ts +2 -0
- package/dist/host/types/src/types/index.d.ts +8 -0
- package/dist/host/types/src/ui/api/plugins-api.d.ts +2 -1
- package/dist/host/types/src/ui/api/rbac-api.d.ts +19 -1
- package/dist/host/types/src/ui/components/data-view.d.ts +1 -1
- package/dist/host/types/src/ui/main-axios.d.ts +1 -1
- package/dist/host/types/src/ui/plugin-host/loader.d.ts +6 -0
- package/dist/host/types/src/ui/plugin-host/sdk-ui.d.ts +1 -1
- package/dist/host/types/src/ui/plugins/use-plugins-manager.d.ts +1 -1
- package/dist/host/types/src/ui/shell/tab-registry.d.ts +2 -0
- package/dist/host/ui.js +356 -369
- package/dist/host/{use-permissions-VAND5GEG.js → use-permissions-EWRI3WLT.js} +1 -1
- package/dist/host-commands.d.ts +7 -0
- package/dist/host-commands.js +35 -5
- package/dist/manifest.d.ts +28 -1
- package/dist/manifest.js +108 -1
- package/package.json +5 -1
- package/schema/manifest.schema.json +42 -0
|
@@ -3,65 +3,33 @@ import {
|
|
|
3
3
|
hasPermission,
|
|
4
4
|
resetPermissionsCache,
|
|
5
5
|
usePermissions
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JRV2HIDK.js";
|
|
7
7
|
import {
|
|
8
|
-
ArrowDownToLine,
|
|
9
|
-
ArrowLeftToLine,
|
|
10
|
-
ArrowRightToLine,
|
|
11
|
-
Button,
|
|
12
|
-
Check,
|
|
13
|
-
Checkbox,
|
|
14
|
-
CheckboxIndicator,
|
|
15
|
-
CircleSlash,
|
|
16
8
|
Columns2,
|
|
17
|
-
DefaultsOnly,
|
|
18
|
-
DocsLink,
|
|
19
|
-
Eye,
|
|
20
|
-
EyeOff,
|
|
21
|
-
FakeSwitch,
|
|
22
|
-
HostDefaultBadge,
|
|
23
|
-
Input,
|
|
24
9
|
KeyRound,
|
|
25
|
-
LayoutPanelLeft,
|
|
26
10
|
LibraryBig,
|
|
27
11
|
Maximize2,
|
|
28
12
|
OPEN_PLUGINS_EVENT,
|
|
29
13
|
OPEN_PLUGIN_SETTINGS_EVENT,
|
|
30
|
-
PLUGINS_CHANGED_EVENT,
|
|
31
14
|
PLUGIN_SETTINGS_CHANGED_EVENT,
|
|
32
|
-
PanelRight,
|
|
33
15
|
Plug,
|
|
34
|
-
PluginIcon,
|
|
35
16
|
Puzzle,
|
|
36
17
|
RotateCcw,
|
|
37
18
|
Rows2,
|
|
38
|
-
SectionCard,
|
|
39
|
-
Select,
|
|
40
|
-
SelectContent,
|
|
41
|
-
SelectItem,
|
|
42
|
-
SelectTrigger,
|
|
43
|
-
SelectValue,
|
|
44
19
|
Server,
|
|
45
|
-
SettingRow,
|
|
46
20
|
Settings,
|
|
47
21
|
Terminal,
|
|
48
22
|
X,
|
|
49
23
|
Zap,
|
|
50
|
-
cn,
|
|
51
24
|
getPluginAdminSettings,
|
|
52
25
|
getPluginHostSettings,
|
|
53
26
|
getPluginUserSettings,
|
|
54
|
-
getPlugins,
|
|
55
27
|
guardCallback,
|
|
56
|
-
hasVisibleFields,
|
|
57
|
-
isFieldShown,
|
|
58
|
-
isRedactedSecret,
|
|
59
28
|
notifyShellReady,
|
|
60
29
|
notifyTabsChanged,
|
|
61
30
|
pluginDocsPage,
|
|
62
31
|
pluginDocsUrl,
|
|
63
32
|
pluginKey,
|
|
64
|
-
pluginName,
|
|
65
33
|
scopeHostArgs,
|
|
66
34
|
scopeHostCallback,
|
|
67
35
|
scopeHostFields,
|
|
@@ -83,7 +51,7 @@ import {
|
|
|
83
51
|
withIconBoundary,
|
|
84
52
|
withPluginContext,
|
|
85
53
|
withPluginScope
|
|
86
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-VKNGNEF3.js";
|
|
87
55
|
import {
|
|
88
56
|
SYNC_CHANGED_EVENT,
|
|
89
57
|
TRUST_TOKEN_KEY,
|
|
@@ -128,95 +96,14 @@ import {
|
|
|
128
96
|
saveUserPreferences,
|
|
129
97
|
setCookie,
|
|
130
98
|
tabTypeForActivity,
|
|
131
|
-
unregisteredViewStatus,
|
|
132
99
|
usePluginStore,
|
|
133
100
|
useTabTypes,
|
|
134
101
|
websocketAuthProtocols
|
|
135
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-P26QKKU5.js";
|
|
136
103
|
import {
|
|
137
|
-
define_import_meta_env_default,
|
|
138
104
|
init_define_import_meta_env
|
|
139
105
|
} from "./chunk-YGYBM7SQ.js";
|
|
140
106
|
|
|
141
|
-
// src/ui/components/checkbox.tsx
|
|
142
|
-
init_define_import_meta_env();
|
|
143
|
-
import { jsx } from "react/jsx-runtime";
|
|
144
|
-
function Checkbox2({
|
|
145
|
-
className,
|
|
146
|
-
...props
|
|
147
|
-
}) {
|
|
148
|
-
return /* @__PURE__ */ jsx(
|
|
149
|
-
Checkbox,
|
|
150
|
-
{
|
|
151
|
-
"data-slot": "checkbox",
|
|
152
|
-
className: cn(
|
|
153
|
-
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-none border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
|
154
|
-
className
|
|
155
|
-
),
|
|
156
|
-
...props,
|
|
157
|
-
children: /* @__PURE__ */ jsx(
|
|
158
|
-
CheckboxIndicator,
|
|
159
|
-
{
|
|
160
|
-
"data-slot": "checkbox-indicator",
|
|
161
|
-
className: "flex items-center justify-center text-current transition-none",
|
|
162
|
-
children: /* @__PURE__ */ jsx(Check, { className: "size-3.5" })
|
|
163
|
-
}
|
|
164
|
-
)
|
|
165
|
-
}
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// src/ui/components/password-input.tsx
|
|
170
|
-
init_define_import_meta_env();
|
|
171
|
-
import * as React from "react";
|
|
172
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
173
|
-
var PasswordInput = React.forwardRef(({ className, ...props }, ref) => {
|
|
174
|
-
const [showPassword, setShowPassword] = React.useState(false);
|
|
175
|
-
return /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
|
|
176
|
-
/* @__PURE__ */ jsx2(
|
|
177
|
-
Input,
|
|
178
|
-
{
|
|
179
|
-
ref,
|
|
180
|
-
type: showPassword ? "text" : "password",
|
|
181
|
-
className: cn("h-11 text-base pr-12", className),
|
|
182
|
-
...props
|
|
183
|
-
}
|
|
184
|
-
),
|
|
185
|
-
/* @__PURE__ */ jsx2(
|
|
186
|
-
"button",
|
|
187
|
-
{
|
|
188
|
-
type: "button",
|
|
189
|
-
onClick: () => setShowPassword((prev) => !prev),
|
|
190
|
-
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition",
|
|
191
|
-
"aria-label": showPassword ? "Hide password" : "Show password",
|
|
192
|
-
children: showPassword ? /* @__PURE__ */ jsx2(EyeOff, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx2(Eye, { className: "h-5 w-5" })
|
|
193
|
-
}
|
|
194
|
-
)
|
|
195
|
-
] });
|
|
196
|
-
});
|
|
197
|
-
PasswordInput.displayName = "PasswordInput";
|
|
198
|
-
|
|
199
|
-
// src/ui/components/textarea.tsx
|
|
200
|
-
init_define_import_meta_env();
|
|
201
|
-
import * as React2 from "react";
|
|
202
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
203
|
-
var Textarea = React2.forwardRef(
|
|
204
|
-
({ className, ...props }, ref) => {
|
|
205
|
-
return /* @__PURE__ */ jsx3(
|
|
206
|
-
"textarea",
|
|
207
|
-
{
|
|
208
|
-
className: cn(
|
|
209
|
-
"flex min-h-[80px] w-full rounded-none border border-input bg-transparent dark:bg-input/30 px-3 py-2 text-sm shadow-xs transition-[color,box-shadow] duration-200 outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 disabled:pointer-events-none",
|
|
210
|
-
className
|
|
211
|
-
),
|
|
212
|
-
ref,
|
|
213
|
-
...props
|
|
214
|
-
}
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
);
|
|
218
|
-
Textarea.displayName = "Textarea";
|
|
219
|
-
|
|
220
107
|
// src/ui/lib/rem.ts
|
|
221
108
|
init_define_import_meta_env();
|
|
222
109
|
var ROOT_PX = 14;
|
|
@@ -232,13 +119,13 @@ function remScale() {
|
|
|
232
119
|
|
|
233
120
|
// src/ui/hooks/use-mobile.ts
|
|
234
121
|
init_define_import_meta_env();
|
|
235
|
-
import * as
|
|
122
|
+
import * as React from "react";
|
|
236
123
|
var MOBILE_BREAKPOINT = 768;
|
|
237
124
|
function useIsMobile() {
|
|
238
|
-
const [isMobile, setIsMobile] =
|
|
125
|
+
const [isMobile, setIsMobile] = React.useState(
|
|
239
126
|
void 0
|
|
240
127
|
);
|
|
241
|
-
|
|
128
|
+
React.useEffect(() => {
|
|
242
129
|
if (isElectron()) {
|
|
243
130
|
setIsMobile(false);
|
|
244
131
|
return;
|
|
@@ -1499,6 +1386,8 @@ var en_default = {
|
|
|
1499
1386
|
closeOnOpenDesc: "Close the sidebar after you open a host from it",
|
|
1500
1387
|
showFolderPaths: "Show folder paths",
|
|
1501
1388
|
showFolderPathsDesc: "Show the parent folder path above nested subfolder names. Subfolders stay indented either way.",
|
|
1389
|
+
stripedRows: "Alternating row colors",
|
|
1390
|
+
stripedRowsDesc: "Shade every other row in the host list",
|
|
1502
1391
|
rowDetailsTitle: "Row details",
|
|
1503
1392
|
rowDetailsDesc: "Choose what shows on each host.",
|
|
1504
1393
|
showAddress: "Address",
|
|
@@ -1684,6 +1573,8 @@ var en_default = {
|
|
|
1684
1573
|
sharedBadge: "Shared",
|
|
1685
1574
|
sharedBadgeTooltip: "Shared by {{owner}} ({{level}} access)",
|
|
1686
1575
|
viewOnlyBanner: "This host is shared with you by {{owner}} with view access. The configuration is read-only.",
|
|
1576
|
+
folderRuleRemoveFromHosts: "Also remove this access from every host in the folder and its subfolders",
|
|
1577
|
+
sharedCopyBanner: "This host is shared with you by {{owner}}. The desktop keeps a read-only copy, so change it on the server and it syncs here.",
|
|
1687
1578
|
sharedEditBanner: "This host is shared with you by {{owner}} with edit access. Changes apply to the real host; authentication references can only be changed by the owner.",
|
|
1688
1579
|
ownerOnlyControl: "Only the host owner can change this",
|
|
1689
1580
|
ownerAuthPrivate: "The host owner's SSH authentication is private. Use \u201CSet personal SSH authentication\u201D from the host menu to choose your own credential.",
|
|
@@ -2862,7 +2753,7 @@ function resetRegisteredRailItems() {
|
|
|
2862
2753
|
|
|
2863
2754
|
// src/ui/sidebar/HostManagerTabs.tsx
|
|
2864
2755
|
init_define_import_meta_env();
|
|
2865
|
-
import { jsx
|
|
2756
|
+
import { jsx } from "react/jsx-runtime";
|
|
2866
2757
|
var sections = createRegistry(byOrderThenId);
|
|
2867
2758
|
var registerHostEditorSection = sections.register;
|
|
2868
2759
|
var unregisterHostEditorSection = sections.unregister;
|
|
@@ -2886,7 +2777,7 @@ function mergeByOrder(core, group, t, protocols2, defaultsMode = false) {
|
|
|
2886
2777
|
return {
|
|
2887
2778
|
id: section.id,
|
|
2888
2779
|
label: t(section.labelKey, { defaultValue: section.label }),
|
|
2889
|
-
icon: Icon ? /* @__PURE__ */
|
|
2780
|
+
icon: Icon ? /* @__PURE__ */ jsx(Icon, { className: "size-3" }) : null,
|
|
2890
2781
|
order: section.order ?? 1e3
|
|
2891
2782
|
};
|
|
2892
2783
|
});
|
|
@@ -2898,13 +2789,13 @@ function makeHostTabs(t, protocols2, defaultsMode = false) {
|
|
|
2898
2789
|
{
|
|
2899
2790
|
id: "general",
|
|
2900
2791
|
label: t("hosts.tabGeneral"),
|
|
2901
|
-
icon: /* @__PURE__ */
|
|
2792
|
+
icon: /* @__PURE__ */ jsx(Settings, { className: "size-3" }),
|
|
2902
2793
|
order: 0
|
|
2903
2794
|
},
|
|
2904
2795
|
{
|
|
2905
2796
|
id: "ssh",
|
|
2906
2797
|
label: t("hosts.tabSsh"),
|
|
2907
|
-
icon: /* @__PURE__ */
|
|
2798
|
+
icon: /* @__PURE__ */ jsx(Terminal, { className: "size-3" }),
|
|
2908
2799
|
order: 10
|
|
2909
2800
|
}
|
|
2910
2801
|
],
|
|
@@ -2920,7 +2811,7 @@ function makeHostSshSubTabs(t, protocols2, defaultsMode = false) {
|
|
|
2920
2811
|
{
|
|
2921
2812
|
id: "ssh",
|
|
2922
2813
|
label: t("hosts.tabGeneral"),
|
|
2923
|
-
icon: /* @__PURE__ */
|
|
2814
|
+
icon: /* @__PURE__ */ jsx(Settings, { className: "size-3" }),
|
|
2924
2815
|
order: 0
|
|
2925
2816
|
}
|
|
2926
2817
|
],
|
|
@@ -3394,7 +3285,7 @@ async function pluginWsUrl(pluginId, path2, options = {}) {
|
|
|
3394
3285
|
}
|
|
3395
3286
|
const token = await fetchSocketTicket() ?? localStorage.getItem("jwt");
|
|
3396
3287
|
const protocols2 = websocketAuthProtocols(token);
|
|
3397
|
-
const devProxy =
|
|
3288
|
+
const devProxy = false;
|
|
3398
3289
|
const wsProtocol = window.location.protocol === "https:" ? "wss" : "ws";
|
|
3399
3290
|
if (devProxy) {
|
|
3400
3291
|
return {
|
|
@@ -3470,7 +3361,7 @@ function sectionPosition(section, order2 = 0, position) {
|
|
|
3470
3361
|
|
|
3471
3362
|
// src/ui/hooks/use-status-color-scheme.ts
|
|
3472
3363
|
init_define_import_meta_env();
|
|
3473
|
-
import { useState as
|
|
3364
|
+
import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
3474
3365
|
var PREFS_KEY = "hostSidebarPreferences";
|
|
3475
3366
|
var PREFS_EVENT = "hostSidebarPreferencesChanged";
|
|
3476
3367
|
function readStatusColorScheme() {
|
|
@@ -3484,7 +3375,7 @@ function readStatusColorScheme() {
|
|
|
3484
3375
|
}
|
|
3485
3376
|
}
|
|
3486
3377
|
function useStatusColorScheme() {
|
|
3487
|
-
const [scheme, setScheme] =
|
|
3378
|
+
const [scheme, setScheme] = useState2(
|
|
3488
3379
|
readStatusColorScheme
|
|
3489
3380
|
);
|
|
3490
3381
|
useEffect2(() => {
|
|
@@ -3524,10 +3415,6 @@ function getStatusClasses(status, scheme, variant, loading = false) {
|
|
|
3524
3415
|
return online ? "border-accent-brand/40 text-accent-brand bg-accent-brand/10" : "border-border/50 text-muted-foreground/60 bg-muted/30";
|
|
3525
3416
|
}
|
|
3526
3417
|
|
|
3527
|
-
// src/ui/components/theme-provider.tsx
|
|
3528
|
-
init_define_import_meta_env();
|
|
3529
|
-
import { createContext, useContext, useEffect as useEffect3, useState as useState4 } from "react";
|
|
3530
|
-
|
|
3531
3418
|
// src/ui/look/theme-registry.ts
|
|
3532
3419
|
init_define_import_meta_env();
|
|
3533
3420
|
import { useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
@@ -3611,6 +3498,10 @@ function arePluginThemesKnown() {
|
|
|
3611
3498
|
return pluginThemesKnown;
|
|
3612
3499
|
}
|
|
3613
3500
|
|
|
3501
|
+
// src/ui/components/theme-provider.tsx
|
|
3502
|
+
init_define_import_meta_env();
|
|
3503
|
+
import { createContext, useContext, useEffect as useEffect3, useState as useState3 } from "react";
|
|
3504
|
+
|
|
3614
3505
|
// src/ui/look/theme-css.ts
|
|
3615
3506
|
init_define_import_meta_env();
|
|
3616
3507
|
var LINK_ID = "termix-theme-css";
|
|
@@ -3661,7 +3552,7 @@ function applyThemeCss(id, theme) {
|
|
|
3661
3552
|
}
|
|
3662
3553
|
|
|
3663
3554
|
// src/ui/components/theme-provider.tsx
|
|
3664
|
-
import { jsx as
|
|
3555
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
3665
3556
|
var initialState = {
|
|
3666
3557
|
theme: "dark",
|
|
3667
3558
|
setTheme: () => null,
|
|
@@ -3675,10 +3566,10 @@ function ThemeProvider({
|
|
|
3675
3566
|
storageKey = "vite-ui-theme",
|
|
3676
3567
|
...props
|
|
3677
3568
|
}) {
|
|
3678
|
-
const [theme, setTheme] =
|
|
3569
|
+
const [theme, setTheme] = useState3(
|
|
3679
3570
|
() => localStorage.getItem(storageKey) || defaultTheme
|
|
3680
3571
|
);
|
|
3681
|
-
const [previewTheme, setPreviewTheme] =
|
|
3572
|
+
const [previewTheme, setPreviewTheme] = useState3(null);
|
|
3682
3573
|
const themes = useThemes();
|
|
3683
3574
|
const shownTheme = effectiveThemeId(theme);
|
|
3684
3575
|
const activeTheme = previewTheme ?? shownTheme;
|
|
@@ -3701,7 +3592,7 @@ function ThemeProvider({
|
|
|
3701
3592
|
setPreviewTheme(preview);
|
|
3702
3593
|
}
|
|
3703
3594
|
};
|
|
3704
|
-
return /* @__PURE__ */
|
|
3595
|
+
return /* @__PURE__ */ jsx2(ThemeProviderContext.Provider, { ...props, value, children });
|
|
3705
3596
|
}
|
|
3706
3597
|
var useTheme = () => {
|
|
3707
3598
|
const context = useContext(ThemeProviderContext);
|
|
@@ -3712,7 +3603,7 @@ var useTheme = () => {
|
|
|
3712
3603
|
|
|
3713
3604
|
// src/ui/hooks/useSshAuthProviders.ts
|
|
3714
3605
|
init_define_import_meta_env();
|
|
3715
|
-
import { useEffect as useEffect4, useMemo as useMemo2, useState as
|
|
3606
|
+
import { useEffect as useEffect4, useMemo as useMemo2, useState as useState4 } from "react";
|
|
3716
3607
|
var BUILTIN_TYPES = ["password", "key", "credential", "agent", "none"];
|
|
3717
3608
|
function builtinSummary(type) {
|
|
3718
3609
|
return {
|
|
@@ -3730,7 +3621,7 @@ function builtinSummary(type) {
|
|
|
3730
3621
|
var cache = null;
|
|
3731
3622
|
function useSshAuthProviders() {
|
|
3732
3623
|
const editors = useSshAuthEditors();
|
|
3733
|
-
const [summaries, setSummaries] =
|
|
3624
|
+
const [summaries, setSummaries] = useState4(
|
|
3734
3625
|
null
|
|
3735
3626
|
);
|
|
3736
3627
|
useEffect4(() => {
|
|
@@ -3812,14 +3703,14 @@ import {
|
|
|
3812
3703
|
useContext as useContext2,
|
|
3813
3704
|
useEffect as useEffect5,
|
|
3814
3705
|
useMemo as useMemo4,
|
|
3815
|
-
useState as
|
|
3706
|
+
useState as useState5
|
|
3816
3707
|
} from "react";
|
|
3817
3708
|
|
|
3818
3709
|
// src/ui/contexts/branding-document.ts
|
|
3819
3710
|
init_define_import_meta_env();
|
|
3820
3711
|
|
|
3821
3712
|
// src/ui/contexts/BrandingContext.tsx
|
|
3822
|
-
import { jsx as
|
|
3713
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
3823
3714
|
var DEFAULT_APP_NAME = "Termix";
|
|
3824
3715
|
var BrandingContext = createContext2({
|
|
3825
3716
|
ready: false,
|
|
@@ -5210,7 +5101,7 @@ import {
|
|
|
5210
5101
|
useLayoutEffect as useLayoutEffect2,
|
|
5211
5102
|
useMemo as useMemo5,
|
|
5212
5103
|
useRef as useRef6,
|
|
5213
|
-
useState as
|
|
5104
|
+
useState as useState11
|
|
5214
5105
|
} from "react";
|
|
5215
5106
|
|
|
5216
5107
|
// src/ui/shell/stage/tab-stage-store.ts
|
|
@@ -5218,14 +5109,14 @@ init_define_import_meta_env();
|
|
|
5218
5109
|
function createTabStageStore() {
|
|
5219
5110
|
const nodes = /* @__PURE__ */ new Map();
|
|
5220
5111
|
const paneEls = /* @__PURE__ */ new Map();
|
|
5221
|
-
const
|
|
5112
|
+
const listeners8 = /* @__PURE__ */ new Set();
|
|
5222
5113
|
let normalView = null;
|
|
5223
|
-
let
|
|
5114
|
+
let version3 = 0;
|
|
5224
5115
|
let order2 = [];
|
|
5225
5116
|
let lastAnimatedTabId = null;
|
|
5226
5117
|
const bump = () => {
|
|
5227
|
-
|
|
5228
|
-
for (const listener of
|
|
5118
|
+
version3 += 1;
|
|
5119
|
+
for (const listener of listeners8) listener();
|
|
5229
5120
|
};
|
|
5230
5121
|
function getNode(tabId, ownBackground) {
|
|
5231
5122
|
let el = nodes.get(tabId);
|
|
@@ -5327,18 +5218,18 @@ function createTabStageStore() {
|
|
|
5327
5218
|
setNormalView,
|
|
5328
5219
|
place,
|
|
5329
5220
|
subscribe: (listener) => {
|
|
5330
|
-
|
|
5221
|
+
listeners8.add(listener);
|
|
5331
5222
|
return () => {
|
|
5332
|
-
|
|
5223
|
+
listeners8.delete(listener);
|
|
5333
5224
|
};
|
|
5334
5225
|
},
|
|
5335
|
-
version: () =>
|
|
5226
|
+
version: () => version3
|
|
5336
5227
|
};
|
|
5337
5228
|
}
|
|
5338
5229
|
|
|
5339
5230
|
// src/ui/shell/controller/use-regions.ts
|
|
5340
5231
|
init_define_import_meta_env();
|
|
5341
|
-
import { useCallback as useCallback2, useEffect as useEffect6, useRef, useState as
|
|
5232
|
+
import { useCallback as useCallback2, useEffect as useEffect6, useRef, useState as useState6 } from "react";
|
|
5342
5233
|
var MIN_WIDTH = 160;
|
|
5343
5234
|
var MAX_WIDTH = 480;
|
|
5344
5235
|
function clampWidth(width) {
|
|
@@ -5371,15 +5262,15 @@ function startDockDrag(e, startW, sign, setWidth, setDragging) {
|
|
|
5371
5262
|
}
|
|
5372
5263
|
var DOCK_DEFAULT_WIDTH = 291;
|
|
5373
5264
|
function useRegions(isMobile) {
|
|
5374
|
-
const [sidebarOpen, setSidebarOpen] =
|
|
5375
|
-
const [railView, setRailView] =
|
|
5376
|
-
const [sidebarWidth, setSidebarWidth] =
|
|
5265
|
+
const [sidebarOpen, setSidebarOpen] = useState6(true);
|
|
5266
|
+
const [railView, setRailView] = useState6("hosts");
|
|
5267
|
+
const [sidebarWidth, setSidebarWidth] = useState6(() => {
|
|
5377
5268
|
const saved = localStorage.getItem("termix_sidebarWidth");
|
|
5378
5269
|
return saved ? parseInt(saved, 10) : 291;
|
|
5379
5270
|
});
|
|
5380
|
-
const [sidebarDragging, setSidebarDragging] =
|
|
5381
|
-
const [panelEditing, setPanelEditing] =
|
|
5382
|
-
const [scopeEditing, setScopeEditing] =
|
|
5271
|
+
const [sidebarDragging, setSidebarDragging] = useState6(false);
|
|
5272
|
+
const [panelEditing, setPanelEditing] = useState6({});
|
|
5273
|
+
const [scopeEditing, setScopeEditing] = useState6({});
|
|
5383
5274
|
const editingSetters = useRef(
|
|
5384
5275
|
/* @__PURE__ */ new Map()
|
|
5385
5276
|
);
|
|
@@ -5405,15 +5296,15 @@ function useRegions(isMobile) {
|
|
|
5405
5296
|
);
|
|
5406
5297
|
return editingSetters.current.get(key);
|
|
5407
5298
|
}, []);
|
|
5408
|
-
const [rightRailView, setRightRailView] =
|
|
5299
|
+
const [rightRailView, setRightRailView] = useState6(() => {
|
|
5409
5300
|
const saved = localStorage.getItem("termix_rightRailView");
|
|
5410
5301
|
return saved && rightDockableIds().includes(saved) ? saved : null;
|
|
5411
5302
|
});
|
|
5412
|
-
const [rightSidebarWidth, setRightSidebarWidth] =
|
|
5303
|
+
const [rightSidebarWidth, setRightSidebarWidth] = useState6(() => {
|
|
5413
5304
|
const saved = localStorage.getItem("termix_rightSidebarWidth");
|
|
5414
5305
|
return saved ? parseInt(saved, 10) : 291;
|
|
5415
5306
|
});
|
|
5416
|
-
const [rightSidebarDragging, setRightSidebarDragging] =
|
|
5307
|
+
const [rightSidebarDragging, setRightSidebarDragging] = useState6(false);
|
|
5417
5308
|
const lastRightRailViewRef = useRef(
|
|
5418
5309
|
localStorage.getItem("termix_lastRightRailView")
|
|
5419
5310
|
);
|
|
@@ -5524,7 +5415,7 @@ function useRegions(isMobile) {
|
|
|
5524
5415
|
|
|
5525
5416
|
// src/ui/shell/controller/use-hosts.ts
|
|
5526
5417
|
init_define_import_meta_env();
|
|
5527
|
-
import { useCallback as useCallback3, useEffect as useEffect7, useRef as useRef2, useState as
|
|
5418
|
+
import { useCallback as useCallback3, useEffect as useEffect7, useRef as useRef2, useState as useState7 } from "react";
|
|
5528
5419
|
|
|
5529
5420
|
// src/ui/sidebar/build-host-tree.ts
|
|
5530
5421
|
init_define_import_meta_env();
|
|
@@ -5596,10 +5487,10 @@ function buildHostTree(hosts, folderMeta) {
|
|
|
5596
5487
|
|
|
5597
5488
|
// src/ui/shell/controller/use-hosts.ts
|
|
5598
5489
|
function useHostList() {
|
|
5599
|
-
const [tree, setTree] =
|
|
5600
|
-
const [loading, setLoading] =
|
|
5601
|
-
const [loaded, setLoaded] =
|
|
5602
|
-
const [list, setList] =
|
|
5490
|
+
const [tree, setTree] = useState7(null);
|
|
5491
|
+
const [loading, setLoading] = useState7(true);
|
|
5492
|
+
const [loaded, setLoaded] = useState7(false);
|
|
5493
|
+
const [list, setList] = useState7([]);
|
|
5603
5494
|
const listRef = useRef2(list);
|
|
5604
5495
|
listRef.current = list;
|
|
5605
5496
|
const reload = useCallback3(async () => {
|
|
@@ -5656,7 +5547,7 @@ import {
|
|
|
5656
5547
|
useCallback as useCallback4,
|
|
5657
5548
|
useEffect as useEffect8,
|
|
5658
5549
|
useRef as useRef3,
|
|
5659
|
-
useState as
|
|
5550
|
+
useState as useState8
|
|
5660
5551
|
} from "react";
|
|
5661
5552
|
import { toast } from "sonner";
|
|
5662
5553
|
import { useTranslation } from "react-i18next";
|
|
@@ -5708,10 +5599,10 @@ function useTabs({
|
|
|
5708
5599
|
}) {
|
|
5709
5600
|
const { t } = useTranslation();
|
|
5710
5601
|
const splitLabel = useSplitLabel();
|
|
5711
|
-
const [tabs, setTabs] =
|
|
5712
|
-
const [activeTabId, setActiveTabId] =
|
|
5713
|
-
const [tabsReady, setTabsReady] =
|
|
5714
|
-
const [backgroundTabRecords, setBackgroundTabRecords] =
|
|
5602
|
+
const [tabs, setTabs] = useState8([dashboardTab(t("nav.dashboard"))]);
|
|
5603
|
+
const [activeTabId, setActiveTabId] = useState8("dashboard");
|
|
5604
|
+
const [tabsReady, setTabsReady] = useState8(false);
|
|
5605
|
+
const [backgroundTabRecords, setBackgroundTabRecords] = useState8([]);
|
|
5715
5606
|
const paneLayoutRestoredRef = useRef3(false);
|
|
5716
5607
|
const splitTabsRestoredRef = useRef3(false);
|
|
5717
5608
|
const splitOpsRef = useRef3({
|
|
@@ -5800,14 +5691,14 @@ function useTabs({
|
|
|
5800
5691
|
if (!isSplitTab(active)) return activeTabId;
|
|
5801
5692
|
return findPane(active.split, active.split.focusedPaneId)?.tabId ?? "";
|
|
5802
5693
|
})();
|
|
5803
|
-
const [lastTerminalTabId, setLastTerminalTabId] =
|
|
5694
|
+
const [lastTerminalTabId, setLastTerminalTabId] = useState8(activeTabId);
|
|
5804
5695
|
useEffect8(() => {
|
|
5805
5696
|
const working = tabs.find((t2) => t2.id === workingTabId);
|
|
5806
5697
|
if (working && getTabType(working.type)?.commandTarget) {
|
|
5807
5698
|
setLastTerminalTabId(working.id);
|
|
5808
5699
|
}
|
|
5809
5700
|
}, [workingTabId, tabs]);
|
|
5810
|
-
const [showTabNumbers, setShowTabNumbers] =
|
|
5701
|
+
const [showTabNumbers, setShowTabNumbers] = useState8(
|
|
5811
5702
|
() => localStorage.getItem("showTabNumbers") === "true"
|
|
5812
5703
|
);
|
|
5813
5704
|
useEffect8(() => {
|
|
@@ -6361,7 +6252,7 @@ function useSplit({
|
|
|
6361
6252
|
tabsState,
|
|
6362
6253
|
isMobile,
|
|
6363
6254
|
paneEls,
|
|
6364
|
-
callbacks
|
|
6255
|
+
callbacks,
|
|
6365
6256
|
resizeAllTerminals
|
|
6366
6257
|
}) {
|
|
6367
6258
|
const { t } = useTranslation2();
|
|
@@ -6760,8 +6651,8 @@ function useSplit({
|
|
|
6760
6651
|
};
|
|
6761
6652
|
}
|
|
6762
6653
|
const pickerShell = {
|
|
6763
|
-
...
|
|
6764
|
-
openTab: (host, type, options) =>
|
|
6654
|
+
...callbacks,
|
|
6655
|
+
openTab: (host, type, options) => callbacks.openTab(host, type, { ...options, forceNewTab: true })
|
|
6765
6656
|
};
|
|
6766
6657
|
const split = {
|
|
6767
6658
|
active: activeSplit,
|
|
@@ -6927,7 +6818,7 @@ function useWorkspaceLayout(tabsState, regions) {
|
|
|
6927
6818
|
|
|
6928
6819
|
// src/ui/shell/controller/use-shell-keybindings.ts
|
|
6929
6820
|
init_define_import_meta_env();
|
|
6930
|
-
import { useEffect as useEffect11, useRef as useRef5, useState as
|
|
6821
|
+
import { useEffect as useEffect11, useRef as useRef5, useState as useState9 } from "react";
|
|
6931
6822
|
|
|
6932
6823
|
// src/ui/lib/pane-nav-hotkey.ts
|
|
6933
6824
|
init_define_import_meta_env();
|
|
@@ -7031,7 +6922,7 @@ function useShellKeybindings({
|
|
|
7031
6922
|
closeActiveTabRef.current();
|
|
7032
6923
|
});
|
|
7033
6924
|
}, []);
|
|
7034
|
-
const [commandPaletteShortcutEnabled, setCommandPaletteShortcutEnabled] =
|
|
6925
|
+
const [commandPaletteShortcutEnabled, setCommandPaletteShortcutEnabled] = useState9(() => {
|
|
7035
6926
|
const v = localStorage.getItem("commandPaletteShortcutEnabled");
|
|
7036
6927
|
return v !== null ? v === "true" : true;
|
|
7037
6928
|
});
|
|
@@ -7098,7 +6989,7 @@ function useShellKeybindings({
|
|
|
7098
6989
|
const tabDigit = getTabJumpDigit(e);
|
|
7099
6990
|
if (tabDigit !== null) {
|
|
7100
6991
|
const currentTabs = tabsRef.current.filter(
|
|
7101
|
-
(tab) => !tab.parentSplitTabId
|
|
6992
|
+
(tab) => !tab.parentSplitTabId && tab.type !== "dashboard"
|
|
7102
6993
|
);
|
|
7103
6994
|
const index = tabDigit - 1;
|
|
7104
6995
|
if (index < currentTabs.length) {
|
|
@@ -7144,7 +7035,7 @@ function useShellKeybindings({
|
|
|
7144
7035
|
|
|
7145
7036
|
// src/ui/shell/controller/use-shell-lifecycle.ts
|
|
7146
7037
|
init_define_import_meta_env();
|
|
7147
|
-
import { useCallback as useCallback5, useEffect as useEffect12, useState as
|
|
7038
|
+
import { useCallback as useCallback5, useEffect as useEffect12, useState as useState10 } from "react";
|
|
7148
7039
|
import { toast as toast3 } from "sonner";
|
|
7149
7040
|
import { useTranslation as useTranslation3 } from "react-i18next";
|
|
7150
7041
|
var SNAPSHOT_KEYS = [
|
|
@@ -7223,12 +7114,12 @@ function useShellLifecycle({
|
|
|
7223
7114
|
}) {
|
|
7224
7115
|
const { t, i18n: i18n2 } = useTranslation3();
|
|
7225
7116
|
const { setTheme } = useTheme();
|
|
7226
|
-
const [userPrefs, setUserPrefs] =
|
|
7117
|
+
const [userPrefs, setUserPrefs] = useState10({
|
|
7227
7118
|
reopenTabsOnLogin: false
|
|
7228
7119
|
});
|
|
7229
|
-
const [userPrefsLoaded, setUserPrefsLoaded] =
|
|
7230
|
-
const [isAdmin, setIsAdmin] =
|
|
7231
|
-
const [isAppFullscreen, setIsAppFullscreen] =
|
|
7120
|
+
const [userPrefsLoaded, setUserPrefsLoaded] = useState10(false);
|
|
7121
|
+
const [isAdmin, setIsAdmin] = useState10(false);
|
|
7122
|
+
const [isAppFullscreen, setIsAppFullscreen] = useState10(
|
|
7232
7123
|
() => !!document.fullscreenElement
|
|
7233
7124
|
);
|
|
7234
7125
|
useEffect12(() => {
|
|
@@ -7359,7 +7250,7 @@ function useShellSnapshot() {
|
|
|
7359
7250
|
}
|
|
7360
7251
|
|
|
7361
7252
|
// src/ui/shell/controller/ShellControllerProvider.tsx
|
|
7362
|
-
import { jsx as
|
|
7253
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
7363
7254
|
var ShellControllerContext = createContext3(null);
|
|
7364
7255
|
var TabStageContext = createContext3(null);
|
|
7365
7256
|
function useShellController() {
|
|
@@ -7391,7 +7282,7 @@ function ShellControllerProvider({
|
|
|
7391
7282
|
useTabTypes();
|
|
7392
7283
|
const { settled: pluginsSettled } = usePluginStore();
|
|
7393
7284
|
const isMobile = useIsMobile();
|
|
7394
|
-
const [stageStore] =
|
|
7285
|
+
const [stageStore] = useState11(createTabStageStore);
|
|
7395
7286
|
const confirmRef = useRef6(null);
|
|
7396
7287
|
const openSingletonRef = useRef6(
|
|
7397
7288
|
() => void 0
|
|
@@ -7402,7 +7293,7 @@ function ShellControllerProvider({
|
|
|
7402
7293
|
});
|
|
7403
7294
|
const regions = useRegions(isMobile);
|
|
7404
7295
|
const hosts = useHostList();
|
|
7405
|
-
const [paletteOpen, setPaletteOpen] =
|
|
7296
|
+
const [paletteOpen, setPaletteOpen] = useState11(false);
|
|
7406
7297
|
const tabsState = useTabs({
|
|
7407
7298
|
hosts: hosts.list,
|
|
7408
7299
|
hostsRef: hosts.listRef,
|
|
@@ -7459,6 +7350,10 @@ function ShellControllerProvider({
|
|
|
7459
7350
|
regions.right.setView((prev) => prev === id ? null : prev);
|
|
7460
7351
|
},
|
|
7461
7352
|
openHostEditor: (draft) => requestManage({ kind: "host", hostId: null, draft }),
|
|
7353
|
+
editHost: (hostId) => {
|
|
7354
|
+
requestManage({ kind: "host", hostId: String(hostId) });
|
|
7355
|
+
if (isMobile) regions.left.setOpen(false);
|
|
7356
|
+
},
|
|
7462
7357
|
saveQuickConnect: tabsState.saveQuickConnectHost,
|
|
7463
7358
|
confirm: (options) => confirmRef.current ? confirmRef.current(options) : Promise.resolve(false)
|
|
7464
7359
|
};
|
|
@@ -7466,7 +7361,7 @@ function ShellControllerProvider({
|
|
|
7466
7361
|
useLayoutEffect2(() => {
|
|
7467
7362
|
shellImplRef.current = shellCallbacksImpl;
|
|
7468
7363
|
});
|
|
7469
|
-
const
|
|
7364
|
+
const callbacks = useMemo5(
|
|
7470
7365
|
() => ({
|
|
7471
7366
|
openTab: (...args) => shellImplRef.current.openTab(...args),
|
|
7472
7367
|
openSingletonTab: (...args) => shellImplRef.current.openSingletonTab(...args),
|
|
@@ -7476,6 +7371,7 @@ function ShellControllerProvider({
|
|
|
7476
7371
|
openRailView: (...args) => shellImplRef.current.openRailView(...args),
|
|
7477
7372
|
closeRailView: (...args) => shellImplRef.current.closeRailView(...args),
|
|
7478
7373
|
openHostEditor: (...args) => shellImplRef.current.openHostEditor?.(...args),
|
|
7374
|
+
editHost: (...args) => shellImplRef.current.editHost?.(...args),
|
|
7479
7375
|
saveQuickConnect: (...args) => shellImplRef.current.saveQuickConnect(...args),
|
|
7480
7376
|
confirm: (...args) => shellImplRef.current.confirm(...args)
|
|
7481
7377
|
}),
|
|
@@ -7483,13 +7379,13 @@ function ShellControllerProvider({
|
|
|
7483
7379
|
);
|
|
7484
7380
|
const panelCallbacks = useMemo5(
|
|
7485
7381
|
() => ({
|
|
7486
|
-
...
|
|
7382
|
+
...callbacks,
|
|
7487
7383
|
openTab: (...args) => {
|
|
7488
|
-
|
|
7384
|
+
callbacks.openTab(...args);
|
|
7489
7385
|
if (isMobile) regions.left.setOpen(false);
|
|
7490
7386
|
}
|
|
7491
7387
|
}),
|
|
7492
|
-
[
|
|
7388
|
+
[callbacks, isMobile]
|
|
7493
7389
|
);
|
|
7494
7390
|
const resizeAllTerminals = useCallback6(() => {
|
|
7495
7391
|
const id = requestAnimationFrame(() => {
|
|
@@ -7506,7 +7402,7 @@ function ShellControllerProvider({
|
|
|
7506
7402
|
tabsState,
|
|
7507
7403
|
isMobile,
|
|
7508
7404
|
paneEls: stageStore.paneEls,
|
|
7509
|
-
callbacks
|
|
7405
|
+
callbacks,
|
|
7510
7406
|
resizeAllTerminals
|
|
7511
7407
|
});
|
|
7512
7408
|
useEffect13(() => {
|
|
@@ -7531,7 +7427,7 @@ function ShellControllerProvider({
|
|
|
7531
7427
|
toggleFullscreen: lifecycle.toggleAppFullscreen
|
|
7532
7428
|
});
|
|
7533
7429
|
useEffect13(() => {
|
|
7534
|
-
setShellCallbacks(
|
|
7430
|
+
setShellCallbacks(callbacks);
|
|
7535
7431
|
});
|
|
7536
7432
|
const activeTab = tabs.find((tab) => tab.id === activeTabId);
|
|
7537
7433
|
const controller = {
|
|
@@ -7580,7 +7476,7 @@ function ShellControllerProvider({
|
|
|
7580
7476
|
active: lifecycle.isAppFullscreen,
|
|
7581
7477
|
toggle: lifecycle.toggleAppFullscreen
|
|
7582
7478
|
},
|
|
7583
|
-
callbacks
|
|
7479
|
+
callbacks,
|
|
7584
7480
|
panelCallbacks,
|
|
7585
7481
|
settings: {
|
|
7586
7482
|
username,
|
|
@@ -7597,7 +7493,7 @@ function ShellControllerProvider({
|
|
|
7597
7493
|
publishShellController(controller);
|
|
7598
7494
|
});
|
|
7599
7495
|
useEffect13(() => () => publishShellController(null), []);
|
|
7600
|
-
return /* @__PURE__ */
|
|
7496
|
+
return /* @__PURE__ */ jsx4(TabStageContext.Provider, { value: stageStore, children: /* @__PURE__ */ jsx4(ShellControllerContext.Provider, { value: controller, children }) });
|
|
7601
7497
|
}
|
|
7602
7498
|
|
|
7603
7499
|
// src/ui/lib/adaptive-polling.ts
|
|
@@ -7706,7 +7602,7 @@ import {
|
|
|
7706
7602
|
useRef as useRef7,
|
|
7707
7603
|
useMemo as useMemo6,
|
|
7708
7604
|
useSyncExternalStore as useSyncExternalStore8,
|
|
7709
|
-
useState as
|
|
7605
|
+
useState as useState12
|
|
7710
7606
|
} from "react";
|
|
7711
7607
|
|
|
7712
7608
|
// src/ui/lib/server-status-store.ts
|
|
@@ -7800,7 +7696,7 @@ var ServerStatusStore = class {
|
|
|
7800
7696
|
};
|
|
7801
7697
|
|
|
7802
7698
|
// src/ui/lib/ServerStatusContext.tsx
|
|
7803
|
-
import { jsx as
|
|
7699
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
7804
7700
|
var StatusStoreContext = createContext4(null);
|
|
7805
7701
|
var ServerStatusContext = createContext4(null);
|
|
7806
7702
|
var activeStore = null;
|
|
@@ -7817,7 +7713,7 @@ function ServerStatusProvider({
|
|
|
7817
7713
|
storeRef.current = new ServerStatusStore();
|
|
7818
7714
|
}
|
|
7819
7715
|
const store = storeRef.current;
|
|
7820
|
-
const [
|
|
7716
|
+
const [version3, setVersion] = useState12(0);
|
|
7821
7717
|
const mountedRef = useRef7(true);
|
|
7822
7718
|
const refreshInFlightRef = useRef7(null);
|
|
7823
7719
|
useEffect14(() => store.subscribeAll(() => setVersion((v) => v + 1)), [store]);
|
|
@@ -7900,9 +7796,9 @@ function ServerStatusProvider({
|
|
|
7900
7796
|
}),
|
|
7901
7797
|
// version refreshes the statuses/initialLoadComplete snapshots
|
|
7902
7798
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
7903
|
-
[
|
|
7799
|
+
[version3, refreshStatuses, getStatus]
|
|
7904
7800
|
);
|
|
7905
|
-
return /* @__PURE__ */
|
|
7801
|
+
return /* @__PURE__ */ jsx5(StatusStoreContext.Provider, { value: store, children: /* @__PURE__ */ jsx5(ServerStatusContext.Provider, { value: contextValue, children }) });
|
|
7906
7802
|
}
|
|
7907
7803
|
function useStatusStore() {
|
|
7908
7804
|
const store = useContext4(StatusStoreContext);
|
|
@@ -7952,7 +7848,7 @@ function useOptionalHostStatusEntry(hostId) {
|
|
|
7952
7848
|
|
|
7953
7849
|
// src/ui/plugin-host/bridge.ts
|
|
7954
7850
|
init_define_import_meta_env();
|
|
7955
|
-
import { useCallback as useCallback8, useEffect as useEffect15, useMemo as useMemo8, useState as
|
|
7851
|
+
import { useCallback as useCallback8, useEffect as useEffect15, useMemo as useMemo8, useState as useState13 } from "react";
|
|
7956
7852
|
|
|
7957
7853
|
// src/ui/shell/companions.ts
|
|
7958
7854
|
init_define_import_meta_env();
|
|
@@ -8272,7 +8168,7 @@ var pluginHostBridge = {
|
|
|
8272
8168
|
},
|
|
8273
8169
|
useSettings(pluginId, scope, hostId) {
|
|
8274
8170
|
const numericHostId = hostId === void 0 ? void 0 : Number.parseInt(String(hostId), 10);
|
|
8275
|
-
const [state2, setState] =
|
|
8171
|
+
const [state2, setState] = useState13({ values: {}, loaded: false });
|
|
8276
8172
|
useEffect15(() => {
|
|
8277
8173
|
let cancelled = false;
|
|
8278
8174
|
if (scope === "host" && !Number.isFinite(numericHostId)) return;
|
|
@@ -8328,7 +8224,7 @@ var pluginHostBridge = {
|
|
|
8328
8224
|
);
|
|
8329
8225
|
},
|
|
8330
8226
|
useCurrentUser() {
|
|
8331
|
-
const [user, setUser] =
|
|
8227
|
+
const [user, setUser] = useState13(null);
|
|
8332
8228
|
useEffect15(() => {
|
|
8333
8229
|
let cancelled = false;
|
|
8334
8230
|
loadCurrentUser().then((next) => {
|
|
@@ -8912,8 +8808,8 @@ function createPluginApp(pluginId, manifest, contributes, options = {}) {
|
|
|
8912
8808
|
},
|
|
8913
8809
|
registerOnboardingStep(step) {
|
|
8914
8810
|
requireStepId(step.id, "onboarding step");
|
|
8915
|
-
const
|
|
8916
|
-
if (!Number.isInteger(
|
|
8811
|
+
const version3 = step.version ?? 1;
|
|
8812
|
+
if (!Number.isInteger(version3) || version3 < 1) {
|
|
8917
8813
|
throw new Error(
|
|
8918
8814
|
`${pluginId}: onboarding step "${step.id}" needs a whole version of 1 or more`
|
|
8919
8815
|
);
|
|
@@ -8923,7 +8819,7 @@ function createPluginApp(pluginId, manifest, contributes, options = {}) {
|
|
|
8923
8819
|
onboardingSteps.register({
|
|
8924
8820
|
id: pluginStepKey(pluginId, step.id),
|
|
8925
8821
|
pluginId,
|
|
8926
|
-
version:
|
|
8822
|
+
version: version3,
|
|
8927
8823
|
titleKey: key(step.titleKey),
|
|
8928
8824
|
descriptionKey: step.descriptionKey ? key(step.descriptionKey) : void 0,
|
|
8929
8825
|
icon: step.icon ? withIconBoundary(pluginId, step.icon) : void 0,
|
|
@@ -9061,918 +8957,6 @@ function createPluginApp(pluginId, manifest, contributes, options = {}) {
|
|
|
9061
8957
|
};
|
|
9062
8958
|
}
|
|
9063
8959
|
|
|
9064
|
-
// src/ui/hooks/use-installed-plugins.ts
|
|
9065
|
-
init_define_import_meta_env();
|
|
9066
|
-
import { useEffect as useEffect17, useState as useState15 } from "react";
|
|
9067
|
-
function useInstalledPlugins() {
|
|
9068
|
-
const [plugins, setPlugins] = useState15([]);
|
|
9069
|
-
useEffect17(() => {
|
|
9070
|
-
let cancelled = false;
|
|
9071
|
-
let request = 0;
|
|
9072
|
-
const load2 = () => {
|
|
9073
|
-
const current2 = ++request;
|
|
9074
|
-
void getPlugins().then((loaded) => {
|
|
9075
|
-
if (!cancelled && current2 === request) setPlugins(loaded);
|
|
9076
|
-
}).catch(() => {
|
|
9077
|
-
});
|
|
9078
|
-
};
|
|
9079
|
-
load2();
|
|
9080
|
-
window.addEventListener(PLUGINS_CHANGED_EVENT, load2);
|
|
9081
|
-
return () => {
|
|
9082
|
-
cancelled = true;
|
|
9083
|
-
window.removeEventListener(PLUGINS_CHANGED_EVENT, load2);
|
|
9084
|
-
};
|
|
9085
|
-
}, []);
|
|
9086
|
-
return plugins;
|
|
9087
|
-
}
|
|
9088
|
-
|
|
9089
|
-
// src/ui/settings/SettingsFields.tsx
|
|
9090
|
-
init_define_import_meta_env();
|
|
9091
|
-
import { useTranslation as useTranslation4 } from "react-i18next";
|
|
9092
|
-
import { Fragment, jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
9093
|
-
function SettingsFieldRow({
|
|
9094
|
-
pluginId,
|
|
9095
|
-
field,
|
|
9096
|
-
values,
|
|
9097
|
-
setValue,
|
|
9098
|
-
running,
|
|
9099
|
-
error,
|
|
9100
|
-
disabled = false,
|
|
9101
|
-
defaultKey
|
|
9102
|
-
}) {
|
|
9103
|
-
const { t } = useTranslation4();
|
|
9104
|
-
useSettingsComponents();
|
|
9105
|
-
const label = (key) => key ? t(pluginKey(pluginId, key)) : "";
|
|
9106
|
-
if (field.type === "custom") {
|
|
9107
|
-
const Component = getSettingsComponent(pluginId, field.component);
|
|
9108
|
-
if (!Component) return null;
|
|
9109
|
-
return /* @__PURE__ */ jsx9(
|
|
9110
|
-
Component,
|
|
9111
|
-
{
|
|
9112
|
-
pluginId,
|
|
9113
|
-
values,
|
|
9114
|
-
setValue,
|
|
9115
|
-
running
|
|
9116
|
-
}
|
|
9117
|
-
);
|
|
9118
|
-
}
|
|
9119
|
-
const value = values[field.key];
|
|
9120
|
-
const readOnly = disabled || !running;
|
|
9121
|
-
const description = field.descriptionKey ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
9122
|
-
label(field.descriptionKey),
|
|
9123
|
-
error && /* @__PURE__ */ jsx9("span", { className: "block text-destructive mt-0.5", children: error })
|
|
9124
|
-
] }) : error ? /* @__PURE__ */ jsx9("span", { className: "text-destructive", children: error }) : void 0;
|
|
9125
|
-
const control = /* @__PURE__ */ jsx9(
|
|
9126
|
-
FieldControl,
|
|
9127
|
-
{
|
|
9128
|
-
pluginId,
|
|
9129
|
-
field,
|
|
9130
|
-
value,
|
|
9131
|
-
setValue,
|
|
9132
|
-
readOnly
|
|
9133
|
-
}
|
|
9134
|
-
);
|
|
9135
|
-
if (field.type === "boolean") {
|
|
9136
|
-
return /* @__PURE__ */ jsx9(
|
|
9137
|
-
SettingRow,
|
|
9138
|
-
{
|
|
9139
|
-
label: label(field.labelKey),
|
|
9140
|
-
description,
|
|
9141
|
-
badge: error ? t("common.error") : void 0,
|
|
9142
|
-
defaultKey,
|
|
9143
|
-
children: control
|
|
9144
|
-
}
|
|
9145
|
-
);
|
|
9146
|
-
}
|
|
9147
|
-
return /* @__PURE__ */ jsx9(DefaultsOnly, { settingKey: defaultKey ?? "", children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-1.5 py-3 border-b border-border last:border-0 min-w-0", children: [
|
|
9148
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
|
|
9149
|
-
/* @__PURE__ */ jsx9("span", { className: "text-sm font-medium leading-snug", children: label(field.labelKey) }),
|
|
9150
|
-
error && /* @__PURE__ */ jsx9("span", { className: "text-[10px] font-bold text-warning border border-warning/40 px-1 shrink-0", children: t("common.error") }),
|
|
9151
|
-
defaultKey && /* @__PURE__ */ jsx9(HostDefaultBadge, { settingKey: defaultKey })
|
|
9152
|
-
] }),
|
|
9153
|
-
description && /* @__PURE__ */ jsx9("span", { className: "text-xs text-muted-foreground leading-snug", children: description }),
|
|
9154
|
-
/* @__PURE__ */ jsx9("div", { className: "min-w-0", children: control })
|
|
9155
|
-
] }) });
|
|
9156
|
-
}
|
|
9157
|
-
function FieldControl({
|
|
9158
|
-
pluginId,
|
|
9159
|
-
field,
|
|
9160
|
-
value,
|
|
9161
|
-
setValue,
|
|
9162
|
-
readOnly
|
|
9163
|
-
}) {
|
|
9164
|
-
const { t } = useTranslation4();
|
|
9165
|
-
const label = (key) => key ? t(pluginKey(pluginId, key)) : "";
|
|
9166
|
-
const placeholder = field.placeholderKey ? label(field.placeholderKey) : void 0;
|
|
9167
|
-
switch (field.type) {
|
|
9168
|
-
case "boolean":
|
|
9169
|
-
return /* @__PURE__ */ jsx9(
|
|
9170
|
-
FakeSwitch,
|
|
9171
|
-
{
|
|
9172
|
-
checked: value === true,
|
|
9173
|
-
disabled: readOnly,
|
|
9174
|
-
onChange: (next) => setValue(field.key, next)
|
|
9175
|
-
}
|
|
9176
|
-
);
|
|
9177
|
-
case "number":
|
|
9178
|
-
return /* @__PURE__ */ jsx9(
|
|
9179
|
-
Input,
|
|
9180
|
-
{
|
|
9181
|
-
type: "number",
|
|
9182
|
-
className: "h-8 w-full max-w-40 text-sm",
|
|
9183
|
-
disabled: readOnly,
|
|
9184
|
-
min: field.min,
|
|
9185
|
-
max: field.max,
|
|
9186
|
-
placeholder,
|
|
9187
|
-
value: value === void 0 || value === null ? "" : String(value),
|
|
9188
|
-
onChange: (event) => setValue(
|
|
9189
|
-
field.key,
|
|
9190
|
-
event.target.value === "" ? null : Number(event.target.value)
|
|
9191
|
-
)
|
|
9192
|
-
}
|
|
9193
|
-
);
|
|
9194
|
-
case "select":
|
|
9195
|
-
return /* @__PURE__ */ jsxs2(
|
|
9196
|
-
Select,
|
|
9197
|
-
{
|
|
9198
|
-
disabled: readOnly,
|
|
9199
|
-
value: typeof value === "string" ? value : "",
|
|
9200
|
-
onValueChange: (next) => setValue(field.key, next),
|
|
9201
|
-
children: [
|
|
9202
|
-
/* @__PURE__ */ jsx9(SelectTrigger, { className: "h-8 w-full min-w-0 text-sm", children: /* @__PURE__ */ jsx9(SelectValue, { placeholder }) }),
|
|
9203
|
-
/* @__PURE__ */ jsx9(SelectContent, { children: (field.options ?? []).map((option) => /* @__PURE__ */ jsx9(SelectItem, { value: option.value, children: label(option.labelKey) }, option.value)) })
|
|
9204
|
-
]
|
|
9205
|
-
}
|
|
9206
|
-
);
|
|
9207
|
-
case "multiselect": {
|
|
9208
|
-
const selected = Array.isArray(value) ? value : [];
|
|
9209
|
-
return /* @__PURE__ */ jsx9("div", { className: "flex flex-col gap-1.5", children: (field.options ?? []).map((option) => /* @__PURE__ */ jsxs2(
|
|
9210
|
-
"label",
|
|
9211
|
-
{
|
|
9212
|
-
className: "flex items-center gap-2 text-xs text-muted-foreground",
|
|
9213
|
-
children: [
|
|
9214
|
-
/* @__PURE__ */ jsx9(
|
|
9215
|
-
Checkbox2,
|
|
9216
|
-
{
|
|
9217
|
-
disabled: readOnly,
|
|
9218
|
-
checked: selected.includes(option.value),
|
|
9219
|
-
onCheckedChange: (checked) => setValue(
|
|
9220
|
-
field.key,
|
|
9221
|
-
checked ? [...selected, option.value] : selected.filter((entry) => entry !== option.value)
|
|
9222
|
-
)
|
|
9223
|
-
}
|
|
9224
|
-
),
|
|
9225
|
-
/* @__PURE__ */ jsx9("span", { children: label(option.labelKey) })
|
|
9226
|
-
]
|
|
9227
|
-
},
|
|
9228
|
-
option.value
|
|
9229
|
-
)) });
|
|
9230
|
-
}
|
|
9231
|
-
case "secret":
|
|
9232
|
-
return /* @__PURE__ */ jsx9(
|
|
9233
|
-
SecretControl,
|
|
9234
|
-
{
|
|
9235
|
-
field,
|
|
9236
|
-
value,
|
|
9237
|
-
setValue,
|
|
9238
|
-
readOnly,
|
|
9239
|
-
placeholder
|
|
9240
|
-
}
|
|
9241
|
-
);
|
|
9242
|
-
case "textarea":
|
|
9243
|
-
case "json":
|
|
9244
|
-
return /* @__PURE__ */ jsx9(
|
|
9245
|
-
Textarea,
|
|
9246
|
-
{
|
|
9247
|
-
className: "w-full text-sm font-mono min-h-16",
|
|
9248
|
-
disabled: readOnly,
|
|
9249
|
-
placeholder,
|
|
9250
|
-
value: typeof value === "string" ? value : value === void 0 || value === null ? "" : JSON.stringify(value, null, 2),
|
|
9251
|
-
onChange: (event) => setValue(field.key, event.target.value)
|
|
9252
|
-
}
|
|
9253
|
-
);
|
|
9254
|
-
default:
|
|
9255
|
-
return /* @__PURE__ */ jsx9(
|
|
9256
|
-
Input,
|
|
9257
|
-
{
|
|
9258
|
-
className: "h-8 w-full text-sm",
|
|
9259
|
-
disabled: readOnly,
|
|
9260
|
-
placeholder,
|
|
9261
|
-
value: typeof value === "string" ? value : "",
|
|
9262
|
-
onChange: (event) => setValue(field.key, event.target.value)
|
|
9263
|
-
}
|
|
9264
|
-
);
|
|
9265
|
-
}
|
|
9266
|
-
}
|
|
9267
|
-
function SecretControl({
|
|
9268
|
-
field,
|
|
9269
|
-
value,
|
|
9270
|
-
setValue,
|
|
9271
|
-
readOnly,
|
|
9272
|
-
placeholder
|
|
9273
|
-
}) {
|
|
9274
|
-
const { t } = useTranslation4();
|
|
9275
|
-
const redacted = isRedactedSecret(value);
|
|
9276
|
-
const stored = redacted && value.set;
|
|
9277
|
-
if (redacted) {
|
|
9278
|
-
return /* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
9279
|
-
/* @__PURE__ */ jsx9("span", { className: "text-xs text-muted-foreground", children: stored ? t("settings.secretSet") : t("settings.secretNotSet") }),
|
|
9280
|
-
/* @__PURE__ */ jsx9(
|
|
9281
|
-
Button,
|
|
9282
|
-
{
|
|
9283
|
-
variant: "outline",
|
|
9284
|
-
size: "sm",
|
|
9285
|
-
className: "h-7 text-xs",
|
|
9286
|
-
disabled: readOnly,
|
|
9287
|
-
onClick: () => setValue(field.key, ""),
|
|
9288
|
-
children: stored ? t("settings.secretReplace") : t("common.edit")
|
|
9289
|
-
}
|
|
9290
|
-
)
|
|
9291
|
-
] });
|
|
9292
|
-
}
|
|
9293
|
-
return /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
9294
|
-
/* @__PURE__ */ jsx9("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx9(
|
|
9295
|
-
PasswordInput,
|
|
9296
|
-
{
|
|
9297
|
-
className: "h-8 w-full text-sm",
|
|
9298
|
-
disabled: readOnly,
|
|
9299
|
-
placeholder,
|
|
9300
|
-
value: typeof value === "string" ? value : "",
|
|
9301
|
-
onChange: (event) => setValue(field.key, event.target.value)
|
|
9302
|
-
}
|
|
9303
|
-
) }),
|
|
9304
|
-
/* @__PURE__ */ jsx9(
|
|
9305
|
-
Button,
|
|
9306
|
-
{
|
|
9307
|
-
variant: "ghost",
|
|
9308
|
-
size: "sm",
|
|
9309
|
-
className: "h-7 text-xs",
|
|
9310
|
-
disabled: readOnly,
|
|
9311
|
-
onClick: () => setValue(field.key, { set: stored }),
|
|
9312
|
-
children: t("common.cancel")
|
|
9313
|
-
}
|
|
9314
|
-
)
|
|
9315
|
-
] });
|
|
9316
|
-
}
|
|
9317
|
-
|
|
9318
|
-
// src/ui/settings/HostPluginSections.tsx
|
|
9319
|
-
init_define_import_meta_env();
|
|
9320
|
-
import { useMemo as useMemo9 } from "react";
|
|
9321
|
-
import { useTranslation as useTranslation5 } from "react-i18next";
|
|
9322
|
-
import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
9323
|
-
function usePluginHostSections() {
|
|
9324
|
-
const plugins = useInstalledPlugins();
|
|
9325
|
-
return useMemo9(
|
|
9326
|
-
() => plugins.filter((plugin) => {
|
|
9327
|
-
if (!plugin.enabled) return false;
|
|
9328
|
-
const host = plugin.contributes?.settings?.host;
|
|
9329
|
-
return !!host && (hasVisibleFields(host.fields) || !!host.enableKey);
|
|
9330
|
-
}),
|
|
9331
|
-
[plugins]
|
|
9332
|
-
);
|
|
9333
|
-
}
|
|
9334
|
-
function hostFieldDefaults(plugin) {
|
|
9335
|
-
const host = plugin.contributes?.settings?.host;
|
|
9336
|
-
if (!host) return {};
|
|
9337
|
-
const defaults3 = {};
|
|
9338
|
-
if (host.enableKey) defaults3[host.enableKey] = host.enableDefault ?? false;
|
|
9339
|
-
for (const field of host.fields) {
|
|
9340
|
-
if (field.default !== void 0) defaults3[field.key] = field.default;
|
|
9341
|
-
}
|
|
9342
|
-
return defaults3;
|
|
9343
|
-
}
|
|
9344
|
-
function HostPluginSections({
|
|
9345
|
-
plugins,
|
|
9346
|
-
values,
|
|
9347
|
-
setValue
|
|
9348
|
-
}) {
|
|
9349
|
-
if (plugins.length === 0) return null;
|
|
9350
|
-
return /* @__PURE__ */ jsx10("div", { className: "flex flex-col gap-2", children: plugins.map((plugin) => /* @__PURE__ */ jsx10(
|
|
9351
|
-
HostPluginSection,
|
|
9352
|
-
{
|
|
9353
|
-
plugin,
|
|
9354
|
-
values: values[plugin.id] ?? {},
|
|
9355
|
-
setValue: (key, value) => setValue(plugin.id, key, value)
|
|
9356
|
-
},
|
|
9357
|
-
plugin.id
|
|
9358
|
-
)) });
|
|
9359
|
-
}
|
|
9360
|
-
function HostFeatureFields({
|
|
9361
|
-
form,
|
|
9362
|
-
updateForm
|
|
9363
|
-
}) {
|
|
9364
|
-
const pluginId = usePluginScope();
|
|
9365
|
-
const plugin = usePluginHostSections().find((p) => p.id === pluginId);
|
|
9366
|
-
if (!plugin) return null;
|
|
9367
|
-
const values = form?.pluginSettings ?? {};
|
|
9368
|
-
return /* @__PURE__ */ jsx10(
|
|
9369
|
-
HostPluginSection,
|
|
9370
|
-
{
|
|
9371
|
-
plugin,
|
|
9372
|
-
values: values[plugin.id] ?? {},
|
|
9373
|
-
setValue: (key, value) => updateForm((current2) => {
|
|
9374
|
-
const all = current2.pluginSettings ?? {};
|
|
9375
|
-
return {
|
|
9376
|
-
...current2,
|
|
9377
|
-
pluginSettings: {
|
|
9378
|
-
...all,
|
|
9379
|
-
[plugin.id]: { ...all[plugin.id] ?? {}, [key]: value }
|
|
9380
|
-
}
|
|
9381
|
-
};
|
|
9382
|
-
})
|
|
9383
|
-
}
|
|
9384
|
-
);
|
|
9385
|
-
}
|
|
9386
|
-
function HostPluginSection({
|
|
9387
|
-
plugin,
|
|
9388
|
-
values,
|
|
9389
|
-
setValue
|
|
9390
|
-
}) {
|
|
9391
|
-
const { t } = useTranslation5();
|
|
9392
|
-
const host = plugin.contributes?.settings?.host;
|
|
9393
|
-
if (!host) return null;
|
|
9394
|
-
const shown = { ...hostFieldDefaults(plugin), ...values };
|
|
9395
|
-
const running = plugin.enabled && plugin.state !== "failed";
|
|
9396
|
-
const enableKey = host.enableKey;
|
|
9397
|
-
const enabled = enableKey ? shown[enableKey] === true : true;
|
|
9398
|
-
return /* @__PURE__ */ jsxs3(
|
|
9399
|
-
SectionCard,
|
|
9400
|
-
{
|
|
9401
|
-
title: pluginName(t, plugin),
|
|
9402
|
-
icon: /* @__PURE__ */ jsx10(PluginIcon, { name: plugin.icon, className: "size-3.5" }),
|
|
9403
|
-
action: /* @__PURE__ */ jsx10(DocsLink, { href: plugin.docs }),
|
|
9404
|
-
children: [
|
|
9405
|
-
!running && /* @__PURE__ */ jsx10("div", { className: "my-3 border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-warning", children: t("settings.featureUnavailable", {
|
|
9406
|
-
name: pluginName(t, plugin)
|
|
9407
|
-
}) }),
|
|
9408
|
-
enableKey && /* @__PURE__ */ jsx10(
|
|
9409
|
-
SettingsFieldRow,
|
|
9410
|
-
{
|
|
9411
|
-
pluginId: plugin.id,
|
|
9412
|
-
field: {
|
|
9413
|
-
key: enableKey,
|
|
9414
|
-
type: "boolean",
|
|
9415
|
-
labelKey: host.enableLabelKey,
|
|
9416
|
-
descriptionKey: host.enableDescriptionKey
|
|
9417
|
-
},
|
|
9418
|
-
values: shown,
|
|
9419
|
-
setValue,
|
|
9420
|
-
running,
|
|
9421
|
-
defaultKey: `${plugin.id}.${enableKey}`
|
|
9422
|
-
}
|
|
9423
|
-
),
|
|
9424
|
-
enabled && host.fields.filter((field) => isFieldShown(field, shown)).map((field) => /* @__PURE__ */ jsx10(
|
|
9425
|
-
SettingsFieldRow,
|
|
9426
|
-
{
|
|
9427
|
-
pluginId: plugin.id,
|
|
9428
|
-
field,
|
|
9429
|
-
values: shown,
|
|
9430
|
-
setValue,
|
|
9431
|
-
running,
|
|
9432
|
-
defaultKey: `${plugin.id}.${field.key}`
|
|
9433
|
-
},
|
|
9434
|
-
field.key
|
|
9435
|
-
))
|
|
9436
|
-
]
|
|
9437
|
-
}
|
|
9438
|
-
);
|
|
9439
|
-
}
|
|
9440
|
-
|
|
9441
|
-
// src/ui/shell/ActionSlot.tsx
|
|
9442
|
-
init_define_import_meta_env();
|
|
9443
|
-
import React5 from "react";
|
|
9444
|
-
import { useTranslation as useTranslation6 } from "react-i18next";
|
|
9445
|
-
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
9446
|
-
function ActionSlot({
|
|
9447
|
-
slotId,
|
|
9448
|
-
context,
|
|
9449
|
-
className,
|
|
9450
|
-
enabled = true,
|
|
9451
|
-
renderItem,
|
|
9452
|
-
hideLabels,
|
|
9453
|
-
when
|
|
9454
|
-
}) {
|
|
9455
|
-
const { t } = useTranslation6();
|
|
9456
|
-
const contributions2 = useActionSlot(slotId, when).filter(
|
|
9457
|
-
(contribution) => contribution.kind !== "component"
|
|
9458
|
-
);
|
|
9459
|
-
if (!enabled || contributions2.length === 0) return null;
|
|
9460
|
-
return /* @__PURE__ */ jsx11(Fragment2, { children: contributions2.map((contribution) => {
|
|
9461
|
-
const invoke = () => {
|
|
9462
|
-
void invokeAction(contribution.actionId, ...context?.() ?? []);
|
|
9463
|
-
};
|
|
9464
|
-
if (renderItem) {
|
|
9465
|
-
return /* @__PURE__ */ jsx11(React5.Fragment, { children: renderItem(contribution, invoke) }, contribution.actionId);
|
|
9466
|
-
}
|
|
9467
|
-
const Icon = contribution.icon;
|
|
9468
|
-
const label = t(contribution.titleKey);
|
|
9469
|
-
return /* @__PURE__ */ jsxs4(
|
|
9470
|
-
"button",
|
|
9471
|
-
{
|
|
9472
|
-
type: "button",
|
|
9473
|
-
className,
|
|
9474
|
-
"aria-label": label,
|
|
9475
|
-
title: label,
|
|
9476
|
-
onClick: invoke,
|
|
9477
|
-
children: [
|
|
9478
|
-
Icon && /* @__PURE__ */ jsx11(Icon, { className: "size-4 shrink-0" }),
|
|
9479
|
-
!hideLabels && label
|
|
9480
|
-
]
|
|
9481
|
-
},
|
|
9482
|
-
contribution.actionId
|
|
9483
|
-
);
|
|
9484
|
-
}) });
|
|
9485
|
-
}
|
|
9486
|
-
function ComponentSlot({
|
|
9487
|
-
slotId,
|
|
9488
|
-
props,
|
|
9489
|
-
when
|
|
9490
|
-
}) {
|
|
9491
|
-
const contributions2 = useActionSlot(slotId, when).filter(
|
|
9492
|
-
(contribution) => contribution.kind === "component" && contribution.component
|
|
9493
|
-
);
|
|
9494
|
-
if (contributions2.length === 0) return null;
|
|
9495
|
-
return /* @__PURE__ */ jsx11(Fragment2, { children: contributions2.map((contribution) => {
|
|
9496
|
-
const Contributed = contribution.component;
|
|
9497
|
-
return /* @__PURE__ */ jsx11(Contributed, { ...props ?? {} }, contribution.actionId);
|
|
9498
|
-
}) });
|
|
9499
|
-
}
|
|
9500
|
-
|
|
9501
|
-
// src/ui/shell/tab-handles.ts
|
|
9502
|
-
init_define_import_meta_env();
|
|
9503
|
-
import { useSyncExternalStore as useSyncExternalStore11 } from "react";
|
|
9504
|
-
var version3 = 0;
|
|
9505
|
-
var listeners8 = /* @__PURE__ */ new Set();
|
|
9506
|
-
var callbacks = /* @__PURE__ */ new WeakMap();
|
|
9507
|
-
function subscribe5(listener) {
|
|
9508
|
-
listeners8.add(listener);
|
|
9509
|
-
return () => listeners8.delete(listener);
|
|
9510
|
-
}
|
|
9511
|
-
function trackTabHandle(ref) {
|
|
9512
|
-
if (!ref) return void 0;
|
|
9513
|
-
let callback = callbacks.get(ref);
|
|
9514
|
-
if (!callback) {
|
|
9515
|
-
callback = (value) => {
|
|
9516
|
-
if (ref.current === value) return;
|
|
9517
|
-
ref.current = value;
|
|
9518
|
-
version3 += 1;
|
|
9519
|
-
for (const listener of listeners8) listener();
|
|
9520
|
-
};
|
|
9521
|
-
callbacks.set(ref, callback);
|
|
9522
|
-
}
|
|
9523
|
-
return callback;
|
|
9524
|
-
}
|
|
9525
|
-
function useTabHandlesVersion() {
|
|
9526
|
-
return useSyncExternalStore11(
|
|
9527
|
-
subscribe5,
|
|
9528
|
-
() => version3,
|
|
9529
|
-
() => version3
|
|
9530
|
-
);
|
|
9531
|
-
}
|
|
9532
|
-
|
|
9533
|
-
// src/ui/plugin-host/PluginViewPlaceholder.tsx
|
|
9534
|
-
init_define_import_meta_env();
|
|
9535
|
-
import { useTranslation as useTranslation7 } from "react-i18next";
|
|
9536
|
-
import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
9537
|
-
function PluginViewPlaceholder({
|
|
9538
|
-
kind,
|
|
9539
|
-
viewId,
|
|
9540
|
-
compact = false
|
|
9541
|
-
}) {
|
|
9542
|
-
const { t } = useTranslation7();
|
|
9543
|
-
usePluginStore();
|
|
9544
|
-
const { has } = usePermissions();
|
|
9545
|
-
const { status, owner } = unregisteredViewStatus(kind, viewId);
|
|
9546
|
-
const name = owner ? pluginName(t, owner.summary) : viewId;
|
|
9547
|
-
if (status === "loading") {
|
|
9548
|
-
return /* @__PURE__ */ jsx12(
|
|
9549
|
-
"div",
|
|
9550
|
-
{
|
|
9551
|
-
className: "flex h-full w-full items-center justify-center",
|
|
9552
|
-
"aria-label": t("plugins.runtime.loading", { name }),
|
|
9553
|
-
children: /* @__PURE__ */ jsx12("div", { className: "size-5 rounded-full border-2 border-muted-foreground/30 border-t-muted-foreground/70 animate-spin" })
|
|
9554
|
-
}
|
|
9555
|
-
);
|
|
9556
|
-
}
|
|
9557
|
-
const title = status === "failed" ? t("plugins.runtime.failed", { name }) : owner ? t("plugins.runtime.needsPlugin", { name }) : t("plugins.runtime.needsUnknownPlugin");
|
|
9558
|
-
const hint = status === "failed" ? t("plugins.runtime.failedHint") : status === "disabled" ? t("plugins.runtime.disabledHint") : t("plugins.runtime.missingHint");
|
|
9559
|
-
return /* @__PURE__ */ jsxs5(
|
|
9560
|
-
"div",
|
|
9561
|
-
{
|
|
9562
|
-
"data-testid": "plugin-view-placeholder",
|
|
9563
|
-
"data-status": status,
|
|
9564
|
-
className: `flex h-full w-full flex-col items-center justify-center gap-2 text-center ${compact ? "p-3" : "p-6"}`,
|
|
9565
|
-
children: [
|
|
9566
|
-
/* @__PURE__ */ jsx12(CircleSlash, { className: "size-6 text-muted-foreground/40" }),
|
|
9567
|
-
/* @__PURE__ */ jsx12("span", { className: "text-sm font-semibold text-muted-foreground", children: title }),
|
|
9568
|
-
/* @__PURE__ */ jsx12("span", { className: "text-xs text-muted-foreground/70", children: hint }),
|
|
9569
|
-
!compact && status !== "failed" && has("admin.plugins.manage") && /* @__PURE__ */ jsx12(
|
|
9570
|
-
Button,
|
|
9571
|
-
{
|
|
9572
|
-
variant: "outline",
|
|
9573
|
-
size: "sm",
|
|
9574
|
-
className: "mt-1",
|
|
9575
|
-
onClick: () => window.dispatchEvent(new CustomEvent(OPEN_PLUGINS_EVENT)),
|
|
9576
|
-
children: t("plugins.manager.browsePlugins")
|
|
9577
|
-
}
|
|
9578
|
-
)
|
|
9579
|
-
]
|
|
9580
|
-
}
|
|
9581
|
-
);
|
|
9582
|
-
}
|
|
9583
|
-
|
|
9584
|
-
// src/ui/lib/adaptive-resource-budget.ts
|
|
9585
|
-
init_define_import_meta_env();
|
|
9586
|
-
|
|
9587
|
-
// src/ui/lib/local-adaptive-engine.ts
|
|
9588
|
-
init_define_import_meta_env();
|
|
9589
|
-
var LOCAL_ADAPTIVE_ENGINE_KEY = "termix.local.adaptive-engine.v1";
|
|
9590
|
-
var VERSION = 1;
|
|
9591
|
-
var HALF_LIFE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
9592
|
-
var MAX_SCOPES = 128;
|
|
9593
|
-
var MAX_ACTIONS_PER_SCOPE = 12;
|
|
9594
|
-
var DEFAULT_MIN_EVIDENCE = 2.5;
|
|
9595
|
-
var DEFAULT_MIN_SHARE = 0.6;
|
|
9596
|
-
var DEFAULT_MIN_MARGIN = 1;
|
|
9597
|
-
var EWMA_ALPHA = 0.25;
|
|
9598
|
-
function emptyStore() {
|
|
9599
|
-
return { version: VERSION, scopes: {} };
|
|
9600
|
-
}
|
|
9601
|
-
function finiteNonNegative(value) {
|
|
9602
|
-
return Number.isFinite(value) && Number(value) >= 0 ? Number(value) : 0;
|
|
9603
|
-
}
|
|
9604
|
-
function sanitizeAction(value) {
|
|
9605
|
-
if (!value || typeof value !== "object") return null;
|
|
9606
|
-
const stat = value;
|
|
9607
|
-
if (!Number.isFinite(stat.weight) || Number(stat.weight) < 0 || !Number.isFinite(stat.updatedAt)) {
|
|
9608
|
-
return null;
|
|
9609
|
-
}
|
|
9610
|
-
const latencyEwmaMs = finiteNonNegative(stat.latencyEwmaMs);
|
|
9611
|
-
return {
|
|
9612
|
-
weight: Number(stat.weight),
|
|
9613
|
-
updatedAt: Number(stat.updatedAt),
|
|
9614
|
-
observations: finiteNonNegative(stat.observations),
|
|
9615
|
-
successes: finiteNonNegative(stat.successes),
|
|
9616
|
-
cancellations: finiteNonNegative(stat.cancellations),
|
|
9617
|
-
fallbacks: finiteNonNegative(stat.fallbacks),
|
|
9618
|
-
...latencyEwmaMs > 0 ? { latencyEwmaMs } : {}
|
|
9619
|
-
};
|
|
9620
|
-
}
|
|
9621
|
-
function sanitizeStore(value) {
|
|
9622
|
-
if (!value || typeof value !== "object") return emptyStore();
|
|
9623
|
-
const candidate = value;
|
|
9624
|
-
if (candidate.version !== VERSION || !candidate.scopes || typeof candidate.scopes !== "object" || Array.isArray(candidate.scopes)) {
|
|
9625
|
-
return emptyStore();
|
|
9626
|
-
}
|
|
9627
|
-
const scopes2 = {};
|
|
9628
|
-
for (const [scope, rawScope] of Object.entries(candidate.scopes)) {
|
|
9629
|
-
if (!rawScope || typeof rawScope !== "object") continue;
|
|
9630
|
-
const value2 = rawScope;
|
|
9631
|
-
if (!Number.isFinite(value2.updatedAt) || !value2.actions || typeof value2.actions !== "object" || Array.isArray(value2.actions)) {
|
|
9632
|
-
continue;
|
|
9633
|
-
}
|
|
9634
|
-
const actions4 = {};
|
|
9635
|
-
for (const [action, rawStat] of Object.entries(value2.actions)) {
|
|
9636
|
-
const stat = sanitizeAction(rawStat);
|
|
9637
|
-
if (stat) actions4[action] = stat;
|
|
9638
|
-
}
|
|
9639
|
-
scopes2[scope] = { actions: actions4, updatedAt: Number(value2.updatedAt) };
|
|
9640
|
-
}
|
|
9641
|
-
return { version: VERSION, scopes: scopes2 };
|
|
9642
|
-
}
|
|
9643
|
-
function readStore() {
|
|
9644
|
-
if (typeof localStorage === "undefined") return emptyStore();
|
|
9645
|
-
try {
|
|
9646
|
-
return sanitizeStore(
|
|
9647
|
-
JSON.parse(localStorage.getItem(LOCAL_ADAPTIVE_ENGINE_KEY) ?? "null")
|
|
9648
|
-
);
|
|
9649
|
-
} catch {
|
|
9650
|
-
return emptyStore();
|
|
9651
|
-
}
|
|
9652
|
-
}
|
|
9653
|
-
function writeStore(store) {
|
|
9654
|
-
if (typeof localStorage === "undefined") return;
|
|
9655
|
-
try {
|
|
9656
|
-
localStorage.setItem(LOCAL_ADAPTIVE_ENGINE_KEY, JSON.stringify(store));
|
|
9657
|
-
} catch {
|
|
9658
|
-
}
|
|
9659
|
-
}
|
|
9660
|
-
function decayedWeight(stat, now) {
|
|
9661
|
-
const age = Math.max(0, now - stat.updatedAt);
|
|
9662
|
-
return stat.weight * 2 ** (-age / HALF_LIFE_MS);
|
|
9663
|
-
}
|
|
9664
|
-
function trimStore(store, now) {
|
|
9665
|
-
for (const scope of Object.values(store.scopes)) {
|
|
9666
|
-
scope.actions = Object.fromEntries(
|
|
9667
|
-
Object.entries(scope.actions).sort(
|
|
9668
|
-
([, a], [, b]) => decayedWeight(b, now) - decayedWeight(a, now) || b.updatedAt - a.updatedAt
|
|
9669
|
-
).slice(0, MAX_ACTIONS_PER_SCOPE)
|
|
9670
|
-
);
|
|
9671
|
-
}
|
|
9672
|
-
store.scopes = Object.fromEntries(
|
|
9673
|
-
Object.entries(store.scopes).sort(([, a], [, b]) => b.updatedAt - a.updatedAt).slice(0, MAX_SCOPES)
|
|
9674
|
-
);
|
|
9675
|
-
}
|
|
9676
|
-
function updateEwma(previous, value) {
|
|
9677
|
-
return previous === void 0 ? value : previous + EWMA_ALPHA * (value - previous);
|
|
9678
|
-
}
|
|
9679
|
-
function getActionStats(store, scope, action, now) {
|
|
9680
|
-
const scopeStats = store.scopes[scope] ?? { actions: {}, updatedAt: now };
|
|
9681
|
-
return [
|
|
9682
|
-
scopeStats,
|
|
9683
|
-
scopeStats.actions[action] ?? {
|
|
9684
|
-
weight: 0,
|
|
9685
|
-
updatedAt: now,
|
|
9686
|
-
observations: 0,
|
|
9687
|
-
successes: 0,
|
|
9688
|
-
cancellations: 0,
|
|
9689
|
-
fallbacks: 0
|
|
9690
|
-
}
|
|
9691
|
-
];
|
|
9692
|
-
}
|
|
9693
|
-
function saveActionStats(store, scope, action, scopeStats, actionStats, now) {
|
|
9694
|
-
scopeStats.actions[action] = actionStats;
|
|
9695
|
-
scopeStats.updatedAt = now;
|
|
9696
|
-
store.scopes[scope] = scopeStats;
|
|
9697
|
-
trimStore(store, now);
|
|
9698
|
-
writeStore(store);
|
|
9699
|
-
}
|
|
9700
|
-
function recordLocalAdaptiveChoice(scope, action, now = Date.now()) {
|
|
9701
|
-
if (!scope || !action) return;
|
|
9702
|
-
const store = readStore();
|
|
9703
|
-
const [scopeStats, previous] = getActionStats(store, scope, action, now);
|
|
9704
|
-
saveActionStats(
|
|
9705
|
-
store,
|
|
9706
|
-
scope,
|
|
9707
|
-
action,
|
|
9708
|
-
scopeStats,
|
|
9709
|
-
{
|
|
9710
|
-
...previous,
|
|
9711
|
-
weight: decayedWeight(previous, now) + 1,
|
|
9712
|
-
updatedAt: now
|
|
9713
|
-
},
|
|
9714
|
-
now
|
|
9715
|
-
);
|
|
9716
|
-
}
|
|
9717
|
-
function recordLocalAdaptiveOutcome(scope, action, outcome, now = Date.now()) {
|
|
9718
|
-
if (!scope || !action || !Object.values(outcome).some((v) => v !== void 0)) {
|
|
9719
|
-
return;
|
|
9720
|
-
}
|
|
9721
|
-
const store = readStore();
|
|
9722
|
-
const [scopeStats, previous] = getActionStats(store, scope, action, now);
|
|
9723
|
-
const latency = finiteNonNegative(outcome.latencyMs);
|
|
9724
|
-
saveActionStats(
|
|
9725
|
-
store,
|
|
9726
|
-
scope,
|
|
9727
|
-
action,
|
|
9728
|
-
scopeStats,
|
|
9729
|
-
{
|
|
9730
|
-
...previous,
|
|
9731
|
-
updatedAt: now,
|
|
9732
|
-
observations: previous.observations + 1,
|
|
9733
|
-
successes: previous.successes + (outcome.success === true ? 1 : 0),
|
|
9734
|
-
cancellations: previous.cancellations + (outcome.cancelled === true ? 1 : 0),
|
|
9735
|
-
fallbacks: previous.fallbacks + (outcome.fallback === true ? 1 : 0),
|
|
9736
|
-
...latency > 0 ? { latencyEwmaMs: updateEwma(previous.latencyEwmaMs, latency) } : {}
|
|
9737
|
-
},
|
|
9738
|
-
now
|
|
9739
|
-
);
|
|
9740
|
-
}
|
|
9741
|
-
function chooseLocalAdaptiveAction({
|
|
9742
|
-
scope,
|
|
9743
|
-
candidates,
|
|
9744
|
-
fallback,
|
|
9745
|
-
now = Date.now(),
|
|
9746
|
-
ttlMs = 5 * 60 * 1e3,
|
|
9747
|
-
minEvidence = DEFAULT_MIN_EVIDENCE,
|
|
9748
|
-
minShare = DEFAULT_MIN_SHARE,
|
|
9749
|
-
minMargin = DEFAULT_MIN_MARGIN
|
|
9750
|
-
}) {
|
|
9751
|
-
const expiresAt = now + Math.max(0, ttlMs);
|
|
9752
|
-
const stats = readStore().scopes[scope]?.actions;
|
|
9753
|
-
if (!stats || candidates.length === 0) {
|
|
9754
|
-
return { action: fallback, confidence: 0, reason: "fallback", expiresAt };
|
|
9755
|
-
}
|
|
9756
|
-
const ranked = candidates.map((action) => ({
|
|
9757
|
-
action,
|
|
9758
|
-
weight: stats[action] ? decayedWeight(stats[action], now) : 0
|
|
9759
|
-
})).sort((a, b) => b.weight - a.weight);
|
|
9760
|
-
const total = ranked.reduce((sum, item) => sum + item.weight, 0);
|
|
9761
|
-
const [best, second] = ranked;
|
|
9762
|
-
if (!best || total <= 0) {
|
|
9763
|
-
return { action: fallback, confidence: 0, reason: "fallback", expiresAt };
|
|
9764
|
-
}
|
|
9765
|
-
const share = best.weight / total;
|
|
9766
|
-
const margin = best.weight - (second?.weight ?? 0);
|
|
9767
|
-
const confidence = Math.min(
|
|
9768
|
-
1,
|
|
9769
|
-
best.weight / Math.max(minEvidence, Number.EPSILON),
|
|
9770
|
-
share / Math.max(minShare, Number.EPSILON),
|
|
9771
|
-
margin / Math.max(minMargin, Number.EPSILON)
|
|
9772
|
-
);
|
|
9773
|
-
const learned = best.weight >= minEvidence && share >= minShare && margin >= minMargin;
|
|
9774
|
-
return {
|
|
9775
|
-
action: learned ? best.action : fallback,
|
|
9776
|
-
confidence,
|
|
9777
|
-
reason: learned ? "learned" : "insufficient-evidence",
|
|
9778
|
-
expiresAt
|
|
9779
|
-
};
|
|
9780
|
-
}
|
|
9781
|
-
function getLocalAdaptiveStats(scope) {
|
|
9782
|
-
return readStore().scopes[scope]?.actions ?? {};
|
|
9783
|
-
}
|
|
9784
|
-
function clearLocalAdaptiveEngine() {
|
|
9785
|
-
if (typeof localStorage === "undefined") return;
|
|
9786
|
-
try {
|
|
9787
|
-
localStorage.removeItem(LOCAL_ADAPTIVE_ENGINE_KEY);
|
|
9788
|
-
} catch {
|
|
9789
|
-
}
|
|
9790
|
-
}
|
|
9791
|
-
|
|
9792
|
-
// src/ui/lib/adaptive-resource-budget.ts
|
|
9793
|
-
var scopes = {
|
|
9794
|
-
module: "resource-budget:module",
|
|
9795
|
-
network: "resource-budget:network"
|
|
9796
|
-
};
|
|
9797
|
-
var usefulnessScopes = {
|
|
9798
|
-
module: "resource-usefulness:module",
|
|
9799
|
-
network: "resource-usefulness:network"
|
|
9800
|
-
};
|
|
9801
|
-
var PRELOAD_USE_WINDOW_MS = 1e4;
|
|
9802
|
-
var pendingPreloads = /* @__PURE__ */ new Map();
|
|
9803
|
-
var activeTasks = {
|
|
9804
|
-
module: 0,
|
|
9805
|
-
network: 0
|
|
9806
|
-
};
|
|
9807
|
-
var budgets = {
|
|
9808
|
-
paused: {
|
|
9809
|
-
tier: "paused",
|
|
9810
|
-
allowModulePreload: false,
|
|
9811
|
-
allowNetworkPrefetch: false,
|
|
9812
|
-
maxPrefetchBytes: 0,
|
|
9813
|
-
maxConcurrentModulePreloads: 0,
|
|
9814
|
-
maxConcurrentNetworkPrefetches: 0,
|
|
9815
|
-
reason: "hidden"
|
|
9816
|
-
},
|
|
9817
|
-
constrained: {
|
|
9818
|
-
tier: "constrained",
|
|
9819
|
-
allowModulePreload: false,
|
|
9820
|
-
allowNetworkPrefetch: false,
|
|
9821
|
-
maxPrefetchBytes: 0,
|
|
9822
|
-
maxConcurrentModulePreloads: 0,
|
|
9823
|
-
maxConcurrentNetworkPrefetches: 0,
|
|
9824
|
-
reason: "environment"
|
|
9825
|
-
},
|
|
9826
|
-
balanced: {
|
|
9827
|
-
tier: "balanced",
|
|
9828
|
-
allowModulePreload: true,
|
|
9829
|
-
allowNetworkPrefetch: true,
|
|
9830
|
-
maxPrefetchBytes: 128 * 1024,
|
|
9831
|
-
maxConcurrentModulePreloads: 1,
|
|
9832
|
-
maxConcurrentNetworkPrefetches: 1,
|
|
9833
|
-
reason: "environment"
|
|
9834
|
-
},
|
|
9835
|
-
eager: {
|
|
9836
|
-
tier: "eager",
|
|
9837
|
-
allowModulePreload: true,
|
|
9838
|
-
allowNetworkPrefetch: true,
|
|
9839
|
-
maxPrefetchBytes: 512 * 1024,
|
|
9840
|
-
maxConcurrentModulePreloads: 2,
|
|
9841
|
-
maxConcurrentNetworkPrefetches: 2,
|
|
9842
|
-
reason: "default"
|
|
9843
|
-
}
|
|
9844
|
-
};
|
|
9845
|
-
function withReason(tier, reason) {
|
|
9846
|
-
return { ...budgets[tier], reason };
|
|
9847
|
-
}
|
|
9848
|
-
function feedbackIsPoor(feedback) {
|
|
9849
|
-
if (!feedback || feedback.observations < 4) return false;
|
|
9850
|
-
const failureRate = 1 - feedback.successes / feedback.observations;
|
|
9851
|
-
const abandoned = feedback.cancellations + feedback.fallbacks;
|
|
9852
|
-
return failureRate > 0.25 || abandoned / feedback.observations > 0.25 || (feedback.latencyEwmaMs ?? 0) > 2e3 || (feedback.usefulnessObservations ?? 0) >= 4 && (feedback.usefulPreloads ?? 0) / (feedback.usefulnessObservations ?? 1) < 0.25;
|
|
9853
|
-
}
|
|
9854
|
-
function preloadKey(kind, action) {
|
|
9855
|
-
return `${kind}:${action}`;
|
|
9856
|
-
}
|
|
9857
|
-
function flushExpiredPreloads(now = Date.now()) {
|
|
9858
|
-
for (const [key, preload] of pendingPreloads) {
|
|
9859
|
-
if (preload.expiresAt > now) continue;
|
|
9860
|
-
recordLocalAdaptiveOutcome(usefulnessScopes[preload.kind], preload.action, {
|
|
9861
|
-
success: false
|
|
9862
|
-
});
|
|
9863
|
-
pendingPreloads.delete(key);
|
|
9864
|
-
}
|
|
9865
|
-
}
|
|
9866
|
-
function markAdaptiveResourceUsed(kind, action, now = Date.now()) {
|
|
9867
|
-
flushExpiredPreloads(now);
|
|
9868
|
-
const key = preloadKey(kind, action);
|
|
9869
|
-
if (!pendingPreloads.has(key)) return;
|
|
9870
|
-
pendingPreloads.delete(key);
|
|
9871
|
-
recordLocalAdaptiveOutcome(
|
|
9872
|
-
usefulnessScopes[kind],
|
|
9873
|
-
action,
|
|
9874
|
-
{ success: true },
|
|
9875
|
-
now
|
|
9876
|
-
);
|
|
9877
|
-
}
|
|
9878
|
-
function computeAdaptiveResourceBudget(environment, feedback) {
|
|
9879
|
-
if (!environment.visible) return withReason("paused", "hidden");
|
|
9880
|
-
if (environment.saveData || ["slow-2g", "2g", "3g"].includes(environment.effectiveType ?? "")) {
|
|
9881
|
-
return withReason("constrained", "environment");
|
|
9882
|
-
}
|
|
9883
|
-
const limitedDevice = (environment.deviceMemoryGb ?? 8) <= 4 || (environment.hardwareConcurrency ?? 8) <= 4;
|
|
9884
|
-
const baseline = limitedDevice ? "balanced" : "eager";
|
|
9885
|
-
if (!feedbackIsPoor(feedback)) {
|
|
9886
|
-
return withReason(baseline, limitedDevice ? "environment" : "default");
|
|
9887
|
-
}
|
|
9888
|
-
return withReason(
|
|
9889
|
-
baseline === "eager" ? "balanced" : "constrained",
|
|
9890
|
-
"feedback"
|
|
9891
|
-
);
|
|
9892
|
-
}
|
|
9893
|
-
function readEnvironment() {
|
|
9894
|
-
const navigatorLike = typeof navigator === "undefined" ? void 0 : navigator;
|
|
9895
|
-
return {
|
|
9896
|
-
visible: typeof document === "undefined" || document.visibilityState !== "hidden",
|
|
9897
|
-
saveData: navigatorLike?.connection?.saveData,
|
|
9898
|
-
effectiveType: navigatorLike?.connection?.effectiveType,
|
|
9899
|
-
deviceMemoryGb: navigatorLike?.deviceMemory,
|
|
9900
|
-
hardwareConcurrency: navigatorLike?.hardwareConcurrency
|
|
9901
|
-
};
|
|
9902
|
-
}
|
|
9903
|
-
function readFeedback(kind) {
|
|
9904
|
-
flushExpiredPreloads();
|
|
9905
|
-
const stats = Object.values(getLocalAdaptiveStats(scopes[kind]));
|
|
9906
|
-
const usefulness = Object.values(
|
|
9907
|
-
getLocalAdaptiveStats(usefulnessScopes[kind])
|
|
9908
|
-
);
|
|
9909
|
-
const observations = stats.reduce((sum, stat) => sum + stat.observations, 0);
|
|
9910
|
-
const latencySamples = stats.filter(
|
|
9911
|
-
(stat) => stat.latencyEwmaMs !== void 0 && stat.observations > 0
|
|
9912
|
-
);
|
|
9913
|
-
const latencyWeight = latencySamples.reduce(
|
|
9914
|
-
(sum, stat) => sum + stat.observations,
|
|
9915
|
-
0
|
|
9916
|
-
);
|
|
9917
|
-
return {
|
|
9918
|
-
observations,
|
|
9919
|
-
successes: stats.reduce((sum, stat) => sum + stat.successes, 0),
|
|
9920
|
-
cancellations: stats.reduce((sum, stat) => sum + stat.cancellations, 0),
|
|
9921
|
-
fallbacks: stats.reduce((sum, stat) => sum + stat.fallbacks, 0),
|
|
9922
|
-
usefulnessObservations: usefulness.reduce(
|
|
9923
|
-
(sum, stat) => sum + stat.observations,
|
|
9924
|
-
0
|
|
9925
|
-
),
|
|
9926
|
-
usefulPreloads: usefulness.reduce((sum, stat) => sum + stat.successes, 0),
|
|
9927
|
-
...latencyWeight > 0 ? {
|
|
9928
|
-
latencyEwmaMs: latencySamples.reduce(
|
|
9929
|
-
(sum, stat) => sum + (stat.latencyEwmaMs ?? 0) * stat.observations,
|
|
9930
|
-
0
|
|
9931
|
-
) / latencyWeight
|
|
9932
|
-
} : {}
|
|
9933
|
-
};
|
|
9934
|
-
}
|
|
9935
|
-
function getAdaptiveResourceBudget(kind) {
|
|
9936
|
-
return computeAdaptiveResourceBudget(readEnvironment(), readFeedback(kind));
|
|
9937
|
-
}
|
|
9938
|
-
function runAdaptiveBackgroundTask(kind, action, task, options = {}) {
|
|
9939
|
-
const budget = getAdaptiveResourceBudget(kind);
|
|
9940
|
-
const allowed = kind === "module" ? budget.allowModulePreload : budget.allowNetworkPrefetch && (options.estimatedBytes === void 0 || options.estimatedBytes <= budget.maxPrefetchBytes);
|
|
9941
|
-
const concurrency = kind === "module" ? budget.maxConcurrentModulePreloads : budget.maxConcurrentNetworkPrefetches;
|
|
9942
|
-
if (!allowed || activeTasks[kind] >= concurrency) return false;
|
|
9943
|
-
activeTasks[kind] += 1;
|
|
9944
|
-
const key = preloadKey(kind, action);
|
|
9945
|
-
pendingPreloads.set(key, {
|
|
9946
|
-
kind,
|
|
9947
|
-
action,
|
|
9948
|
-
expiresAt: Date.now() + PRELOAD_USE_WINDOW_MS
|
|
9949
|
-
});
|
|
9950
|
-
const startedAt = performance.now();
|
|
9951
|
-
void Promise.resolve().then(task).then(
|
|
9952
|
-
() => {
|
|
9953
|
-
activeTasks[kind] -= 1;
|
|
9954
|
-
recordLocalAdaptiveOutcome(scopes[kind], action, {
|
|
9955
|
-
success: true,
|
|
9956
|
-
latencyMs: performance.now() - startedAt
|
|
9957
|
-
});
|
|
9958
|
-
},
|
|
9959
|
-
() => {
|
|
9960
|
-
activeTasks[kind] -= 1;
|
|
9961
|
-
pendingPreloads.delete(key);
|
|
9962
|
-
recordLocalAdaptiveOutcome(scopes[kind], action, {
|
|
9963
|
-
success: false,
|
|
9964
|
-
latencyMs: performance.now() - startedAt
|
|
9965
|
-
});
|
|
9966
|
-
}
|
|
9967
|
-
);
|
|
9968
|
-
return true;
|
|
9969
|
-
}
|
|
9970
|
-
|
|
9971
|
-
// src/ui/shell/tabUtils.tsx
|
|
9972
|
-
init_define_import_meta_env();
|
|
9973
|
-
import { lazy, memo as memo2, Suspense } from "react";
|
|
9974
|
-
import { useTranslation as useTranslation9 } from "react-i18next";
|
|
9975
|
-
|
|
9976
8960
|
// src/ui/lib/host-to-ssh-host.ts
|
|
9977
8961
|
init_define_import_meta_env();
|
|
9978
8962
|
function hostToSSHHost(h) {
|
|
@@ -10009,446 +8993,7 @@ function hostToSSHHost(h) {
|
|
|
10009
8993
|
};
|
|
10010
8994
|
}
|
|
10011
8995
|
|
|
10012
|
-
// src/ui/shell/CompanionFrame.tsx
|
|
10013
|
-
init_define_import_meta_env();
|
|
10014
|
-
import {
|
|
10015
|
-
memo,
|
|
10016
|
-
useCallback as useCallback9,
|
|
10017
|
-
useEffect as useEffect18,
|
|
10018
|
-
useMemo as useMemo10,
|
|
10019
|
-
useRef as useRef8,
|
|
10020
|
-
useState as useState16
|
|
10021
|
-
} from "react";
|
|
10022
|
-
import { useTranslation as useTranslation8 } from "react-i18next";
|
|
10023
|
-
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
10024
|
-
var DEFAULT_SIDE_SIZE = 360;
|
|
10025
|
-
var DEFAULT_BOTTOM_SIZE = 280;
|
|
10026
|
-
var MIN_SIZE = 200;
|
|
10027
|
-
function DefaultsReader({
|
|
10028
|
-
def,
|
|
10029
|
-
onValue
|
|
10030
|
-
}) {
|
|
10031
|
-
const Reader = def.Defaults;
|
|
10032
|
-
const report = useCallback9(
|
|
10033
|
-
(value) => onValue(def.id, value),
|
|
10034
|
-
[def.id, onValue]
|
|
10035
|
-
);
|
|
10036
|
-
return Reader ? /* @__PURE__ */ jsx13(Reader, { onValue: report }) : null;
|
|
10037
|
-
}
|
|
10038
|
-
function sideIcon(side) {
|
|
10039
|
-
if (side === "left") return ArrowLeftToLine;
|
|
10040
|
-
if (side === "bottom") return ArrowDownToLine;
|
|
10041
|
-
return ArrowRightToLine;
|
|
10042
|
-
}
|
|
10043
|
-
var CompanionFrame = memo(function CompanionFrame2({
|
|
10044
|
-
tab,
|
|
10045
|
-
isVisible,
|
|
10046
|
-
children
|
|
10047
|
-
}) {
|
|
10048
|
-
const defs = useCompanionDefs();
|
|
10049
|
-
const layoutDefs = useCompanionLayoutDefs();
|
|
10050
|
-
const applicable = useMemo10(
|
|
10051
|
-
() => arrangeCompanions(
|
|
10052
|
-
defs.filter((def) => companionApplies(def, tab)),
|
|
10053
|
-
resolveCompanionLayout(tab.type, tab.host).order
|
|
10054
|
-
),
|
|
10055
|
-
// tab.host and tab.type decide it
|
|
10056
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
10057
|
-
[defs, layoutDefs, tab.type, tab.host]
|
|
10058
|
-
);
|
|
10059
|
-
if (applicable.length === 0) return /* @__PURE__ */ jsx13(Fragment3, { children });
|
|
10060
|
-
return /* @__PURE__ */ jsx13(CompanionLayout, { tab, defs: applicable, isVisible, children });
|
|
10061
|
-
});
|
|
10062
|
-
function CompanionLayout({
|
|
10063
|
-
tab,
|
|
10064
|
-
defs,
|
|
10065
|
-
isVisible,
|
|
10066
|
-
children
|
|
10067
|
-
}) {
|
|
10068
|
-
const { t } = useTranslation8();
|
|
10069
|
-
const isMobile = useIsMobile();
|
|
10070
|
-
const key = companionKey(tab);
|
|
10071
|
-
const state2 = useCompanionState(key);
|
|
10072
|
-
const [defaults3, setDefaults] = useState16(
|
|
10073
|
-
{}
|
|
10074
|
-
);
|
|
10075
|
-
const [dragging, setDragging] = useState16(false);
|
|
10076
|
-
const [mounted, setMounted] = useState16(/* @__PURE__ */ new Set());
|
|
10077
|
-
const rootRef = useRef8(null);
|
|
10078
|
-
const onDefaults = useCallback9((id, value) => {
|
|
10079
|
-
setDefaults((prev) => {
|
|
10080
|
-
const old = prev[id];
|
|
10081
|
-
if (old && old.open === value.open && old.side === value.side && old.size === value.size && old.edgeButton === value.edgeButton) {
|
|
10082
|
-
return prev;
|
|
10083
|
-
}
|
|
10084
|
-
return { ...prev, [id]: value };
|
|
10085
|
-
});
|
|
10086
|
-
}, []);
|
|
10087
|
-
useEffect18(() => {
|
|
10088
|
-
if (state2.seen || !isVisible) return;
|
|
10089
|
-
const ready = defs.every(
|
|
10090
|
-
(def) => !def.Defaults || defaults3[def.id] !== void 0
|
|
10091
|
-
);
|
|
10092
|
-
if (!ready) return;
|
|
10093
|
-
const auto = defs.find((def) => defaults3[def.id]?.open);
|
|
10094
|
-
patchCompanionState(key, { seen: true, openId: auto?.id ?? null });
|
|
10095
|
-
}, [state2.seen, isVisible, defs, defaults3, key]);
|
|
10096
|
-
const active = defs.find((def) => def.id === state2.openId) ?? null;
|
|
10097
|
-
useEffect18(() => {
|
|
10098
|
-
if (!active) return;
|
|
10099
|
-
setMounted(
|
|
10100
|
-
(prev) => prev.has(active.id) ? prev : new Set(prev).add(active.id)
|
|
10101
|
-
);
|
|
10102
|
-
}, [active]);
|
|
10103
|
-
const activeDefaults = active ? defaults3[active.id] : void 0;
|
|
10104
|
-
const layout = useMemo10(
|
|
10105
|
-
() => resolveCompanionLayout(tab.type, tab.host),
|
|
10106
|
-
[tab.type, tab.host]
|
|
10107
|
-
);
|
|
10108
|
-
const side = isMobile ? "bottom" : state2.side ?? layout.side ?? activeDefaults?.side ?? "right";
|
|
10109
|
-
const baseSize = state2.size ?? activeDefaults?.size ?? (side === "bottom" ? DEFAULT_BOTTOM_SIZE : DEFAULT_SIDE_SIZE);
|
|
10110
|
-
const setSide = useCallback9(
|
|
10111
|
-
(next) => patchCompanionState(key, { side: next }),
|
|
10112
|
-
[key]
|
|
10113
|
-
);
|
|
10114
|
-
const close = useCallback9(
|
|
10115
|
-
() => patchCompanionState(key, { openId: null }),
|
|
10116
|
-
[key]
|
|
10117
|
-
);
|
|
10118
|
-
const startResize = (event) => {
|
|
10119
|
-
event.preventDefault();
|
|
10120
|
-
const root = rootRef.current;
|
|
10121
|
-
if (!root) return;
|
|
10122
|
-
const rect = root.getBoundingClientRect();
|
|
10123
|
-
const total = side === "bottom" ? rect.height : rect.width;
|
|
10124
|
-
const max = Math.max(MIN_SIZE, total - MIN_SIZE);
|
|
10125
|
-
setDragging(true);
|
|
10126
|
-
const move = (e) => {
|
|
10127
|
-
const raw = side === "right" ? rect.right - e.clientX : side === "left" ? e.clientX - rect.left : rect.bottom - e.clientY;
|
|
10128
|
-
patchCompanionState(key, {
|
|
10129
|
-
size: Math.round(Math.min(max, Math.max(MIN_SIZE, raw)))
|
|
10130
|
-
});
|
|
10131
|
-
};
|
|
10132
|
-
const up = () => {
|
|
10133
|
-
setDragging(false);
|
|
10134
|
-
window.removeEventListener("mousemove", move);
|
|
10135
|
-
window.removeEventListener("mouseup", up);
|
|
10136
|
-
};
|
|
10137
|
-
window.addEventListener("mousemove", move);
|
|
10138
|
-
window.addEventListener("mouseup", up);
|
|
10139
|
-
};
|
|
10140
|
-
const getHandle = useCallback9(
|
|
10141
|
-
() => tab.terminalRef?.current ?? null,
|
|
10142
|
-
[tab.terminalRef]
|
|
10143
|
-
);
|
|
10144
|
-
const sshHost = useMemo10(
|
|
10145
|
-
() => tab.host ? hostToSSHHost(tab.host) : void 0,
|
|
10146
|
-
[tab.host]
|
|
10147
|
-
);
|
|
10148
|
-
const showEdge = defs.filter((def) => defaults3[def.id]?.edgeButton !== false);
|
|
10149
|
-
const vertical = side === "bottom";
|
|
10150
|
-
const clamped = vertical ? Math.min(baseSize, 2e3) : baseSize;
|
|
10151
|
-
const paneStyle = isMobile ? { height: "55%" } : vertical ? { height: clamped } : { width: clamped };
|
|
10152
|
-
const SideIcon = sideIcon(side);
|
|
10153
|
-
return /* @__PURE__ */ jsxs6("div", { className: "flex h-full w-full min-h-0 min-w-0", children: [
|
|
10154
|
-
defs.map(
|
|
10155
|
-
(def) => def.Defaults ? /* @__PURE__ */ jsx13(DefaultsReader, { def, onValue: onDefaults }, def.id) : null
|
|
10156
|
-
),
|
|
10157
|
-
/* @__PURE__ */ jsxs6(
|
|
10158
|
-
"div",
|
|
10159
|
-
{
|
|
10160
|
-
ref: rootRef,
|
|
10161
|
-
className: cn(
|
|
10162
|
-
"relative flex flex-1 min-h-0 min-w-0",
|
|
10163
|
-
vertical ? "flex-col" : side === "left" ? "flex-row-reverse" : "flex-row"
|
|
10164
|
-
),
|
|
10165
|
-
children: [
|
|
10166
|
-
/* @__PURE__ */ jsx13("div", { className: "relative flex-1 min-h-0 min-w-0", children }),
|
|
10167
|
-
defs.map((def) => {
|
|
10168
|
-
if (!mounted.has(def.id)) return null;
|
|
10169
|
-
const open = active?.id === def.id;
|
|
10170
|
-
const Component = def.component;
|
|
10171
|
-
const Icon = def.icon;
|
|
10172
|
-
return /* @__PURE__ */ jsxs6(
|
|
10173
|
-
"div",
|
|
10174
|
-
{
|
|
10175
|
-
className: cn(
|
|
10176
|
-
"relative flex-shrink-0 flex-col min-h-0 min-w-0 bg-background border-border",
|
|
10177
|
-
open ? "flex" : "hidden",
|
|
10178
|
-
vertical ? "border-t" : side === "left" ? "border-r" : "border-l",
|
|
10179
|
-
isMobile && "absolute inset-x-0 bottom-0 z-20 shadow-lg"
|
|
10180
|
-
),
|
|
10181
|
-
style: paneStyle,
|
|
10182
|
-
children: [
|
|
10183
|
-
!isMobile && /* @__PURE__ */ jsx13(
|
|
10184
|
-
"div",
|
|
10185
|
-
{
|
|
10186
|
-
role: "separator",
|
|
10187
|
-
"aria-label": t("companion.resize"),
|
|
10188
|
-
onMouseDown: startResize,
|
|
10189
|
-
className: cn(
|
|
10190
|
-
"absolute z-10",
|
|
10191
|
-
vertical ? "inset-x-0 -top-1 h-2 cursor-row-resize" : side === "left" ? "inset-y-0 -right-1 w-2 cursor-col-resize" : "inset-y-0 -left-1 w-2 cursor-col-resize",
|
|
10192
|
-
dragging && "bg-primary/30"
|
|
10193
|
-
)
|
|
10194
|
-
}
|
|
10195
|
-
),
|
|
10196
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1.5 h-8 px-2 border-b border-border flex-shrink-0", children: [
|
|
10197
|
-
Icon && /* @__PURE__ */ jsx13(Icon, { className: "size-3.5 text-muted-foreground" }),
|
|
10198
|
-
/* @__PURE__ */ jsx13("span", { className: "text-xs font-medium truncate flex-1", children: def.titleKey ? t(def.titleKey) : def.id }),
|
|
10199
|
-
!isMobile && /* @__PURE__ */ jsx13(
|
|
10200
|
-
"button",
|
|
10201
|
-
{
|
|
10202
|
-
type: "button",
|
|
10203
|
-
className: "p-1 text-muted-foreground hover:text-foreground",
|
|
10204
|
-
title: t("companion.moveSide"),
|
|
10205
|
-
onClick: () => setSide(
|
|
10206
|
-
side === "right" ? "bottom" : side === "bottom" ? "left" : "right"
|
|
10207
|
-
),
|
|
10208
|
-
children: /* @__PURE__ */ jsx13(SideIcon, { className: "size-3.5" })
|
|
10209
|
-
}
|
|
10210
|
-
),
|
|
10211
|
-
/* @__PURE__ */ jsx13(
|
|
10212
|
-
"button",
|
|
10213
|
-
{
|
|
10214
|
-
type: "button",
|
|
10215
|
-
className: "p-1 text-muted-foreground hover:text-foreground",
|
|
10216
|
-
title: t("companion.close"),
|
|
10217
|
-
onClick: close,
|
|
10218
|
-
children: /* @__PURE__ */ jsx13(X, { className: "size-3.5" })
|
|
10219
|
-
}
|
|
10220
|
-
)
|
|
10221
|
-
] }),
|
|
10222
|
-
/* @__PURE__ */ jsx13("div", { className: "flex-1 min-h-0 min-w-0 overflow-hidden", children: /* @__PURE__ */ jsx13(
|
|
10223
|
-
Component,
|
|
10224
|
-
{
|
|
10225
|
-
tab,
|
|
10226
|
-
host: tab.host,
|
|
10227
|
-
sshHost,
|
|
10228
|
-
getHandle,
|
|
10229
|
-
side,
|
|
10230
|
-
isVisible: isVisible && open,
|
|
10231
|
-
close,
|
|
10232
|
-
setSide
|
|
10233
|
-
}
|
|
10234
|
-
) })
|
|
10235
|
-
]
|
|
10236
|
-
},
|
|
10237
|
-
def.id
|
|
10238
|
-
);
|
|
10239
|
-
})
|
|
10240
|
-
]
|
|
10241
|
-
}
|
|
10242
|
-
),
|
|
10243
|
-
showEdge.length > 0 && !isMobile && /* @__PURE__ */ jsx13("div", { className: "flex flex-col flex-shrink-0 w-6 items-center gap-1 pt-1 border-l border-border bg-background", children: showEdge.map((def) => {
|
|
10244
|
-
const Icon = def.icon ?? PanelRight;
|
|
10245
|
-
const open = active?.id === def.id;
|
|
10246
|
-
return /* @__PURE__ */ jsx13(
|
|
10247
|
-
"button",
|
|
10248
|
-
{
|
|
10249
|
-
type: "button",
|
|
10250
|
-
title: def.titleKey ? t(def.titleKey) : def.id,
|
|
10251
|
-
"aria-pressed": open,
|
|
10252
|
-
onClick: () => patchCompanionState(key, {
|
|
10253
|
-
seen: true,
|
|
10254
|
-
openId: open ? null : def.id
|
|
10255
|
-
}),
|
|
10256
|
-
className: cn(
|
|
10257
|
-
"p-1 text-muted-foreground hover:text-foreground",
|
|
10258
|
-
open && "text-foreground bg-accent"
|
|
10259
|
-
),
|
|
10260
|
-
children: /* @__PURE__ */ jsx13(Icon, { className: "size-3.5" })
|
|
10261
|
-
},
|
|
10262
|
-
def.id
|
|
10263
|
-
);
|
|
10264
|
-
}) })
|
|
10265
|
-
] });
|
|
10266
|
-
}
|
|
10267
|
-
|
|
10268
|
-
// src/ui/shell/tabUtils.tsx
|
|
10269
|
-
import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
10270
|
-
var PluginsTab = lazy(
|
|
10271
|
-
() => import("./PluginsTab-HQGSDSHS.js").then((m) => ({ default: m.PluginsTab }))
|
|
10272
|
-
);
|
|
10273
|
-
function preloadTabSurface(type) {
|
|
10274
|
-
const loader = getTabType(type)?.preload;
|
|
10275
|
-
if (loader) runAdaptiveBackgroundTask("module", `tab:${type}`, loader);
|
|
10276
|
-
}
|
|
10277
|
-
function markTabSurfaceUsed(type) {
|
|
10278
|
-
markAdaptiveResourceUsed("module", `tab:${type}`);
|
|
10279
|
-
}
|
|
10280
|
-
function EmptyState({
|
|
10281
|
-
icon: Icon,
|
|
10282
|
-
messageKey
|
|
10283
|
-
}) {
|
|
10284
|
-
const { t } = useTranslation9();
|
|
10285
|
-
return /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-center justify-center flex-1 gap-3 p-6 text-center", children: [
|
|
10286
|
-
/* @__PURE__ */ jsx14("div", { className: "size-10 rounded-full bg-muted/40 flex items-center justify-center", children: /* @__PURE__ */ jsx14(Icon, { className: "size-5 text-muted-foreground/30" }) }),
|
|
10287
|
-
/* @__PURE__ */ jsx14("span", { className: "text-sm font-semibold text-muted-foreground/60", children: t(messageKey) })
|
|
10288
|
-
] });
|
|
10289
|
-
}
|
|
10290
|
-
function TabChunkFallback() {
|
|
10291
|
-
return /* @__PURE__ */ jsx14("div", { className: "flex h-full w-full items-center justify-center bg-background", children: /* @__PURE__ */ jsx14("div", { className: "size-5 rounded-full border-2 border-muted-foreground/30 border-t-muted-foreground/70 animate-spin" }) });
|
|
10292
|
-
}
|
|
10293
|
-
function withTabSuspense(node) {
|
|
10294
|
-
return /* @__PURE__ */ jsx14(Suspense, { fallback: /* @__PURE__ */ jsx14(TabChunkFallback, {}), children: node });
|
|
10295
|
-
}
|
|
10296
|
-
function PanelTabFrame({ children }) {
|
|
10297
|
-
return /* @__PURE__ */ jsx14("div", { className: "flex h-full w-full justify-center overflow-y-auto bg-background", children: /* @__PURE__ */ jsx14("div", { className: "flex flex-col flex-1 min-h-0 w-full max-w-5xl", children }) });
|
|
10298
|
-
}
|
|
10299
|
-
function tabIcon(type) {
|
|
10300
|
-
switch (type) {
|
|
10301
|
-
case "user-profile":
|
|
10302
|
-
case "admin-settings":
|
|
10303
|
-
return /* @__PURE__ */ jsx14(Settings, { className: "size-3.5" });
|
|
10304
|
-
case "split-screen":
|
|
10305
|
-
return /* @__PURE__ */ jsx14(LayoutPanelLeft, { className: "size-3.5" });
|
|
10306
|
-
case "plugins":
|
|
10307
|
-
return /* @__PURE__ */ jsx14(Puzzle, { className: "size-3.5" });
|
|
10308
|
-
default: {
|
|
10309
|
-
const Icon = getTabType(type)?.icon;
|
|
10310
|
-
return Icon ? /* @__PURE__ */ jsx14(Icon, { className: "size-3.5" }) : null;
|
|
10311
|
-
}
|
|
10312
|
-
}
|
|
10313
|
-
}
|
|
10314
|
-
var RegisteredTab = memo2(function RegisteredTab2({
|
|
10315
|
-
def,
|
|
10316
|
-
tab,
|
|
10317
|
-
isVisible,
|
|
10318
|
-
isFocusedPane,
|
|
10319
|
-
inSplit,
|
|
10320
|
-
shell: shell2
|
|
10321
|
-
}) {
|
|
10322
|
-
const { host, label } = tab;
|
|
10323
|
-
if (def.requiresHost && !host) {
|
|
10324
|
-
return /* @__PURE__ */ jsx14(
|
|
10325
|
-
EmptyState,
|
|
10326
|
-
{
|
|
10327
|
-
icon: Server,
|
|
10328
|
-
messageKey: def.noHostMessageKey ?? "hosts.noHostSelected"
|
|
10329
|
-
}
|
|
10330
|
-
);
|
|
10331
|
-
}
|
|
10332
|
-
const Component = def.component;
|
|
10333
|
-
const content = /* @__PURE__ */ jsx14(
|
|
10334
|
-
Component,
|
|
10335
|
-
{
|
|
10336
|
-
tab,
|
|
10337
|
-
host,
|
|
10338
|
-
sshHost: host ? hostToSSHHost(host) : void 0,
|
|
10339
|
-
label,
|
|
10340
|
-
isVisible,
|
|
10341
|
-
isFocusedPane,
|
|
10342
|
-
inSplit,
|
|
10343
|
-
handleRef: trackTabHandle(
|
|
10344
|
-
tab.terminalRef
|
|
10345
|
-
),
|
|
10346
|
-
shell: shell2
|
|
10347
|
-
}
|
|
10348
|
-
);
|
|
10349
|
-
return withTabSuspense(
|
|
10350
|
-
/* @__PURE__ */ jsx14(CompanionFrame, { tab, isVisible, children: def.panelFrame ? /* @__PURE__ */ jsx14(PanelTabFrame, { children: content }) : content })
|
|
10351
|
-
);
|
|
10352
|
-
});
|
|
10353
|
-
var PanelAsTab = memo2(function PanelAsTab2({
|
|
10354
|
-
panel,
|
|
10355
|
-
isVisible,
|
|
10356
|
-
targetTab,
|
|
10357
|
-
shell: shell2
|
|
10358
|
-
}) {
|
|
10359
|
-
const Panel = panel.component;
|
|
10360
|
-
return withTabSuspense(
|
|
10361
|
-
/* @__PURE__ */ jsx14(PanelTabFrame, { children: /* @__PURE__ */ jsx14(
|
|
10362
|
-
Panel,
|
|
10363
|
-
{
|
|
10364
|
-
targetTab,
|
|
10365
|
-
active: isVisible,
|
|
10366
|
-
shell: shell2,
|
|
10367
|
-
setEditing: noop,
|
|
10368
|
-
placement: "tab"
|
|
10369
|
-
}
|
|
10370
|
-
) })
|
|
10371
|
-
);
|
|
10372
|
-
});
|
|
10373
|
-
function noop() {
|
|
10374
|
-
}
|
|
10375
|
-
function renderTabContent(tab, context) {
|
|
10376
|
-
const {
|
|
10377
|
-
shell: shell2,
|
|
10378
|
-
isVisible = true,
|
|
10379
|
-
isFocusedPane = true,
|
|
10380
|
-
inSplit = false
|
|
10381
|
-
} = context;
|
|
10382
|
-
switch (tab.type) {
|
|
10383
|
-
case "split-screen":
|
|
10384
|
-
return null;
|
|
10385
|
-
case "plugins":
|
|
10386
|
-
return withTabSuspense(/* @__PURE__ */ jsx14(PluginsTab, {}));
|
|
10387
|
-
case "user-profile":
|
|
10388
|
-
case "admin-settings":
|
|
10389
|
-
return null;
|
|
10390
|
-
default: {
|
|
10391
|
-
const def = getTabType(tab.type);
|
|
10392
|
-
if (!def && tab.type === "dashboard") return null;
|
|
10393
|
-
if (!def) {
|
|
10394
|
-
const panel = getPanel(tab.type);
|
|
10395
|
-
if (panel) {
|
|
10396
|
-
return /* @__PURE__ */ jsx14(
|
|
10397
|
-
PanelAsTab,
|
|
10398
|
-
{
|
|
10399
|
-
panel,
|
|
10400
|
-
isVisible,
|
|
10401
|
-
targetTab: context.panelTargetTab,
|
|
10402
|
-
shell: shell2
|
|
10403
|
-
}
|
|
10404
|
-
);
|
|
10405
|
-
}
|
|
10406
|
-
return /* @__PURE__ */ jsx14(PluginViewPlaceholder, { kind: "tab", viewId: tab.type });
|
|
10407
|
-
}
|
|
10408
|
-
return /* @__PURE__ */ jsx14(
|
|
10409
|
-
RegisteredTab,
|
|
10410
|
-
{
|
|
10411
|
-
def,
|
|
10412
|
-
tab,
|
|
10413
|
-
isVisible,
|
|
10414
|
-
isFocusedPane,
|
|
10415
|
-
inSplit,
|
|
10416
|
-
shell: shell2
|
|
10417
|
-
}
|
|
10418
|
-
);
|
|
10419
|
-
}
|
|
10420
|
-
}
|
|
10421
|
-
}
|
|
10422
|
-
|
|
10423
|
-
// src/ui/lib/local-adaptive-preferences.ts
|
|
10424
|
-
init_define_import_meta_env();
|
|
10425
|
-
var LOCAL_ADAPTIVE_PREFERENCES_KEY = LOCAL_ADAPTIVE_ENGINE_KEY;
|
|
10426
|
-
function recordLocalPreference(scope, action, now = Date.now()) {
|
|
10427
|
-
recordLocalAdaptiveChoice(scope, action, now);
|
|
10428
|
-
}
|
|
10429
|
-
function getLocalPreference(scope, candidates, fallback, now = Date.now()) {
|
|
10430
|
-
return chooseLocalAdaptiveAction({
|
|
10431
|
-
scope,
|
|
10432
|
-
candidates,
|
|
10433
|
-
fallback,
|
|
10434
|
-
now
|
|
10435
|
-
}).action;
|
|
10436
|
-
}
|
|
10437
|
-
function clearLocalAdaptivePreferences() {
|
|
10438
|
-
clearLocalAdaptiveEngine();
|
|
10439
|
-
}
|
|
10440
|
-
var hostActionScope = (hostId) => `host-action:${hostId}`;
|
|
10441
|
-
function recordHostActionPreference(hostId, action) {
|
|
10442
|
-
recordLocalPreference(hostActionScope(hostId), action);
|
|
10443
|
-
}
|
|
10444
|
-
function getPreferredHostAction(hostId, candidates, fallback) {
|
|
10445
|
-
return getLocalPreference(hostActionScope(hostId), candidates, fallback);
|
|
10446
|
-
}
|
|
10447
|
-
|
|
10448
8996
|
export {
|
|
10449
|
-
Checkbox2 as Checkbox,
|
|
10450
|
-
PasswordInput,
|
|
10451
|
-
Textarea,
|
|
10452
8997
|
rem,
|
|
10453
8998
|
remScale,
|
|
10454
8999
|
useIsMobile,
|
|
@@ -10487,6 +9032,14 @@ export {
|
|
|
10487
9032
|
isCoreRailView,
|
|
10488
9033
|
railItemLabel,
|
|
10489
9034
|
resetRegisteredRailItems,
|
|
9035
|
+
useCompanionDefs,
|
|
9036
|
+
useCompanionLayoutDefs,
|
|
9037
|
+
resolveCompanionLayout,
|
|
9038
|
+
companionApplies,
|
|
9039
|
+
arrangeCompanions,
|
|
9040
|
+
companionKey,
|
|
9041
|
+
patchCompanionState,
|
|
9042
|
+
useCompanionState,
|
|
10490
9043
|
registerHostEditorSection,
|
|
10491
9044
|
unregisterHostEditorSection,
|
|
10492
9045
|
getHostEditorSection,
|
|
@@ -10540,8 +9093,10 @@ export {
|
|
|
10540
9093
|
listExtensions,
|
|
10541
9094
|
getSettingsComponent,
|
|
10542
9095
|
listSettingsComponents,
|
|
9096
|
+
useSettingsComponents,
|
|
10543
9097
|
registerAction,
|
|
10544
9098
|
listActions,
|
|
9099
|
+
invokeAction,
|
|
10545
9100
|
declareActionSlot,
|
|
10546
9101
|
registerSlotContribution,
|
|
10547
9102
|
getSlotContributions,
|
|
@@ -10626,25 +9181,5 @@ export {
|
|
|
10626
9181
|
useLayouts,
|
|
10627
9182
|
layoutLabel,
|
|
10628
9183
|
createPluginApp,
|
|
10629
|
-
|
|
10630
|
-
SettingsFieldRow,
|
|
10631
|
-
usePluginHostSections,
|
|
10632
|
-
HostPluginSections,
|
|
10633
|
-
HostFeatureFields,
|
|
10634
|
-
ActionSlot,
|
|
10635
|
-
ComponentSlot,
|
|
10636
|
-
trackTabHandle,
|
|
10637
|
-
useTabHandlesVersion,
|
|
10638
|
-
PluginViewPlaceholder,
|
|
10639
|
-
markAdaptiveResourceUsed,
|
|
10640
|
-
getAdaptiveResourceBudget,
|
|
10641
|
-
runAdaptiveBackgroundTask,
|
|
10642
|
-
preloadTabSurface,
|
|
10643
|
-
markTabSurfaceUsed,
|
|
10644
|
-
tabIcon,
|
|
10645
|
-
renderTabContent,
|
|
10646
|
-
LOCAL_ADAPTIVE_PREFERENCES_KEY,
|
|
10647
|
-
clearLocalAdaptivePreferences,
|
|
10648
|
-
recordHostActionPreference,
|
|
10649
|
-
getPreferredHostAction
|
|
9184
|
+
hostToSSHHost
|
|
10650
9185
|
};
|