Browse Source

feat: undo/redo filters (WIP)

Signed-off-by: mertmit <mertmit99@gmail.com>
pull/5332/head
mertmit 1 year ago
parent
commit
a104fcf7fd
  1. 4
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue
  2. 156
      packages/nc-gui/composables/useViewFilters.ts

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

@ -364,7 +364,7 @@ defineExpose({
</div>
<div class="flex gap-2 mb-2 mt-4">
<a-button class="elevation-0 text-capitalize" type="primary" ghost @click.stop="addFilter">
<a-button class="elevation-0 text-capitalize" type="primary" ghost @click.stop="addFilter()">
<div class="flex items-center gap-1">
<component :is="iconMap.plus" />
<!-- Add Filter -->
@ -372,7 +372,7 @@ defineExpose({
</div>
</a-button>
<a-button v-if="!webHook" class="text-capitalize !text-gray-500" @click.stop="addFilterGroup">
<a-button v-if="!webHook" class="text-capitalize !text-gray-500" @click.stop="addFilterGroup()">
<div class="flex items-center gap-1">
<!-- Add Filter Group -->
<component :is="iconMap.plus" />

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

@ -20,7 +20,7 @@ import {
watch,
} from '#imports'
import { TabMetaInj } from '~/context'
import type { Filter, TabItem } from '~/lib'
import type { Filter, TabItem, UndoRedoAction } from '~/lib'
export function useViewFilters(
view: Ref<ViewType | undefined>,
@ -46,6 +46,8 @@ export function useViewFilters(
const { metas } = useMetas()
const { addUndo, clone } = useUndoRedo()
const _filters = ref<Filter[]>([])
const nestedMode = computed(() => isPublic.value || !isUIAllowed('filterSync') || !isUIAllowed('filterChildrenRead'))
@ -107,6 +109,19 @@ export function useViewFilters(
}, {})
})
const lastFilters = ref<Filter[]>([])
watchOnce(filters, (filters: Filter[]) => {
lastFilters.value = clone(filters)
})
// get delta between two objects and return the changed fields (value is from b)
const getFieldDelta = (a: any, b: any) => {
return Object.entries(b)
.filter(([key, val]) => a[key] !== val && key in a)
.reduce((a, [key, v]) => ({ ...a, [key]: v }), {})
}
const isComparisonOpAllowed = (
filter: FilterType,
compOp: {
@ -230,39 +245,39 @@ export function useViewFilters(
}
}
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
// no splice is required here
} 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))
}
const saveOrUpdate = async (filter: Filter, i: number, force = false, undo = false) => {
if (!view.value) return
if (!undo) {
const lastFilter = lastFilters.value[i]
if (lastFilter) {
const delta = clone(getFieldDelta(filter, lastFilter))
if (Object.keys(delta).length > 0) {
addUndo({
undo: {
fn: (prop: string, data: any) => {
const f = filters.value[i]
if (f) {
f[prop as keyof Filter] = data
saveOrUpdate(f, i, force, true)
}
},
args: [Object.keys(delta)[0], Object.values(delta)[0]],
},
redo: {
fn: (prop: string, data: any) => {
const f = filters.value[i]
if (f) {
f[prop as keyof Filter] = data
saveOrUpdate(f, i, force, true)
}
},
args: [Object.keys(delta)[0], filter[Object.keys(delta)[0] as keyof Filter]],
},
})
}
// if not synced yet remove it from array
} else {
filters.value.splice(i, 1)
}
$e('a:filter:delete', { length: nonDeletedFilters.value.length })
}
}
const saveOrUpdate = async (filter: Filter, i: number, force = false) => {
if (!view.value) return
try {
if (nestedMode.value) {
@ -270,7 +285,7 @@ export function useViewFilters(
filters.value = [...filters.value]
} else if (!autoApply?.value && !force) {
filter.status = filter.id ? 'update' : 'create'
} else if (filter.id) {
} else if (filter.id && filter.status !== 'create') {
await $api.dbTableFilter.update(filter.id, {
...filter,
fk_parent_id: parentId,
@ -290,13 +305,86 @@ export function useViewFilters(
message.error(await extractSdkResponseErrorMsg(e))
}
lastFilters.value = clone(filters.value)
reloadData?.()
}
const deleteFilter = async (filter: Filter, i: number, undo = false) => {
if (!undo && !filter.is_group) {
addUndo({
undo: {
fn: async (fl: Filter) => {
fl.status = 'create'
filters.value.splice(i, 0, fl)
await saveOrUpdate(fl, i, false, true)
},
args: [clone(filter)],
},
redo: {
fn: async (index: number) => {
await deleteFilter(filters.value[index], index, true)
},
args: [i],
},
})
}
// 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
// no splice is required here
} 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', { length: nonDeletedFilters.value.length })
}
}
const saveOrUpdateDebounced = useDebounceFn(saveOrUpdate, 500)
const addFilter = () => {
const addFilter = async (undo = false) => {
filters.value.push(placeholderFilter())
if (!undo) {
addUndo({
undo: {
fn: async function undo(this: UndoRedoAction, i: number) {
this.redo.args = [i, clone(filters.value[i])]
await deleteFilter(filters.value[i], i, true)
},
args: [filters.value.length - 1],
},
redo: {
fn: async (i: number, fl: Filter) => {
fl.status = 'create'
filters.value.splice(i, 0, fl)
await saveOrUpdate(fl, i, false, true)
},
args: [],
},
})
}
lastFilters.value = clone(filters.value)
$e('a:filter:add', { length: filters.value.length })
}
@ -317,6 +405,8 @@ export function useViewFilters(
await saveOrUpdate(filters.value[index], index, true)
lastFilters.value = clone(filters.value)
$e('a:filter:add', { length: filters.value.length, group: true })
}

Loading…
Cancel
Save