Browse Source

Nc feat: update tab title as per view/table/base title (#8017)

* feat(nc-gui): set tab title for view

* feat(nc-gui): update tab title as per view title

* fix(nc-gui): shared view ui break issue

* feat(nc-gui): update shared form view tab title as per form heading

* chore(nc-gui): lint

* fix(nc-gui): tab title update issue when switching from base to view
pull/8029/head
Ramesh Mane 8 months ago committed by GitHub
parent
commit
ca7c01b4c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue
  2. 3
      packages/nc-gui/components/dlg/TableRename.vue
  3. 9
      packages/nc-gui/components/project/View.vue
  4. 11
      packages/nc-gui/composables/useSharedFormViewStore.ts
  5. 44
      packages/nc-gui/helpers/parsers/parserHelpers.ts
  6. 15
      packages/nc-gui/store/tables.ts
  7. 42
      packages/nc-gui/store/views.ts

5
packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue

@ -4,7 +4,6 @@ import { message } from 'ant-design-vue'
import { stringifyRolesObj } from 'nocodb-sdk' import { stringifyRolesObj } from 'nocodb-sdk'
import type { BaseType, SourceType, TableType } from 'nocodb-sdk' import type { BaseType, SourceType, TableType } from 'nocodb-sdk'
import { LoadingOutlined } from '@ant-design/icons-vue' import { LoadingOutlined } from '@ant-design/icons-vue'
import { useTitle } from '@vueuse/core'
import { import {
NcProjectType, NcProjectType,
ProjectInj, ProjectInj,
@ -109,6 +108,8 @@ const keys = ref<Record<string, number>>({})
const isTableDeleteDialogVisible = ref(false) const isTableDeleteDialogVisible = ref(false)
const isProjectDeleteDialogVisible = ref(false) const isProjectDeleteDialogVisible = ref(false)
const { refreshViewTabTitle } = useViewsStore()
// If only base is open, i.e in case of docs, base view is open and not the page view // If only base is open, i.e in case of docs, base view is open and not the page view
const baseViewOpen = computed(() => { const baseViewOpen = computed(() => {
const routeNameSplit = String(route.value?.name).split('baseId-index-index') const routeNameSplit = String(route.value?.name).split('baseId-index-index')
@ -144,7 +145,7 @@ const updateProjectTitle = async () => {
$e('a:base:rename') $e('a:base:rename')
useTitle(`${base.value?.title}`) refreshViewTabTitle?.()
} catch (e: any) { } catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e)) message.error(await extractSdkResponseErrorMsg(e))
} }

3
packages/nc-gui/components/dlg/TableRename.vue

@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { TableType } from 'nocodb-sdk' import type { TableType } from 'nocodb-sdk'
import type { ComponentPublicInstance } from '@vue/runtime-core' import type { ComponentPublicInstance } from '@vue/runtime-core'
import { useTitle } from '@vueuse/core'
import { import {
Form, Form,
computed, computed,
@ -180,8 +179,6 @@ const renameTable = async (undo = false, disableTitleDiffCheck?: boolean | undef
$e('a:table:rename') $e('a:table:rename')
useTitle(`${base.value?.title}: ${newMeta?.title}`)
dialogShow.value = false dialogShow.value = false
} catch (e: any) { } catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e)) message.error(await extractSdkResponseErrorMsg(e))

9
packages/nc-gui/components/project/View.vue

@ -6,7 +6,7 @@ import { isEeUI } from '#imports'
const basesStore = useBases() const basesStore = useBases()
const { openedProject, activeProjectId, basesUser } = storeToRefs(basesStore) const { openedProject, activeProjectId, basesUser } = storeToRefs(basesStore)
const { activeTables } = storeToRefs(useTablesStore()) const { activeTables, activeTable } = storeToRefs(useTablesStore())
const { activeWorkspace, workspaceUserCount } = storeToRefs(useWorkspace()) const { activeWorkspace, workspaceUserCount } = storeToRefs(useWorkspace())
const { navigateToProjectPage } = useBase() const { navigateToProjectPage } = useBase()
@ -66,10 +66,15 @@ watch(projectPageTab, () => {
}) })
watch( watch(
() => openedProject.value?.title, () => [openedProject.value?.id, openedProject.value?.title],
() => { () => {
if (activeTable.value?.title) return
useTitle(`${openedProject.value?.title ?? activeWorkspace.value?.title ?? 'NocoDB'}`) useTitle(`${openedProject.value?.title ?? activeWorkspace.value?.title ?? 'NocoDB'}`)
}, },
{
immediate: true,
},
) )
</script> </script>

11
packages/nc-gui/composables/useSharedFormViewStore.ts

@ -14,6 +14,7 @@ import type {
} from 'nocodb-sdk' } from 'nocodb-sdk'
import { RelationTypes, UITypes, isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk' import { RelationTypes, UITypes, isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import { isString } from '@vue/shared' import { isString } from '@vue/shared'
import { useTitle } from '@vueuse/core'
import { filterNullOrUndefinedObjectProperties } from '~/helpers/parsers/parserHelpers' import { filterNullOrUndefinedObjectProperties } from '~/helpers/parsers/parserHelpers'
import { import {
NcErrorType, NcErrorType,
@ -546,6 +547,16 @@ const [useProvideSharedFormStore, useSharedFormStore] = useInjectionState((share
if (next !== prev && passwordError.value) passwordError.value = null if (next !== prev && passwordError.value) passwordError.value = null
}) })
watch(
() => sharedFormView.value?.heading,
() => {
useTitle(`${sharedFormView.value?.heading ?? 'NocoDB'}`)
},
{
flush: 'post',
},
)
return { return {
sharedView, sharedView,
sharedFormView, sharedFormView,

44
packages/nc-gui/helpers/parsers/parserHelpers.ts

@ -235,3 +235,47 @@ export const extractNextDefaultName = (namesData: string[], defaultName: string,
? `${defaultName}${splitOperator}${extractedSortedNumbers[extractedSortedNumbers.length - 1] + 1}` ? `${defaultName}${splitOperator}${extractedSortedNumbers[extractedSortedNumbers.length - 1] + 1}`
: `${defaultName}${splitOperator}1` : `${defaultName}${splitOperator}1`
} }
export const getFormattedViewTabTitle = ({
viewName,
tableName,
baseName,
isDefaultView = false,
charLimit = 20,
isSharedView = false,
}: {
viewName: string
tableName: string
baseName: string
isDefaultView?: boolean
charLimit?: number
isSharedView?: boolean
}) => {
if (isSharedView) {
return viewName || 'NocoDB'
}
let title = `${viewName} | ${tableName} | ${baseName}`
if (isDefaultView) {
charLimit = 30
title = `${tableName} | ${baseName}`
}
if (title.length <= 60) {
return title
}
// Function to truncate text and add ellipsis if needed
const truncateText = (text: string) => {
return text.length > charLimit ? `${text.substring(0, charLimit - 3)}...` : text
}
if (isDefaultView) {
title = `${truncateText(tableName)} | ${truncateText(baseName)}`
} else {
title = `${truncateText(viewName)} | ${truncateText(tableName)} | ${truncateText(baseName)}`
}
return title
}

15
packages/nc-gui/store/tables.ts

@ -1,6 +1,5 @@
import { acceptHMRUpdate, defineStore } from 'pinia' import { acceptHMRUpdate, defineStore } from 'pinia'
import type { TableType } from 'nocodb-sdk' import type { TableType } from 'nocodb-sdk'
import { useTitle } from '@vueuse/core'
import type { SidebarTableNode } from '~/lib' import type { SidebarTableNode } from '~/lib'
export const useTablesStore = defineStore('tablesStore', () => { export const useTablesStore = defineStore('tablesStore', () => {
@ -49,20 +48,6 @@ export const useTablesStore = defineStore('tablesStore', () => {
return activeTables.value.find((t) => t.id === activeTableId.value) return activeTables.value.find((t) => t.id === activeTableId.value)
}) })
watch(
() => activeTable.value?.title,
(title) => {
if (basesStore.openedProject?.type !== 'database') return
if (!title) {
useTitle(basesStore.openedProject?.title)
return
}
useTitle(`${basesStore.openedProject?.title}: ${title}`)
},
)
const loadProjectTables = async (baseId: string, force = false) => { const loadProjectTables = async (baseId: string, force = false) => {
if (!force && baseTables.value.get(baseId)) { if (!force && baseTables.value.get(baseId)) {
return return

42
packages/nc-gui/store/views.ts

@ -1,7 +1,9 @@
import type { FilterType, SortType, ViewType, ViewTypes } from 'nocodb-sdk' import type { FilterType, SortType, ViewType, ViewTypes } from 'nocodb-sdk'
import { acceptHMRUpdate, defineStore } from 'pinia' import { acceptHMRUpdate, defineStore } from 'pinia'
import { useTitle } from '@vueuse/core'
import type { ViewPageType } from '~/lib' import type { ViewPageType } from '~/lib'
import { navigateToBlankTargetOpenOption, useMagicKeys } from '#imports' import { navigateToBlankTargetOpenOption, useMagicKeys } from '#imports'
import { getFormattedViewTabTitle } from '~/helpers/parsers/parserHelpers'
export const useViewsStore = defineStore('viewsStore', () => { export const useViewsStore = defineStore('viewsStore', () => {
const { $api } = useNuxtApp() const { $api } = useNuxtApp()
@ -23,6 +25,7 @@ export const useViewsStore = defineStore('viewsStore', () => {
const route = router.currentRoute const route = router.currentRoute
const bases = useBases() const bases = useBases()
const { openedProject } = storeToRefs(bases)
const tablesStore = useTablesStore() const tablesStore = useTablesStore()
@ -121,6 +124,8 @@ export const useViewsStore = defineStore('viewsStore', () => {
const preFillFormSearchParams = ref('') const preFillFormSearchParams = ref('')
const refreshViewTabTitle = createEventHook<void>()
const loadViews = async ({ const loadViews = async ({
tableId, tableId,
ignoreLoading, ignoreLoading,
@ -343,6 +348,42 @@ export const useViewsStore = defineStore('viewsStore', () => {
] ]
}) })
const updateTabTitle = () => {
if (!activeView.value || !activeView.value.base_id) {
if (openedProject.value?.title) {
useTitle(openedProject.value?.title)
}
return
}
const tableName = tablesStore.baseTables
.get(activeView.value.base_id)
?.find((t) => t.id === activeView.value.fk_model_id)?.title
const baseName = bases.basesList.find((p) => p.id === activeView.value.base_id)?.title
useTitle(
getFormattedViewTabTitle({
viewName: activeView.value.title,
tableName: tableName || '',
baseName: baseName || '',
isDefaultView: !!activeView.value.is_default,
isSharedView: !!sharedView.value?.id,
}),
)
}
refreshViewTabTitle.on(() => {
updateTabTitle()
})
watch(
() => [activeView.value?.title, activeView.value?.id],
() => {
refreshViewTabTitle.trigger()
},
)
return { return {
isLockedView, isLockedView,
isViewsLoading, isViewsLoading,
@ -365,6 +406,7 @@ export const useViewsStore = defineStore('viewsStore', () => {
activeNestedFilters, activeNestedFilters,
isActiveViewLocked, isActiveViewLocked,
preFillFormSearchParams, preFillFormSearchParams,
refreshViewTabTitle: refreshViewTabTitle.trigger,
} }
}) })

Loading…
Cancel
Save