From 28f58ed465d0284d5b3d82ffec8cea8a7238df40 Mon Sep 17 00:00:00 2001 From: Carlo <1778532+cdcme@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:54:30 -0500 Subject: [PATCH] Fix iOS/iPadOS self-service UI routing and database errors (#35739) Fixes #35722 --- .../DeviceUserError/DeviceUserError.tsx | 4 ++++ .../layouts/UnsupportedScreenSize/helpers.ts | 8 ++++++- .../details/DeviceUserPage/DeviceUserPage.tsx | 21 ++++++++++++++++--- server/datastore/mysql/software.go | 5 +++-- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/frontend/components/DeviceUserError/DeviceUserError.tsx b/frontend/components/DeviceUserError/DeviceUserError.tsx index 2c86bfba6e..7625128196 100644 --- a/frontend/components/DeviceUserError/DeviceUserError.tsx +++ b/frontend/components/DeviceUserError/DeviceUserError.tsx @@ -10,17 +10,21 @@ interface IDeviceUserErrorProps { /** Modifies error message for iPhone/iPad/Android */ isMobileDevice?: boolean; isAuthenticationError?: boolean; + platform?: string; } const DeviceUserError = ({ isMobileView = false, isMobileDevice = false, isAuthenticationError = false, + platform, }: IDeviceUserErrorProps): JSX.Element => { const wrapperClassnames = classNames(baseClass, { [`${baseClass}__mobile-view`]: isMobileView, }); + const isIOSIPadOS = platform === "ios" || platform === "ipados"; + // Default: "Something went wrong" let headerContent: React.ReactNode = ( <> diff --git a/frontend/layouts/UnsupportedScreenSize/helpers.ts b/frontend/layouts/UnsupportedScreenSize/helpers.ts index 58c6f717e5..29e78048aa 100644 --- a/frontend/layouts/UnsupportedScreenSize/helpers.ts +++ b/frontend/layouts/UnsupportedScreenSize/helpers.ts @@ -4,8 +4,14 @@ const deviceSelfServiceRegex = new RegExp( `^${url_prefix}/device/[^/]+/self-service/?$` ); +// iOS/iPadOS base device route should support low-width screens +const deviceIOSIPadOSRegex = new RegExp(`^${url_prefix}/device/[^/]+/?$`); + // Define paths that will not show the unsupported screen overlay -const lowWidthSupportedPathsRegex = [deviceSelfServiceRegex]; +const lowWidthSupportedPathsRegex = [ + deviceSelfServiceRegex, + deviceIOSIPadOSRegex, +]; const shouldShowUnsupportedScreen = (locationPathname: string) => !lowWidthSupportedPathsRegex.some((regex) => regex.test(locationPathname)); diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index 200a688b5e..f5fe4612ca 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -343,6 +343,7 @@ const DeviceUserPage = ({ } = dupResponse || {}; const isPremiumTier = license?.tier === "premium"; const isAppleHost = isAppleDevice(host?.platform); + const isIOSIPadOS = host?.platform === "ios" || host?.platform === "ipados"; const isSetupExperienceSoftwareEnabledPlatform = isLinuxLike(host?.platform || "") || host?.platform === "windows" || @@ -595,9 +596,22 @@ const DeviceUserPage = ({ ); } - if (isMobileView) { + // iOS/iPadOS devices or narrow screens should show mobile UI + const shouldShowMobileUI = isIOSIPadOS || isMobileView; + + if (shouldShowMobileUI) { + // Force redirect to self-service route for iOS/iPadOS devices + if ( + isIOSIPadOS && + !location.pathname.includes("/self-service") && + hasSelfService + ) { + router.replace(PATHS.DEVICE_USER_DETAILS_SELF_SERVICE(deviceAuthToken)); + return ; + } + // Render the simplified mobile version - // Currently only available for self-service page + // For iOS/iPadOS and narrow screen devices return (
@@ -612,7 +626,7 @@ const DeviceUserPage = ({ isHostDetailsPolling={showRefetchSpinner} hostSoftwareUpdatedAt={host.software_updated_at} hostDisplayName={host?.hostname || ""} - isMobileView={isMobileView} + isMobileView={shouldShowMobileUI} />
@@ -872,6 +886,7 @@ const DeviceUserPage = ({ isMobileView={isMobileView} isMobileDevice={isMobileDevice} isAuthenticationError={!!isAuthenticationError} + platform={host?.platform} /> ) : (
{renderDeviceUserPage()}
diff --git a/server/datastore/mysql/software.go b/server/datastore/mysql/software.go index c1c12f509e..51cfe7a8b7 100644 --- a/server/datastore/mysql/software.go +++ b/server/datastore/mysql/software.go @@ -2538,6 +2538,7 @@ type hostSoftware struct { SoftwareID *uint `db:"software_id"` SoftwareSource *string `db:"software_source"` SoftwareExtensionFor *string `db:"software_extension_for"` + UpgradeCode *string `db:"upgrade_code"` InstallerID *uint `db:"installer_id"` PackageSelfService *bool `db:"package_self_service"` PackageName *string `db:"package_name"` @@ -2574,7 +2575,6 @@ type hostSoftware struct { } func hostInstalledSoftware(ds *Datastore, ctx context.Context, hostID uint) ([]*hostSoftware, error) { - // TODO(jacob)?: software_titles.upgrade_code AS upgrade_code, installedSoftwareStmt := ` SELECT software_titles.id AS id, @@ -2583,7 +2583,8 @@ func hostInstalledSoftware(ds *Datastore, ctx context.Context, hostID uint) ([]* software.source AS software_source, software.extension_for AS software_extension_for, software.version AS version, - software.bundle_identifier AS bundle_identifier + software.bundle_identifier AS bundle_identifier, + software_titles.upgrade_code AS upgrade_code FROM host_software INNER JOIN