Add record filter preset saving
This commit is contained in:
@@ -215,13 +215,23 @@
|
||||
{{ $t('general:label.reset') }}
|
||||
</b-button>
|
||||
|
||||
<b-button
|
||||
ref="btnSave"
|
||||
variant="primary"
|
||||
@click="onSave"
|
||||
>
|
||||
{{ $t('general.label.save') }}
|
||||
</b-button>
|
||||
<div class="d-flex">
|
||||
<b-button
|
||||
v-if="allowFilterPresetSave"
|
||||
variant="outline-primary"
|
||||
class="mr-2"
|
||||
@click="onSave(true, 'filter-preset')"
|
||||
>
|
||||
{{ $t('recordList.filter.addFilterToPreset') }}
|
||||
</b-button>
|
||||
<b-button
|
||||
ref="btnSave"
|
||||
variant="primary"
|
||||
@click="onSave"
|
||||
>
|
||||
{{ $t('general.label.save') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-card-footer>
|
||||
</b-card>
|
||||
|
||||
@@ -288,6 +298,11 @@ export default {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
|
||||
allowFilterPresetSave: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
data () {
|
||||
@@ -592,13 +607,8 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
onSave (close = true) {
|
||||
if (close) {
|
||||
this.$refs.popover.$emit('close')
|
||||
}
|
||||
|
||||
// Emit only value and not whole record with every filter
|
||||
this.$emit('filter', this.componentFilter.map(({ groupCondition, filter = [], name }) => {
|
||||
processFilter () {
|
||||
return this.componentFilter.map(({ groupCondition, filter = [], name }) => {
|
||||
filter = filter.map(({ record, ...f }) => {
|
||||
if (record) {
|
||||
f.value = record[f.name] || record.values[f.name]
|
||||
@@ -615,7 +625,16 @@ export default {
|
||||
})
|
||||
|
||||
return { groupCondition, filter, name }
|
||||
}))
|
||||
})
|
||||
},
|
||||
|
||||
onSave (close = true, type = 'filter') {
|
||||
if (close) {
|
||||
this.$refs.popover.$emit('close')
|
||||
}
|
||||
|
||||
// Emit only value and not whole record with every filter
|
||||
this.$emit(type, this.processFilter())
|
||||
},
|
||||
|
||||
updateFilterProperties (filter) {
|
||||
|
||||
@@ -78,22 +78,32 @@
|
||||
@export="onExport"
|
||||
/>
|
||||
|
||||
<b-dropdown
|
||||
v-if="filterPresets.length"
|
||||
size="lg"
|
||||
variant="light"
|
||||
right
|
||||
:text="$t('recordList.filter.filters.label')"
|
||||
<b-button
|
||||
:id="`${uniqueID}-filter-preset`"
|
||||
class="btn dropdown-toggle btn-light btn-lg"
|
||||
>
|
||||
<b-dropdown-item
|
||||
v-for="(f, idx) in filterPresets"
|
||||
:key="idx"
|
||||
:disabled="activeFilters.includes(f.name)"
|
||||
@click="updateFilter(f.filter, f.name)"
|
||||
>
|
||||
{{ f.name }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
{{ $t('recordList.filter.filters.label') }}
|
||||
</b-button>
|
||||
<b-popover
|
||||
:target="`${uniqueID}-filter-preset`"
|
||||
triggers="click blur"
|
||||
placement="bottom"
|
||||
>
|
||||
<ul class="list-style-none">
|
||||
<li
|
||||
v-for="(f, idx) in filterPresets"
|
||||
:key="idx"
|
||||
>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
:disabled="activeFilters.includes(f.name)"
|
||||
@click="updateFilter(f.filter, f.name)"
|
||||
>
|
||||
{{ f.name }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</b-popover>
|
||||
|
||||
<column-picker
|
||||
v-if="!options.hideConfigureFieldsButton"
|
||||
@@ -293,8 +303,10 @@
|
||||
:namespace="namespace"
|
||||
:module="recordListModule"
|
||||
:record-list-filter="recordListFilter"
|
||||
:allow-filter-preset-save="options.customFilterPresets"
|
||||
class="d-print-none ml-1"
|
||||
@filter="onFilter"
|
||||
@filter-preset="onSaveFilterPreset"
|
||||
@reset="activeFilters = []"
|
||||
/>
|
||||
|
||||
@@ -609,6 +621,13 @@
|
||||
open-on-select
|
||||
@save="onInlineEdit()"
|
||||
/>
|
||||
|
||||
<!-- Modal for naming custom filter -->
|
||||
<custom-filter-preset
|
||||
:visible="showCustomPresetFilterModal"
|
||||
@save="setStorageRecordListFilterPreset"
|
||||
@close="showCustomPresetFilterModal = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template
|
||||
@@ -733,6 +752,7 @@ import draggable from 'vuedraggable'
|
||||
import RecordListFilter from 'corteza-webapp-compose/src/components/Common/RecordListFilter'
|
||||
import ColumnPicker from 'corteza-webapp-compose/src/components/Admin/Module/Records/ColumnPicker'
|
||||
import BulkEditModal from 'corteza-webapp-compose/src/components/Public/Record/BulkEdit'
|
||||
import CustomFilterPreset from 'corteza-webapp-compose/src/components/Public/Record/CustomFilterPreset'
|
||||
|
||||
const { CInputSearch } = components
|
||||
|
||||
@@ -752,6 +772,7 @@ export default {
|
||||
ColumnPicker,
|
||||
CInputSearch,
|
||||
BulkEditModal,
|
||||
CustomFilterPreset,
|
||||
},
|
||||
|
||||
extends: base,
|
||||
@@ -815,6 +836,9 @@ export default {
|
||||
items: [],
|
||||
showingDeletedRecords: false,
|
||||
activeFilters: [],
|
||||
customPresetFilters: [],
|
||||
currentCustomPresetFilter: undefined,
|
||||
showCustomPresetFilterModal: false,
|
||||
}
|
||||
},
|
||||
|
||||
@@ -982,7 +1006,10 @@ export default {
|
||||
},
|
||||
|
||||
filterPresets () {
|
||||
return this.options.filterPresets.filter(({ name, roles }) => name && this.isUserRoleMember(roles))
|
||||
return [
|
||||
...this.options.filterPresets.filter(({ name, roles }) => name && this.isUserRoleMember(roles)),
|
||||
...this.customPresetFilters,
|
||||
]
|
||||
},
|
||||
|
||||
authUserRoles () {
|
||||
@@ -1008,6 +1035,7 @@ export default {
|
||||
handler () {
|
||||
this.createEvents()
|
||||
this.getStorageRecordListFilter()
|
||||
this.getStorageRecordListFilterPreset()
|
||||
this.prepRecordList()
|
||||
this.refresh(true)
|
||||
},
|
||||
@@ -1064,12 +1092,24 @@ export default {
|
||||
onFilter (filter = []) {
|
||||
filter.forEach(f => {
|
||||
if (this.activeFilters.includes(f.name)) {
|
||||
this.filterPresets.find(p => p.name === f.name).filter.forEach((filterPreset) => {
|
||||
if (!isEqual(f.filter, filterPreset.filter)) {
|
||||
const filterIndex = this.activeFilters.indexOf(f.name)
|
||||
this.activeFilters.splice(filterIndex, 1)
|
||||
}
|
||||
})
|
||||
const filterPresets = this.filterPresets.find(p => p.name === f.name)
|
||||
|
||||
if (filterPresets) {
|
||||
filterPresets.filter.forEach((filterPreset) => {
|
||||
if (!isEqual(f.filter, filterPreset.filter)) {
|
||||
const filterIndex = this.activeFilters.indexOf(f.name)
|
||||
this.activeFilters.splice(filterIndex, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (f.filter.length === 1 && (!f.filter[0].value && !f.filter[0].name)) {
|
||||
const filterIndex = this.activeFilters.indexOf(f.name)
|
||||
this.activeFilters.splice(filterIndex, 1)
|
||||
} else {
|
||||
this.activeFilters.push(this.$t('recordList.customFilter'))
|
||||
f.name = this.$t('recordList.customFilter')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1078,6 +1118,15 @@ export default {
|
||||
this.refresh(true)
|
||||
},
|
||||
|
||||
onSaveFilterPreset (filter = []) {
|
||||
this.currentCustomPresetFilter = {
|
||||
filter,
|
||||
}
|
||||
|
||||
this.showCustomPresetFilterModal = true
|
||||
this.refresh(true)
|
||||
},
|
||||
|
||||
onUpdateFields (fields = []) {
|
||||
this.options.fields = [...fields]
|
||||
this.$emit('save-fields', this.options.fields)
|
||||
@@ -1597,6 +1646,7 @@ export default {
|
||||
removeItem(`record-list-filters-${this.uniqueID}`)
|
||||
} else {
|
||||
this.recordListFilter = currentFilters
|
||||
this.activeFilters = currentFilters.map(f => f.name)
|
||||
}
|
||||
} catch (e) {
|
||||
// Land here if the filter is corrupted
|
||||
@@ -1606,6 +1656,21 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
getStorageRecordListFilterPreset () {
|
||||
try {
|
||||
// Get record list filters from localStorage
|
||||
const currentFilterPresets = getItem(`record-list-preset-${this.uniqueID}`)
|
||||
|
||||
// Set the custom preset filters
|
||||
this.customPresetFilters = currentFilterPresets
|
||||
} catch (e) {
|
||||
// Land here if the filter is corrupted
|
||||
console.warn(this.$t('notification:record-list.corrupted-filter'))
|
||||
// Remove filter from the local storage
|
||||
removeItem(`record-list-filters-${this.uniqueID}`)
|
||||
}
|
||||
},
|
||||
|
||||
setStorageRecordListFilter () {
|
||||
let currentListFilters = []
|
||||
|
||||
@@ -1615,7 +1680,23 @@ export default {
|
||||
currentListFilters = this.recordListFilter
|
||||
setItem(`record-list-filters-${this.uniqueID}`, currentListFilters)
|
||||
} catch (e) {
|
||||
console.warning(this.$t('notification:record-list.corrupted-filter'))
|
||||
console.warn(this.$t('notification:record-list.corrupted-filter'))
|
||||
}
|
||||
},
|
||||
|
||||
setStorageRecordListFilterPreset ({ name }) {
|
||||
this.showCustomPresetFilterModal = false
|
||||
|
||||
const currentListFilters = [...this.customPresetFilters]
|
||||
currentListFilters.push({ ...this.currentCustomPresetFilter, name })
|
||||
|
||||
this.customPresetFilters = currentListFilters
|
||||
this.updateFilter(this.currentCustomPresetFilter.filter, name)
|
||||
|
||||
try {
|
||||
setItem(`record-list-preset-${this.uniqueID}`, currentListFilters)
|
||||
} catch (e) {
|
||||
console.warn(this.$t('notification:record-list.corrupted-filter'))
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1714,7 +1795,7 @@ export default {
|
||||
return !expressions.value
|
||||
},
|
||||
|
||||
updateFilter (filter, name) {
|
||||
updateFilter (filter = [], name) {
|
||||
const lastFilterIdx = this.recordListFilter.length - 1
|
||||
filter = filter.map((filter) => ({ ...filter, name }))
|
||||
|
||||
@@ -1800,4 +1881,10 @@ td:hover .inline-actions {
|
||||
font-family: $font-regular !important;
|
||||
}
|
||||
}
|
||||
|
||||
.list-style-none {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -347,6 +347,21 @@
|
||||
{{ $t('recordList.filter.addFilter') }}
|
||||
</b-button>
|
||||
</b-form-group>
|
||||
|
||||
<b-row class="mb-3">
|
||||
<b-col>
|
||||
<b-form-group
|
||||
:label="$t('recordList.record.setCustomFilterPresets')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<c-input-checkbox
|
||||
v-model="options.customFilterPresets"
|
||||
switch
|
||||
:labels="checkboxLabel"
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-modal
|
||||
:visible="showModal"
|
||||
:title="$t('recordList.filterPresets.saveFilterAsPreset')"
|
||||
body-class="p-0"
|
||||
footer-class="d-flex w-100 align-items-center justify-content-between"
|
||||
centered
|
||||
@hide="onModalHide"
|
||||
>
|
||||
<b-card
|
||||
class="pt-0"
|
||||
>
|
||||
<b-form-group
|
||||
:label="$t('recordList.filterPresets.filterName')"
|
||||
label-class="primary"
|
||||
>
|
||||
<b-form-input
|
||||
v-model="filterName"
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-card>
|
||||
|
||||
<template #modal-footer>
|
||||
<b-button
|
||||
variant="light"
|
||||
@click="onModalHide"
|
||||
>
|
||||
{{ $t('general.label.cancel') }}
|
||||
</b-button>
|
||||
|
||||
<div>
|
||||
<b-button
|
||||
variant="primary"
|
||||
:disabled="!filterName"
|
||||
@click="onSave"
|
||||
>
|
||||
{{ $t('general.label.save') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</template>
|
||||
</b-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
i18nOptions: {
|
||||
namespaces: 'block',
|
||||
},
|
||||
|
||||
name: 'CustomFilterPreset',
|
||||
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
showModal: false,
|
||||
filterName: '',
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
visible: {
|
||||
immediate: true,
|
||||
handler (val) {
|
||||
this.showModal = val
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onModalHide () {
|
||||
this.showModal = false
|
||||
this.filterName = ''
|
||||
this.$emit('close')
|
||||
},
|
||||
|
||||
onSave () {
|
||||
this.$emit('save', {
|
||||
name: this.filterName,
|
||||
})
|
||||
|
||||
this.onModalHide()
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.position-initial {
|
||||
position: initial;
|
||||
}
|
||||
</style>
|
||||
@@ -40,6 +40,7 @@ interface Options {
|
||||
fullPageNavigation: boolean;
|
||||
showTotalCount: boolean;
|
||||
showDeletedRecordsOption: boolean;
|
||||
customFilterPresets: boolean;
|
||||
refreshRate: number;
|
||||
showRefresh: boolean;
|
||||
|
||||
@@ -97,6 +98,7 @@ const defaults: Readonly<Options> = Object.freeze({
|
||||
fullPageNavigation: false,
|
||||
showTotalCount: false,
|
||||
showDeletedRecordsOption: false,
|
||||
customFilterPresets: false,
|
||||
|
||||
editable: false,
|
||||
draggable: false,
|
||||
@@ -164,6 +166,7 @@ export class PageBlockRecordList extends PageBlock {
|
||||
'fullPageNavigation',
|
||||
'showTotalCount',
|
||||
'showDeletedRecordsOption',
|
||||
'customFilterPresets',
|
||||
'hideSorting',
|
||||
'allowExport',
|
||||
'selectable',
|
||||
|
||||
@@ -264,6 +264,10 @@ record:
|
||||
recordList:
|
||||
addRecord: Add
|
||||
cancelSelection: Cancel
|
||||
customFilter: Custom filter
|
||||
filterPresets:
|
||||
filterName: Filter name
|
||||
saveFilterAsPreset: Save filter as preset
|
||||
inlineEdit:
|
||||
enabled: Inline value editing enabled
|
||||
button:
|
||||
@@ -321,6 +325,7 @@ recordList:
|
||||
addField: Add new filter field
|
||||
addFilter: + Add filter
|
||||
byValue: Filter records based on field value
|
||||
addFilterToPreset: Save as preset
|
||||
conditions:
|
||||
and: AND
|
||||
or: OR
|
||||
@@ -455,6 +460,7 @@ recordList:
|
||||
presortPlaceholder: field1 DESC, field2 ASC
|
||||
showTotalCount: Show total record count
|
||||
showDeletedRecordsOption: Show option to see deleted records
|
||||
setCustomFilterPresets: User will be able to set custom filter presets
|
||||
openInSameTab: Open record in the same tab
|
||||
openInNewTab: Open record in a new tab
|
||||
openInModal: Open record in a modal
|
||||
|
||||
Reference in New Issue
Block a user