From 1e1bd7f493df6f1ea5211b512ee8035bc75e070d Mon Sep 17 00:00:00 2001 From: Isjuanplayer <180686912+Isjuanplayer@users.noreply.github.com> Date: Mon, 11 May 2026 13:14:00 +0200 Subject: [PATCH] fix: show rename form as topbar popup --- .../lib/hooks/useCloudResourceModals.tsx | 117 ++++++++++++------ src/cloud/lib/mappers/topbarBreadcrumbs.ts | 20 ++- .../Topbar/atoms/TopbarActionItem.tsx | 4 +- .../components/organisms/Topbar/index.tsx | 2 +- 4 files changed, 94 insertions(+), 49 deletions(-) diff --git a/src/cloud/lib/hooks/useCloudResourceModals.tsx b/src/cloud/lib/hooks/useCloudResourceModals.tsx index c2bbcb4989..af0ab6b437 100644 --- a/src/cloud/lib/hooks/useCloudResourceModals.tsx +++ b/src/cloud/lib/hooks/useCloudResourceModals.tsx @@ -36,7 +36,7 @@ import { stringify } from 'querystring' import { docPreviewCloseEvent } from './useCloudDocPreview' export function useCloudResourceModals() { - const { openModal, closeLastModal } = useModal() + const { openModal, openContextModal, closeLastModal } = useModal() const { messageBox } = useDialog() const { updateFolder, @@ -71,68 +71,105 @@ export function useCloudResourceModals() { ) const openRenameFolderForm = useCallback( - (folder: SerializedFolder) => { - openModal( + (folder: SerializedFolder, event?: React.MouseEvent) => { + let renameSubmitted = false + const updateFolderName = async (inputValue: string, emoji?: string) => { + if (renameSubmitted) { + return + } + + try { + renameSubmitted = true + await updateFolder(folder, { + workspaceId: folder.workspaceId, + parentFolderId: folder.parentFolderId, + folderName: inputValue, + emoji: typeof emoji === 'string' ? emoji : null, + }) + } catch (error) { + renameSubmitted = false + throw error + } + } + + const content = ( { - await updateFolder(folder, { - workspaceId: folder.workspaceId, - parentFolderId: folder.parentFolderId, - folderName: inputValue, - emoji: typeof emoji === 'string' ? emoji : null, - }) + await updateFolderName(inputValue, emoji) closeLastModal() }} - />, - { - showCloseIcon: true, - title: translate(lngKeys.RenameFolder), - } + onBlur={updateFolderName} + /> ) + if (event != null) { + openContextModal(event, content, { + width: 320, + alignment: 'right', + }) + return + } + + openModal(content, { + showCloseIcon: false, + width: 'small', + }) }, - [openModal, closeLastModal, updateFolder, translate] + [openModal, openContextModal, closeLastModal, updateFolder, translate] ) const openRenameDocForm = useCallback( - (doc: SerializedDoc) => { - openModal( + (doc: SerializedDoc, event?: React.MouseEvent) => { + let renameSubmitted = false + const updateDocTitle = async (inputValue: string, emoji?: string) => { + if (renameSubmitted) { + return + } + + try { + renameSubmitted = true + await updateDoc(doc, { + workspaceId: doc.workspaceId, + parentFolderId: doc.parentFolderId, + title: inputValue, + emoji: emoji == null ? null : emoji, + }) + } catch (error) { + renameSubmitted = false + throw error + } + } + + const content = ( { - await updateDoc(doc, { - workspaceId: doc.workspaceId, - parentFolderId: doc.parentFolderId, - title: inputValue, - emoji: emoji == null ? null : emoji, - }) + await updateDocTitle(inputValue, emoji) closeLastModal() }} - onBlur={async (inputValue: string, emoji?: string) => { - await updateDoc(doc, { - workspaceId: doc.workspaceId, - parentFolderId: doc.parentFolderId, - title: inputValue, - emoji: emoji == null ? null : emoji, - }) - }} - />, - { - showCloseIcon: false, - width: 'small', - } + onBlur={updateDocTitle} + /> ) + if (event != null) { + openContextModal(event, content, { + width: 320, + alignment: 'right', + }) + return + } + + openModal(content, { + showCloseIcon: false, + width: 'small', + }) }, - [closeLastModal, openModal, translate, updateDoc] + [closeLastModal, openModal, openContextModal, translate, updateDoc] ) const openNewFolderForm = useCallback( diff --git a/src/cloud/lib/mappers/topbarBreadcrumbs.ts b/src/cloud/lib/mappers/topbarBreadcrumbs.ts index f9b0546dd3..c3f4dcfa77 100644 --- a/src/cloud/lib/mappers/topbarBreadcrumbs.ts +++ b/src/cloud/lib/mappers/topbarBreadcrumbs.ts @@ -8,6 +8,7 @@ import { mdiTrashCanOutline, } from '@mdi/js' import { TFunction } from 'i18next' +import type { MouseEvent } from 'react' import { TopbarBreadcrumbProps } from '../../../design/components/organisms/Topbar' import { getDocLinkHref } from '../../components/Link/DocLink' import { getFolderHref } from '../../components/Link/FolderLink' @@ -48,8 +49,11 @@ export function mapTopbarBreadcrumbs( pageDoc?: SerializedDoc pageFolder?: SerializedFolder }, - renameFolder?: (folder: SerializedFolder) => void, - renameDoc?: (doc: SerializedDoc) => void, + renameFolder?: ( + folder: SerializedFolder, + event?: MouseEvent + ) => void, + renameDoc?: (doc: SerializedDoc, event?: MouseEvent) => void, openNewDocForm?: ( body: CloudNewResourceRequestBody, options: UIFormOptions @@ -196,7 +200,7 @@ function getDocBreadcrumb( doc: SerializedDoc, active: boolean, push: (url: string) => void, - renameDoc?: (doc: SerializedDoc) => void, + renameDoc?: (doc: SerializedDoc, event?: MouseEvent) => void, deleteDoc?: (doc: SerializedDoc) => void ): TopbarBreadcrumbProps & AddedProperties { return { @@ -217,7 +221,7 @@ function getDocBreadcrumb( { icon: mdiPencil, label: t(lngKeys.GeneralRenameVerb), - onClick: () => renameDoc(doc), + onClick: (event: MouseEvent) => renameDoc(doc, event), }, ] : []), @@ -248,7 +252,10 @@ function getFolderBreadcrumb( body: CloudNewResourceRequestBody, options: UIFormOptions ) => void, - renameFolder?: (folder: SerializedFolder) => void, + renameFolder?: ( + folder: SerializedFolder, + event?: MouseEvent + ) => void, deleteFolder?: (folder: SerializedFolder) => void ): TopbarBreadcrumbProps & AddedProperties { const newResourceBody = { @@ -310,7 +317,8 @@ function getFolderBreadcrumb( { icon: mdiPencil, label: t(lngKeys.GeneralRenameVerb), - onClick: () => renameFolder(folder), + onClick: (event: MouseEvent) => + renameFolder(folder, event), }, ] : []), diff --git a/src/design/components/organisms/Topbar/atoms/TopbarActionItem.tsx b/src/design/components/organisms/Topbar/atoms/TopbarActionItem.tsx index 237d3fe7a6..753eb3cb5e 100644 --- a/src/design/components/organisms/Topbar/atoms/TopbarActionItem.tsx +++ b/src/design/components/organisms/Topbar/atoms/TopbarActionItem.tsx @@ -14,7 +14,7 @@ interface TopbarActionItemProps { export interface TopbarActionItemAttrbs { label: string icon: string - onClick: () => void + onClick: (event: React.MouseEvent) => void } const TopbarActionItem = ({ @@ -40,7 +40,7 @@ const TopbarActionItem = ({ id={`tree-action-${shortid.generate()}`} onClick={(event: React.MouseEvent) => { event.preventDefault() - item.onClick() + item.onClick(event) }} onFocus={() => setFocused(true)} tabIndex={0} diff --git a/src/design/components/organisms/Topbar/index.tsx b/src/design/components/organisms/Topbar/index.tsx index 0ab93e99f0..a21c4e32a6 100644 --- a/src/design/components/organisms/Topbar/index.tsx +++ b/src/design/components/organisms/Topbar/index.tsx @@ -20,7 +20,7 @@ export interface TopbarBreadcrumbProps { icon?: string parentId: string active?: boolean - controls?: { label: string; onClick: () => void; icon: string }[] + controls?: TopbarActionItemAttrbs[] } export type TopbarControlButtonProps = ButtonProps & {