Disables hover on opened form in drandrop fields and filters. Creates actions for filter CRUD in axios (needs api update). Initiates FiltersList comonent.

This commit is contained in:
mateuswetah 2018-03-12 15:45:59 -03:00
parent 36f14798fc
commit db2d785dbc
8 changed files with 486 additions and 15 deletions

View File

@ -12,7 +12,7 @@
:options="{group: { name:'fields', pull: false, put: true }, 'handle': '.handle', chosenClass: 'sortable-chosen', filter: '.not-sortable-item'}">
<div
class="active-field-item"
:class="{'not-sortable-item': field.id == undefined, 'inherited-field': field.collection_id != collectionId}"
:class="{'not-sortable-item': field.id == undefined || openedFieldId == field.id, 'inherited-field': field.collection_id != collectionId}"
v-for="(field, index) in activeFieldList" :key="index">
<div class="handle">
<b-icon type="is-gray" class="is-pulled-left" icon="drag"></b-icon>
@ -43,7 +43,7 @@
</b-field>
</div>
<div class="column">
<b-field :label="$i18n.get('label_available_fields_types')">
<b-field :label="$i18n.get('label_available_field_types')">
<div class="columns box available-fields-area" >
<draggable class="column" :list="availableFieldList" :options="{ sort: false, group: { name:'fields', pull: 'clone', put: false, revertClone: true }}">
<div class="available-field-item" v-if="index % 2 == 0" v-for="(field, index) in availableFieldList" :key="index">
@ -260,7 +260,9 @@ export default {
height: 1em;
width: 1em;
}
&.not-sortable-item {
&.not-sortable-item, &.not-sortable-item:hover {
box-shadow: none !important;
top: 0px !important;
color: gray;
cursor: default;
}

View File

@ -1,21 +1,314 @@
<template>
<div>
<h1>Filters List</h1>
<b-loading :active.sync="isLoadingFilterTypes"></b-loading>
<div class="columns">
<div class="column">
<b-filter :label="$i18n.get('label_active_filters')" is-grouped>
<draggable
class="box active-filters-area"
@change="handleChange"
:class="{'filters-area-receive': isDraggingFromAvailable}"
:list="activeFilterList"
:options="{group: { name:'filters', pull: false, put: true }, 'handle': '.handle', chosenClass: 'sortable-chosen', filter: '.not-sortable-item'}">
<div
class="active-filter-item"
:class="{'not-sortable-item': filter.id == undefined || openedFilterId == filter.id, 'inherited-filter': filter.collection_id != collectionId}"
v-for="(filter, index) in activeFilterList" :key="index">
<div class="handle">
<b-icon type="is-gray" class="is-pulled-left" icon="drag"></b-icon>
<span class="filter-name">{{ filter.name }}</span>
<span class="label-details">{{ $i18n.get(filter.filter_type_object.component)}}<span class="loading-spinner" v-if="filter.id == undefined"></span></span>
<span class="controls">
<b-switch size="is-small" v-model="filter.disabled" @input="onChangeEnable($event, index)">{{ filter.disabled ? $i18n.get('label_disabled') : $i18n.get('label_enabled') }}</b-switch>
<a @click.prevent="removeFilter(filter)" v-if="filter.id != undefined">
<b-icon icon="delete"></b-icon>
</a>
<a @click.prevent="editFilter(filter)" v-if="filter.id != undefined">
<b-icon icon="pencil" v-if="filter.id != undefined"></b-icon>
</a>
</span>
</div>
<b-filter v-if="openedFilterId == filter.id">
<!-- <filter-edition-form
:collectionId="collectionId"
:isRepositoryLevel="isRepositoryLevel"
@onEditionFinished="onEditionFinished()"
@onEditionCanceled="onEditionCanceled()"
:filter="editForm"></filter-edition-form> -->
</b-filter>
</div>
<!-- <div class="not-sortable-item" slot="footer">{{ $i18n.get('instruction_dragndrop_filters_collection') }}</div> -->
</draggable>
</b-filter>
</div>
<div class="column">
<b-filter :label="$i18n.get('label_available_filter_types')">
<div class="columns box available-filters-area" >
<draggable class="column" :list="availableFilterList" :options="{ sort: false, group: { name:'filters', pull: 'clone', put: false, revertClone: true }}">
<div class="available-filter-item" v-if="index % 2 == 0" v-for="(filter, index) in availableFilterList" :key="index">
{{ filter.name }} <b-icon type="is-gray" class="is-pulled-left" icon="drag"></b-icon>
</div>
</draggable>
<draggable class="column" :list="availableFilterList" :options="{ sort: false, group: { name:'filters', pull: 'clone', put: false, revertClone: true }}">
<div class="available-filter-item" v-if="index % 2 != 0" v-for="(filter, index) in availableFilterList" :key="index">
{{ filter.name }} <b-icon type="is-gray" class="is-pulled-left" icon="drag"></b-icon>
</div>
</draggable>
</div>
</b-filter>
</div>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
import FilterEditionForm from './../edition/filter-edition-form.vue';
export default {
name: 'FiltersList',
data(){
return {
collectionId: '',
isRepositoryLevel: false,
isDraggingFromAvailable: false,
isLoadingFilterTypes: true,
isLoadingFilters: false,
isLoadingFilter: false,
openedFilterId: '',
editForm: {}
}
},
components: {
//FilterEditionForm
},
methods: {
...mapActions('filter', [
'fetchFilterTypes',
'fetchFilters',
'sendFilter',
'deleteFilter',
'updateCollectionFiltersOrder'
]),
...mapGetters('filter',[
'getFilterTypes',
'getFilters'
]),
handleChange($event) {
if ($event.added) {
this.addNewFilter($event.added.element, $event.added.newIndex);
} else if ($event.removed) {
this.removeFilter($event.removed.element);
} else if ($event.moved) {
if (!this.isRepositoryLevel)
this.updateFiltersOrder();
}
},
updateFiltersOrder() {
let filtersOrder = [];
for (let filter of this.activeFilterList) {
filtersOrder.push({'id': filter.id, 'enabled': !filter.disabled});
}
this.updateCollectionFiltersOrder({ collectionId: this.collectionId, filtersOrder: filtersOrder });
},
onChangeEnable($event, index) {
this.activeFilterList[index].disabled = $event;
let filtersOrder = [];
for (let filter of this.activeFilterList) {
filtersOrder.push({'id': filter.id, 'enabled': !filter.disabled});
}
this.updateCollectionFiltersOrder({ collectionId: this.collectionId, filtersOrder: filtersOrder });
},
addNewFilter(newFilter, newIndex) {
this.sendFilter({collectionId: this.collectionId, name: newFilter.name, filterType: newFilter.className, status: 'auto-draft', isRepositoryLevel: this.isRepositoryLevel})
.then((filter) => {
if (newIndex < 0) {
this.activeFilterList.pop();
this.activeFilterList.push(filter);
} else {
this.activeFilterList.splice(newIndex, 1, filter);
}
if (!this.isRepositoryLevel)
this.updateFiltersOrder();
this.editFilter(filter);
})
.catch((error) => {
console.log(error);
});
},
removeFilter(removedFilter) {
this.deleteFilter({ collectionId: this.collectionId, filterId: removedFilter.id, isRepositoryLevel: this.isRepositoryLevel})
.then((filter) => {
let index = this.activeFilterList.findIndex(deletedFilter => deletedFilter.id === filter.id);
if (index >= 0)
this.activeFilterList.splice(index, 1);
if (!this.isRepositoryLevel)
this.updateFiltersOrder();
})
.catch((error) => {
});
},
editFilter(filter) {
if (this.openedFilterId == filter.id) {
this.openedFilterId = '';
this.editForm = {};
} else {
this.openedFilterId = filter.id;
this.editForm = JSON.parse(JSON.stringify(filter));
this.editForm.status = 'publish';
}
},
onEditionFinished() {
this.openedFilterId = '';
this.fetchFilters({collectionId: this.collectionId, isRepositoryLevel: this.isRepositoryLevel});
},
onEditionCanceled() {
this.openedFilterId = '';
}
},
computed: {
availableFilterList() {
return this.getFilterTypes();
},
activeFilterList() {
return this.getFilters();
}
},
created() {
this.isLoadingFilterTypes = true;
this.isLoadingFilters = true;
this.fetchFilterTypes()
.then((res) => {
this.isLoadingFilterTypes = false;
})
.catch((error) => {
this.isLoadingFilterTypes = false;
});
this.isRepositoryLevel = this.$route.name == 'FiltersPage' ? true : false;
if (this.isRepositoryLevel)
this.collectionId = 'default';
else
this.collectionId = this.$route.params.collectionId;
this.fetchFilters({collectionId: this.collectionId, isRepositoryLevel: this.isRepositoryLevel})
.then((res) => {
this.isLoadingFilters = false;
})
.catch((error) => {
this.isLoadingFilters = false;
});
}
}
</script>
<style scoped>
<style lang="scss" scoped>
@import "../../scss/_variables.scss";
.active-filters-area {
min-height: 40px;
padding: 10px;
&.filters-area-receive {
background-color: whitesmoke;
border: 1px dashed gray;
}
.collapse {
display: initial;
}
.active-filter-item {
background-color: white;
padding: 0.4em;
margin: 10px;
border-radius: 5px;
border: 1px solid gainsboro;
display: block;
transition: top 0.2s ease;
cursor: grab;
.filter-name {
text-overflow: ellipsis;
overflow-x: hidden;
white-space: nowrap;
}
.label-details {
font-weight: normal;
font-style: italic;
color: gray;
}
.controls { float: right }
.loading-spinner {
animation: spinAround 500ms infinite linear;
border: 2px solid #dbdbdb;
border-radius: 290486px;
border-right-color: transparent;
border-top-color: transparent;
content: "";
display: inline-block;
height: 1em;
width: 1em;
}
&.not-sortable-item, &.not-sortable-item:hover {
box-shadow: none !important;
top: 0px !important;
color: gray;
cursor: default;
}
&.inherited-filter {
color: gray;
}
}
.active-filter-item:hover {
box-shadow: 0 3px 4px rgba(0,0,0,0.25);
position: relative;
top: -2px;
}
.sortable-chosen {
background-color: $primary-lighter;
margin: 10px;
border-radius: 5px;
border: 1px dashed $primary-light;
display: block;
}
}
.available-filters-area {
padding: 0 10px;
margin: 0;
background-color: whitesmoke;
.available-filter-item {
padding: 0.4em;
margin: 10px 10% 10px 0px;
border-radius: 5px;
background-color: white;
border: 1px solid gainsboro;
width: 100%;
cursor: grab;
top: 0;
transition: top 0.2s ease;
}
.available-filter-item:hover {
border: 1px solid lightgrey;
box-shadow: 2px 3px 4px rgba(0,0,0,.25);
position: relative;
top: -2px;
left: -2px;
}
}
</style>

View File

@ -76,7 +76,10 @@ return [
'label_items_per_page' => __('Items per Page:', 'tainacan'),
'label_active_fields' => __('Active Fields', 'tainacan'),
'label_available_fields' => __('Available Fields', 'tainacan'),
'label_available_fields_types' => __('Available Fields Types', 'tainacan'),
'label_available_fields_types' => __('Available Field Types', 'tainacan'),
'label_active_filters' => __('Active Filters', 'tainacan'),
'label_available_filters' => __('Available Filters', 'tainacan'),
'label_available_filter_types' => __('Available Filter Types', 'tainacan'),
'label_per_page' => __('per Page', 'tainacan'),
'label_table_fields' => __('Fields on table', 'tainacan'),
'label_required' => __('Required', 'tainacan'),

View File

@ -59,7 +59,7 @@ export const sendField = ( { commit }, { collectionId, name, fieldType, status,
status: status
})
.then( res => {
commit('setField', { collection_id: collectionId, name: name, field_type: fieldType, status: status });
commit('setSingleField', { collection_id: collectionId, name: name, field_type: fieldType, status: status });
resolve( res.data );
})
.catch(error => {

View File

@ -1,6 +1,7 @@
import axios from '../../../axios/axios';
import qs from 'qs';
// METAQUERIES ----------------------------------------------------
export const search_by_collection = ({ state, dispatch, rootGetters }, collectionId) => {
return new Promise((resolve, reject) =>{
axios.tainacan.get('/collection/' + collectionId + '/items?' + qs.stringify( state.postquery ))
@ -14,9 +15,8 @@ export const search_by_collection = ({ state, dispatch, rootGetters }, collecti
});
};
export const set_postquery_attribute = ({ commit }, field, value ) => {
commit('setPostQuery', { attr: field, value: value } );
export const set_postquery_attribute = ({ commit }, filter, value ) => {
commit('setPostQuery', { attr: filter, value: value } );
};
export const add_metaquery = ( { commit }, filter ) => {
@ -27,5 +27,140 @@ export const remove_metaquery = ( { commit }, filter ) => {
commit('removeMetaQuery', filter );
};
// FILTERS --------------------------------------------------------
export const fetchFilters = ({ commit }, {collectionId, isRepositoryLevel}) => {
return new Promise((resolve, reject) => {
let endpoint = '';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/filters/';
else
endpoint = '/filters/';
axios.tainacan.get(endpoint + '?context=edit')
.then((res) => {
let filters= res.data;
commit('setFilters', filters);
resolve (filters);
})
.catch((error) => {
console.log(error);
reject(error);
});
});
}
export const fetchFilter = ({ commit }, {collectionId, filterId, isRepositoryLevel}) => {
return new Promise((resolve, reject) => {
let endpoint = '';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/filters/' + filterId;
else
endpoint = '/filters/' + filterId;
axios.tainacan.get(endpoint + '?context=edit')
.then((res) => {
let filter = res.data;
commit('setSingleFilter', filter);
resolve (filter);
})
.catch((error) => {
console.log(error);
reject(error);
});
});
}
export const sendFilter = ( { commit }, { collectionId, fieldId, name, filterType, status, isRepositoryLevel }) => {
return new Promise(( resolve, reject ) => {
let endpoint = '';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/field/' + fieldId +'/filters/';
else
endpoint = '/filters/';
axios.tainacan.post(endpoint + '?context=edit', {
name: name,
filter_type: filterType,
status: status
})
.then( res => {
commit('setSingleFilter', { collection_id: collectionId, name: name, filter_type: filterType, status: status });
resolve( res.data );
})
.catch(error => {
reject( error.response );
});
});
};
export const updateFilter = ( { commit }, { collectionId, fieldId, filterId, isRepositoryLevel, options }) => {
return new Promise(( resolve, reject ) => {
let endpoint = '';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/field/' + fieldId +'/filters/';
else
endpoint = '/filters/' + filterId;
axios.tainacan.put(endpoint, options)
.then( res => {
commit('setSingleFilter', res.data);
resolve( res.data );
})
.catch(error => {
console.log(error);
reject({ error_message: error['response']['data'].error_message, errors: error['response']['data'].errors });
});
});
};
export const deleteFilter = ({ commit }, { collectionId, fieldId, filterId, isRepositoryLevel }) => {
let endpoint = '';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/field/' + fieldId +'/filters/';
else
endpoint = '/filters/' + filterId;
return new Promise((resolve, reject) => {
axios.tainacan.delete(endpoint)
.then( res => {
commit('deleteFilter', { filterId } );
resolve( res.data );
}).catch((error) => {
console.log(error);
reject( error );
});
});
};
export const updateCollectionFiltersOrder = ({ commit }, { collectionId, filtersOrder }) => {
return new Promise((resolve, reject) => {
axios.tainacan.patch('/collections/' + collectionId, {
filters_order: filtersOrder
}).then( res => {
commit('setCollection', res.data);
resolve( res.data );
}).catch( error => {
reject( error.response );
});
});
}
export const fetchFilterTypes = ({ commit} ) => {
return new Promise((resolve, reject) => {
axios.tainacan.get('/filter-types')
.then((res) => {
let filterTypes = res.data;
commit('setFilterTypes', filterTypes);
resolve (filterTypes);
})
.catch((error) => {
console.log(error);
reject(error);
});
});
}

View File

@ -9,3 +9,12 @@ export const getMetaQuery = state => {
export const getTaxQuery = state => {
return state.taxquery;
}
export const getFilters = state => {
return state.filters;
}
export const getFilterTypes = state => {
return state.flterTypes;
}

View File

@ -8,7 +8,9 @@ const state = {
post_type: [],
metaquery: [],
taxquery: []
}
},
filters: [],
filterTypes: []
};
export default {

View File

@ -1,5 +1,6 @@
import Vue from 'vue';
// METAQUERIES ----------------------------------------------------------------------------
export const setPostQuery = ( state, { attr, value }) => {
Vue.set( state.postquery, attr , value );
};
@ -29,3 +30,29 @@ export const removeMetaQuery = ( state, filter ) => {
state.metaquery.splice(index, 1);
}
}
// FILTERS ------------------------------------------------------------------------
export const deleteFilter = ( state, filter ) => {
let index = state.filters.findIndex(deletedFilter => deletedFilter.id === filter.id);
if (index >= 0) {
state.filters.splice(index, 1);
}
}
export const setSingleFilter = (state, filter) => {
let index = state.filters.findIndex(newFilter => newFilter.id === filter.id);
if ( index >= 0){
Vue.set( state.filters, index, filter );
} else {
state.filters.push( filter );
}
}
export const setFilters = (state, filters) => {
state.filters = filters;
}
export const setFilterTypes = (state, filterTypes) => {
state.filterTypes = filterTypes;
}