From 7b658de727fc4424b07642bbe59a49348d618a78 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Sun, 24 Nov 2024 21:26:47 +0100 Subject: [PATCH] [chore] added a beat saber version outdated warning in the version view --- assets/jsons/translations/de.json | 9 +++++ assets/jsons/translations/en.json | 9 +++++ assets/jsons/translations/es.json | 9 +++++ assets/jsons/translations/fr.json | 9 +++++ assets/jsons/translations/ja.json | 9 +++++ assets/jsons/translations/ko.json | 9 +++++ assets/jsons/translations/ru.json | 9 +++++ assets/jsons/translations/zh-tw.json | 9 +++++ assets/jsons/translations/zh.json | 9 +++++ .../bs-version-outdated-modal.component.tsx | 2 +- .../components/svgs/bsm-icon.component.tsx | 7 +++- .../svgs/icons/warning-icon.component.tsx | 9 +++++ .../slides/launch/launch-slide.component.tsx | 28 +++++++++++++--- .../available-versions-list.components.tsx | 11 +++---- .../pages/version-viewer.component.tsx | 33 +++++++++++++++++++ .../services/bs-version-manager.service.ts | 4 +++ src/shared/helpers/semver.helpers.ts | 8 +++++ 17 files changed, 170 insertions(+), 13 deletions(-) create mode 100644 src/renderer/components/svgs/icons/warning-icon.component.tsx create mode 100644 src/shared/helpers/semver.helpers.ts diff --git a/assets/jsons/translations/de.json b/assets/jsons/translations/de.json index 36e6e2edb..4117e8177 100644 --- a/assets/jsons/translations/de.json +++ b/assets/jsons/translations/de.json @@ -38,6 +38,7 @@ "desktop-description": "Auf diese Weise kannst du WASD und die Maus verwenden, um im Spiel durch das Menü zu navigieren. Dies erleichtert das Testen erheblich, da du dein Headset nicht aufsetzen musst!", "debug": "Debug Modus", "debug-description": "Aktiviert das Ausgabeprotokollfenster für IPA. Dies zeigt die Debug-Konsole, welche die Mods verwenden.", + "outdated-tippy": "Diese Version ist veraltet, und einige Mods oder Funktionen funktionieren möglicherweise nicht wie erwartet. Es wird empfohlen, die empfohlene Version ({recommendedVersion}) von Beat Saber zu verwenden, um die neuesten Funktionen und Fehlerbehebungen zu genießen.", "advanced-launch": { "button": "Erweiterter Start", "placeholder": "Weitere Argumente, bspw: --revert; --nowait" @@ -591,6 +592,14 @@ "error": { "msg": "Beim Erstellen der Verknüpfung ist ein Fehler aufgetreten." } + }, + "bs-version-oudated": { + "title": "Veraltete Version", + "msg": "Diese Version von Beat Saber ist veraltet. Verwenden Sie die empfohlene Version, um die neuesten Funktionen und Fehlerbehebungen zu nutzen.", + "actions": { + "do-not-remind": "Nicht mehr daran erinnern", + "ok": "Ok" + } } }, "modals": { diff --git a/assets/jsons/translations/en.json b/assets/jsons/translations/en.json index b778c7e32..7f061f640 100644 --- a/assets/jsons/translations/en.json +++ b/assets/jsons/translations/en.json @@ -38,6 +38,7 @@ "desktop-description": "First Person Flying Controller mode allows you to use WASD and the mouse to navigate around the menu in game. This makes testing much easier, because you don't have to put on your headset!", "debug": "Debug Mode", "debug-description": "Enables the output log window for IPA. This will show the debug console that mods use.", + "outdated-tippy": "This version is outdated, and some mods or features may no longer work as expected. Prefer using the recommended version ({recommendedVersion}) of Beat Saber to enjoy the latest features and bugfixes.", "advanced-launch": { "button": "Advanced launch", "placeholder": "Additional arguments ex: --revert; --nowait" @@ -591,6 +592,14 @@ "error": { "msg": "An error occurred while creating the shortcut." } + }, + "bs-version-oudated": { + "title": "Version Outdated", + "msg": "This Beat Saber version is outdated, use the recommended version to enjoy the latest features and bugfixes", + "actions": { + "do-not-remind": "Do not remind me", + "ok": "Ok" + } } }, "modals": { diff --git a/assets/jsons/translations/es.json b/assets/jsons/translations/es.json index 966574d58..9e621c75b 100644 --- a/assets/jsons/translations/es.json +++ b/assets/jsons/translations/es.json @@ -38,6 +38,7 @@ "desktop-description": "El modo FPFC te permite usar WASD y el mouse para navegar por el menú en juego. Esto hace que las pruebas sean mucho más fáciles, ¡porque no tienes que ponerte las gafas VR!", "debug": "Modo Depuración", "debug-description": "Habilita la ventana de registro de salida para IPA. Esto mostrará la consola de depuración que usan los mods.", + "outdated-tippy": "Esta versión está desactualizada, y algunos mods o funciones pueden no funcionar como se espera. Es mejor usar la versión recomendada ({recommendedVersion}) de Beat Saber para disfrutar de las últimas características y correcciones.", "advanced-launch": { "button": "Opciones avanzadas", "placeholder": "Argumentos adicionales ej: --revert; --no-wait" @@ -591,6 +592,14 @@ "error": { "msg": "Se produjo un error al crear el acceso directo." } + }, + "bs-version-oudated": { + "title": "Versión desactualizada", + "msg": "Esta versión de Beat Saber está desactualizada. Usa la versión recomendada para disfrutar de las últimas características y correcciones.", + "actions": { + "do-not-remind": "No volver a recordármelo", + "ok": "Ok" + } } }, "modals": { diff --git a/assets/jsons/translations/fr.json b/assets/jsons/translations/fr.json index 720e56d70..8dd40666c 100644 --- a/assets/jsons/translations/fr.json +++ b/assets/jsons/translations/fr.json @@ -38,6 +38,7 @@ "desktop-description": "Cela vous permet d'utiliser WASD et la souris pour naviguer dans le menu en jeu. Cela rend les tests beaucoup plus faciles, car vous n'avez pas à mettre votre casque!", "debug": "Mode Debug", "debug-description": "Active la fenêtre de log pour IPA. Cela affichera la console de débogage utilisée par les mods.", + "outdated-tippy": "Cette version est obsolète et certains mods ou fonctionnalités peuvent ne plus fonctionner comme prévu. Préférez utiliser la version recommandée ({recommendedVersion}) de Beat Saber pour profiter des dernières fonctionnalités et correctifs.", "advanced-launch": { "button": "Lancement avancé", "placeholder": "Arguments supplémentaires ex: --revert; --nowait" @@ -592,6 +593,14 @@ "error": { "msg": "Une erreur s'est produite lors de la création du raccourci." } + }, + "bs-version-oudated": { + "title": "Version obsolète", + "msg": "Cette version de Beat Saber est obsolète. Utilisez la version recommandée pour profiter des dernières fonctionnalités et correctifs.", + "actions": { + "do-not-remind": "Ne plus me rappeler", + "ok": "Ok" + } } }, "modals": { diff --git a/assets/jsons/translations/ja.json b/assets/jsons/translations/ja.json index 8ba85b8bc..d5b1ac2fd 100644 --- a/assets/jsons/translations/ja.json +++ b/assets/jsons/translations/ja.json @@ -38,6 +38,7 @@ "desktop-description": "ファーストパーソン・フライング・コントローラー・モードでは、WASDとマウスを使ってゲーム内のメニューを操作できます。ヘッドセットを装着する必要がないので、テストがより簡単になります!", "debug": "デバックモード", "debug-description": "IPAの出力ログウィンドウを有効にします。これはMODのデバッグコンソールを表示します。", + "outdated-tippy": "このバージョンは古いため、一部のMODや機能が期待通りに動作しない可能性があります。最新の機能やバグ修正を楽しむには、推奨バージョン ({recommendedVersion}) のBeat Saberを使用することをお勧めします。", "advanced-launch": { "button": "高度な起動", "placeholder": "追加引数 例:--revert; --nowait" @@ -591,6 +592,14 @@ "error": { "msg": "ショートカットの作成中にエラーが発生しました。" } + }, + "bs-version-oudated": { + "title": "バージョンが古い", + "msg": "このBeat Saberのバージョンは古いため、推奨バージョンを使用して最新の機能やバグ修正をお楽しみください。", + "actions": { + "do-not-remind": "再度通知しない", + "ok": "OK" + } } }, "modals": { diff --git a/assets/jsons/translations/ko.json b/assets/jsons/translations/ko.json index 0b9ca3949..039995c15 100644 --- a/assets/jsons/translations/ko.json +++ b/assets/jsons/translations/ko.json @@ -38,6 +38,7 @@ "desktop-description": "FPFC 모드에서는 WASD와 마우스로 게임 내 메뉴를 조작할 수 있어 테스트가 더 쉬워집니다. 헤드셋을 착용할 필요가 없습니다!", "debug": "디버그 모드", "debug-description": "IPA 출력 로그 창을 활성화하여 MOD의 디버그 콘솔을 표시합니다.", + "outdated-tippy": "이 버전은 오래되어 일부 모드나 기능이 예상대로 작동하지 않을 수 있습니다. 최신 기능과 버그 수정을 사용하려면 권장 버전({recommendedVersion})의 Beat Saber를 사용하는 것이 좋습니다.", "advanced-launch": { "button": "고급 실행", "placeholder": "추가 인수 예: --revert; --nowait" @@ -591,6 +592,14 @@ "error": { "msg": "바로 가기 생성 중 오류가 발생했습니다." } + }, + "bs-version-oudated": { + "title": "버전이 오래됨", + "msg": "이 Beat Saber 버전은 오래되었습니다. 최신 기능과 버그 수정을 즐기려면 권장 버전을 사용하세요.", + "actions": { + "do-not-remind": "다시 알리지 않기", + "ok": "확인" + } } }, "modals": { diff --git a/assets/jsons/translations/ru.json b/assets/jsons/translations/ru.json index f52fb4248..e40394dd5 100644 --- a/assets/jsons/translations/ru.json +++ b/assets/jsons/translations/ru.json @@ -38,6 +38,7 @@ "desktop-description": "Режим Летающих контроллеров от первого лица(FPFC) позволит вам использовать меню с помощью WASD и мышки. Это облегчает тестирование модов, потому что вам не нужно подключать шлем!", "debug": "Режим отладки", "debug-description": "Включает окно логов для IPA. В окне будут отображаться логи модов.", + "outdated-tippy": "Эта версия устарела, и некоторые моды или функции могут работать не так, как ожидалось. Рекомендуется использовать рекомендуемую версию ({recommendedVersion}) Beat Saber, чтобы воспользоваться последними функциями и исправлениями ошибок.", "advanced-launch": { "button": "Расширенный запуск", "placeholder": "Параметры запуска, например: --revert; --nowait" @@ -591,6 +592,14 @@ "error": { "msg": "Ошибка создания ярлыка." } + }, + "bs-version-oudated": { + "title": "Устаревшая версия", + "msg": "Эта версия Beat Saber устарела. Используйте рекомендуемую версию, чтобы воспользоваться последними функциями и исправлениями ошибок.", + "actions": { + "do-not-remind": "Больше не напоминать", + "ok": "Ок" + } } }, "modals": { diff --git a/assets/jsons/translations/zh-tw.json b/assets/jsons/translations/zh-tw.json index 512c7e920..dd6358a00 100644 --- a/assets/jsons/translations/zh-tw.json +++ b/assets/jsons/translations/zh-tw.json @@ -38,6 +38,7 @@ "desktop-description": "第一人稱飛控模式允許你使用鍵盤 WASD 和滑鼠在遊戲中進行導航。你無需帶上頭顯即可進行測試!", "debug": "Debug 模式", "debug-description": "為 IPA 啟用輸出日誌窗口。 會顯示所用 Mod 的 debug 輸出", + "outdated-tippy": "此版本已過時,某些模組或功能可能無法按預期運作。建議使用推薦版本的 Beat Saber ({recommendedVersion}),以享受最新功能和修復。", "advanced-launch": { "button": "高級啟動", "placeholder": "額外啟動參數,例如: --revert; --nowait" @@ -591,6 +592,14 @@ "error": { "msg": "創建捷徑時發生錯誤" } + }, + "bs-version-oudated": { + "title": "版本過時", + "msg": "此 Beat Saber 版本已過時,請使用推薦版本以享受最新功能和修復。", + "actions": { + "do-not-remind": "不要再提醒我", + "ok": "確定" + } } }, "modals": { diff --git a/assets/jsons/translations/zh.json b/assets/jsons/translations/zh.json index 8ce5c85ae..ef4d146cc 100644 --- a/assets/jsons/translations/zh.json +++ b/assets/jsons/translations/zh.json @@ -38,6 +38,7 @@ "desktop-description": "第一人称飞控模式允许你使用键盘 WASD 和鼠标在游戏中进行导航。你无需带上头显即可进行测试!", "debug": "Debug 模式", "debug-description": "为 IPA 启用输出日志窗口。 会显示所用 Mod 的 debug 输出", + "outdated-tippy": "此版本已过时,某些模组或功能可能无法按预期运行。建议使用推荐版本的 Beat Saber ({recommendedVersion}),以享受最新功能和修复。", "advanced-launch": { "button": "高级启动", "placeholder": "额外启动参数,例如: --revert; --nowait" @@ -591,6 +592,14 @@ "error": { "msg": "创建快捷方式时发生错误" } + }, + "bs-version-oudated": { + "title": "版本过时", + "msg": "此 Beat Saber 版本已过时,请使用推荐版本以享受最新功能和修复。", + "actions": { + "do-not-remind": "不再提醒", + "ok": "确定" + } } }, "modals": { diff --git a/src/renderer/components/modal/modal-types/bs-version-outdated-modal.component.tsx b/src/renderer/components/modal/modal-types/bs-version-outdated-modal.component.tsx index 869130e01..821d5ef26 100644 --- a/src/renderer/components/modal/modal-types/bs-version-outdated-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/bs-version-outdated-modal.component.tsx @@ -18,7 +18,7 @@ export const BSVersionOutdatedModal: ModalComponent { if (remember) { - config.set("not-show-bs-version-outdated", true); + config.set("not-show-bs-version-outdated-modal", true); } resolver({ exitCode: ModalExitCode.COMPLETED }); diff --git a/src/renderer/components/svgs/bsm-icon.component.tsx b/src/renderer/components/svgs/bsm-icon.component.tsx index 5d3336129..bf947f816 100644 --- a/src/renderer/components/svgs/bsm-icon.component.tsx +++ b/src/renderer/components/svgs/bsm-icon.component.tsx @@ -66,9 +66,10 @@ import { CleanIcon } from "./icons/clean-icon.component"; import { BrowseIcon } from "./icons/browse-icon.component"; import { AddFileIcon } from "./icons/add-file-icon.component"; import { CancelIcon } from "./icons/cancel-icon.component"; +import { WarningIcon } from "./icons/warning-icon.component"; -export type BsmIconType = SongDetailDiffCharactertistic | ("settings" | "trash" | "favorite" | "folder" | "bsNote" | "check" | "three-dots" | "twitch" | "eye" | "play" | "checkCircleIcon" | "discord" | "info" | "eye-cross" | "terminal" | "desktop" | "oculus" | "add" | "cross" | "task" | "github" | "close" | "thumbUpFill" | "timerFill" | "pause" | "twitter" | "sync" | "chevron-top" | "copy" | "steam" | "edit" | "export" | "patreon" | "search" | "bsMapDifficulty" | "link" | "unlink" | "download" | "filter" | "mee6" | "volume-up" | "volume-off" | "volume-down" | "shortcut" | "backup-restore" | "web-site" | "clean" | "browse" | "add-file" | "cancel" | "fr-FR-flag" | "es-ES-flag" | "en-US-flag" | "en-EN-flag" | "de-DE-flag" | "ru-RU-flag" | "zh-CN-flag" | "zh-TW-flag" | "ja-JP-flag" | "ko-KR-flag"); +export type BsmIconType = SongDetailDiffCharactertistic | ("settings" | "trash" | "favorite" | "folder" | "bsNote" | "check" | "three-dots" | "twitch" | "eye" | "play" | "checkCircleIcon" | "discord" | "info" | "eye-cross" | "terminal" | "desktop" | "oculus" | "add" | "cross" | "task" | "github" | "close" | "thumbUpFill" | "timerFill" | "pause" | "twitter" | "sync" | "chevron-top" | "copy" | "steam" | "edit" | "export" | "patreon" | "search" | "bsMapDifficulty" | "link" | "unlink" | "download" | "filter" | "mee6" | "volume-up" | "volume-off" | "volume-down" | "shortcut" | "backup-restore" | "web-site" | "clean" | "browse" | "add-file" | "cancel" | "warning" | "fr-FR-flag" | "es-ES-flag" | "en-US-flag" | "en-EN-flag" | "de-DE-flag" | "ru-RU-flag" | "zh-CN-flag" | "zh-TW-flag" | "ja-JP-flag" | "ko-KR-flag"); export const BsmIcon = memo(({ className, icon, style }: { className?: string; icon: BsmIconType; style?: CSSProperties }) => { // TODO : Very ugly very messy, need to find a better way to do this @@ -281,6 +282,10 @@ export const BsmIcon = memo(({ className, icon, style }: { className?: string; i return ; } + if(icon === "warning"){ + return ; + } + return ; diff --git a/src/renderer/components/svgs/icons/warning-icon.component.tsx b/src/renderer/components/svgs/icons/warning-icon.component.tsx new file mode 100644 index 000000000..d514194ff --- /dev/null +++ b/src/renderer/components/svgs/icons/warning-icon.component.tsx @@ -0,0 +1,9 @@ +import { createSvgIcon } from "../svg-icon.type"; + +export const WarningIcon = createSvgIcon((props, ref) => { + return ( + + + + ); +}) diff --git a/src/renderer/components/version-viewer/slides/launch/launch-slide.component.tsx b/src/renderer/components/version-viewer/slides/launch/launch-slide.component.tsx index 3f64b672e..279029890 100644 --- a/src/renderer/components/version-viewer/slides/launch/launch-slide.component.tsx +++ b/src/renderer/components/version-viewer/slides/launch/launch-slide.component.tsx @@ -1,7 +1,7 @@ -import { ChangeEvent, useEffect, useState } from "react"; +import { ChangeEvent, useEffect, useMemo, useState } from "react"; import { BsmButton } from "renderer/components/shared/bsm-button.component"; import { useObservable } from "renderer/hooks/use-observable.hook"; -import { useTranslation } from "renderer/hooks/use-translation.hook"; +import { useTranslationV2 } from "renderer/hooks/use-translation.hook"; import { BSLauncherService, LaunchMods } from "renderer/services/bs-launcher.service"; import { ConfigurationService } from "renderer/services/configuration.service"; import { BSVersion } from "shared/bs-version.interface"; @@ -15,15 +15,20 @@ import { BsDownloaderService } from "renderer/services/bs-version-download/bs-do import equal from "fast-deep-equal"; import { GlowEffect } from "renderer/components/shared/glow-effect.component"; import { cn } from "renderer/helpers/css-class.helpers"; +import { BSVersionManagerService } from "renderer/services/bs-version-manager.service"; +import { safeLt } from "shared/helpers/semver.helpers"; +import { WarningIcon } from "renderer/components/svgs/icons/warning-icon.component"; +import Tippy from "@tippyjs/react"; type Props = { version: BSVersion }; export function LaunchSlide({ version }: Props) { - const t = useTranslation(); + const { text: t, element: te } = useTranslationV2(); const configService = useService(ConfigurationService); const bsLauncherService = useService(BSLauncherService); const bsDownloader = useService(BsDownloaderService); + const versions = useService(BSVersionManagerService); const [oculusMode, setOculusMode] = useState(!!configService.get(LaunchMods.OCULUS_MOD)); const [desktopMode, setDesktopMode] = useState(!!configService.get(LaunchMods.DESKTOP_MOD)); @@ -71,11 +76,24 @@ export function LaunchSlide({ version }: Props) { return lastValueFrom(launch$).catch(() => {}); }; + const isOutdated = useMemo(() => { + return safeLt(version?.BSVersion, versions.getRecommendedVersion()?.BSVersion); + }, [version]); + return (
-

{version.name ? `${version.BSVersion} - ${version.name}` : version.BSVersion}

+

+ {version.name ? `${version.BSVersion} - ${version.name}` : version.BSVersion} + {isOutdated && ( + {versions.getRecommendedVersion().BSVersion} })}> + + + + + )} +

{!(version.oculus || version.metadata?.store === BsStore.OCULUS) && setMode(LaunchMods.OCULUS_MOD, !oculusMode)} active={oculusMode} text="pages.version-viewer.launch-mods.oculus" />} @@ -111,3 +129,5 @@ export function LaunchSlide({ version }: Props) {
); } + + diff --git a/src/renderer/pages/available-versions-list.components.tsx b/src/renderer/pages/available-versions-list.components.tsx index b781282dd..69f5e4a38 100644 --- a/src/renderer/pages/available-versions-list.components.tsx +++ b/src/renderer/pages/available-versions-list.components.tsx @@ -15,8 +15,7 @@ import { logRenderError } from "renderer"; import { ModalExitCode, ModalService } from "renderer/services/modale.service"; import { BSVersionOutdatedModal } from "renderer/components/modal/modal-types/bs-version-outdated-modal.component"; import { ConfigurationService } from "renderer/services/configuration.service"; -import { coerce, lt, valid } from "semver"; -import { tryit } from "shared/helpers/error.helpers"; +import { safeLt } from "shared/helpers/semver.helpers"; export const AvailableVersionsContext = createContext<{ selectedVersion: BSVersion; setSelectedVersion: (version: BSVersion) => void }>(null); @@ -34,12 +33,10 @@ export function AvailableVersionsList() { const t = useTranslation(); const startDownload = async (version: BSVersion) => { - const showOutdated = !config.get("not-show-bs-version-outdated"); - const recommendedVersion = showOutdated ? versionManager.availableVersions$.value.find(v => v.recommended) : undefined; + const showOutdated = !config.get("not-show-bs-version-outdated-modal"); + const recommendedVersion = versionManager.getRecommendedVersion(); - const isVersionOutdated = recommendedVersion?.BSVersion ? ( - tryit(() => lt(valid(coerce(version.BSVersion)), valid(coerce(recommendedVersion.BSVersion)))).result ?? false - ) : false; + const isVersionOutdated = safeLt(version.BSVersion, recommendedVersion?.BSVersion); if (showOutdated && isVersionOutdated) { diff --git a/src/renderer/pages/version-viewer.component.tsx b/src/renderer/pages/version-viewer.component.tsx index 8a1d464b2..b2b03ecd4 100644 --- a/src/renderer/pages/version-viewer.component.tsx +++ b/src/renderer/pages/version-viewer.component.tsx @@ -21,6 +21,9 @@ import { CreateLaunchShortcutModal } from "renderer/components/modal/modal-types import { lastValueFrom } from "rxjs"; import { NotificationService } from "renderer/services/notification.service"; import { BsDownloaderService } from "renderer/services/bs-version-download/bs-downloader.service"; +import { useOnUpdate } from "renderer/hooks/use-on-update.hook"; +import { safeLt } from "shared/helpers/semver.helpers"; +import { ConfigurationService } from "renderer/services/configuration.service"; export function VersionViewer() { @@ -31,11 +34,41 @@ export function VersionViewer() { const ipcService = useService(IpcService); const bsLauncher = useService(BSLauncherService); const notification = useService(NotificationService); + const config = useService(ConfigurationService); const { state } = useLocation() as { state: BSVersion }; const navigate = useNavigate(); const [currentTabIndex, setCurrentTabIndex] = useState(0); + useOnUpdate(() => { + + checkIsVersionOutaded(); + + }, [state]); + + const checkIsVersionOutaded = async () => { + + if(config.get("not-show-bs-version-outdated-notification")){ + return; + } + + const recommended = bsVersionManagerService.getRecommendedVersion(); + const isOutdated = safeLt(state.BSVersion, recommended?.BSVersion); + + if(!isOutdated){ + return; + } + + const res = await notification.notifyWarning({ title: "notifications.bs-version-oudated.title", desc: "notifications.bs-version-oudated.msg", duration: 9000, actions: [ + { id: "0", title: "notifications.bs-version-oudated.actions.do-not-remind" }, + { id: "1", title: "notifications.bs-version-oudated.actions.ok", cancel: true } + ] }); + + if(res === "0"){ + config.set("not-show-bs-version-outdated-notification", true); + } + } + const navigateToVersion = (version?: BSVersion) => { if (!version) { return navigate("/available-versions"); diff --git a/src/renderer/services/bs-version-manager.service.ts b/src/renderer/services/bs-version-manager.service.ts index d63ffffad..696e7d85d 100644 --- a/src/renderer/services/bs-version-manager.service.ts +++ b/src/renderer/services/bs-version-manager.service.ts @@ -211,4 +211,8 @@ export class BSVersionManagerService { version ]))).values()); } + + public getRecommendedVersion(): BSVersion | undefined { + return (this.availableVersions$.value ?? []).find(v => v.recommended); + } } diff --git a/src/shared/helpers/semver.helpers.ts b/src/shared/helpers/semver.helpers.ts new file mode 100644 index 000000000..617982d39 --- /dev/null +++ b/src/shared/helpers/semver.helpers.ts @@ -0,0 +1,8 @@ +import { coerce, lt, valid } from "semver"; +import { tryit } from "./error.helpers"; + +export function safeLt(a: string, b: string): boolean { + const { result } = tryit(() => lt(valid(coerce(a)), valid(coerce(b)))); + return result ?? false; +} +