fix(apps): repair netbird install and app icons
This commit is contained in:
@@ -2098,7 +2098,7 @@ html:has(body.video-background-active)::before {
|
||||
position: relative;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 14px;
|
||||
border-radius: 18px;
|
||||
overflow: visible;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
@@ -2108,7 +2108,16 @@ html:has(body.video-background-active)::before {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 14px;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.app-card-icon {
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.app-detail-icon {
|
||||
border-radius: 22px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* Status dot — top-right of icon */
|
||||
@@ -2140,7 +2149,7 @@ html:has(body.video-background-active)::before {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
border-radius: 14px;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.app-icon-label {
|
||||
|
||||
@@ -158,7 +158,7 @@ const { t } = useI18n()
|
||||
const appId = computed(() => {
|
||||
const id = route.params.id
|
||||
if (typeof id !== 'string' || !/^[a-z0-9][a-z0-9._-]*$/.test(id) || id.length > 64) {
|
||||
router.replace('/apps')
|
||||
router.replace('/dashboard/apps')
|
||||
return ''
|
||||
}
|
||||
return id
|
||||
|
||||
@@ -138,7 +138,7 @@ const displayMode = ref<DisplayMode>(
|
||||
const appId = computed(() => {
|
||||
const id = props.appIdProp || (route.params.appId as string)
|
||||
if (typeof id !== 'string' || !/^[a-z0-9][a-z0-9._-]*$/.test(id) || id.length > 64) {
|
||||
router.replace('/apps')
|
||||
router.replace('/dashboard/apps')
|
||||
return ''
|
||||
}
|
||||
return id
|
||||
@@ -146,7 +146,7 @@ const appId = computed(() => {
|
||||
|
||||
const appTitle = computed(() => resolveAppTitle(appId.value))
|
||||
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
|
||||
const mustOpenNewTab = computed(() => !isMobile && NEW_TAB_APPS.has(appId.value))
|
||||
const mustOpenNewTab = computed(() => NEW_TAB_APPS.has(appId.value))
|
||||
const screensaverReason = computed(() => `app-session:${appId.value}`)
|
||||
const screensaverSuppressedApps = new Set([
|
||||
'indeedhub',
|
||||
@@ -197,7 +197,11 @@ function setMode(mode: DisplayMode) {
|
||||
if (!isInlinePanel.value && mode === 'panel') {
|
||||
const id = appId.value
|
||||
const launcher = useAppLauncherStore()
|
||||
router.push({ name: 'apps' }).then(() => {
|
||||
const fallback = route.query.returnTo
|
||||
const fallbackPath = typeof fallback === 'string' && fallback.startsWith('/dashboard')
|
||||
? fallback
|
||||
: '/dashboard/apps'
|
||||
router.push(fallbackPath).then(() => {
|
||||
launcher.panelAppId = id
|
||||
})
|
||||
return
|
||||
@@ -337,8 +341,9 @@ watch(displayMode, (mode) => {
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Apps that block iframes (X-Frame-Options) -- open in new tab, close session
|
||||
if (mustOpenNewTab.value && appUrl.value) {
|
||||
// Desktop apps that block iframes open externally. Mobile keeps the user in
|
||||
// Archipelago and shows the explicit fallback instead of leaving the shell.
|
||||
if (!isMobile && mustOpenNewTab.value && appUrl.value) {
|
||||
window.open(appUrl.value, '_blank', 'noopener,noreferrer')
|
||||
if (isInlinePanel.value) emit('close')
|
||||
else closeRouteSession()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<img
|
||||
:src="icon"
|
||||
:alt="pkg.manifest.title"
|
||||
class="w-20 h-20 rounded-xl shadow-xl flex-shrink-0"
|
||||
class="app-detail-icon w-20 h-20 shadow-xl flex-shrink-0"
|
||||
@error="handleImageError"
|
||||
/>
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
<img
|
||||
:src="icon"
|
||||
:alt="pkg.manifest.title"
|
||||
class="w-20 h-20 rounded-xl shadow-xl flex-shrink-0"
|
||||
class="app-detail-icon w-20 h-20 shadow-xl flex-shrink-0"
|
||||
@error="handleImageError"
|
||||
/>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<img
|
||||
:src="icon"
|
||||
:alt="title"
|
||||
class="w-14 h-14 rounded-lg object-cover bg-white/10"
|
||||
class="app-card-icon w-14 h-14 object-cover bg-white/10"
|
||||
@error="handleImageError"
|
||||
/>
|
||||
<div class="flex-1 min-w-0 overflow-hidden">
|
||||
|
||||
@@ -35,6 +35,11 @@ describe('AppIconGrid', () => {
|
||||
setActivePinia(createPinia())
|
||||
vi.clearAllMocks()
|
||||
localStorage.clear()
|
||||
Object.defineProperty(window, 'innerWidth', {
|
||||
value: 1024,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
})
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: { hostname: '192.168.1.198' },
|
||||
writable: true,
|
||||
@@ -55,4 +60,23 @@ describe('AppIconGrid', () => {
|
||||
expect(mockWindowOpen).not.toHaveBeenCalled()
|
||||
expect(useAppLauncherStore().panelAppId).toBe('lnd')
|
||||
})
|
||||
|
||||
it('opens desktop new-tab apps through app session on mobile', async () => {
|
||||
Object.defineProperty(window, 'innerWidth', {
|
||||
value: 390,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
})
|
||||
|
||||
const wrapper = mount(AppIconGrid, {
|
||||
props: { apps: [['gitea', makePkg('gitea')]] },
|
||||
global: {
|
||||
plugins: [createPinia()],
|
||||
},
|
||||
})
|
||||
|
||||
await wrapper.get('.app-icon-item').trigger('click')
|
||||
|
||||
expect(mockWindowOpen).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -166,7 +166,8 @@ const APP_ICON_FALLBACKS: Record<string, string> = {
|
||||
}
|
||||
|
||||
export function resolveAppIcon(id: string, pkg: PackageDataEntry, curatedIcon?: string): string {
|
||||
const icon = (pkg["static-files"]?.icon || "").trim()
|
||||
const rawIcon = (pkg["static-files"]?.icon || "").trim()
|
||||
const icon = rawIcon === '/assets/img/favico.png' ? '' : rawIcon
|
||||
if (
|
||||
icon.startsWith("/") ||
|
||||
icon.startsWith("http://") ||
|
||||
|
||||
Reference in New Issue
Block a user