diff --git a/.changeset/fn-7477-connection-manager-clarity.md b/.changeset/fn-7477-connection-manager-clarity.md
new file mode 100644
index 0000000000..bcb18981e7
--- /dev/null
+++ b/.changeset/fn-7477-connection-manager-clarity.md
@@ -0,0 +1,7 @@
+---
+"@runfusion/fusion": patch
+---
+
+summary: Clarify the desktop Connection Manager add-remote flow.
+category: fix
+dev: Desktop Connection Manager now separates Local Server context from saved remote profiles and collapses the remote editor until add/edit.
diff --git a/docs/native-shell.md b/docs/native-shell.md
index be03bbad3d..df9fc26aaa 100644
--- a/docs/native-shell.md
+++ b/docs/native-shell.md
@@ -57,11 +57,12 @@ Profiles are first-class saved objects shared by onboarding and Connection Manag
Connection Manager supports:
-- **Desktop Switch server** shows **Local Server** as a selectable destination in the same list as saved remote/server profiles. Selecting **Local Server** calls `setDesktopMode("local")` and returns the shell to the embedded/local Fusion server without deleting remote profiles.
+- **Desktop Switch server** presents the built-in **Local Server** separately from saved **Remote servers**. Local Server is always available in the desktop shell; selecting it calls `setDesktopMode("local")` and returns the shell to the embedded/local Fusion server without deleting remote profiles.
+- **Add remote server** is the desktop CTA for saving another Fusion server profile. The remote profile editor stays collapsed until a user chooses **Add remote server** or edits an existing saved profile, so local-only desktop users do not see an empty setup form.
- **Use** (activate a saved remote profile). In desktop local mode, using a remote profile first switches desktop mode back to `remote`, then activates the selected profile.
- **Edit** (update name/URL/token)
- **Delete**
-- **Add connection**
+- **Mobile Add connection / Scan QR** remains focused on remote profile setup and does not show the desktop-only Local Server guidance.
Activation updates `activeProfileId` and stamps `lastUsedAt` on the selected profile.
diff --git a/packages/dashboard/app/components/NativeShellConnectionManager.css b/packages/dashboard/app/components/NativeShellConnectionManager.css
index 345c428e06..cec1de78f2 100644
--- a/packages/dashboard/app/components/NativeShellConnectionManager.css
+++ b/packages/dashboard/app/components/NativeShellConnectionManager.css
@@ -2,21 +2,17 @@
width: min(100%, 42rem);
}
-.native-shell-connection-manager__mode-row {
- display: flex;
- gap: var(--space-sm);
- padding: 0 var(--space-xl) var(--space-md);
-}
-
.native-shell-connection-manager__profiles {
display: flex;
flex-direction: column;
gap: var(--space-sm);
padding: 0 var(--space-xl);
- max-height: 16rem;
+ max-height: 18rem;
overflow: auto;
}
+.native-shell-connection-manager__overview,
+.native-shell-connection-manager__section-heading,
.native-shell-connection-manager__profile {
display: flex;
align-items: center;
@@ -24,40 +20,56 @@
gap: var(--space-md);
}
-.native-shell-connection-manager__destination {
- width: 100%;
- border-color: var(--border);
- color: var(--text);
- text-align: start;
- cursor: pointer;
-}
-
-.native-shell-connection-manager__destination:hover,
-.native-shell-connection-manager__destination:focus-visible {
- border-color: var(--accent-primary);
-}
-
-.native-shell-connection-manager__destination > span:first-child {
+.native-shell-connection-manager__overview-copy {
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
-.native-shell-connection-manager__profile-actions {
+.native-shell-connection-manager__overview-copy h3,
+.native-shell-connection-manager__section-heading h3,
+.native-shell-connection-manager__editor h3 {
+ margin: 0;
+}
+
+.native-shell-connection-manager__overview-copy p,
+.native-shell-connection-manager__section-heading p {
+ margin: var(--space-xs) 0 0;
+}
+
+.native-shell-connection-manager__section-heading {
+ padding: var(--space-sm) 0;
+}
+
+.native-shell-connection-manager__profile-actions,
+.native-shell-connection-manager__mobile-actions {
display: inline-flex;
gap: var(--space-sm);
+ flex-wrap: wrap;
+}
+
+.native-shell-connection-manager__mobile-actions {
+ padding: var(--space-md) var(--space-xl) 0;
}
.native-shell-connection-manager__editor {
padding-top: var(--space-lg);
}
+.native-shell-connection-manager__editor h3 {
+ padding-bottom: var(--space-sm);
+}
+
.native-shell-connection-manager__empty-state {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
+.native-shell-connection-manager__empty-state p {
+ margin: 0;
+}
+
.native-shell-connection-manager__active-pill {
display: inline-flex;
margin-top: var(--space-xs);
@@ -75,13 +87,20 @@
background: color-mix(in srgb, var(--color-warning) 8%, transparent);
}
+.native-shell-connection-manager__standalone-error {
+ margin: var(--space-md) var(--space-xl) 0;
+}
+
@media (max-width: 768px) {
+ .native-shell-connection-manager__overview,
+ .native-shell-connection-manager__section-heading,
.native-shell-connection-manager__profile {
flex-direction: column;
align-items: flex-start;
}
- .native-shell-connection-manager__mode-row {
- flex-wrap: wrap;
+ .native-shell-connection-manager__section-heading > .btn,
+ .native-shell-connection-manager__overview > .btn {
+ width: 100%;
}
}
diff --git a/packages/dashboard/app/components/NativeShellConnectionManager.tsx b/packages/dashboard/app/components/NativeShellConnectionManager.tsx
index 372e32044b..5cb6430074 100644
--- a/packages/dashboard/app/components/NativeShellConnectionManager.tsx
+++ b/packages/dashboard/app/components/NativeShellConnectionManager.tsx
@@ -24,6 +24,7 @@ export function NativeShellConnectionManager({ open, shellApi, shellState, onClo
if (!open) return null;
const isAddingConnection = editingProfileId === "__new__";
+ const isEditorOpen = editingProfileId !== null;
const editingProfile = isAddingConnection
? null
: shellState.profiles.find((profile) => profile.id === editingProfileId) ?? activeProfile;
@@ -37,6 +38,12 @@ export function NativeShellConnectionManager({ open, shellApi, shellState, onClo
setError(null);
};
+ const startNewRemoteDraft = () => {
+ setEditingProfileId("__new__");
+ setDraft({ name: "", serverUrl: "", authToken: "" });
+ setError(null);
+ };
+
const saveCurrent = async () => {
setError(null);
try {
@@ -120,44 +127,57 @@ export function NativeShellConnectionManager({ open, shellApi, shellState, onClo
{isDesktopShell && (
-
void handleUseLocalServer()}
- aria-pressed={isDesktopLocalActive}
- >
-
- {t("shell.localServerTitle", "Local Server")}
- {t("shell.localServerDescription", "Use the embedded Fusion server on this device.")}
- {isDesktopLocalActive && {t("shell.activePill", "Active")} }
-
-
- {isDesktopLocalActive ? t("shell.localServerActive", "Current") : t("shell.use", "Use")}
-
-
+ <>
+ {/*
+ FNXC:DesktopConnectionManager 2026-07-03-16:25:
+ Desktop Connection Manager must explain that Local Server is built in and remote servers are saved profiles. Keep the remote editor collapsed until the user explicitly adds or edits a remote server so first-run local mode never looks like incomplete setup.
+ */}
+
+
+
{t("shell.localServerTitle", "Local Server")}
+
{t("shell.localServerDescription", "Use the embedded Fusion server on this device.")}
+ {isDesktopLocalActive &&
{t("shell.activePill", "Active")} }
+
+ void handleUseLocalServer()}
+ aria-label={isDesktopLocalActive ? t("shell.currentLocalServer", "Current Local Server") : t("shell.useLocalServer", "Use Local Server")}
+ aria-pressed={isDesktopLocalActive}
+ >
+ {isDesktopLocalActive ? t("shell.localServerActive", "Current") : t("shell.use", "Use")}
+
+
+
+
+
+
{t("shell.remoteServersTitle", "Remote servers")}
+
{t("shell.remoteServersDescription", "Save Fusion servers you want this desktop app to open later.")}
+
+
+ {t("shell.addRemoteServer", "Add remote server")}
+
+
+ >
)}
{shellState.profiles.length === 0 ? (
-
{t("shell.noServersSaved", "No remote servers saved yet.")}
-
-
{
- setEditingProfileId("__new__");
- setDraft({ name: "", serverUrl: "", authToken: "" });
- setError(null);
- }}
- >
- {t("shell.addServer", "Add server")}
-
- {shellState.host === "mobile-shell" && (
+
+ {isDesktopShell
+ ? t("shell.noRemoteServersDesktop", "No remote servers saved yet. Add one only when you want this desktop app to open another Fusion server.")
+ : t("shell.noServersSaved", "No remote servers saved yet.")}
+
+ {!isDesktopShell && (
+
+
+ {t("shell.addServer", "Add server")}
+
void handleScanQr()}>
{t("shell.scanQr", "Scan QR")}
- )}
-
+
+ )}
) : (
shellState.profiles.map((profile) => (
@@ -171,7 +191,7 @@ export function NativeShellConnectionManager({ open, shellApi, shellState, onClo
{
setEditingProfileId(profile.id);
setDraft(profile);
@@ -179,42 +199,53 @@ export function NativeShellConnectionManager({ open, shellApi, shellState, onClo
>
{t("actions.edit", "Edit")}
-
void handleUseProfile(profile.id)}>{t("shell.use", "Use")}
-
setDeleteCandidate(profile)}>{t("actions.delete", "Delete")}
+
void handleUseProfile(profile.id)}
+ >
+ {t("shell.use", "Use")}
+
+
setDeleteCandidate(profile)}
+ >
+ {t("actions.delete", "Delete")}
+
))
)}
-
-
{
- setEditingProfileId("__new__");
- setDraft({ name: "", serverUrl: "", authToken: "" });
- setError(null);
- }}
- >
- {t("shell.addConnection", "Add connection")}
-
- {shellState.host === "mobile-shell" && (
+ {!isDesktopShell && shellState.profiles.length > 0 && (
+
+
+ {t("shell.addConnection", "Add connection")}
+
void handleScanQr()}>
{t("shell.scanQr", "Scan QR")}
- )}
-
+
+ )}
-
-
{t("shell.nameLabel", "Name")}
-
setDraft((value) => ({ ...value, name: event.target.value }))} />
-
{t("shell.serverUrlLabel", "Server URL")}
-
setDraft((value) => ({ ...value, serverUrl: event.target.value }))} />
-
{t("shell.authTokenLabel", "Auth token (optional)")}
-
setDraft((value) => ({ ...value, authToken: event.target.value }))} />
- {error &&
{error}
}
-
+ {error && !isEditorOpen && {error}
}
+
+ {isEditorOpen && (
+
+
{isAddingConnection ? t("shell.addRemoteServer", "Add remote server") : t("shell.editRemoteServer", "Edit remote server")}
+
{t("shell.nameLabel", "Name")}
+
setDraft((value) => ({ ...value, name: event.target.value }))} />
+
{t("shell.serverUrlLabel", "Server URL")}
+
setDraft((value) => ({ ...value, serverUrl: event.target.value }))} />
+
{t("shell.authTokenLabel", "Auth token (optional)")}
+
setDraft((value) => ({ ...value, authToken: event.target.value }))} />
+ {error &&
{error}
}
+
+ )}
{deleteCandidate && (
@@ -228,8 +259,12 @@ export function NativeShellConnectionManager({ open, shellApi, shellState, onClo
{t("actions.close", "Close")}
- {t("actions.cancel", "Cancel")}
- void saveCurrent()} disabled={!workingUrl.trim()}>{t("actions.save", "Save")}
+ {isEditorOpen && (
+ <>
+ {t("actions.cancel", "Cancel")}
+ void saveCurrent()} disabled={!workingUrl.trim()}>{t("actions.save", "Save")}
+ >
+ )}
diff --git a/packages/dashboard/app/components/__tests__/NativeShellConnectionManager.test.tsx b/packages/dashboard/app/components/__tests__/NativeShellConnectionManager.test.tsx
index f95d0b7056..b7b4b73934 100644
--- a/packages/dashboard/app/components/__tests__/NativeShellConnectionManager.test.tsx
+++ b/packages/dashboard/app/components/__tests__/NativeShellConnectionManager.test.tsx
@@ -1,4 +1,4 @@
-import { fireEvent, render, screen, waitFor } from "@testing-library/react";
+import { fireEvent, render, screen, waitFor, within } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { NativeShellConnectionManager } from "../NativeShellConnectionManager";
@@ -6,10 +6,11 @@ function createShellApi() {
return {
getState: vi.fn(),
listProfiles: vi.fn(),
- saveProfile: vi.fn(async (input?: { id?: string }) => ({
+ saveProfile: vi.fn(async (input?: { id?: string; name?: string; serverUrl?: string; authToken?: string | null }) => ({
id: input?.id ?? "p2",
- name: "Prod",
- serverUrl: "https://fusion.example.com",
+ name: input?.name || "Prod",
+ serverUrl: input?.serverUrl || "https://fusion.example.com",
+ authToken: input?.authToken ?? null,
createdAt: "",
updatedAt: "",
})),
@@ -32,7 +33,37 @@ const remoteProfile = {
};
describe("NativeShellConnectionManager", () => {
- it("shows a desktop Local Server destination and switches back from an active remote profile", async () => {
+ it("explains desktop local mode with no remote profiles and hides the editor until add", () => {
+ const shellApi = createShellApi();
+ render(
+ ,
+ );
+
+ expect(screen.getByRole("heading", { name: "Local Server" })).toBeInTheDocument();
+ expect(screen.getByText("Use the embedded Fusion server on this device.")).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: "Current Local Server" })).toHaveAttribute("aria-pressed", "true");
+ expect(screen.getByRole("heading", { name: "Remote servers" })).toBeInTheDocument();
+ expect(screen.getByText(/No remote servers saved yet/i)).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: "Add remote server" })).toBeInTheDocument();
+ expect(screen.queryByRole("button", { name: "Add connection" })).not.toBeInTheDocument();
+ expect(screen.queryByRole("button", { name: /^Local$/i })).not.toBeInTheDocument();
+ expect(screen.queryByRole("button", { name: /^Remote$/i })).not.toBeInTheDocument();
+ expect(screen.queryByLabelText("Name")).not.toBeInTheDocument();
+
+ fireEvent.click(screen.getByRole("button", { name: "Add remote server" }));
+
+ expect(screen.getByRole("heading", { name: "Add remote server" })).toBeInTheDocument();
+ expect(screen.getByLabelText("Name")).toBeInTheDocument();
+ expect(screen.getByLabelText("Server URL")).toBeInTheDocument();
+ expect(screen.getByLabelText("Auth token (optional)")).toHaveAttribute("type", "password");
+ });
+
+ it("keeps the Local Server destination available from desktop remote mode", async () => {
const shellApi = createShellApi();
render(
{
/>,
);
- expect(screen.getByRole("button", { name: /Local Server/i })).toBeInTheDocument();
+ expect(screen.getByRole("heading", { name: "Local Server" })).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: "Use Local Server" })).toHaveAttribute("aria-pressed", "false");
expect(screen.getByText("Remote")).toBeInTheDocument();
- fireEvent.click(screen.getByRole("button", { name: /Local Server/i }));
+ fireEvent.click(screen.getByRole("button", { name: "Use Local Server" }));
await waitFor(() => expect(shellApi.setDesktopMode).toHaveBeenCalledWith("local"));
expect(shellApi.setActiveProfile).not.toHaveBeenCalled();
});
- it("marks Local Server active in desktop local mode and switches remote profile use into remote mode", async () => {
+ it("separates populated desktop remote profiles from local state and exposes deterministic actions", async () => {
const shellApi = createShellApi();
+ const duplicateNameProfiles = [
+ remoteProfile,
+ { ...remoteProfile, id: "remote-2", serverUrl: "https://other.example.com" },
+ ];
render(
,
);
- expect(screen.getByRole("button", { name: /Local Server/i })).toHaveAttribute("aria-pressed", "true");
- expect(screen.getByText("Active")).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: "Current Local Server" })).toHaveAttribute("aria-pressed", "true");
+ expect(screen.getByRole("button", { name: "Add remote server" })).toBeInTheDocument();
+ expect(screen.queryByLabelText("Server URL")).not.toBeInTheDocument();
- fireEvent.click(screen.getAllByLabelText("Use Remote")[1]!);
+ const firstCard = screen.getByText("https://fusion.example.com").closest(".native-shell-connection-manager__profile");
+ expect(firstCard).not.toBeNull();
+ expect(within(firstCard as HTMLElement).getByRole("button", { name: "Edit Remote at https://fusion.example.com" })).toBeInTheDocument();
+ expect(within(firstCard as HTMLElement).getByRole("button", { name: "Use Remote at https://fusion.example.com" })).toBeInTheDocument();
+ expect(within(firstCard as HTMLElement).getByRole("button", { name: "Delete Remote at https://fusion.example.com" })).toBeInTheDocument();
+
+ fireEvent.click(screen.getByRole("button", { name: "Use Remote at https://other.example.com" }));
await waitFor(() => {
expect(shellApi.setDesktopMode).toHaveBeenCalledWith("remote");
@@ -83,7 +118,7 @@ describe("NativeShellConnectionManager", () => {
expect(shellApi.setDesktopMode.mock.invocationCallOrder[0]).toBeLessThan(shellApi.setActiveProfile.mock.invocationCallOrder[0]);
});
- it("renders Local Server deterministically with no remote profiles and an unset desktop mode", () => {
+ it("validates and saves a new desktop remote profile only after add is chosen", async () => {
const shellApi = createShellApi();
render(
{
/>,
);
- expect(screen.getByRole("button", { name: /Local Server/i })).toBeInTheDocument();
- expect(screen.getByText("No remote servers saved yet.")).toBeInTheDocument();
- expect(screen.getByRole("button", { name: "Add server" })).toBeInTheDocument();
+ fireEvent.click(screen.getByRole("button", { name: "Add remote server" }));
+ fireEvent.change(screen.getByLabelText("Name"), { target: { value: "Prod" } });
+ fireEvent.change(screen.getByLabelText("Server URL"), { target: { value: "ftp://fusion.example.com" } });
+ fireEvent.click(screen.getByRole("button", { name: "Save" }));
+
+ expect(await screen.findByRole("alert")).toHaveTextContent("Server URL must use http or https");
+ expect(shellApi.saveProfile).not.toHaveBeenCalled();
+
+ fireEvent.change(screen.getByLabelText("Server URL"), { target: { value: "https://prod.example.com" } });
+ fireEvent.change(screen.getByLabelText("Auth token (optional)"), { target: { value: "secret-token" } });
+ fireEvent.click(screen.getByRole("button", { name: "Save" }));
+
+ await waitFor(() => {
+ expect(shellApi.saveProfile).toHaveBeenCalledWith(expect.objectContaining({
+ id: undefined,
+ name: "Prod",
+ serverUrl: "https://prod.example.com",
+ authToken: "secret-token",
+ }));
+ expect(shellApi.setActiveProfile).toHaveBeenCalledWith("p2");
+ });
+ expect(screen.queryByText("secret-token")).not.toBeInTheDocument();
});
- it("shows active profile indicator and requires delete confirmation", async () => {
+ it("edits an existing profile from a collapsed desktop editor", async () => {
+ const shellApi = createShellApi();
+ render(
+ ,
+ );
+
+ expect(screen.queryByLabelText("Server URL")).not.toBeInTheDocument();
+ fireEvent.click(screen.getByRole("button", { name: "Edit Remote at https://fusion.example.com" }));
+ expect(screen.getByRole("heading", { name: "Edit remote server" })).toBeInTheDocument();
+ fireEvent.change(screen.getByDisplayValue("https://fusion.example.com"), { target: { value: "https://next.example.com" } });
+ fireEvent.click(screen.getByRole("button", { name: "Save" }));
+
+ await waitFor(() => {
+ expect(shellApi.saveProfile).toHaveBeenCalledWith(expect.objectContaining({ id: "remote-1", serverUrl: "https://next.example.com" }));
+ expect(shellApi.setActiveProfile).toHaveBeenCalledWith("remote-1");
+ });
+ });
+
+ it("keeps mobile QR, manual add, active state, and delete confirmation available", async () => {
const shellApi = createShellApi();
render(
{
/>,
);
- expect(screen.queryByRole("button", { name: /Local Server/i })).toBeNull();
+ expect(screen.queryByRole("heading", { name: "Local Server" })).not.toBeInTheDocument();
+ expect(screen.queryByRole("button", { name: "Add remote server" })).not.toBeInTheDocument();
expect(screen.getByText("Active")).toBeInTheDocument();
- fireEvent.click(screen.getByLabelText("Delete Prod"));
+ expect(screen.getByRole("button", { name: "Add connection" })).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: "Scan QR" })).toBeInTheDocument();
+
+ fireEvent.click(screen.getByRole("button", { name: "Scan QR" }));
+
+ await waitFor(() => {
+ expect(shellApi.startQrScan).toHaveBeenCalled();
+ expect(screen.getByDisplayValue("https://qr.example.com")).toBeInTheDocument();
+ });
+
+ fireEvent.click(screen.getByRole("button", { name: "Delete Prod at https://fusion.example.com" }));
expect(screen.getByRole("alertdialog", { name: "Delete server confirmation" })).toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: "Delete" }));
@@ -121,27 +209,7 @@ describe("NativeShellConnectionManager", () => {
});
});
- it("edits and saves active profile", async () => {
- const shellApi = createShellApi();
- render(
- ,
- );
-
- fireEvent.change(screen.getByDisplayValue("https://fusion.example.com"), { target: { value: "https://next.example.com" } });
- fireEvent.click(screen.getByText("Save"));
-
- await waitFor(() => {
- expect(shellApi.saveProfile).toHaveBeenCalledWith(expect.objectContaining({ id: "p1", serverUrl: "https://next.example.com" }));
- expect(shellApi.setActiveProfile).toHaveBeenCalledWith("p1");
- });
- });
-
- it("supports empty-state recovery and QR import without a mobile Local Server option", async () => {
+ it("keeps mobile empty state focused on QR and manual entry without desktop guidance", async () => {
const shellApi = createShellApi();
render(
{
/>,
);
- expect(screen.queryByRole("button", { name: /Local Server/i })).toBeNull();
+ expect(screen.queryByRole("heading", { name: "Local Server" })).not.toBeInTheDocument();
expect(screen.getByText("No remote servers saved yet.")).toBeInTheDocument();
- fireEvent.click(screen.getAllByText("Scan QR")[0]!);
+ expect(screen.getByRole("button", { name: "Add server" })).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: "Scan QR" })).toBeInTheDocument();
+ expect(screen.queryByLabelText("Server URL")).not.toBeInTheDocument();
- await waitFor(() => {
- expect(shellApi.startQrScan).toHaveBeenCalled();
- expect(screen.getByDisplayValue("https://qr.example.com")).toBeInTheDocument();
- });
+ fireEvent.click(screen.getByRole("button", { name: "Add server" }));
+ expect(screen.getByLabelText("Server URL")).toBeInTheDocument();
});
});
diff --git a/packages/i18n/locales/en/app.json b/packages/i18n/locales/en/app.json
index de0f51f91a..168ab300c9 100644
--- a/packages/i18n/locales/en/app.json
+++ b/packages/i18n/locales/en/app.json
@@ -6956,8 +6956,8 @@
"defaultProfileName": "Remote Server",
"deleteConfirmLabel": "Delete server confirmation",
"deleteConfirmMessage": "Delete {{name}}? This removes the saved profile.",
- "deleteProfile": "Delete {{name}}",
- "editProfile": "Edit {{name}}",
+ "deleteProfile": "Delete {{name}} at {{url}}",
+ "editProfile": "Edit {{name}} at {{url}}",
"modeLocal": "Local",
"modeRemote": "Remote",
"nameLabel": "Name",
@@ -6966,10 +6966,17 @@
"serverUrlLabel": "Server URL",
"serverUrlProtocolError": "Server URL must use http or https",
"use": "Use",
- "useProfile": "Use {{name}}",
+ "useProfile": "Use {{name}} at {{url}}",
"localServerTitle": "Local Server",
"localServerDescription": "Use the embedded Fusion server on this device.",
- "localServerActive": "Current"
+ "localServerActive": "Current",
+ "addRemoteServer": "Add remote server",
+ "editRemoteServer": "Edit remote server",
+ "remoteServersTitle": "Remote servers",
+ "remoteServersDescription": "Save Fusion servers you want this desktop app to open later.",
+ "noRemoteServersDesktop": "No remote servers saved yet. Add one only when you want this desktop app to open another Fusion server.",
+ "useLocalServer": "Use Local Server",
+ "currentLocalServer": "Current Local Server"
},
"skills": {
"addSkill": "Add a skill…",
diff --git a/packages/i18n/locales/es/app.json b/packages/i18n/locales/es/app.json
index dfbba3c62a..2eb6efea7d 100644
--- a/packages/i18n/locales/es/app.json
+++ b/packages/i18n/locales/es/app.json
@@ -6946,8 +6946,8 @@
"defaultProfileName": "Servidor remoto",
"deleteConfirmLabel": "Confirmación de eliminación del servidor",
"deleteConfirmMessage": "¿Eliminar {{name}}? Esto eliminará el perfil guardado.",
- "deleteProfile": "Eliminar {{name}}",
- "editProfile": "Editar {{name}}",
+ "deleteProfile": "Eliminar {{name}} en {{url}}",
+ "editProfile": "Editar {{name}} en {{url}}",
"modeLocal": "Local",
"modeRemote": "Remoto",
"nameLabel": "Nombre",
@@ -6956,10 +6956,17 @@
"serverUrlLabel": "URL del servidor",
"serverUrlProtocolError": "La URL del servidor debe usar http o https",
"use": "Usar",
- "useProfile": "Usar {{name}}",
+ "useProfile": "Usar {{name}} en {{url}}",
"localServerTitle": "Servidor local",
"localServerDescription": "Usa el servidor Fusion integrado en este dispositivo.",
- "localServerActive": "Actual"
+ "localServerActive": "Actual",
+ "addRemoteServer": "Añadir servidor remoto",
+ "editRemoteServer": "Editar servidor remoto",
+ "remoteServersTitle": "Servidores remotos",
+ "remoteServersDescription": "Guarda los servidores Fusion que quieras que esta aplicación de escritorio abra más tarde.",
+ "noRemoteServersDesktop": "Aún no hay servidores remotos guardados. Añade uno solo cuando quieras que esta aplicación de escritorio abra otro servidor Fusion.",
+ "useLocalServer": "Usar servidor local",
+ "currentLocalServer": "Servidor local actual"
},
"skills": {
"addSkill": "Añadir una habilidad…",
diff --git a/packages/i18n/locales/fr/app.json b/packages/i18n/locales/fr/app.json
index d7390c5702..88c6809298 100644
--- a/packages/i18n/locales/fr/app.json
+++ b/packages/i18n/locales/fr/app.json
@@ -6946,8 +6946,8 @@
"defaultProfileName": "Serveur distant",
"deleteConfirmLabel": "Confirmation de suppression du serveur",
"deleteConfirmMessage": "Supprimer {{name}} ? Cela supprimera le profil enregistré.",
- "deleteProfile": "Supprimer {{name}}",
- "editProfile": "Modifier {{name}}",
+ "deleteProfile": "Supprimer {{name}} sur {{url}}",
+ "editProfile": "Modifier {{name}} sur {{url}}",
"modeLocal": "Local",
"modeRemote": "Distant",
"nameLabel": "Nom",
@@ -6956,10 +6956,17 @@
"serverUrlLabel": "URL du serveur",
"serverUrlProtocolError": "L'URL du serveur doit utiliser http ou https",
"use": "Utiliser",
- "useProfile": "Utiliser {{name}}",
+ "useProfile": "Utiliser {{name}} sur {{url}}",
"localServerTitle": "Serveur local",
"localServerDescription": "Utiliser le serveur Fusion intégré sur cet appareil.",
- "localServerActive": "Actuel"
+ "localServerActive": "Actuel",
+ "addRemoteServer": "Ajouter un serveur distant",
+ "editRemoteServer": "Modifier le serveur distant",
+ "remoteServersTitle": "Serveurs distants",
+ "remoteServersDescription": "Enregistrez les serveurs Fusion que cette application de bureau doit ouvrir plus tard.",
+ "noRemoteServersDesktop": "Aucun serveur distant enregistré pour l'instant. Ajoutez-en un uniquement si cette application de bureau doit ouvrir un autre serveur Fusion.",
+ "useLocalServer": "Utiliser le serveur local",
+ "currentLocalServer": "Serveur local actuel"
},
"skills": {
"addSkill": "Ajouter une compétence…",
diff --git a/packages/i18n/locales/ko/app.json b/packages/i18n/locales/ko/app.json
index 3d5295dd3f..bd67143a2e 100644
--- a/packages/i18n/locales/ko/app.json
+++ b/packages/i18n/locales/ko/app.json
@@ -6946,8 +6946,8 @@
"defaultProfileName": "원격 서버",
"deleteConfirmLabel": "서버 삭제 확인",
"deleteConfirmMessage": "{{name}}을(를) 삭제하시겠습니까? 저장된 프로필이 제거됩니다.",
- "deleteProfile": "{{name}} 삭제",
- "editProfile": "{{name}} 편집",
+ "deleteProfile": "{{url}}의 {{name}} 삭제",
+ "editProfile": "{{url}}의 {{name}} 편집",
"modeLocal": "로컬",
"modeRemote": "원격",
"nameLabel": "이름",
@@ -6956,10 +6956,17 @@
"serverUrlLabel": "서버 URL",
"serverUrlProtocolError": "서버 URL은 http 또는 https를 사용해야 합니다",
"use": "사용",
- "useProfile": "{{name}} 사용",
+ "useProfile": "{{url}}의 {{name}} 사용",
"localServerTitle": "로컬 서버",
"localServerDescription": "이 기기의 내장 Fusion 서버를 사용합니다.",
- "localServerActive": "현재"
+ "localServerActive": "현재",
+ "addRemoteServer": "원격 서버 추가",
+ "editRemoteServer": "원격 서버 편집",
+ "remoteServersTitle": "원격 서버",
+ "remoteServersDescription": "이 데스크톱 앱에서 나중에 열 Fusion 서버를 저장합니다.",
+ "noRemoteServersDesktop": "저장된 원격 서버가 없습니다. 이 데스크톱 앱에서 다른 Fusion 서버를 열어야 할 때만 추가하세요.",
+ "useLocalServer": "로컬 서버 사용",
+ "currentLocalServer": "현재 로컬 서버"
},
"skills": {
"addSkill": "스킬 추가…",
diff --git a/packages/i18n/locales/zh-CN/app.json b/packages/i18n/locales/zh-CN/app.json
index a3e7443cb5..06aa4b480e 100644
--- a/packages/i18n/locales/zh-CN/app.json
+++ b/packages/i18n/locales/zh-CN/app.json
@@ -6946,8 +6946,8 @@
"defaultProfileName": "远程服务器",
"deleteConfirmLabel": "删除服务器确认",
"deleteConfirmMessage": "删除 {{name}}?这将移除保存的配置文件。",
- "deleteProfile": "删除 {{name}}",
- "editProfile": "编辑 {{name}}",
+ "deleteProfile": "删除 {{url}} 上的 {{name}}",
+ "editProfile": "编辑 {{url}} 上的 {{name}}",
"modeLocal": "本地",
"modeRemote": "远程",
"nameLabel": "名称",
@@ -6956,10 +6956,17 @@
"serverUrlLabel": "服务器 URL",
"serverUrlProtocolError": "服务器 URL 必须使用 http 或 https",
"use": "使用",
- "useProfile": "使用 {{name}}",
+ "useProfile": "使用 {{url}} 上的 {{name}}",
"localServerTitle": "本地服务器",
"localServerDescription": "使用此设备上的内置 Fusion 服务器。",
- "localServerActive": "当前"
+ "localServerActive": "当前",
+ "addRemoteServer": "添加远程服务器",
+ "editRemoteServer": "编辑远程服务器",
+ "remoteServersTitle": "远程服务器",
+ "remoteServersDescription": "保存你希望此桌面应用稍后打开的 Fusion 服务器。",
+ "noRemoteServersDesktop": "尚未保存远程服务器。仅当你希望此桌面应用打开另一个 Fusion 服务器时再添加。",
+ "useLocalServer": "使用本地服务器",
+ "currentLocalServer": "当前本地服务器"
},
"skills": {
"addSkill": "添加技能…",
diff --git a/packages/i18n/locales/zh-TW/app.json b/packages/i18n/locales/zh-TW/app.json
index 341992e7cc..c7c46932fd 100644
--- a/packages/i18n/locales/zh-TW/app.json
+++ b/packages/i18n/locales/zh-TW/app.json
@@ -6946,8 +6946,8 @@
"defaultProfileName": "遠端伺服器",
"deleteConfirmLabel": "刪除伺服器確認",
"deleteConfirmMessage": "刪除 {{name}}?這將移除已保存的設定檔。",
- "deleteProfile": "刪除 {{name}}",
- "editProfile": "編輯 {{name}}",
+ "deleteProfile": "刪除 {{url}} 上的 {{name}}",
+ "editProfile": "編輯 {{url}} 上的 {{name}}",
"modeLocal": "本機",
"modeRemote": "遠端",
"nameLabel": "名稱",
@@ -6956,10 +6956,17 @@
"serverUrlLabel": "伺服器 URL",
"serverUrlProtocolError": "伺服器 URL 必須使用 http 或 https",
"use": "使用",
- "useProfile": "使用 {{name}}",
+ "useProfile": "使用 {{url}} 上的 {{name}}",
"localServerTitle": "本機伺服器",
"localServerDescription": "使用此裝置上的內建 Fusion 伺服器。",
- "localServerActive": "目前"
+ "localServerActive": "目前",
+ "addRemoteServer": "新增遠端伺服器",
+ "editRemoteServer": "編輯遠端伺服器",
+ "remoteServersTitle": "遠端伺服器",
+ "remoteServersDescription": "儲存你希望此桌面應用稍後開啟的 Fusion 伺服器。",
+ "noRemoteServersDesktop": "尚未儲存遠端伺服器。只有在你希望此桌面應用開啟另一個 Fusion 伺服器時才需要新增。",
+ "useLocalServer": "使用本機伺服器",
+ "currentLocalServer": "目前的本機伺服器"
},
"skills": {
"addSkill": "新增技能…",
diff --git a/packages/i18n/src/resources.d.ts b/packages/i18n/src/resources.d.ts
index 747a287605..8506205ee5 100644
--- a/packages/i18n/src/resources.d.ts
+++ b/packages/i18n/src/resources.d.ts
@@ -6951,27 +6951,34 @@ export default interface Resources {
"shell": {
"activePill": "Active",
"addConnection": "Add connection",
+ "addRemoteServer": "Add remote server",
"addServer": "Add server",
"authTokenLabel": "Auth token (optional)",
"connectionManager": "Connection Manager",
"connectionManagerLabel": "Connection Manager",
"defaultProfileName": "Remote Server",
+ "currentLocalServer": "Current Local Server",
+ "editRemoteServer": "Edit remote server",
"deleteConfirmLabel": "Delete server confirmation",
"deleteConfirmMessage": "Delete {{name}}? This removes the saved profile.",
- "deleteProfile": "Delete {{name}}",
- "editProfile": "Edit {{name}}",
+ "deleteProfile": "Delete {{name}} at {{url}}",
+ "editProfile": "Edit {{name}} at {{url}}",
"localServerActive": "Current",
"localServerDescription": "Use the embedded Fusion server on this device.",
"localServerTitle": "Local Server",
"modeLocal": "Local",
"modeRemote": "Remote",
"nameLabel": "Name",
+ "noRemoteServersDesktop": "No remote servers saved yet. Add one only when you want this desktop app to open another Fusion server.",
"noServersSaved": "No remote servers saved yet.",
+ "remoteServersDescription": "Save Fusion servers you want this desktop app to open later.",
+ "remoteServersTitle": "Remote servers",
"scanQr": "Scan QR",
"serverUrlLabel": "Server URL",
"serverUrlProtocolError": "Server URL must use http or https",
"use": "Use",
- "useProfile": "Use {{name}}"
+ "useLocalServer": "Use Local Server",
+ "useProfile": "Use {{name}} at {{url}}"
},
"skills": {
"addSkill": "Add a skill…",