Browse Source

feat(gui-v2): integrate search with grid view

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2860/head
Pranav C 2 years ago
parent
commit
bd6fa6ff73
  1. 5
      packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilter.vue
  2. 23
      packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue
  3. 31
      packages/nc-gui-v2/components/smartsheet-toolbar/SearchData.vue
  4. 4
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  5. 23
      packages/nc-gui-v2/composables/useSmartsheetStore.ts
  6. 8
      packages/nc-gui-v2/composables/useViewData.ts

5
packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilter.vue

@ -99,13 +99,14 @@ const applyChanges = async () => {
for (const nestedFilter of nestedFilters?.value || []) { for (const nestedFilter of nestedFilters?.value || []) {
if (nestedFilter.parentId) { if (nestedFilter.parentId) {
await nestedFilter.applyChanges(true); await nestedFilter.applyChanges(true)
} }
} }
} }
defineExpose({ defineExpose({
applyChanges, parentId applyChanges,
parentId,
}) })
</script> </script>

23
packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue

@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
// todo: move to persisted state // todo: move to persisted state
import type ColumnFilter from './ColumnFilter.vue'
import { useState } from '#app' import { useState } from '#app'
import { IsLockedInj } from '~/context' import { IsLockedInj } from '~/context'
import MdiFilterIcon from '~icons/mdi/filter-outline' import MdiFilterIcon from '~icons/mdi/filter-outline'
import MdiMenuDownIcon from '~icons/mdi/menu-down' import MdiMenuDownIcon from '~icons/mdi/menu-down'
import ColumnFilter from './ColumnFilter.vue'
const autoApplyFilter = useState('autoApplyFilter', () => false) const autoApplyFilter = useState('autoApplyFilter', () => false)
const isLocked = inject(IsLockedInj) const isLocked = inject(IsLockedInj)
@ -35,25 +35,22 @@ const applyChanges = async () => {
</a-button> </a-button>
</div> </div>
<template #overlay> <template #overlay>
<SmartsheetToolbarColumnFilter ref="filterComp" class="nc-table-toolbar-menu" @update:filters-length="filtersLength = $event" :auto-save="autosave" > <SmartsheetToolbarColumnFilter
<div class="d-flex align-end mt-2 min-h-[30px]" @click.stop> ref="filterComp"
<a-checkbox class="nc-table-toolbar-menu"
id="col-filter-checkbox" :auto-save="autosave"
v-model:checked="autosave" @update:filters-length="filtersLength = $event"
class="col-filter-checkbox"
hide-details
dense
> >
<div class="d-flex align-end mt-2 min-h-[30px]" @click.stop>
<a-checkbox id="col-filter-checkbox" v-model:checked="autosave" class="col-filter-checkbox" hide-details dense>
<span class="text-grey text-xs"> <span class="text-grey text-xs">
{{ $t('msg.info.filterAutoApply') }} {{ $t('msg.info.filterAutoApply') }}
<!-- Auto apply --> <!-- Auto apply -->
</span> </span>
</a-checkbox> </a-checkbox>
<div class="flex-1"/> <div class="flex-1" />
<a-button v-show="!autosave" size="small" class="text-xs ml-2" @click="applyChanges"> <a-button v-show="!autosave" size="small" class="text-xs ml-2" @click="applyChanges"> Apply changes </a-button>
Apply changes
</a-button>
</div> </div>
</SmartsheetToolbarColumnFilter> </SmartsheetToolbarColumnFilter>
</template> </template>

31
packages/nc-gui-v2/components/smartsheet-toolbar/SearchData.vue

@ -1,23 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { MetaInj } from '~/context' import { useProvideSmartsheetStore, useSmartsheetStoreOrThrow } from '~/composables/useSmartsheetStore'
import { MetaInj, ReloadViewDataHookInj, SearchFieldAndQueryCbkInj } from '~/context'
const { modelValue, field } = defineProps<{ const reloadData = inject(ReloadViewDataHookInj)
modelValue?: string const { search, meta } = useSmartsheetStoreOrThrow()
field?: any
}>()
const emit = defineEmits(['update:modelValue', 'update:field'])
const localValue = computed({
get: () => modelValue,
set: (val) => emit('update:modelValue', val),
})
const localField = computed({
get: () => field,
set: (val) => emit('update:field', val),
})
const meta = inject(MetaInj)
const columns = computed(() => const columns = computed(() =>
meta?.value?.columns?.map((c) => ({ meta?.value?.columns?.map((c) => ({
value: c.id, value: c.id,
@ -27,9 +14,15 @@ const columns = computed(() =>
</script> </script>
<template> <template>
<a-input v-model:value="localValue" size="small" class="max-w-[250px]" placeholder="Filter query"> <a-input
v-model:value="search.value"
size="small"
class="max-w-[250px]"
placeholder="Filter query"
@pressEnter="reloadData.trigger()"
>
<template #addonBefore> <template #addonBefore>
<a-select v-model:value="localField" :options="columns" style="width: 80px" class="!text-xs" size="small" /> <a-select v-model:value="search.field" :options="columns" style="width: 80px" class="!text-xs" size="small" />
</template> </template>
</a-input> </a-input>
</template> </template>

4
packages/nc-gui-v2/components/smartsheet/Grid.vue

@ -32,9 +32,11 @@ const isPublicView = false
const selected = reactive<{ row?: number | null; col?: number | null }>({}) const selected = reactive<{ row?: number | null; col?: number | null }>({})
const editEnabled = ref(false) const editEnabled = ref(false)
const { sqlUi } = useProject()
const { xWhere } = useSmartsheetStoreOrThrow()
const addColumnDropdown = ref(false) const addColumnDropdown = ref(false)
const { loadData, paginationData, formattedData: data, updateRowProperty, changePage } = useViewData(meta, view as any) const { loadData, paginationData, formattedData: data, updateRowProperty, changePage } = useViewData(meta, view as any, xWhere)
const { loadGridViewColumns, updateWidth, resizingColWidth, resizingCol } = useGridViewColumnWidth(view) const { loadGridViewColumns, updateWidth, resizingColWidth, resizingCol } = useGridViewColumnWidth(view)
onMounted(loadGridViewColumns) onMounted(loadGridViewColumns)

23
packages/nc-gui-v2/composables/useSmartsheetStore.ts

@ -1,15 +1,36 @@
import { computed } from '@vue/reactivity'
import { createInjectionState } from '@vueuse/core' import { createInjectionState } from '@vueuse/core'
import type { TableType, ViewType } from 'nocodb-sdk' import type { TableType, ViewType } from 'nocodb-sdk'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import { useNuxtApp } from '#app' import { useNuxtApp } from '#app'
import useProject from '~/composables/useProject'
const [useProvideSmartsheetStore, useSmartsheetStore] = createInjectionState((view: Ref<ViewType>, meta: Ref<TableType>) => { const [useProvideSmartsheetStore, useSmartsheetStore] = createInjectionState((view: Ref<ViewType>, meta: Ref<TableType>) => {
const { $api } = useNuxtApp() const { $api } = useNuxtApp()
const { sqlUi } = useProject()
// state // state
// todo: move to grid view store
const search = reactive({
field: '',
value: '',
})
// getters // getters
const isLocked = computed(() => view?.value?.lock_type === 'locked') const isLocked = computed(() => view?.value?.lock_type === 'locked')
const xWhere = computed(() => {
let where
const col = meta?.value?.columns?.find(({ id }) => id === search.field) || meta?.value?.columns?.find((v) => v.pv)
if (!col) return
if (!search.value.trim()) return
if (['text', 'string'].includes(sqlUi.value.getAbstractType(col)) && col.dt !== 'bigint') {
where = `(${col.title},like,%${search.value.trim()}%)`
} else {
where = `(${col.title},eq,${search.value.trim()})`
}
return where
})
// actions // actions
@ -18,6 +39,8 @@ const [useProvideSmartsheetStore, useSmartsheetStore] = createInjectionState((vi
meta, meta,
isLocked, isLocked,
$api, $api,
search,
xWhere,
} }
}) })

8
packages/nc-gui-v2/composables/useViewData.ts

@ -17,6 +17,7 @@ export function useViewData(
| Ref<(GridType | GalleryType | FormType) & { id: string }> | Ref<(GridType | GalleryType | FormType) & { id: string }>
| ComputedRef<(GridType | GalleryType | FormType) & { id: string }> | ComputedRef<(GridType | GalleryType | FormType) & { id: string }>
| undefined, | undefined,
where?: ComputedRef<string | undefined>,
) { ) {
const data = ref<Record<string, any>[]>() const data = ref<Record<string, any>[]>()
const formattedData = ref<{ row: Record<string, any>; oldRow: Record<string, any>; rowMeta?: any }[]>() const formattedData = ref<{ row: Record<string, any>; oldRow: Record<string, any>; rowMeta?: any }[]>()
@ -27,7 +28,10 @@ export function useViewData(
const loadData = async (params: Parameters<Api<any>['dbViewRow']['list']>[4] = {}) => { const loadData = async (params: Parameters<Api<any>['dbViewRow']['list']>[4] = {}) => {
if (!project?.value?.id || !meta?.value?.id || !viewMeta?.value?.id) return if (!project?.value?.id || !meta?.value?.id || !viewMeta?.value?.id) return
const response = await $api.dbViewRow.list('noco', project.value.id, meta.value.id, viewMeta.value.id, params) const response = await $api.dbViewRow.list('noco', project.value.id, meta.value.id, viewMeta.value.id, {
...params,
where: where?.value,
})
data.value = response.list data.value = response.list
formattedData.value = formatData(response.list) formattedData.value = formatData(response.list)
paginationData.value = response.pageInfo paginationData.value = response.pageInfo
@ -97,7 +101,7 @@ export function useViewData(
const changePage = async (page: number) => { const changePage = async (page: number) => {
paginationData.value.page = page paginationData.value.page = page
await loadData({ offset: (page - 1) * (paginationData.value.pageSize || 25) } as any) await loadData({ offset: (page - 1) * (paginationData.value.pageSize || 25), where: where?.value } as any)
} }
return { data, loadData, paginationData, formattedData, insertRow, updateRowProperty, changePage } return { data, loadData, paginationData, formattedData, insertRow, updateRowProperty, changePage }

Loading…
Cancel
Save