@termix-ssh/plugin-sdk 1.0.15 → 1.0.18

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/PLUGIN-GUIDE.md +92 -72
  3. package/dist/backend.d.ts +381 -0
  4. package/dist/capabilities.js +2 -0
  5. package/dist/frontend.d.ts +45 -0
  6. package/dist/host/{PluginsTab-S33WIIGC.js → PluginsTab-YAGYRBIE.js} +3 -3
  7. package/dist/host/{chunk-57DJU2ZA.js → chunk-2MU6WNSX.js} +1 -1
  8. package/dist/host/{chunk-VFTB2RDP.js → chunk-446UEDSK.js} +4 -2
  9. package/dist/host/{chunk-3L45NNT5.js → chunk-7LEJ3HYF.js} +20 -3
  10. package/dist/host/{chunk-V44FCJBQ.js → chunk-J2AILBXM.js} +540 -400
  11. package/dist/host/{chunk-2IV3VX7F.js → chunk-LQKK2JJA.js} +5 -1
  12. package/dist/host/core-classes.json +1 -1
  13. package/dist/host/{linked-server-SCJH7DSL.js → linked-server-OUF3POT7.js} +5 -3
  14. package/dist/host/{rbac-api-KA5IPQQL.js → rbac-api-LZVENREG.js} +1 -1
  15. package/dist/host/testing-host.js +4 -4
  16. package/dist/host/types/src/types/onboarding.d.ts +0 -1
  17. package/dist/host/types/src/ui/auth/Auth.d.ts +1 -0
  18. package/dist/host/types/src/ui/lib/linked-server.d.ts +2 -0
  19. package/dist/host/types/src/ui/plugin-host/NativeView.d.ts +19 -0
  20. package/dist/host/types/src/ui/plugin-host/sdk-ui.d.ts +2 -6
  21. package/dist/host/types/src/ui/shell/CompanionFrame.d.ts +11 -0
  22. package/dist/host/types/src/ui/shell/companions.d.ts +63 -0
  23. package/dist/host/ui.js +149 -815
  24. package/dist/host/{use-permissions-LLN6TLAL.js → use-permissions-BYCDS5PD.js} +1 -1
  25. package/dist/manifest.d.ts +1 -1
  26. package/dist/manifest.js +1 -1
  27. package/dist/testing.d.ts +5 -1
  28. package/dist/testing.js +28 -0
  29. package/package.json +1 -1
  30. package/schema/manifest.schema.json +2 -0
  31. package/dist/host/types/src/ui/api/sync-api.d.ts +0 -93
  32. package/dist/host/types/src/ui/auth/ElectronLoginForm.d.ts +0 -9
  33. package/dist/host/types/src/ui/hooks/use-sync-status.d.ts +0 -4
  34. package/dist/host/types/src/ui/lib/sync-status.d.ts +0 -6
  35. package/dist/host/types/src/ui/settings/sync/LinkServerDialog.d.ts +0 -12
  36. package/dist/host/types/src/ui/settings/sync/ProxySettingsFields.d.ts +0 -15
  37. package/dist/host/types/src/ui/settings/sync/saved-servers.d.ts +0 -3
