mirror of
https://github.com/nocodb/nocodb.git
synced 2026-04-25 00:45:19 +00:00
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
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 (!state) {
|
||||
return setup(props)
|
||||
} 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
|
||||
if (!sidebarStorage) {
|
||||
sidebarStorage = setupSidebarStore()
|
||||
}
|
||||
|
||||
return state
|
||||
return sidebarStorage
|
||||
}
|
||||
|
||||
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 {
|
||||
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()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -18,7 +18,7 @@ definePageMeta({
|
||||
public: true,
|
||||
})
|
||||
|
||||
useSidebar({ hasSidebar: false })
|
||||
useSidebar('nc-left-sidebar', { hasSidebar: false })
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
|
||||
const { isLoading } = useApi()
|
||||
|
||||
useSidebar({ hasSidebar: false })
|
||||
useSidebar('nc-left-sidebar', { hasSidebar: false })
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ const { api, isLoading } = useApi()
|
||||
|
||||
const { $e } = useNuxtApp()
|
||||
|
||||
useSidebar({ hasSidebar: false })
|
||||
useSidebar('nc-left-sidebar', { hasSidebar: false })
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const { $e } = useNuxtApp()
|
||||
|
||||
const { api, isLoading } = useApi()
|
||||
|
||||
useSidebar({ hasSidebar: false })
|
||||
useSidebar('nc-left-sidebar', { hasSidebar: false })
|
||||
|
||||
const nameValidationRules = [
|
||||
{
|
||||
|
||||
@@ -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('')
|
||||
|
||||
|
||||
@@ -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
Normal file
36
packages/nc-gui/utils/memStorage.ts
Normal file
@@ -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++}`
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user