diff options
author | Julius Härtl <jus@bitgrid.net> | 2018-05-22 08:57:09 +0200 |
---|---|---|
committer | Julius Härtl <jus@bitgrid.net> | 2018-06-06 11:40:09 +0200 |
commit | 3b39e9c97196a3141a3087cce4b24e1784879c6f (patch) | |
tree | baf6fae8a97b3273af0faafee55dbdd9ee4a8246 /settings | |
parent | 23462275ba4c694a43325554afec851071e1a01a (diff) | |
download | nextcloud-server-3b39e9c97196a3141a3087cce4b24e1784879c6f.tar.gz nextcloud-server-3b39e9c97196a3141a3087cce4b24e1784879c6f.zip |
More app management implementation
Signed-off-by: Julius Härtl <jus@bitgrid.net>
Diffstat (limited to 'settings')
-rw-r--r-- | settings/src/components/appList.vue | 99 | ||||
-rw-r--r-- | settings/src/components/appList/appItem.vue | 171 | ||||
-rw-r--r-- | settings/src/store/api.js | 2 | ||||
-rw-r--r-- | settings/src/store/apps.js | 42 | ||||
-rw-r--r-- | settings/src/views/Apps.vue | 30 |
5 files changed, 300 insertions, 44 deletions
diff --git a/settings/src/components/appList.vue b/settings/src/components/appList.vue index 8dc7fede01d..b446b9c8a61 100644 --- a/settings/src/components/appList.vue +++ b/settings/src/components/appList.vue @@ -21,7 +21,7 @@ --> <template> - <div id="app-content"> + <div id="app-content" :class="{ 'with-app-sidebar': app }"> <div id="apps-list" class="installed"> <div class="apps-header" v-if="category === 'app-bundles'"> <div class="app-image"></div> @@ -32,73 +32,92 @@ <div class="actions"> </div> </div> - <div class="section" v-for="app in apps"> - <div class="app-image app-image-icon"> - <svg width="32" height="32" viewBox="0 0 32 32"> - <defs><filter id="invertIconApps-606"><feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"></feColorMatrix></filter></defs> - <image x="0" y="0" width="32" height="32" preserveAspectRatio="xMinYMin meet" filter="url(#invertIconApps-606)" xlink:href="/core/img/places/default-app-icon.svg?v=13.0.2.1" class="app-icon"></image> - </svg> - </div> - <div class="app-name"> - {{ app.name }} - </div> - <div class="app-version">{{ app.version }}</div> - <div class="app-level"> - <a href="https://apps.nextcloud.com/apps/apporder">Im Store anzeigen ↗</a> - </div> - - <div class="app-groups"> - <div class="groups-enable"> - <input type="checkbox" class="groups-enable__checkbox checkbox" id="groups_enable-apporder"> - <label for="groups_enable-apporder">Auf Gruppen beschränken</label> - <input type="hidden" class="group_select" title="Alle" value=""> - </div> - </div> - - <div class="actions"> - <div class="warning hidden"></div> - <input class="update hidden" type="submit" value="Aktualisierung auf false" data-appid="apporder"> - <input class="enable" type="submit" data-appid="apporder" data-active="true" value="Deaktivieren"> - </div> - </div> + <app-item v-for="app in apps" :key="app.id" :app="app" :category="category" /> </div> </div> </template> <script> -import userRow from './userList/userRow'; +import appItem from './appList/appItem'; import Multiselect from 'vue-multiselect'; -import InfiniteLoading from 'vue-infinite-loading'; -import Vue from 'vue'; export default { name: 'appList', - props: ['category'], + props: ['category', 'app'], components: { Multiselect, + appItem }, data() { return { + groupCheckedAppsData: [], loading: false, scrolled: false, }; }, watch: { - // watch url change and group select - category: function (val, old) { - this.$store.commit('resetApps'); - this.$store.dispatch('getApps', { category: this.category }); - } + }, mounted() { - this.$store.dispatch('getApps', { category: this.category }); + //this.$store.dispatch('getApps', { category: this.category }); + this.$store.dispatch('getGroups'); + }, computed: { apps() { return this.$store.getters.getApps; }, + groups() { + console.log(this.$store.getters.getGroups); + return this.$store.getters.getGroups; + /*.filter(group => group.id !== 'disabled') + .sort((a, b) => a.name.localeCompare(b.name));*/ + }, }, methods: { + prefix(prefix, content) { + return prefix + '_' + content; + }, + isLimitedToGroups(app) { + if (app.groups.length || this.groupCheckedAppsData.includes(app.id)) { + return true; + } + return false; + }, + canLimitToGroups(app) { + if (app.types && app.types.includes('filesystem') + || app.types.includes('prelogin') + || app.types.includes('authentication') + || app.types.includes('logging') + || app.types.includes('prevent_group_restriction')) { + return false; + } + return true; + }, + addGroupLimitation(appId, group) { + let currentGroups = this.$store.apps.find(app => app.id === appId).groups; + currentGroups.push(group); + this.$store.dispatch('enableApp', { appId: appId, groups: groups}); + }, + removeGroupLimitation(appId, group) { + let currentGroups = this.$store.apps.find(app => app.id === appId).groups; + currentGroups.push(group); + let index = currentGroups.indexOf(group); + if (index > -1) { + currentGroups.splice(index, 1); + } + this.$store.dispatch('enableApp', { appId: appId, groups: groups}); + }, + enable(appId) { + this.$store.dispatch('enableApp', { appId: appId }) + .catch((error) => { OC.Notification.show(error)}); + }, + disable(appId) { + this.$store.dispatch('disableApp', { appId: appId }) + .catch((error) => { OC.Notification.show(error)}); + }, + remove() {}, + install() {}, createUser() { this.loading = true; this.$store.dispatch('addUser', { diff --git a/settings/src/components/appList/appItem.vue b/settings/src/components/appList/appItem.vue new file mode 100644 index 00000000000..d72f69ff267 --- /dev/null +++ b/settings/src/components/appList/appItem.vue @@ -0,0 +1,171 @@ +<!-- + - @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> + - + - @author Julius Härtl <jus@bitgrid.net> + - + - @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="section" v-on:click="showAppDetails"> + <div class="app-image app-image-icon"> + <svg width="32" height="32" viewBox="0 0 32 32"> + <defs><filter id="invertIconApps-606"><feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"></feColorMatrix></filter></defs> + <image x="0" y="0" width="32" height="32" preserveAspectRatio="xMinYMin meet" filter="url(#invertIconApps-606)" xlink:href="/core/img/places/default-app-icon.svg?v=13.0.2.1" class="app-icon"></image> + </svg> + </div> + <div class="app-name"> + {{ app.name }} + </div> + <div class="app-version">{{ app.version }}</div> + <div class="app-level"> + <span class="official icon-checkmark" v-if="app.level === 200">{{ t('settings', 'Official') }}</span> + <a :href="app.appstoreUrl" v-if="!app.internal">Im Store anzeigen ↗</a> + </div> + + <div class="app-groups"> + <div class="groups-enable" v-if="app.active && canLimitToGroups(app)"> + <input type="checkbox" :value="app.id" v-model="groupCheckedAppsData" v-on:change="setGroupLimit" class="groups-enable__checkbox checkbox" :id="prefix('groups_enable', app.id)"> + <label :for="prefix('groups_enable', app.id)">Auf Gruppen beschränken</label> + <input type="hidden" class="group_select" title="Alle" value=""> + <multiselect v-if="isLimitedToGroups(app)" :options="groups" :value="appGroups" @select="addGroupLimitation" @remove="removeGroupLimitation" + :placeholder="t('settings', 'Limit app usage to groups')" + label="name" track-by="id" class="multiselect-vue" + :multiple="true" :close-on-select="false"> + <span slot="noResult">{{t('settings', 'No results')}}</span> + </multiselect> + </div> + </div> + + <div class="actions"> + <div class="warning hidden"></div> + <input v-if="app.update" class="update" type="button" :value="t('settings', 'Update to %s', app.update)" :data-appid="app.id" /> + <input v-if="app.canUnInstall" class="uninstall" type="button" :value="t('settings', 'Remove')" :data-appid="app.id" /> + <input v-if="app.active" class="enable" type="button" :data-appid="app.id" data-active="true" :value="t('settings','Disable')" v-on:click="disable(app.id)" /> + <input v-if="!app.active && !app.needsDownload" class="enable" type="button" :data-appid="app.id" :value="t('settings','Enable')" v-on:click="enable(app.id)" /> + <!--if !canInstall -> disable the enable button {{#unless canInstall}}disabled="disabled"{{/unless}} //--> + <input v-if="!app.active && app.needsDownload" class="enable needs-download" type="button" :data-appid="app.id" :value="t('settings', 'Enable')"/> + <!-- <php /* data-active="false" {{#unless canInstall}}disabled="disabled"{{/unless}} */ ?>//--> + + </div> + </div> +</template> + +<script> + import Multiselect from 'vue-multiselect'; + + export default { + name: 'appItem', + props: ['app', 'category'], + components: { + Multiselect, + }, + data() { + return { + groupCheckedAppsData: false, + loading: false, + scrolled: false, + }; + }, + mounted() { + if (this.app.groups.length > 0) { + this.groupCheckedAppsData = true; + } + }, + computed: { + appGroups() { + return this.app.groups.map(group => {return {id: group, name: group}}); + }, + groups() { + console.log(this.$store.getters.getGroups); + return this.$store.getters.getGroups + .filter(group => group.id !== 'disabled') + .sort((a, b) => a.name.localeCompare(b.name)); + }, + }, + watchers: { + + }, + methods: { + showAppDetails() { + console.log(this.app.id); + this.$router.push({ + name: 'apps-details', + params: {category: this.category, id: this.app.id} + }); + }, + prefix(prefix, content) { + return prefix + '_' + content; + }, + isLimitedToGroups(app) { + if (this.app.groups.length || this.groupCheckedAppsData) { + return true; + } + return false; + }, + setGroupLimit: function() { + if (!this.groupCheckedAppsData) { + this.$store.dispatch('enableApp', {appId: this.app.id, groups: []}); + } + }, + canLimitToGroups(app) { + if (app.types && app.types.includes('filesystem') + || app.types.includes('prelogin') + || app.types.includes('authentication') + || app.types.includes('logging') + || app.types.includes('prevent_group_restriction')) { + return false; + } + return true; + }, + addGroupLimitation(group) { + let groups = this.app.groups.concat([]).concat([group.id]); + this.$store.dispatch('enableApp', { appId: this.app.id, groups: groups}); + }, + removeGroupLimitation(group) { + let currentGroups = this.app.groups.concat([]); + let index = currentGroups.indexOf(group.id); + if (index > -1) { + currentGroups.splice(index, 1); + } + this.$store.dispatch('enableApp', { appId: this.app.id, groups: currentGroups}); + }, + enable(appId) { + this.$store.dispatch('enableApp', { appId: appId }) + .catch((error) => { OC.Notification.show(error)}); + }, + disable(appId) { + this.$store.dispatch('disableApp', { appId: appId }) + .catch((error) => { OC.Notification.show(error)}); + }, + remove() {}, + install() {}, + createUser() { + this.loading = true; + this.$store.dispatch('addUser', { + userid: this.newUser.id, + password: this.newUser.password, + email: this.newUser.mailAddress, + groups: this.newUser.groups.map(group => group.id), + subadmin: this.newUser.subAdminsGroups.map(group => group.id), + quota: this.newUser.quota.id, + language: this.newUser.language.code, + }).then(() => this.resetForm()); + } + } + } +</script> diff --git a/settings/src/store/api.js b/settings/src/store/api.js index 7501a7bb4cc..059c9a11ef8 100644 --- a/settings/src/store/api.js +++ b/settings/src/store/api.js @@ -71,7 +71,7 @@ export default { waitForpassword(); }); }, - get(url) { + get(url, data) { return axios.get(sanitize(url), tokenHeaders) .then((response) => Promise.resolve(response)) .catch((error) => Promise.reject(error)); diff --git a/settings/src/store/apps.js b/settings/src/store/apps.js index d9888465dd6..d79540ad525 100644 --- a/settings/src/store/apps.js +++ b/settings/src/store/apps.js @@ -21,6 +21,7 @@ */ import api from './api'; +import axios from 'axios/index'; const state = { apps: [], @@ -51,6 +52,16 @@ const mutations = { state.apps = apps; }, + enableApp(state, {appId, groups}) { + state.apps.find(app => app.id === appId).active = true; + state.apps.find(app => app.id === appId).groups = groups; + console.log(state.apps.find(app => app.id === appId).groups); + }, + + disableApp(state, appId) { + state.apps.find(app => app.id === appId).active = false; + }, + reset(state) { state.apps = []; state.categories = []; @@ -72,6 +83,36 @@ const getters = { const actions = { + enableApp(context, { appId, groups }) { + return api.requireAdmin().then((response) => { + return api.post(OC.generateUrl(`settings/apps/enable/${appId}`), { + groups: groups + }) + .then((response) => { + context.commit('enableApp', {appId: appId, groups: groups}); + return true; + }) + .catch((error) => {throw error;}) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); + + }, + disableApp(context, { appId }) { + return api.requireAdmin().then((response) => { + return api.get(OC.generateUrl(`settings/apps/disable/${appId}`)) + .then((response) => { + context.commit('disableApp', appId); + return true; + }) + .catch((error) => {throw error;}) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); + }, + installApp(appId) { + + }, + uninstallApp(appId) { + + }, + getApps(context, { category }) { return api.get(OC.generateUrl(`settings/apps/list?category=${category}`)) .then((response) => { @@ -79,7 +120,6 @@ const actions = { return true; }) .catch((error) => context.commit('API_FAILURE', error)) - }, getCategories(context) { diff --git a/settings/src/views/Apps.vue b/settings/src/views/Apps.vue index eac9bec7527..17b54415979 100644 --- a/settings/src/views/Apps.vue +++ b/settings/src/views/Apps.vue @@ -23,7 +23,13 @@ <template> <div id="app"> <app-navigation :menu="menu" /> - <app-list :category="category"></app-list> + <app-list :category="category" :app="currentApp"></app-list> + <div id="app-sidebar" v-if="currentApp"> + {{ currentApp.name }} + <div class="app-description"> + {{ currentApp.description }} + </div> + </div> </div> </template> @@ -41,13 +47,23 @@ Vue.use(VueLocalStorage) export default { name: 'Apps', - props: ['category'], + props: { + category: { + type: String, + default: 'installed', + }, + id: { + type: String, + default: '', + } + }, components: { appNavigation, appList, }, beforeMount() { this.$store.dispatch('getCategories'); + this.$store.dispatch('getApps', { category: this.category }); this.$store.commit('setUpdateCount', this.$store.getters.getServerData.updateCount) }, data() { @@ -55,7 +71,17 @@ export default { } }, + watch: { + // watch url change and group select + category: function (val, old) { + this.$store.commit('resetApps'); + this.$store.dispatch('getApps', { category: this.category }); + } + }, computed: { + currentApp() { + return this.apps.find(app => app.id === this.id ); + }, categories() { return this.$store.getters.getCategories; }, |