Browse Source

More app management implementation

Signed-off-by: Julius Härtl <jus@bitgrid.net>
tags/v14.0.0beta1
Julius Härtl 6 years ago
parent
commit
3b39e9c971
No account linked to committer's email address

+ 59
- 40
settings/src/components/appList.vue View File

@@ -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', {

+ 171
- 0
settings/src/components/appList/appItem.vue View File

@@ -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>

+ 1
- 1
settings/src/store/api.js View File

@@ -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));

+ 41
- 1
settings/src/store/apps.js View File

@@ -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) {

+ 28
- 2
settings/src/views/Apps.vue View File

@@ -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;
},

Loading…
Cancel
Save