diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/connection.ts b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/connection.js similarity index 63% rename from client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/connection.ts rename to client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/connection.js index db3e2b556..ca48f6b94 100644 --- a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/connection.ts +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/connection.js @@ -1,3 +1,4 @@ +// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT @@ -14,17 +15,28 @@ import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Cr // @ts-ignore: Unused imports import * as $models from "./models.js"; -export function Down(): $CancellablePromise { +/** + * @returns {$CancellablePromise} + */ +export function Down() { return $Call.ByID(70044537); } -export function Login(p: $models.LoginParams): $CancellablePromise<$models.LoginResult> { - return $Call.ByID(252661358, p).then(($result: any) => { +/** + * @param {$models.LoginParams} p + * @returns {$CancellablePromise<$models.LoginResult>} + */ +export function Login(p) { + return $Call.ByID(252661358, p).then(/** @type {($result: any) => any} */(($result) => { return $$createType0($result); - }); + })); } -export function Logout(p: $models.LogoutParams): $CancellablePromise { +/** + * @param {$models.LogoutParams} p + * @returns {$CancellablePromise} + */ +export function Logout(p) { return $Call.ByID(3824847887, p); } @@ -34,16 +46,26 @@ export function Logout(p: $models.LogoutParams): $CancellablePromise { * the same way as the legacy UI — WebKitGTK's window.open is blocked by the * embedded webview, and asking the user to copy/paste defeats the point of * SSO. Honors $BROWSER first, then falls back to the platform default. + * @param {string} url + * @returns {$CancellablePromise} */ -export function OpenURL(url: string): $CancellablePromise { +export function OpenURL(url) { return $Call.ByID(3786555598, url); } -export function Up(p: $models.UpParams): $CancellablePromise { +/** + * @param {$models.UpParams} p + * @returns {$CancellablePromise} + */ +export function Up(p) { return $Call.ByID(3381092588, p); } -export function WaitSSOLogin(p: $models.WaitSSOParams): $CancellablePromise { +/** + * @param {$models.WaitSSOParams} p + * @returns {$CancellablePromise} + */ +export function WaitSSOLogin(p) { return $Call.ByID(1751351500, p); } diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/debug.ts b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/debug.js similarity index 58% rename from client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/debug.ts rename to client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/debug.js index 578dd20b3..40b5bb910 100644 --- a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/debug.ts +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/debug.js @@ -1,3 +1,4 @@ +// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT @@ -14,19 +15,30 @@ import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Cr // @ts-ignore: Unused imports import * as $models from "./models.js"; -export function Bundle(p: $models.DebugBundleParams): $CancellablePromise<$models.DebugBundleResult> { - return $Call.ByID(617551238, p).then(($result: any) => { +/** + * @param {$models.DebugBundleParams} p + * @returns {$CancellablePromise<$models.DebugBundleResult>} + */ +export function Bundle(p) { + return $Call.ByID(617551238, p).then(/** @type {($result: any) => any} */(($result) => { return $$createType0($result); - }); + })); } -export function GetLogLevel(): $CancellablePromise<$models.LogLevel> { - return $Call.ByID(3832950014).then(($result: any) => { +/** + * @returns {$CancellablePromise<$models.LogLevel>} + */ +export function GetLogLevel() { + return $Call.ByID(3832950014).then(/** @type {($result: any) => any} */(($result) => { return $$createType1($result); - }); + })); } -export function SetLogLevel(lvl: $models.LogLevel): $CancellablePromise { +/** + * @param {$models.LogLevel} lvl + * @returns {$CancellablePromise} + */ +export function SetLogLevel(lvl) { return $Call.ByID(4122411498, lvl); } diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/forwarding.ts b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/forwarding.js similarity index 81% rename from client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/forwarding.ts rename to client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/forwarding.js index 803afe6b0..c0484e931 100644 --- a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/forwarding.ts +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/forwarding.js @@ -1,3 +1,4 @@ +// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT @@ -17,11 +18,12 @@ import * as $models from "./models.js"; /** * List returns the current set of forwarding rules from the daemon's * reverse proxy. The frontend renders these as the "exposed services" list. + * @returns {$CancellablePromise<$models.ForwardingRule[]>} */ -export function List(): $CancellablePromise<$models.ForwardingRule[]> { - return $Call.ByID(3831092172).then(($result: any) => { +export function List() { + return $Call.ByID(3831092172).then(/** @type {($result: any) => any} */(($result) => { return $$createType1($result); - }); + })); } // Private type creation functions diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/index.ts b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/index.js similarity index 92% rename from client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/index.ts rename to client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/index.js index bb3a7b821..030b3bdd4 100644 --- a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/index.ts +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/index.js @@ -1,3 +1,4 @@ +// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT @@ -6,6 +7,7 @@ import * as Debug from "./debug.js"; import * as Forwarding from "./forwarding.js"; import * as Networks from "./networks.js"; import * as Peers from "./peers.js"; +import * as ProfileSwitcher from "./profileswitcher.js"; import * as Profiles from "./profiles.js"; import * as Settings from "./settings.js"; import * as Update from "./update.js"; @@ -15,6 +17,7 @@ export { Forwarding, Networks, Peers, + ProfileSwitcher, Profiles, Settings, Update diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/models.js b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/models.js new file mode 100644 index 000000000..dd3ee3a03 --- /dev/null +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/models.js @@ -0,0 +1,1844 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +/** + * ActiveProfile is the result of GetActiveProfile. + */ +export class ActiveProfile { + /** + * Creates a new ActiveProfile instance. + * @param {Partial} [$$source = {}] - The source object to create the ActiveProfile. + */ + constructor($$source = {}) { + if (!("profileName" in $$source)) { + /** + * @member + * @type {string} + */ + this["profileName"] = ""; + } + if (!("username" in $$source)) { + /** + * @member + * @type {string} + */ + this["username"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ActiveProfile instance from a string or object. + * @param {any} [$$source = {}] + * @returns {ActiveProfile} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ActiveProfile(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * Config is the daemon configuration the UI exposes in the settings window. + * Pointer fields mark "set" vs "unset" so the UI can omit a value to keep the + * daemon's current setting (matching SetConfigRequest's optional semantics). + */ +export class Config { + /** + * Creates a new Config instance. + * @param {Partial} [$$source = {}] - The source object to create the Config. + */ + constructor($$source = {}) { + if (!("managementUrl" in $$source)) { + /** + * @member + * @type {string} + */ + this["managementUrl"] = ""; + } + if (!("adminUrl" in $$source)) { + /** + * @member + * @type {string} + */ + this["adminUrl"] = ""; + } + if (!("configFile" in $$source)) { + /** + * @member + * @type {string} + */ + this["configFile"] = ""; + } + if (!("logFile" in $$source)) { + /** + * @member + * @type {string} + */ + this["logFile"] = ""; + } + if (!("preSharedKey" in $$source)) { + /** + * @member + * @type {string} + */ + this["preSharedKey"] = ""; + } + if (!("interfaceName" in $$source)) { + /** + * @member + * @type {string} + */ + this["interfaceName"] = ""; + } + if (!("wireguardPort" in $$source)) { + /** + * @member + * @type {number} + */ + this["wireguardPort"] = 0; + } + if (!("mtu" in $$source)) { + /** + * @member + * @type {number} + */ + this["mtu"] = 0; + } + if (!("disableAutoConnect" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["disableAutoConnect"] = false; + } + if (!("serverSshAllowed" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["serverSshAllowed"] = false; + } + if (!("rosenpassEnabled" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["rosenpassEnabled"] = false; + } + if (!("rosenpassPermissive" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["rosenpassPermissive"] = false; + } + if (!("disableNotifications" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["disableNotifications"] = false; + } + if (!("lazyConnectionEnabled" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["lazyConnectionEnabled"] = false; + } + if (!("blockInbound" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["blockInbound"] = false; + } + if (!("networkMonitor" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["networkMonitor"] = false; + } + if (!("disableClientRoutes" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["disableClientRoutes"] = false; + } + if (!("disableServerRoutes" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["disableServerRoutes"] = false; + } + if (!("disableDns" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["disableDns"] = false; + } + if (!("disableIpv6" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["disableIpv6"] = false; + } + if (!("blockLanAccess" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["blockLanAccess"] = false; + } + if (!("enableSshRoot" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["enableSshRoot"] = false; + } + if (!("enableSshSftp" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["enableSshSftp"] = false; + } + if (!("enableSshLocalPortForwarding" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["enableSshLocalPortForwarding"] = false; + } + if (!("enableSshRemotePortForwarding" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["enableSshRemotePortForwarding"] = false; + } + if (!("disableSshAuth" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["disableSshAuth"] = false; + } + if (!("sshJwtCacheTtl" in $$source)) { + /** + * @member + * @type {number} + */ + this["sshJwtCacheTtl"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Config instance from a string or object. + * @param {any} [$$source = {}] + * @returns {Config} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new Config(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * ConfigParams selects which profile/user to read or write config for. + */ +export class ConfigParams { + /** + * Creates a new ConfigParams instance. + * @param {Partial} [$$source = {}] - The source object to create the ConfigParams. + */ + constructor($$source = {}) { + if (!("profileName" in $$source)) { + /** + * @member + * @type {string} + */ + this["profileName"] = ""; + } + if (!("username" in $$source)) { + /** + * @member + * @type {string} + */ + this["username"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ConfigParams instance from a string or object. + * @param {any} [$$source = {}] + * @returns {ConfigParams} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ConfigParams(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * DebugBundleParams configures what the daemon collects when generating a + * debug bundle. + */ +export class DebugBundleParams { + /** + * Creates a new DebugBundleParams instance. + * @param {Partial} [$$source = {}] - The source object to create the DebugBundleParams. + */ + constructor($$source = {}) { + if (!("anonymize" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["anonymize"] = false; + } + if (!("systemInfo" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["systemInfo"] = false; + } + if (!("uploadUrl" in $$source)) { + /** + * @member + * @type {string} + */ + this["uploadUrl"] = ""; + } + if (!("logFileCount" in $$source)) { + /** + * @member + * @type {number} + */ + this["logFileCount"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DebugBundleParams instance from a string or object. + * @param {any} [$$source = {}] + * @returns {DebugBundleParams} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new DebugBundleParams(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * DebugBundleResult mirrors DebugBundleResponse — Path is set on local-only + * bundles, UploadedKey on successful uploads, UploadFailureReason on failed + * uploads. + */ +export class DebugBundleResult { + /** + * Creates a new DebugBundleResult instance. + * @param {Partial} [$$source = {}] - The source object to create the DebugBundleResult. + */ + constructor($$source = {}) { + if (!("path" in $$source)) { + /** + * @member + * @type {string} + */ + this["path"] = ""; + } + if (!("uploadedKey" in $$source)) { + /** + * @member + * @type {string} + */ + this["uploadedKey"] = ""; + } + if (!("uploadFailureReason" in $$source)) { + /** + * @member + * @type {string} + */ + this["uploadFailureReason"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DebugBundleResult instance from a string or object. + * @param {any} [$$source = {}] + * @returns {DebugBundleResult} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new DebugBundleResult(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * Features reports which UI surfaces the daemon has disabled. The Fyne UI uses + * these flags to grey out menu items the operator turned off server-side. + */ +export class Features { + /** + * Creates a new Features instance. + * @param {Partial} [$$source = {}] - The source object to create the Features. + */ + constructor($$source = {}) { + if (!("disableProfiles" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["disableProfiles"] = false; + } + if (!("disableUpdateSettings" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["disableUpdateSettings"] = false; + } + if (!("disableNetworks" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["disableNetworks"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Features instance from a string or object. + * @param {any} [$$source = {}] + * @returns {Features} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new Features(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * ForwardingRule is one entry from the daemon's reverse-proxy table — + * what we ship to the frontend's "exposed services" view. + */ +export class ForwardingRule { + /** + * Creates a new ForwardingRule instance. + * @param {Partial} [$$source = {}] - The source object to create the ForwardingRule. + */ + constructor($$source = {}) { + if (!("protocol" in $$source)) { + /** + * @member + * @type {string} + */ + this["protocol"] = ""; + } + if (!("destinationPort" in $$source)) { + /** + * @member + * @type {PortInfo} + */ + this["destinationPort"] = (new PortInfo()); + } + if (!("translatedAddress" in $$source)) { + /** + * @member + * @type {string} + */ + this["translatedAddress"] = ""; + } + if (!("translatedHostname" in $$source)) { + /** + * @member + * @type {string} + */ + this["translatedHostname"] = ""; + } + if (!("translatedPort" in $$source)) { + /** + * @member + * @type {PortInfo} + */ + this["translatedPort"] = (new PortInfo()); + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ForwardingRule instance from a string or object. + * @param {any} [$$source = {}] + * @returns {ForwardingRule} + */ + static createFrom($$source = {}) { + const $$createField1_0 = $$createType0; + const $$createField4_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("destinationPort" in $$parsedSource) { + $$parsedSource["destinationPort"] = $$createField1_0($$parsedSource["destinationPort"]); + } + if ("translatedPort" in $$parsedSource) { + $$parsedSource["translatedPort"] = $$createField4_0($$parsedSource["translatedPort"]); + } + return new ForwardingRule(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * LocalPeer mirrors LocalPeerState — what this client looks like on the mesh. + */ +export class LocalPeer { + /** + * Creates a new LocalPeer instance. + * @param {Partial} [$$source = {}] - The source object to create the LocalPeer. + */ + constructor($$source = {}) { + if (!("ip" in $$source)) { + /** + * @member + * @type {string} + */ + this["ip"] = ""; + } + if (!("pubKey" in $$source)) { + /** + * @member + * @type {string} + */ + this["pubKey"] = ""; + } + if (!("fqdn" in $$source)) { + /** + * @member + * @type {string} + */ + this["fqdn"] = ""; + } + if (!("networks" in $$source)) { + /** + * @member + * @type {string[]} + */ + this["networks"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LocalPeer instance from a string or object. + * @param {any} [$$source = {}] + * @returns {LocalPeer} + */ + static createFrom($$source = {}) { + const $$createField3_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("networks" in $$parsedSource) { + $$parsedSource["networks"] = $$createField3_0($$parsedSource["networks"]); + } + return new LocalPeer(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * LogLevel is a single log-level value the daemon understands ("error", + * "warn", "info", "debug", "trace"). + */ +export class LogLevel { + /** + * Creates a new LogLevel instance. + * @param {Partial} [$$source = {}] - The source object to create the LogLevel. + */ + constructor($$source = {}) { + if (!("level" in $$source)) { + /** + * @member + * @type {string} + */ + this["level"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LogLevel instance from a string or object. + * @param {any} [$$source = {}] + * @returns {LogLevel} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new LogLevel(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * LoginParams carries the fields the UI sets when starting a login. + */ +export class LoginParams { + /** + * Creates a new LoginParams instance. + * @param {Partial} [$$source = {}] - The source object to create the LoginParams. + */ + constructor($$source = {}) { + if (!("profileName" in $$source)) { + /** + * @member + * @type {string} + */ + this["profileName"] = ""; + } + if (!("username" in $$source)) { + /** + * @member + * @type {string} + */ + this["username"] = ""; + } + if (!("managementUrl" in $$source)) { + /** + * @member + * @type {string} + */ + this["managementUrl"] = ""; + } + if (!("setupKey" in $$source)) { + /** + * @member + * @type {string} + */ + this["setupKey"] = ""; + } + if (!("preSharedKey" in $$source)) { + /** + * @member + * @type {string} + */ + this["preSharedKey"] = ""; + } + if (!("hostname" in $$source)) { + /** + * @member + * @type {string} + */ + this["hostname"] = ""; + } + if (!("hint" in $$source)) { + /** + * @member + * @type {string} + */ + this["hint"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LoginParams instance from a string or object. + * @param {any} [$$source = {}] + * @returns {LoginParams} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new LoginParams(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * LoginResult is the daemon's reply to a Login call. + */ +export class LoginResult { + /** + * Creates a new LoginResult instance. + * @param {Partial} [$$source = {}] - The source object to create the LoginResult. + */ + constructor($$source = {}) { + if (!("needsSsoLogin" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["needsSsoLogin"] = false; + } + if (!("userCode" in $$source)) { + /** + * @member + * @type {string} + */ + this["userCode"] = ""; + } + if (!("verificationUri" in $$source)) { + /** + * @member + * @type {string} + */ + this["verificationUri"] = ""; + } + if (!("verificationUriComplete" in $$source)) { + /** + * @member + * @type {string} + */ + this["verificationUriComplete"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LoginResult instance from a string or object. + * @param {any} [$$source = {}] + * @returns {LoginResult} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new LoginResult(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * LogoutParams selects the profile the daemon should log out. + */ +export class LogoutParams { + /** + * Creates a new LogoutParams instance. + * @param {Partial} [$$source = {}] - The source object to create the LogoutParams. + */ + constructor($$source = {}) { + if (!("profileName" in $$source)) { + /** + * @member + * @type {string} + */ + this["profileName"] = ""; + } + if (!("username" in $$source)) { + /** + * @member + * @type {string} + */ + this["username"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LogoutParams instance from a string or object. + * @param {any} [$$source = {}] + * @returns {LogoutParams} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new LogoutParams(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * Network is one routed network the daemon offers to the client. + */ +export class Network { + /** + * Creates a new Network instance. + * @param {Partial} [$$source = {}] - The source object to create the Network. + */ + constructor($$source = {}) { + if (!("id" in $$source)) { + /** + * @member + * @type {string} + */ + this["id"] = ""; + } + if (!("range" in $$source)) { + /** + * @member + * @type {string} + */ + this["range"] = ""; + } + if (!("selected" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["selected"] = false; + } + if (!("domains" in $$source)) { + /** + * @member + * @type {string[]} + */ + this["domains"] = []; + } + if (!("resolvedIps" in $$source)) { + /** + * @member + * @type {{ [_ in string]?: string[] }} + */ + this["resolvedIps"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Network instance from a string or object. + * @param {any} [$$source = {}] + * @returns {Network} + */ + static createFrom($$source = {}) { + const $$createField3_0 = $$createType1; + const $$createField4_0 = $$createType2; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("domains" in $$parsedSource) { + $$parsedSource["domains"] = $$createField3_0($$parsedSource["domains"]); + } + if ("resolvedIps" in $$parsedSource) { + $$parsedSource["resolvedIps"] = $$createField4_0($$parsedSource["resolvedIps"]); + } + return new Network(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * PeerLink is one of the named connections between this peer and its mgmt + * or signal server. + */ +export class PeerLink { + /** + * Creates a new PeerLink instance. + * @param {Partial} [$$source = {}] - The source object to create the PeerLink. + */ + constructor($$source = {}) { + if (!("url" in $$source)) { + /** + * @member + * @type {string} + */ + this["url"] = ""; + } + if (!("connected" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["connected"] = false; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {string | undefined} + */ + this["error"] = undefined; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PeerLink instance from a string or object. + * @param {any} [$$source = {}] + * @returns {PeerLink} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new PeerLink(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * PeerStatus is the frontend-facing shape of a daemon PeerState. Carries + * enough detail for the dashboard's compact peer row plus the on-click + * troubleshooting expansion (ICE candidate types, endpoints, handshake age). + */ +export class PeerStatus { + /** + * Creates a new PeerStatus instance. + * @param {Partial} [$$source = {}] - The source object to create the PeerStatus. + */ + constructor($$source = {}) { + if (!("ip" in $$source)) { + /** + * @member + * @type {string} + */ + this["ip"] = ""; + } + if (!("pubKey" in $$source)) { + /** + * @member + * @type {string} + */ + this["pubKey"] = ""; + } + if (!("connStatus" in $$source)) { + /** + * @member + * @type {string} + */ + this["connStatus"] = ""; + } + if (!("connStatusUpdateUnix" in $$source)) { + /** + * @member + * @type {number} + */ + this["connStatusUpdateUnix"] = 0; + } + if (!("relayed" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["relayed"] = false; + } + if (!("localIceCandidateType" in $$source)) { + /** + * @member + * @type {string} + */ + this["localIceCandidateType"] = ""; + } + if (!("remoteIceCandidateType" in $$source)) { + /** + * @member + * @type {string} + */ + this["remoteIceCandidateType"] = ""; + } + if (!("localIceCandidateEndpoint" in $$source)) { + /** + * @member + * @type {string} + */ + this["localIceCandidateEndpoint"] = ""; + } + if (!("remoteIceCandidateEndpoint" in $$source)) { + /** + * @member + * @type {string} + */ + this["remoteIceCandidateEndpoint"] = ""; + } + if (!("fqdn" in $$source)) { + /** + * @member + * @type {string} + */ + this["fqdn"] = ""; + } + if (!("bytesRx" in $$source)) { + /** + * @member + * @type {number} + */ + this["bytesRx"] = 0; + } + if (!("bytesTx" in $$source)) { + /** + * @member + * @type {number} + */ + this["bytesTx"] = 0; + } + if (!("latencyMs" in $$source)) { + /** + * @member + * @type {number} + */ + this["latencyMs"] = 0; + } + if (!("relayAddress" in $$source)) { + /** + * @member + * @type {string} + */ + this["relayAddress"] = ""; + } + if (!("lastHandshakeUnix" in $$source)) { + /** + * @member + * @type {number} + */ + this["lastHandshakeUnix"] = 0; + } + if (!("rosenpassEnabled" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["rosenpassEnabled"] = false; + } + if (!("networks" in $$source)) { + /** + * @member + * @type {string[]} + */ + this["networks"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PeerStatus instance from a string or object. + * @param {any} [$$source = {}] + * @returns {PeerStatus} + */ + static createFrom($$source = {}) { + const $$createField16_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("networks" in $$parsedSource) { + $$parsedSource["networks"] = $$createField16_0($$parsedSource["networks"]); + } + return new PeerStatus(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * PortInfo carries the destination or translated port for a forwarding rule. + * Exactly one of Port or Range is populated, mirroring the daemon's oneof. + */ +export class PortInfo { + /** + * Creates a new PortInfo instance. + * @param {Partial} [$$source = {}] - The source object to create the PortInfo. + */ + constructor($$source = {}) { + if (/** @type {any} */(false)) { + /** + * @member + * @type {number | null | undefined} + */ + this["port"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {PortRange | null | undefined} + */ + this["range"] = undefined; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PortInfo instance from a string or object. + * @param {any} [$$source = {}] + * @returns {PortInfo} + */ + static createFrom($$source = {}) { + const $$createField1_0 = $$createType4; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("range" in $$parsedSource) { + $$parsedSource["range"] = $$createField1_0($$parsedSource["range"]); + } + return new PortInfo(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * PortRange describes a contiguous port range. Both ends are inclusive. + */ +export class PortRange { + /** + * Creates a new PortRange instance. + * @param {Partial} [$$source = {}] - The source object to create the PortRange. + */ + constructor($$source = {}) { + if (!("start" in $$source)) { + /** + * @member + * @type {number} + */ + this["start"] = 0; + } + if (!("end" in $$source)) { + /** + * @member + * @type {number} + */ + this["end"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PortRange instance from a string or object. + * @param {any} [$$source = {}] + * @returns {PortRange} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new PortRange(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * Profile is one named daemon profile. + */ +export class Profile { + /** + * Creates a new Profile instance. + * @param {Partial} [$$source = {}] - The source object to create the Profile. + */ + constructor($$source = {}) { + if (!("name" in $$source)) { + /** + * @member + * @type {string} + */ + this["name"] = ""; + } + if (!("isActive" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["isActive"] = false; + } + if (!("email" in $$source)) { + /** + * Email is the account address associated with this profile, sourced from + * the per-profile state file written by the CLI after a successful SSO + * login (e.g. ~/Library/Application Support/netbird/default.state.json on + * macOS). The daemon always runs as root, so its getConfigDir() resolves to + * the root home directory and cannot reach the user-owned state file. The + * UI process runs as the logged-in user and can read it directly via + * profilemanager.ProfileManager, which is why the email is fetched here + * instead of being returned by the ListProfiles RPC. + * @member + * @type {string} + */ + this["email"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Profile instance from a string or object. + * @param {any} [$$source = {}] + * @returns {Profile} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new Profile(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * ProfileRef identifies a profile by name+username. + */ +export class ProfileRef { + /** + * Creates a new ProfileRef instance. + * @param {Partial} [$$source = {}] - The source object to create the ProfileRef. + */ + constructor($$source = {}) { + if (!("profileName" in $$source)) { + /** + * @member + * @type {string} + */ + this["profileName"] = ""; + } + if (!("username" in $$source)) { + /** + * @member + * @type {string} + */ + this["username"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ProfileRef instance from a string or object. + * @param {any} [$$source = {}] + * @returns {ProfileRef} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ProfileRef(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * SelectNetworksParams selects which networks to enable / disable. + * All means "every available network" (used by Select-All / Deselect-All buttons); + * Append means "leave the existing selection in place and merge these IDs in". + */ +export class SelectNetworksParams { + /** + * Creates a new SelectNetworksParams instance. + * @param {Partial} [$$source = {}] - The source object to create the SelectNetworksParams. + */ + constructor($$source = {}) { + if (!("networkIds" in $$source)) { + /** + * @member + * @type {string[]} + */ + this["networkIds"] = []; + } + if (!("append" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["append"] = false; + } + if (!("all" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["all"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SelectNetworksParams instance from a string or object. + * @param {any} [$$source = {}] + * @returns {SelectNetworksParams} + */ + static createFrom($$source = {}) { + const $$createField0_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("networkIds" in $$parsedSource) { + $$parsedSource["networkIds"] = $$createField0_0($$parsedSource["networkIds"]); + } + return new SelectNetworksParams(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * SetConfigParams is a partial update — only fields with non-nil pointers + * are sent to the daemon. The frontend uses this to flip individual toggles. + */ +export class SetConfigParams { + /** + * Creates a new SetConfigParams instance. + * @param {Partial} [$$source = {}] - The source object to create the SetConfigParams. + */ + constructor($$source = {}) { + if (!("profileName" in $$source)) { + /** + * @member + * @type {string} + */ + this["profileName"] = ""; + } + if (!("username" in $$source)) { + /** + * @member + * @type {string} + */ + this["username"] = ""; + } + if (!("managementUrl" in $$source)) { + /** + * @member + * @type {string} + */ + this["managementUrl"] = ""; + } + if (!("adminUrl" in $$source)) { + /** + * @member + * @type {string} + */ + this["adminUrl"] = ""; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {string | null | undefined} + */ + this["interfaceName"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {number | null | undefined} + */ + this["wireguardPort"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {number | null | undefined} + */ + this["mtu"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {string | null | undefined} + */ + this["preSharedKey"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["disableAutoConnect"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["serverSshAllowed"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["rosenpassEnabled"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["rosenpassPermissive"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["disableNotifications"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["lazyConnectionEnabled"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["blockInbound"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["networkMonitor"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["disableClientRoutes"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["disableServerRoutes"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["disableDns"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["disableIpv6"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["disableFirewall"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["blockLanAccess"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["enableSshRoot"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["enableSshSftp"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["enableSshLocalPortForwarding"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["enableSshRemotePortForwarding"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | null | undefined} + */ + this["disableSshAuth"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {number | null | undefined} + */ + this["sshJwtCacheTtl"] = undefined; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SetConfigParams instance from a string or object. + * @param {any} [$$source = {}] + * @returns {SetConfigParams} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new SetConfigParams(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * Status is the snapshot the frontend renders on the dashboard. + */ +export class Status { + /** + * Creates a new Status instance. + * @param {Partial} [$$source = {}] - The source object to create the Status. + */ + constructor($$source = {}) { + if (!("status" in $$source)) { + /** + * @member + * @type {string} + */ + this["status"] = ""; + } + if (!("daemonVersion" in $$source)) { + /** + * @member + * @type {string} + */ + this["daemonVersion"] = ""; + } + if (!("management" in $$source)) { + /** + * @member + * @type {PeerLink} + */ + this["management"] = (new PeerLink()); + } + if (!("signal" in $$source)) { + /** + * @member + * @type {PeerLink} + */ + this["signal"] = (new PeerLink()); + } + if (!("local" in $$source)) { + /** + * @member + * @type {LocalPeer} + */ + this["local"] = (new LocalPeer()); + } + if (!("peers" in $$source)) { + /** + * @member + * @type {PeerStatus[]} + */ + this["peers"] = []; + } + if (!("events" in $$source)) { + /** + * @member + * @type {SystemEvent[]} + */ + this["events"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Status instance from a string or object. + * @param {any} [$$source = {}] + * @returns {Status} + */ + static createFrom($$source = {}) { + const $$createField2_0 = $$createType5; + const $$createField3_0 = $$createType5; + const $$createField4_0 = $$createType6; + const $$createField5_0 = $$createType8; + const $$createField6_0 = $$createType10; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("management" in $$parsedSource) { + $$parsedSource["management"] = $$createField2_0($$parsedSource["management"]); + } + if ("signal" in $$parsedSource) { + $$parsedSource["signal"] = $$createField3_0($$parsedSource["signal"]); + } + if ("local" in $$parsedSource) { + $$parsedSource["local"] = $$createField4_0($$parsedSource["local"]); + } + if ("peers" in $$parsedSource) { + $$parsedSource["peers"] = $$createField5_0($$parsedSource["peers"]); + } + if ("events" in $$parsedSource) { + $$parsedSource["events"] = $$createField6_0($$parsedSource["events"]); + } + return new Status(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * SystemEvent is the frontend-facing shape of a daemon SystemEvent. + */ +export class SystemEvent { + /** + * Creates a new SystemEvent instance. + * @param {Partial} [$$source = {}] - The source object to create the SystemEvent. + */ + constructor($$source = {}) { + if (!("id" in $$source)) { + /** + * @member + * @type {string} + */ + this["id"] = ""; + } + if (!("severity" in $$source)) { + /** + * @member + * @type {string} + */ + this["severity"] = ""; + } + if (!("category" in $$source)) { + /** + * @member + * @type {string} + */ + this["category"] = ""; + } + if (!("message" in $$source)) { + /** + * @member + * @type {string} + */ + this["message"] = ""; + } + if (!("userMessage" in $$source)) { + /** + * @member + * @type {string} + */ + this["userMessage"] = ""; + } + if (!("timestamp" in $$source)) { + /** + * @member + * @type {number} + */ + this["timestamp"] = 0; + } + if (!("metadata" in $$source)) { + /** + * @member + * @type {{ [_ in string]?: string }} + */ + this["metadata"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SystemEvent instance from a string or object. + * @param {any} [$$source = {}] + * @returns {SystemEvent} + */ + static createFrom($$source = {}) { + const $$createField6_0 = $$createType11; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("metadata" in $$parsedSource) { + $$parsedSource["metadata"] = $$createField6_0($$parsedSource["metadata"]); + } + return new SystemEvent(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * UpParams selects the profile the daemon should bring up. + */ +export class UpParams { + /** + * Creates a new UpParams instance. + * @param {Partial} [$$source = {}] - The source object to create the UpParams. + */ + constructor($$source = {}) { + if (!("profileName" in $$source)) { + /** + * @member + * @type {string} + */ + this["profileName"] = ""; + } + if (!("username" in $$source)) { + /** + * @member + * @type {string} + */ + this["username"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new UpParams instance from a string or object. + * @param {any} [$$source = {}] + * @returns {UpParams} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new UpParams(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * UpdateAvailable carries the new_version_available metadata. + */ +export class UpdateAvailable { + /** + * Creates a new UpdateAvailable instance. + * @param {Partial} [$$source = {}] - The source object to create the UpdateAvailable. + */ + constructor($$source = {}) { + if (!("version" in $$source)) { + /** + * @member + * @type {string} + */ + this["version"] = ""; + } + if (!("enforced" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["enforced"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new UpdateAvailable instance from a string or object. + * @param {any} [$$source = {}] + * @returns {UpdateAvailable} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new UpdateAvailable(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * UpdateProgress carries the progress_window metadata. + */ +export class UpdateProgress { + /** + * Creates a new UpdateProgress instance. + * @param {Partial} [$$source = {}] - The source object to create the UpdateProgress. + */ + constructor($$source = {}) { + if (!("action" in $$source)) { + /** + * @member + * @type {string} + */ + this["action"] = ""; + } + if (!("version" in $$source)) { + /** + * @member + * @type {string} + */ + this["version"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new UpdateProgress instance from a string or object. + * @param {any} [$$source = {}] + * @returns {UpdateProgress} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new UpdateProgress(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * UpdateResult mirrors TriggerUpdateResponse: Success false carries an error + * message in ErrorMsg. + */ +export class UpdateResult { + /** + * Creates a new UpdateResult instance. + * @param {Partial} [$$source = {}] - The source object to create the UpdateResult. + */ + constructor($$source = {}) { + if (!("success" in $$source)) { + /** + * @member + * @type {boolean} + */ + this["success"] = false; + } + if (!("errorMsg" in $$source)) { + /** + * @member + * @type {string} + */ + this["errorMsg"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new UpdateResult instance from a string or object. + * @param {any} [$$source = {}] + * @returns {UpdateResult} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new UpdateResult(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * WaitSSOParams carries the fields the UI passes to WaitSSOLogin. + */ +export class WaitSSOParams { + /** + * Creates a new WaitSSOParams instance. + * @param {Partial} [$$source = {}] - The source object to create the WaitSSOParams. + */ + constructor($$source = {}) { + if (!("userCode" in $$source)) { + /** + * @member + * @type {string} + */ + this["userCode"] = ""; + } + if (!("hostname" in $$source)) { + /** + * @member + * @type {string} + */ + this["hostname"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new WaitSSOParams instance from a string or object. + * @param {any} [$$source = {}] + * @returns {WaitSSOParams} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new WaitSSOParams(/** @type {Partial} */($$parsedSource)); + } +} + +// Private type creation functions +const $$createType0 = PortInfo.createFrom; +const $$createType1 = $Create.Array($Create.Any); +const $$createType2 = $Create.Map($Create.Any, $$createType1); +const $$createType3 = PortRange.createFrom; +const $$createType4 = $Create.Nullable($$createType3); +const $$createType5 = PeerLink.createFrom; +const $$createType6 = LocalPeer.createFrom; +const $$createType7 = PeerStatus.createFrom; +const $$createType8 = $Create.Array($$createType7); +const $$createType9 = SystemEvent.createFrom; +const $$createType10 = $Create.Array($$createType9); +const $$createType11 = $Create.Map($Create.Any, $Create.Any); diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/models.ts b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/models.ts deleted file mode 100644 index d561338bf..000000000 --- a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/models.ts +++ /dev/null @@ -1,1194 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore: Unused imports -import { Create as $Create } from "@wailsio/runtime"; - -/** - * ActiveProfile is the result of GetActiveProfile. - */ -export class ActiveProfile { - "profileName": string; - "username": string; - - /** Creates a new ActiveProfile instance. */ - constructor($$source: Partial = {}) { - if (!("profileName" in $$source)) { - this["profileName"] = ""; - } - if (!("username" in $$source)) { - this["username"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new ActiveProfile instance from a string or object. - */ - static createFrom($$source: any = {}): ActiveProfile { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new ActiveProfile($$parsedSource as Partial); - } -} - -/** - * Config is the daemon configuration the UI exposes in the settings window. - * Pointer fields mark "set" vs "unset" so the UI can omit a value to keep the - * daemon's current setting (matching SetConfigRequest's optional semantics). - */ -export class Config { - "managementUrl": string; - "adminUrl": string; - "configFile": string; - "logFile": string; - "preSharedKey": string; - "interfaceName": string; - "wireguardPort": number; - "mtu": number; - "disableAutoConnect": boolean; - "serverSshAllowed": boolean; - "rosenpassEnabled": boolean; - "rosenpassPermissive": boolean; - "disableNotifications": boolean; - "lazyConnectionEnabled": boolean; - "blockInbound": boolean; - "networkMonitor": boolean; - "disableClientRoutes": boolean; - "disableServerRoutes": boolean; - "disableDns": boolean; - "disableIpv6": boolean; - "blockLanAccess": boolean; - "enableSshRoot": boolean; - "enableSshSftp": boolean; - "enableSshLocalPortForwarding": boolean; - "enableSshRemotePortForwarding": boolean; - "disableSshAuth": boolean; - "sshJwtCacheTtl": number; - - /** Creates a new Config instance. */ - constructor($$source: Partial = {}) { - if (!("managementUrl" in $$source)) { - this["managementUrl"] = ""; - } - if (!("adminUrl" in $$source)) { - this["adminUrl"] = ""; - } - if (!("configFile" in $$source)) { - this["configFile"] = ""; - } - if (!("logFile" in $$source)) { - this["logFile"] = ""; - } - if (!("preSharedKey" in $$source)) { - this["preSharedKey"] = ""; - } - if (!("interfaceName" in $$source)) { - this["interfaceName"] = ""; - } - if (!("wireguardPort" in $$source)) { - this["wireguardPort"] = 0; - } - if (!("mtu" in $$source)) { - this["mtu"] = 0; - } - if (!("disableAutoConnect" in $$source)) { - this["disableAutoConnect"] = false; - } - if (!("serverSshAllowed" in $$source)) { - this["serverSshAllowed"] = false; - } - if (!("rosenpassEnabled" in $$source)) { - this["rosenpassEnabled"] = false; - } - if (!("rosenpassPermissive" in $$source)) { - this["rosenpassPermissive"] = false; - } - if (!("disableNotifications" in $$source)) { - this["disableNotifications"] = false; - } - if (!("lazyConnectionEnabled" in $$source)) { - this["lazyConnectionEnabled"] = false; - } - if (!("blockInbound" in $$source)) { - this["blockInbound"] = false; - } - if (!("networkMonitor" in $$source)) { - this["networkMonitor"] = false; - } - if (!("disableClientRoutes" in $$source)) { - this["disableClientRoutes"] = false; - } - if (!("disableServerRoutes" in $$source)) { - this["disableServerRoutes"] = false; - } - if (!("disableDns" in $$source)) { - this["disableDns"] = false; - } - if (!("disableIpv6" in $$source)) { - this["disableIpv6"] = false; - } - if (!("blockLanAccess" in $$source)) { - this["blockLanAccess"] = false; - } - if (!("enableSshRoot" in $$source)) { - this["enableSshRoot"] = false; - } - if (!("enableSshSftp" in $$source)) { - this["enableSshSftp"] = false; - } - if (!("enableSshLocalPortForwarding" in $$source)) { - this["enableSshLocalPortForwarding"] = false; - } - if (!("enableSshRemotePortForwarding" in $$source)) { - this["enableSshRemotePortForwarding"] = false; - } - if (!("disableSshAuth" in $$source)) { - this["disableSshAuth"] = false; - } - if (!("sshJwtCacheTtl" in $$source)) { - this["sshJwtCacheTtl"] = 0; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new Config instance from a string or object. - */ - static createFrom($$source: any = {}): Config { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new Config($$parsedSource as Partial); - } -} - -/** - * ConfigParams selects which profile/user to read or write config for. - */ -export class ConfigParams { - "profileName": string; - "username": string; - - /** Creates a new ConfigParams instance. */ - constructor($$source: Partial = {}) { - if (!("profileName" in $$source)) { - this["profileName"] = ""; - } - if (!("username" in $$source)) { - this["username"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new ConfigParams instance from a string or object. - */ - static createFrom($$source: any = {}): ConfigParams { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new ConfigParams($$parsedSource as Partial); - } -} - -/** - * DebugBundleParams configures what the daemon collects when generating a - * debug bundle. - */ -export class DebugBundleParams { - "anonymize": boolean; - "systemInfo": boolean; - "uploadUrl": string; - "logFileCount": number; - - /** Creates a new DebugBundleParams instance. */ - constructor($$source: Partial = {}) { - if (!("anonymize" in $$source)) { - this["anonymize"] = false; - } - if (!("systemInfo" in $$source)) { - this["systemInfo"] = false; - } - if (!("uploadUrl" in $$source)) { - this["uploadUrl"] = ""; - } - if (!("logFileCount" in $$source)) { - this["logFileCount"] = 0; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new DebugBundleParams instance from a string or object. - */ - static createFrom($$source: any = {}): DebugBundleParams { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new DebugBundleParams($$parsedSource as Partial); - } -} - -/** - * DebugBundleResult mirrors DebugBundleResponse — Path is set on local-only - * bundles, UploadedKey on successful uploads, UploadFailureReason on failed - * uploads. - */ -export class DebugBundleResult { - "path": string; - "uploadedKey": string; - "uploadFailureReason": string; - - /** Creates a new DebugBundleResult instance. */ - constructor($$source: Partial = {}) { - if (!("path" in $$source)) { - this["path"] = ""; - } - if (!("uploadedKey" in $$source)) { - this["uploadedKey"] = ""; - } - if (!("uploadFailureReason" in $$source)) { - this["uploadFailureReason"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new DebugBundleResult instance from a string or object. - */ - static createFrom($$source: any = {}): DebugBundleResult { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new DebugBundleResult($$parsedSource as Partial); - } -} - -/** - * Features reports which UI surfaces the daemon has disabled. The Fyne UI uses - * these flags to grey out menu items the operator turned off server-side. - */ -export class Features { - "disableProfiles": boolean; - "disableUpdateSettings": boolean; - "disableNetworks": boolean; - - /** Creates a new Features instance. */ - constructor($$source: Partial = {}) { - if (!("disableProfiles" in $$source)) { - this["disableProfiles"] = false; - } - if (!("disableUpdateSettings" in $$source)) { - this["disableUpdateSettings"] = false; - } - if (!("disableNetworks" in $$source)) { - this["disableNetworks"] = false; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new Features instance from a string or object. - */ - static createFrom($$source: any = {}): Features { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new Features($$parsedSource as Partial); - } -} - -/** - * ForwardingRule is one entry from the daemon's reverse-proxy table — - * what we ship to the frontend's "exposed services" view. - */ -export class ForwardingRule { - "protocol": string; - "destinationPort": PortInfo; - "translatedAddress": string; - "translatedHostname": string; - "translatedPort": PortInfo; - - /** Creates a new ForwardingRule instance. */ - constructor($$source: Partial = {}) { - if (!("protocol" in $$source)) { - this["protocol"] = ""; - } - if (!("destinationPort" in $$source)) { - this["destinationPort"] = (new PortInfo()); - } - if (!("translatedAddress" in $$source)) { - this["translatedAddress"] = ""; - } - if (!("translatedHostname" in $$source)) { - this["translatedHostname"] = ""; - } - if (!("translatedPort" in $$source)) { - this["translatedPort"] = (new PortInfo()); - } - - Object.assign(this, $$source); - } - - /** - * Creates a new ForwardingRule instance from a string or object. - */ - static createFrom($$source: any = {}): ForwardingRule { - const $$createField1_0 = $$createType0; - const $$createField4_0 = $$createType0; - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - if ("destinationPort" in $$parsedSource) { - $$parsedSource["destinationPort"] = $$createField1_0($$parsedSource["destinationPort"]); - } - if ("translatedPort" in $$parsedSource) { - $$parsedSource["translatedPort"] = $$createField4_0($$parsedSource["translatedPort"]); - } - return new ForwardingRule($$parsedSource as Partial); - } -} - -/** - * LocalPeer mirrors LocalPeerState — what this client looks like on the mesh. - */ -export class LocalPeer { - "ip": string; - "pubKey": string; - "fqdn": string; - "networks": string[]; - - /** Creates a new LocalPeer instance. */ - constructor($$source: Partial = {}) { - if (!("ip" in $$source)) { - this["ip"] = ""; - } - if (!("pubKey" in $$source)) { - this["pubKey"] = ""; - } - if (!("fqdn" in $$source)) { - this["fqdn"] = ""; - } - if (!("networks" in $$source)) { - this["networks"] = []; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new LocalPeer instance from a string or object. - */ - static createFrom($$source: any = {}): LocalPeer { - const $$createField3_0 = $$createType1; - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - if ("networks" in $$parsedSource) { - $$parsedSource["networks"] = $$createField3_0($$parsedSource["networks"]); - } - return new LocalPeer($$parsedSource as Partial); - } -} - -/** - * LogLevel is a single log-level value the daemon understands ("error", - * "warn", "info", "debug", "trace"). - */ -export class LogLevel { - "level": string; - - /** Creates a new LogLevel instance. */ - constructor($$source: Partial = {}) { - if (!("level" in $$source)) { - this["level"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new LogLevel instance from a string or object. - */ - static createFrom($$source: any = {}): LogLevel { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new LogLevel($$parsedSource as Partial); - } -} - -/** - * LoginParams carries the fields the UI sets when starting a login. - */ -export class LoginParams { - "profileName": string; - "username": string; - "managementUrl": string; - "setupKey": string; - "preSharedKey": string; - "hostname": string; - "hint": string; - - /** Creates a new LoginParams instance. */ - constructor($$source: Partial = {}) { - if (!("profileName" in $$source)) { - this["profileName"] = ""; - } - if (!("username" in $$source)) { - this["username"] = ""; - } - if (!("managementUrl" in $$source)) { - this["managementUrl"] = ""; - } - if (!("setupKey" in $$source)) { - this["setupKey"] = ""; - } - if (!("preSharedKey" in $$source)) { - this["preSharedKey"] = ""; - } - if (!("hostname" in $$source)) { - this["hostname"] = ""; - } - if (!("hint" in $$source)) { - this["hint"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new LoginParams instance from a string or object. - */ - static createFrom($$source: any = {}): LoginParams { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new LoginParams($$parsedSource as Partial); - } -} - -/** - * LoginResult is the daemon's reply to a Login call. - */ -export class LoginResult { - "needsSsoLogin": boolean; - "userCode": string; - "verificationUri": string; - "verificationUriComplete": string; - - /** Creates a new LoginResult instance. */ - constructor($$source: Partial = {}) { - if (!("needsSsoLogin" in $$source)) { - this["needsSsoLogin"] = false; - } - if (!("userCode" in $$source)) { - this["userCode"] = ""; - } - if (!("verificationUri" in $$source)) { - this["verificationUri"] = ""; - } - if (!("verificationUriComplete" in $$source)) { - this["verificationUriComplete"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new LoginResult instance from a string or object. - */ - static createFrom($$source: any = {}): LoginResult { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new LoginResult($$parsedSource as Partial); - } -} - -/** - * LogoutParams selects the profile the daemon should log out. - */ -export class LogoutParams { - "profileName": string; - "username": string; - - /** Creates a new LogoutParams instance. */ - constructor($$source: Partial = {}) { - if (!("profileName" in $$source)) { - this["profileName"] = ""; - } - if (!("username" in $$source)) { - this["username"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new LogoutParams instance from a string or object. - */ - static createFrom($$source: any = {}): LogoutParams { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new LogoutParams($$parsedSource as Partial); - } -} - -/** - * Network is one routed network the daemon offers to the client. - */ -export class Network { - "id": string; - "range": string; - "selected": boolean; - "domains": string[]; - "resolvedIps": { [_ in string]?: string[] }; - - /** Creates a new Network instance. */ - constructor($$source: Partial = {}) { - if (!("id" in $$source)) { - this["id"] = ""; - } - if (!("range" in $$source)) { - this["range"] = ""; - } - if (!("selected" in $$source)) { - this["selected"] = false; - } - if (!("domains" in $$source)) { - this["domains"] = []; - } - if (!("resolvedIps" in $$source)) { - this["resolvedIps"] = {}; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new Network instance from a string or object. - */ - static createFrom($$source: any = {}): Network { - const $$createField3_0 = $$createType1; - const $$createField4_0 = $$createType2; - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - if ("domains" in $$parsedSource) { - $$parsedSource["domains"] = $$createField3_0($$parsedSource["domains"]); - } - if ("resolvedIps" in $$parsedSource) { - $$parsedSource["resolvedIps"] = $$createField4_0($$parsedSource["resolvedIps"]); - } - return new Network($$parsedSource as Partial); - } -} - -/** - * PeerLink is one of the named connections between this peer and its mgmt - * or signal server. - */ -export class PeerLink { - "url": string; - "connected": boolean; - "error"?: string; - - /** Creates a new PeerLink instance. */ - constructor($$source: Partial = {}) { - if (!("url" in $$source)) { - this["url"] = ""; - } - if (!("connected" in $$source)) { - this["connected"] = false; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new PeerLink instance from a string or object. - */ - static createFrom($$source: any = {}): PeerLink { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new PeerLink($$parsedSource as Partial); - } -} - -/** - * PeerStatus is the frontend-facing shape of a daemon PeerState. Carries - * enough detail for the dashboard's compact peer row plus the on-click - * troubleshooting expansion (ICE candidate types, endpoints, handshake age). - */ -export class PeerStatus { - "ip": string; - "pubKey": string; - "connStatus": string; - "connStatusUpdateUnix": number; - "relayed": boolean; - "localIceCandidateType": string; - "remoteIceCandidateType": string; - "localIceCandidateEndpoint": string; - "remoteIceCandidateEndpoint": string; - "fqdn": string; - "bytesRx": number; - "bytesTx": number; - "latencyMs": number; - "relayAddress": string; - "lastHandshakeUnix": number; - "rosenpassEnabled": boolean; - "networks": string[]; - - /** Creates a new PeerStatus instance. */ - constructor($$source: Partial = {}) { - if (!("ip" in $$source)) { - this["ip"] = ""; - } - if (!("pubKey" in $$source)) { - this["pubKey"] = ""; - } - if (!("connStatus" in $$source)) { - this["connStatus"] = ""; - } - if (!("connStatusUpdateUnix" in $$source)) { - this["connStatusUpdateUnix"] = 0; - } - if (!("relayed" in $$source)) { - this["relayed"] = false; - } - if (!("localIceCandidateType" in $$source)) { - this["localIceCandidateType"] = ""; - } - if (!("remoteIceCandidateType" in $$source)) { - this["remoteIceCandidateType"] = ""; - } - if (!("localIceCandidateEndpoint" in $$source)) { - this["localIceCandidateEndpoint"] = ""; - } - if (!("remoteIceCandidateEndpoint" in $$source)) { - this["remoteIceCandidateEndpoint"] = ""; - } - if (!("fqdn" in $$source)) { - this["fqdn"] = ""; - } - if (!("bytesRx" in $$source)) { - this["bytesRx"] = 0; - } - if (!("bytesTx" in $$source)) { - this["bytesTx"] = 0; - } - if (!("latencyMs" in $$source)) { - this["latencyMs"] = 0; - } - if (!("relayAddress" in $$source)) { - this["relayAddress"] = ""; - } - if (!("lastHandshakeUnix" in $$source)) { - this["lastHandshakeUnix"] = 0; - } - if (!("rosenpassEnabled" in $$source)) { - this["rosenpassEnabled"] = false; - } - if (!("networks" in $$source)) { - this["networks"] = []; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new PeerStatus instance from a string or object. - */ - static createFrom($$source: any = {}): PeerStatus { - const $$createField16_0 = $$createType1; - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - if ("networks" in $$parsedSource) { - $$parsedSource["networks"] = $$createField16_0($$parsedSource["networks"]); - } - return new PeerStatus($$parsedSource as Partial); - } -} - -/** - * PortInfo carries the destination or translated port for a forwarding rule. - * Exactly one of Port or Range is populated, mirroring the daemon's oneof. - */ -export class PortInfo { - "port"?: number | null; - "range"?: PortRange | null; - - /** Creates a new PortInfo instance. */ - constructor($$source: Partial = {}) { - - Object.assign(this, $$source); - } - - /** - * Creates a new PortInfo instance from a string or object. - */ - static createFrom($$source: any = {}): PortInfo { - const $$createField1_0 = $$createType4; - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - if ("range" in $$parsedSource) { - $$parsedSource["range"] = $$createField1_0($$parsedSource["range"]); - } - return new PortInfo($$parsedSource as Partial); - } -} - -/** - * PortRange describes a contiguous port range. Both ends are inclusive. - */ -export class PortRange { - "start": number; - "end": number; - - /** Creates a new PortRange instance. */ - constructor($$source: Partial = {}) { - if (!("start" in $$source)) { - this["start"] = 0; - } - if (!("end" in $$source)) { - this["end"] = 0; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new PortRange instance from a string or object. - */ - static createFrom($$source: any = {}): PortRange { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new PortRange($$parsedSource as Partial); - } -} - -/** - * Profile is one named daemon profile. - */ -export class Profile { - "name": string; - "isActive": boolean; - - /** - * Email is the account address associated with this profile, sourced from - * the per-profile state file written by the CLI after a successful SSO - * login (e.g. ~/Library/Application Support/netbird/default.state.json on - * macOS). The daemon always runs as root, so its getConfigDir() resolves to - * the root home directory and cannot reach the user-owned state file. The - * UI process runs as the logged-in user and can read it directly via - * profilemanager.ProfileManager, which is why the email is fetched here - * instead of being returned by the ListProfiles RPC. - */ - "email": string; - - /** Creates a new Profile instance. */ - constructor($$source: Partial = {}) { - if (!("name" in $$source)) { - this["name"] = ""; - } - if (!("isActive" in $$source)) { - this["isActive"] = false; - } - if (!("email" in $$source)) { - this["email"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new Profile instance from a string or object. - */ - static createFrom($$source: any = {}): Profile { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new Profile($$parsedSource as Partial); - } -} - -/** - * ProfileRef identifies a profile by name+username. - */ -export class ProfileRef { - "profileName": string; - "username": string; - - /** Creates a new ProfileRef instance. */ - constructor($$source: Partial = {}) { - if (!("profileName" in $$source)) { - this["profileName"] = ""; - } - if (!("username" in $$source)) { - this["username"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new ProfileRef instance from a string or object. - */ - static createFrom($$source: any = {}): ProfileRef { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new ProfileRef($$parsedSource as Partial); - } -} - -/** - * SelectNetworksParams selects which networks to enable / disable. - * All means "every available network" (used by Select-All / Deselect-All buttons); - * Append means "leave the existing selection in place and merge these IDs in". - */ -export class SelectNetworksParams { - "networkIds": string[]; - "append": boolean; - "all": boolean; - - /** Creates a new SelectNetworksParams instance. */ - constructor($$source: Partial = {}) { - if (!("networkIds" in $$source)) { - this["networkIds"] = []; - } - if (!("append" in $$source)) { - this["append"] = false; - } - if (!("all" in $$source)) { - this["all"] = false; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new SelectNetworksParams instance from a string or object. - */ - static createFrom($$source: any = {}): SelectNetworksParams { - const $$createField0_0 = $$createType1; - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - if ("networkIds" in $$parsedSource) { - $$parsedSource["networkIds"] = $$createField0_0($$parsedSource["networkIds"]); - } - return new SelectNetworksParams($$parsedSource as Partial); - } -} - -/** - * SetConfigParams is a partial update — only fields with non-nil pointers - * are sent to the daemon. The frontend uses this to flip individual toggles. - */ -export class SetConfigParams { - "profileName": string; - "username": string; - "managementUrl": string; - "adminUrl": string; - "interfaceName"?: string | null; - "wireguardPort"?: number | null; - "mtu"?: number | null; - "preSharedKey"?: string | null; - "disableAutoConnect"?: boolean | null; - "serverSshAllowed"?: boolean | null; - "rosenpassEnabled"?: boolean | null; - "rosenpassPermissive"?: boolean | null; - "disableNotifications"?: boolean | null; - "lazyConnectionEnabled"?: boolean | null; - "blockInbound"?: boolean | null; - "networkMonitor"?: boolean | null; - "disableClientRoutes"?: boolean | null; - "disableServerRoutes"?: boolean | null; - "disableDns"?: boolean | null; - "disableIpv6"?: boolean | null; - "disableFirewall"?: boolean | null; - "blockLanAccess"?: boolean | null; - "enableSshRoot"?: boolean | null; - "enableSshSftp"?: boolean | null; - "enableSshLocalPortForwarding"?: boolean | null; - "enableSshRemotePortForwarding"?: boolean | null; - "disableSshAuth"?: boolean | null; - "sshJwtCacheTtl"?: number | null; - - /** Creates a new SetConfigParams instance. */ - constructor($$source: Partial = {}) { - if (!("profileName" in $$source)) { - this["profileName"] = ""; - } - if (!("username" in $$source)) { - this["username"] = ""; - } - if (!("managementUrl" in $$source)) { - this["managementUrl"] = ""; - } - if (!("adminUrl" in $$source)) { - this["adminUrl"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new SetConfigParams instance from a string or object. - */ - static createFrom($$source: any = {}): SetConfigParams { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new SetConfigParams($$parsedSource as Partial); - } -} - -/** - * Status is the snapshot the frontend renders on the dashboard. - */ -export class Status { - "status": string; - "daemonVersion": string; - "management": PeerLink; - "signal": PeerLink; - "local": LocalPeer; - "peers": PeerStatus[]; - "events": SystemEvent[]; - - /** Creates a new Status instance. */ - constructor($$source: Partial = {}) { - if (!("status" in $$source)) { - this["status"] = ""; - } - if (!("daemonVersion" in $$source)) { - this["daemonVersion"] = ""; - } - if (!("management" in $$source)) { - this["management"] = (new PeerLink()); - } - if (!("signal" in $$source)) { - this["signal"] = (new PeerLink()); - } - if (!("local" in $$source)) { - this["local"] = (new LocalPeer()); - } - if (!("peers" in $$source)) { - this["peers"] = []; - } - if (!("events" in $$source)) { - this["events"] = []; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new Status instance from a string or object. - */ - static createFrom($$source: any = {}): Status { - const $$createField2_0 = $$createType5; - const $$createField3_0 = $$createType5; - const $$createField4_0 = $$createType6; - const $$createField5_0 = $$createType8; - const $$createField6_0 = $$createType10; - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - if ("management" in $$parsedSource) { - $$parsedSource["management"] = $$createField2_0($$parsedSource["management"]); - } - if ("signal" in $$parsedSource) { - $$parsedSource["signal"] = $$createField3_0($$parsedSource["signal"]); - } - if ("local" in $$parsedSource) { - $$parsedSource["local"] = $$createField4_0($$parsedSource["local"]); - } - if ("peers" in $$parsedSource) { - $$parsedSource["peers"] = $$createField5_0($$parsedSource["peers"]); - } - if ("events" in $$parsedSource) { - $$parsedSource["events"] = $$createField6_0($$parsedSource["events"]); - } - return new Status($$parsedSource as Partial); - } -} - -/** - * SystemEvent is the frontend-facing shape of a daemon SystemEvent. - */ -export class SystemEvent { - "id": string; - "severity": string; - "category": string; - "message": string; - "userMessage": string; - "timestamp": number; - "metadata": { [_ in string]?: string }; - - /** Creates a new SystemEvent instance. */ - constructor($$source: Partial = {}) { - if (!("id" in $$source)) { - this["id"] = ""; - } - if (!("severity" in $$source)) { - this["severity"] = ""; - } - if (!("category" in $$source)) { - this["category"] = ""; - } - if (!("message" in $$source)) { - this["message"] = ""; - } - if (!("userMessage" in $$source)) { - this["userMessage"] = ""; - } - if (!("timestamp" in $$source)) { - this["timestamp"] = 0; - } - if (!("metadata" in $$source)) { - this["metadata"] = {}; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new SystemEvent instance from a string or object. - */ - static createFrom($$source: any = {}): SystemEvent { - const $$createField6_0 = $$createType11; - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - if ("metadata" in $$parsedSource) { - $$parsedSource["metadata"] = $$createField6_0($$parsedSource["metadata"]); - } - return new SystemEvent($$parsedSource as Partial); - } -} - -/** - * UpParams selects the profile the daemon should bring up. - */ -export class UpParams { - "profileName": string; - "username": string; - - /** Creates a new UpParams instance. */ - constructor($$source: Partial = {}) { - if (!("profileName" in $$source)) { - this["profileName"] = ""; - } - if (!("username" in $$source)) { - this["username"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new UpParams instance from a string or object. - */ - static createFrom($$source: any = {}): UpParams { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new UpParams($$parsedSource as Partial); - } -} - -/** - * UpdateAvailable carries the new_version_available metadata. - */ -export class UpdateAvailable { - "version": string; - "enforced": boolean; - - /** Creates a new UpdateAvailable instance. */ - constructor($$source: Partial = {}) { - if (!("version" in $$source)) { - this["version"] = ""; - } - if (!("enforced" in $$source)) { - this["enforced"] = false; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new UpdateAvailable instance from a string or object. - */ - static createFrom($$source: any = {}): UpdateAvailable { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new UpdateAvailable($$parsedSource as Partial); - } -} - -/** - * UpdateProgress carries the progress_window metadata. - */ -export class UpdateProgress { - "action": string; - "version": string; - - /** Creates a new UpdateProgress instance. */ - constructor($$source: Partial = {}) { - if (!("action" in $$source)) { - this["action"] = ""; - } - if (!("version" in $$source)) { - this["version"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new UpdateProgress instance from a string or object. - */ - static createFrom($$source: any = {}): UpdateProgress { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new UpdateProgress($$parsedSource as Partial); - } -} - -/** - * UpdateResult mirrors TriggerUpdateResponse: Success false carries an error - * message in ErrorMsg. - */ -export class UpdateResult { - "success": boolean; - "errorMsg": string; - - /** Creates a new UpdateResult instance. */ - constructor($$source: Partial = {}) { - if (!("success" in $$source)) { - this["success"] = false; - } - if (!("errorMsg" in $$source)) { - this["errorMsg"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new UpdateResult instance from a string or object. - */ - static createFrom($$source: any = {}): UpdateResult { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new UpdateResult($$parsedSource as Partial); - } -} - -/** - * WaitSSOParams carries the fields the UI passes to WaitSSOLogin. - */ -export class WaitSSOParams { - "userCode": string; - "hostname": string; - - /** Creates a new WaitSSOParams instance. */ - constructor($$source: Partial = {}) { - if (!("userCode" in $$source)) { - this["userCode"] = ""; - } - if (!("hostname" in $$source)) { - this["hostname"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new WaitSSOParams instance from a string or object. - */ - static createFrom($$source: any = {}): WaitSSOParams { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new WaitSSOParams($$parsedSource as Partial); - } -} - -// Private type creation functions -const $$createType0 = PortInfo.createFrom; -const $$createType1 = $Create.Array($Create.Any); -const $$createType2 = $Create.Map($Create.Any, $$createType1); -const $$createType3 = PortRange.createFrom; -const $$createType4 = $Create.Nullable($$createType3); -const $$createType5 = PeerLink.createFrom; -const $$createType6 = LocalPeer.createFrom; -const $$createType7 = PeerStatus.createFrom; -const $$createType8 = $Create.Array($$createType7); -const $$createType9 = SystemEvent.createFrom; -const $$createType10 = $Create.Array($$createType9); -const $$createType11 = $Create.Map($Create.Any, $Create.Any); diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/networks.ts b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/networks.js similarity index 64% rename from client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/networks.ts rename to client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/networks.js index 82a8d870f..b0b8fe666 100644 --- a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/networks.ts +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/networks.js @@ -1,3 +1,4 @@ +// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT @@ -14,17 +15,28 @@ import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Cr // @ts-ignore: Unused imports import * as $models from "./models.js"; -export function Deselect(p: $models.SelectNetworksParams): $CancellablePromise { +/** + * @param {$models.SelectNetworksParams} p + * @returns {$CancellablePromise} + */ +export function Deselect(p) { return $Call.ByID(3382210947, p); } -export function List(): $CancellablePromise<$models.Network[]> { - return $Call.ByID(1550842096).then(($result: any) => { +/** + * @returns {$CancellablePromise<$models.Network[]>} + */ +export function List() { + return $Call.ByID(1550842096).then(/** @type {($result: any) => any} */(($result) => { return $$createType1($result); - }); + })); } -export function Select(p: $models.SelectNetworksParams): $CancellablePromise { +/** + * @param {$models.SelectNetworksParams} p + * @returns {$CancellablePromise} + */ +export function Select(p) { return $Call.ByID(1339338400, p); } diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/peers.ts b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/peers.js similarity index 85% rename from client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/peers.ts rename to client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/peers.js index f70d8cc7c..7b41f718d 100644 --- a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/peers.ts +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/peers.js @@ -1,3 +1,4 @@ +// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT @@ -17,11 +18,12 @@ import * as $models from "./models.js"; /** * Get returns the current daemon status snapshot. + * @returns {$CancellablePromise<$models.Status>} */ -export function Get(): $CancellablePromise<$models.Status> { - return $Call.ByID(3266051360).then(($result: any) => { +export function Get() { + return $Call.ByID(3266051360).then(/** @type {($result: any) => any} */(($result) => { return $$createType0($result); - }); + })); } /** @@ -37,8 +39,9 @@ export function Get(): $CancellablePromise<$models.Status> { * * Safe to call once at boot; both loops self-restart on stream errors * via exponential backoff. + * @returns {$CancellablePromise} */ -export function Watch(): $CancellablePromise { +export function Watch() { return $Call.ByID(2799871735); } diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/profiles.ts b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/profiles.js similarity index 57% rename from client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/profiles.ts rename to client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/profiles.js index 9a4577e0b..5a207d6ca 100644 --- a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/profiles.ts +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/profiles.js @@ -1,3 +1,4 @@ +// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT @@ -14,35 +15,55 @@ import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Cr // @ts-ignore: Unused imports import * as $models from "./models.js"; -export function Add(p: $models.ProfileRef): $CancellablePromise { +/** + * @param {$models.ProfileRef} p + * @returns {$CancellablePromise} + */ +export function Add(p) { return $Call.ByID(722930578, p); } -export function GetActive(): $CancellablePromise<$models.ActiveProfile> { - return $Call.ByID(3458449443).then(($result: any) => { +/** + * @returns {$CancellablePromise<$models.ActiveProfile>} + */ +export function GetActive() { + return $Call.ByID(3458449443).then(/** @type {($result: any) => any} */(($result) => { return $$createType0($result); - }); + })); } -export function List(username: string): $CancellablePromise<$models.Profile[]> { - return $Call.ByID(3702185167, username).then(($result: any) => { +/** + * @param {string} username + * @returns {$CancellablePromise<$models.Profile[]>} + */ +export function List(username) { + return $Call.ByID(3702185167, username).then(/** @type {($result: any) => any} */(($result) => { return $$createType2($result); - }); + })); } -export function Remove(p: $models.ProfileRef): $CancellablePromise { +/** + * @param {$models.ProfileRef} p + * @returns {$CancellablePromise} + */ +export function Remove(p) { return $Call.ByID(2365690315, p); } -export function Switch(p: $models.ProfileRef): $CancellablePromise { +/** + * @param {$models.ProfileRef} p + * @returns {$CancellablePromise} + */ +export function Switch(p) { return $Call.ByID(3209858855, p); } /** * Username returns the OS username the daemon expects for profile lookups. * The frontend calls this once at boot and reuses the result. + * @returns {$CancellablePromise} */ -export function Username(): $CancellablePromise { +export function Username() { return $Call.ByID(262345647); } diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/profileswitcher.js b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/profileswitcher.js new file mode 100644 index 000000000..6020c6fc2 --- /dev/null +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/profileswitcher.js @@ -0,0 +1,41 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * ProfileSwitcher encapsulates the full profile-switching reconnect policy so + * both the tray and the React frontend use identical logic. + * + * Reconnect policy: + * + * ┌─────────────────┬──────────────────────┬────────────────────────────────────┐ + * │ Previous status │ Action │ Rationale │ + * ├─────────────────┼──────────────────────┼────────────────────────────────────┤ + * │ Connected │ Switch + Down + Up │ Reconnect with the new profile. │ + * │ Connecting │ Switch + Down + Up │ Stop old retry loop, restart. │ + * │ NeedsLogin │ Switch + Down │ Clear stale error; user logs in. │ + * │ LoginFailed │ Switch + Down │ Clear stale error; user logs in. │ + * │ SessionExpired │ Switch + Down │ Clear stale error; user logs in. │ + * │ Idle │ Switch only │ User chose offline; don't connect. │ + * └─────────────────┴──────────────────────┴────────────────────────────────────┘ + * @module + */ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as $models from "./models.js"; + +/** + * SwitchActive switches to the named profile applying the reconnect policy. + * It returns after the Switch RPC completes so the caller can refresh its UI + * immediately; Down and Up run in a background goroutine. + * @param {$models.ProfileRef} p + * @returns {$CancellablePromise} + */ +export function SwitchActive(p) { + return $Call.ByID(4025913103, p); +} diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/settings.ts b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/settings.js similarity index 59% rename from client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/settings.ts rename to client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/settings.js index bc7b7b2d1..9d5bf6e77 100644 --- a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/settings.ts +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/settings.js @@ -1,3 +1,4 @@ +// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT @@ -14,19 +15,30 @@ import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Cr // @ts-ignore: Unused imports import * as $models from "./models.js"; -export function GetConfig(p: $models.ConfigParams): $CancellablePromise<$models.Config> { - return $Call.ByID(59246988, p).then(($result: any) => { +/** + * @param {$models.ConfigParams} p + * @returns {$CancellablePromise<$models.Config>} + */ +export function GetConfig(p) { + return $Call.ByID(59246988, p).then(/** @type {($result: any) => any} */(($result) => { return $$createType0($result); - }); + })); } -export function GetFeatures(): $CancellablePromise<$models.Features> { - return $Call.ByID(2056724965).then(($result: any) => { +/** + * @returns {$CancellablePromise<$models.Features>} + */ +export function GetFeatures() { + return $Call.ByID(2056724965).then(/** @type {($result: any) => any} */(($result) => { return $$createType1($result); - }); + })); } -export function SetConfig(p: $models.SetConfigParams): $CancellablePromise { +/** + * @param {$models.SetConfigParams} p + * @returns {$CancellablePromise} + */ +export function SetConfig(p) { return $Call.ByID(26939944, p); } diff --git a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/update.ts b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/update.js similarity index 69% rename from client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/update.ts rename to client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/update.js index c2bdd85e9..668d0d670 100644 --- a/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/update.ts +++ b/client/ui/frontend/bindings/github.com/netbirdio/netbird/client/ui/services/update.js @@ -1,3 +1,4 @@ +// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT @@ -14,10 +15,13 @@ import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Cr // @ts-ignore: Unused imports import * as $models from "./models.js"; -export function GetInstallerResult(): $CancellablePromise<$models.UpdateResult> { - return $Call.ByID(2533624807).then(($result: any) => { +/** + * @returns {$CancellablePromise<$models.UpdateResult>} + */ +export function GetInstallerResult() { + return $Call.ByID(2533624807).then(/** @type {($result: any) => any} */(($result) => { return $$createType0($result); - }); + })); } /** @@ -26,15 +30,19 @@ export function GetInstallerResult(): $CancellablePromise<$models.UpdateResult> * Fyne UI's app.Quit() in showInstallerResult. Schedules the actual exit * off the calling goroutine so the JS-side caller's response can return * before the runtime tears down. + * @returns {$CancellablePromise} */ -export function Quit(): $CancellablePromise { +export function Quit() { return $Call.ByID(409602657); } -export function Trigger(): $CancellablePromise<$models.UpdateResult> { - return $Call.ByID(166270378).then(($result: any) => { +/** + * @returns {$CancellablePromise<$models.UpdateResult>} + */ +export function Trigger() { + return $Call.ByID(166270378).then(/** @type {($result: any) => any} */(($result) => { return $$createType0($result); - }); + })); } // Private type creation functions diff --git a/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.ts b/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.js similarity index 100% rename from client/ui/frontend/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.ts rename to client/ui/frontend/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.js diff --git a/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/index.ts b/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/index.js similarity index 96% rename from client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/index.ts rename to client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/index.js index 71eda3bb9..e2c2be532 100644 --- a/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/index.ts +++ b/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/index.js @@ -1,3 +1,4 @@ +// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT diff --git a/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/models.js b/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/models.js new file mode 100644 index 000000000..6cdc2516f --- /dev/null +++ b/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/models.js @@ -0,0 +1,192 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +/** + * NotificationAction represents an action button for a notification. + */ +export class NotificationAction { + /** + * Creates a new NotificationAction instance. + * @param {Partial} [$$source = {}] - The source object to create the NotificationAction. + */ + constructor($$source = {}) { + if (/** @type {any} */(false)) { + /** + * @member + * @type {string | undefined} + */ + this["id"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {string | undefined} + */ + this["title"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * (macOS-specific) + * @member + * @type {boolean | undefined} + */ + this["destructive"] = undefined; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new NotificationAction instance from a string or object. + * @param {any} [$$source = {}] + * @returns {NotificationAction} + */ + static createFrom($$source = {}) { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new NotificationAction(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * NotificationCategory groups actions for notifications. + */ +export class NotificationCategory { + /** + * Creates a new NotificationCategory instance. + * @param {Partial} [$$source = {}] - The source object to create the NotificationCategory. + */ + constructor($$source = {}) { + if (/** @type {any} */(false)) { + /** + * @member + * @type {string | undefined} + */ + this["id"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {NotificationAction[] | undefined} + */ + this["actions"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {boolean | undefined} + */ + this["hasReplyField"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {string | undefined} + */ + this["replyPlaceholder"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {string | undefined} + */ + this["replyButtonTitle"] = undefined; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new NotificationCategory instance from a string or object. + * @param {any} [$$source = {}] + * @returns {NotificationCategory} + */ + static createFrom($$source = {}) { + const $$createField1_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("actions" in $$parsedSource) { + $$parsedSource["actions"] = $$createField1_0($$parsedSource["actions"]); + } + return new NotificationCategory(/** @type {Partial} */($$parsedSource)); + } +} + +/** + * NotificationOptions contains configuration for a notification + */ +export class NotificationOptions { + /** + * Creates a new NotificationOptions instance. + * @param {Partial} [$$source = {}] - The source object to create the NotificationOptions. + */ + constructor($$source = {}) { + if (!("id" in $$source)) { + /** + * @member + * @type {string} + */ + this["id"] = ""; + } + if (!("title" in $$source)) { + /** + * @member + * @type {string} + */ + this["title"] = ""; + } + if (/** @type {any} */(false)) { + /** + * (macOS and Linux only) + * @member + * @type {string | undefined} + */ + this["subtitle"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {string | undefined} + */ + this["body"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {string | undefined} + */ + this["categoryId"] = undefined; + } + if (/** @type {any} */(false)) { + /** + * @member + * @type {{ [_ in string]?: any } | undefined} + */ + this["data"] = undefined; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new NotificationOptions instance from a string or object. + * @param {any} [$$source = {}] + * @returns {NotificationOptions} + */ + static createFrom($$source = {}) { + const $$createField5_0 = $$createType2; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("data" in $$parsedSource) { + $$parsedSource["data"] = $$createField5_0($$parsedSource["data"]); + } + return new NotificationOptions(/** @type {Partial} */($$parsedSource)); + } +} + +// Private type creation functions +const $$createType0 = NotificationAction.createFrom; +const $$createType1 = $Create.Array($$createType0); +const $$createType2 = $Create.Map($Create.Any, $Create.Any); diff --git a/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/models.ts b/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/models.ts deleted file mode 100644 index 3fbcb8270..000000000 --- a/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/models.ts +++ /dev/null @@ -1,107 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore: Unused imports -import { Create as $Create } from "@wailsio/runtime"; - -/** - * NotificationAction represents an action button for a notification. - */ -export class NotificationAction { - "id"?: string; - "title"?: string; - - /** - * (macOS-specific) - */ - "destructive"?: boolean; - - /** Creates a new NotificationAction instance. */ - constructor($$source: Partial = {}) { - - Object.assign(this, $$source); - } - - /** - * Creates a new NotificationAction instance from a string or object. - */ - static createFrom($$source: any = {}): NotificationAction { - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - return new NotificationAction($$parsedSource as Partial); - } -} - -/** - * NotificationCategory groups actions for notifications. - */ -export class NotificationCategory { - "id"?: string; - "actions"?: NotificationAction[]; - "hasReplyField"?: boolean; - "replyPlaceholder"?: string; - "replyButtonTitle"?: string; - - /** Creates a new NotificationCategory instance. */ - constructor($$source: Partial = {}) { - - Object.assign(this, $$source); - } - - /** - * Creates a new NotificationCategory instance from a string or object. - */ - static createFrom($$source: any = {}): NotificationCategory { - const $$createField1_0 = $$createType1; - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - if ("actions" in $$parsedSource) { - $$parsedSource["actions"] = $$createField1_0($$parsedSource["actions"]); - } - return new NotificationCategory($$parsedSource as Partial); - } -} - -/** - * NotificationOptions contains configuration for a notification - */ -export class NotificationOptions { - "id": string; - "title": string; - - /** - * (macOS and Linux only) - */ - "subtitle"?: string; - "body"?: string; - "categoryId"?: string; - "data"?: { [_ in string]?: any }; - - /** Creates a new NotificationOptions instance. */ - constructor($$source: Partial = {}) { - if (!("id" in $$source)) { - this["id"] = ""; - } - if (!("title" in $$source)) { - this["title"] = ""; - } - - Object.assign(this, $$source); - } - - /** - * Creates a new NotificationOptions instance from a string or object. - */ - static createFrom($$source: any = {}): NotificationOptions { - const $$createField5_0 = $$createType2; - let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; - if ("data" in $$parsedSource) { - $$parsedSource["data"] = $$createField5_0($$parsedSource["data"]); - } - return new NotificationOptions($$parsedSource as Partial); - } -} - -// Private type creation functions -const $$createType0 = NotificationAction.createFrom; -const $$createType1 = $Create.Array($$createType0); -const $$createType2 = $Create.Map($Create.Any, $Create.Any); diff --git a/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/notificationservice.js b/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/notificationservice.js new file mode 100644 index 000000000..e16f96b80 --- /dev/null +++ b/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/notificationservice.js @@ -0,0 +1,101 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * Service represents the notifications service + * @module + */ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as $models from "./models.js"; + +/** + * @returns {$CancellablePromise} + */ +export function CheckNotificationAuthorization() { + return $Call.ByID(2216952893); +} + +/** + * @param {$models.NotificationCategory} category + * @returns {$CancellablePromise} + */ +export function RegisterNotificationCategory(category) { + return $Call.ByID(2917562919, category); +} + +/** + * @returns {$CancellablePromise} + */ +export function RemoveAllDeliveredNotifications() { + return $Call.ByID(3956282340); +} + +/** + * @returns {$CancellablePromise} + */ +export function RemoveAllPendingNotifications() { + return $Call.ByID(108821341); +} + +/** + * @param {string} identifier + * @returns {$CancellablePromise} + */ +export function RemoveDeliveredNotification(identifier) { + return $Call.ByID(975691940, identifier); +} + +/** + * @param {string} identifier + * @returns {$CancellablePromise} + */ +export function RemoveNotification(identifier) { + return $Call.ByID(3966653866, identifier); +} + +/** + * @param {string} categoryID + * @returns {$CancellablePromise} + */ +export function RemoveNotificationCategory(categoryID) { + return $Call.ByID(2032615554, categoryID); +} + +/** + * @param {string} identifier + * @returns {$CancellablePromise} + */ +export function RemovePendingNotification(identifier) { + return $Call.ByID(3729049703, identifier); +} + +/** + * Public methods that delegate to the implementation. + * @returns {$CancellablePromise} + */ +export function RequestNotificationAuthorization() { + return $Call.ByID(3933442950); +} + +/** + * @param {$models.NotificationOptions} options + * @returns {$CancellablePromise} + */ +export function SendNotification(options) { + return $Call.ByID(3968228732, options); +} + +/** + * @param {$models.NotificationOptions} options + * @returns {$CancellablePromise} + */ +export function SendNotificationWithActions(options) { + return $Call.ByID(1886542847, options); +} diff --git a/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/notificationservice.ts b/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/notificationservice.ts deleted file mode 100644 index 859f3570f..000000000 --- a/client/ui/frontend/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/notificationservice.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -/** - * Service represents the notifications service - * @module - */ - -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore: Unused imports -import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; - -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore: Unused imports -import * as $models from "./models.js"; - -export function CheckNotificationAuthorization(): $CancellablePromise { - return $Call.ByID(2216952893); -} - -export function RegisterNotificationCategory(category: $models.NotificationCategory): $CancellablePromise { - return $Call.ByID(2917562919, category); -} - -export function RemoveAllDeliveredNotifications(): $CancellablePromise { - return $Call.ByID(3956282340); -} - -export function RemoveAllPendingNotifications(): $CancellablePromise { - return $Call.ByID(108821341); -} - -export function RemoveDeliveredNotification(identifier: string): $CancellablePromise { - return $Call.ByID(975691940, identifier); -} - -export function RemoveNotification(identifier: string): $CancellablePromise { - return $Call.ByID(3966653866, identifier); -} - -export function RemoveNotificationCategory(categoryID: string): $CancellablePromise { - return $Call.ByID(2032615554, categoryID); -} - -export function RemovePendingNotification(identifier: string): $CancellablePromise { - return $Call.ByID(3729049703, identifier); -} - -/** - * Public methods that delegate to the implementation. - */ -export function RequestNotificationAuthorization(): $CancellablePromise { - return $Call.ByID(3933442950); -} - -export function SendNotification(options: $models.NotificationOptions): $CancellablePromise { - return $Call.ByID(3968228732, options); -} - -export function SendNotificationWithActions(options: $models.NotificationOptions): $CancellablePromise { - return $Call.ByID(1886542847, options); -} diff --git a/client/ui/frontend/src/pages/Profiles.tsx b/client/ui/frontend/src/pages/Profiles.tsx index d6be78890..5f66e7c20 100644 --- a/client/ui/frontend/src/pages/Profiles.tsx +++ b/client/ui/frontend/src/pages/Profiles.tsx @@ -3,6 +3,7 @@ import { Plus, RefreshCw } from "lucide-react"; import { Profiles as ProfilesSvc, Connection, + ProfileSwitcher, } from "../../bindings/github.com/netbirdio/netbird/client/ui/services"; import type { Profile } from "../../bindings/github.com/netbirdio/netbird/client/ui/services/models.js"; import { Button } from "../components/Button"; @@ -33,8 +34,7 @@ export default function Profiles() { const select = async (name: string) => { try { - await ProfilesSvc.Switch({ profileName: name, username }); - await Connection.Up({ profileName: name, username }); + await ProfileSwitcher.SwitchActive({ profileName: name, username }); await refresh(); } catch (e) { setError(String(e)); diff --git a/client/ui/main.go b/client/ui/main.go index 6fc38a971..f9437be52 100644 --- a/client/ui/main.go +++ b/client/ui/main.go @@ -103,6 +103,7 @@ func main() { peers := services.NewPeers(conn, app.Event) update := services.NewUpdate(conn) notifier := notifications.New() + profileSwitcher := services.NewProfileSwitcher(profiles, connection, peers) app.RegisterService(application.NewService(connection)) app.RegisterService(application.NewService(settings)) @@ -113,6 +114,7 @@ func main() { app.RegisterService(application.NewService(update)) app.RegisterService(application.NewService(peers)) app.RegisterService(application.NewService(notifier)) + app.RegisterService(application.NewService(profileSwitcher)) window := app.Window.NewWithOptions(application.WebviewWindowOptions{ Title: "NetBird", @@ -146,12 +148,13 @@ func main() { startStatusNotifierWatcher() tray = NewTray(app, window, TrayServices{ - Connection: connection, - Settings: settings, - Profiles: profiles, - Peers: peers, - Notifier: notifier, - Update: update, + Connection: connection, + Settings: settings, + Profiles: profiles, + Peers: peers, + Notifier: notifier, + Update: update, + ProfileSwitcher: profileSwitcher, }) listenForShowSignal(context.Background(), tray) diff --git a/client/ui/services/peers.go b/client/ui/services/peers.go index b658cf9aa..0adeeba25 100644 --- a/client/ui/services/peers.go +++ b/client/ui/services/peers.go @@ -37,6 +37,15 @@ const ( // permission, etc.). Real daemon statuses come straight from // internal.Status* — none of those collide with this label. StatusDaemonUnavailable = "DaemonUnavailable" + + // Daemon connection status strings — mirror internal.Status* in + // client/internal/state.go. + StatusConnected = "Connected" + StatusConnecting = "Connecting" + StatusIdle = "Idle" + StatusNeedsLogin = "NeedsLogin" + StatusLoginFailed = "LoginFailed" + StatusSessionExpired = "SessionExpired" ) // Emitter is what peers.Watch needs from the host application: a simple diff --git a/client/ui/services/profileswitcher.go b/client/ui/services/profileswitcher.go new file mode 100644 index 000000000..a63364ec7 --- /dev/null +++ b/client/ui/services/profileswitcher.go @@ -0,0 +1,82 @@ +//go:build !android && !ios && !freebsd && !js + +package services + +import ( + "context" + "fmt" + "strings" + + log "github.com/sirupsen/logrus" +) + +// ProfileSwitcher encapsulates the full profile-switching reconnect policy so +// both the tray and the React frontend use identical logic. +// +// Reconnect policy: +// +// ┌─────────────────┬──────────────────────┬────────────────────────────────────┐ +// │ Previous status │ Action │ Rationale │ +// ├─────────────────┼──────────────────────┼────────────────────────────────────┤ +// │ Connected │ Switch + Down + Up │ Reconnect with the new profile. │ +// │ Connecting │ Switch + Down + Up │ Stop old retry loop, restart. │ +// │ NeedsLogin │ Switch + Down │ Clear stale error; user logs in. │ +// │ LoginFailed │ Switch + Down │ Clear stale error; user logs in. │ +// │ SessionExpired │ Switch + Down │ Clear stale error; user logs in. │ +// │ Idle │ Switch only │ User chose offline; don't connect. │ +// └─────────────────┴──────────────────────┴────────────────────────────────────┘ +type ProfileSwitcher struct { + profiles *Profiles + connection *Connection + peers *Peers +} + +// NewProfileSwitcher creates a ProfileSwitcher backed by the given services. +func NewProfileSwitcher(profiles *Profiles, connection *Connection, peers *Peers) *ProfileSwitcher { + return &ProfileSwitcher{profiles: profiles, connection: connection, peers: peers} +} + +// SwitchActive switches to the named profile applying the reconnect policy. +// It returns after the Switch RPC completes so the caller can refresh its UI +// immediately; Down and Up run in a background goroutine. +func (s *ProfileSwitcher) SwitchActive(ctx context.Context, p ProfileRef) error { + prevStatus := "" + if st, err := s.peers.Get(ctx); err == nil { + prevStatus = st.Status + } else { + log.Warnf("profileswitcher: get status: %v", err) + } + + wasActive := strings.EqualFold(prevStatus, StatusConnected) || + strings.EqualFold(prevStatus, StatusConnecting) + needsDown := wasActive || + strings.EqualFold(prevStatus, StatusNeedsLogin) || + strings.EqualFold(prevStatus, StatusLoginFailed) || + strings.EqualFold(prevStatus, StatusSessionExpired) + + log.Infof("profileswitcher: switch profile=%q prevStatus=%q wasActive=%v needsDown=%v", + p.ProfileName, prevStatus, wasActive, needsDown) + + if err := s.profiles.Switch(ctx, p); err != nil { + return fmt.Errorf("switch profile %q: %w", p.ProfileName, err) + } + + go func() { + bgCtx := context.Background() + if needsDown { + if err := s.connection.Down(bgCtx); err != nil { + log.Errorf("profileswitcher: Down: %v", err) + } + } + if wasActive { + if err := s.connection.Up(bgCtx, UpParams{ + ProfileName: p.ProfileName, + Username: p.Username, + }); err != nil { + log.Errorf("profileswitcher: Up %s: %v", p.ProfileName, err) + } + } + }() + + return nil +} diff --git a/client/ui/tray.go b/client/ui/tray.go index 9e5dc702d..63938ba17 100644 --- a/client/ui/tray.go +++ b/client/ui/tray.go @@ -75,25 +75,9 @@ const ( notifyIDTrayError = "netbird-tray-error" notifyIDSessionExpired = "netbird-session-expired" - // Daemon status strings mirroring internal.Status* — kept in sync - // with client/internal/state.go. - statusConnected = "Connected" - statusConnecting = "Connecting" - statusIdle = "Idle" - statusError = "Error" - // Daemon status string for an SSO session that has expired and needs - // re-authentication. Mirrors internal.StatusSessionExpired. - statusSessionExpired = "SessionExpired" - // statusNeedsLogin is what the daemon publishes before the user has - // completed an SSO authentication on this profile. Mirrors - // internal.StatusNeedsLogin. - statusNeedsLogin = "NeedsLogin" - // statusLoginFailed is what the daemon publishes when a login attempt - // failed with a non-auth error (management unreachable, init error, - // etc.). The CLI groups it with NeedsLogin/SessionExpired and prompts - // the user to run "netbird up", so we mirror that here. Mirrors - // internal.StatusLoginFailed. - statusLoginFailed = "LoginFailed" + // statusError is a tray-only synthetic label used for the error icon; + // it does not come from the daemon and is not exported. + statusError = "Error" // External URLs. urlGitHubRepo = "https://github.com/netbirdio/netbird" @@ -108,12 +92,13 @@ const ( // linter's parameter-count threshold and so adding another service later // is a one-line struct change instead of a NewTray signature break. type TrayServices struct { - Connection *services.Connection - Settings *services.Settings - Profiles *services.Profiles - Peers *services.Peers - Notifier *notifications.NotificationService - Update *services.Update + Connection *services.Connection + Settings *services.Settings + Profiles *services.Profiles + Peers *services.Peers + Notifier *notifications.NotificationService + Update *services.Update + ProfileSwitcher *services.ProfileSwitcher } type Tray struct { @@ -466,15 +451,15 @@ func (t *Tray) onUpdateProgress(ev *application.CustomEvent) { // otherwise spam Shell_NotifyIcon and the log. func (t *Tray) applyStatus(st services.Status) { t.mu.Lock() - connected := strings.EqualFold(st.Status, statusConnected) + connected := strings.EqualFold(st.Status, services.StatusConnected) iconChanged := connected != t.connected || st.Status != t.lastStatus // Detect the transition into SessionExpired: the daemon emits the // state on every Status snapshot for as long as the session stays // expired, so without this guard we would re-fire the notification // on every push. Mirrors the legacy Fyne client's sendNotification // flag in onSessionExpire. - sessionExpiredEnter := strings.EqualFold(st.Status, statusSessionExpired) && - !strings.EqualFold(t.lastStatus, statusSessionExpired) + sessionExpiredEnter := strings.EqualFold(st.Status, services.StatusSessionExpired) && + !strings.EqualFold(t.lastStatus, services.StatusSessionExpired) daemonVersionChanged := st.DaemonVersion != "" && st.DaemonVersion != t.lastDaemonVersion t.connected = connected t.lastStatus = st.Status @@ -489,11 +474,11 @@ func (t *Tray) applyStatus(st services.Status) { if iconChanged { t.applyIcon() - needsLogin := strings.EqualFold(st.Status, statusNeedsLogin) || - strings.EqualFold(st.Status, statusSessionExpired) || - strings.EqualFold(st.Status, statusLoginFailed) + needsLogin := strings.EqualFold(st.Status, services.StatusNeedsLogin) || + strings.EqualFold(st.Status, services.StatusSessionExpired) || + strings.EqualFold(st.Status, services.StatusLoginFailed) daemonUnavailable := strings.EqualFold(st.Status, services.StatusDaemonUnavailable) - connecting := strings.EqualFold(st.Status, statusConnecting) + connecting := strings.EqualFold(st.Status, services.StatusConnecting) if t.statusItem != nil { // When the daemon needs re-authentication the status row turns // into the actionable Login entry — Connect would only fail. @@ -503,7 +488,7 @@ func (t *Tray) applyStatus(st services.Status) { switch { case daemonUnavailable: label = menuStatusDaemonUnavailable - case strings.EqualFold(st.Status, statusIdle): + case strings.EqualFold(st.Status, services.StatusIdle): label = menuStatusDisconnected } t.statusItem.SetLabel(label) @@ -603,14 +588,14 @@ func (t *Tray) applyStatusIndicator(status string) { func statusIndicatorBitmap(status string) []byte { switch { - case strings.EqualFold(status, statusConnected): + case strings.EqualFold(status, services.StatusConnected): return iconMenuDotConnected - case strings.EqualFold(status, statusConnecting): + case strings.EqualFold(status, services.StatusConnecting): return iconMenuDotConnecting - case strings.EqualFold(status, statusNeedsLogin), - strings.EqualFold(status, statusSessionExpired): + case strings.EqualFold(status, services.StatusNeedsLogin), + strings.EqualFold(status, services.StatusSessionExpired): return iconMenuDotLogin - case strings.EqualFold(status, statusLoginFailed), + case strings.EqualFold(status, services.StatusLoginFailed), strings.EqualFold(status, statusError): return iconMenuDotError case strings.EqualFold(status, services.StatusDaemonUnavailable): @@ -648,12 +633,12 @@ func (t *Tray) iconForState() (icon, dark []byte) { statusLabel := t.lastStatus t.mu.Unlock() - connecting := strings.EqualFold(statusLabel, statusConnecting) + connecting := strings.EqualFold(statusLabel, services.StatusConnecting) errored := strings.EqualFold(statusLabel, statusError) || strings.EqualFold(statusLabel, services.StatusDaemonUnavailable) - needsLogin := strings.EqualFold(statusLabel, statusNeedsLogin) || - strings.EqualFold(statusLabel, statusSessionExpired) || - strings.EqualFold(statusLabel, statusLoginFailed) + needsLogin := strings.EqualFold(statusLabel, services.StatusNeedsLogin) || + strings.EqualFold(statusLabel, services.StatusSessionExpired) || + strings.EqualFold(statusLabel, services.StatusLoginFailed) if runtime.GOOS == "darwin" { switch { @@ -799,78 +784,30 @@ func (t *Tray) loadProfiles() { } } -// switchProfile runs the daemon RPC in a goroutine so the menu click -// returns immediately, then reloads the submenu to move the checkmark. -// -// Reconnect policy by previous daemon status: -// -// ┌─────────────────┬──────────────────────┬────────────────────────────────────┐ -// │ Previous status │ Tray action │ Rationale │ -// ├─────────────────┼──────────────────────┼────────────────────────────────────┤ -// │ Connected │ Switch + Down + Up │ Reconnect with the new profile. │ -// │ Connecting │ Switch + Down + Up │ Stop the retry loop still dialing │ -// │ │ │ the old management server, then │ -// │ │ │ restart with new config. │ -// │ Idle │ Switch only │ User chose to be offline; don't │ -// │ │ │ silently flip the daemon online. │ -// │ NeedsLogin │ Switch + Down │ Clean stale error state so the new │ -// │ LoginFailed │ Switch + Down │ profile starts from Idle. User │ -// │ SessionExpired │ Switch + Down │ initiates login manually. │ -// └─────────────────┴──────────────────────┴────────────────────────────────────┘ -// -// Rule of thumb: auto-reconnect only when the daemon was actively trying to be -// online (Connected or Connecting). Login-error states get Down so stale errors -// are cleared, but no Up — the user initiates login on the new profile manually. +// switchProfile delegates to ProfileSwitcher.SwitchActive in a goroutine so +// the menu click returns immediately. The menu is refreshed as soon as the +// Switch RPC completes (before Down/Up finishes in the background). func (t *Tray) switchProfile(name string) { - t.mu.Lock() - prevStatus := t.lastStatus - t.mu.Unlock() - wasActive := strings.EqualFold(prevStatus, statusConnected) || - strings.EqualFold(prevStatus, statusConnecting) - needsDown := wasActive || - strings.EqualFold(prevStatus, statusNeedsLogin) || - strings.EqualFold(prevStatus, statusLoginFailed) || - strings.EqualFold(prevStatus, statusSessionExpired) - go func() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() username, err := t.svc.Profiles.Username() if err != nil { - log.Errorf("get current user: %v", err) + log.Errorf("tray switchProfile: get current user: %v", err) return } - log.Infof("tray switchProfile: sending SwitchProfile RPC profile=%q user=%q prevStatus=%q wasActive=%v needsDown=%v", - name, username, prevStatus, wasActive, needsDown) - if err := t.svc.Profiles.Switch(ctx, services.ProfileRef{ + if err := t.svc.ProfileSwitcher.SwitchActive(ctx, services.ProfileRef{ ProfileName: name, Username: username, }); err != nil { - log.Errorf("tray switchProfile: SwitchProfile RPC failed profile=%q err=%v", name, err) + log.Errorf("tray switchProfile: %v", err) t.notifyError(fmt.Sprintf("Failed to switch to %s", name)) return } - log.Infof("tray switchProfile: SwitchProfile RPC succeeded profile=%q", name) - - if needsDown { - log.Infof("tray switchProfile: calling Down to clean up previous state (%s)", prevStatus) - if err := t.svc.Connection.Down(ctx); err != nil { - log.Errorf("tray switchProfile: Down failed: %v", err) - } - } - if wasActive { - // Bring the connection back up against the new profile's management server. - log.Infof("tray switchProfile: was active (%s), reconnecting with new profile %q", prevStatus, name) - if err := t.svc.Connection.Up(ctx, services.UpParams{ - ProfileName: name, - Username: username, - }); err != nil { - log.Errorf("tray switchProfile: Up failed: %v", err) - t.notifyError(fmt.Sprintf("Failed to reconnect with %s", name)) - } - } - + // SwitchActive returns after the Switch RPC — active_profile.json is + // updated; Down/Up run in the background. Refresh menu now so the + // checkmark moves immediately. t.loadProfiles() }() }