diff --git a/dashboard/src/components/AppInstallDialog.vue b/dashboard/src/components/AppInstallDialog.vue index 80ff0ad64..d47113e3f 100644 --- a/dashboard/src/components/AppInstallDialog.vue +++ b/dashboard/src/components/AppInstallDialog.vue @@ -7,6 +7,8 @@ import { prettyDate, prettyBinarySize } from '@cloudron/pankow/utils'; import AccessControl from './AccessControl.vue'; import PortBindings from './PortBindings.vue'; import AppsModel from '../models/AppsModel.js'; +import CommunityModel from '../models/CommunityModel.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'; @@ -18,7 +20,9 @@ const STEP = Object.freeze({ INSTALL: Symbol('install'), }); +const appstoreModel = AppstoreModel.create(); const appsModel = AppsModel.create(); +const communityModel = CommunityModel.create(); const domainsModel = DomainsModel.create(); const usersModel = UsersModel.create(); const groupsModel = GroupsModel.create(); @@ -29,7 +33,7 @@ const dashboardDomain = inject('dashboardDomain'); // reactive const busy = ref(false); const formError = ref({}); -const app = ref({}); +const appData = ref({}); const manifest = ref({}); const step = ref(STEP.DETAILS); const dialog = useTemplateRef('dialogHandle'); @@ -155,7 +159,7 @@ async function onSubmit(overwriteDns) { if (manifest.value.id === PROXY_APP_ID) config.upstreamUri = upstreamUri.value; - const [error, result] = await appsModel.install(manifest.value, config); + const [error, result] = await appsModel.install(appData.value, config); if (!error) { dialog.value.close(); @@ -209,14 +213,36 @@ function onScreenshotNext() { } defineExpose({ - open: function(appData, appCountExceeded, domainList) { + open: async function(upstreamRef, appCountExceeded, domainList) { busy.value = false; - step.value = STEP.DETAILS; + step.value = STEP.LOADING; formError.value = {}; - app.value = appData; + // give it some time to fetch before showing loading + const openTimer = setTimeout(dialog.value.open, 200); + + if (upstreamRef.appStoreId) { + const [id, version] = upstreamRef.appStoreId.split('@'); + const [error, result] = await appstoreModel.get(id, version); + if (error) { + clearTimeout(openTimer); + dialog.value.close(); + throw new Error('App not found'); + } + appData.value = { ...result, ...upstreamRef }; + } else if (upstreamRef.versionsUrl) { + const [url, version] = upstreamRef.versionsUrl.split('@'); + const [error, result] = await communityModel.getApp(url, version); + if (error) { + clearTimeout(openTimer); + dialog.value.close(); + throw new Error(error.body?.message || 'Failed to fetch community app'); + } + appData.value = { ...result, ...upstreamRef }; + } + appMaxCountExceeded.value = appCountExceeded; - manifest.value = appData.manifest; + manifest.value = appData.value.manifest; location.value = ''; accessRestrictionOption.value = ACL_OPTIONS.ANY; accessRestrictionAcl.value = { users: [], groups: [] }; @@ -233,8 +259,8 @@ defineExpose({ // preselect with dashboard domain domain.value = domains.value.find(d => d.domain === dashboardDomain.value).domain; - tcpPorts.value = appData.manifest.tcpPorts; - udpPorts.value = appData.manifest.udpPorts; + tcpPorts.value = manifest.value.tcpPorts; + udpPorts.value = manifest.value.udpPorts; // ensure we have value property for (const p in tcpPorts.value) { @@ -246,7 +272,7 @@ defineExpose({ udpPorts.value[p].enabled = udpPorts.value[p].enabledByDefault ?? true; } - secondaryDomains.value = appData.manifest.httpPorts; + secondaryDomains.value = manifest.value.httpPorts; for (const p in secondaryDomains.value) { const port = secondaryDomains.value[p]; port.value = port.defaultValue; @@ -254,7 +280,7 @@ defineExpose({ } currentScreenshotPos = 0; - dialog.value.open(); + step.value = STEP.DETAILS; }, close() { dialog.value.close(); @@ -270,13 +296,13 @@ defineExpose({