package/dist/host/ui.js CHANGED
@@ -32,7 +32,6 @@ import {
32
32
  challengeSecondFactor,
33
33
  changeAppLanguage,
34
34
  clearLocalAdaptivePreferences,
35
- completeLink,
36
35
  createPluginApp,
37
36
  createQuickConnectHost,
38
37
  defaultConnectAction,
@@ -45,7 +44,6 @@ import {
45
44
  getAdaptiveResourceBudget,
46
45
  getDefaultConnectionTab,
47
46
  getHostEditorSection,
48
- getLinkPreview,
49
47
  getLiveHostStatus,
50
48
  getLoginMethods,
51
49
  getPanel,
@@ -54,8 +52,6 @@ import {
54
52
  getRegisteredDashboardCard,
55
53
  getRememberDeviceAllowed,
56
54
  getStatusClasses,
57
- getSyncConflicts,
58
- getSyncErrors,
59
55
  getUserSecondFactors,
60
56
  globalShortcutHandler,
61
57
  groupRailItems,
@@ -93,18 +89,15 @@ import {
93
89
  paneNavHotkeyLabel,
94
90
  pluginWsUrl,
95
91
  preloadTabSurface,
96
- probeServer,
97
92
  promotableIds,
98
93
  protocolEnabled,
99
94
  protocolPort,
100
95
  quickConnectTargets,
101
96
  railItemLabel,
102
97
  recordHostActionPreference,
103
- refreshSyncStatus,
104
98
  registerHostEditorSection,
105
99
  registerLayout,
106
100
  registerTabCloseGuard,
107
- reloginLink,
108
101
  rem,
109
102
  remScale,
110
103
  rememberLoginLanguage,
@@ -113,7 +106,6 @@ import {
113
106
  requestManage,
114
107
  resetUserSecondFactors,
115
108
  resolveHostTabType,
116
- retrySyncErrors,
117
109
  rightDockableIds,
118
110
  runAdaptiveBackgroundTask,
119
111
  runAdaptivePolling,
@@ -122,20 +114,15 @@ import {
122
114
  setPluginLocaleResolver,
123
115
  setPluginThemes,
124
116
  setSplitDropHitTest,
125
- setSyncStatus,
126
- settleSyncConflict,
127
117
  shownPanes,
128
118
  sshHostToHost,
129
119
  startLoginRedirect,
130
120
  submitLoginMethod,
131
- syncNow,
132
121
  tabIcon,
133
122
  tabJumpHotkeyKeys,
134
123
  takePendingManageRequest,
135
124
  themeLabel,
136
- unlinkServer,
137
125
  unregisterHostEditorSection,
138
- updateSyncSettings,
139
126
  useActionSlot,
140
127
  useBranding,
141
128
  useHostActions,
@@ -167,17 +154,16 @@ import {
167
154
  useSshAuthEditors,
168
155
  useSshAuthProviders,
169
156
  useStatusColorScheme,
170
- useSyncStatus,
171
157
  useTabHandlesVersion,
172
158
  useTabStageStore,
173
159
  useTheme,
174
160
  useThemes,
175
161
  verifySecondFactor,
176
162
  withProtocolSettings
177
- } from "./chunk-V44FCJBQ.js";
163
+ } from "./chunk-J2AILBXM.js";
178
164
  import {
179
165
  usePermissions
180
- } from "./chunk-57DJU2ZA.js";
166
+ } from "./chunk-2MU6WNSX.js";
181
167
  import {
182
168
  AddButton,
183
169
  Card,
@@ -198,7 +184,7 @@ import {
198
184
  isPrerelease,
199
185
  reportBetaFeedbackUrl,
200
186
  reportCoreIssueUrl
201
- } from "./chunk-VFTB2RDP.js";
187
+ } from "./chunk-446UEDSK.js";
202
188
  import {
203
189
  Action,
204
190
  Activity,
@@ -388,7 +374,7 @@ import {
388
374
  useSurfaceKind,
389
375
  useUiPreference,
390
376
  useUiPreferencesContext
391
- } from "./chunk-2IV3VX7F.js";
377
+ } from "./chunk-LQKK2JJA.js";
392
378
  import {
393
379
  CREDENTIAL_ROW_FIELD_KEYS,
394
380
  PRESETS,
@@ -544,11 +530,12 @@ import {
544
530
  updateSecondFactorAfterExternalLogin,
545
531
  updateSessionTimeout,
546
532
  updateStatusCheckSettings,
533
+ useDesktopLinked,
547
534
  usePluginStore,
548
535
  useTabs,
549
536
  useTabsSafe,
550
537
  verifyPasswordResetCode
551
- } from "./chunk-3L45NNT5.js";
538
+ } from "./chunk-7LEJ3HYF.js";
552
539
  import {
553
540
  define_import_meta_env_default,
554
541
  init_define_import_meta_env
@@ -3328,10 +3315,11 @@ init_define_import_meta_env();
3328
3315
  function isInMobileWebView() {
3329
3316
  return /Termix-Mobile\/(Android|iOS)/.test(navigator.userAgent) || !!window.ReactNativeWebView;
3330
3317
  }
3318
+ var DESKTOP_USER_AGENT = /Termix-Desktop\/|\btermix\/[\w.-]+ .*\bElectron\//i;
3331
3319
  function isInElectronWebView() {
3332
3320
  if (isInMobileWebView()) return false;
3333
3321
  if (window.IS_ELECTRON_WEBVIEW) return true;
3334
- if (!/Termix-Desktop\//.test(navigator.userAgent)) return false;
3322
+ if (!DESKTOP_USER_AGENT.test(navigator.userAgent)) return false;
3335
3323
  try {
3336
3324
  if (window.self !== window.top) return true;
3337
3325
  } catch {
@@ -31716,7 +31704,7 @@ function Gate({
31716
31704
  const [dropped, setDropped] = useState18(false);
31717
31705
  const maxAttempts = retry?.maxAttempts ?? 8;
31718
31706
  const gateRef = useRef10(null);
31719
- const write2 = useCallback8(
31707
+ const write = useCallback8(
31720
31708
  (type) => (text, stage = "connection") => addLog({ type, stage, message: text }),
31721
31709
  [addLog]
31722
31710
  );
@@ -31745,12 +31733,12 @@ function Gate({
31745
31733
  } = retryState;
31746
31734
  const log = useMemo7(
31747
31735
  () => ({
31748
- info: write2("info"),
31749
- success: write2("success"),
31750
- warning: write2("warning"),
31751
- error: write2("error")
31736
+ info: write("info"),
31737
+ success: write("success"),
31738
+ warning: write("warning"),
31739
+ error: write("error")
31752
31740
  }),
31753
- [write2]
31741
+ [write]
31754
31742
  );
31755
31743
  const markFailed = useCallback8(
31756
31744
  (err) => {
@@ -33040,776 +33028,132 @@ var LIGHT_SWATCH = BUILTIN_THEMES.find(
33040
33028
  ).swatch;
33041
33029
  var DARK_SWATCH = BUILTIN_THEMES.find((theme2) => theme2.id === "dark").swatch;
33042
33030
 
33043
- // src/ui/settings/sync/LinkServerDialog.tsx
33031
+ // src/ui/plugin-host/NativeView.tsx
33044
33032
  init_define_import_meta_env();
33045
- import { useEffect as useEffect17, useState as useState24 } from "react";
33046
- import { useTranslation as useTranslation26 } from "react-i18next";
33047
- import { toast as toast5 } from "sonner";
33048
-
33049
- // src/ui/auth/ElectronLoginForm.tsx
33050
- init_define_import_meta_env();
33051
- import { useState as useState23, useEffect as useEffect16, useRef as useRef14, useCallback as useCallback10 } from "react";
33052
- import { useTranslation as useTranslation24 } from "react-i18next";
33053
- import { jsx as jsx53, jsxs as jsxs40 } from "react/jsx-runtime";
33054
- var AUTH_MESSAGE_SOURCES = /* @__PURE__ */ new Set([
33055
- "auth_component",
33056
- "second_factor_auth_component",
33057
- "method_auth_component",
33058
- "oidc_callback"
33059
- ]);
33060
- function ElectronLoginForm({
33061
- serverUrl,
33062
- onAuthSuccess,
33063
- onChangeServer,
33064
- targetPurpose = "local"
33033
+ import { useEffect as useEffect16, useRef as useRef14 } from "react";
33034
+ import { Fragment as Fragment8, jsx as jsx53 } from "react/jsx-runtime";
33035
+ function embeddedViewApi() {
33036
+ if (typeof window === "undefined") return null;
33037
+ const api = window.electronAPI?.embeddedView;
33038
+ return api ?? null;
33039
+ }
33040
+ var OVERLAY = [
33041
+ '[role="dialog"]',
33042
+ '[role="alertdialog"]',
33043
+ '[role="menu"]',
33044
+ '[role="listbox"]',
33045
+ "[data-radix-popper-content-wrapper]"
33046
+ ].join(",");
33047
+ function overlayOpen(host) {
33048
+ return Array.from(document.querySelectorAll(OVERLAY)).some(
33049
+ (node) => !host.contains(node)
33050
+ );
33051
+ }
33052
+ function NativeView({
33053
+ url,
33054
+ ignoreCert,
33055
+ hidden,
33056
+ fallback,
33057
+ className,
33058
+ style
33065
33059
  }) {
33066
- const { t: t3 } = useTranslation24();
33067
- const [loading, setLoading] = useState23(true);
33068
- const [error, setError] = useState23(null);
33069
- const [isAuthenticating, setIsAuthenticating] = useState23(false);
33070
- const isAuthenticatingRef = useRef14(false);
33071
- const iframeRef = useRef14(null);
33072
- const hasAuthenticatedRef = useRef14(false);
33073
- const [currentUrl, setCurrentUrl] = useState23(serverUrl);
33074
- const hasLoadedOnce = useRef14(false);
33075
- const onAuthSuccessRef = useRef14(onAuthSuccess);
33060
+ const host = useRef14(null);
33061
+ const api = embeddedViewApi();
33062
+ const hiddenRef = useRef14(!!hidden);
33063
+ hiddenRef.current = !!hidden;
33064
+ const sync = useRef14(() => {
33065
+ });
33076
33066
  useEffect16(() => {
33077
- onAuthSuccessRef.current = onAuthSuccess;
33078
- }, [onAuthSuccess]);
33079
- const handleAuthSuccess = useCallback10(
33080
- async (token) => {
33081
- if (hasAuthenticatedRef.current || isAuthenticatingRef.current) return;
33082
- hasAuthenticatedRef.current = true;
33083
- isAuthenticatingRef.current = true;
33084
- setIsAuthenticating(true);
33085
- try {
33086
- if (targetPurpose === "link") {
33087
- if (!token) {
33088
- throw new Error(t3("errors.authTokenMissing"));
33089
- }
33090
- } else if (token) {
33091
- localStorage.setItem("jwt", token);
33092
- }
33093
- await onAuthSuccessRef.current(token);
33094
- } catch (err) {
33095
- setError(
33096
- err instanceof Error && err.message ? err.message : t3("errors.authTokenSaveFailed")
33097
- );
33098
- isAuthenticatingRef.current = false;
33099
- setIsAuthenticating(false);
33100
- hasAuthenticatedRef.current = false;
33067
+ const element = host.current;
33068
+ const view = embeddedViewApi();
33069
+ if (!element || !view) return;
33070
+ const id = crypto.randomUUID();
33071
+ let opened = false;
33072
+ let lastBounds = "";
33073
+ let lastVisible = null;
33074
+ let frame = 0;
33075
+ const update = () => {
33076
+ frame = 0;
33077
+ const rect = element.getBoundingClientRect();
33078
+ const bounds = {
33079
+ x: rect.left,
33080
+ y: rect.top,
33081
+ width: rect.width,
33082
+ height: rect.height
33083
+ };
33084
+ const visible = !hiddenRef.current && rect.width > 0 && rect.height > 0 && element.offsetParent !== null && !overlayOpen(element);
33085
+ if (!opened) {
33086
+ opened = true;
33087
+ lastBounds = JSON.stringify(bounds);
33088
+ lastVisible = visible;
33089
+ void view.open({ id, url, ignoreCert, bounds, visible });
33090
+ return;
33101
33091
  }
33102
- },
33103
- [t3, targetPurpose]
33104
- );
33105
- useEffect16(() => {
33106
- let serverOrigin;
33107
- try {
33108
- serverOrigin = new URL(serverUrl).origin;
33109
- } catch {
33110
- return;
33111
- }
33112
- const handleMessage = async (event) => {
33113
- try {
33114
- if (event.source !== iframeRef.current?.contentWindow) return;
33115
- if (event.origin !== serverOrigin) return;
33116
- if (!event.data || typeof event.data !== "object") return;
33117
- const {
33118
- type,
33119
- platform,
33120
- source,
33121
- token,
33122
- authUrl,
33123
- callbackPort,
33124
- providerId
33125
- } = event.data;
33126
- if (type === "AUTH_SUCCESS" && platform === "desktop" && AUTH_MESSAGE_SOURCES.has(source)) {
33127
- await handleAuthSuccess(token ?? null);
33128
- return;
33129
- }
33130
- if (type === "OIDC_SYSTEM_BROWSER_AUTH" && authUrl && callbackPort) {
33131
- const sendResultToIframe = (result2) => {
33132
- iframeRef.current?.contentWindow?.postMessage(
33133
- {
33134
- type: "OIDC_SYSTEM_BROWSER_AUTH_RESULT",
33135
- source: "oidc_system_browser_auth",
33136
- providerId,
33137
- ...result2
33138
- },
33139
- serverOrigin
33140
- );
33141
- };
33142
- const electronAPI = window.electronAPI;
33143
- if (!electronAPI?.externalBrowserLogin) {
33144
- sendResultToIframe({
33145
- success: false,
33146
- error: t3("errors.failedExternalLogin")
33147
- });
33148
- return;
33149
- }
33150
- const result = await electronAPI.externalBrowserLogin(
33151
- authUrl,
33152
- callbackPort
33153
- );
33154
- if (result.success && result.token) {
33155
- await handleAuthSuccess(result.token);
33156
- return;
33157
- }
33158
- if (result.secondFactor) {
33159
- sendResultToIframe({
33160
- success: false,
33161
- secondFactor: true,
33162
- tempToken: result.tempToken,
33163
- factors: result.factors
33164
- });
33165
- return;
33166
- }
33167
- sendResultToIframe({
33168
- success: false,
33169
- error: result.error || t3("errors.failedExternalLogin")
33170
- });
33171
- }
33172
- } catch (err) {
33173
- const providerId = event.data && typeof event.data === "object" && typeof event.data.providerId === "number" ? event.data.providerId : void 0;
33174
- const error2 = getErrorMessage(err, t3("errors.failedExternalLogin"));
33175
- iframeRef.current?.contentWindow?.postMessage(
33176
- {
33177
- type: "OIDC_SYSTEM_BROWSER_AUTH_RESULT",
33178
- source: "oidc_system_browser_auth",
33179
- providerId,
33180
- success: false,
33181
- error: error2
33182
- },
33183
- serverOrigin
33184
- );
33092
+ const key = JSON.stringify(bounds);
33093
+ if (key !== lastBounds) {
33094
+ lastBounds = key;
33095
+ void view.setBounds(id, bounds);
33185
33096
  }
33186
- };
33187
- window.addEventListener("message", handleMessage);
33188
- return () => window.removeEventListener("message", handleMessage);
33189
- }, [handleAuthSuccess, serverUrl, t3]);
33190
- useEffect16(() => {
33191
- const iframe = iframeRef.current;
33192
- if (!iframe) return;
33193
- const handleLoad = () => {
33194
- setLoading(false);
33195
- hasLoadedOnce.current = true;
33196
- setError(null);
33197
- try {
33198
- if (iframe.contentWindow) {
33199
- setCurrentUrl(iframe.contentWindow.location.href);
33200
- }
33201
- } catch {
33202
- setCurrentUrl(serverUrl);
33097
+ if (visible !== lastVisible) {
33098
+ lastVisible = visible;
33099
+ void view.setVisible(id, visible);
33203
33100
  }
33204
33101
  };
33205
- const handleError = () => {
33206
- setLoading(false);
33207
- if (hasLoadedOnce.current) {
33208
- setError(t3("errors.failedToLoadServer"));
33209
- }
33102
+ const schedule = () => {
33103
+ if (!frame) frame = requestAnimationFrame(update);
33210
33104
  };
33211
- iframe.addEventListener("load", handleLoad);
33212
- iframe.addEventListener("error", handleError);
33105
+ sync.current = schedule;
33106
+ const resize = new ResizeObserver(schedule);
33107
+ resize.observe(element);
33108
+ const mutations = new MutationObserver(schedule);
33109
+ mutations.observe(document.body, {
33110
+ childList: true,
33111
+ subtree: true,
33112
+ attributes: true,
33113
+ attributeFilter: ["class", "style", "hidden", "data-state"]
33114
+ });
33115
+ window.addEventListener("resize", schedule);
33116
+ window.addEventListener("scroll", schedule, true);
33117
+ const timer = window.setInterval(schedule, 500);
33118
+ schedule();
33213
33119
  return () => {
33214
- iframe.removeEventListener("load", handleLoad);
33215
- iframe.removeEventListener("error", handleError);
33120
+ sync.current = () => {
33121
+ };
33122
+ resize.disconnect();
33123
+ mutations.disconnect();
33124
+ window.removeEventListener("resize", schedule);
33125
+ window.removeEventListener("scroll", schedule, true);
33126
+ window.clearInterval(timer);
33127
+ if (frame) cancelAnimationFrame(frame);
33128
+ void view.close(id);
33216
33129
  };
33217
- }, [serverUrl, t3]);
33218
- const handleRefresh = () => {
33219
- if (iframeRef.current) {
33220
- iframeRef.current.src = serverUrl;
33221
- setLoading(true);
33222
- setError(null);
33223
- }
33224
- };
33225
- const displayUrl = currentUrl.replace(/^https?:\/\//, "");
33226
- return /* @__PURE__ */ jsxs40("div", { className: "relative w-full h-full bg-background flex flex-col", children: [
33227
- isAuthenticating && /* @__PURE__ */ jsx53("div", { className: "absolute inset-0 flex items-center justify-center bg-background z-50", children: /* @__PURE__ */ jsx53(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" }) }),
33228
- !isAuthenticating && /* @__PURE__ */ jsxs40("div", { className: "flex items-center justify-between p-4 pr-12 bg-background border-b border-border", children: [
33229
- /* @__PURE__ */ jsxs40(
33230
- "button",
33231
- {
33232
- onClick: onChangeServer,
33233
- className: "flex items-center gap-2 text-foreground hover:text-primary transition-colors",
33234
- children: [
33235
- /* @__PURE__ */ jsx53(ArrowLeft, { className: "h-5 w-5" }),
33236
- /* @__PURE__ */ jsx53("span", { className: "text-base font-medium", children: t3("sync.wizard.back") })
33237
- ]
33238
- }
33239
- ),
33240
- /* @__PURE__ */ jsx53("div", { className: "flex-1 mx-4 text-center", children: /* @__PURE__ */ jsx53("span", { className: "text-muted-foreground text-sm truncate block", children: displayUrl }) }),
33241
- /* @__PURE__ */ jsx53(
33242
- "button",
33243
- {
33244
- onClick: handleRefresh,
33245
- className: "p-2 text-foreground hover:text-primary transition-colors",
33246
- disabled: loading,
33247
- children: /* @__PURE__ */ jsx53(RefreshCw, { className: `h-5 w-5 ${loading ? "animate-spin" : ""}` })
33248
- }
33249
- )
33250
- ] }),
33251
- error && !isAuthenticating && /* @__PURE__ */ jsx53("div", { className: "absolute top-20 left-1/2 transform -translate-x-1/2 z-50 w-full max-w-md px-4", children: /* @__PURE__ */ jsxs40(Alert, { variant: "destructive", children: [
33252
- /* @__PURE__ */ jsx53(CircleAlert, { className: "h-4 w-4" }),
33253
- /* @__PURE__ */ jsx53(AlertTitle, { children: t3("common.error") }),
33254
- /* @__PURE__ */ jsx53(AlertDescription, { children: error })
33255
- ] }) }),
33256
- loading && !isAuthenticating && /* @__PURE__ */ jsx53(
33257
- "div",
33258
- {
33259
- className: "absolute inset-0 flex items-center justify-center bg-background z-40",
33260
- style: { marginTop: "60px" },
33261
- children: /* @__PURE__ */ jsxs40("div", { className: "flex items-center", children: [
33262
- /* @__PURE__ */ jsx53(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" }),
33263
- /* @__PURE__ */ jsx53("span", { className: "ml-3 text-muted-foreground", children: t3("auth.loadingServer") })
33264
- ] })
33265
- }
33266
- ),
33267
- /* @__PURE__ */ jsx53(
33268
- "div",
33269
- {
33270
- className: "flex-1 overflow-hidden",
33271
- style: { visibility: isAuthenticating ? "hidden" : "visible" },
33272
- children: /* @__PURE__ */ jsx53(
33273
- "iframe",
33274
- {
33275
- ref: iframeRef,
33276
- src: serverUrl,
33277
- className: "w-full h-full border-0",
33278
- title: t3("auth.serverAuthentication"),
33279
- sandbox: "allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-storage-access-by-user-activation allow-top-navigation allow-top-navigation-by-user-activation allow-modals allow-downloads",
33280
- allow: "clipboard-read; clipboard-write; publickey-credentials-get; publickey-credentials-create"
33281
- }
33282
- )
33283
- }
33284
- )
33285
- ] });
33286
- }
33287
-
33288
- // src/ui/settings/sync/ProxySettingsFields.tsx
33289
- init_define_import_meta_env();
33290
- import { useTranslation as useTranslation25 } from "react-i18next";
33291
- import { jsx as jsx54, jsxs as jsxs41 } from "react/jsx-runtime";
33292
- function ProxySettingsFields({
33293
- customHeaders,
33294
- basicAuth,
33295
- onChange
33296
- }) {
33297
- const { t: t3 } = useTranslation25();
33298
- const setHeader = (index, patch) => {
33299
- onChange({
33300
- customHeaders: customHeaders.map(
33301
- (header, i2) => i2 === index ? { ...header, ...patch } : header
33302
- )
33303
- });
33304
- };
33305
- return /* @__PURE__ */ jsxs41("div", { className: "flex flex-col gap-4 border border-border p-3", children: [
33306
- /* @__PURE__ */ jsxs41("div", { className: "flex flex-col gap-2", children: [
33307
- /* @__PURE__ */ jsxs41("div", { className: "flex flex-col gap-0.5", children: [
33308
- /* @__PURE__ */ jsx54("span", { className: "text-xs font-semibold", children: t3("sync.proxy.headersTitle") }),
33309
- /* @__PURE__ */ jsx54("span", { className: "text-[10px] text-muted-foreground", children: t3("sync.proxy.headersHint") })
33310
- ] }),
33311
- customHeaders.map((header, index) => /* @__PURE__ */ jsxs41("div", { className: "flex items-center gap-2", children: [
33312
- /* @__PURE__ */ jsx54(
33313
- Input,
33314
- {
33315
- className: "rounded-none h-8 text-xs",
33316
- placeholder: t3("sync.proxy.headerName"),
33317
- value: header.name,
33318
- onChange: (event) => setHeader(index, { name: event.target.value })
33319
- }
33320
- ),
33321
- /* @__PURE__ */ jsx54(
33322
- PasswordInput,
33323
- {
33324
- className: "rounded-none h-8 text-xs",
33325
- placeholder: header.set ? t3("sync.proxy.savedValue") : t3("sync.proxy.headerValue"),
33326
- value: header.value,
33327
- onChange: (event) => setHeader(index, { value: event.target.value })
33328
- }
33329
- ),
33330
- /* @__PURE__ */ jsx54(
33331
- "button",
33332
- {
33333
- type: "button",
33334
- "aria-label": t3("sync.proxy.removeHeader"),
33335
- className: "p-1.5 text-muted-foreground hover:text-destructive",
33336
- onClick: () => onChange({
33337
- customHeaders: customHeaders.filter((_, i2) => i2 !== index)
33338
- }),
33339
- children: /* @__PURE__ */ jsx54(Trash, { className: "size-3.5" })
33340
- }
33341
- )
33342
- ] }, index)),
33343
- /* @__PURE__ */ jsxs41(
33344
- "button",
33345
- {
33346
- type: "button",
33347
- className: "self-start flex items-center gap-1 text-[10px] font-bold uppercase tracking-widest text-muted-foreground hover:text-foreground",
33348
- onClick: () => onChange({
33349
- customHeaders: [...customHeaders, { name: "", value: "" }]
33350
- }),
33351
- children: [
33352
- /* @__PURE__ */ jsx54(Plus, { className: "size-3" }),
33353
- t3("sync.proxy.addHeader")
33354
- ]
33355
- }
33356
- )
33357
- ] }),
33358
- /* @__PURE__ */ jsxs41("div", { className: "flex flex-col gap-2 border-t border-border pt-3", children: [
33359
- /* @__PURE__ */ jsxs41("div", { className: "flex items-center justify-between gap-3", children: [
33360
- /* @__PURE__ */ jsxs41("div", { className: "flex flex-col gap-0.5", children: [
33361
- /* @__PURE__ */ jsx54("span", { className: "text-xs font-semibold", children: t3("sync.proxy.basicAuthTitle") }),
33362
- /* @__PURE__ */ jsx54("span", { className: "text-[10px] text-muted-foreground", children: t3("sync.proxy.basicAuthHint") })
33363
- ] }),
33364
- /* @__PURE__ */ jsx54(
33365
- Switch2,
33366
- {
33367
- checked: !!basicAuth,
33368
- onCheckedChange: (checked) => onChange({
33369
- basicAuth: checked ? { username: "", password: "" } : null
33370
- })
33371
- }
33372
- )
33373
- ] }),
33374
- basicAuth && /* @__PURE__ */ jsxs41("div", { className: "flex items-center gap-2", children: [
33375
- /* @__PURE__ */ jsx54(
33376
- Input,
33377
- {
33378
- className: "rounded-none h-8 text-xs",
33379
- placeholder: t3("sync.proxy.username"),
33380
- value: basicAuth.username,
33381
- onChange: (event) => onChange({
33382
- basicAuth: { ...basicAuth, username: event.target.value }
33383
- })
33384
- }
33385
- ),
33386
- /* @__PURE__ */ jsx54(
33387
- PasswordInput,
33388
- {
33389
- className: "rounded-none h-8 text-xs",
33390
- placeholder: basicAuth.set ? t3("sync.proxy.savedValue") : t3("sync.proxy.password"),
33391
- value: basicAuth.password,
33392
- onChange: (event) => onChange({
33393
- basicAuth: { ...basicAuth, password: event.target.value }
33394
- })
33395
- }
33396
- )
33397
- ] })
33398
- ] })
33399
- ] });
33400
- }
33401
-
33402
- // src/ui/settings/sync/saved-servers.ts
33403
- init_define_import_meta_env();
33404
- var SAVED_URLS_KEY = "termix_saved_server_urls";
33405
- var MAX_SAVED_URLS = 5;
33406
- function getSavedServerUrls() {
33407
- try {
33408
- const parsed = JSON.parse(localStorage.getItem(SAVED_URLS_KEY) ?? "[]");
33409
- return Array.isArray(parsed) ? parsed.filter((url) => typeof url === "string") : [];
33410
- } catch {
33411
- return [];
33412
- }
33413
- }
33414
- function write(urls) {
33415
- try {
33416
- localStorage.setItem(SAVED_URLS_KEY, JSON.stringify(urls));
33417
- } catch {
33418
- }
33419
- }
33420
- function rememberServerUrl(url) {
33421
- const trimmed = url.trim().replace(/\/+$/, "");
33422
- if (!trimmed) return getSavedServerUrls();
33423
- const urls = [
33424
- trimmed,
33425
- ...getSavedServerUrls().filter((saved) => saved !== trimmed)
33426
- ].slice(0, MAX_SAVED_URLS);
33427
- write(urls);
33428
- return urls;
33429
- }
33430
- function forgetServerUrl(url) {
33431
- const urls = getSavedServerUrls().filter((saved) => saved !== url);
33432
- write(urls);
33433
- return urls;
33434
- }
33435
-
33436
- // src/ui/settings/sync/LinkServerDialog.tsx
33437
- import { Fragment as Fragment8, jsx as jsx55, jsxs as jsxs42 } from "react/jsx-runtime";
33438
- function problemText(t3, problem, message) {
33439
- switch (problem) {
33440
- case "invalid_url":
33441
- return t3("sync.problems.invalidUrl");
33442
- case "tls_untrusted":
33443
- return t3("sync.problems.tlsUntrusted");
33444
- case "basic_auth_required":
33445
- return t3("sync.problems.basicAuthRequired");
33446
- case "proxy_login":
33447
- return t3("sync.problems.proxyLogin");
33448
- case "not_termix":
33449
- return t3("sync.problems.notTermix");
33450
- case "version_mismatch":
33451
- return t3("sync.problems.versionMismatch");
33452
- case "different_account":
33453
- return t3("sync.problems.differentAccount");
33454
- default:
33455
- return message ? t3("sync.problems.unreachableWithReason", { reason: message }) : t3("sync.problems.unreachable");
33456
- }
33457
- }
33458
- function LinkServerDialog({
33459
- open,
33460
- onOpenChange,
33461
- onLinked,
33462
- relogin
33463
- }) {
33464
- const { t: t3 } = useTranslation26();
33465
- const [step, setStep] = useState24(relogin ? "signin" : "server");
33466
- const [savedUrls, setSavedUrls] = useState24(getSavedServerUrls);
33467
- const [target, setTarget] = useState24({
33468
- serverUrl: relogin?.serverUrl ?? "",
33469
- customHeaders: [],
33470
- basicAuth: null,
33471
- allowInvalidCertificate: false
33472
- });
33473
- const [showAdvanced, setShowAdvanced] = useState24(false);
33474
- const [checking, setChecking] = useState24(false);
33475
- const [problem, setProblem] = useState24(null);
33476
- const [problemKind, setProblemKind] = useState24(null);
33477
- const [serverName, setServerName] = useState24();
33478
- const [token, setToken] = useState24(null);
33479
- const [counts, setCounts] = useState24({});
33480
- const [mode, setMode] = useState24("merge");
33481
- const [finishError, setFinishError] = useState24(null);
33482
- useEffect17(() => {
33483
- if (!open) return;
33484
- setStep(relogin ? "signin" : "server");
33485
- setProblem(null);
33486
- setProblemKind(null);
33487
- setToken(null);
33488
- setFinishError(null);
33489
- setMode("merge");
33490
- if (relogin) {
33491
- setTarget((current) => ({ ...current, serverUrl: relogin.serverUrl }));
33492
- return;
33493
- }
33494
- window.electronAPI?.invoke?.("get-previous-server-url").then((result) => {
33495
- const url = result?.serverUrl;
33496
- if (url) {
33497
- setTarget(
33498
- (current) => current.serverUrl ? current : { ...current, serverUrl: url }
33499
- );
33500
- }
33501
- }).catch(() => {
33502
- });
33503
- }, [open, relogin]);
33504
- const handleCheck = async () => {
33505
- setChecking(true);
33506
- setProblem(null);
33507
- setProblemKind(null);
33508
- try {
33509
- const result = await probeServer(target);
33510
- if (!result.ok) {
33511
- setProblemKind(result.problem ?? null);
33512
- setProblem(problemText(t3, result.problem, result.message));
33513
- if (result.problem === "basic_auth_required" || result.problem === "proxy_login") {
33514
- setShowAdvanced(true);
33515
- }
33516
- if (result.problem === "basic_auth_required" && !target.basicAuth) {
33517
- setTarget((current) => ({
33518
- ...current,
33519
- basicAuth: { username: "", password: "" }
33520
- }));
33521
- }
33522
- return;
33523
- }
33524
- setTarget((current) => ({
33525
- ...current,
33526
- serverUrl: result.serverUrl ?? current.serverUrl
33527
- }));
33528
- setServerName(result.name);
33529
- setStep("signin");
33530
- } catch {
33531
- setProblem(problemText(t3, "unreachable", void 0));
33532
- } finally {
33533
- setChecking(false);
33534
- }
33535
- };
33536
- const finish = async (sessionToken, chosen) => {
33537
- setStep("finishing");
33538
- setFinishError(null);
33539
- try {
33540
- const status = await completeLink({
33541
- ...target,
33542
- token: sessionToken,
33543
- mode: chosen,
33544
- serverName
33545
- });
33546
- rememberServerUrl(target.serverUrl);
33547
- toast5.success(t3("sync.wizard.linked"));
33548
- onLinked(status);
33549
- onOpenChange(false);
33550
- } catch (error) {
33551
- const data = error?.response?.data;
33552
- setFinishError(problemText(t3, data?.problem, data?.message));
33553
- setStep("choose");
33554
- }
33555
- };
33556
- const handleSignedIn = async (sessionToken) => {
33557
- if (!sessionToken) return;
33558
- if (relogin) {
33559
- try {
33560
- const status = await reloginLink(sessionToken);
33561
- toast5.success(t3("sync.wizard.signedInAgain"));
33562
- onLinked(status);
33563
- onOpenChange(false);
33564
- } catch (error) {
33565
- const data = error?.response?.data;
33566
- throw new Error(
33567
- data?.error === "different_account" ? t3("sync.problems.differentAccount") : problemText(t3, data?.problem, data?.message)
33568
- );
33569
- }
33570
- return;
33571
- }
33572
- setToken(sessionToken);
33573
- const preview = await getLinkPreview().catch(() => ({}));
33574
- setCounts(preview);
33575
- const total = Object.values(preview).reduce((sum, count) => sum + count, 0);
33576
- if (total === 0) {
33577
- await finish(sessionToken, "merge");
33578
- return;
33579
- }
33580
- setStep("choose");
33581
- };
33582
- const localTotal = Object.values(counts).reduce(
33583
- (sum, count) => sum + count,
33584
- 0
33585
- );
33586
- const wide = step === "signin";
33587
- const title = relogin ? t3("sync.wizard.reloginTitle") : t3("sync.wizard.title");
33588
- const description = step === "server" ? t3("sync.wizard.serverDescription") : step === "signin" ? t3("sync.wizard.signinDescription", { url: target.serverUrl }) : step === "choose" ? t3("sync.wizard.chooseDescription") : t3("sync.wizard.finishingDescription");
33589
- const content2 = /* @__PURE__ */ jsxs42(Fragment8, { children: [
33590
- step === "server" && /* @__PURE__ */ jsxs42(
33591
- "form",
33592
- {
33593
- className: "flex flex-col gap-4",
33594
- onSubmit: (event) => {
33595
- event.preventDefault();
33596
- void handleCheck();
33597
- },
33598
- children: [
33599
- /* @__PURE__ */ jsxs42("div", { className: "flex flex-col gap-1.5", children: [
33600
- /* @__PURE__ */ jsx55("label", { className: "text-xs font-semibold", htmlFor: "sync-server-url", children: t3("sync.wizard.serverUrl") }),
33601
- /* @__PURE__ */ jsx55(
33602
- Input,
33603
- {
33604
- id: "sync-server-url",
33605
- autoFocus: true,
33606
- className: "rounded-none",
33607
- placeholder: "https://termix.example.com",
33608
- value: target.serverUrl,
33609
- onChange: (event) => setTarget({ ...target, serverUrl: event.target.value })
33610
- }
33611
- ),
33612
- /* @__PURE__ */ jsx55("p", { className: "text-[10px] text-muted-foreground", children: t3("sync.wizard.serverUrlHint") }),
33613
- !relogin && savedUrls.length > 0 && /* @__PURE__ */ jsxs42("div", { className: "flex flex-col gap-1 pt-1", children: [
33614
- /* @__PURE__ */ jsx55("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: t3("sync.wizard.savedServers") }),
33615
- savedUrls.map((url) => /* @__PURE__ */ jsxs42(
33616
- "div",
33617
- {
33618
- className: "flex items-center border border-border hover:bg-muted",
33619
- children: [
33620
- /* @__PURE__ */ jsx55(
33621
- "button",
33622
- {
33623
- type: "button",
33624
- className: "flex-1 min-w-0 truncate px-2 py-1.5 text-left font-mono text-xs",
33625
- onClick: () => setTarget({ ...target, serverUrl: url }),
33626
- children: url
33627
- }
33628
- ),
33629
- /* @__PURE__ */ jsx55(
33630
- "button",
33631
- {
33632
- type: "button",
33633
- title: t3("sync.wizard.removeServer"),
33634
- className: "px-2 py-1.5 text-muted-foreground hover:text-destructive",
33635
- onClick: () => setSavedUrls(forgetServerUrl(url)),
33636
- children: /* @__PURE__ */ jsx55(X, { className: "size-3" })
33637
- }
33638
- )
33639
- ]
33640
- },
33641
- url
33642
- ))
33643
- ] })
33644
- ] }),
33645
- problem && /* @__PURE__ */ jsxs42("div", { className: "flex gap-2 border border-destructive/40 bg-destructive/10 p-2.5 text-xs", children: [
33646
- /* @__PURE__ */ jsx55(CircleAlert, { className: "size-4 shrink-0 text-destructive" }),
33647
- /* @__PURE__ */ jsx55("span", { children: problem })
33648
- ] }),
33649
- (problemKind === "tls_untrusted" || target.allowInvalidCertificate) && /* @__PURE__ */ jsxs42("div", { className: "flex items-center justify-between gap-3 border border-border p-2.5", children: [
33650
- /* @__PURE__ */ jsxs42("div", { className: "flex flex-col gap-0.5", children: [
33651
- /* @__PURE__ */ jsx55("span", { className: "text-xs font-medium", children: t3("sync.proxy.allowInvalidCertificate") }),
33652
- /* @__PURE__ */ jsx55("span", { className: "text-[10px] text-muted-foreground", children: t3("sync.proxy.allowInvalidCertificateHint") })
33653
- ] }),
33654
- /* @__PURE__ */ jsx55(
33655
- Switch2,
33656
- {
33657
- checked: !!target.allowInvalidCertificate,
33658
- onCheckedChange: (checked) => setTarget({ ...target, allowInvalidCertificate: checked })
33659
- }
33660
- )
33661
- ] }),
33662
- /* @__PURE__ */ jsx55(
33663
- "button",
33664
- {
33665
- type: "button",
33666
- className: "self-start text-[10px] font-bold uppercase tracking-widest text-muted-foreground hover:text-foreground",
33667
- onClick: () => setShowAdvanced((value) => !value),
33668
- children: showAdvanced ? t3("sync.wizard.hideProxySettings") : t3("sync.wizard.showProxySettings")
33669
- }
33670
- ),
33671
- showAdvanced && /* @__PURE__ */ jsx55(
33672
- ProxySettingsFields,
33673
- {
33674
- customHeaders: target.customHeaders ?? [],
33675
- basicAuth: target.basicAuth ?? null,
33676
- onChange: (next) => setTarget({ ...target, ...next })
33677
- }
33678
- ),
33679
- /* @__PURE__ */ jsxs42("div", { className: "flex justify-end gap-2", children: [
33680
- /* @__PURE__ */ jsx55(
33681
- Button,
33682
- {
33683
- type: "button",
33684
- variant: "outline",
33685
- className: "rounded-none",
33686
- onClick: () => onOpenChange(false),
33687
- children: t3("common.cancel")
33688
- }
33689
- ),
33690
- /* @__PURE__ */ jsxs42(
33691
- Button,
33692
- {
33693
- variant: "outline",
33694
- type: "submit",
33695
- className: "rounded-none border-accent-brand/40 text-accent-brand hover:bg-accent-brand/10 hover:text-accent-brand dark:border-accent-brand/40 dark:bg-transparent dark:hover:bg-accent-brand/10",
33696
- disabled: checking || !target.serverUrl.trim(),
33697
- children: [
33698
- checking && /* @__PURE__ */ jsx55(LoaderCircle, { className: "size-4 animate-spin" }),
33699
- t3("sync.wizard.continue")
33700
- ]
33701
- }
33702
- )
33703
- ] })
33704
- ]
33705
- }
33706
- ),
33707
- step === "signin" && /* @__PURE__ */ jsx55("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsx55(
33708
- ElectronLoginForm,
33709
- {
33710
- serverUrl: target.serverUrl,
33711
- targetPurpose: "link",
33712
- onAuthSuccess: handleSignedIn,
33713
- onChangeServer: () => relogin ? onOpenChange(false) : setStep("server")
33714
- }
33715
- ) }),
33716
- step === "choose" && /* @__PURE__ */ jsxs42("div", { className: "flex flex-col gap-3", children: [
33717
- finishError && /* @__PURE__ */ jsxs42("div", { className: "flex gap-2 border border-destructive/40 bg-destructive/10 p-2.5 text-xs", children: [
33718
- /* @__PURE__ */ jsx55(CircleAlert, { className: "size-4 shrink-0 text-destructive" }),
33719
- /* @__PURE__ */ jsx55("span", { children: finishError })
33720
- ] }),
33721
- [
33722
- {
33723
- value: "merge",
33724
- title: t3("sync.wizard.mergeTitle"),
33725
- body: t3("sync.wizard.mergeBody", { count: localTotal })
33726
- },
33727
- {
33728
- value: "replace",
33729
- title: t3("sync.wizard.replaceTitle"),
33730
- body: t3("sync.wizard.replaceBody", { count: localTotal })
33731
- }
33732
- ].map((option) => /* @__PURE__ */ jsxs42(
33733
- "button",
33734
- {
33735
- type: "button",
33736
- onClick: () => setMode(option.value),
33737
- className: `text-left border p-3 flex flex-col gap-1 transition-colors ${mode === option.value ? "border-accent-brand bg-accent-brand/10" : "border-border hover:bg-muted/40"}`,
33738
- children: [
33739
- /* @__PURE__ */ jsx55("span", { className: "text-sm font-semibold", children: option.title }),
33740
- /* @__PURE__ */ jsx55("span", { className: "text-xs text-muted-foreground", children: option.body })
33741
- ]
33742
- },
33743
- option.value
33744
- )),
33745
- /* @__PURE__ */ jsxs42("div", { className: "flex justify-end gap-2", children: [
33746
- /* @__PURE__ */ jsx55(
33747
- Button,
33748
- {
33749
- type: "button",
33750
- variant: "outline",
33751
- className: "rounded-none",
33752
- onClick: () => onOpenChange(false),
33753
- children: t3("common.cancel")
33754
- }
33755
- ),
33756
- /* @__PURE__ */ jsx55(
33757
- Button,
33758
- {
33759
- variant: "outline",
33760
- type: "button",
33761
- className: "rounded-none border-accent-brand/40 text-accent-brand hover:bg-accent-brand/10 hover:text-accent-brand dark:border-accent-brand/40 dark:bg-transparent dark:hover:bg-accent-brand/10",
33762
- disabled: !token,
33763
- onClick: () => token && void finish(token, mode),
33764
- children: t3("sync.wizard.link")
33765
- }
33766
- )
33767
- ] })
33768
- ] }),
33769
- step === "finishing" && /* @__PURE__ */ jsxs42("div", { className: "flex items-center gap-3 py-6 text-sm text-muted-foreground", children: [
33770
- /* @__PURE__ */ jsx55(LoaderCircle, { className: "size-5 animate-spin text-accent-brand" }),
33771
- t3("sync.wizard.linking")
33772
- ] })
33773
- ] });
33774
- return /* @__PURE__ */ jsxs42(
33775
- InlineView,
33776
- {
33777
- open,
33778
- onOpenChange,
33779
- title,
33780
- width: "wide",
33781
- scroll: !wide,
33782
- children: [
33783
- !wide && /* @__PURE__ */ jsxs42("p", { className: "text-xs text-muted-foreground", children: [
33784
- description,
33785
- " ",
33786
- step === "server" && /* @__PURE__ */ jsx55(DocsLink, { core: "desktopSync" })
33787
- ] }),
33788
- content2
33789
- ]
33790
- }
33791
- );
33130
+ }, [url, ignoreCert]);
33131
+ useEffect16(() => {
33132
+ sync.current();
33133
+ }, [hidden]);
33134
+ if (!api) return /* @__PURE__ */ jsx53(Fragment8, { children: fallback ?? null });
33135
+ return /* @__PURE__ */ jsx53("div", { ref: host, className, style });
33792
33136
  }
33793
33137
 
33794
33138
  // src/ui/shell/split/SplitLayoutMenu.tsx
33795
33139
  init_define_import_meta_env();
33796
33140
  import { useMemo as useMemo9 } from "react";
33797
- import { useTranslation as useTranslation27 } from "react-i18next";
33798
- import { jsx as jsx56, jsxs as jsxs43 } from "react/jsx-runtime";
33141
+ import { useTranslation as useTranslation24 } from "react-i18next";
33142
+ import { jsx as jsx54, jsxs as jsxs40 } from "react/jsx-runtime";
33799
33143
  function NodeThumb({ node }) {
33800
33144
  if (node.kind === "pane") {
33801
- return /* @__PURE__ */ jsx56("div", { className: "size-full border border-current" });
33145
+ return /* @__PURE__ */ jsx54("div", { className: "size-full border border-current" });
33802
33146
  }
33803
- return /* @__PURE__ */ jsx56(
33147
+ return /* @__PURE__ */ jsx54(
33804
33148
  "div",
33805
33149
  {
33806
33150
  className: `flex size-full gap-0.5 ${node.direction === "row" ? "flex-row" : "flex-col"}`,
33807
- children: node.children.map((child, index) => /* @__PURE__ */ jsx56(
33151
+ children: node.children.map((child, index) => /* @__PURE__ */ jsx54(
33808
33152
  "div",
33809
33153
  {
33810
33154
  className: "min-w-0 min-h-0",
33811
33155
  style: { flex: `${node.sizes[index]} 1 0px` },
33812
- children: /* @__PURE__ */ jsx56(NodeThumb, { node: child })
33156
+ children: /* @__PURE__ */ jsx54(NodeThumb, { node: child })
33813
33157
  },
33814
33158
  child.id
33815
33159
  ))
@@ -33818,7 +33162,7 @@ function NodeThumb({ node }) {
33818
33162
  }
33819
33163
  function PresetThumb({ id }) {
33820
33164
  const node = useMemo9(() => buildPreset(id), [id]);
33821
- return /* @__PURE__ */ jsx56(NodeThumb, { node });
33165
+ return /* @__PURE__ */ jsx54(NodeThumb, { node });
33822
33166
  }
33823
33167
  function SplitLayoutMenu({
33824
33168
  activeIsSplit,
@@ -33826,10 +33170,10 @@ function SplitLayoutMenu({
33826
33170
  onSplit,
33827
33171
  onPreset
33828
33172
  }) {
33829
- const { t: t3 } = useTranslation27();
33173
+ const { t: t3 } = useTranslation24();
33830
33174
  const fullTitle = canAddPane ? void 0 : t3("splitScreen.maxPanes", { count: MAX_PANES });
33831
- return /* @__PURE__ */ jsxs43(DropdownMenu, { children: [
33832
- /* @__PURE__ */ jsx56(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx56(
33175
+ return /* @__PURE__ */ jsxs40(DropdownMenu, { children: [
33176
+ /* @__PURE__ */ jsx54(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx54(
33833
33177
  Button,
33834
33178
  {
33835
33179
  variant: "ghost",
@@ -33837,65 +33181,65 @@ function SplitLayoutMenu({
33837
33181
  className: `h-full w-12.5 rounded-none ${activeIsSplit ? "text-accent-brand" : "text-muted-foreground hover:text-foreground"}`,
33838
33182
  title: t3("splitScreen.title"),
33839
33183
  "aria-label": t3("splitScreen.title"),
33840
- children: /* @__PURE__ */ jsx56(LayoutPanelLeft, { className: "size-4" })
33184
+ children: /* @__PURE__ */ jsx54(LayoutPanelLeft, { className: "size-4" })
33841
33185
  }
33842
33186
  ) }),
33843
- /* @__PURE__ */ jsxs43(
33187
+ /* @__PURE__ */ jsxs40(
33844
33188
  DropdownMenuContent,
33845
33189
  {
33846
33190
  align: "end",
33847
33191
  sideOffset: 1,
33848
33192
  className: "w-64 border-t-0 [clip-path:inset(0px_-4px_-4px_-4px)] p-1",
33849
33193
  children: [
33850
- /* @__PURE__ */ jsxs43(
33194
+ /* @__PURE__ */ jsxs40(
33851
33195
  DropdownMenuItem,
33852
33196
  {
33853
33197
  disabled: !canAddPane,
33854
33198
  title: fullTitle,
33855
33199
  onSelect: () => onSplit("right"),
33856
33200
  children: [
33857
- /* @__PURE__ */ jsx56(Columns2, { className: "size-3.5" }),
33201
+ /* @__PURE__ */ jsx54(Columns2, { className: "size-3.5" }),
33858
33202
  t3("splitScreen.splitRight"),
33859
- /* @__PURE__ */ jsx56(DropdownMenuShortcut, { children: "Ctrl+Shift+\\" })
33203
+ /* @__PURE__ */ jsx54(DropdownMenuShortcut, { children: "Ctrl+Shift+\\" })
33860
33204
  ]
33861
33205
  }
33862
33206
  ),
33863
- /* @__PURE__ */ jsxs43(
33207
+ /* @__PURE__ */ jsxs40(
33864
33208
  DropdownMenuItem,
33865
33209
  {
33866
33210
  disabled: !canAddPane,
33867
33211
  title: fullTitle,
33868
33212
  onSelect: () => onSplit("bottom"),
33869
33213
  children: [
33870
- /* @__PURE__ */ jsx56(Rows2, { className: "size-3.5" }),
33214
+ /* @__PURE__ */ jsx54(Rows2, { className: "size-3.5" }),
33871
33215
  t3("splitScreen.splitDown"),
33872
- /* @__PURE__ */ jsx56(DropdownMenuShortcut, { children: "Ctrl+Shift+-" })
33216
+ /* @__PURE__ */ jsx54(DropdownMenuShortcut, { children: "Ctrl+Shift+-" })
33873
33217
  ]
33874
33218
  }
33875
33219
  ),
33876
- /* @__PURE__ */ jsx56(DropdownMenuSeparator, {}),
33877
- /* @__PURE__ */ jsx56(DropdownMenuLabel, { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: activeIsSplit ? t3("splitScreen.applyLayout") : t3("splitScreen.layouts") }),
33878
- /* @__PURE__ */ jsx56("div", { className: "grid grid-cols-4 gap-1 p-1", children: SPLIT_PRESETS.map((preset) => /* @__PURE__ */ jsx56(
33220
+ /* @__PURE__ */ jsx54(DropdownMenuSeparator, {}),
33221
+ /* @__PURE__ */ jsx54(DropdownMenuLabel, { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: activeIsSplit ? t3("splitScreen.applyLayout") : t3("splitScreen.layouts") }),
33222
+ /* @__PURE__ */ jsx54("div", { className: "grid grid-cols-4 gap-1 p-1", children: SPLIT_PRESETS.map((preset) => /* @__PURE__ */ jsx54(
33879
33223
  DropdownMenuItem,
33880
33224
  {
33881
33225
  className: "flex h-12 items-center justify-center p-1.5 text-muted-foreground focus:text-accent-brand",
33882
33226
  title: t3(preset.titleKey),
33883
33227
  "aria-label": t3(preset.titleKey),
33884
33228
  onSelect: () => onPreset(preset.id),
33885
- children: /* @__PURE__ */ jsx56("div", { className: "h-8 w-11", children: /* @__PURE__ */ jsx56(PresetThumb, { id: preset.id }) })
33229
+ children: /* @__PURE__ */ jsx54("div", { className: "h-8 w-11", children: /* @__PURE__ */ jsx54(PresetThumb, { id: preset.id }) })
33886
33230
  },
33887
33231
  preset.id
33888
33232
  )) }),
33889
- /* @__PURE__ */ jsx56(DropdownMenuSeparator, {}),
33890
- /* @__PURE__ */ jsx56(DropdownMenuLabel, { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: t3("splitScreen.shortcuts") }),
33891
- /* @__PURE__ */ jsxs43("div", { className: "flex flex-col gap-1 px-2 pb-1.5 text-xs text-muted-foreground", children: [
33892
- /* @__PURE__ */ jsxs43("div", { className: "flex items-center justify-between gap-2", children: [
33893
- /* @__PURE__ */ jsx56("span", { children: t3("splitScreen.shortcutNavigate") }),
33894
- /* @__PURE__ */ jsx56("kbd", { className: "font-mono text-[10px]", children: paneNavHotkeyLabel() })
33233
+ /* @__PURE__ */ jsx54(DropdownMenuSeparator, {}),
33234
+ /* @__PURE__ */ jsx54(DropdownMenuLabel, { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: t3("splitScreen.shortcuts") }),
33235
+ /* @__PURE__ */ jsxs40("div", { className: "flex flex-col gap-1 px-2 pb-1.5 text-xs text-muted-foreground", children: [
33236
+ /* @__PURE__ */ jsxs40("div", { className: "flex items-center justify-between gap-2", children: [
33237
+ /* @__PURE__ */ jsx54("span", { children: t3("splitScreen.shortcutNavigate") }),
33238
+ /* @__PURE__ */ jsx54("kbd", { className: "font-mono text-[10px]", children: paneNavHotkeyLabel() })
33895
33239
  ] }),
33896
- /* @__PURE__ */ jsxs43("div", { className: "flex items-center justify-between gap-2", children: [
33897
- /* @__PURE__ */ jsx56("span", { children: t3("splitScreen.zoom") }),
33898
- /* @__PURE__ */ jsx56("kbd", { className: "font-mono text-[10px]", children: "Ctrl+Shift+Enter" })
33240
+ /* @__PURE__ */ jsxs40("div", { className: "flex items-center justify-between gap-2", children: [
33241
+ /* @__PURE__ */ jsx54("span", { children: t3("splitScreen.zoom") }),
33242
+ /* @__PURE__ */ jsx54("kbd", { className: "font-mono text-[10px]", children: "Ctrl+Shift+Enter" })
33899
33243
  ] })
33900
33244
  ] })
33901
33245
  ]
@@ -33906,27 +33250,27 @@ function SplitLayoutMenu({
33906
33250
 
33907
33251
  // src/ui/sidebar/AuthEnrollmentSections.tsx
33908
33252
  init_define_import_meta_env();
33909
- import { useTranslation as useTranslation28 } from "react-i18next";
33910
- import { jsx as jsx57, jsxs as jsxs44 } from "react/jsx-runtime";
33253
+ import { useTranslation as useTranslation25 } from "react-i18next";
33254
+ import { jsx as jsx55, jsxs as jsxs41 } from "react/jsx-runtime";
33911
33255
  function AuthEnrollmentSections({
33912
33256
  factorsOnly = false
33913
33257
  } = {}) {
33914
- const { t: t3 } = useTranslation28();
33258
+ const { t: t3 } = useTranslation25();
33915
33259
  const methods = useLoginMethods();
33916
33260
  const factors = useSecondFactors();
33917
33261
  const sections = [...factorsOnly ? [] : methods, ...factors].filter(
33918
33262
  (entry) => entry.enrollment
33919
33263
  );
33920
33264
  if (sections.length === 0) return null;
33921
- return /* @__PURE__ */ jsx57("div", { className: "flex flex-col gap-4", children: sections.map((entry) => {
33265
+ return /* @__PURE__ */ jsx55("div", { className: "flex flex-col gap-4", children: sections.map((entry) => {
33922
33266
  const Enrollment = entry.enrollment;
33923
- return /* @__PURE__ */ jsxs44(
33267
+ return /* @__PURE__ */ jsxs41(
33924
33268
  "div",
33925
33269
  {
33926
33270
  className: "flex flex-col gap-2",
33927
33271
  children: [
33928
- /* @__PURE__ */ jsx57("span", { className: "text-[10px] font-bold uppercase tracking-widest text-muted-foreground", children: t3(entry.titleKey) }),
33929
- /* @__PURE__ */ jsx57(Enrollment, {})
33272
+ /* @__PURE__ */ jsx55("span", { className: "text-[10px] font-bold uppercase tracking-widest text-muted-foreground", children: t3(entry.titleKey) }),
33273
+ /* @__PURE__ */ jsx55(Enrollment, {})
33930
33274
  ]
33931
33275
  },
33932
33276
  `${entry.pluginId}:${entry.id}`
@@ -34041,7 +33385,6 @@ export {
34041
33385
  LANGUAGES,
34042
33386
  Label,
34043
33387
  LineChart,
34044
- LinkServerDialog,
34045
33388
  ListBadge,
34046
33389
  ListRow,
34047
33390
  ListRowAction,
@@ -34054,6 +33397,7 @@ export {
34054
33397
  Meter,
34055
33398
  MetricCard,
34056
33399
  MiniStat,
33400
+ NativeView,
34057
33401
  NumberField,
34058
33402
  OPEN_PLUGINS_EVENT,
34059
33403
  PANEL,
@@ -34075,7 +33419,6 @@ export {
34075
33419
  PopoverAnchor,
34076
33420
  PopoverContent,
34077
33421
  PopoverTrigger,
34078
- ProxySettingsFields,
34079
33422
  RadialGauge,
34080
33423
  Repeater,
34081
33424
  RobustClipboardProvider,
@@ -34248,8 +33591,6 @@ export {
34248
33591
  getSessions,
34249
33592
  getStatusCheckSettings,
34250
33593
  getStatusClasses,
34251
- getSyncConflicts,
34252
- getSyncErrors,
34253
33594
  getTabType,
34254
33595
  getTlsStatus,
34255
33596
  getUpdateChannel,
@@ -34314,7 +33655,6 @@ export {
34314
33655
  railItemLabel,
34315
33656
  readFromClipboard,
34316
33657
  recordHostActionPreference,
34317
- refreshSyncStatus,
34318
33658
  registerLayout,
34319
33659
  registerTabCloseGuard,
34320
33660
  releaseUrlFrom,
@@ -34337,7 +33677,6 @@ export {
34337
33677
  resolveHostDefaults,
34338
33678
  resolveHostTabType,
34339
33679
  resolveRemoteHostId,
34340
- retrySyncErrors,
34341
33680
  revokeAllUserSessions,
34342
33681
  revokeCredentialAccess,
34343
33682
  revokeFolderAccess,
@@ -34361,21 +33700,17 @@ export {
34361
33700
  setHostAuthOverride,
34362
33701
  setNotificationPrivateEndpoints,
34363
33702
  setPluginOptions,
34364
- setSyncStatus,
34365
33703
  setUpdateChannel,
34366
- settleSyncConflict,
34367
33704
  shareCredential,
34368
33705
  shareFolder,
34369
33706
  shareHost,
34370
33707
  shell,
34371
33708
  splitDefaultKey,
34372
33709
  sshHostToHost,
34373
- syncNow,
34374
33710
  tabIcon,
34375
33711
  tabJumpHotkeyKeys,
34376
33712
  takePendingManageRequest,
34377
33713
  unlinkExternalFromPasswordAccount,
34378
- unlinkServer,
34379
33714
  updateCredential,
34380
33715
  updateExternalAutoProvision,
34381
33716
  updateFolderMetadata,
@@ -34393,7 +33728,6 @@ export {
34393
33728
  updateSecondFactorAfterExternalLogin,
34394
33729
  updateSessionTimeout,
34395
33730
  updateStatusCheckSettings,
34396
- updateSyncSettings,
34397
33731
  uploadTlsCertificate,
34398
33732
  usageBarColor,
34399
33733
  usageColor,
@@ -34406,6 +33740,7 @@ export {
34406
33740
  useConfirm,
34407
33741
  useConnectionGate,
34408
33742
  useConnectionLog,
33743
+ useDesktopLinked,
34409
33744
  useDesktopUpdate,
34410
33745
  useEditorDefaultKeys,
34411
33746
  useHostActions,
@@ -34440,7 +33775,6 @@ export {
34440
33775
  useSshAuthProviders,
34441
33776
  useStatusColorScheme,
34442
33777
  useSurfaceKind,
34443
- useSyncStatus,
34444
33778
  useTabHandlesVersion,
34445
33779
  useTabs,
34446
33780
  useTabsSafe,