Browse Source

feat(nc-gui): store sidebar states separately by id

# What's changed?

* use a sidebar id to identify the state
* use in memory storage to store the states
* use local storage to store persistent states
* add MemStorage class
pull/3664/head
braks 2 years ago
parent
commit
d3a4bca8f3
  1. 2
      packages/nc-gui/components/general/MiniSidebar.vue
  2. 5
      packages/nc-gui/components/smartsheet/Toolbar.vue
  3. 3
      packages/nc-gui/components/smartsheet/sidebar/index.vue
  4. 2
      packages/nc-gui/components/smartsheet/sidebar/toolbar/DeleteTable.vue
  5. 2
      packages/nc-gui/components/smartsheet/sidebar/toolbar/ToggleDrawer.vue
  6. 2
      packages/nc-gui/components/tabs/Smartsheet.vue
  7. 62
      packages/nc-gui/composables/useSidebar/index.ts
  8. 4
      packages/nc-gui/layouts/default.vue
  9. 4
      packages/nc-gui/pages/[projectType]/[projectId]/index.vue
  10. 2
      packages/nc-gui/pages/[projectType]/[projectId]/index/index.vue
  11. 2
      packages/nc-gui/pages/[projectType]/form/[viewId].vue
  12. 2
      packages/nc-gui/pages/index/index/[projectId].vue
  13. 2
      packages/nc-gui/pages/index/index/create-external.vue
  14. 2
      packages/nc-gui/pages/index/index/create.vue
  15. 5
      packages/nc-gui/pages/index/index/index.vue
  16. 2
      packages/nc-gui/pages/signin.vue
  17. 36
      packages/nc-gui/utils/memStorage.ts

2
packages/nc-gui/components/general/MiniSidebar.vue

@ -4,7 +4,7 @@ import { computed, useGlobal, useProject, useRoute, useSidebar } from '#imports'
const { signOut, signedIn, user } = useGlobal()
const { isOpen } = useSidebar({ isOpen: true })
const { isOpen } = useSidebar('nc-mini-sidebar', { isOpen: true })
const { project } = useProject()

5
packages/nc-gui/components/smartsheet/Toolbar.vue

@ -1,5 +1,5 @@
<script setup lang="ts">
import { IsPublicInj, useSharedView, useSmartsheetStoreOrThrow } from '#imports'
import { IsPublicInj, useSharedView, useSidebar, useSmartsheetStoreOrThrow } from '#imports'
import ToggleDrawer from '~/components/smartsheet/sidebar/toolbar/ToggleDrawer.vue'
const { isGrid, isForm, isGallery, isSqlView } = useSmartsheetStoreOrThrow()
@ -8,7 +8,7 @@ const isPublic = inject(IsPublicInj, ref(false))
const { isUIAllowed } = useUIPermission()
const { isOpen } = useSidebar()
const { isOpen } = useSidebar('nc-right-sidebar')
const { allowCSVDownload } = useSharedView()
</script>
@ -42,6 +42,7 @@ const { allowCSVDownload } = useSharedView()
<SmartsheetToolbarAddRow v-if="isUIAllowed('dataInsert') && !isPublic && !isForm && !isSqlView" class="mx-1" />
<SmartsheetToolbarSearchData v-if="(isGrid || isGallery) && !isPublic" class="shrink mr-2 ml-2" />
<template v-if="!isOpen && !isPublic">
<div class="border-l-1 pl-3">
<ToggleDrawer class="mr-2" />

3
packages/nc-gui/components/smartsheet/sidebar/index.vue

@ -13,6 +13,7 @@ import {
ref,
useRoute,
useRouter,
useSidebar,
useViews,
watch,
} from '#imports'
@ -34,7 +35,7 @@ const { $e } = useNuxtApp()
provide(ViewListInj, views)
/** Sidebar visible */
const { isOpen } = useSidebar({ storageKey: 'nc-right-sidebar', isOpen: true })
const { isOpen } = useSidebar('nc-right-sidebar', { useStorage: true, isOpen: true })
const sidebarCollapsed = computed(() => !isOpen.value)

2
packages/nc-gui/components/smartsheet/sidebar/toolbar/DeleteTable.vue

@ -5,7 +5,7 @@ const meta = inject(MetaInj, ref())
const { deleteTable } = useTable()
const { isOpen } = useSidebar({ storageKey: 'nc-right-sidebar' })
const { isOpen } = useSidebar('nc-right-sidebar')
</script>
<template>

