diff --git a/apps/settings/js/vue-4.js b/apps/settings/js/vue-4.js index b2e85769945182a862fdcfa3765efb9df5195c89..be21d10b35e1c81cbd6ac945dcb729e6a53222e0 100644 Binary files a/apps/settings/js/vue-4.js and b/apps/settings/js/vue-4.js differ diff --git a/apps/settings/js/vue-4.js.map b/apps/settings/js/vue-4.js.map index d9b80b7ad159a28f084d023b5820a6e481b3a0a7..d78ea55117994640840113ac4e5f206d6defba58 100644 Binary files a/apps/settings/js/vue-4.js.map and b/apps/settings/js/vue-4.js.map differ diff --git a/apps/settings/js/vue-5.js b/apps/settings/js/vue-5.js index 98317284ec1e54385e20c5871e513deb7359d6eb..8eb491497f46c411f12a9d9aa142e2dd6d51631a 100644 Binary files a/apps/settings/js/vue-5.js and b/apps/settings/js/vue-5.js differ diff --git a/apps/settings/js/vue-5.js.map b/apps/settings/js/vue-5.js.map index d2fa0760e74879ab5c9f644dc70967065f332a3e..9f67448e32291599e495d78b269469de3c34ae21 100644 Binary files a/apps/settings/js/vue-5.js.map and b/apps/settings/js/vue-5.js.map differ diff --git a/apps/settings/js/vue-settings-apps-users-management.js b/apps/settings/js/vue-settings-apps-users-management.js index 2e1fd3a3c9f099e0d01ae508aa068b10fb2fad9c..5b9b5beee627f3c98d599d12ecea191327c52951 100644 Binary files a/apps/settings/js/vue-settings-apps-users-management.js and b/apps/settings/js/vue-settings-apps-users-management.js differ diff --git a/apps/settings/js/vue-settings-apps-users-management.js.map b/apps/settings/js/vue-settings-apps-users-management.js.map index 7e8e035706ca0785ab2561166f0a57e74bcd9696..bfaa3be2d04ab982c6dfa9451f2db0cf62ea42d5 100644 Binary files a/apps/settings/js/vue-settings-apps-users-management.js.map and b/apps/settings/js/vue-settings-apps-users-management.js.map differ diff --git a/apps/settings/src/components/AppList.vue b/apps/settings/src/components/AppList.vue index f03d7c5a6947b7938c2458a45b380f101fa61257..a406f6b8ff63e81d44551a6a86118d9598e5e576 100644 --- a/apps/settings/src/components/AppList.vue +++ b/apps/settings/src/components/AppList.vue @@ -96,11 +96,9 @@ </template> <script> -import pLimit from 'p-limit' - import AppItem from './AppList/AppItem' import PrefixMixin from './PrefixMixin' -import recommended from '../recommendedApps' +import pLimit from 'p-limit' export default { name: 'AppList', @@ -131,26 +129,26 @@ export default { return OC.Util.naturalSortCompare(sortStringA, sortStringB) }) - switch (this.category) { - case 'installed': + if (this.category === 'installed') { return apps.filter(app => app.installed) - case 'recommended': - return apps.filter(app => recommended.includes(app.id)) - case 'enabled': + } + if (this.category === 'enabled') { return apps.filter(app => app.active && app.installed) - case 'disabled': + } + if (this.category === 'disabled') { return apps.filter(app => !app.active && app.installed) - case 'app-bundles': + } + if (this.category === 'app-bundles') { return apps.filter(app => app.bundles) - case 'updates': + } + if (this.category === 'updates') { return apps.filter(app => app.update) - default: - // filter app store categories - return apps.filter(app => { - return app.appstore && app.category !== undefined - && (app.category === this.category || app.category.indexOf(this.category) > -1) - }) } + // filter app store categories + return apps.filter(app => { + return app.appstore && app.category !== undefined + && (app.category === this.category || app.category.indexOf(this.category) > -1) + }) }, bundles() { return this.$store.getters.getServerData.bundles.filter(bundle => this.bundleApps(bundle.id).length > 0) @@ -177,7 +175,7 @@ export default { return !this.useListView && !this.useBundleView }, useListView() { - return ['installed', 'recommended', 'enabled', 'disabled', 'updates'].includes(this.category) + return (this.category === 'installed' || this.category === 'enabled' || this.category === 'disabled' || this.category === 'updates') }, useBundleView() { return (this.category === 'app-bundles') @@ -198,24 +196,6 @@ export default { } } }, - mounted() { - if (this.category === 'recommended' && 'download' in this.$route.query) { - const limit = pLimit(1) - const installing = this.apps - .filter(app => !app.active && app.canInstall) - .map(app => limit(() => this.$store.dispatch('enableApp', { appId: app.id, groups: [] }))) - console.debug(`installing ${installing.length} recommended apps`) - Promise.all(installing) - .then(() => { - console.info('recommended apps installed') - - if ('returnTo' in this.$route.query) { - window.location = this.$route.query.returnTo - } - }) - .catch(e => console.error('could not install recommended apps', e)) - } - }, methods: { toggleBundle(id) { if (this.allBundlesEnabled(id)) { diff --git a/apps/settings/src/views/Apps.vue b/apps/settings/src/views/Apps.vue index a2c4cae825d0cdf02b153c4f92735e0a6e0c6185..2e0649f7f56555c5f350990ee3890377796301f6 100644 --- a/apps/settings/src/views/Apps.vue +++ b/apps/settings/src/views/Apps.vue @@ -31,10 +31,7 @@ </ul> </AppNavigation> <AppContent class="app-settings-content" :class="{ 'icon-loading': loadingList }"> - <AppList v-if="!loadingList" - :category="category" - :app="currentApp" - :search="searchQuery" /> + <AppList :category="category" :app="currentApp" :search="searchQuery" /> </AppContent> <AppSidebar v-if="id && currentApp" @close="hideAppDetails"> <AppDetails :category="category" :app="currentApp" /> @@ -136,21 +133,13 @@ export default { icon: 'icon-category-installed', text: t('settings', 'Your apps') }, - { - id: 'app-category-recommended', - classes: [], - router: { name: 'apps-category', params: { category: 'recommended' } }, - icon: 'icon-category-installed', - text: t('settings', 'Recommended apps') - }, { id: 'app-category-enabled', classes: [], icon: 'icon-category-enabled', router: { name: 'apps-category', params: { category: 'enabled' } }, text: t('settings', 'Active apps') - }, - { + }, { id: 'app-category-disabled', classes: [], icon: 'icon-category-disabled', diff --git a/core/Controller/RecommendedAppsController.php b/core/Controller/RecommendedAppsController.php new file mode 100644 index 0000000000000000000000000000000000000000..9f3f6187d29184c03bb46ba0c6e4a4b42cb26eec --- /dev/null +++ b/core/Controller/RecommendedAppsController.php @@ -0,0 +1,53 @@ +<?php declare(strict_types=1); + +/** + * @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/>. + */ + +namespace OC\Core\Controller; + +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\AppFramework\Http\Response; +use OCP\AppFramework\Http\StandaloneTemplateResponse; +use OCP\IInitialStateService; +use OCP\IRequest; + +class RecommendedAppsController extends Controller { + + /** @var IInitialStateService */ + private $initialStateService; + + public function __construct(IRequest $request, + IInitialStateService $initialStateService) { + parent::__construct('core', $request); + $this->initialStateService = $initialStateService; + } + + /** + * @NoCSRFRequired + * @return Response + */ + public function index(): Response { + $this->initialStateService->provideInitialState('core', 'defaultPageUrl', \OC_Util::getDefaultPageUrl()); + return new StandaloneTemplateResponse($this->appName, 'recommendedapps', [], 'guest'); + } + +} diff --git a/core/Controller/SetupController.php b/core/Controller/SetupController.php index 1d83b0f42b59cd0dfd6aa2147394045723101bf8..302edccf7a64df7fec97c2dc2d8d912a5c0f569c 100644 --- a/core/Controller/SetupController.php +++ b/core/Controller/SetupController.php @@ -123,7 +123,7 @@ class SetupController { if ($installRecommended) { $urlGenerator = \OC::$server->getURLGenerator(); - $location = $urlGenerator->getAbsoluteURL('/index.php/settings/apps/recommended?download&returnTo=' . urlencode(\OC_Util::getDefaultPageUrl())); + $location = $urlGenerator->getAbsoluteURL('index.php/core/apps/recommended'); header('Location: ' . $location); exit(); } diff --git a/core/js/dist/login.js b/core/js/dist/login.js index 5ea0190122eac45bf3ff02acb483f2f05b10fd97..f0c2f5ac6949cf78c3832da9484cac6604db5c79 100644 Binary files a/core/js/dist/login.js and b/core/js/dist/login.js differ diff --git a/core/js/dist/login.js.map b/core/js/dist/login.js.map index 00070f2b94d8ef9d932a3342afd439bbbc8544b9..52f80a252a0566094aa276ba69d977158f9972e9 100644 Binary files a/core/js/dist/login.js.map and b/core/js/dist/login.js.map differ diff --git a/core/js/dist/main.js b/core/js/dist/main.js index 25ab4584a5f9cba1f35e8088c282209421866354..0165a44d4ffb15aad8169b0578d2434335108390 100644 Binary files a/core/js/dist/main.js and b/core/js/dist/main.js differ diff --git a/core/js/dist/main.js.map b/core/js/dist/main.js.map index 41ce56dd140000f7300d86a5ccb4df8b0ba8f507..ce6ec5de97b75005520a670fdb20aae8ad447337 100644 Binary files a/core/js/dist/main.js.map and b/core/js/dist/main.js.map differ diff --git a/core/js/dist/maintenance.js b/core/js/dist/maintenance.js index 71d3594216f9bd415f10ef19f863e4e5019e6a22..bf7d88665b794de03a11de3174c6b92bc0c13946 100644 Binary files a/core/js/dist/maintenance.js and b/core/js/dist/maintenance.js differ diff --git a/core/js/dist/maintenance.js.map b/core/js/dist/maintenance.js.map index f94bbff48beb962c64817ad0acb61740e8d74d18..27d2f3d16b041c94ab35ea36be8197bcb65acc5b 100644 Binary files a/core/js/dist/maintenance.js.map and b/core/js/dist/maintenance.js.map differ diff --git a/core/js/dist/recommendedapps.js b/core/js/dist/recommendedapps.js new file mode 100644 index 0000000000000000000000000000000000000000..105c68c3cb2a5615046ce4cabed2ba326b83d5ea Binary files /dev/null and b/core/js/dist/recommendedapps.js differ diff --git a/core/js/dist/recommendedapps.js.map b/core/js/dist/recommendedapps.js.map new file mode 100644 index 0000000000000000000000000000000000000000..a57245548a9c9b2de6860a4352be05d5b28fb31e Binary files /dev/null and b/core/js/dist/recommendedapps.js.map differ diff --git a/core/routes.php b/core/routes.php index f88bab1d539efb63bece1ede0ece7827aeb2f713..5fb13bc298afccf1fc9addf73ec6a0f2a7bf5721 100644 --- a/core/routes.php +++ b/core/routes.php @@ -74,6 +74,7 @@ $application->registerRoutes($this, [ ['name' => 'OCJS#getConfig', 'url' => '/core/js/oc.js', 'verb' => 'GET'], ['name' => 'Preview#getPreviewByFileId', 'url' => '/core/preview', 'verb' => 'GET'], ['name' => 'Preview#getPreview', 'url' => '/core/preview.png', 'verb' => 'GET'], + ['name' => 'RecommendedApps#index', 'url' => '/core/apps/recommended', 'verb' => 'GET'], ['name' => 'Svg#getSvgFromCore', 'url' => '/svg/core/{folder}/{fileName}', 'verb' => 'GET'], ['name' => 'Svg#getSvgFromApp', 'url' => '/svg/{app}/{fileName}', 'verb' => 'GET'], ['name' => 'Css#getCss', 'url' => '/css/{appName}/{fileName}', 'verb' => 'GET'], diff --git a/core/src/components/setup/RecommendedApps.vue b/core/src/components/setup/RecommendedApps.vue new file mode 100644 index 0000000000000000000000000000000000000000..e8f56c8468dfc690608a24c1e97ccf58b337418e --- /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 0000000000000000000000000000000000000000..4a9c8623a7f815d83720c868c728d032361f0aff --- /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 0000000000000000000000000000000000000000..ac0afb99daa866df67ccd7052dfb39a2184cf262 --- /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') diff --git a/apps/settings/src/recommendedApps.js b/core/templates/recommendedapps.php similarity index 88% rename from apps/settings/src/recommendedApps.js rename to core/templates/recommendedapps.php index d2868b8728b3c3bca2ee73dc297a213b6186a45b..2fe13355278bdeb52235822fe125e67c005d9e77 100644 --- a/apps/settings/src/recommendedApps.js +++ b/core/templates/recommendedapps.php @@ -1,4 +1,6 @@ -/* +<?php declare(strict_types=1); + +/** * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> * * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at> @@ -19,8 +21,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -export default [ - 'contacts', - 'calendar', - 'mail' -] +script('core', 'dist/recommendedapps'); + +?> + +<div id="recommended-apps"></div> diff --git a/core/webpack.js b/core/webpack.js index 9404c354ebb4d848da2f481ac9a0c205a5e56759..cb80f049fab685f38c93c9d8faeea1d36127dfaa 100644 --- a/core/webpack.js +++ b/core/webpack.js @@ -7,6 +7,7 @@ module.exports = [ login: path.join(__dirname, 'src/login.js'), main: path.join(__dirname, 'src/main.js'), maintenance: path.join(__dirname, 'src/maintenance.js'), + recommendedapps: path.join(__dirname, 'src/recommendedapps.js'), }, output: { filename: '[name].js', diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 21e44181d971bbfffdcfe3c3289101a8d7a37bb3..016b3c360efab4260ed49b1aaf131840431791c3 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -789,6 +789,7 @@ return array( 'OC\\Core\\Controller\\OCJSController' => $baseDir . '/core/Controller/OCJSController.php', 'OC\\Core\\Controller\\OCSController' => $baseDir . '/core/Controller/OCSController.php', 'OC\\Core\\Controller\\PreviewController' => $baseDir . '/core/Controller/PreviewController.php', + 'OC\\Core\\Controller\\RecommendedAppsController' => $baseDir . '/core/Controller/RecommendedAppsController.php', 'OC\\Core\\Controller\\SearchController' => $baseDir . '/core/Controller/SearchController.php', 'OC\\Core\\Controller\\SetupController' => $baseDir . '/core/Controller/SetupController.php', 'OC\\Core\\Controller\\SvgController' => $baseDir . '/core/Controller/SvgController.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 6e4762360e078289c451e9c8cce4cdfb2c4d0a3b..5d63c7740eb7066e100406a238d5aa2eb085bf0e 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -818,6 +818,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Controller\\OCJSController' => __DIR__ . '/../../..' . '/core/Controller/OCJSController.php', 'OC\\Core\\Controller\\OCSController' => __DIR__ . '/../../..' . '/core/Controller/OCSController.php', 'OC\\Core\\Controller\\PreviewController' => __DIR__ . '/../../..' . '/core/Controller/PreviewController.php', + 'OC\\Core\\Controller\\RecommendedAppsController' => __DIR__ . '/../../..' . '/core/Controller/RecommendedAppsController.php', 'OC\\Core\\Controller\\SearchController' => __DIR__ . '/../../..' . '/core/Controller/SearchController.php', 'OC\\Core\\Controller\\SetupController' => __DIR__ . '/../../..' . '/core/Controller/SetupController.php', 'OC\\Core\\Controller\\SvgController' => __DIR__ . '/../../..' . '/core/Controller/SvgController.php', diff --git a/package-lock.json b/package-lock.json index 0da04927c39593dad801f29f29232b444d32f661..99e65c93f373bd267215090cad729b3d80bac156 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2168,6 +2168,21 @@ } } }, + "@nextcloud/l10n": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-0.2.1.tgz", + "integrity": "sha512-iLdyxluCehsRibR4R/nH3O8T9CcGoAaW3eWEdQW2qPtn6eEiBXASek5nWhXa5hko1GvE7koYia4FoTWuL85/Ng==", + "requires": { + "core-js": "3.2.1" + }, + "dependencies": { + "core-js": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==" + } + } + }, "@nextcloud/logger": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@nextcloud/logger/-/logger-0.1.0.tgz", @@ -3122,7 +3137,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -3159,7 +3174,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -3203,7 +3218,7 @@ }, "buffer": { "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { @@ -3644,7 +3659,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -3657,7 +3672,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -3918,7 +3933,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { @@ -4514,7 +4529,7 @@ }, "events": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "resolved": "http://registry.npmjs.org/events/-/events-3.0.0.tgz", "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", "dev": true }, @@ -5551,7 +5566,7 @@ }, "get-stream": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { @@ -8420,7 +8435,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -8748,7 +8763,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -9062,7 +9077,7 @@ }, "stream-browserify": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "resolved": "http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "dev": true, "requires": { @@ -9162,7 +9177,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, @@ -9408,7 +9423,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -9462,7 +9477,7 @@ }, "underscore": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "resolved": "http://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" }, "unicode-canonical-property-names-ecmascript": { diff --git a/package.json b/package.json index dad7ead15c42380d99840158a65197bb86681ef1..8a9b154b476b44df43b388e3713017564abb886a 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@nextcloud/dialogs": "^0.1.1", "@nextcloud/event-bus": "^0.2.1", "@nextcloud/initial-state": "^0.2.0", + "@nextcloud/l10n": "^0.2.1", "@nextcloud/logger": "^0.1.0", "@nextcloud/paths": "^0.2.0", "@nextcloud/router": "^0.1.0",