initial implementation of community packages
This commit is contained in:
@@ -7,7 +7,6 @@ import { prettyDate, prettyBinarySize } 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';
|
||||
@@ -19,7 +18,6 @@ const STEP = Object.freeze({
|
||||
INSTALL: Symbol('install'),
|
||||
});
|
||||
|
||||
const appstoreModel = AppstoreModel.create();
|
||||
const appsModel = AppsModel.create();
|
||||
const domainsModel = DomainsModel.create();
|
||||
const usersModel = UsersModel.create();
|
||||
@@ -210,35 +208,15 @@ 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(appId, version, appCountExceeded, domainList) {
|
||||
open: function(appData, appCountExceeded, domainList) {
|
||||
busy.value = false;
|
||||
step.value = STEP.LOADING;
|
||||
step.value = STEP.DETAILS;
|
||||
formError.value = {};
|
||||
|
||||
// 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;
|
||||
app.value = appData;
|
||||
appMaxCountExceeded.value = appCountExceeded;
|
||||
manifest.value = a.manifest;
|
||||
manifest.value = appData.manifest;
|
||||
location.value = '';
|
||||
accessRestrictionOption.value = ACL_OPTIONS.ANY;
|
||||
accessRestrictionAcl.value = { users: [], groups: [] };
|
||||
@@ -255,8 +233,8 @@ defineExpose({
|
||||
// preselect with dashboard domain
|
||||
domain.value = domains.value.find(d => d.domain === dashboardDomain.value).domain;
|
||||
|
||||
tcpPorts.value = a.manifest.tcpPorts;
|
||||
udpPorts.value = a.manifest.udpPorts;
|
||||
tcpPorts.value = appData.manifest.tcpPorts;
|
||||
udpPorts.value = appData.manifest.udpPorts;
|
||||
|
||||
// ensure we have value property
|
||||
for (const p in tcpPorts.value) {
|
||||
@@ -268,7 +246,7 @@ defineExpose({
|
||||
udpPorts.value[p].enabled = udpPorts.value[p].enabledByDefault ?? true;
|
||||
}
|
||||
|
||||
secondaryDomains.value = a.manifest.httpPorts;
|
||||
secondaryDomains.value = appData.manifest.httpPorts;
|
||||
for (const p in secondaryDomains.value) {
|
||||
const port = secondaryDomains.value[p];
|
||||
port.value = port.defaultValue;
|
||||
@@ -276,7 +254,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
currentScreenshotPos = 0;
|
||||
step.value = STEP.DETAILS;
|
||||
dialog.value.open();
|
||||
},
|
||||
close() {
|
||||
dialog.value.close();
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<script setup>
|
||||
|
||||
import { ref, useTemplateRef } from 'vue';
|
||||
import { Dialog, TextInput, FormGroup } from '@cloudron/pankow';
|
||||
import CommunityModel from '../models/CommunityModel.js';
|
||||
|
||||
const communityModel = CommunityModel.create();
|
||||
|
||||
const emit = defineEmits([ 'success' ]);
|
||||
|
||||
const dialog = useTemplateRef('dialog');
|
||||
|
||||
const busy = ref(false);
|
||||
const formError = ref({});
|
||||
const url = ref('');
|
||||
const version = ref('latest');
|
||||
|
||||
async function onSubmit() {
|
||||
busy.value = true;
|
||||
formError.value = {};
|
||||
|
||||
const [error, result] = await communityModel.getApp(url.value, version.value);
|
||||
if (error) {
|
||||
formError.value.generic = error.body?.message || 'Failed to fetch community app';
|
||||
busy.value = false;
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
emit('success', result);
|
||||
dialog.value.close();
|
||||
busy.value = false;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open() {
|
||||
url.value = '';
|
||||
version.value = 'latest';
|
||||
formError.value = {};
|
||||
busy.value = false;
|
||||
dialog.value.open();
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog ref="dialog"
|
||||
title="Install Community App"
|
||||
confirm-label="Continue"
|
||||
:confirm-busy="busy"
|
||||
:confirm-active="!busy && url !== ''"
|
||||
reject-style="secondary"
|
||||
reject-label="Cancel"
|
||||
:reject-active="!busy"
|
||||
@confirm="onSubmit()"
|
||||
>
|
||||
<form @submit.prevent="onSubmit()" autocomplete="off">
|
||||
<fieldset :disabled="busy">
|
||||
<input type="submit" style="display: none;" />
|
||||
|
||||
<div class="error-label" v-if="formError.generic">{{ formError.generic }}</div>
|
||||
|
||||
<FormGroup>
|
||||
<label for="urlInput">CloudronVersions.json URL</label>
|
||||
<TextInput id="urlInput" v-model="url" required placeholder="https://example.com/CloudronVersions.json"/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<label for="versionInput">Version</label>
|
||||
<TextInput id="versionInput" v-model="version" required/>
|
||||
</FormGroup>
|
||||
</fieldset>
|
||||
</form>
|
||||
</Dialog>
|
||||
</template>
|
||||
Reference in New Issue
Block a user