2
packages/nc-gui/components/smartsheet/sidebar/toolbar/ToggleDrawer.vue

@ -1,6 +1,6 @@
<script setup lang="ts">
/** Sidebar visible */
const { isOpen, toggle } = useSidebar({ storageKey: 'nc-right-sidebar' })
const { isOpen, toggle } = useSidebar('nc-right-sidebar', { isOpen: true })
const onClick = () => {
toggle(!isOpen.value)

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

@ -40,7 +40,7 @@ const openNewRecordFormHook = createEventHook<void>()
const { isGallery, isGrid, isForm, isLocked } = useProvideSmartsheetStore(activeView, meta)
// provide the sidebar injection state
provideSidebar({ storageKey: 'nc-right-sidebar', isOpen: true })
provideSidebar('nc-right-sidebar', { useStorage: true, isOpen: true })
// todo: move to store
provide(MetaInj, meta)

62
packages/nc-gui/composables/useSidebar/index.ts

@ -1,10 +1,10 @@
import { useStorage } from '@vueuse/core'
import { ref, syncRef, toRefs, useInjectionState, watch } from '#imports'
import { MemStorage, useInjectionState, watch } from '#imports'
interface UseSidebarProps {
hasSidebar?: boolean
isOpen?: boolean
storageKey?: string // if a storageKey is passed, use that key for localStorage
useStorage?: boolean
}
/**
@ -15,7 +15,9 @@ interface UseSidebarProps {
*
* If `provideSidebar` is not called explicitly, `useSidebar` will trigger the provider if no injection state can be found
*/
const [setup, use] = useInjectionState((props: UseSidebarProps = {}) => {
const [setupSidebarStore, useSidebarStore] = useInjectionState(() => new MemStorage(), 'SidebarStore')
const createSidebar = (id: string, props: UseSidebarProps = {}) => {
const isOpen = ref(props.isOpen ?? false)
const hasSidebar = ref(props.hasSidebar ?? true)
@ -27,8 +29,8 @@ const [setup, use] = useInjectionState((props: UseSidebarProps = {}) => {
hasSidebar.value = state ?? !hasSidebar.value
}
if (props.storageKey) {
const storage = toRefs(useStorage(props.storageKey, { isOpen, hasSidebar }, localStorage, { mergeDefaults: true }).value)
if (props.useStorage) {
const storage = toRefs(useStorage(id, { isOpen, hasSidebar }, localStorage, { mergeDefaults: true }).value)
syncRef(isOpen, storage.isOpen)
syncRef(hasSidebar, storage.hasSidebar)
}
@ -55,20 +57,50 @@ const [setup, use] = useInjectionState((props: UseSidebarProps = {}) => {
hasSidebar,
toggleHasSidebar,
}
}, 'useSidebar')
}
export const provideSidebar = setup
const useSidebarStorage = () => {
let sidebarStorage = useSidebarStore()
export function useSidebar(props: UseSidebarProps = {}) {
const state = use()
if (!sidebarStorage) {
sidebarStorage = setupSidebarStore()
}
return sidebarStorage
}
if (!state) {
return setup(props)
export const provideSidebar = (id: string, props: UseSidebarProps = {}) => {
const sidebarStorage = useSidebarStorage()
if (!sidebarStorage.has(id)) {
const sidebar = createSidebar(id, props)
sidebarStorage.set(id, sidebar)
return sidebar
} else {
// set state if props were passed
if (typeof props.isOpen !== 'undefined') state.isOpen.value = props.isOpen
if (typeof props.hasSidebar !== 'undefined') state.hasSidebar.value = props.hasSidebar
const sidebar = sidebarStorage.get(id)
if (props.isOpen !== undefined) sidebar.isOpen.value = props.isOpen
if (props.hasSidebar !== undefined) sidebar.hasSidebar.value = props.hasSidebar
return sidebar
}
}
export function useSidebar(id: string, props: UseSidebarProps = {}) {
if (!id) throw new Error('useSidebar requires an id')
const sidebarStorage = useSidebarStorage()
return state
if (sidebarStorage.has(id)) {
const sidebar = sidebarStorage.get(id)
if (props.isOpen !== undefined) sidebar.isOpen.value = props.isOpen
if (props.hasSidebar !== undefined) sidebar.hasSidebar.value = props.hasSidebar
return sidebar
} else {
return provideSidebar(id, props)
}
}

4
packages/nc-gui/layouts/default.vue

@ -1,12 +1,12 @@
<script lang="ts" setup>
import { useTitle } from '@vueuse/core'
import { useI18n, useRoute, useSidebar } from '#imports'
import { provideSidebar, useI18n, useRoute } from '#imports'
const route = useRoute()
const { te, t } = useI18n()
const { hasSidebar } = useSidebar()
const { hasSidebar } = provideSidebar('nc-left-sidebar')
useTitle(route.meta?.title && te(route.meta.title) ? `${t(route.meta.title)} | NocoDB` : 'NocoDB')
</script>

4
packages/nc-gui/pages/[projectType]/[projectId]/index.vue

@ -11,7 +11,6 @@ import {
openLink,
projectThemeColors,
provide,
provideSidebar,
ref,
useClipboard,
useGlobal,
@ -19,6 +18,7 @@ import {
useProject,
useRoute,
useRouter,
useSidebar,
useTabs,
useUIPermission,
} from '#imports'
@ -49,7 +49,7 @@ const isLocked = ref(false)
provide('TreeViewIsLockedInj', isLocked)
// create a new sidebar state
const { isOpen, toggle } = provideSidebar({ isOpen: true })
const { isOpen, toggle } = useSidebar('nc-left-sidebar', { isOpen: true })
const dialogOpen = ref(false)

2
packages/nc-gui/pages/[projectType]/[projectId]/index/index.vue

@ -25,7 +25,7 @@ const icon = (tab: TabItem) => {
}
}
const { isOpen, toggle } = useSidebar()
const { isOpen, toggle } = useSidebar('nc-left-sidebar')
function onEdit(targetKey: number, action: 'add' | 'remove' | string) {
if (action === 'remove') closeTab(targetKey)

2
packages/nc-gui/pages/[projectType]/form/[viewId].vue

@ -18,7 +18,7 @@ definePageMeta({
public: true,
})
useSidebar({ hasSidebar: false })
useSidebar('nc-left-sidebar', { hasSidebar: false })
const route = useRoute()

2
packages/nc-gui/pages/index/index/[projectId].vue

@ -17,7 +17,7 @@ import {
const { isLoading } = useApi()
useSidebar({ hasSidebar: false })
useSidebar('nc-left-sidebar', { hasSidebar: false })
const route = useRoute()

2
packages/nc-gui/pages/index/index/create-external.vue

@ -37,7 +37,7 @@ const { api, isLoading } = useApi()
const { $e } = useNuxtApp()
useSidebar({ hasSidebar: false })
useSidebar('nc-left-sidebar', { hasSidebar: false })
const { t } = useI18n()

2
packages/nc-gui/pages/index/index/create.vue

@ -18,7 +18,7 @@ const { $e } = useNuxtApp()
const { api, isLoading } = useApi()
useSidebar({ hasSidebar: false })
useSidebar('nc-left-sidebar', { hasSidebar: false })
const nameValidationRules = [
{

5
packages/nc-gui/pages/index/index/index.vue

@ -12,7 +12,6 @@ import {
themeV2Colors,
useApi,
useNuxtApp,
useProject,
useSidebar,
useUIPermission,
} from '#imports'
@ -27,9 +26,7 @@ const { api, isLoading } = useApi()
const { isUIAllowed } = useUIPermission()
useSidebar({ hasSidebar: true, isOpen: true })
const { loadProject } = useProject()
useSidebar('nc-left-sidebar', { hasSidebar: false, isOpen: true })
const filterQuery = ref('')

2
packages/nc-gui/pages/signin.vue

@ -19,7 +19,7 @@ const { api, isLoading } = useApi()
const { t } = useI18n()
useSidebar({ hasSidebar: false })
useSidebar('nc-left-sidebar', { hasSidebar: false })
definePageMeta({
requiresAuth: false,

36
packages/nc-gui/utils/memStorage.ts

@ -0,0 +1,36 @@
/**
* Stores all currently created store instances
*/
export class MemStorage<T = any> {
public currentId = 0
public items = new Map<string, T>()
static instance: MemStorage
public static getInstance(): MemStorage {
if (!MemStorage.instance) {
MemStorage.instance = new MemStorage()
}
return MemStorage.instance
}
public set(id: string, item: T) {
return this.items.set(id, item)
}
public get(id: string) {
return this.items.get(id)
}
public has(id: string) {
return this.items.has(id)
}
public remove(id: string) {
return this.items.delete(id)
}
public getId(prefix?: string) {
return `${prefix}${this.currentId++}`
}
}
Loading…
Cancel
Save