2828 <p v-else-if =" loadingAppsError" class =" loading-error text-center" >
2929 {{ t('core', 'Could not fetch list of apps from the App Store.') }}
3030 </p >
31- <p v-else class =" text-center" >
31+ <p v-else-if = " installingApps " class =" text-center" >
3232 {{ t('core', 'Installing apps …') }}
3333 </p >
34+
3435 <div v-for =" app in recommendedApps" :key =" app.id" class =" app" >
3536 <img :src =" customIcon(app.id)" alt =" " >
3637 <div class =" info" >
5152 </p >
5253 </div >
5354 </div >
55+
56+ <InstallButton v-if =" showInstallButton"
57+ @click.stop.prevent =" installApps" />
58+
5459 <p class =" text-center" >
5560 <a :href =" defaultPageUrl" >{{ t('core', 'Cancel') }}</a >
5661 </p >
@@ -64,6 +69,9 @@ import { loadState } from '@nextcloud/initial-state'
6469import pLimit from ' p-limit'
6570import { translate as t } from ' @nextcloud/l10n'
6671
72+ // TODO replace with Button component when @nextcloud/vue is upgraded to v5
73+ import InstallButton from ' ./InstallButton'
74+
6775import logger from ' ../../logger'
6876
6977const recommended = {
@@ -97,8 +105,13 @@ const defaultPageUrl = loadState('core', 'defaultPageUrl')
97105
98106export default {
99107 name: ' RecommendedApps' ,
108+ components: {
109+ InstallButton,
110+ },
100111 data () {
101112 return {
113+ showInstallButton: false ,
114+ installingApps: false ,
102115 loadingApps: true ,
103116 loadingAppsError: false ,
104117 apps: [],
@@ -110,28 +123,28 @@ export default {
110123 return this .apps .filter (app => recommendedIds .includes (app .id ))
111124 },
112125 },
113- mounted () {
114- return axios .get (generateUrl (' settings/apps/list' ))
115- .then (resp => resp .data )
116- .then (data => {
117- logger .info (` ${ data .apps .length } apps fetched` )
118-
119- this .apps = data .apps .map (app => Object .assign (app, { loading: false , installationError: false }))
120- logger .debug (` ${ this .recommendedApps .length } recommended apps found` , { apps: this .recommendedApps })
121-
122- this .installApps ()
123- })
124- .catch (error => {
125- logger .error (' could not fetch app list' , { error })
126-
127- this .loadingAppsError = true
128- })
129- .then (() => {
130- this .loadingApps = false
131- })
126+ async mounted () {
127+ try {
128+ const { data } = await axios .get (generateUrl (' settings/apps/list' ))
129+ logger .info (` ${ data .apps .length } apps fetched` )
130+
131+ this .apps = data .apps .map (app => Object .assign (app, { loading: false , installationError: false }))
132+ logger .debug (` ${ this .recommendedApps .length } recommended apps found` , { apps: this .recommendedApps })
133+
134+ this .showInstallButton = true
135+ } catch (error) {
136+ logger .error (' could not fetch app list' , { error })
137+
138+ this .loadingAppsError = true
139+ } finally {
140+ this .loadingApps = false
141+ }
132142 },
133143 methods: {
134144 installApps () {
145+ this .showInstallButton = false
146+ this .installingApps = true
147+
135148 const limit = pLimit (1 )
136149 const installing = this .recommendedApps
137150 .filter (app => ! app .active && app .isCompatible && app .canInstall )
@@ -180,8 +193,15 @@ export default {
180193
181194}
182195
183- p .loading , p .loading-error {
184- height : 100px ;
196+ p {
197+ & .loading ,
198+ & .loading-error {
199+ height : 100px ;
200+ }
201+
202+ & :last-child {
203+ margin-top : 10px ;
204+ }
185205}
186206
187207.text-center {
0 commit comments