mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
[comp] add AppCatalogDetails modal to display app info before install
This commit is contained in:
parent
581a919044
commit
daf8e58ce0
3 changed files with 217 additions and 4 deletions
|
@ -54,6 +54,43 @@
|
|||
"api_not_found": "Seems like the web-admin tried to query something that doesn't exist.",
|
||||
"api_not_responding": "The YunoHost API is not responding. Maybe 'yunohost-api' is down or got restarted?",
|
||||
"api_waiting": "Waiting for the server's response...",
|
||||
"app": {
|
||||
"antifeatures": "Antifeatures:",
|
||||
"preview": {
|
||||
"before_install": "Things to know before install",
|
||||
"integration": {
|
||||
"archs": "Supported architectures:",
|
||||
"ldap": {
|
||||
"false": "Does not use YunoHost accounts to login (LDAP)",
|
||||
"null": "No information about LDAP integration",
|
||||
"true": "Use YunoHost accounts to login (LDAP)"
|
||||
},
|
||||
"multi_instance": {
|
||||
"false": "Can be installed only once",
|
||||
"true": "Can be installed several times"
|
||||
},
|
||||
"resources": "Typical resource usage: {ram} RAM, {disk} disk",
|
||||
"sso": {
|
||||
"false": "Single sign-on is not available (SSO)",
|
||||
"null": "No information about SSO integration",
|
||||
"true": "Single sign-on is available (SSO)"
|
||||
},
|
||||
"title": "YunoHost integration"
|
||||
},
|
||||
"links": {
|
||||
"admindoc": "Official documentation",
|
||||
"code": "Upstream code repository",
|
||||
"forum": "Topics about this app on YunoHost's forum",
|
||||
"package": "YunoHost package repository",
|
||||
"title": "Links",
|
||||
"website": "Website"
|
||||
},
|
||||
"title": "App details",
|
||||
"try_demo": "Try the demo",
|
||||
"version": "Current version: {version}"
|
||||
},
|
||||
"potential_alternative_to": "Potential alternative to:"
|
||||
},
|
||||
"app_choose_category": "Choose a category",
|
||||
"app_config_panel": "Config panel",
|
||||
"app_config_panel_label": "Configure this app",
|
||||
|
|
|
@ -106,10 +106,15 @@
|
|||
</b-card>
|
||||
</card-deck-feed>
|
||||
|
||||
<b-modal
|
||||
<app-catalog-details
|
||||
v-if="selectedApp"
|
||||
id="modal-app-info"
|
||||
:app-id="selectedApp"
|
||||
:antifeatures="antifeatures"
|
||||
@ok="onInstallClick(selectedApp)"
|
||||
@hide="selectedApp = undefined"
|
||||
/>
|
||||
|
||||
<template #bot>
|
||||
<!-- INSTALL CUSTOM APP -->
|
||||
<card-form
|
||||
|
@ -154,6 +159,7 @@
|
|||
import { validationMixin } from 'vuelidate'
|
||||
|
||||
import CardDeckFeed from '@/components/CardDeckFeed'
|
||||
import AppCatalogDetails from './AppCatalogDetails'
|
||||
import { required, appRepoUrl } from '@/helpers/validators'
|
||||
import { randint } from '@/helpers/commons'
|
||||
|
||||
|
@ -161,18 +167,20 @@ export default {
|
|||
name: 'AppCatalog',
|
||||
|
||||
components: {
|
||||
CardDeckFeed
|
||||
CardDeckFeed,
|
||||
AppCatalogDetails
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
queries: [
|
||||
['GET', 'apps/catalog?full&with_categories']
|
||||
['GET', 'apps/catalog?full&with_categories&with_antifeatures']
|
||||
],
|
||||
|
||||
// Data
|
||||
apps: undefined,
|
||||
selectedApp: undefined,
|
||||
antifeatures: undefined,
|
||||
|
||||
// Filtering options
|
||||
qualityOptions: [
|
||||
|
@ -291,6 +299,7 @@ export default {
|
|||
data.categories.forEach(({ title, id, icon, subtags, description }) => {
|
||||
this.categories.push({ text: title, value: id, icon, subtags, description })
|
||||
})
|
||||
this.antifeatures = Object.fromEntries(data.antifeatures.map((af) => ([af.id, af])))
|
||||
},
|
||||
|
||||
setCategory () {
|
||||
|
@ -301,7 +310,8 @@ export default {
|
|||
},
|
||||
|
||||
// INSTALL APP
|
||||
async onInstallClick (app) {
|
||||
async onInstallClick (appId) {
|
||||
const app = this.apps.find((app) => app.id === appId)
|
||||
if (!app.decent_quality) {
|
||||
const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_install_app_' + app.state))
|
||||
if (!confirmed) return
|
||||
|
|
166
app/src/views/app/AppCatalogDetails.vue
Normal file
166
app/src/views/app/AppCatalogDetails.vue
Normal file
|
@ -0,0 +1,166 @@
|
|||
<template>
|
||||
<b-modal
|
||||
v-bind="$attrs" v-on="$listeners"
|
||||
body-class="p-0"
|
||||
static lazy size="lg"
|
||||
:title="$t('app.preview.title')" :ok-title="$t('install')"
|
||||
>
|
||||
<b-overlay :show="app === undefined">
|
||||
<template v-if="app">
|
||||
<section class="p-3">
|
||||
<h3>{{ app.name }}</h3>
|
||||
|
||||
<p v-if="app.alternatives" class="mt-3">
|
||||
<strong v-t="'app.potential_alternative_to'" />
|
||||
{{ app.alternatives }}
|
||||
</p>
|
||||
|
||||
<vue-showdown :markdown="app.description" flavor="github" />
|
||||
|
||||
<b-img
|
||||
v-if="app.image"
|
||||
:src="app.image"
|
||||
aria-hidden="true" class="d-block mb-3" fluid
|
||||
/>
|
||||
|
||||
<p>{{ $t('app.preview.version', { version: app.version }) }}</p>
|
||||
|
||||
<b-button
|
||||
v-if="app.demo"
|
||||
:href="app.demo" variant="primary" target="_blank"
|
||||
>
|
||||
<icon iname="external-link" />
|
||||
{{ $t('app.preview.try_demo') }}
|
||||
</b-button>
|
||||
</section>
|
||||
|
||||
<card-collapse
|
||||
id="app-warning" flush variant="warning"
|
||||
:title="$t('app.preview.before_install')"
|
||||
>
|
||||
<b-card-body>
|
||||
<strong v-t="'app.antifeatures'" class="d-block mb-1" />
|
||||
<ul class="antifeatures">
|
||||
<li v-for="antifeature in app.antifeatures" :key="antifeature.id">
|
||||
<icon :iname="antifeature.icon" class="md mr-1" />
|
||||
{{ antifeature.title }}
|
||||
<explain-what
|
||||
:id="antifeature.id"
|
||||
:title="antifeature.title"
|
||||
:content="antifeature.description"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<vue-showdown :markdown="app.preInstall" flavor="github" />
|
||||
</b-card-body>
|
||||
</card-collapse>
|
||||
|
||||
<card-collapse id="app-integration" flush :title="$t('app.preview.integration.title')">
|
||||
<b-list-group flush tag="section">
|
||||
<yuno-list-group-item variant="info">
|
||||
{{ $t('app.preview.integration.archs') }} {{ app.integration.archs }}
|
||||
</yuno-list-group-item>
|
||||
<yuno-list-group-item :variant="app.integration.ldap ? 'success' : 'warning'">
|
||||
{{ $t(`app.preview.integration.ldap.${app.integration.ldap}`) }}
|
||||
</yuno-list-group-item>
|
||||
<yuno-list-group-item :variant="app.integration.sso ? 'success' : 'warning'">
|
||||
{{ $t(`app.preview.integration.sso.${app.integration.sso}`) }}
|
||||
</yuno-list-group-item>
|
||||
<yuno-list-group-item variant="info">
|
||||
{{ $t(`app.preview.integration.multi_instance.${app.integration.multi_instance}`) }}
|
||||
</yuno-list-group-item>
|
||||
<yuno-list-group-item variant="info">
|
||||
{{ $t('app.preview.integration.resources', app.integration.resources) }}
|
||||
</yuno-list-group-item>
|
||||
</b-list-group>
|
||||
</card-collapse>
|
||||
|
||||
<card-collapse id="app-links" flush :title="$t('app.preview.links.title')">
|
||||
<b-list-group flush tag="section">
|
||||
<yuno-list-group-item v-for="[key, link] in app.links" :key="key" no-status>
|
||||
<b-link :href="link" target="_blank">
|
||||
{{ $t('app.preview.links.' + key) }}
|
||||
</b-link>
|
||||
</yuno-list-group-item>
|
||||
</b-list-group>
|
||||
</card-collapse>
|
||||
</template>
|
||||
</b-overlay>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import api from '@/api'
|
||||
import CardCollapse from '@/components/CardCollapse'
|
||||
import { formatI18nField } from '@/helpers/yunohostArguments'
|
||||
|
||||
export default {
|
||||
name: 'AppCatalogDetails',
|
||||
|
||||
components: {
|
||||
CardCollapse
|
||||
},
|
||||
|
||||
props: {
|
||||
appId: { type: String, required: true },
|
||||
antifeatures: { type: Object, required: true }
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
app: undefined
|
||||
}
|
||||
},
|
||||
|
||||
async created () {
|
||||
let { id, name, version, potential_alternative_to: alternatives, ...app } = await api.get('apps/manifest?app=' + this.appId)
|
||||
const archs = app.integration.architectures
|
||||
const integration = {
|
||||
archs: Array.isArray(archs) ? archs.join(this.$i18n.t('words.separator')) : archs,
|
||||
ldap: app.integration.ldap === '?' ? null : app.integration.ldap,
|
||||
sso: app.integration.sso === '?' ? null : app.integration.sso,
|
||||
multi_instance: app.integration.multi_instance,
|
||||
resources: {
|
||||
ram: app.integration.ram.runtime,
|
||||
disk: app.integration.disk
|
||||
}
|
||||
}
|
||||
|
||||
const links = [
|
||||
...['website', 'admindoc', 'code'].map((key) => ([key, app.upstream[key]])),
|
||||
['package', app.remote.url],
|
||||
['forum', `https://forum.yunohost.org/tag/${id}`]
|
||||
].filter(([key, val]) => !!val)
|
||||
|
||||
this.app = {
|
||||
id,
|
||||
name,
|
||||
alternatives: alternatives && alternatives.length ? alternatives.join(this.$i18n.t('words.separator')) : null,
|
||||
description: formatI18nField(app.doc.DESCRIPTION),
|
||||
image: app.image,
|
||||
demo: app.upstream.demo,
|
||||
version,
|
||||
preInstall: formatI18nField(app.notifications.pre_install.main),
|
||||
antifeatures: app.antifeatures?.map((af) => this.antifeatures[af]),
|
||||
integration,
|
||||
links
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .modal-body .b-overlay-wrap {
|
||||
min-height: 50vh;
|
||||
}
|
||||
|
||||
.antifeatures {
|
||||
padding-left: 1rem;
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in a new issue