Browse Source

Merge pull request #3370 from nocodb/feat/3261-tab-level-state

fix: tab level state
pull/4043/head
աɨռɢӄաօռɢ 2 years ago committed by GitHub
parent
commit
a0de3dc6bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      packages/nc-gui/components/cell/MultiSelect.vue
  2. 7
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue
  3. 2
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilterMenu.vue
  4. 8
      packages/nc-gui/components/tabs/Smartsheet.vue
  5. 4
      packages/nc-gui/composables/useTabs.ts
  6. 28
      packages/nc-gui/composables/useViewFilters.ts
  7. 15
      packages/nc-gui/composables/useViewSorts.ts
  8. 2
      packages/nc-gui/lib/types.ts

3
packages/nc-gui/components/cell/MultiSelect.vue

@ -1,8 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import tinycolor from 'tinycolor2' import tinycolor from 'tinycolor2'
import type { Select as AntSelect } from 'ant-design-vue' import type { Select as AntSelect } from 'ant-design-vue'
import { SelectOptionType } from 'nocodb-sdk' import type { SelectOptionType, SelectOptionsType } from 'nocodb-sdk'
import type { SelectOptionsType } from 'nocodb-sdk'
import { import {
ActiveCellInj, ActiveCellInj,
ColumnInj, ColumnInj,

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

@ -86,11 +86,13 @@ const types = computed(() => {
watch( watch(
() => activeView.value?.id, () => activeView.value?.id,
(n, o) => { (n, o) => {
if (n !== o && (hookId || !webHook)) loadFilters(hookId as string) // if nested no need to reload since it will get reloaded from parent
if (!nested && n !== o && (hookId || !webHook)) loadFilters(hookId as string)
}, },
{ immediate: true },
) )
loadFilters(hookId as string)
watch( watch(
() => nonDeletedFilters.value.length, () => nonDeletedFilters.value.length,
(length) => { (length) => {
@ -153,6 +155,7 @@ defineExpose({
<div class="col-span-5"> <div class="col-span-5">
<LazySmartsheetToolbarColumnFilter <LazySmartsheetToolbarColumnFilter
v-if="filter.id || filter.children" v-if="filter.id || filter.children"
:key="filter.id ?? i"
ref="localNestedFilters" ref="localNestedFilters"
v-model="filter.children" v-model="filter.children"
:parent-id="filter.id" :parent-id="filter.id"

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

@ -30,7 +30,7 @@ const { nestedFilters } = useSmartsheetStoreOrThrow()
// todo: avoid duplicate api call by keeping a filter store // todo: avoid duplicate api call by keeping a filter store
const { nonDeletedFilters, loadFilters } = useViewFilters( const { nonDeletedFilters, loadFilters } = useViewFilters(
activeView, activeView!,
undefined, undefined,
computed(() => true), computed(() => true),
() => false, () => false,

8
packages/nc-gui/components/tabs/Smartsheet.vue

@ -35,13 +35,13 @@ const fields = ref<ColumnType[]>([])
const meta = computed<TableType | undefined>(() => activeTab.value && metas.value[activeTab.value.id!]) const meta = computed<TableType | undefined>(() => activeTab.value && metas.value[activeTab.value.id!])
const reloadEventHook = createEventHook()
const { isGallery, isGrid, isForm, isKanban, isLocked } = useProvideSmartsheetStore(activeView, meta) const { isGallery, isGrid, isForm, isKanban, isLocked } = useProvideSmartsheetStore(activeView, meta)
const openNewRecordFormHook = createEventHook() const reloadEventHook = createEventHook<void | boolean>()
const reloadViewMetaEventHook = createEventHook<void | boolean>()
const reloadViewMetaEventHook = createEventHook() const openNewRecordFormHook = createEventHook<void>()
useProvideKanbanViewStore(meta, activeView) useProvideKanbanViewStore(meta, activeView)

4
packages/nc-gui/composables/useTabs.ts

@ -38,6 +38,8 @@ const [setup, use] = useInjectionState(() => {
let index = tabs.value.findIndex((t) => t.id === tab.id) let index = tabs.value.findIndex((t) => t.id === tab.id)
if (index === -1) { if (index === -1) {
tab.sortsState = tab.sortsState || new Map()
tab.filterState = tab.filterState || new Map()
tabs.value.push(tab) tabs.value.push(tab)
index = tabs.value.length - 1 index = tabs.value.length - 1
} }
@ -70,6 +72,8 @@ const [setup, use] = useInjectionState(() => {
const activeTab = computed(() => tabs.value?.[activeTabIndex.value]) const activeTab = computed(() => tabs.value?.[activeTabIndex.value])
const addTab = (tabMeta: TabItem) => { const addTab = (tabMeta: TabItem) => {
tabMeta.sortsState = tabMeta.sortsState || new Map()
tabMeta.filterState = tabMeta.filterState || new Map()
const tabIndex = tabs.value.findIndex((tab) => tab.id === tabMeta.id) const tabIndex = tabs.value.findIndex((tab) => tab.id === tabMeta.id)
// if tab already found make it active // if tab already found make it active
if (tabIndex > -1) { if (tabIndex > -1) {

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

@ -13,16 +13,19 @@ import {
useUIPermission, useUIPermission,
watch, watch,
} from '#imports' } from '#imports'
import type { Filter } from '~/lib' import { TabMetaInj } from '~/context'
import type { Filter, TabItem } from '~/lib'
export function useViewFilters( export function useViewFilters(
view: Ref<ViewType | undefined>, view: Ref<ViewType | undefined>,
parentId?: string, parentId?: string,
autoApply?: ComputedRef<boolean>, autoApply?: ComputedRef<boolean>,
reloadData?: () => void, reloadData?: () => void,
currentFilters?: Filter[], _currentFilters?: Filter[],
isNestedRoot?: boolean, isNestedRoot?: boolean,
) { ) {
let currentFilters = $ref(_currentFilters)
const reloadHook = inject(ReloadViewDataHookInj) const reloadHook = inject(ReloadViewDataHookInj)
const { nestedFilters } = useSmartsheetStoreOrThrow() const { nestedFilters } = useSmartsheetStoreOrThrow()
@ -37,16 +40,23 @@ export function useViewFilters(
const _filters = ref<Filter[]>([]) const _filters = ref<Filter[]>([])
const nestedMode = computed(() => isPublic.value || !isUIAllowed('filterSync' || !isUIAllowed('filterChildrenRead'))) const nestedMode = computed(() => isPublic.value || !isUIAllowed('filte rSync') || !isUIAllowed('filterChildrenRead'))
const tabMeta = inject(TabMetaInj, ref({ filterState: new Map(), sortsState: new Map() } as TabItem))
const filters = computed<Filter[]>({ const filters = computed<Filter[]>({
get: () => (nestedMode.value ? currentFilters! : _filters.value), get: () => {
return nestedMode.value ? currentFilters! : _filters.value
},
set: (value: Filter[]) => { set: (value: Filter[]) => {
if (nestedMode.value) { if (nestedMode.value) {
currentFilters = value currentFilters = value
if (isNestedRoot) nestedFilters.value = value if (isNestedRoot) {
nestedFilters.value = value
tabMeta.value.filterState!.set(view.value!.id!, nestedFilters.value)
}
nestedFilters.value = [...nestedFilters.value] nestedFilters.value = [...nestedFilters.value]
reloadHook?.trigger()
return return
} }
@ -66,7 +76,11 @@ export function useViewFilters(
} }
const loadFilters = async (hookId?: string) => { const loadFilters = async (hookId?: string) => {
if (nestedMode.value) return if (nestedMode.value) {
// ignore restoring if not root filter group
if (isNestedRoot) filters.value = tabMeta.value.filterState!.get(view.value!.id!) || []
return
}
try { try {
if (hookId) { if (hookId) {

15
packages/nc-gui/composables/useViewSorts.ts

@ -13,6 +13,7 @@ import {
useSmartsheetStoreOrThrow, useSmartsheetStoreOrThrow,
useUIPermission, useUIPermission,
} from '#imports' } from '#imports'
import type { TabItem } from '~/lib'
export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () => void) { export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () => void) {
const { sharedView } = useSharedView() const { sharedView } = useSharedView()
@ -29,6 +30,8 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
const isPublic = inject(IsPublicInj, ref(false)) const isPublic = inject(IsPublicInj, ref(false))
const tabMeta = inject(TabMetaInj, ref({ sortsState: new Map() } as TabItem))
const loadSorts = async () => { const loadSorts = async () => {
if (isPublic.value) { if (isPublic.value) {
// todo: sorts missing on `ViewType` // todo: sorts missing on `ViewType`
@ -38,6 +41,13 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
} }
try { try {
if (!isUIAllowed('sortSync')) {
const sortsBackup = tabMeta.value.sortsState!.get(view.value!.id!)
if (sortsBackup) {
sorts.value = sortsBackup
return
}
}
if (!view?.value) return if (!view?.value) return
sorts.value = (await $api.dbTableSort.list(view.value!.id!)).sorts?.list || [] sorts.value = (await $api.dbTableSort.list(view.value!.id!)).sorts?.list || []
} catch (e: any) { } catch (e: any) {
@ -51,6 +61,7 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
sorts.value[i] = sort sorts.value[i] = sort
sorts.value = [...sorts.value] sorts.value = [...sorts.value]
reloadHook?.trigger() reloadHook?.trigger()
tabMeta.value.sortsState!.set(view.value!.id!, sorts.value)
return return
} }
@ -79,6 +90,8 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
] ]
$e('a:sort:add', { length: sorts?.value?.length }) $e('a:sort:add', { length: sorts?.value?.length })
tabMeta.value.sortsState!.set(view.value!.id!, sorts.value)
} }
const deleteSort = async (sort: SortType, i: number) => { const deleteSort = async (sort: SortType, i: number) => {
@ -89,6 +102,8 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
sorts.value.splice(i, 1) sorts.value.splice(i, 1)
sorts.value = [...sorts.value] sorts.value = [...sorts.value]
tabMeta.value.sortsState!.set(view.value!.id!, sorts.value)
reloadHook?.trigger() reloadHook?.trigger()
$e('a:sort:delete') $e('a:sort:delete')
} catch (e: any) { } catch (e: any) {

2
packages/nc-gui/lib/types.ts

@ -69,6 +69,8 @@ export interface TabItem {
id?: string id?: string
viewTitle?: string viewTitle?: string
viewId?: string viewId?: string
sortsState?: Map<string, any>
filterState?: Map<string, any>
} }
export interface SharedViewMeta extends Record<string, any> { export interface SharedViewMeta extends Record<string, any> {

Loading…
Cancel
Save