diff --git a/src/web-ui/src/app/scenes/miniapps/views/MiniAppMarketView.scss b/src/web-ui/src/app/scenes/miniapps/views/MiniAppMarketView.scss
index dbfc189655..17d90514e7 100644
--- a/src/web-ui/src/app/scenes/miniapps/views/MiniAppMarketView.scss
+++ b/src/web-ui/src/app/scenes/miniapps/views/MiniAppMarketView.scss
@@ -159,6 +159,15 @@
}
}
+ // Inert "installed" state that sits beside the action buttons in the modal footer.
+ &__installed-state {
+ display: inline-flex;
+ align-items: center;
+ gap: $size-gap-1;
+ color: var(--color-success);
+ font-size: var(--font-size-sm);
+ }
+
&__screenshots {
display: flex;
gap: $size-gap-2;
diff --git a/src/web-ui/src/app/scenes/miniapps/views/MiniAppMarketView.tsx b/src/web-ui/src/app/scenes/miniapps/views/MiniAppMarketView.tsx
index 24b22a8250..14c630d2ad 100644
--- a/src/web-ui/src/app/scenes/miniapps/views/MiniAppMarketView.tsx
+++ b/src/web-ui/src/app/scenes/miniapps/views/MiniAppMarketView.tsx
@@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
AlertTriangle,
+ ArrowUpRight,
Check,
Download,
ExternalLink,
@@ -89,6 +90,18 @@ const MiniAppMarketView: React.FC = () => {
const openTabIds = useMemo(() => new Set(openTabs.map((tab) => tab.id)), [openTabs]);
+ /** Focuses the installed MiniApp's scene tab, opening it when absent. */
+ const openInstalledApp = useCallback((appId: string) => {
+ setDetail(undefined);
+ setInstalled(null);
+ const tabId: SceneTabId = `miniapp:${appId}`;
+ if (openTabIds.has(tabId)) {
+ activateScene(tabId);
+ } else {
+ openScene(tabId);
+ }
+ }, [activateScene, openScene, openTabIds]);
+
const loadCatalog = useCallback(async (append = false) => {
if (append) {
setLoadingMore(true);
@@ -241,17 +254,10 @@ const MiniAppMarketView: React.FC = () => {
confirmOverwrite: Boolean(installed?.localOverride),
});
upsertApp(result.app);
- setDetail(undefined);
- setInstalled(null);
notification.success(
t(result.updated ? 'market.messages.updated' : 'market.messages.installed'),
);
- const tabId: SceneTabId = `miniapp:${result.app.id}`;
- if (openTabIds.has(tabId)) {
- activateScene(tabId);
- } else {
- openScene(tabId);
- }
+ openInstalledApp(result.app.id);
} catch (installError) {
notification.error(t('market.messages.installFailed', { error: String(installError) }));
} finally {
@@ -283,11 +289,8 @@ const MiniAppMarketView: React.FC = () => {
&& requiresWorkspace(detail.permissions),
);
const canUpdate = Boolean(installed && detail && detail.latestRelease > installed.origin.releaseNumber);
- const installLabel = installed
- ? canUpdate
- ? t('market.detail.update')
- : t('market.detail.installed')
- : t('market.detail.install');
+ // The install button only renders for the actionable states: fresh install or update.
+ const installLabel = canUpdate ? t('market.detail.update') : t('market.detail.install');
const detailName = detail
? pickLocalizedString(detail, currentLanguage, 'name')
: '';
@@ -472,15 +475,35 @@ const MiniAppMarketView: React.FC = () => {
{formatNumber(detail.favoriteCount)}
-
+ {/* Installed and up to date: nothing left to install, so say so and let "Open" lead. */}
+ {installed && !canUpdate ? (
+
+
+ {t('market.detail.installed')}
+
+ ) : null}
+ {installed ? (
+
+ ) : null}
+ {!installed || canUpdate ? (
+
+ ) : null}
>
) : null}
>
diff --git a/src/web-ui/src/locales/en-US/scenes/miniapp.json b/src/web-ui/src/locales/en-US/scenes/miniapp.json
index c83263d504..2d0adaf5aa 100644
--- a/src/web-ui/src/locales/en-US/scenes/miniapp.json
+++ b/src/web-ui/src/locales/en-US/scenes/miniapp.json
@@ -72,8 +72,9 @@
"reviewed": "Human reviewed",
"by": "By @{{owner}}",
"install": "Install",
- "update": "Update manually",
+ "update": "Update",
"installed": "Installed",
+ "open": "Open",
"permissions": "Install permissions",
"noPermissions": "No additional host permissions",
"rating": "Rating",
diff --git a/src/web-ui/src/locales/zh-CN/scenes/miniapp.json b/src/web-ui/src/locales/zh-CN/scenes/miniapp.json
index 806b533b79..baaa76abf1 100644
--- a/src/web-ui/src/locales/zh-CN/scenes/miniapp.json
+++ b/src/web-ui/src/locales/zh-CN/scenes/miniapp.json
@@ -72,8 +72,9 @@
"reviewed": "人工审核",
"by": "作者 @{{owner}}",
"install": "安装",
- "update": "手动更新",
+ "update": "更新",
"installed": "已安装",
+ "open": "打开",
"permissions": "安装权限",
"noPermissions": "不需要额外宿主权限",
"rating": "评分",
diff --git a/src/web-ui/src/locales/zh-TW/scenes/miniapp.json b/src/web-ui/src/locales/zh-TW/scenes/miniapp.json
index 4056266953..d9038f0d01 100644
--- a/src/web-ui/src/locales/zh-TW/scenes/miniapp.json
+++ b/src/web-ui/src/locales/zh-TW/scenes/miniapp.json
@@ -72,8 +72,9 @@
"reviewed": "人工審核",
"by": "作者 @{{owner}}",
"install": "安裝",
- "update": "手動更新",
+ "update": "更新",
"installed": "已安裝",
+ "open": "開啟",
"permissions": "安裝權限",
"noPermissions": "不需要額外宿主權限",
"rating": "評分",