M2M list editor; users list & group mgt; add missing files
This commit is contained in:
		@ -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)
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
                    —
 | 
			
		||||
                    <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]
 | 
			
		||||
            })
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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),
 | 
			
		||||
 | 
			
		||||
@ -91,3 +91,8 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.modal .dropdown-menu {
 | 
			
		||||
    z-index: 50,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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 }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user