Browse Source

feat: enable nested filter and some css corrections

re #2669

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2670/head
Pranav C 2 years ago
parent
commit
a0e5cd8e69
  1. 200
      packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue

200
packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue

@ -3,7 +3,7 @@
<div class="grid" @click.stop> <div class="grid" @click.stop>
<template v-for="(filter, i) in filters" dense> <template v-for="(filter, i) in filters" dense>
<template v-if="filter.status !== 'delete'"> <template v-if="filter.status !== 'delete'">
<div v-if="filter.is_group" :key="i" style="grid-column: span 4; padding: 6px" class="elevation-4"> <div v-if="filter.is_group" :key="i" style="grid-column: span 5; padding: 6px" class="elevation-4">
<div class="d-flex" style="gap: 6px; padding: 0 6px"> <div class="d-flex" style="gap: 6px; padding: 0 6px">
<v-icon <v-icon
v-if="!filter.readOnly" v-if="!filter.readOnly"
@ -58,7 +58,7 @@
mdi-close-box mdi-close-box
</v-icon> </v-icon>
<span v-else :key="i + '_1'" /> <span v-else :key="i + '_1'" />
<span v-if="!i" :key="i + '_2'" class="caption d-flex align-center">{{ $t('labels.where') }}</span> <span v-if="!i" :key="i + '_2'" class="caption d-flex align-center">{{ $t("labels.where") }}</span>
<v-select <v-select
v-else v-else
@ -95,7 +95,7 @@
class="flex-shrink-1 flex-grow-0 caption nc-filter-operation-select" class="flex-shrink-1 flex-grow-0 caption nc-filter-operation-select"
:items="filterComparisonOp(filter)" :items="filterComparisonOp(filter)"
:placeholder="$t('labels.operation')" :placeholder="$t('labels.operation')"
v-show="filter && filter.fk_column_id" v-if="filter && filter.fk_column_id"
solo solo
flat flat
style="max-width: 120px" style="max-width: 120px"
@ -110,7 +110,8 @@
<span class="caption font-weight-regular">{{ item.text }}</span> <span class="caption font-weight-regular">{{ item.text }}</span>
</template> </template>
</v-select> </v-select>
<span v-if="['null', 'notnull', 'empty', 'notempty'].includes(filter.comparison_op)" :key="'span' + i" /> <span v-else :key="'span1' + i"></span>
<span v-if="['null', 'notnull', 'empty', 'notempty'].includes(filter.comparison_op)" :key="'span2' + i" />
<v-checkbox <v-checkbox
v-else-if="types[filter.field] === 'boolean'" v-else-if="types[filter.field] === 'boolean'"
:key="i + '_7'" :key="i + '_7'"
@ -120,10 +121,9 @@
@change="saveOrUpdate(filter, i)" @change="saveOrUpdate(filter, i)"
/> />
<v-text-field <v-text-field
v-else v-else-if="filter && filter.fk_column_id"
:key="i + '_7'" :key="i + '_7'"
v-model="filter.value" v-model="filter.value"
v-show="filter && filter.fk_column_id"
solo solo
flat flat
hide-details hide-details
@ -133,28 +133,34 @@
@click.stop @click.stop
@input="saveOrUpdate(filter, i)" @input="saveOrUpdate(filter, i)"
/> />
<span v-else :key="'span1' + i"></span>
</template> </template>
</template> </template>
</template> </template>
</div> </div>
<v-btn small class="elevation-0 grey--text my-3" @click.stop="addFilter"> <v-btn small class="elevation-0 grey--text my-3" @click.stop="addFilter">
<v-icon small color="grey"> mdi-plus </v-icon> <v-icon small color="grey"> mdi-plus</v-icon>
<!-- Add Filter --> <!-- Add Filter -->
{{ $t('activity.addFilter') }} {{ $t("activity.addFilter") }}
</v-btn>
<v-btn small class="elevation-0 grey--text my-3" @click.stop="addFilterGroup">
<v-icon small color="grey"> mdi-plus</v-icon>
Add Filter Group
<!-- todo: add i18n {{ $t('activity.addFilterGroup') }}-->
</v-btn> </v-btn>
<slot /> <slot />
</div> </div>
</template> </template>
<script> <script>
import { getUIDTIcon, UITypes } from '~/components/project/spreadsheet/helpers/uiTypes'; import { getUIDTIcon, UITypes } from "~/components/project/spreadsheet/helpers/uiTypes";
import FieldListAutoCompleteDropdown from '~/components/project/spreadsheet/components/FieldListAutoCompleteDropdown'; import FieldListAutoCompleteDropdown from "~/components/project/spreadsheet/components/FieldListAutoCompleteDropdown";
export default { export default {
name: 'ColumnFilter', name: "ColumnFilter",
components: { components: {
FieldListAutoCompleteDropdown, FieldListAutoCompleteDropdown
}, },
props: { props: {
fieldList: [Array], fieldList: [Array],
@ -164,77 +170,77 @@ export default {
viewId: String, viewId: String,
shared: Boolean, shared: Boolean,
webHook: Boolean, webHook: Boolean,
hookId: String, hookId: String
}, },
data: () => ({ data: () => ({
filters: [], filters: [],
opList: [ opList: [
'is equal', "is equal",
'is not equal', "is not equal",
'is like', "is like",
'is not like', "is not like",
// 'is empty', 'is not empty', // 'is empty', 'is not empty',
'is null', "is null",
'is not null', "is not null",
'>', ">",
'<', "<",
'>=', ">=",
'<=', "<="
], ],
comparisonOp: [ comparisonOp: [
{ {
text: 'is equal', text: "is equal",
value: 'eq', value: "eq"
}, },
{ {
text: 'is not equal', text: "is not equal",
value: 'neq', value: "neq"
}, },
{ {
text: 'is like', text: "is like",
value: 'like', value: "like"
}, },
{ {
text: 'is not like', text: "is not like",
value: 'nlike', value: "nlike"
}, },
{ {
text: 'is empty', text: "is empty",
value: 'empty', value: "empty",
ignoreVal: true, ignoreVal: true
}, },
{ {
text: 'is not empty', text: "is not empty",
value: 'notempty', value: "notempty",
ignoreVal: true, ignoreVal: true
}, },
{ {
text: 'is null', text: "is null",
value: 'null', value: "null",
ignoreVal: true, ignoreVal: true
}, },
{ {
text: 'is not null', text: "is not null",
value: 'notnull', value: "notnull",
ignoreVal: true, ignoreVal: true
}, },
{ {
text: '>', text: ">",
value: 'gt', value: "gt"
}, },
{ {
text: '<', text: "<",
value: 'lt', value: "lt"
}, },
{ {
text: '>=', text: ">=",
value: 'gte', value: "gte"
}, },
{ {
text: '<=', text: "<=",
value: 'lte', value: "lte"
}, }
], ]
}), }),
computed: { computed: {
columnIcon() { columnIcon() {
@ -255,7 +261,7 @@ export default {
.filter(c => c && (!c.colOptions || !c.system)) .filter(c => c && (!c.colOptions || !c.system))
.map(c => ({ .map(c => ({
...c, ...c,
icon: getUIDTIcon(c.uidt), icon: getUIDTIcon(c.uidt)
})) }))
); );
}, },
@ -268,17 +274,17 @@ export default {
switch (col.uidt) { switch (col.uidt) {
case UITypes.Number: case UITypes.Number:
case UITypes.Decimal: case UITypes.Decimal:
obj[col.title] = obj[col.column_name] = 'number'; obj[col.title] = obj[col.column_name] = "number";
break; break;
case UITypes.Checkbox: case UITypes.Checkbox:
obj[col.title] = obj[col.column_name] = 'boolean'; obj[col.title] = obj[col.column_name] = "boolean";
break; break;
default: default:
break; break;
} }
return obj; return obj;
}, {}); }, {});
}, }
}, },
watch: { watch: {
async viewId(v) { async viewId(v) {
@ -288,10 +294,10 @@ export default {
}, },
filters: { filters: {
handler(v) { handler(v) {
this.$emit('input', v && v.filter(f => (f.fk_column_id && f.comparison_op) || f.is_group)); this.$emit("input", v && v.filter(f => (f.fk_column_id && f.comparison_op) || f.is_group));
},
deep: true,
}, },
deep: true
}
}, },
created() { created() {
this.loadFilter(); this.loadFilter();
@ -303,15 +309,15 @@ export default {
const uidt = this.columnsById[f.fk_column_id].uidt; const uidt = this.columnsById[f.fk_column_id].uidt;
if (uidt === UITypes.Lookup) { if (uidt === UITypes.Lookup) {
// TODO: handle it later // TODO: handle it later
return !['notempty', 'empty', 'notnull', 'null'].includes(op.value); return !["notempty", "empty", "notnull", "null"].includes(op.value);
} else if (uidt === UITypes.LinkToAnotherRecord) { } else if (uidt === UITypes.LinkToAnotherRecord) {
const type = this.columnsById[f.fk_column_id].colOptions.type; const type = this.columnsById[f.fk_column_id].colOptions.type;
if (type === 'hm' || type === 'mm') { if (type === "hm" || type === "mm") {
// exclude notnull & null // exclude notnull & null
return !['notnull', 'null'].includes(op.value); return !["notnull", "null"].includes(op.value);
} else if (type === 'bt') { } else if (type === "bt") {
// exclude notempty & empty // exclude notempty & empty
return !['notempty', 'empty'].includes(op.value); return !["notempty", "empty"].includes(op.value);
} }
} }
} }
@ -320,23 +326,23 @@ export default {
}, },
async applyChanges(nested = false, { hookId } = {}) { async applyChanges(nested = false, { hookId } = {}) {
for (const [i, filter] of Object.entries(this.filters)) { for (const [i, filter] of Object.entries(this.filters)) {
if (filter.status === 'delete') { if (filter.status === "delete") {
if (this.hookId || hookId) { if (this.hookId || hookId) {
await this.$api.dbTableFilter.delete(filter.id); await this.$api.dbTableFilter.delete(filter.id);
} else { } else {
await this.$api.dbTableFilter.delete(filter.id); await this.$api.dbTableFilter.delete(filter.id);
} }
} else if (filter.status === 'update') { } else if (filter.status === "update") {
if (filter.id) { if (filter.id) {
if (this.hookId || hookId) { if (this.hookId || hookId) {
await this.$api.dbTableFilter.update(filter.id, { await this.$api.dbTableFilter.update(filter.id, {
...filter, ...filter,
fk_parent_id: this.parentId, fk_parent_id: this.parentId
}); });
} else { } else {
await this.$api.dbTableFilter.update(filter.id, { await this.$api.dbTableFilter.update(filter.id, {
...filter, ...filter,
fk_parent_id: this.parentId, fk_parent_id: this.parentId
}); });
} }
} else if (this.hookId || hookId) { } else if (this.hookId || hookId) {
@ -345,7 +351,7 @@ export default {
i, i,
await this.$api.dbTableWebhookFilter.create(this.hookId || hookId, { await this.$api.dbTableWebhookFilter.create(this.hookId || hookId, {
...filter, ...filter,
fk_parent_id: this.parentId, fk_parent_id: this.parentId
}) })
); );
} else { } else {
@ -354,7 +360,7 @@ export default {
i, i,
await this.$api.dbTableFilter.create(this.viewId, { await this.$api.dbTableFilter.create(this.viewId, {
...filter, ...filter,
fk_parent_id: this.parentId, fk_parent_id: this.parentId
}) })
); );
} }
@ -367,17 +373,17 @@ export default {
} }
this.loadFilter(); this.loadFilter();
if (!nested) { if (!nested) {
this.$emit('updated'); this.$emit("updated");
} }
}, },
async loadFilter() { async loadFilter() {
let filters = []; let filters = [];
if (this.viewId && this._isUIAllowed('filterSync')) { if (this.viewId && this._isUIAllowed("filterSync")) {
filters = this.parentId filters = this.parentId
? await this.$api.dbTableFilter.childrenRead(this.parentId) ? await this.$api.dbTableFilter.childrenRead(this.parentId)
: await this.$api.dbTableFilter.read(this.viewId); : await this.$api.dbTableFilter.read(this.viewId);
} }
if (this.hookId && this._isUIAllowed('filterSync')) { if (this.hookId && this._isUIAllowed("filterSync")) {
filters = this.parentId filters = this.parentId
? await this.$api.dbTableFilter.childrenRead(this.parentId) ? await this.$api.dbTableFilter.childrenRead(this.parentId)
: await this.$api.dbTableWebhookFilter.read(this.hookId); : await this.$api.dbTableWebhookFilter.read(this.hookId);
@ -388,19 +394,19 @@ export default {
addFilter() { addFilter() {
this.filters.push({ this.filters.push({
fk_column_id: null, fk_column_id: null,
comparison_op: 'eq', comparison_op: "eq",
value: '', value: "",
status: 'update', status: "update",
logical_op: 'and', logical_op: "and"
}); });
this.filters = this.filters.slice(); this.filters = this.filters.slice();
this.$e('a:filter:add', { length: this.filters.length }); this.$e("a:filter:add", { length: this.filters.length });
}, },
addFilterGroup() { addFilterGroup() {
this.filters.push({ this.filters.push({
parentId: this.parentId, parentId: this.parentId,
is_group: true, is_group: true,
status: 'update', status: "update"
}); });
this.filters = this.filters.slice(); this.filters = this.filters.slice();
const index = this.filters.length - 1; const index = this.filters.length - 1;
@ -408,56 +414,56 @@ export default {
}, },
filterUpdateCondition(filter, i) { filterUpdateCondition(filter, i) {
this.saveOrUpdate(filter, i); this.saveOrUpdate(filter, i);
this.$e('a:filter:update', { this.$e("a:filter:update", {
logical: filter.logical_op, logical: filter.logical_op,
comparison: filter.comparison_op, comparison: filter.comparison_op
}); });
}, },
async saveOrUpdate(filter, i) { async saveOrUpdate(filter, i) {
if (this.shared || !this._isUIAllowed('filterSync')) { if (this.shared || !this._isUIAllowed("filterSync")) {
// this.$emit('input', this.filters.filter(f => f.fk_column_id && f.comparison_op)) // this.$emit('input', this.filters.filter(f => f.fk_column_id && f.comparison_op))
this.$emit('updated'); this.$emit("updated");
} else if (!this.autoApply) { } else if (!this.autoApply) {
filter.status = 'update'; filter.status = "update";
} else if (filter.id) { } else if (filter.id) {
await this.$api.dbTableFilter.update(filter.id, { await this.$api.dbTableFilter.update(filter.id, {
...filter, ...filter,
fk_parent_id: this.parentId, fk_parent_id: this.parentId
}); });
this.$emit('updated'); this.$emit("updated");
} else { } else {
this.$set( this.$set(
this.filters, this.filters,
i, i,
await this.$api.dbTableFilter.create(this.viewId, { await this.$api.dbTableFilter.create(this.viewId, {
...filter, ...filter,
fk_parent_id: this.parentId, fk_parent_id: this.parentId
}) })
); );
this.$emit('updated'); this.$emit("updated");
} }
}, },
async deleteFilter(filter, i) { async deleteFilter(filter, i) {
if (this.shared || !this._isUIAllowed('filterSync')) { if (this.shared || !this._isUIAllowed("filterSync")) {
this.filters.splice(i, 1); this.filters.splice(i, 1);
this.$emit('updated'); this.$emit("updated");
} else if (filter.id) { } else if (filter.id) {
if (!this.autoApply) { if (!this.autoApply) {
this.$set(filter, 'status', 'delete'); this.$set(filter, "status", "delete");
} else { } else {
await this.$api.dbTableFilter.delete(filter.id); await this.$api.dbTableFilter.delete(filter.id);
await this.loadFilter(); await this.loadFilter();
this.$emit('updated'); this.$emit("updated");
} }
} else { } else {
this.filters.splice(i, 1); this.filters.splice(i, 1);
this.$emit('updated'); this.$emit("updated");
}
this.$e("a:filter:delete");
}
} }
this.$e('a:filter:delete');
},
},
}; };
</script> </script>

Loading…
Cancel
Save