Skip to content
This repository was archived by the owner on May 12, 2026. It is now read-only.

Commit 1e1bd7f

Browse files
committed
fix: show rename form as topbar popup
1 parent 6a3002d commit 1e1bd7f

4 files changed

Lines changed: 94 additions & 49 deletions

File tree

src/cloud/lib/hooks/useCloudResourceModals.tsx

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { stringify } from 'querystring'
3636
import { docPreviewCloseEvent } from './useCloudDocPreview'
3737

3838
export function useCloudResourceModals() {
39-
const { openModal, closeLastModal } = useModal()
39+
const { openModal, openContextModal, closeLastModal } = useModal()
4040
const { messageBox } = useDialog()
4141
const {
4242
updateFolder,
@@ -71,68 +71,105 @@ export function useCloudResourceModals() {
7171
)
7272

7373
const openRenameFolderForm = useCallback(
74-
(folder: SerializedFolder) => {
75-
openModal(
74+
(folder: SerializedFolder, event?: React.MouseEvent<Element>) => {
75+
let renameSubmitted = false
76+
const updateFolderName = async (inputValue: string, emoji?: string) => {
77+
if (renameSubmitted) {
78+
return
79+
}
80+
81+
try {
82+
renameSubmitted = true
83+
await updateFolder(folder, {
84+
workspaceId: folder.workspaceId,
85+
parentFolderId: folder.parentFolderId,
86+
folderName: inputValue,
87+
emoji: typeof emoji === 'string' ? emoji : null,
88+
})
89+
} catch (error) {
90+
renameSubmitted = false
91+
throw error
92+
}
93+
}
94+
95+
const content = (
7696
<EmojiInputForm
7797
defaultIcon={mdiFolderOutline}
7898
defaultInputValue={folder.name}
7999
defaultEmoji={folder.emoji}
80100
placeholder={translate(lngKeys.FolderNamePlaceholder)}
81-
submitButtonProps={{
82-
label: translate(lngKeys.GeneralUpdateVerb),
83-
}}
84101
onSubmit={async (inputValue: string, emoji?: string) => {
85-
await updateFolder(folder, {
86-
workspaceId: folder.workspaceId,
87-
parentFolderId: folder.parentFolderId,
88-
folderName: inputValue,
89-
emoji: typeof emoji === 'string' ? emoji : null,
90-
})
102+
await updateFolderName(inputValue, emoji)
91103
closeLastModal()
92104
}}
93-
/>,
94-
{
95-
showCloseIcon: true,
96-
title: translate(lngKeys.RenameFolder),
97-
}
105+
onBlur={updateFolderName}
106+
/>
98107
)
108+
if (event != null) {
109+
openContextModal(event, content, {
110+
width: 320,
111+
alignment: 'right',
112+
})
113+
return
114+
}
115+
116+
openModal(content, {
117+
showCloseIcon: false,
118+
width: 'small',
119+
})
99120
},
100-
[openModal, closeLastModal, updateFolder, translate]
121+
[openModal, openContextModal, closeLastModal, updateFolder, translate]
101122
)
102123

103124
const openRenameDocForm = useCallback(
104-
(doc: SerializedDoc) => {
105-
openModal(
125+
(doc: SerializedDoc, event?: React.MouseEvent<Element>) => {
126+
let renameSubmitted = false
127+
const updateDocTitle = async (inputValue: string, emoji?: string) => {
128+
if (renameSubmitted) {
129+
return
130+
}
131+
132+
try {
133+
renameSubmitted = true
134+
await updateDoc(doc, {
135+
workspaceId: doc.workspaceId,
136+
parentFolderId: doc.parentFolderId,
137+
title: inputValue,
138+
emoji: emoji == null ? null : emoji,
139+
})
140+
} catch (error) {
141+
renameSubmitted = false
142+
throw error
143+
}
144+
}
145+
146+
const content = (
106147
<EmojiInputForm
107148
defaultIcon={mdiFileDocumentOutline}
108149
defaultInputValue={doc.title}
109150
defaultEmoji={doc.emoji}
110151
placeholder={translate(lngKeys.DocTitlePlaceholder)}
111152
onSubmit={async (inputValue: string, emoji?: string) => {
112-
await updateDoc(doc, {
113-
workspaceId: doc.workspaceId,
114-
parentFolderId: doc.parentFolderId,
115-
title: inputValue,
116-
emoji: emoji == null ? null : emoji,
117-
})
153+
await updateDocTitle(inputValue, emoji)
118154
closeLastModal()
119155
}}
120-
onBlur={async (inputValue: string, emoji?: string) => {
121-
await updateDoc(doc, {
122-
workspaceId: doc.workspaceId,
123-
parentFolderId: doc.parentFolderId,
124-
title: inputValue,
125-
emoji: emoji == null ? null : emoji,
126-
})
127-
}}
128-
/>,
129-
{
130-
showCloseIcon: false,
131-
width: 'small',
132-
}
156+
onBlur={updateDocTitle}
157+
/>
133158
)
159+
if (event != null) {
160+
openContextModal(event, content, {
161+
width: 320,
162+
alignment: 'right',
163+
})
164+
return
165+
}
166+
167+
openModal(content, {
168+
showCloseIcon: false,
169+
width: 'small',
170+
})
134171
},
135-
[closeLastModal, openModal, translate, updateDoc]
172+
[closeLastModal, openModal, openContextModal, translate, updateDoc]
136173
)
137174

138175
const openNewFolderForm = useCallback(

src/cloud/lib/mappers/topbarBreadcrumbs.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
mdiTrashCanOutline,
99
} from '@mdi/js'
1010
import { TFunction } from 'i18next'
11+
import type { MouseEvent } from 'react'
1112
import { TopbarBreadcrumbProps } from '../../../design/components/organisms/Topbar'
1213
import { getDocLinkHref } from '../../components/Link/DocLink'
1314
import { getFolderHref } from '../../components/Link/FolderLink'
@@ -48,8 +49,11 @@ export function mapTopbarBreadcrumbs(
4849
pageDoc?: SerializedDoc
4950
pageFolder?: SerializedFolder
5051
},
51-
renameFolder?: (folder: SerializedFolder) => void,
52-
renameDoc?: (doc: SerializedDoc) => void,
52+
renameFolder?: (
53+
folder: SerializedFolder,
54+
event?: MouseEvent<Element>
55+
) => void,
56+
renameDoc?: (doc: SerializedDoc, event?: MouseEvent<Element>) => void,
5357
openNewDocForm?: (
5458
body: CloudNewResourceRequestBody,
5559
options: UIFormOptions
@@ -196,7 +200,7 @@ function getDocBreadcrumb(
196200
doc: SerializedDoc,
197201
active: boolean,
198202
push: (url: string) => void,
199-
renameDoc?: (doc: SerializedDoc) => void,
203+
renameDoc?: (doc: SerializedDoc, event?: MouseEvent<Element>) => void,
200204
deleteDoc?: (doc: SerializedDoc) => void
201205
): TopbarBreadcrumbProps & AddedProperties {
202206
return {
@@ -217,7 +221,7 @@ function getDocBreadcrumb(
217221
{
218222
icon: mdiPencil,
219223
label: t(lngKeys.GeneralRenameVerb),
220-
onClick: () => renameDoc(doc),
224+
onClick: (event: MouseEvent<Element>) => renameDoc(doc, event),
221225
},
222226
]
223227
: []),
@@ -248,7 +252,10 @@ function getFolderBreadcrumb(
248252
body: CloudNewResourceRequestBody,
249253
options: UIFormOptions
250254
) => void,
251-
renameFolder?: (folder: SerializedFolder) => void,
255+
renameFolder?: (
256+
folder: SerializedFolder,
257+
event?: MouseEvent<Element>
258+
) => void,
252259
deleteFolder?: (folder: SerializedFolder) => void
253260
): TopbarBreadcrumbProps & AddedProperties {
254261
const newResourceBody = {
@@ -310,7 +317,8 @@ function getFolderBreadcrumb(
310317
{
311318
icon: mdiPencil,
312319
label: t(lngKeys.GeneralRenameVerb),
313-
onClick: () => renameFolder(folder),
320+
onClick: (event: MouseEvent<Element>) =>
321+
renameFolder(folder, event),
314322
},
315323
]
316324
: []),

src/design/components/organisms/Topbar/atoms/TopbarActionItem.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ interface TopbarActionItemProps {
1414
export interface TopbarActionItemAttrbs {
1515
label: string
1616
icon: string
17-
onClick: () => void
17+
onClick: (event: React.MouseEvent<Element>) => void
1818
}
1919

2020
const TopbarActionItem = ({
@@ -40,7 +40,7 @@ const TopbarActionItem = ({
4040
id={`tree-action-${shortid.generate()}`}
4141
onClick={(event: React.MouseEvent) => {
4242
event.preventDefault()
43-
item.onClick()
43+
item.onClick(event)
4444
}}
4545
onFocus={() => setFocused(true)}
4646
tabIndex={0}

src/design/components/organisms/Topbar/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export interface TopbarBreadcrumbProps {
2020
icon?: string
2121
parentId: string
2222
active?: boolean
23-
controls?: { label: string; onClick: () => void; icon: string }[]
23+
controls?: TopbarActionItemAttrbs[]
2424
}
2525

2626
export type TopbarControlButtonProps = ButtonProps & {

0 commit comments

Comments
 (0)