Browse Source

Merge pull request #8396 from nocodb/nc-filter-group-logic-op

Allow only same logical operation in filter group level
pull/8401/head
Pranav C 5 months ago committed by GitHub
parent
commit
6786d374ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 24
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue
  2. 8
      packages/nc-gui/composables/useViewFilters.ts
  3. 11
      packages/nocodb/src/helpers/webhookHelpers.ts
  4. 2
      tests/playwright/pages/Dashboard/WebhookForm/index.ts

24
packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue

@ -371,6 +371,23 @@ watch(
immediate: true, immediate: true,
}, },
) )
const isLogicalOpChangeAllowed = computed(() => {
return new Set(filters.value.slice(1).map((filter) => filter.logical_op)).size > 1
})
// when logical operation is updated, update all the siblings with the same logical operation only if it's in locked state
const onLogicalOpUpdate = async (filter: Filter, index: number) => {
if (index === 1 && filters.value.slice(2).every((siblingFilter) => siblingFilter.logical_op !== filter.logical_op)) {
await Promise.all(
filters.value.slice(2).map(async (siblingFilter, i) => {
siblingFilter.logical_op = filter.logical_op
await saveOrUpdate(siblingFilter, i + 2, false, false, true)
}),
)
}
await filterUpdateCondition(filter, index)
}
</script> </script>
<template> <template>
@ -403,6 +420,7 @@ watch(
class="min-w-20 capitalize" class="min-w-20 capitalize"
placeholder="Group op" placeholder="Group op"
dropdown-class-name="nc-dropdown-filter-logical-op-group" dropdown-class-name="nc-dropdown-filter-logical-op-group"
:disabled="i > 1 && !isLogicalOpChangeAllowed"
@click.stop @click.stop
@change="saveOrUpdate(filter, i)" @change="saveOrUpdate(filter, i)"
> >
@ -455,9 +473,9 @@ watch(
:dropdown-match-select-width="false" :dropdown-match-select-width="false"
class="h-full !min-w-20 !max-w-20 capitalize" class="h-full !min-w-20 !max-w-20 capitalize"
hide-details hide-details
:disabled="filter.readOnly" :disabled="filter.readOnly || (i > 1 && !isLogicalOpChangeAllowed)"
dropdown-class-name="nc-dropdown-filter-logical-op" dropdown-class-name="nc-dropdown-filter-logical-op"
@change="filterUpdateCondition(filter, i)" @change="onLogicalOpUpdate(filter, i)"
@click.stop @click.stop
> >
<a-select-option v-for="op of logicalOps" :key="op.value" :value="op.value"> <a-select-option v-for="op of logicalOps" :key="op.value" :value="op.value">
@ -601,7 +619,7 @@ watch(
</div> </div>
</NcButton> </NcButton>
<NcButton v-if="!webHook && nestedLevel < 5" type="text" size="small" @click.stop="addFilterGroup()"> <NcButton v-if="nestedLevel < 5" type="text" size="small" @click.stop="addFilterGroup()">
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<!-- Add Filter Group --> <!-- Add Filter Group -->
<component :is="iconMap.plus" /> <component :is="iconMap.plus" />

8
packages/nc-gui/composables/useViewFilters.ts

@ -198,13 +198,15 @@ export function useViewFilters(
} }
const placeholderFilter = (): Filter => { const placeholderFilter = (): Filter => {
const logicalOps = new Set(filters.value.slice(1).map((filter) => filter.logical_op))
return { return {
comparison_op: comparisonOpList(options.value?.[0].uidt as UITypes).filter((compOp) => comparison_op: comparisonOpList(options.value?.[0].uidt as UITypes).filter((compOp) =>
isComparisonOpAllowed({ fk_column_id: options.value?.[0].id }, compOp), isComparisonOpAllowed({ fk_column_id: options.value?.[0].id }, compOp),
)?.[0].value as FilterType['comparison_op'], )?.[0].value as FilterType['comparison_op'],
value: '', value: '',
status: 'create', status: 'create',
logical_op: 'and', logical_op: logicalOps.size === 1 ? logicalOps.values().next().value :'and' ,
} }
} }
@ -307,7 +309,7 @@ export function useViewFilters(
} }
} }
const saveOrUpdate = async (filter: Filter, i: number, force = false, undo = false) => { const saveOrUpdate = async (filter: Filter, i: number, force = false, undo = false, skipDataReload = false) => {
if (!view.value) return if (!view.value) return
if (!undo) { if (!undo) {
@ -372,7 +374,7 @@ export function useViewFilters(
lastFilters.value = clone(filters.value) lastFilters.value = clone(filters.value)
if (!isWebhook) reloadData?.() if (!isWebhook && !skipDataReload) reloadData?.()
} }
function deleteFilterGroupFromAllFilters(filter: Filter) { function deleteFilterGroupFromAllFilters(filter: Filter) {

11
packages/nocodb/src/helpers/webhookHelpers.ts

@ -54,8 +54,15 @@ export async function validateCondition(
const column = await filter.getColumn(); const column = await filter.getColumn();
const field = column.title; const field = column.title;
let val = data[field]; let val = data[field];
if (filter.is_group) {
if ( res = await validateCondition(
filter.children || (await filter.getChildren()),
data,
{
client,
},
);
} else if (
[ [
UITypes.Date, UITypes.Date,
UITypes.DateTime, UITypes.DateTime,

2
tests/playwright/pages/Dashboard/WebhookForm/index.ts

@ -70,7 +70,7 @@ export class WebhookFormPage extends BasePage {
await this.get().locator(`.nc-check-box-hook-condition`).click(); await this.get().locator(`.nc-check-box-hook-condition`).click();
const modal = this.get().locator(`.menu-filter-dropdown`).last(); const modal = this.get().locator(`.menu-filter-dropdown`).last();
await modal.locator(`button:has-text("Add Filter")`).click(); await modal.locator(`button:has-text("Add Filter")`).first().click();
await modal.locator('.nc-filter-field-select').waitFor({ state: 'visible', timeout: 4000 }); await modal.locator('.nc-filter-field-select').waitFor({ state: 'visible', timeout: 4000 });
await modal.locator('.nc-filter-field-select').click(); await modal.locator('.nc-filter-field-select').click();

Loading…
Cancel
Save