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>
This commit is contained in:
parent
97deaf85b9
commit
302558cfd2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
|||
!function(t){function e(e){for(var n,o,i=e[0],a=e[1],s=0,c=[];s<i.length;s++)o=i[s],Object.prototype.hasOwnProperty.call(r,o)&&r[o]&&c.push(r[o][0]),r[o]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(t[n]=a[n]);for(u&&u(e);c.length;)c.shift()()}var n={},r={2:0};function o(e){if(n[e])return n[e].exports;var r=n[e]={i:e,l:!1,exports:{}};return t[e].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.e=function(t){var e=[],n=r[t];if(0!==n)if(n)e.push(n[2]);else{var i=new Promise((function(e,o){n=r[t]=[e,o]}));e.push(n[2]=i);var a,s=document.createElement("script");s.charset="utf-8",s.timeout=120,o.nc&&s.setAttribute("nonce",o.nc),s.src=function(t){return o.p+"vue-"+({}[t]||t)+".js?v="+{0:"f1063acdadacc88028ec",4:"57623c76b02684c2b53b",5:"6aedce1af43a98e73126",6:"60121aec3037a1fa3701"}[t]}(t);var u=new Error;a=function(e){s.onerror=s.onload=null,clearTimeout(c);var n=r[t];if(0!==n){if(n){var o=e&&("load"===e.type?"missing":e.type),i=e&&e.target&&e.target.src;u.message="Loading chunk "+t+" failed.\n("+o+": "+i+")",u.name="ChunkLoadError",u.type=o,u.request=i,n[1](u)}r[t]=void 0}};var c=setTimeout((function(){a({type:"timeout",target:s})}),12e4);s.onerror=s.onload=a,document.head.appendChild(s)}return Promise.all(e)},o.m=t,o.c=n,o.d=function(t,e,n){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)o.d(n,r,function(e){return t[e]}.bind(null,r));return n},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="/js/",o.oe=function(t){throw console.error(t),t};var i=window.webpackJsonpSettings=window.webpackJsonpSettings||[],a=i.push.bind(i);i.push=e,i=i.slice();for(var s=0;s<i.length;s++)e(i[s]);var u=a;o(o.s=313)}([function(t,e,n){var r=n(2),o=n(34),i=n(50),a=n(224),s=r.Symbol,u=o("wks");t.exports=function(t){return u[t]||(u[t]=a&&s[t]||(a?s:i)("Symbol."+t))}},function(t,e,n){"use strict";var r=n(79),o=n(163),i=Object.prototype.toString;function a(t){return"[object Array]"===i.call(t)}function s(t){return null!==t&&"object"==typeof t}function u(t){return"[object Function]"===i.call(t)}function c(t,e){if(null!=t)if("object"!=typeof t&&(t=[t]),a(t))for(var n=0,r=t.length;n<r;n++)e.call(null,t[n],n,t);else for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.call(null,t[o],o,t)}t.exports={isArray:a,isArrayBuffer:function(t){return"[object ArrayBuffer]"===i.call(t)},isBuffer:o,isFormData:function(t){return"undefined"!=typeof FormData&&t instanceof FormData},isArrayBufferView:function(t){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&t.buffer instanceof ArrayBuffer},isString:function(t){return"string"==typeof t},isNumber:function(t){return"number"==typeof t},isObject:s,isUndefined:function(t){return void 0===t},isDate:function(t){return"[object Date]"===i.call(t)},isFile:function(t){return"[object File]"===i.call(t)},isBlob:function(t){return"[object Blob]"===i.call(t)},isFunction:u,isStream:function(t){return s(t)&&u(t.pipe)},isURLSearchParams:function(t){return"undefined"!=typeof URLSearchParams&&t instanceof URLSearchParams},isStandardBrowserEnv:function(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)},forEach:c,merge:function t(){var e={};function n(n,r){"object"==typeof e[r]&&"object"==typeof n?e[r]=t(e[r],n):e[r]=n}for(var r=0,o=arguments.length;r<o;r++)c(arguments[r],n);return e},deepMerge:function t(){var e={};function n(n,r){"object"==typeof e[r]&&"object"==typeof n?e[r]=t(e[r],n):e[r]="object"==typeof n?t({},n):n}for(var r=0,o=arguments.length;r<o;r++)c(arguments[r],n);return e},extend:function(t,e,n){return c(e,(function(e,o){t[o]=n&&"function"==typeof e?r(e,n):e})),t},trim:function(t){return t.replace(/^\s*/,"").replace(/\s*$/,"")}}},function(t,e,n){(function(e){var n="object",r=function(t){return t&&t.Math==Math&&t};t.exports=r(typeof globalThis==n&&globalThis)||r(typeof window==n&&window)||r(typeof self==n&&self)||r(typeof e==n&&e)||Function("return this")()}).call(this,n(7))},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e,n){"use strict";n.r(e),function(t,n){
|
||||
!function(t){function e(e){for(var n,o,i=e[0],a=e[1],s=0,c=[];s<i.length;s++)o=i[s],Object.prototype.hasOwnProperty.call(r,o)&&r[o]&&c.push(r[o][0]),r[o]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(t[n]=a[n]);for(u&&u(e);c.length;)c.shift()()}var n={},r={2:0};function o(e){if(n[e])return n[e].exports;var r=n[e]={i:e,l:!1,exports:{}};return t[e].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.e=function(t){var e=[],n=r[t];if(0!==n)if(n)e.push(n[2]);else{var i=new Promise((function(e,o){n=r[t]=[e,o]}));e.push(n[2]=i);var a,s=document.createElement("script");s.charset="utf-8",s.timeout=120,o.nc&&s.setAttribute("nonce",o.nc),s.src=function(t){return o.p+"vue-"+({}[t]||t)+".js?v="+{0:"f1063acdadacc88028ec",4:"1b9a9a854189f065cd3c",5:"d26e956d157c0c427e8e",6:"60121aec3037a1fa3701"}[t]}(t);var u=new Error;a=function(e){s.onerror=s.onload=null,clearTimeout(c);var n=r[t];if(0!==n){if(n){var o=e&&("load"===e.type?"missing":e.type),i=e&&e.target&&e.target.src;u.message="Loading chunk "+t+" failed.\n("+o+": "+i+")",u.name="ChunkLoadError",u.type=o,u.request=i,n[1](u)}r[t]=void 0}};var c=setTimeout((function(){a({type:"timeout",target:s})}),12e4);s.onerror=s.onload=a,document.head.appendChild(s)}return Promise.all(e)},o.m=t,o.c=n,o.d=function(t,e,n){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)o.d(n,r,function(e){return t[e]}.bind(null,r));return n},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="/js/",o.oe=function(t){throw console.error(t),t};var i=window.webpackJsonpSettings=window.webpackJsonpSettings||[],a=i.push.bind(i);i.push=e,i=i.slice();for(var s=0;s<i.length;s++)e(i[s]);var u=a;o(o.s=313)}([function(t,e,n){var r=n(2),o=n(34),i=n(50),a=n(224),s=r.Symbol,u=o("wks");t.exports=function(t){return u[t]||(u[t]=a&&s[t]||(a?s:i)("Symbol."+t))}},function(t,e,n){"use strict";var r=n(79),o=n(163),i=Object.prototype.toString;function a(t){return"[object Array]"===i.call(t)}function s(t){return null!==t&&"object"==typeof t}function u(t){return"[object Function]"===i.call(t)}function c(t,e){if(null!=t)if("object"!=typeof t&&(t=[t]),a(t))for(var n=0,r=t.length;n<r;n++)e.call(null,t[n],n,t);else for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.call(null,t[o],o,t)}t.exports={isArray:a,isArrayBuffer:function(t){return"[object ArrayBuffer]"===i.call(t)},isBuffer:o,isFormData:function(t){return"undefined"!=typeof FormData&&t instanceof FormData},isArrayBufferView:function(t){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&t.buffer instanceof ArrayBuffer},isString:function(t){return"string"==typeof t},isNumber:function(t){return"number"==typeof t},isObject:s,isUndefined:function(t){return void 0===t},isDate:function(t){return"[object Date]"===i.call(t)},isFile:function(t){return"[object File]"===i.call(t)},isBlob:function(t){return"[object Blob]"===i.call(t)},isFunction:u,isStream:function(t){return s(t)&&u(t.pipe)},isURLSearchParams:function(t){return"undefined"!=typeof URLSearchParams&&t instanceof URLSearchParams},isStandardBrowserEnv:function(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)},forEach:c,merge:function t(){var e={};function n(n,r){"object"==typeof e[r]&&"object"==typeof n?e[r]=t(e[r],n):e[r]=n}for(var r=0,o=arguments.length;r<o;r++)c(arguments[r],n);return e},deepMerge:function t(){var e={};function n(n,r){"object"==typeof e[r]&&"object"==typeof n?e[r]=t(e[r],n):e[r]="object"==typeof n?t({},n):n}for(var r=0,o=arguments.length;r<o;r++)c(arguments[r],n);return e},extend:function(t,e,n){return c(e,(function(e,o){t[o]=n&&"function"==typeof e?r(e,n):e})),t},trim:function(t){return t.replace(/^\s*/,"").replace(/\s*$/,"")}}},function(t,e,n){(function(e){var n="object",r=function(t){return t&&t.Math==Math&&t};t.exports=r(typeof globalThis==n&&globalThis)||r(typeof window==n&&window)||r(typeof self==n&&self)||r(typeof e==n&&e)||Function("return this")()}).call(this,n(7))},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e,n){"use strict";n.r(e),function(t,n){
|
||||
/*!
|
||||
* Vue.js v2.6.10
|
||||
* (c) 2014-2019 Evan You
|
||||
|
@ -110,4 +110,4 @@ o.default.use(Jt.a);var he={API_FAILURE:function(e,n){try{var r=n.error.response
|
|||
*
|
||||
*/
|
||||
o.default.use(i.a,{defaultHtml:!1}),Object(a.sync)(ve,Xt),r.nc=btoa(OC.requestToken),r.p=OC.linkTo("settings","js/"),o.default.prototype.t=t,o.default.prototype.OC=OC,o.default.prototype.OCA=OCA,o.default.prototype.oc_userconfig=oc_userconfig;var me=new o.default({router:Xt,store:ve,render:function(t){return t(c)}}).$mount("#content")}]);
|
||||
//# sourceMappingURL=vue-settings-apps-users-management.js.map?v=6f99ac5627310d3591f4
|
||||
//# sourceMappingURL=vue-settings-apps-users-management.js.map?v=346dee5757d76be545c2
|
File diff suppressed because one or more lines are too long
|
@ -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':
|
||||
return apps.filter(app => app.active && app.installed)
|
||||
case 'disabled':
|
||||
return apps.filter(app => !app.active && app.installed)
|
||||
case 'app-bundles':
|
||||
return apps.filter(app => app.bundles)
|
||||
case '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)
|
||||
})
|
||||
}
|
||||
if (this.category === 'enabled') {
|
||||
return apps.filter(app => app.active && app.installed)
|
||||
}
|
||||
if (this.category === 'disabled') {
|
||||
return apps.filter(app => !app.active && app.installed)
|
||||
}
|
||||
if (this.category === 'app-bundles') {
|
||||
return apps.filter(app => app.bundles)
|
||||
}
|
||||
if (this.category === 'updates') {
|
||||
return apps.filter(app => app.update)
|
||||
}
|
||||
// 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)) {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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'],
|
||||
|
|
|
@ -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>
|
|
@ -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())
|
|
@ -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')
|
|
@ -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>
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue