Signed-off-by: Christopher Ng <chrng8@gmail.com>tags/v24.0.0beta1
@@ -78,7 +78,7 @@ class SetupController { | |||
$options = array_merge($opts, $post, $errors); | |||
$this->display($options); | |||
} else { | |||
$this->finishSetup(isset($post['install-recommended-apps'])); | |||
$this->finishSetup(); | |||
} | |||
} else { | |||
$options = array_merge($opts, $post); | |||
@@ -106,7 +106,7 @@ class SetupController { | |||
\OC_Template::printGuestPage('', 'installation', $parameters); | |||
} | |||
private function finishSetup(bool $installRecommended) { | |||
private function finishSetup() { | |||
if (file_exists($this->autoConfigFile)) { | |||
unlink($this->autoConfigFile); | |||
} | |||
@@ -118,13 +118,8 @@ class SetupController { | |||
} | |||
} | |||
if ($installRecommended) { | |||
header('Location: ' . \OC::$server->getURLGenerator()->getAbsoluteURL('index.php/core/apps/recommended')); | |||
exit(); | |||
} else { | |||
header('Location: ' . \OC::$server->getURLGenerator()->linkToDefaultPageUrl()); | |||
exit(); | |||
} | |||
header('Location: ' . \OC::$server->getURLGenerator()->getAbsoluteURL('index.php/core/apps/recommended')); | |||
exit(); | |||
} | |||
public function loadAutoConfig($post) { |
@@ -667,18 +667,14 @@ form #selectDbType label span { | |||
margin: 5px 0 !important; | |||
} | |||
#install-recommended-apps + label span { | |||
display: inline-block; | |||
opacity: .7; | |||
} | |||
/* Errors */ | |||
/* Warnings and errors are the same */ | |||
.body-login-container, | |||
.warning, | |||
.update, | |||
.error { | |||
display: block; | |||
display: flex; | |||
flex-direction: column; | |||
margin-top: 15px; | |||
padding: 15px; | |||
background-color: rgba(0,0,0,.3); |
@@ -0,0 +1,44 @@ | |||
<!-- | |||
- @copyright 2022 Christopher Ng <chrng8@gmail.com> | |||
- | |||
- @author Christopher Ng <chrng8@gmail.com> | |||
- | |||
- @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> | |||
<button | |||
class="primary" | |||
:autofocus="true" | |||
v-on="$listeners"> | |||
{{ t('core', 'Install recommended apps') }} | |||
</button> | |||
</template> | |||
<script> | |||
export default { | |||
name: 'InstallButton', | |||
} | |||
</script> | |||
<style lang="scss" scoped> | |||
button { | |||
margin: 24px auto 10px auto; | |||
padding: 10px 20px; | |||
font-size: 20px; | |||
} | |||
</style> |
@@ -28,9 +28,10 @@ | |||
<p v-else-if="loadingAppsError" class="loading-error text-center"> | |||
{{ t('core', 'Could not fetch list of apps from the App Store.') }} | |||
</p> | |||
<p v-else class="text-center"> | |||
<p v-else-if="installingApps" class="text-center"> | |||
{{ t('core', 'Installing apps …') }} | |||
</p> | |||
<div v-for="app in recommendedApps" :key="app.id" class="app"> | |||
<img :src="customIcon(app.id)" alt=""> | |||
<div class="info"> | |||
@@ -51,6 +52,10 @@ | |||
</p> | |||
</div> | |||
</div> | |||
<InstallButton v-if="showInstallButton" | |||
@click.stop.prevent="installApps" /> | |||
<p class="text-center"> | |||
<a :href="defaultPageUrl">{{ t('core', 'Cancel') }}</a> | |||
</p> | |||
@@ -64,6 +69,9 @@ import { loadState } from '@nextcloud/initial-state' | |||
import pLimit from 'p-limit' | |||
import { translate as t } from '@nextcloud/l10n' | |||
// TODO replace with Button component when @nextcloud/vue is upgraded to v5 | |||
import InstallButton from './InstallButton' | |||
import logger from '../../logger' | |||
const recommended = { | |||
@@ -97,8 +105,13 @@ const defaultPageUrl = loadState('core', 'defaultPageUrl') | |||
export default { | |||
name: 'RecommendedApps', | |||
components: { | |||
InstallButton, | |||
}, | |||
data() { | |||
return { | |||
showInstallButton: false, | |||
installingApps: false, | |||
loadingApps: true, | |||
loadingAppsError: false, | |||
apps: [], | |||
@@ -110,28 +123,28 @@ export default { | |||
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 | |||
}) | |||
async mounted() { | |||
try { | |||
const { data } = await axios.get(generateUrl('settings/apps/list')) | |||
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.showInstallButton = true | |||
} catch (error) { | |||
logger.error('could not fetch app list', { error }) | |||
this.loadingAppsError = true | |||
} finally { | |||
this.loadingApps = false | |||
} | |||
}, | |||
methods: { | |||
installApps() { | |||
this.showInstallButton = false | |||
this.installingApps = true | |||
const limit = pLimit(1) | |||
const installing = this.recommendedApps | |||
.filter(app => !app.active && app.isCompatible && app.canInstall) | |||
@@ -180,8 +193,15 @@ export default { | |||
} | |||
p.loading, p.loading-error { | |||
height: 100px; | |||
p { | |||
&.loading, | |||
&.loading-error { | |||
height: 100px; | |||
} | |||
&:last-child { | |||
margin-top: 10px; | |||
} | |||
} | |||
.text-center { |
@@ -159,19 +159,9 @@ script('core', 'install'); | |||
</fieldset> | |||
<?php endif ?> | |||
<fieldset> | |||
<p class="info"> | |||
<input type="checkbox" id="install-recommended-apps" name="install-recommended-apps" class="checkbox checkbox--white" checked> | |||
<label for="install-recommended-apps"> | |||
<?php p($l->t('Install recommended apps')); ?> | |||
<span><?php p($l->t('Calendar, Contacts, Talk, Mail & Collaborative editing')); ?></span> | |||
</label> | |||
</p> | |||
</fieldset> | |||
<div class="icon-loading-dark float-spinner"> </div> | |||
<div class="buttons"><input type="submit" class="primary" value="<?php p($l->t('Finish setup')); ?>" data-finishing="<?php p($l->t('Finishing …')); ?>"></div> | |||
<div class="buttons"><input type="submit" class="primary" value="<?php p($l->t('Install')); ?>" data-finishing="<?php p($l->t('Installing …')); ?>"></div> | |||
<p class="info"> | |||
<span class="icon-info-white"></span> |