From 52e1276c8d9d43be7a33db0c7c75079cb5c93302 Mon Sep 17 00:00:00 2001 From: Johannes Zellner Date: Wed, 10 Dec 2025 14:20:59 +0100 Subject: [PATCH] Improve reactivity if app install dialog should be opened --- dashboard/src/components/AppInstallDialog.vue | 40 +++++++++++++++---- dashboard/src/views/AppstoreView.vue | 8 ++-- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/dashboard/src/components/AppInstallDialog.vue b/dashboard/src/components/AppInstallDialog.vue index 1c537d47a..2ae75a5f5 100644 --- a/dashboard/src/components/AppInstallDialog.vue +++ b/dashboard/src/components/AppInstallDialog.vue @@ -2,21 +2,24 @@ import { ref, computed, useTemplateRef, onMounted, inject } from 'vue'; import { marked } from 'marked'; -import { Button, Dialog, SingleSelect, FormGroup, TextInput, InputGroup } from '@cloudron/pankow'; +import { Button, Dialog, SingleSelect, FormGroup, TextInput, InputGroup, Spinner } from '@cloudron/pankow'; import { prettyDate, prettyBinarySize, isValidDomain } from '@cloudron/pankow/utils'; import AccessControl from './AccessControl.vue'; import PortBindings from './PortBindings.vue'; import AppsModel from '../models/AppsModel.js'; +import AppstoreModel from '../models/AppstoreModel.js'; import DomainsModel from '../models/DomainsModel.js'; import UsersModel from '../models/UsersModel.js'; import GroupsModel from '../models/GroupsModel.js'; import { PROXY_APP_ID, ACL_OPTIONS } from '../constants.js'; const STEP = Object.freeze({ + LOADING: Symbol('loading'), DETAILS: Symbol('details'), INSTALL: Symbol('install'), }); +const appstoreModel = AppstoreModel.create(); const appsModel = AppsModel.create(); const domainsModel = DomainsModel.create(); const usersModel = UsersModel.create(); @@ -199,10 +202,31 @@ function onScreenshotNext() { elem.scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest' }); } +async function getApp(id, version = '') { + const [error, result] = await appstoreModel.get(id, version); + if (error) { + console.error(error); + return null; + } + + return result; +} + defineExpose({ - open: async function(a, appCountExceeded, domainList) { + open: async function(appId, version, appCountExceeded, domainList) { busy.value = false; - step.value = STEP.DETAILS; + step.value = STEP.LOADING; + + // give it some time to fetch before showing loading + const openTimer = setTimeout(dialog.value.open, 200); + + const a = await getApp(appId, version); + if (!a) { + clearTimeout(openTimer); + dialog.value.close(); + throw new Error('app not found'); + } + app.value = a; appMaxCountExceeded.value = appCountExceeded; manifest.value = a.manifest; @@ -243,8 +267,7 @@ defineExpose({ } currentScreenshotPos = 0; - - dialog.value.open(); + step.value = STEP.DETAILS; }, close() { dialog.value.close(); @@ -254,8 +277,11 @@ defineExpose({