import type { FilterType, ViewType } from 'nocodb-sdk' import type { ComputedRef, Ref } from 'vue' import { IsPublicInj, ReloadViewDataHookInj, computed, extractSdkResponseErrorMsg, inject, message, ref, useMetas, useNuxtApp, useUIPermission, watch, } from '#imports' import type { Filter } from '~/lib' export function useViewFilters( view: Ref, parentId?: string, autoApply?: ComputedRef, reloadData?: () => void, currentFilters?: Filter[], isNestedRoot?: boolean, ) { const reloadHook = inject(ReloadViewDataHookInj) const { nestedFilters } = useSmartsheetStoreOrThrow() const isPublic = inject(IsPublicInj, ref(false)) const { $api, $e } = useNuxtApp() const { isUIAllowed } = useUIPermission() const { metas } = useMetas() const _filters = ref([]) const nestedMode = computed(() => isPublic.value || !isUIAllowed('filterSync' || !isUIAllowed('filterChildrenRead'))) const filters = computed({ get: () => (nestedMode.value ? currentFilters! : _filters.value), set: (value: Filter[]) => { if (nestedMode.value) { currentFilters = value if (isNestedRoot) nestedFilters.value = value nestedFilters.value = [...nestedFilters.value] return } _filters.value = value }, }) const placeholderFilter: Filter = { comparison_op: 'eq', value: '', status: 'create', logical_op: 'and', } const loadFilters = async (hookId?: string) => { if (nestedMode.value) return try { if (hookId) { if (parentId) { filters.value = await $api.dbTableFilter.childrenRead(parentId) } else { // todo: return type is incorrect filters.value = (await $api.dbTableWebhookFilter.read(hookId!)) as unknown as Filter[] } } else { if (parentId) { filters.value = await $api.dbTableFilter.childrenRead(parentId) } else { filters.value = await $api.dbTableFilter.read(view.value!.id!) } } } catch (e: any) { console.log(e) message.error(await extractSdkResponseErrorMsg(e)) } } const sync = async (hookId?: string, _nested = false) => { try { for (const [i, filter] of Object.entries(filters.value)) { if (filter.status === 'delete') { await $api.dbTableFilter.delete(filter.id as string) } else if (filter.status === 'update') { await $api.dbTableFilter.update(filter.id as string, { ...filter, fk_parent_id: parentId, }) } else if (filter.status === 'create') { if (hookId) { filters.value[+i] = (await $api.dbTableWebhookFilter.create(hookId, { ...filter, fk_parent_id: parentId, })) as unknown as FilterType } else { filters.value[+i] = await $api.dbTableFilter.create(view?.value?.id as string, { ...filter, fk_parent_id: parentId, }) } } } reloadData?.() } catch (e: any) { console.log(e) message.error(await extractSdkResponseErrorMsg(e)) } } const deleteFilter = async (filter: Filter, i: number) => { // if shared or sync permission not allowed simply remove it from array if (nestedMode.value) { filters.value.splice(i, 1) filters.value = [...filters.value] reloadData?.() } else { if (filter.id) { // if auto-apply disabled mark it as disabled if (!autoApply?.value) { filter.status = 'delete' // if auto-apply enabled invoke delete api and remove from array } else { try { await $api.dbTableFilter.delete(filter.id) reloadData?.() filters.value.splice(i, 1) } catch (e: any) { console.log(e) message.error(await extractSdkResponseErrorMsg(e)) } } // if not synced yet remove it from array } else { filters.value.splice(i, 1) } $e('a:filter:delete') } } const saveOrUpdate = async (filter: Filter, i: number, force = false) => { if (!view.value) return try { if (nestedMode.value) { filters.value[i] = { ...filter } filters.value = [...filters.value] } else if (!autoApply?.value && !force) { filter.status = filter.id ? 'update' : 'create' } else if (filter.id) { await $api.dbTableFilter.update(filter.id, { ...filter, fk_parent_id: parentId, }) $e('a:filter:update', { logical: filter.logical_op, comparison: filter.comparison_op, }) } else { // todo: return type of dbTableFilter is void? filters.value[i] = await $api.dbTableFilter.create(view.value.id!, { ...filter, fk_parent_id: parentId, }) } reloadHook?.trigger() } catch (e: any) { console.log(e) message.error(await extractSdkResponseErrorMsg(e)) } reloadData?.() } const addFilter = () => { filters.value.push({ ...placeholderFilter }) $e('a:filter:add', { length: filters.value.length }) } const addFilterGroup = async () => { const child = { ...placeholderFilter } const placeHolderGroupFilter: Filter = { is_group: true, status: 'create', logical_op: 'and', } if (nestedMode.value) placeHolderGroupFilter.children = [child] filters.value.push(placeHolderGroupFilter) const index = filters.value.length - 1 await saveOrUpdate(filters.value[index], index, true) $e('a:filter:add', { length: filters.value.length, group: true }) } /** on column delete reload filters, identify by checking columns count */ watch( () => { if (!view?.value || !metas?.value?.[view?.value?.fk_model_id as string]) { return 0 } return metas?.value?.[view?.value?.fk_model_id as string]?.columns?.length || 0 }, async (nextColsLength, oldColsLength) => { if (nextColsLength < oldColsLength) await loadFilters() }, ) return { filters, loadFilters, sync, deleteFilter, saveOrUpdate, addFilter, addFilterGroup } }