Browse Source

fix(nc-gui): disable add filter from context menu if limit exceed

pull/8309/head
Ramesh Mane 5 months ago
parent
commit
61bab38907
  1. 43
      packages/nc-gui/components/smartsheet/header/Menu.vue
  2. 2
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilterMenu.vue
  3. 3
      packages/nc-gui/composables/useSmartsheetStore.ts
  4. 67
      packages/nc-gui/composables/useViewFilters.ts

43
packages/nc-gui/components/smartsheet/header/Menu.vue

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { ColumnReqType } from 'nocodb-sdk' import type { ColumnReqType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isLinksOrLTAR } from 'nocodb-sdk' import { PlanLimitTypes, RelationTypes, UITypes, isLinksOrLTAR } from 'nocodb-sdk'
import { computed } from 'vue' import { computed } from 'vue'
import { import {
ActiveViewInj, ActiveViewInj,
@ -28,7 +28,7 @@ const virtual = toRef(props, 'virtual')
const isOpen = useVModel(props, 'isOpen', emit) const isOpen = useVModel(props, 'isOpen', emit)
const { eventBus } = useSmartsheetStoreOrThrow() const { eventBus, allFilters } = useSmartsheetStoreOrThrow()
const column = inject(ColumnInj) const column = inject(ColumnInj)
@ -38,10 +38,12 @@ const meta = inject(MetaInj, ref())
const view = inject(ActiveViewInj, ref()) const view = inject(ActiveViewInj, ref())
const { insertSort } = useViewSorts(view, () => reloadDataHook?.trigger())
const isLocked = inject(IsLockedInj) const isLocked = inject(IsLockedInj)
const isPublic = inject(IsPublicInj, ref(false))
const { insertSort } = useViewSorts(view, () => reloadDataHook?.trigger())
const { $api, $e } = useNuxtApp() const { $api, $e } = useNuxtApp()
const { t } = useI18n() const { t } = useI18n()
@ -304,8 +306,12 @@ const isFilterSupported = computed(
!!(meta.value?.columns || []).find((f) => f.id === column?.value?.id && ![UITypes.QrCode, UITypes.Barcode].includes(f.uidt)), !!(meta.value?.columns || []).find((f) => f.id === column?.value?.id && ![UITypes.QrCode, UITypes.Barcode].includes(f.uidt)),
) )
// TODO: calculate filter limit const { getPlanLimit } = useWorkspace()
const isFilterLimitExceeded = computed(() => false)
const isFilterLimitExceeded = computed(
() =>
allFilters.value.filter((f) => !(f.is_group || f.status === 'delete')).length >= getPlanLimit(PlanLimitTypes.FILTER_LIMIT),
)
const isGroupedByThisField = computed(() => !!gridViewCols.value[column?.value?.id]?.group_by) const isGroupedByThisField = computed(() => !!gridViewCols.value[column?.value?.id]?.group_by)
@ -392,9 +398,20 @@ const filterOrGroupByThisField = (event: SmartsheetStoreEvents) => {
<a-divider v-if="!column?.pk" class="!my-0" /> <a-divider v-if="!column?.pk" class="!my-0" />
<template v-if="true"> <template v-if="true">
<NcTooltip :disabled="isFilterSupported"> <NcTooltip :disabled="isFilterSupported && !isFilterLimitExceeded">
<template #title> This field type doesn't support filtering </template> <template #title>
<NcMenuItem @click="filterOrGroupByThisField(SmartsheetStoreEvents.FILTER_ADD)" :disabled="!isFilterSupported"> {{
!isFilterSupported
? "This field type doesn't support filtering"
: isFilterLimitExceeded
? 'Filter by limit exceeded'
: ''
}}
</template>
<NcMenuItem
@click="filterOrGroupByThisField(SmartsheetStoreEvents.FILTER_ADD)"
:disabled="!isFilterSupported || isFilterLimitExceeded"
>
<div v-e="['a:field:add:filter']" class="nc-column-filter nc-header-menu-item"> <div v-e="['a:field:add:filter']" class="nc-column-filter nc-header-menu-item">
<component :is="iconMap.filter" class="text-gray-700" /> <component :is="iconMap.filter" class="text-gray-700" />
<!-- Filter by this field --> <!-- Filter by this field -->
@ -403,16 +420,18 @@ const filterOrGroupByThisField = (event: SmartsheetStoreEvents) => {
</NcMenuItem> </NcMenuItem>
</NcTooltip> </NcTooltip>
<NcTooltip :disabled="(isGroupBySupported && !isGroupByLimitExceeded) || isGroupedByThisField"> <NcTooltip
:disabled="(isGroupBySupported && !isGroupByLimitExceeded) || isGroupedByThisField || !(isEeUI && !isPublic)"
>
<template #title>{{ <template #title>{{
!isGroupBySupported !isGroupBySupported
? "This field type doesn't support grouping" ? "This field type doesn't support grouping"
: isGroupByLimitExceeded : isGroupByLimitExceeded
? 'Group by limit exceeded' ? 'Group by limit exceeded'
: 'ds' : ''
}}</template> }}</template>
<NcMenuItem <NcMenuItem
:disabled="(!isGroupBySupported || isGroupByLimitExceeded) && !isGroupedByThisField" :disabled="isEeUI && !isPublic && (!isGroupBySupported || isGroupByLimitExceeded) && !isGroupedByThisField"
@click=" @click="
filterOrGroupByThisField( filterOrGroupByThisField(
isGroupedByThisField ? SmartsheetStoreEvents.GROUP_BY_REMOVE : SmartsheetStoreEvents.GROUP_BY_ADD, isGroupedByThisField ? SmartsheetStoreEvents.GROUP_BY_REMOVE : SmartsheetStoreEvents.GROUP_BY_ADD,

2
packages/nc-gui/components/smartsheet/toolbar/ColumnFilterMenu.vue

@ -42,7 +42,7 @@ watch(
() => activeView?.value?.id, () => activeView?.value?.id,
async (viewId) => { async (viewId) => {
if (viewId) { if (viewId) {
await loadFilters() await loadFilters(undefined, false, true)
filtersLength.value = nonDeletedFilters.value.length || 0 filtersLength.value = nonDeletedFilters.value.length || 0
} }
}, },

3
packages/nc-gui/composables/useSmartsheetStore.ts

@ -58,6 +58,8 @@ const [useProvideSmartsheetStore, useSmartsheetStore] = useInjectionState(
const sorts = ref<SortType[]>(unref(initialSorts) ?? []) const sorts = ref<SortType[]>(unref(initialSorts) ?? [])
const nestedFilters = ref<FilterType[]>(unref(initialFilters) ?? []) const nestedFilters = ref<FilterType[]>(unref(initialFilters) ?? [])
const allFilters = ref<Filter[]>([])
watch( watch(
sorts, sorts,
() => { () => {
@ -97,6 +99,7 @@ const [useProvideSmartsheetStore, useSmartsheetStore] = useInjectionState(
isSqlView, isSqlView,
eventBus, eventBus,
sqlUi, sqlUi,
allFilters,
} }
}, },
'smartsheet-store', 'smartsheet-store',

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

@ -43,7 +43,7 @@ export function useViewFilters(
const reloadHook = inject(ReloadViewDataHookInj) const reloadHook = inject(ReloadViewDataHookInj)
const { nestedFilters } = useSmartsheetStoreOrThrow() const { nestedFilters, allFilters } = useSmartsheetStoreOrThrow()
const { baseMeta } = storeToRefs(useBase()) const { baseMeta } = storeToRefs(useBase())
@ -208,7 +208,35 @@ export function useViewFilters(
} }
} }
const loadFilters = async (hookId?: string, isWebhook = false) => { const loadAllChildFilters = async (filters: Filter[]) => {
// Array to store promises of child filter loading
const promises = []
// Array to store all child filters
const allChildFilters: Filter[] = []
// Iterate over all filters
for (const filter of filters) {
// Check if the filter is a group
if (filter.id && filter.is_group) {
// Load children filters from the backend
const childFilterPromise = $api.dbTableFilter.childrenRead(filter.id).then((response) => {
const childFilters = response.list as Filter[]
allChildFilters.push(...childFilters)
return loadAllChildFilters(childFilters)
})
promises.push(childFilterPromise)
}
}
// Wait for all promises to resolve
await Promise.all(promises)
// Push all child filters into the allFilters array
allFilters.value.push(...allChildFilters)
}
const loadFilters = async (hookId?: string, isWebhook = false, loadAllFilters = false) => {
if (!view.value?.id) return if (!view.value?.id) return
if (nestedMode.value) { if (nestedMode.value) {
@ -228,6 +256,10 @@ export function useViewFilters(
filters.value = (await $api.dbTableFilter.childrenRead(parentId)).list as Filter[] filters.value = (await $api.dbTableFilter.childrenRead(parentId)).list as Filter[]
} else { } else {
filters.value = (await $api.dbTableFilter.read(view.value!.id!)).list as Filter[] filters.value = (await $api.dbTableFilter.read(view.value!.id!)).list as Filter[]
if (loadAllFilters) {
allFilters.value = [...filters.value]
await loadAllChildFilters(allFilters.value)
}
} }
} }
} catch (e: any) { } catch (e: any) {
@ -241,6 +273,11 @@ export function useViewFilters(
for (const [i, filter] of Object.entries(filters.value)) { for (const [i, filter] of Object.entries(filters.value)) {
if (filter.status === 'delete') { if (filter.status === 'delete') {
await $api.dbTableFilter.delete(filter.id as string) await $api.dbTableFilter.delete(filter.id as string)
if (filter.is_group) {
deleteFilterGroupFromAllFilters(filter)
} else {
allFilters.value = allFilters.value.filter((f) => f.id !== filter.id)
}
} else if (filter.status === 'update') { } else if (filter.status === 'update') {
await $api.dbTableFilter.update(filter.id as string, { await $api.dbTableFilter.update(filter.id as string, {
...filter, ...filter,
@ -258,6 +295,8 @@ export function useViewFilters(
fk_parent_id: parentId, fk_parent_id: parentId,
}) })
} }
allFilters.value.push(filters.value[+i])
} }
} }
@ -323,6 +362,8 @@ export function useViewFilters(
...filter, ...filter,
fk_parent_id: parentId, fk_parent_id: parentId,
}) })
allFilters.value.push(filters.value[+i])
} }
} catch (e: any) { } catch (e: any) {
console.log(e) console.log(e)
@ -334,6 +375,21 @@ export function useViewFilters(
if (!isWebhook) reloadData?.() if (!isWebhook) reloadData?.()
} }
function deleteFilterGroupFromAllFilters(filter: Filter) {
// Find all child filters of the specified parentId
const childFilters = allFilters.value.filter((f) => f.fk_parent_id === filter.id)
// Recursively delete child filter of child filter
childFilters.forEach((childFilter) => {
if (childFilter.is_group) {
deleteFilterGroupFromAllFilters(childFilter)
}
})
// Remove the parent object and its children from the array
allFilters.value = allFilters.value.filter((f) => f.id !== filter.id && f.fk_parent_id !== filter.id)
}
const deleteFilter = async (filter: Filter, i: number, undo = false) => { const deleteFilter = async (filter: Filter, i: number, undo = false) => {
if (!undo && !filter.is_group) { if (!undo && !filter.is_group) {
addUndo({ addUndo({
@ -369,6 +425,7 @@ export function useViewFilters(
} else { } else {
try { try {
await $api.dbTableFilter.delete(filter.id) await $api.dbTableFilter.delete(filter.id)
if (!isWebhook) reloadData?.() if (!isWebhook) reloadData?.()
filters.value.splice(i, 1) filters.value.splice(i, 1)
} catch (e: any) { } catch (e: any) {
@ -382,6 +439,12 @@ export function useViewFilters(
} }
$e('a:filter:delete', { length: nonDeletedFilters.value.length }) $e('a:filter:delete', { length: nonDeletedFilters.value.length })
} }
if (filter.is_group) {
deleteFilterGroupFromAllFilters(filter)
} else {
allFilters.value = allFilters.value.filter((f) => f.id !== filter.id)
}
} }
const saveOrUpdateDebounced = useDebounceFn(saveOrUpdate, 500) const saveOrUpdateDebounced = useDebounceFn(saveOrUpdate, 500)

Loading…
Cancel
Save