summaryrefslogtreecommitdiffstats
path: root/settings
diff options
context:
space:
mode:
authorJulius Härtl <jus@bitgrid.net>2018-05-22 08:57:09 +0200
committerJulius Härtl <jus@bitgrid.net>2018-06-06 11:40:09 +0200
commit3b39e9c97196a3141a3087cce4b24e1784879c6f (patch)
treebaf6fae8a97b3273af0faafee55dbdd9ee4a8246 /settings
parent23462275ba4c694a43325554afec851071e1a01a (diff)
downloadnextcloud-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.vue99
-rw-r--r--settings/src/components/appList/appItem.vue171
-rw-r--r--settings/src/store/api.js2
-rw-r--r--settings/src/store/apps.js42
-rw-r--r--settings/src/views/Apps.vue30
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">&nbsp;</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;
},