M2M list editor; users list & group mgt; add missing files

This commit is contained in:
bkfox
2024-04-27 21:05:36 +02:00
parent ae176dc623
commit 8f1ec9cbc1
43 changed files with 613 additions and 257 deletions

View File

@ -283,7 +283,7 @@ export default {
mounted() {
const form = this.$el.closest('form')
form.addEventListener('reset', () => {
form && form.addEventListener('reset', () => {
this.inputValue = this.value;
this.select(-1)
})

View File

@ -1,10 +1,10 @@
<template>
<div class="a-group-users">
<div class="a-m2m-edit">
<table class="table is-fullwidth">
<thead>
<tr>
<th>
Members
<slot name="items-title"></slot>
</th>
<th style="width: 1rem">
<span class="icon">
@ -17,8 +17,9 @@
<template v-for="item of items" :key="item.id">
<tr :class="[item.created && 'has-text-info', item.deleted && 'has-text-danger']">
<td>
<b class="mr-3">{{ item.data.user.username }}</b>
<span>{{ item.data.user.first_name }} {{ item.data.user.last_name }}</span>
<slot name="item" :item="item">
{{ item.data }}
</slot>
</td>
<td class="align-center">
<input type="checkbox" class="checkbox" @change="item.deleted = $event.target.checked">
@ -30,18 +31,14 @@
<div>
<label>
<span class="icon">
<i class="fa fa-user"/>
<i class="fa fa-plus"/>
</span>
Add user
Add
</label>
<a-autocomplete ref="autocomplete" :url="searchUrl"
label-field="username" value-field="id"
@select="onUserSelect">
<a-autocomplete ref="autocomplete" v-bind="autocomplete"
@select="onSelect">
<template #item="{item}">
<b class="mr-3">{{ item.username }}</b>
<span class="text-light">{{ item.first_name }} {{ item.last_name }}</span>
&mdash;
<i>{{ item.email }}</i>
<slot name="autocomplete-item" :item="item">{{ item }}</slot>
</template>
</a-autocomplete>
</div>
@ -57,12 +54,14 @@ export default {
model: {type: Function, default: Model },
// List url
url: String,
// User autocomplete url
searchUrl: String,
// POST url
commitUrl: String,
// default values
initials: {type: Object, default: () => ({})},
// v-bind to autocomplete search box
autocomplete: {type: Object },
source_id: Number,
source_field: String,
target_field: String,
},
data() {
@ -73,24 +72,32 @@ export default {
computed: {
items() { return this.set?.items || [] },
user_ids() { return this.set?.items.map(i => i.data.user.id) },
initials() {
let obj = {}
obj[this.source_id_attr] = this.source_id
return obj
},
source_id_attr() { return this.source_field + "_id" },
target_id_attr() { return this.target_field + "_id" },
target_ids() { return this.set?.items.map(i => i.data[this.target_id_attr]) },
},
methods: {
onUserSelect(index, item, value) {
if(this.user_ids.indexOf(item.id) != -1)
onSelect(index, item, value) {
if(this.target_ids.indexOf(item.id) != -1)
return
this.set.push({
...this.initials,
user: {...item},
})
let obj = {...this.initials}
obj[this.target_field] = {...item}
obj[this.target_id_attr] = item.id
this.set.push(obj)
this.$refs.autocomplete.reset()
},
save() {
this.set.commit(this.commitUrl, {
getData: i => ({...this.initials, user_id: i.data.user.id})
fields: [...Object.keys(this.initials), this.target_id_attr]
})
},
},

View File

@ -7,14 +7,14 @@ import AFormSet from './AFormSet.vue'
import ATrackListEditor from './ATrackListEditor.vue'
import ASoundListEditor from './ASoundListEditor.vue'
import AGroupUsers from "./AGroupUsers.vue"
import AManyToManyEdit from "./AManyToManyEdit.vue"
import base from "./index.js"
export const admin = {
...base,
AGroupUsers,
AManyToManyEdit,
AFileUpload, ASelectFile,
AFormSet, ATrackListEditor, ASoundListEditor,
AStatistics, AStreamer,

View File

@ -232,9 +232,14 @@ export class Set {
/**
* Commit changes to server.
* ref: `views.mixin.ListCommitMixin`
* py-ref: `views.mixin.ListCommitMixin`
*/
commit(url, {getData=null, ...options}={}) {
commit(url, {getData=null, fields=null, ...options}={}) {
if(!getData && fields)
getData = (i) => fields.reduce((r, f) => {
r[f] = i.data[f]
return r
}, {})
const createdItems = this.createdItems
const body = {
delete: this.deletedItems.map(i => i.id),

View File

@ -91,3 +91,8 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
display: flex;
flex-direction: column;
}
.modal .dropdown-menu {
z-index: 50,
}

View File

@ -88,6 +88,11 @@
.flex-column { display: flex; flex-direction: column }
.flex-grow-0 { flex-grow: 0 !important; }
.flex-grow-1 { flex-grow: 1 !important; }
.flex-grow-2 { flex-grow: 2 !important; }
.flex-grow-3 { flex-grow: 3 !important; }
.flex-grow-4 { flex-grow: 4 !important; }
.flex-grow-5 { flex-grow: 5 !important; }
.flex-grow-6 { flex-grow: 6 !important; }
.float-right { float: right }
.float-left { float: left }