Improve reactivity if app install dialog should be opened

This commit is contained in:
Johannes Zellner
2025-12-10 14:20:59 +01:00
parent 241be5eaee
commit 52e1276c8d
2 changed files with 37 additions and 11 deletions
+33 -7
View File
@@ -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({
</script>
<template>
<Dialog ref="dialogHandle" @close="onClose()" :show-x="true" style="width: unset; min-width: min(450px, 95%)">
<div class="app-install-dialog-body" :class="{ 'step-detail': step === STEP.DETAILS, 'step-install': step === STEP.INSTALL }">
<Dialog ref="dialogHandle" @close="onClose()" :show-x="step !== STEP.LOADING" style="width: unset;" :style="{ 'min-width': step !== STEP.LOADING ? 'min(450px, 95%)' : 'unset' }">
<div v-if="step === STEP.LOADING" class="app-install-dialog-body">
<Spinner class="pankow-spinner-large"/>
</div>
<div v-else class="app-install-dialog-body" :class="{ 'step-detail': step === STEP.DETAILS, 'step-install': step === STEP.INSTALL }">
<div class="app-install-header">
<div class="summary" v-if="app.manifest">
<div class="title"><img class="icon pankow-no-desktop" style="width: 32px; height: 32px; margin-right: 10px" :src="app.iconUrl" />{{ manifest.title }}</div>
+4 -4
View File
@@ -155,10 +155,10 @@ async function onHashChange() {
const params = new URLSearchParams(window.location.hash.slice(window.location.hash.indexOf('?')));
const version = params.get('version') || 'latest';
const app = await getApp(appId, version);
if (app) {
appInstallDialog.value.open(app, installedApps.value.length >= features.value.appMaxCount, domains.value);
} else {
try {
await appInstallDialog.value.open(appId, version, installedApps.value.length >= features.value.appMaxCount, domains.value);
// eslint-disable-next-line no-unused-vars
} catch (e) {
inputDialog.value.info({
title: t('appstore.appNotFoundDialog.title'),
message: t('appstore.appNotFoundDialog.description', { appId, version }),