|
|
@ -1,16 +1,74 @@ |
|
|
|
<script setup lang="ts"> |
|
|
|
<script setup lang="ts"> |
|
|
|
import { inject } from 'vue' |
|
|
|
import { UITypes } from 'nocodb-sdk' |
|
|
|
import { ActiveViewInj, MetaInj } from '~/components' |
|
|
|
import FieldListAutoCompleteDropdown from './FieldListAutoCompleteDropdown.vue' |
|
|
|
|
|
|
|
import { useNuxtApp } from '#app' |
|
|
|
|
|
|
|
import { inject } from '#imports' |
|
|
|
|
|
|
|
import { comparisonOp } from '~/utils/filterUtils' |
|
|
|
|
|
|
|
import { ActiveViewInj, MetaInj, ReloadViewDataHookInj } from '~/components' |
|
|
|
import useViewFilters from '~/composables/useViewFilters' |
|
|
|
import useViewFilters from '~/composables/useViewFilters' |
|
|
|
import { comparisonOp } from '~/utils/comparisonOp' |
|
|
|
import MdiDeleteIcon from '~icons/mdi/close-box' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { nested = false, parentId } = defineProps<{ nested?: boolean; parentId?: string }>() |
|
|
|
|
|
|
|
|
|
|
|
const meta = inject(MetaInj) |
|
|
|
const meta = inject(MetaInj) |
|
|
|
const activeView = inject(ActiveViewInj) |
|
|
|
const activeView = inject(ActiveViewInj) |
|
|
|
|
|
|
|
const reloadDataHook = inject(ReloadViewDataHookInj) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { $e } = useNuxtApp() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { filters, deleteFilter, saveOrUpdate, loadFilters, addFilter } = useViewFilters(activeView, parentId, () => { |
|
|
|
|
|
|
|
reloadDataHook?.trigger() |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const filterUpdateCondition = (filter, i) => { |
|
|
|
|
|
|
|
saveOrUpdate(filter, i) |
|
|
|
|
|
|
|
$e('a:filter:update', { |
|
|
|
|
|
|
|
logical: filter.logical_op, |
|
|
|
|
|
|
|
comparison: filter.comparison_op, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const { filters, deleteFilter, saveOrUpdate } = useViewFilters(activeView) |
|
|
|
// todo |
|
|
|
|
|
|
|
// const filterComparisonOp = (f) => |
|
|
|
|
|
|
|
// comparisonOp.filter((op) => { |
|
|
|
|
|
|
|
// // if ( |
|
|
|
|
|
|
|
// // f && |
|
|
|
|
|
|
|
// // f.fk_column_id && |
|
|
|
|
|
|
|
// // this.columnsById[f.fk_column_id] && |
|
|
|
|
|
|
|
// // this.columnsById[f.fk_column_id].uidt === UITypes.LinkToAnotherRecord && |
|
|
|
|
|
|
|
// // this.columnsById[f.fk_column_id].uidt === UITypes.Lookup |
|
|
|
|
|
|
|
// // ) { |
|
|
|
|
|
|
|
// // return !['notempty', 'empty', 'notnull', 'null'].includes(op.value) |
|
|
|
|
|
|
|
// // } |
|
|
|
|
|
|
|
// return true |
|
|
|
|
|
|
|
// }) |
|
|
|
|
|
|
|
|
|
|
|
const filterUpdateCondition = (filter, i) => {} |
|
|
|
const columns = computed(() => meta?.value?.columns) |
|
|
|
const filterComparisonOp = (filter) => {} |
|
|
|
const types = computed(() => { |
|
|
|
|
|
|
|
if (!meta?.value?.columns?.length) { |
|
|
|
|
|
|
|
return {} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return meta?.value?.columns?.reduce((obj: any, col: any) => { |
|
|
|
|
|
|
|
switch (col.uidt) { |
|
|
|
|
|
|
|
case UITypes.Number: |
|
|
|
|
|
|
|
case UITypes.Decimal: |
|
|
|
|
|
|
|
obj[col.title] = obj[col.column_name] = 'number' |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
case UITypes.Checkbox: |
|
|
|
|
|
|
|
obj[col.title] = obj[col.column_name] = 'boolean' |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return obj |
|
|
|
|
|
|
|
}, {}) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
watch( |
|
|
|
|
|
|
|
() => activeView?.value?.id, |
|
|
|
|
|
|
|
(n, o) => { |
|
|
|
|
|
|
|
if (n !== o) loadFilters() |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ immediate: true }, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
/* import { UITypes, getUIDTIcon } from '~/components/project/spreadsheet/helpers/uiTypes' |
|
|
|
/* import { UITypes, getUIDTIcon } from '~/components/project/spreadsheet/helpers/uiTypes' |
|
|
|
import FieldListAutoCompleteDropdown from '~/components/project/spreadsheet/components/FieldListAutoCompleteDropdown' |
|
|
|
import FieldListAutoCompleteDropdown from '~/components/project/spreadsheet/components/FieldListAutoCompleteDropdown' |
|
|
@ -319,9 +377,9 @@ export default { |
|
|
|
</script> |
|
|
|
</script> |
|
|
|
|
|
|
|
|
|
|
|
<template> |
|
|
|
<template> |
|
|
|
<div class="backgroundColor pa-2 menu-filter-dropdown" :style="{ width: nested ? '100%' : '530px' }"> |
|
|
|
<div class="backgroundColor pa-2 menu-filter-dropdown bg-background" :style="{ width: nested ? '100%' : '630px' }"> |
|
|
|
<div class="grid" @click.stop> |
|
|
|
<div v-if="filters && filters.length" class="grid" @click.stop> |
|
|
|
<template v-for="(filter, i) in filters"> |
|
|
|
<template v-for="(filter, i) in filters" :key="filter.id || i"> |
|
|
|
<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 4; 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"> |
|
|
@ -339,17 +397,16 @@ export default { |
|
|
|
v-model="filter.logical_op" |
|
|
|
v-model="filter.logical_op" |
|
|
|
class="flex-shrink-1 flex-grow-0 elevation-0 caption" |
|
|
|
class="flex-shrink-1 flex-grow-0 elevation-0 caption" |
|
|
|
:items="['and', 'or']" |
|
|
|
:items="['and', 'or']" |
|
|
|
solo |
|
|
|
density="compact" |
|
|
|
flat |
|
|
|
variant="solo" |
|
|
|
dense |
|
|
|
|
|
|
|
hide-details |
|
|
|
hide-details |
|
|
|
placeholder="Group op" |
|
|
|
placeholder="Group op" |
|
|
|
@click.stop |
|
|
|
@click.stop |
|
|
|
@change="saveOrUpdate(filter, i)" |
|
|
|
@change="saveOrUpdate(filter, i)" |
|
|
|
> |
|
|
|
> |
|
|
|
<template #item="{ item }"> |
|
|
|
<!-- <template #item="{ item }"> --> |
|
|
|
<span class="caption font-weight-regular">{{ item }}</span> |
|
|
|
<!-- <span class="caption font-weight-regular">{{ item }}</span> --> |
|
|
|
</template> |
|
|
|
<!-- </template> --> |
|
|
|
</v-select> |
|
|
|
</v-select> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<!-- <column-filter |
|
|
|
<!-- <column-filter |
|
|
@ -368,41 +425,47 @@ export default { |
|
|
|
/> --> |
|
|
|
/> --> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<template v-else> |
|
|
|
<template v-else> |
|
|
|
<v-icon |
|
|
|
<!-- <v-icon |
|
|
|
|
|
|
|
v-if="!filter.readOnly" |
|
|
|
|
|
|
|
:key="`${i}_3`" |
|
|
|
|
|
|
|
small |
|
|
|
|
|
|
|
class="nc-filter-item-remove-btn" |
|
|
|
|
|
|
|
@click.stop="deleteFilter(filter, i)" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
mdi-close-box |
|
|
|
|
|
|
|
</v-icon> --> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<MdiDeleteIcon |
|
|
|
v-if="!filter.readOnly" |
|
|
|
v-if="!filter.readOnly" |
|
|
|
:key="`${i}_3`" |
|
|
|
class="nc-filter-item-remove-btn text-grey" |
|
|
|
small |
|
|
|
|
|
|
|
class="nc-filter-item-remove-btn" |
|
|
|
|
|
|
|
@click.stop="deleteFilter(filter, i)" |
|
|
|
@click.stop="deleteFilter(filter, i)" |
|
|
|
> |
|
|
|
></MdiDeleteIcon> |
|
|
|
mdi-close-box |
|
|
|
<span v-else /> |
|
|
|
</v-icon> |
|
|
|
|
|
|
|
<span v-else :key="`${i}_1`" /> |
|
|
|
<span v-if="!i" :key="`${i}_2`" class="text-xs 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 |
|
|
|
:key="`${i}_4`" |
|
|
|
:key="`${i}_4`" |
|
|
|
v-model="filter.logical_op" |
|
|
|
v-model="filter.logical_op" |
|
|
|
class="flex-shrink-1 flex-grow-0 elevation-0 caption" |
|
|
|
class="w-full elevation-0 caption" |
|
|
|
:items="['and', 'or']" |
|
|
|
:items="['and', 'or']" |
|
|
|
solo |
|
|
|
density="compact" |
|
|
|
flat |
|
|
|
variant="solo" |
|
|
|
dense |
|
|
|
|
|
|
|
hide-details |
|
|
|
hide-details |
|
|
|
:disabled="filter.readOnly" |
|
|
|
:disabled="filter.readOnly" |
|
|
|
@click.stop |
|
|
|
@click.stop |
|
|
|
@change="filterUpdateCondition(filter, i)" |
|
|
|
@change="filterUpdateCondition(filter, i)" |
|
|
|
> |
|
|
|
/> |
|
|
|
<template #item="{ item }"> |
|
|
|
<!-- <template #item="{ item }"> |
|
|
|
<span class="caption font-weight-regular">{{ item }}</span> |
|
|
|
<span class="caption font-weight-regular">{{ item }}</span> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
</v-select> |
|
|
|
</v-select> --> |
|
|
|
|
|
|
|
|
|
|
|
<FieldListAutoCompleteDropdown |
|
|
|
<FieldListAutoCompleteDropdown |
|
|
|
:key="`${i}_6`" |
|
|
|
:key="`${i}_6`" |
|
|
|
v-model="filter.fk_column_id" |
|
|
|
v-model="filter.fk_column_id" |
|
|
|
class="caption nc-filter-field-select" |
|
|
|
class="caption text-sm nc-filter-field-select" |
|
|
|
:columns="columns" |
|
|
|
:columns="columns" |
|
|
|
:disabled="filter.readOnly" |
|
|
|
:disabled="filter.readOnly" |
|
|
|
@click.stop |
|
|
|
@click.stop |
|
|
@ -410,25 +473,26 @@ export default { |
|
|
|
/> |
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
<v-select |
|
|
|
<v-select |
|
|
|
:key="`k${i}`" |
|
|
|
|
|
|
|
v-model="filter.comparison_op" |
|
|
|
v-model="filter.comparison_op" |
|
|
|
class="flex-shrink-1 flex-grow-0 caption nc-filter-operation-select" |
|
|
|
class="caption nc-filter-operation-select text-sm" |
|
|
|
:items="filterComparisonOp(filter)" |
|
|
|
:items="comparisonOp.map((it) => it.value)" |
|
|
|
:placeholder="$t('labels.operation')" |
|
|
|
:placeholder="$t('labels.operation')" |
|
|
|
solo |
|
|
|
density="compact" |
|
|
|
flat |
|
|
|
variant="solo" |
|
|
|
style="max-width: 120px" |
|
|
|
|
|
|
|
dense |
|
|
|
|
|
|
|
:disabled="filter.readOnly" |
|
|
|
:disabled="filter.readOnly" |
|
|
|
hide-details |
|
|
|
hide-details |
|
|
|
item-value="value" |
|
|
|
|
|
|
|
@click.stop |
|
|
|
|
|
|
|
@change="filterUpdateCondition(filter, i)" |
|
|
|
@change="filterUpdateCondition(filter, i)" |
|
|
|
> |
|
|
|
/><!-- |
|
|
|
<template #item="{ item }"> |
|
|
|
todo: filter based on column type |
|
|
|
<span class="caption font-weight-regular">{{ item.text }}</span> |
|
|
|
|
|
|
|
</template> |
|
|
|
item-value="value" |
|
|
|
</v-select> |
|
|
|
item-text="text" |
|
|
|
|
|
|
|
:items="filterComparisonOp(filter)" --> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- <template #item="{ item }"> --> |
|
|
|
|
|
|
|
<!-- <span class="caption font-weight-regular">{{ item.text }}</span> --> |
|
|
|
|
|
|
|
<!-- </template> --> |
|
|
|
|
|
|
|
<!-- </v-select> --> |
|
|
|
<span v-if="['null', 'notnull', 'empty', 'notempty'].includes(filter.comparison_op)" :key="`span${i}`" /> |
|
|
|
<span v-if="['null', 'notnull', 'empty', 'notempty'].includes(filter.comparison_op)" :key="`span${i}`" /> |
|
|
|
<v-checkbox |
|
|
|
<v-checkbox |
|
|
|
v-else-if="types[filter.field] === 'boolean'" |
|
|
|
v-else-if="types[filter.field] === 'boolean'" |
|
|
@ -442,11 +506,10 @@ export default { |
|
|
|
v-else |
|
|
|
v-else |
|
|
|
:key="`${i}_7`" |
|
|
|
:key="`${i}_7`" |
|
|
|
v-model="filter.value" |
|
|
|
v-model="filter.value" |
|
|
|
solo |
|
|
|
density="compact" |
|
|
|
flat |
|
|
|
variant="solo" |
|
|
|
hide-details |
|
|
|
hide-details |
|
|
|
dense |
|
|
|
class="caption text-sm nc-filter-value-select" |
|
|
|
class="caption nc-filter-value-select" |
|
|
|
|
|
|
|
:disabled="filter.readOnly" |
|
|
|
:disabled="filter.readOnly" |
|
|
|
@click.stop |
|
|
|
@click.stop |
|
|
|
@input="saveOrUpdate(filter, i)" |
|
|
|
@input="saveOrUpdate(filter, i)" |
|
|
@ -455,6 +518,13 @@ export default { |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<v-btn small class="elevation-0 text-sm text-capitalize my-3" @click.stop="addFilter"> |
|
|
|
|
|
|
|
<!-- <v-icon small color="grey"> mdi-plus </v-icon> --> |
|
|
|
|
|
|
|
<!-- Add Filter --> |
|
|
|
|
|
|
|
{{ $t('activity.addFilter') }} |
|
|
|
|
|
|
|
</v-btn> |
|
|
|
|
|
|
|
<slot /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<!-- <div class="backgroundColor pa-2 menu-filter-dropdown" :style="{ width: nested ? '100%' : '530px' }"> |
|
|
|
<!-- <div class="backgroundColor pa-2 menu-filter-dropdown" :style="{ width: nested ? '100%' : '530px' }"> |
|
|
@ -604,10 +674,10 @@ export default { |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
|
|
<style scoped> |
|
|
|
<style scoped> |
|
|
|
/*.grid { |
|
|
|
.grid { |
|
|
|
display: grid; |
|
|
|
display: grid; |
|
|
|
grid-template-columns: 22px 80px auto auto auto; |
|
|
|
grid-template-columns: 30px 130px auto auto auto; |
|
|
|
column-gap: 6px; |
|
|
|
column-gap: 6px; |
|
|
|
row-gap: 6px; |
|
|
|
row-gap: 6px; |
|
|
|
}*/ |
|
|
|
} |
|
|
|
</style> |
|
|
|
</style> |
|
|
|