Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
67 changes: 45 additions & 22 deletions src/web-ui/src/app/scenes/miniapps/views/MiniAppMarketView.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
AlertTriangle,
ArrowUpRight,
Check,
Download,
ExternalLink,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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')
: '';
Expand Down Expand Up @@ -472,15 +475,35 @@ const MiniAppMarketView: React.FC = () => {
<Heart size={14} fill={detail.isFavorited ? 'currentColor' : 'none'} />
{formatNumber(detail.favoriteCount)}
</Button>
<Button
size="small"
variant="primary"
disabled={actionBusy || Boolean(installed && !canUpdate) || workspaceUnsupported}
onClick={() => setInstallPrompt(true)}
>
{actionBusy ? <Loader2 size={14} className="gallery-spinning" /> : installed ? <RefreshCw size={14} /> : <Download size={14} />}
{installLabel}
</Button>
{/* Installed and up to date: nothing left to install, so say so and let "Open" lead. */}
{installed && !canUpdate ? (
<span className="miniapp-market-detail__installed-state">
<Check size={14} />
{t('market.detail.installed')}
</span>
) : null}
{installed ? (
<Button
size="small"
variant={canUpdate ? 'secondary' : 'primary'}
disabled={actionBusy || workspaceUnsupported}
onClick={() => openInstalledApp(installed.appId)}
>
<ArrowUpRight size={14} />
{t('market.detail.open')}
</Button>
) : null}
{!installed || canUpdate ? (
<Button
size="small"
variant="primary"
disabled={actionBusy || workspaceUnsupported}
onClick={() => setInstallPrompt(true)}
>
{actionBusy ? <Loader2 size={14} className="gallery-spinning" /> : canUpdate ? <RefreshCw size={14} /> : <Download size={14} />}
{installLabel}
</Button>
) : null}
</>
) : null}
>
Expand Down
3 changes: 2 additions & 1 deletion src/web-ui/src/locales/en-US/scenes/miniapp.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 2 additions & 1 deletion src/web-ui/src/locales/zh-CN/scenes/miniapp.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@
"reviewed": "人工审核",
"by": "作者 @{{owner}}",
"install": "安装",
"update": "手动更新",
"update": "更新",
"installed": "已安装",
"open": "打开",
"permissions": "安装权限",
"noPermissions": "不需要额外宿主权限",
"rating": "评分",
Expand Down
3 changes: 2 additions & 1 deletion src/web-ui/src/locales/zh-TW/scenes/miniapp.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@
"reviewed": "人工審核",
"by": "作者 @{{owner}}",
"install": "安裝",
"update": "手動更新",
"update": "更新",
"installed": "已安裝",
"open": "開啟",
"permissions": "安裝權限",
"noPermissions": "不需要額外宿主權限",
"rating": "評分",
Expand Down
Loading