Add file skeleton for app settings
Signed-off-by: Julius Härtl <jus@bitgrid.net>pull/9565/head
parent
8594fdc493
commit
125d1d3d4e
@ -0,0 +1,187 @@
|
||||
<!--
|
||||
- @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 id="app-sidebar">
|
||||
<h2>{{ app.name }}</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import userRow from './userList/userRow';
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import InfiniteLoading from 'vue-infinite-loading';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'userList',
|
||||
props: ['users', 'showConfig', 'selectedGroup'],
|
||||
components: {
|
||||
userRow,
|
||||
Multiselect,
|
||||
InfiniteLoading
|
||||
},
|
||||
data() {
|
||||
let unlimitedQuota = {id:'none', label:t('settings', 'Unlimited')},
|
||||
defaultQuota = {id:'default', label:t('settings', 'Default quota')};
|
||||
return {
|
||||
unlimitedQuota: unlimitedQuota,
|
||||
defaultQuota: defaultQuota,
|
||||
loading: false,
|
||||
scrolled: false,
|
||||
newUser: {
|
||||
id:'',
|
||||
displayName:'',
|
||||
password:'',
|
||||
mailAddress:'',
|
||||
groups: [],
|
||||
subAdminsGroups: [],
|
||||
quota: defaultQuota,
|
||||
language: {code: 'en', name: t('settings', 'Default language')}
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (!this.settings.canChangePassword) {
|
||||
OC.Notification.showTemporary(t('settings', 'Password change is disabled because the master key is disabled'));
|
||||
}
|
||||
/**
|
||||
* Init default language from server data. The use of this.settings
|
||||
* requires a computed variable,vwhich break the v-model binding of the form,
|
||||
* this is a much easier solution than getter and setter
|
||||
*/
|
||||
Vue.set(this.newUser.language, 'code', this.settings.defaultLanguage);
|
||||
},
|
||||
computed: {
|
||||
settings() {
|
||||
return this.$store.getters.getServerData;
|
||||
},
|
||||
filteredUsers() {
|
||||
if (this.selectedGroup === 'disabled') {
|
||||
let disabledUsers = this.users.filter(user => user.enabled !== true);
|
||||
if (disabledUsers.length===0 && this.$refs.infiniteLoading && this.$refs.infiniteLoading.isComplete) {
|
||||
// disabled group is empty, redirection to all users
|
||||
this.$router.push('users');
|
||||
this.$refs.infiniteLoading.$emit('$InfiniteLoading:reset');
|
||||
}
|
||||
return disabledUsers;
|
||||
}
|
||||
return this.users.filter(user => user.enabled === true);
|
||||
},
|
||||
groups() {
|
||||
// data provided php side + remove the disabled group
|
||||
return this.$store.getters.getGroups.filter(group => group.id !== 'disabled');
|
||||
},
|
||||
subAdminsGroups() {
|
||||
// data provided php side
|
||||
return this.$store.getters.getServerData.subadmingroups;
|
||||
},
|
||||
quotaOptions() {
|
||||
// convert the preset array into objects
|
||||
let quotaPreset = this.settings.quotaPreset.reduce((acc, cur) => acc.concat({id:cur, label:cur}), []);
|
||||
// add default presets
|
||||
quotaPreset.unshift(this.unlimitedQuota);
|
||||
quotaPreset.unshift(this.defaultQuota);
|
||||
return quotaPreset;
|
||||
},
|
||||
minPasswordLength() {
|
||||
return this.$store.getters.getPasswordPolicyMinLength;
|
||||
},
|
||||
usersOffset() {
|
||||
return this.$store.getters.getUsersOffset;
|
||||
},
|
||||
usersLimit() {
|
||||
return this.$store.getters.getUsersLimit;
|
||||
},
|
||||
|
||||
/* LANGUAGES */
|
||||
languages() {
|
||||
return Array(
|
||||
{
|
||||
label: t('settings', 'Common languages'),
|
||||
languages: this.settings.languages.commonlanguages
|
||||
},
|
||||
{
|
||||
label: t('settings', 'All languages'),
|
||||
languages: this.settings.languages.languages
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// watch url change and group select
|
||||
selectedGroup: function (val, old) {
|
||||
this.$store.commit('resetUsers');
|
||||
this.$refs.infiniteLoading.$emit('$InfiniteLoading:reset');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onScroll(event) {
|
||||
this.scrolled = event.target.scrollTop>0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate quota string to make sure it's a valid human file size
|
||||
*
|
||||
* @param {string} quota Quota in readable format '5 GB'
|
||||
* @returns {Object}
|
||||
*/
|
||||
validateQuota(quota) {
|
||||
// only used for new presets sent through @Tag
|
||||
let validQuota = OC.Util.computerFileSize(quota);
|
||||
if (validQuota !== null && validQuota > 0) {
|
||||
// unify format output
|
||||
quota = OC.Util.humanFileSize(OC.Util.computerFileSize(quota));
|
||||
return this.newUser.quota = {id: quota, label: quota};
|
||||
}
|
||||
// Default is unlimited
|
||||
return this.newUser.quota = this.quotaOptions[0];
|
||||
},
|
||||
|
||||
infiniteHandler($state) {
|
||||
this.$store.dispatch('getUsers', {
|
||||
offset: this.usersOffset,
|
||||
limit: this.usersLimit,
|
||||
group: this.selectedGroup !== 'disabled' ? this.selectedGroup : ''})
|
||||
.then((response) => {response?$state.loaded():$state.complete()});
|
||||
},
|
||||
|
||||
resetForm() {
|
||||
// revert form to original state
|
||||
Object.assign(this.newUser, this.$options.data.call(this).newUser);
|
||||
this.loading = false;
|
||||
},
|
||||
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>
|
||||
@ -0,0 +1,116 @@
|
||||
<!--
|
||||
- @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 id="app-content">
|
||||
<div id="apps-list" class="installed">
|
||||
<div class="apps-header" v-if="category === 'app-bundles'">
|
||||
<div class="app-image"></div>
|
||||
<h2>Firmen-Paket <input class="enable" type="submit" data-bundleid="EnterpriseBundle" data-active="true" value="Alle aktivieren"></h2>
|
||||
<div class="app-version"></div>
|
||||
<div class="app-level"></div>
|
||||
<div class="app-groups"></div>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import userRow from './userList/userRow';
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import InfiniteLoading from 'vue-infinite-loading';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'appList',
|
||||
props: ['category'],
|
||||
components: {
|
||||
Multiselect,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
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 });
|
||||
},
|
||||
computed: {
|
||||
apps() {
|
||||
return this.$store.getters.getApps;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
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>
|
||||
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* @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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
import api from './api';
|
||||
|
||||
const state = {
|
||||
apps: [],
|
||||
categories: [],
|
||||
updateCount: 0
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
initCategories(state, {categories, updateCount}) {
|
||||
state.categories = categories;
|
||||
state.updateCount = updateCount;
|
||||
},
|
||||
|
||||
setUpdateCount(state, updateCount) {
|
||||
state.updateCount = updateCount;
|
||||
},
|
||||
|
||||
addCategory(state, category) {
|
||||
state.categories.push(category);
|
||||
},
|
||||
|
||||
appendCategories(state, categoriesArray) {
|
||||
// convert obj to array
|
||||
state.categories = categoriesArray;
|
||||
},
|
||||
|
||||
setApps(state, apps) {
|
||||
state.apps = apps;
|
||||
},
|
||||
|
||||
reset(state) {
|
||||
state.apps = [];
|
||||
state.categories = [];
|
||||
state.updateCount = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const getters = {
|
||||
getCategories(state) {
|
||||
return state.categories;
|
||||
},
|
||||
getApps(state) {
|
||||
return state.apps;
|
||||
},
|
||||
getUpdateCount(state) {
|
||||
return state.updateCount;
|
||||
}
|
||||
};
|
||||
|
||||
const actions = {
|
||||
|
||||
getApps(context, { category }) {
|
||||
return api.get(OC.generateUrl(`settings/apps/list?category=${category}`))
|
||||
.then((response) => {
|
||||
context.commit('setApps', response.data.apps);
|
||||
return true;
|
||||
})
|
||||
.catch((error) => context.commit('API_FAILURE', error))
|
||||
|
||||
},
|
||||
|
||||
getCategories(context) {
|
||||
return api.get(OC.generateUrl('settings/apps/categories'))
|
||||
.then((response) => {
|
||||
if (response.data.length > 0) {
|
||||
context.commit('appendCategories', response.data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.catch((error) => context.commit('API_FAILURE', error));
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export default { state, mutations, getters, actions };
|
||||
@ -0,0 +1,157 @@
|
||||
<!--
|
||||
- @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 id="app">
|
||||
<app-navigation :menu="menu" />
|
||||
<app-list :category="category"></app-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import appNavigation from '../components/appNavigation';
|
||||
import appList from '../components/appList';
|
||||
import Vue from 'vue';
|
||||
import VueLocalStorage from 'vue-localstorage'
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import api from '../store/api';
|
||||
|
||||
Vue.use(VueLocalStorage)
|
||||
Vue.use(VueLocalStorage)
|
||||
|
||||
export default {
|
||||
name: 'Apps',
|
||||
props: ['category'],
|
||||
components: {
|
||||
appNavigation,
|
||||
appList,
|
||||
},
|
||||
beforeMount() {
|
||||
this.$store.dispatch('getCategories');
|
||||
this.$store.commit('setUpdateCount', this.$store.getters.getServerData.updateCount)
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
categories() {
|
||||
return this.$store.getters.getCategories;
|
||||
},
|
||||
apps() {
|
||||
return this.$store.getters.getApps;
|
||||
},
|
||||
loading() {
|
||||
return Object.keys(this.apps).length === 0;
|
||||
},
|
||||
updateCount() {
|
||||
return this.$store.getters.getUpdateCount;
|
||||
},
|
||||
settings() {
|
||||
return this.$store.getters.getServerData;
|
||||
},
|
||||
|
||||
// BUILD APP NAVIGATION MENU OBJECT
|
||||
menu() {
|
||||
// Data provided php side
|
||||
let categories = this.$store.getters.getCategories;
|
||||
categories = Array.isArray(categories) ? categories : [];
|
||||
|
||||
// Map groups
|
||||
categories = categories.map(category => {
|
||||
let item = {};
|
||||
item.id = category.ident;
|
||||
item.icon = 'icon-category-' + category.ident;
|
||||
item.classes = []; // empty classes, active will be set later
|
||||
item.router = { // router link to
|
||||
name: 'apps-category',
|
||||
params: {category: category.ident}
|
||||
};
|
||||
item.text = category.displayName;
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
|
||||
// Add everyone group
|
||||
let defaultCategories = [
|
||||
{
|
||||
id: 'app-category-your-apps',
|
||||
classes: [],
|
||||
router: {name: 'apps'},
|
||||
icon: 'icon-category-installed',
|
||||
text: t('settings', 'Your apps'),
|
||||
},
|
||||
{
|
||||
id: 'app-category-enabled',
|
||||
classes: [],
|
||||
icon: 'icon-category-enabled',
|
||||
router: {name: 'apps-category', params: {category: 'enabled'}},
|
||||
text: t('settings', 'Active apps'),
|
||||
}, {
|
||||
id: 'app-category-disabled',
|
||||
classes: [],
|
||||
icon: 'icon-category-disabled',
|
||||
router: {name: 'apps-category', params: {category: 'disabled'}},
|
||||
text: t('settings', 'Disabled apps'),
|
||||
}
|
||||
];
|
||||
if (this.$store.getters.getUpdateCount > 0) {
|
||||
defaultCategories.push({
|
||||
id: 'app-category-updates',
|
||||
classes: [],
|
||||
icon: 'icon-download',
|
||||
router: {name: 'apps-category', params: {category: 'updates'}},
|
||||
text: t('settings', 'Updates'),
|
||||
utils: {counter: this.$store.getters.getUpdateCount}
|
||||
});
|
||||
}
|
||||
|
||||
defaultCategories.push({
|
||||
id: 'app-category-app-bundles',
|
||||
classes: [],
|
||||
icon: 'icon-category-app-bundles',
|
||||
router: {name: 'apps-category', params: {category: 'app-bundles'}},
|
||||
text: t('settings', 'App bundles'),
|
||||
});
|
||||
|
||||
categories = defaultCategories.concat(categories);
|
||||
|
||||
// Set current group as active
|
||||
let activeGroup = categories.findIndex(group => group.id === this.category);
|
||||
if (activeGroup >= 0) {
|
||||
categories[activeGroup].classes.push('active');
|
||||
} else {
|
||||
categories[0].classes.push('active');
|
||||
}
|
||||
|
||||
// Return
|
||||
return {
|
||||
id: 'appscategories',
|
||||
items: categories
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Loading…
Reference in New Issue