Merge pull request #11575 from nextcloud/stb14-add-group-settings

[stable14] Add new group entry on users list + fixes
This commit is contained in:
Morris Jobke 2018-10-03 14:53:48 +02:00 committed by GitHub
commit 0ca305b1c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 300 additions and 309 deletions

View File

@ -1377,21 +1377,6 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
/* USERS LIST -------------------------------------------------------------- */
#body-settings {
#app-navigation {
/* Hack to override the javascript orderBy */
#usergrouplist > li {
order: 4;
&#everyone {
order:1;
}
&#admin {
order:2;
}
&#disabled {
order:3;
}
}
}
$grid-row-height: 46px;
#app-content.user-list-grid {
display: grid;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"name": "settings",
"version": "1.2.2",
"version": "1.2.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -1526,7 +1526,7 @@
},
"browserify-aes": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"dev": true,
"requires": {
@ -1563,7 +1563,7 @@
},
"browserify-rsa": {
"version": "4.0.1",
"resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
"dev": true,
"requires": {
@ -1597,7 +1597,7 @@
},
"buffer": {
"version": "4.9.1",
"resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"dev": true,
"requires": {
@ -1913,7 +1913,7 @@
},
"create-hash": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"dev": true,
"requires": {
@ -1926,7 +1926,7 @@
},
"create-hmac": {
"version": "1.1.7",
"resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"dev": true,
"requires": {
@ -2123,7 +2123,7 @@
},
"diffie-hellman": {
"version": "5.0.3",
"resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
"dev": true,
"requires": {
@ -2278,7 +2278,7 @@
},
"events": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
"dev": true
},
@ -2455,6 +2455,11 @@
"integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=",
"dev": true
},
"fecha": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
"integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg=="
},
"file-loader": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz",
@ -2589,7 +2594,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -2610,12 +2616,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -2630,17 +2638,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -2757,7 +2768,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -2769,6 +2781,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -2783,6 +2796,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -2790,12 +2804,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@ -2814,6 +2830,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -2894,7 +2911,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -2906,6 +2924,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -2991,7 +3010,8 @@
"safe-buffer": {
"version": "5.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -3027,6 +3047,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -3046,6 +3067,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -3089,12 +3111,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},
@ -3560,7 +3584,7 @@
},
"is-obj": {
"version": "1.0.1",
"resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
"dev": true
},
@ -3979,6 +4003,18 @@
"integrity": "sha512-vdqTKI9GBIYcAEbFAcpKPErKINfPF5zIuz3/niBfq8WUZjpT2tytLlFVrBgWdOtqI4uaA/Rb6No0hux39XXDuw==",
"dev": true
},
"nextcloud-vue": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/nextcloud-vue/-/nextcloud-vue-0.1.5.tgz",
"integrity": "sha512-2tFfPPzhTMtZnbBmUk91o2o+jiri3X6BEgNs+iAWf9WZq4Gcpb6kIFW2ckizZuPFccmV1rA4Ts18IpU25vGERw==",
"requires": {
"@babel/polyfill": "^7.0.0",
"v-tooltip": "^2.0.0-rc.33",
"vue": "^2.5.16",
"vue-click-outside": "^1.0.7",
"vue2-datepicker": "^2.4.1"
}
},
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@ -4209,7 +4245,7 @@
},
"parse-asn1": {
"version": "5.1.1",
"resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
"integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
"dev": true,
"requires": {
@ -4449,7 +4485,7 @@
},
"public-encrypt": {
"version": "4.0.2",
"resolved": "http://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz",
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz",
"integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==",
"dev": true,
"requires": {
@ -4520,7 +4556,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -4773,7 +4809,7 @@
},
"sha.js": {
"version": "2.4.11",
"resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"dev": true,
"requires": {
@ -5085,9 +5121,9 @@
"dev": true
},
"tapable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.0.tgz",
"integrity": "sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz",
"integrity": "sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg==",
"dev": true
},
"through2": {
@ -5485,9 +5521,9 @@
"integrity": "sha512-29YQVVkIdoS6BZBCJAyu9d0OR0eKSm5gk5OjsLssV1+NM4zJnf9cxhN1AVeXkUHJLqOonECweuaR8PZ2x307dw=="
},
"vue-multiselect": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.0.tgz",
"integrity": "sha512-mEhApxZ6MUISGLuGDy0RF5UlAKUgG/Qq0DWYE/C+CA1h6ZszM3cHfpNFfFm2AMWLclY2SAWpY1HlQLjsw8WnvQ=="
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.2.tgz",
"integrity": "sha512-pTJ8s7DYhvvWxolexPfNBPjpF5x7rFa3mwhqgDFZrNxDkyQvY6g7FWuY+IsbqT4LBF4uL6p7q0nh3Q4vobWW0w=="
},
"vue-resize": {
"version": "0.4.4",
@ -5525,6 +5561,14 @@
"integrity": "sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==",
"dev": true
},
"vue2-datepicker": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/vue2-datepicker/-/vue2-datepicker-2.4.3.tgz",
"integrity": "sha512-Tw6k7AZyCl698CQgrNFKzHy1po6LVHYXBw+gQ3yozsxbpX6TCdq7MasvSpP5q0cQxgs8COlIZr1x4EjIKYjejQ==",
"requires": {
"fecha": "^2.3.3"
}
},
"vuex": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.0.1.tgz",
@ -5576,6 +5620,14 @@
"uglifyjs-webpack-plugin": "^1.2.4",
"watchpack": "^1.5.0",
"webpack-sources": "^1.3.0"
},
"dependencies": {
"tapable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.0.tgz",
"integrity": "sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==",
"dev": true
}
}
},
"webpack-cli": {
@ -5680,7 +5732,7 @@
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"dev": true,
"requires": {

View File

@ -1,7 +1,7 @@
{
"name": "settings",
"description": "Nextcloud settings",
"version": "1.2.2",
"version": "1.2.3",
"author": "John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>",
"license": "AGPL3",
"private": true,
@ -13,12 +13,13 @@
"dependencies": {
"@babel/polyfill": "^7.0.0",
"axios": "^0.18.0",
"nextcloud-vue": "^0.1.5",
"v-tooltip": "^2.0.0-rc.33",
"vue": "^2.5.17",
"vue-click-outside": "^1.0.7",
"vue-infinite-loading": "^2.3.3",
"vue-localstorage": "^0.6.2",
"vue-multiselect": "^2.1.0",
"vue-multiselect": "^2.1.2",
"vue-router": "^3.0.1",
"vuex": "^3.0.1",
"vuex-router-sync": "^5.0.0"

View File

@ -1,54 +0,0 @@
<!--
- @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
-
- @author John Molakvoæ <skjnldsv@protonmail.com>
-
- @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-navigation" :class="{'icon-loading': menu.loading}">
<div class="app-navigation-new" v-if="menu.new">
<button type="button" :id="menu.new.id" :class="menu.new.icon" @click="menu.new.action">{{menu.new.text}}</button>
</div>
<ul :id="menu.id">
<navigation-item v-for="item in menu.items" :item="item" :key="item.key" />
</ul>
<div id="app-settings" v-if="!!$slots['settings-content']">
<div id="app-settings-header">
<button class="settings-button"
data-apps-slide-toggle="#app-settings-content"
>{{t('settings', 'Settings')}}</button>
</div>
<div id="app-settings-content">
<slot name="settings-content"></slot>
</div>
</div>
</div>
</template>
<script>
import navigationItem from './appNavigation/navigationItem';
export default {
name: 'appNavigation',
props: ['menu'],
components: {
navigationItem
}
};
</script>

View File

@ -1,155 +0,0 @@
<!--
- @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
-
- @author John Molakvoæ <skjnldsv@protonmail.com>
-
- @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>
<!-- Is this a caption ? -->
<li class="app-navigation-caption" v-if="item.caption">{{item.text}}</li>
<!-- Navigation item -->
<nav-element v-else :id="item.id" v-bind="navElement(item)"
:class="[{'icon-loading-small': item.loading, 'open': item.opened, 'collapsible': item.collapsible&&item.children&&item.children.length>0 }, item.classes]">
<!-- Bullet -->
<div v-if="item.bullet" class="app-navigation-entry-bullet" :style="{ backgroundColor: item.bullet }"></div>
<!-- Main link -->
<a :href="(item.href) ? item.href : '#' " @click="toggleCollapse" :class="item.icon">
<img v-if="item.iconUrl" :alt="item.text" :src="item.iconUrl">
{{item.text}}
</a>
<!-- Popover, counter and button(s) -->
<div v-if="item.utils" class="app-navigation-entry-utils">
<ul>
<!-- counter -->
<li v-if="Number.isInteger(item.utils.counter)"
class="app-navigation-entry-utils-counter">{{item.utils.counter}}</li>
<!-- first action if only one action -->
<li v-if="item.utils.actions && item.utils.actions.length === 1"
class="app-navigation-entry-utils-menu-button">
<button @click="item.utils.actions[0].action" :class="item.utils.actions[0].icon" :title="item.utils.actions[0].text"></button>
</li>
<!-- second action only two actions and no counter -->
<li v-else-if="item.utils.actions && item.utils.actions.length === 2 && !Number.isInteger(item.utils.counter)"
v-for="action in item.utils.actions" :key="action.action"
class="app-navigation-entry-utils-menu-button">
<button @click="action.action" :class="action.icon" :title="action.text"></button>
</li>
<!-- menu if only at least one action and counter OR two actions and no counter-->
<li v-else-if="item.utils.actions && item.utils.actions.length > 1 && (Number.isInteger(item.utils.counter) || item.utils.actions.length > 2)"
class="app-navigation-entry-utils-menu-button">
<button v-click-outside="hideMenu" @click="showMenu" ></button>
</li>
</ul>
</div>
<!-- if more than 2 actions or more than 1 actions with counter -->
<div v-if="item.utils && item.utils.actions && item.utils.actions.length > 1 && (Number.isInteger(item.utils.counter) || item.utils.actions.length > 2)"
class="app-navigation-entry-menu" :class="{ 'open': openedMenu }">
<popover-menu :menu="item.utils.actions"/>
</div>
<!-- undo entry -->
<div class="app-navigation-entry-deleted" v-if="item.undo">
<div class="app-navigation-entry-deleted-description">{{item.undo.text}}</div>
<button class="app-navigation-entry-deleted-button icon-history" :title="t('settings', 'Undo')"></button>
</div>
<!-- edit entry -->
<div class="app-navigation-entry-edit" v-if="item.edit">
<form>
<input type="text" v-model="item.text">
<input type="submit" value="" class="icon-confirm">
<input type="submit" value="" class="icon-close" @click.stop.prevent="cancelEdit">
</form>
</div>
<!-- if the item has children, inject the component with proper data -->
<ul v-if="item.children">
<navigation-item v-for="(item, key) in item.children" :item="item" :key="key" />
</ul>
</nav-element>
</template>
<script>
import popoverMenu from '../popoverMenu';
import ClickOutside from 'vue-click-outside';
import Vue from 'vue';
export default {
name: 'navigationItem',
props: ['item'],
components: {
popoverMenu
},
directives: {
ClickOutside
},
data() {
return {
openedMenu: false
};
},
methods: {
showMenu() {
this.openedMenu = true;
},
hideMenu() {
this.openedMenu = false;
},
toggleCollapse() {
// if item.opened isn't set, Vue won't trigger view updates https://vuejs.org/v2/api/#Vue-set
// ternary is here to detect the undefined state of item.opened
Vue.set(this.item, 'opened', this.item.opened ? !this.item.opened : true);
},
cancelEdit() {
// remove the editing class
if (Array.isArray(this.item.classes))
this.item.classes = this.item.classes.filter(
item => item !== 'editing'
);
},
// This is used to decide which outter element type to use
// li or router-link
navElement(item) {
if (item.href) {
return {
is: 'li'
};
}
return {
is: 'router-link',
tag: 'li',
to: item.router,
exact: true
};
}
},
mounted() {
// prevent click outside event with popupItem.
this.popupItem = this.$el;
}
};
</script>

View File

@ -44,9 +44,9 @@
</div>
<form class="row" id="new-user" v-show="showConfig.showNewUserForm"
v-on:submit.prevent="createUser" :disabled="loading"
v-on:submit.prevent="createUser" :disabled="loading.all"
:class="{'sticky': scrolled && showConfig.showNewUserForm}">
<div :class="loading?'icon-loading-small':'icon-add'"></div>
<div :class="loading.all?'icon-loading-small':'icon-add'"></div>
<div class="name">
<input id="newusername" type="text" required v-model="newUser.id"
:placeholder="t('settings', 'Username')" name="username"
@ -74,12 +74,13 @@
<div class="groups">
<!-- hidden input trick for vanilla html5 form validation -->
<input type="text" :value="newUser.groups" v-if="!settings.isAdmin"
tabindex="-1" id="newgroups" :required="!settings.isAdmin" />
<multiselect :options="canAddGroups" v-model="newUser.groups"
:placeholder="t('settings', 'Add user in group')"
label="name" track-by="id" class="multiselect-vue"
:multiple="true" :close-on-select="false"
:allowEmpty="settings.isAdmin">
tabindex="-1" id="newgroups" :required="!settings.isAdmin"
:class="{'icon-loading-small': loading.groups}"/>
<multiselect v-model="newUser.groups" :options="canAddGroups" :disabled="loading.groups||loading.all"
tag-placeholder="create" :placeholder="t('settings', 'Add user in group')"
label="name" track-by="id" class="multiselect-vue"
:multiple="true" :taggable="true" :close-on-select="false"
@tag="createGroup">
<!-- If user is not admin, he is a subadmin.
Subadmins can't create users outside their groups
Therefore, empty select is forbidden -->
@ -154,7 +155,10 @@ export default {
return {
unlimitedQuota: unlimitedQuota,
defaultQuota: defaultQuota,
loading: false,
loading: {
all: false,
groups: false
},
scrolled: false,
searchQuery: '',
newUser: {
@ -318,10 +322,10 @@ export default {
resetForm() {
// revert form to original state
Object.assign(this.newUser, this.$options.data.call(this).newUser);
this.loading = false;
this.loading.all = false;
},
createUser() {
this.loading = true;
this.loading.all = true;
this.$store.dispatch('addUser', {
userid: this.newUser.id,
password: this.newUser.password,
@ -332,7 +336,7 @@ export default {
quota: this.newUser.quota.id,
language: this.newUser.language.code,
}).then(() => this.resetForm())
.catch(() => this.loading = false);
.catch(() => this.loading.all = false);
},
setNewUserDefaultGroup(value) {
if (value && value.length > 0) {
@ -345,6 +349,25 @@ export default {
}
// fallback, empty selected group
this.newUser.groups = [];
},
/**
* Create a new group
*
* @param {string} groups Group id
* @returns {Promise}
*/
createGroup(gid) {
this.loading.groups = true;
this.$store.dispatch('addGroup', gid)
.then((group) => {
this.newUser.groups.push(this.groups.find(group => group.id === gid))
this.loading.groups = false;
})
.catch(() => {
this.loading.groups = false;
});
return this.$store.getters.getGroups[this.groups.length];
}
}
}

View File

@ -296,7 +296,10 @@ const actions = {
addGroup(context, gid) {
return api.requireAdmin().then((response) => {
return api.post(OC.linkToOCS(`cloud/groups`, 2), {groupid: gid})
.then((response) => context.commit('addGroup', {gid: gid, displayName: gid}))
.then((response) => {
context.commit('addGroup', {gid: gid, displayName: gid})
return {gid: gid, displayName: gid}
})
.catch((error) => {throw error;});
}).catch((error) => {
context.commit('API_FAILURE', { gid, error });

View File

@ -34,7 +34,7 @@
<script>
import appNavigation from '../components/appNavigation';
import { AppNavigation } from 'nextcloud-vue';
import appList from '../components/appList';
import Vue from 'vue';
import VueLocalStorage from 'vue-localstorage'
@ -42,7 +42,6 @@ import Multiselect from 'vue-multiselect';
import api from '../store/api';
import AppDetails from '../components/appDetails';
Vue.use(VueLocalStorage)
Vue.use(VueLocalStorage)
export default {
@ -59,7 +58,7 @@ export default {
},
components: {
AppDetails,
appNavigation,
AppNavigation,
appList,
},
methods: {

View File

@ -57,21 +57,20 @@
</template>
<script>
import appNavigation from '../components/appNavigation';
import { AppNavigation } from 'nextcloud-vue';
import userList from '../components/userList';
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: 'Users',
props: ['selectedGroup'],
components: {
appNavigation,
AppNavigation,
userList,
Multiselect
},
@ -101,6 +100,8 @@ export default {
// temporary value used for multiselect change
selectedQuota: false,
externalActions: [],
showAddGroupEntry: false,
loadingAddGroup: false,
showConfig: {
showStoragePath: false,
showUserBackend: false,
@ -198,6 +199,24 @@ export default {
action: action
});
return this.externalActions;
},
/**
* Create a new group
*
* @param {Object} event The form submit event
*/
createGroup(event) {
let gid = event.target[0].value;
this.loadingAddGroup = true;
this.$store.dispatch('addGroup', gid)
.then(() => {
this.showAddGroupEntry = false;
this.loadingAddGroup = false;
})
.catch(() => {
this.loadingAddGroup = false;
});
}
},
computed: {
@ -276,6 +295,7 @@ export default {
// BUILD APP NAVIGATION MENU OBJECT
menu() {
// Data provided php side
let self = this;
let groups = this.$store.getters.getGroups;
groups = Array.isArray(groups) ? groups : [];
@ -302,31 +322,19 @@ export default {
if (item.id !== 'admin' && item.id !== 'disabled' && this.settings.isAdmin) {
// add delete button on real groups
let self = this;
item.utils.actions = [{
icon: 'icon-delete',
text: t('settings', 'Remove group'),
action: function() {self.removeGroup(group.id)}
action: function() {
self.removeGroup(group.id)
}
}];
};
return item;
});
// Adjust data
let adminGroup = groups.find(group => group.id == 'admin');
let disabledGroupIndex = groups.findIndex(group => group.id == 'disabled');
let disabledGroup = groups[disabledGroupIndex];
if (adminGroup && adminGroup.text) {
adminGroup.text = t('settings', 'Admins'); // rename admin group
adminGroup.icon = 'icon-user-admin'; // set icon
}
if (disabledGroup && disabledGroup.text) {
disabledGroup.text = t('settings', 'Disabled users'); // rename disabled group
disabledGroup.icon = 'icon-disabled-users'; // set icon
if (!disabledGroup.utils.counter) {
groups.splice(disabledGroupIndex, 1); // remove disabled if empty
}
}
// Every item is added on top of the array, so we're going backward
// Groups, separator, disabled, admin, everyone
// Add separator
let realGroups = groups.find((group) => {return group.id !== 'disabled' && group.id !== 'admin'});
@ -340,6 +348,26 @@ export default {
groups.unshift(separator);
}
// Adjust admin and disabled groups
let adminGroup = groups.find(group => group.id == 'admin');
let disabledGroup = groups.find(group => group.id == 'disabled');
// filter out admin and disabled
groups = groups.filter(group => ['admin', 'disabled'].indexOf(group.id) === -1);
if (adminGroup && adminGroup.text) {
adminGroup.text = t('settings', 'Admins'); // rename admin group
adminGroup.icon = 'icon-user-admin'; // set icon
groups.unshift(adminGroup); // add admin group if present
}
if (disabledGroup && disabledGroup.text) {
disabledGroup.text = t('settings', 'Disabled users'); // rename disabled group
disabledGroup.icon = 'icon-disabled-users'; // set icon
if (disabledGroup.utils && disabledGroup.utils.counter > 0) {
groups.unshift(disabledGroup); // add disabled if not empty
}
}
// Add everyone group
let everyoneGroup = {
@ -351,10 +379,35 @@ export default {
};
// users count
if (this.userCount > 0) {
everyoneGroup.utils = {counter: this.userCount};
Vue.set(everyoneGroup, 'utils', {
counter: this.userCount
});
}
groups.unshift(everyoneGroup);
let addGroup = {
id: 'addgroup',
key: 'addgroup',
icon: 'icon-add',
text: t('settings', 'Add group'),
classes: this.loadingAddGroup ? 'icon-loading-small' : ''
};
if (this.showAddGroupEntry) {
Vue.set(addGroup, 'edit', {
text: t('settings', 'Add group'),
action: this.createGroup,
reset: function() {
self.showAddGroupEntry = false
}
});
addGroup.classes = 'editing';
} else {
Vue.set(addGroup, 'action', function() {
self.showAddGroupEntry = true
})
}
groups.unshift(addGroup);
// Return
return {
id: 'usergrouplist',

View File

@ -13,14 +13,13 @@ module.exports = {
{
test: /\.css$/,
use: [
'css-loader'
'vue-style-loader', 'css-loader'
],
},
{
test: /\.scss$/,
use: [
'css-loader',
'sass-loader'
'vue-style-loader', 'css-loader', 'sass-loader'
],
},
{