From ca7c01b4c6f503a896edd09a0a3d31d843ad17d0 Mon Sep 17 00:00:00 2001 From: Ramesh Mane <101566080+rameshmane7218@users.noreply.github.com> Date: Thu, 4 Apr 2024 19:20:29 +0530 Subject: [PATCH] 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 --- .../dashboard/TreeView/ProjectNode.vue | 5 ++- .../nc-gui/components/dlg/TableRename.vue | 3 -- packages/nc-gui/components/project/View.vue | 9 +++- .../composables/useSharedFormViewStore.ts | 11 +++++ .../nc-gui/helpers/parsers/parserHelpers.ts | 44 +++++++++++++++++++ packages/nc-gui/store/tables.ts | 15 ------- packages/nc-gui/store/views.ts | 42 ++++++++++++++++++ 7 files changed, 107 insertions(+), 22 deletions(-) diff --git a/packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue b/packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue index 3666365f59..78ad734d10 100644 --- a/packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue +++ b/packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue @@ -4,7 +4,6 @@ import { message } from 'ant-design-vue' import { stringifyRolesObj } from 'nocodb-sdk' import type { BaseType, SourceType, TableType } from 'nocodb-sdk' import { LoadingOutlined } from '@ant-design/icons-vue' -import { useTitle } from '@vueuse/core' import { NcProjectType, ProjectInj, @@ -109,6 +108,8 @@ const keys = ref>({}) const isTableDeleteDialogVisible = 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 const baseViewOpen = computed(() => { const routeNameSplit = String(route.value?.name).split('baseId-index-index') @@ -144,7 +145,7 @@ const updateProjectTitle = async () => { $e('a:base:rename') - useTitle(`${base.value?.title}`) + refreshViewTabTitle?.() } catch (e: any) { message.error(await extractSdkResponseErrorMsg(e)) } diff --git a/packages/nc-gui/components/dlg/TableRename.vue b/packages/nc-gui/components/dlg/TableRename.vue index d8550d56ea..ab7739c41d 100644 --- a/packages/nc-gui/components/dlg/TableRename.vue +++ b/packages/nc-gui/components/dlg/TableRename.vue @@ -1,7 +1,6 @@ diff --git a/packages/nc-gui/composables/useSharedFormViewStore.ts b/packages/nc-gui/composables/useSharedFormViewStore.ts index 0a865f97d2..35acaccc1c 100644 --- a/packages/nc-gui/composables/useSharedFormViewStore.ts +++ b/packages/nc-gui/composables/useSharedFormViewStore.ts @@ -14,6 +14,7 @@ import type { } from 'nocodb-sdk' import { RelationTypes, UITypes, isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk' import { isString } from '@vue/shared' +import { useTitle } from '@vueuse/core' import { filterNullOrUndefinedObjectProperties } from '~/helpers/parsers/parserHelpers' import { NcErrorType, @@ -546,6 +547,16 @@ const [useProvideSharedFormStore, useSharedFormStore] = useInjectionState((share if (next !== prev && passwordError.value) passwordError.value = null }) + watch( + () => sharedFormView.value?.heading, + () => { + useTitle(`${sharedFormView.value?.heading ?? 'NocoDB'}`) + }, + { + flush: 'post', + }, + ) + return { sharedView, sharedFormView, diff --git a/packages/nc-gui/helpers/parsers/parserHelpers.ts b/packages/nc-gui/helpers/parsers/parserHelpers.ts index 6feef93279..f336d9d753 100644 --- a/packages/nc-gui/helpers/parsers/parserHelpers.ts +++ b/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}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 +} diff --git a/packages/nc-gui/store/tables.ts b/packages/nc-gui/store/tables.ts index 0a7d24d0c8..a186b0e647 100644 --- a/packages/nc-gui/store/tables.ts +++ b/packages/nc-gui/store/tables.ts @@ -1,6 +1,5 @@ import { acceptHMRUpdate, defineStore } from 'pinia' import type { TableType } from 'nocodb-sdk' -import { useTitle } from '@vueuse/core' import type { SidebarTableNode } from '~/lib' export const useTablesStore = defineStore('tablesStore', () => { @@ -49,20 +48,6 @@ export const useTablesStore = defineStore('tablesStore', () => { 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) => { if (!force && baseTables.value.get(baseId)) { return diff --git a/packages/nc-gui/store/views.ts b/packages/nc-gui/store/views.ts index 49e44d7557..9b94672b9f 100644 --- a/packages/nc-gui/store/views.ts +++ b/packages/nc-gui/store/views.ts @@ -1,7 +1,9 @@ import type { FilterType, SortType, ViewType, ViewTypes } from 'nocodb-sdk' import { acceptHMRUpdate, defineStore } from 'pinia' +import { useTitle } from '@vueuse/core' import type { ViewPageType } from '~/lib' import { navigateToBlankTargetOpenOption, useMagicKeys } from '#imports' +import { getFormattedViewTabTitle } from '~/helpers/parsers/parserHelpers' export const useViewsStore = defineStore('viewsStore', () => { const { $api } = useNuxtApp() @@ -23,6 +25,7 @@ export const useViewsStore = defineStore('viewsStore', () => { const route = router.currentRoute const bases = useBases() + const { openedProject } = storeToRefs(bases) const tablesStore = useTablesStore() @@ -121,6 +124,8 @@ export const useViewsStore = defineStore('viewsStore', () => { const preFillFormSearchParams = ref('') + const refreshViewTabTitle = createEventHook() + const loadViews = async ({ tableId, 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 { isLockedView, isViewsLoading, @@ -365,6 +406,7 @@ export const useViewsStore = defineStore('viewsStore', () => { activeNestedFilters, isActiveViewLocked, preFillFormSearchParams, + refreshViewTabTitle: refreshViewTabTitle.trigger, } })