@@ -10,7 +10,6 @@ import { ReactQueryKeys } from '@teable/sdk/config';
1010import { useBaseId , useBasePermission } from '@teable/sdk/hooks' ;
1111import {
1212 Button ,
13- cn ,
1413 DropdownMenu ,
1514 DropdownMenuContent ,
1615 DropdownMenuItem ,
@@ -22,20 +21,20 @@ import { toast } from '@teable/ui-lib/shadcn/ui/sonner';
2221import Head from 'next/head' ;
2322import { useRouter } from 'next/router' ;
2423import { useTranslation } from 'next-i18next' ;
25- import { useRef , useState } from 'react' ;
24+ import { useEffect , useRef , useState } from 'react' ;
2625import { dashboardConfig } from '@/features/i18n/dashboard.config' ;
2726import { MenuDeleteItem } from '../components/MenuDeleteItem' ;
2827import { useBrand } from '../hooks/useBrand' ;
2928import { AddPluginDialog } from './components/AddPluginDialog' ;
30- import { DashboardSwitcher } from './components/DashboardSwitcher' ;
3129
3230export const DashboardHeader = ( props : { dashboardId : string } ) => {
3331 const { dashboardId } = props ;
3432 const baseId = useBaseId ( ) ! ;
3533 const router = useRouter ( ) ;
3634 const queryClient = useQueryClient ( ) ;
3735 const [ menuOpen , setMenuOpen ] = useState ( false ) ;
38- const [ rename , setRename ] = useState < string | null > ( null ) ;
36+ const [ isRenaming , setIsRenaming ] = useState ( false ) ;
37+ const [ editName , setEditName ] = useState < string > ( '' ) ;
3938 const renameRef = useRef < HTMLInputElement > ( null ) ;
4039 const { t } = useTranslation ( dashboardConfig . i18nNamespaces ) ;
4140 const basePermissions = useBasePermission ( ) ;
@@ -71,60 +70,77 @@ export const DashboardHeader = (props: { dashboardId: string }) => {
7170 } ) ;
7271
7372 const { mutate : renameDashboardMutate } = useMutation ( {
74- mutationFn : ( ) => renameDashboard ( baseId , dashboardId , rename ! ) ,
73+ mutationFn : ( { name } : { name : string } ) => renameDashboard ( baseId , dashboardId , name ) ,
7574 onSuccess : ( ) => {
76- setRename ( null ) ;
75+ setIsRenaming ( false ) ;
7776 queryClient . invalidateQueries ( ReactQueryKeys . getDashboardList ( baseId ) ) ;
7877 } ,
7978 } ) ;
8079
8180 const selectedDashboard = dashboardList ?. find ( ( { id } ) => id === dashboardId ) ;
81+ const dashboardName = selectedDashboard ?. name ?? t ( 'common:noun.dashboard' ) ;
82+
83+ const startRename = ( ) => {
84+ setIsRenaming ( true ) ;
85+ setEditName ( dashboardName ) ;
86+ } ;
87+
88+ const cancelRename = ( ) => {
89+ setIsRenaming ( false ) ;
90+ setEditName ( dashboardName ) ;
91+ } ;
92+
8293 const submitRename = ( ) => {
83- if ( ! rename || selectedDashboard ?. name === rename ) {
84- setRename ( null ) ;
94+ const newName = editName . trim ( ) ;
95+ if ( dashboardName === newName ) {
96+ setIsRenaming ( false ) ;
8597 return ;
8698 }
87- renameDashboardMutate ( ) ;
99+ setIsRenaming ( false ) ;
100+ renameDashboardMutate ( { name : newName } ) ;
88101 } ;
89102
103+ const handleKeyDown = ( e : React . KeyboardEvent ) => {
104+ if ( e . key === 'Enter' ) {
105+ submitRename ( ) ;
106+ } else if ( e . key === 'Escape' ) {
107+ cancelRename ( ) ;
108+ }
109+ } ;
110+
111+ useEffect ( ( ) => {
112+ if ( isRenaming && renameRef . current ) {
113+ renameRef . current . focus ( ) ;
114+ renameRef . current . select ( ) ;
115+ }
116+ } , [ isRenaming ] ) ;
117+
90118 return (
91- < div className = "flex h-16 shrink-0 items-center justify-between border-b px-4" >
119+ < div className = "flex h-12 shrink-0 items-center justify-between border-b px-4" >
92120 < Head >
93- < title >
94- { selectedDashboard ?. name ? `${ selectedDashboard ?. name } - ${ brandName } ` : brandName }
95- </ title >
121+ < title > { dashboardName ? `${ dashboardName } - ${ brandName } ` : brandName } </ title >
96122 </ Head >
97- < DashboardSwitcher
98- className = { cn ( 'w-44' , {
99- hidden : rename !== null ,
100- } ) }
101- dashboardId = { dashboardId }
102- onChange = { ( dashboardId ) => {
103- router . push ( {
104- pathname : '/base/[baseId]/dashboard/[dashboardId]' ,
105- query : { baseId, dashboardId } ,
106- } ) ;
107- } }
108- />
109- < Input
110- ref = { renameRef }
111- className = { cn ( 'w-44' , {
112- hidden : rename === null ,
113- } ) }
114- value = { rename ?? '' }
115- onBlur = { ( ) => {
116- submitRename ( ) ;
117- } }
118- onKeyDown = { ( e ) => {
119- if ( e . key === 'Enter' ) {
120- submitRename ( ) ;
121- }
122- if ( e . key === 'Escape' ) {
123- setRename ( null ) ;
124- }
125- } }
126- onChange = { ( e ) => setRename ( e . target . value ) }
127- />
123+ { isRenaming ? (
124+ < Input
125+ ref = { renameRef }
126+ className = "max-w-60"
127+ value = { editName ?? '' }
128+ onBlur = { submitRename }
129+ onKeyDown = { handleKeyDown }
130+ onChange = { ( e ) => setEditName ( e . target . value ) }
131+ />
132+ ) : (
133+ < Button
134+ variant = "ghost"
135+ size = "sm"
136+ className = "justify-start text-sm"
137+ disabled = { ! canManage }
138+ onClick = { startRename }
139+ >
140+ < span className = "truncate" > { dashboardName } </ span >
141+ </ Button >
142+ ) }
143+
128144 < div className = "flex items-center gap-2" >
129145 { canManage && (
130146 < AddPluginDialog dashboardId = { dashboardId } >
@@ -142,12 +158,7 @@ export const DashboardHeader = (props: { dashboardId: string }) => {
142158 </ Button >
143159 </ DropdownMenuTrigger >
144160 < DropdownMenuContent align = "end" className = "relative min-w-36 overflow-hidden" >
145- < DropdownMenuItem
146- onSelect = { ( ) => {
147- setRename ( selectedDashboard ?. name ?? null ) ;
148- setTimeout ( ( ) => renameRef . current ?. focus ( ) , 200 ) ;
149- } }
150- >
161+ < DropdownMenuItem onSelect = { startRename } >
151162 < Edit className = "mr-1.5" />
152163 { t ( 'common:actions.rename' ) }
153164 </ DropdownMenuItem >
0 commit comments