summaryrefslogtreecommitdiffstats
path: root/core/src
diff options
context:
space:
mode:
authorChristoph Wurst <christoph@winzerhof-wurst.at>2019-12-04 20:18:58 +0100
committerRoeland Jago Douma <roeland@famdouma.nl>2019-12-12 08:13:01 +0100
commit302558cfd2b3dd37e6332c0d9c650174b64f20fb (patch)
tree27a7bcbf35f94a496fc2c42c361c79793811418e /core/src
parent97deaf85b9d18cabfc345025ef273da24006c6de (diff)
downloadnextcloud-server-302558cfd2b3dd37e6332c0d9c650174b64f20fb.tar.gz
nextcloud-server-302558cfd2b3dd37e6332c0d9c650174b64f20fb.zip
Add a dedicated page for the recommended apps installation
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at> Signed-off-by: npmbuildbot[bot] <npmbuildbot[bot]@users.noreply.github.com>
Diffstat (limited to 'core/src')
-rw-r--r--core/src/components/setup/RecommendedApps.vue194
-rw-r--r--core/src/logger.js37
-rw-r--r--core/src/recommendedapps.js44
3 files changed, 275 insertions, 0 deletions
diff --git a/core/src/components/setup/RecommendedApps.vue b/core/src/components/setup/RecommendedApps.vue
new file mode 100644
index 00000000000..e8f56c8468d
--- /dev/null
+++ b/core/src/components/setup/RecommendedApps.vue
@@ -0,0 +1,194 @@
+<!--
+ - @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ -
+ - @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -->
+
+<template>
+ <div class="update">
+ <h2>{{ t('core', 'Recommended apps') }}</h2>
+ <p v-if="loadingApps" class="loading">
+ {{ t('core', 'Loading apps …') }}
+ </p>
+ <p v-else-if="loadingAppsError" class="loading-error">
+ {{ t('core', 'Could not fetch list of apps from the app store.') }}
+ </p>
+ <p v-else>
+ {{ t('core', 'Installing recommended apps …') }}
+ </p>
+ <div v-for="app in recommendedApps" :key="app.id" class="app">
+ <img :src="customIcon(app.id)" :alt="t('core', 'Nextcloud app {app}', { app: app.name })">
+ <div class="info">
+ <h3>
+ {{ app.name }}
+ <span v-if="app.loading" class="icon icon-loading-small" />
+ <span v-else-if="app.active" class="icon icon-checkmark-white" />
+ </h3>
+ <p v-html="customDescription(app.id)" />
+ <p v-if="app.installationError" class="error">
+ {{ t('core', 'App download or installation failed') }}
+ </p>
+ <p v-else-if="!app.isCompatible" class="error">
+ {{ t('core', 'Can\'t install this app because it is not compatible') }}
+ </p>
+ <p v-else-if="!app.canInstall" class="error">
+ {{ t('core', 'Can\'t install this app') }}
+ </p>
+ </div>
+ </div>
+ <a :href="defaultPageUrl">{{ t('core', 'Go back') }}</a>
+ </div>
+</template>
+
+<script>
+import axios from '@nextcloud/axios'
+import { generateUrl, imagePath } from '@nextcloud/router'
+import { loadState } from '@nextcloud/initial-state'
+import pLimit from 'p-limit'
+import { translate as t } from '@nextcloud/l10n'
+
+import logger from '../../logger'
+
+const recommended = {
+ calendar: {
+ description: t('core', 'Schedule work & meetings, synced with all your devices.'),
+ icon: imagePath('core', 'places/calendar.svg')
+ },
+ contacts: {
+ description: t('core', 'Keep your colleagues and friends in one place without leaking their private info.'),
+ icon: imagePath('core', 'places/contacts.svg')
+ },
+ mail: {
+ description: t('core', 'Simple email app nicely integrated with Files, Contacts and Calendar.'),
+ icon: imagePath('core', 'actions/mail.svg')
+ },
+ talk: {
+ description: t('core', 'Screensharing, online meetings and web conferencing – on desktop and with mobile apps.')
+ }
+}
+const recommendedIds = Object.keys(recommended)
+const defaultPageUrl = loadState('core', 'defaultPageUrl')
+
+export default {
+ name: 'RecommendedApps',
+ data() {
+ return {
+ loadingApps: true,
+ loadingAppsError: false,
+ apps: [],
+ defaultPageUrl
+ }
+ },
+ computed: {
+ recommendedApps() {
+ return this.apps.filter(app => recommendedIds.includes(app.id))
+ }
+ },
+ mounted() {
+ return axios.get(generateUrl('settings/apps/list'))
+ .then(resp => resp.data)
+ .then(data => {
+ logger.info(`${data.apps.length} apps fetched`)
+
+ this.apps = data.apps.map(app => Object.assign(app, { loading: false, installationError: false }))
+ logger.debug(`${this.recommendedApps.length} recommended apps found`, { apps: this.recommendedApps })
+
+ this.installApps()
+ })
+ .catch(error => {
+ logger.error('could not fetch app list', { error })
+
+ this.loadingAppsError = true
+ })
+ .then(() => {
+ this.loadingApps = false
+ })
+ },
+ methods: {
+ installApps() {
+ const limit = pLimit(1)
+ const installing = this.recommendedApps
+ .filter(app => !app.active && app.isCompatible && app.canInstall)
+ .map(app => limit(() => {
+ logger.info(`installing ${app.id}`)
+ app.loading = true
+ return axios.post(generateUrl(`settings/apps/enable`), { appIds: [app.id], groups: [] })
+ .catch(error => {
+ logger.error(`could not install ${app.id}`, { error })
+ app.installationError = true
+ })
+ .then(() => {
+ logger.info(`installed ${app.id}`)
+ app.loading = false
+ })
+ }))
+ logger.debug(`installing ${installing.length} recommended apps`)
+ Promise.all(installing)
+ .then(() => {
+ logger.info('all recommended apps installed, redirecting …')
+
+ window.location = defaultPageUrl
+ })
+ .catch(error => logger.error('could not install recommended apps', { error }))
+ },
+ customIcon(appId) {
+ if (!(appId in recommended)) {
+ logger.warn(`no app icon for recommended app ${appId}`)
+ return imagePath('core', 'places/default-app-icon.svg')
+ }
+ return recommended[appId].icon
+ },
+ customDescription(appId) {
+ if (!(appId in recommended)) {
+ logger.warn(`no app description for recommended app ${appId}`)
+ return ''
+ }
+ return recommended[appId].description
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+p.loading, p.loading-error {
+ height: 100px;
+}
+.app {
+ display: flex;
+ flex-direction: row;
+
+ img {
+ height: 64px;
+ width: 64px;
+ }
+
+ img, .info {
+ padding: 12px;
+ }
+
+ .info {
+ h3 {
+ text-align: left;
+ }
+
+ h3 > span.icon {
+ display: inline-block;
+ }
+ }
+}
+</style>
diff --git a/core/src/logger.js b/core/src/logger.js
new file mode 100644
index 00000000000..4a9c8623a7f
--- /dev/null
+++ b/core/src/logger.js
@@ -0,0 +1,37 @@
+/*
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import { getCurrentUser } from '@nextcloud/auth'
+import { getLoggerBuilder } from '@nextcloud/logger'
+
+const getLogger = user => {
+ if (user === null) {
+ return getLoggerBuilder()
+ .setApp('core')
+ .build()
+ }
+ return getLoggerBuilder()
+ .setApp('core')
+ .setUid(user.uid)
+ .build()
+}
+
+export default getLogger(getCurrentUser())
diff --git a/core/src/recommendedapps.js b/core/src/recommendedapps.js
new file mode 100644
index 00000000000..ac0afb99daa
--- /dev/null
+++ b/core/src/recommendedapps.js
@@ -0,0 +1,44 @@
+/*
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import { getRequestToken } from '@nextcloud/auth'
+import { generateFilePath } from '@nextcloud/router'
+import { translate as t } from '@nextcloud/l10n'
+import Vue from 'vue'
+
+import logger from './logger'
+import RecommendedApps from './components/setup/RecommendedApps'
+
+// eslint-disable-next-line camelcase
+__webpack_nonce__ = btoa(getRequestToken())
+// eslint-disable-next-line camelcase
+__webpack_public_path__ = generateFilePath('core', '', 'js/')
+
+Vue.mixin({
+ methods: {
+ t
+ }
+})
+
+const View = Vue.extend(RecommendedApps)
+new View().$mount('#recommended-apps')
+
+logger.debug('recommended apps view rendered')