Signed-off-by: Julius Härtl <jus@bitgrid.net>tags/v14.0.0beta1
@@ -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', { |
@@ -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> |
@@ -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)); |
@@ -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) { |
@@ -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; | |||
}, |