mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
add base card and controls for GroupList view
This commit is contained in:
parent
f4fe02f798
commit
90fc7d0092
4 changed files with 182 additions and 4 deletions
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
<b-input-group>
|
<b-input-group>
|
||||||
<b-input-group-prepend is-text>
|
<b-input-group-prepend is-text>
|
||||||
<label class="sr-only" for="search-user">{{ $t('user.search') }}</label>
|
<label class="sr-only" for="selectize">{{ ariaLabel }}</label>
|
||||||
<icon :iname="searchIcon" v-if="searchIcon" />
|
<icon :iname="searchIcon" v-if="searchIcon" />
|
||||||
</b-input-group-prepend>
|
</b-input-group-prepend>
|
||||||
<b-form-input
|
<b-form-input
|
||||||
:class="visible ? null : 'collapsed'"
|
id="selectize" :class="visible ? null : 'collapsed'"
|
||||||
aria-controls="collapse" :aria-expanded="visible ? 'true' : 'false'"
|
aria-controls="collapse" :aria-expanded="visible ? 'true' : 'false'"
|
||||||
@focus="onInputFocus" @blur="onInputBlur" @keydown="onInputKeydown"
|
@focus="onInputFocus" @blur="onInputBlur" @keydown="onInputKeydown"
|
||||||
v-model="search" ref="input"
|
v-model="search" ref="input"
|
||||||
|
@ -56,7 +56,8 @@ export default {
|
||||||
searchIcon: { type: String, default: 'search' },
|
searchIcon: { type: String, default: 'search' },
|
||||||
itemIcon: { type: String, default: null },
|
itemIcon: { type: String, default: null },
|
||||||
itemRoute: { type: String, default: null },
|
itemRoute: { type: String, default: null },
|
||||||
itemVariant: { type: String, default: 'secondary' }
|
itemVariant: { type: String, default: 'secondary' },
|
||||||
|
ariaLabel: { type: String, required: true }
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
|
|
|
@ -337,6 +337,9 @@
|
||||||
"version": "Version",
|
"version": "Version",
|
||||||
"warnings": "%s warnings",
|
"warnings": "%s warnings",
|
||||||
"warning_first_user": "You probably need to <a href='#/users/create' class='alert-link'>create a user</a> first.",
|
"warning_first_user": "You probably need to <a href='#/users/create' class='alert-link'>create a user</a> first.",
|
||||||
|
"words": {
|
||||||
|
"collapse": "Collapse"
|
||||||
|
},
|
||||||
"wrong_password": "Wrong password",
|
"wrong_password": "Wrong password",
|
||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"certificate_alert_not_valid": "CRITICAL: Current certificate is not valid! HTTPS won't work at all!",
|
"certificate_alert_not_valid": "CRITICAL: Current certificate is not valid! HTTPS won't work at all!",
|
||||||
|
|
|
@ -65,6 +65,7 @@ body {
|
||||||
|
|
||||||
.card-header h2 {
|
.card-header h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
font-size: 1.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,186 @@
|
||||||
<template lang="html">
|
<template lang="html">
|
||||||
<div class="group-list">
|
<div class="group-list">
|
||||||
|
<div class="actions">
|
||||||
|
<b-input-group>
|
||||||
|
<b-input-group-prepend is-text>
|
||||||
|
<label class="sr-only" for="search-group">Search group</label>
|
||||||
|
<icon iname="search" />
|
||||||
|
</b-input-group-prepend>
|
||||||
|
<b-form-input id="search-group" v-model="search" placeholder="Search group" />
|
||||||
|
</b-input-group>
|
||||||
|
<div class="buttons">
|
||||||
|
<b-button variant="success" :to="{name: 'group-create'}">
|
||||||
|
<icon iname="plus" /> {{ $t('group_new') }}
|
||||||
|
</b-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PRIMARY GROUPS CARDS -->
|
||||||
|
<template v-if="groups">
|
||||||
|
<b-card
|
||||||
|
v-for="(group, name, index) in primaryGroups" :key="index"
|
||||||
|
no-body
|
||||||
|
>
|
||||||
|
<b-card-header class="d-flex align-items-center">
|
||||||
|
<h2>
|
||||||
|
<icon iname="group" />{{ group.isSpecial ? $t('group_' + name) : `${$t('group')} "${name}"` }}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="ml-auto">
|
||||||
|
<b-button v-b-toggle="'collapse-' + index" size="sm" variant="outline-secondary">
|
||||||
|
<icon iname="chevron-right" class="rotate" /><span class="sr-only">{{ $t('words.collapse') }}</span>
|
||||||
|
</b-button>
|
||||||
|
|
||||||
|
<b-button
|
||||||
|
v-if="!group.isSpecial" v-b-modal.delete-modal
|
||||||
|
variant="danger" class="ml-2" size="sm"
|
||||||
|
>
|
||||||
|
<icon :title="$t('delete')" iname="trash-o" /> <span class="sr-only">{{ $t('delete') }}</span>
|
||||||
|
</b-button>
|
||||||
|
</div>
|
||||||
|
</b-card-header>
|
||||||
|
|
||||||
|
<b-collapse :id="'collapse-' + index" visible>
|
||||||
|
<b-card-body>
|
||||||
|
<b-row>
|
||||||
|
<b-col md="3" lg="2">
|
||||||
|
<strong>{{ $t('users') }}</strong>
|
||||||
|
</b-col>
|
||||||
|
|
||||||
|
<b-col>
|
||||||
|
<template v-if="group.isSpecial">
|
||||||
|
<p><icon iname="info-circle" /> {{ $t('group_explain_' + name) }}</p>
|
||||||
|
<p v-if="name === 'visitors'">
|
||||||
|
<em>{{ $t('group_explain_visitors_needed_for_external_client') }}</em>
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<selectize-zone
|
||||||
|
:choices="group.membersInv" :selected="group.members"
|
||||||
|
item-icon="user" search-icon="user-plus" item-route="user-info"
|
||||||
|
:aria-label="$t('group_add_member')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
<hr>
|
||||||
|
<b-row>
|
||||||
|
<b-col md="3" lg="2">
|
||||||
|
<strong>{{ $t('permissions') }}</strong>
|
||||||
|
</b-col>
|
||||||
|
<b-col>
|
||||||
|
<selectize-zone
|
||||||
|
:choices="group.permissionsInv" :selected="group.permissions"
|
||||||
|
item-icon="key-modern" item-variant="info"
|
||||||
|
:aria-label="$t('group_add_permission')"
|
||||||
|
/>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</b-card-body>
|
||||||
|
</b-collapse>
|
||||||
|
</b-card>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import SelectizeZone from '@/components/SelectizeZone'
|
||||||
|
|
||||||
|
// TODO add global search with type (search by: group, user, permission)
|
||||||
export default {
|
export default {
|
||||||
name: 'GroupList'
|
name: 'GroupList',
|
||||||
|
|
||||||
|
data: () => ({
|
||||||
|
search: ''
|
||||||
|
}),
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
users () {
|
||||||
|
const users = this.$store.state.data.users
|
||||||
|
return users ? Object.values(users) : users
|
||||||
|
},
|
||||||
|
|
||||||
|
groups () {
|
||||||
|
const users = this.$store.state.data.users
|
||||||
|
const groups = this.$store.state.data.groups
|
||||||
|
const perms = this.$store.state.data.permissions
|
||||||
|
if (!users || !groups || !perms) return
|
||||||
|
const userNames = Object.keys(users)
|
||||||
|
|
||||||
|
for (const groupName in groups) {
|
||||||
|
groups[groupName].isPrimary = !userNames.includes(groupName)
|
||||||
|
groups[groupName].permissionsInv = perms.filter(perm => {
|
||||||
|
// Remove 'email' and 'xmpp' in visitors's permission choice list
|
||||||
|
if (groupName === 'visitors' && ['mail.main', 'xmpp.main'].includes(perm)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !groups[groupName].permissions.includes(perm)
|
||||||
|
})
|
||||||
|
groups[groupName].membersInv = userNames.filter(name => {
|
||||||
|
return !groups[groupName].members.includes(name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
groups.visitors.isSpecial = true
|
||||||
|
groups.all_users.isSpecial = true
|
||||||
|
|
||||||
|
return groups
|
||||||
|
},
|
||||||
|
|
||||||
|
permissions () {
|
||||||
|
return this.$store.state.data.permissions
|
||||||
|
},
|
||||||
|
|
||||||
|
primaryGroups () {
|
||||||
|
const groups = this.groups
|
||||||
|
if (!groups) return
|
||||||
|
const search = this.search.toLowerCase()
|
||||||
|
const primaryGroups = {}
|
||||||
|
for (const [groupName, group] of Object.entries(groups)) {
|
||||||
|
if (group.isPrimary && groupName.toLowerCase().includes(search)) {
|
||||||
|
primaryGroups[groupName] = group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return primaryGroups
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created () {
|
||||||
|
this.$store.dispatch('FETCH_ALL', [
|
||||||
|
{ uri: 'users' },
|
||||||
|
{ uri: 'users/groups?full&include_primary_groups', storeKey: 'groups' },
|
||||||
|
{ uri: 'users/permissions?short', storeKey: 'permissions' }
|
||||||
|
])
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
SelectizeZone
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.card + .card {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
.card-header {
|
||||||
|
h2 .icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
width: 1.5rem;
|
||||||
|
margin-right: 1.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collapse icon
|
||||||
|
.not-collapsed .icon {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
.collapsed .icon {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row > div:first-child {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Add table
Reference in a new issue