@@ -24,6 +24,7 @@ import {
2424 MachineInfo ,
2525} from "@app/services/updateService" ;
2626import { Z_INDEX_OVER_CONFIG_MODAL } from "@app/styles/zIndex" ;
27+ import { openExternal } from "@app/platform/openExternal" ;
2728import WarningAmberIcon from "@mui/icons-material/WarningAmber" ;
2829import OpenInNewIcon from "@mui/icons-material/OpenInNew" ;
2930import DownloadIcon from "@mui/icons-material/Download" ;
@@ -36,6 +37,19 @@ import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
3637import ExpandMoreIcon from "@mui/icons-material/ExpandMore" ;
3738import ExpandLessIcon from "@mui/icons-material/ExpandLess" ;
3839
40+ /**
41+ * Best-effort Tauri detection without importing `@tauri-apps/api` into the
42+ * core bundle (which must stay runnable on plain web). Tauri v2 injects
43+ * `__TAURI_INTERNALS__` before any user code runs. Mirrors UpdateStartupPopup.
44+ */
45+ function isRunningInTauri ( ) : boolean {
46+ if ( typeof window === "undefined" ) return false ;
47+ return (
48+ typeof ( window as unknown as { __TAURI_INTERNALS__ ?: unknown } )
49+ . __TAURI_INTERNALS__ !== "undefined"
50+ ) ;
51+ }
52+
3953export type DesktopInstallState =
4054 | "idle"
4155 | "downloading"
@@ -197,6 +211,20 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
197211 onClose ( ) ;
198212 } ;
199213
214+ // External links (release notes, migration guides, download fallback) use
215+ // real anchors so they open a new tab on web. Inside Tauri the webview traps
216+ // target="_blank", so on desktop we intercept and hand the URL to the OS
217+ // browser via the platform seam. stopPropagation keeps links nested in the
218+ // clickable version-history rows from toggling the row.
219+ const handleExternalLink =
220+ ( url : string ) => ( e : React . MouseEvent < HTMLElement > ) => {
221+ e . stopPropagation ( ) ;
222+ if ( isRunningInTauri ( ) ) {
223+ e . preventDefault ( ) ;
224+ void openExternal ( url ) ;
225+ }
226+ } ;
227+
200228 // Sort versions newest first, skip the latest (already shown in header)
201229 const sortedVersions = fullUpdateInfo ?. new_versions
202230 ? [ ...fullUpdateInfo . new_versions ] . sort ( ( a , b ) =>
@@ -323,11 +351,25 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
323351 </ Group >
324352 </ Box >
325353
326- { /* Priority badge + recommendation — compact single line */ }
354+ { /* Priority badge + recommendation — compact single line. When the
355+ update contains breaking changes we surface a compact inline
356+ chip here rather than a separate full-width orange banner; the
357+ specific per-version detail lives in Version History below. */ }
327358 < Group gap = "sm" align = "center" px = { 4 } >
328359 < Badge color = { priorityColor } variant = "filled" size = "lg" radius = "sm" >
329360 { getPriorityLabel ( updateSummary . max_priority ) }
330361 </ Badge >
362+ { updateSummary . any_breaking && (
363+ < Badge
364+ color = "orange"
365+ variant = "light"
366+ size = "lg"
367+ radius = "sm"
368+ leftSection = { < WarningAmberIcon style = { { fontSize : 14 } } /> }
369+ >
370+ { t ( "update.breaking" , "Breaking" ) }
371+ </ Badge >
372+ ) }
331373 < Text size = "sm" c = "dimmed" style = { { flex : 1 } } >
332374 { updateSummary . recommended_action ||
333375 t (
@@ -362,6 +404,7 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
362404 href = { WINDOWS_INSTALL_DOCS_URL }
363405 target = "_blank"
364406 rel = "noopener noreferrer"
407+ onClick = { handleExternalLink ( WINDOWS_INSTALL_DOCS_URL ) }
365408 >
366409 { t (
367410 "desktopUpdate.blocked.docsLink" ,
@@ -402,6 +445,9 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
402445 component = "a"
403446 href = { `https://github.com/Stirling-Tools/Stirling-PDF/releases/tag/v${ updateSummary . latest_version } ` }
404447 target = "_blank"
448+ onClick = { handleExternalLink (
449+ `https://github.com/Stirling-Tools/Stirling-PDF/releases/tag/v${ updateSummary . latest_version } ` ,
450+ ) }
405451 c = "blue"
406452 style = { {
407453 textDecoration : "none" ,
@@ -418,6 +464,9 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
418464 component = "a"
419465 href = "https://github.com/Stirling-Tools/Stirling-PDF/releases"
420466 target = "_blank"
467+ onClick = { handleExternalLink (
468+ "https://github.com/Stirling-Tools/Stirling-PDF/releases" ,
469+ ) }
421470 c = "dimmed"
422471 style = { {
423472 textDecoration : "none" ,
@@ -433,25 +482,6 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
433482 </ Group >
434483 </ Box >
435484
436- { /* Breaking changes */ }
437- { updateSummary . any_breaking && (
438- < Alert
439- variant = "light"
440- color = "orange"
441- radius = "md"
442- icon = { < WarningAmberIcon style = { { fontSize : 18 } } /> }
443- title = { t (
444- "update.breakingChangesDetected" ,
445- "Breaking Changes Detected" ,
446- ) }
447- >
448- { t (
449- "update.breakingChangesMessage" ,
450- "Some versions contain breaking changes. Please review the migration guides below before updating." ,
451- ) }
452- </ Alert >
453- ) }
454-
455485 { /* Migration guides */ }
456486 { updateSummary . migration_guides &&
457487 updateSummary . migration_guides . length > 0 && (
@@ -505,6 +535,7 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
505535 component = "a"
506536 href = { guide . url }
507537 target = "_blank"
538+ onClick = { handleExternalLink ( guide . url ) }
508539 variant = "default"
509540 size = "xs"
510541 rightSection = {
@@ -603,7 +634,9 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
603634 variant = "subtle"
604635 size = "xs"
605636 px = { 6 }
606- onClick = { ( e ) => e . stopPropagation ( ) }
637+ onClick = { handleExternalLink (
638+ `https://github.com/Stirling-Tools/Stirling-PDF/releases/tag/v${ version . version } ` ,
639+ ) }
607640 rightSection = {
608641 < OpenInNewIcon style = { { fontSize : 11 } } />
609642 }
@@ -673,6 +706,10 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
673706 version . compatibility . migration_guide_url
674707 }
675708 target = "_blank"
709+ onClick = { handleExternalLink (
710+ version . compatibility
711+ . migration_guide_url ?? "" ,
712+ ) }
676713 variant = "light"
677714 color = "orange"
678715 size = "xs"
@@ -844,6 +881,7 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
844881 component = "a"
845882 href = { downloadUrl }
846883 target = "_blank"
884+ onClick = { handleExternalLink ( downloadUrl ) }
847885 variant = "default"
848886 radius = "md"
849887 size = "md"
@@ -884,6 +922,7 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
884922 component = "a"
885923 href = { downloadUrl }
886924 target = "_blank"
925+ onClick = { handleExternalLink ( downloadUrl ) }
887926 color = "blue"
888927 radius = "md"
889928 size = "lg"
0 commit comments