From 836372a3740915dfdaa7619ab3803a2b5afc45b8 Mon Sep 17 00:00:00 2001 From: Derikyan Date: Fri, 22 Nov 2024 11:02:43 +0400 Subject: [PATCH 1/2] fix(chat): fix modals outside click (Issue #2578) --- .../src/components/Chat/Publish/PublishWizard.tsx | 7 +++++++ .../Chat/Publish/ReviewApplicationDialog.tsx | 9 ++++++++- .../Common/ApplicationWizard/ApplicationWizard.tsx | 6 +++++- .../ApplicationWizard/CodeAppView/CodeEditor.tsx | 14 ++++++++++++++ .../ApplicationDetails/ApplicationDetails.tsx | 4 ++++ .../src/components/Marketplace/ApplicationLogs.tsx | 4 ++++ .../Promptbar/components/PreviewPromptModal.tsx | 7 +++++++ 7 files changed, 49 insertions(+), 2 deletions(-) diff --git a/apps/chat/src/components/Chat/Publish/PublishWizard.tsx b/apps/chat/src/components/Chat/Publish/PublishWizard.tsx index 83dd326b4d..450f295af3 100644 --- a/apps/chat/src/components/Chat/Publish/PublishWizard.tsx +++ b/apps/chat/src/components/Chat/Publish/PublishWizard.tsx @@ -1,3 +1,4 @@ +import { UseDismissProps } from '@floating-ui/react'; import { IconPlus, IconX } from '@tabler/icons-react'; import { ClipboardEvent, @@ -68,6 +69,11 @@ import isEqual from 'lodash-es/isEqual'; import startCase from 'lodash-es/startCase'; import toLower from 'lodash-es/toLower'; +const modalDismissProps = { + outsidePress: false, + escapeKey: false, +} as UseDismissProps; + interface Props< T extends Conversation | ShareEntity | PublishRequestDialAIEntityModel, > { @@ -451,6 +457,7 @@ export function PublishModal< state={isOpen ? ModalState.OPENED : ModalState.CLOSED} onClose={onClose} initialFocus={nameInputRef} + dismissProps={modalDismissProps} >
diff --git a/apps/chat/src/components/Chat/Publish/ReviewApplicationDialog.tsx b/apps/chat/src/components/Chat/Publish/ReviewApplicationDialog.tsx index fa6849fd0b..5116952ad3 100644 --- a/apps/chat/src/components/Chat/Publish/ReviewApplicationDialog.tsx +++ b/apps/chat/src/components/Chat/Publish/ReviewApplicationDialog.tsx @@ -1,3 +1,5 @@ +import { UseDismissProps } from '@floating-ui/react'; + import { ModalState } from '@/src/types/modal'; import { ApplicationSelectors } from '@/src/store/application/application.reducers'; @@ -8,6 +10,11 @@ import Modal from '../../Common/Modal'; import { Spinner } from '../../Common/Spinner'; import { ReviewApplicationDialogView } from './ReviewApplicationDialogView'; +const modalDismissProps = { + outsidePress: true, + escapeKey: true, +} as UseDismissProps; + export function ReviewApplicationDialog() { const isLoading = useAppSelector( ApplicationSelectors.selectIsApplicationLoading, @@ -25,8 +32,8 @@ export function ReviewApplicationDialog() { onClose={handleClose} overlayClassName="fixed inset-0 top-[48px]" state={ModalState.OPENED} + dismissProps={modalDismissProps} containerClassName="flex flex-col gap-4 sm:w-[600px] w-full" - dismissProps={{ outsidePressEvent: 'mousedown' }} > {isLoading ? (
diff --git a/apps/chat/src/components/Common/ApplicationWizard/ApplicationWizard.tsx b/apps/chat/src/components/Common/ApplicationWizard/ApplicationWizard.tsx index 03a1ec2563..5fc96edc4d 100644 --- a/apps/chat/src/components/Common/ApplicationWizard/ApplicationWizard.tsx +++ b/apps/chat/src/components/Common/ApplicationWizard/ApplicationWizard.tsx @@ -14,7 +14,11 @@ import { QuickAppView } from '@/src/components/Common/ApplicationWizard/QuickApp import Modal from '@/src/components/Common/Modal'; import { Spinner } from '@/src/components/Common/Spinner'; -const modalDismissProps = { outsidePressEvent: 'mousedown' } as UseDismissProps; +const modalDismissProps = { + outsidePress: false, + escapeKey: false, +} as UseDismissProps; + interface ApplicationWizardProps { isOpen: boolean; onClose: (value: boolean) => void; diff --git a/apps/chat/src/components/Common/ApplicationWizard/CodeAppView/CodeEditor.tsx b/apps/chat/src/components/Common/ApplicationWizard/CodeAppView/CodeEditor.tsx index aa991916ed..6d6a70770f 100644 --- a/apps/chat/src/components/Common/ApplicationWizard/CodeAppView/CodeEditor.tsx +++ b/apps/chat/src/components/Common/ApplicationWizard/CodeAppView/CodeEditor.tsx @@ -328,6 +328,20 @@ export const CodeEditor = ({ sourcesFolderId, setValue }: Props) => { } }, [rootFileNames, setValue, sourcesFolderId]); + useEffect(() => { + const handleKeyUp = (event: KeyboardEvent) => { + if (event.key === 'Escape' && isFullScreen) { + setIsFullScreen(false); + } + }; + + window.addEventListener('keyup', handleKeyUp); + + return () => { + window.removeEventListener('keyup', handleKeyUp); + }; + }, [isFullScreen]); + const handleUploadFile = useCallback( (relativePath: string) => { setUploadFolderId(relativePath); diff --git a/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationDetails.tsx b/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationDetails.tsx index e732aaed08..c3ca967360 100644 --- a/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationDetails.tsx +++ b/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationDetails.tsx @@ -1,3 +1,4 @@ +import { UseDismissProps } from '@floating-ui/react'; import { useCallback, useEffect, useMemo } from 'react'; import { useSearchParams } from 'next/navigation'; @@ -18,6 +19,8 @@ import { ApplicationDetailsHeader } from './ApplicationHeader'; import { PublishActions } from '@epam/ai-dial-shared'; +const modalDismissProps = { outsidePress: true } as UseDismissProps; + interface Props { isMobileView: boolean; entity: DialAIEntityModel; @@ -82,6 +85,7 @@ const ApplicationDetails = ({ overlayClassName="!z-40" containerClassName="flex w-full flex-col divide-y divide-tertiary divide-tertiary xl:max-w-[720px] max-w-[700px]" onClose={onClose} + dismissProps={modalDismissProps} > diff --git a/apps/chat/src/components/Marketplace/ApplicationLogs.tsx b/apps/chat/src/components/Marketplace/ApplicationLogs.tsx index 8708780f3a..f22bdd8b68 100644 --- a/apps/chat/src/components/Marketplace/ApplicationLogs.tsx +++ b/apps/chat/src/components/Marketplace/ApplicationLogs.tsx @@ -1,3 +1,4 @@ +import { UseDismissProps } from '@floating-ui/react'; import { IconDownload, IconRefresh } from '@tabler/icons-react'; import React from 'react'; @@ -115,6 +116,8 @@ const LogsFooter = ({ entityId }: { entityId: string }) => { ); }; +const modalDismissProps = { outsidePress: true } as UseDismissProps; + interface ApplicationLogsProps { entityId: string; isOpen: boolean; @@ -134,6 +137,7 @@ export const ApplicationLogs = ({ overlayClassName="!z-40" containerClassName="flex w-full flex-col min-h-[350px] xl:max-w-[820px] max-w-[800px]" onClose={onClose} + dismissProps={modalDismissProps} > diff --git a/apps/chat/src/components/Promptbar/components/PreviewPromptModal.tsx b/apps/chat/src/components/Promptbar/components/PreviewPromptModal.tsx index e5740f581d..a9fd18b2a4 100644 --- a/apps/chat/src/components/Promptbar/components/PreviewPromptModal.tsx +++ b/apps/chat/src/components/Promptbar/components/PreviewPromptModal.tsx @@ -1,3 +1,4 @@ +import { UseDismissProps } from '@floating-ui/react'; import { IconFileArrowRight, IconTrashX } from '@tabler/icons-react'; import { MouseEventHandler, useCallback } from 'react'; @@ -32,6 +33,11 @@ import Modal from '../../Common/Modal'; import { PublishActions } from '@epam/ai-dial-shared'; +const modalDismissProps = { + outsidePress: true, + escapeKey: true, +} as UseDismissProps; + interface Props { isOpen: boolean; onDuplicate?: MouseEventHandler; @@ -106,6 +112,7 @@ export const PreviewPromptModal = ({ portalId="theme-main" containerClassName="inline-block w-full overflow-y-auto py-4 md:p-0 align-bottom transition-all xl:max-h-[800px] xl:max-w-[720px] 2xl:max-w-[1000px]" dataQa="preview-prompt-modal" + dismissProps={modalDismissProps} headingClassName={classNames( 'px-3 md:p-6', prompt.publicationInfo?.action === PublishActions.DELETE && From 01875667895c5cadf188aa7a5bf379777b29f9eb Mon Sep 17 00:00:00 2001 From: Derikyan Date: Tue, 26 Nov 2024 14:32:10 +0400 Subject: [PATCH 2/2] create constat for reuse --- .../src/components/Chat/Publish/PublishWizard.tsx | 9 ++------- .../Chat/Publish/ReviewApplicationDialog.tsx | 11 +++-------- .../Common/ApplicationWizard/ApplicationWizard.tsx | 10 +++------- .../ApplicationDetails/ApplicationDetails.tsx | 6 ++---- .../src/components/Marketplace/ApplicationLogs.tsx | 7 +++---- .../Promptbar/components/PreviewPromptModal.tsx | 10 +++------- apps/chat/src/constants/dialogs.ts | 11 +++++++++++ 7 files changed, 27 insertions(+), 37 deletions(-) create mode 100644 apps/chat/src/constants/dialogs.ts diff --git a/apps/chat/src/components/Chat/Publish/PublishWizard.tsx b/apps/chat/src/components/Chat/Publish/PublishWizard.tsx index 450f295af3..1055dfef0b 100644 --- a/apps/chat/src/components/Chat/Publish/PublishWizard.tsx +++ b/apps/chat/src/components/Chat/Publish/PublishWizard.tsx @@ -1,4 +1,3 @@ -import { UseDismissProps } from '@floating-ui/react'; import { IconPlus, IconX } from '@tabler/icons-react'; import { ClipboardEvent, @@ -50,6 +49,7 @@ import { } from '@/src/store/publication/publication.reducers'; import { UIActions } from '@/src/store/ui/ui.reducers'; +import { DISALLOW_CLICK_OUTSIDE } from '@/src/constants/dialogs'; import { PUBLISHING_FOLDER_NAME } from '@/src/constants/folders'; import { PUBLIC_URL_PREFIX } from '@/src/constants/public'; @@ -69,11 +69,6 @@ import isEqual from 'lodash-es/isEqual'; import startCase from 'lodash-es/startCase'; import toLower from 'lodash-es/toLower'; -const modalDismissProps = { - outsidePress: false, - escapeKey: false, -} as UseDismissProps; - interface Props< T extends Conversation | ShareEntity | PublishRequestDialAIEntityModel, > { @@ -457,7 +452,7 @@ export function PublishModal< state={isOpen ? ModalState.OPENED : ModalState.CLOSED} onClose={onClose} initialFocus={nameInputRef} - dismissProps={modalDismissProps} + dismissProps={DISALLOW_CLICK_OUTSIDE} >
diff --git a/apps/chat/src/components/Chat/Publish/ReviewApplicationDialog.tsx b/apps/chat/src/components/Chat/Publish/ReviewApplicationDialog.tsx index 5116952ad3..a02de2c8e0 100644 --- a/apps/chat/src/components/Chat/Publish/ReviewApplicationDialog.tsx +++ b/apps/chat/src/components/Chat/Publish/ReviewApplicationDialog.tsx @@ -1,20 +1,15 @@ -import { UseDismissProps } from '@floating-ui/react'; - import { ModalState } from '@/src/types/modal'; import { ApplicationSelectors } from '@/src/store/application/application.reducers'; import { useAppDispatch, useAppSelector } from '@/src/store/hooks'; import { PublicationActions } from '@/src/store/publication/publication.reducers'; +import { ALLOW_CLICK_OUTSIDE } from '@/src/constants/dialogs'; + import Modal from '../../Common/Modal'; import { Spinner } from '../../Common/Spinner'; import { ReviewApplicationDialogView } from './ReviewApplicationDialogView'; -const modalDismissProps = { - outsidePress: true, - escapeKey: true, -} as UseDismissProps; - export function ReviewApplicationDialog() { const isLoading = useAppSelector( ApplicationSelectors.selectIsApplicationLoading, @@ -32,7 +27,7 @@ export function ReviewApplicationDialog() { onClose={handleClose} overlayClassName="fixed inset-0 top-[48px]" state={ModalState.OPENED} - dismissProps={modalDismissProps} + dismissProps={ALLOW_CLICK_OUTSIDE} containerClassName="flex flex-col gap-4 sm:w-[600px] w-full" > {isLoading ? ( diff --git a/apps/chat/src/components/Common/ApplicationWizard/ApplicationWizard.tsx b/apps/chat/src/components/Common/ApplicationWizard/ApplicationWizard.tsx index 5fc96edc4d..75e613bdd1 100644 --- a/apps/chat/src/components/Common/ApplicationWizard/ApplicationWizard.tsx +++ b/apps/chat/src/components/Common/ApplicationWizard/ApplicationWizard.tsx @@ -1,4 +1,3 @@ -import { UseDismissProps } from '@floating-ui/react'; import React, { useCallback, useMemo } from 'react'; import { ApplicationType } from '@/src/types/applications'; @@ -7,6 +6,8 @@ import { ModalState } from '@/src/types/modal'; import { ApplicationSelectors } from '@/src/store/application/application.reducers'; import { useAppSelector } from '@/src/store/hooks'; +import { DISALLOW_CLICK_OUTSIDE } from '@/src/constants/dialogs'; + import { ApplicationWizardHeader } from '@/src/components/Common/ApplicationWizard/ApplicationWizardHeader'; import { CodeAppView } from '@/src/components/Common/ApplicationWizard/CodeAppView/CodeAppView'; import { CustomAppView } from '@/src/components/Common/ApplicationWizard/CustomAppView'; @@ -14,11 +15,6 @@ import { QuickAppView } from '@/src/components/Common/ApplicationWizard/QuickApp import Modal from '@/src/components/Common/Modal'; import { Spinner } from '@/src/components/Common/Spinner'; -const modalDismissProps = { - outsidePress: false, - escapeKey: false, -} as UseDismissProps; - interface ApplicationWizardProps { isOpen: boolean; onClose: (value: boolean) => void; @@ -64,7 +60,7 @@ export const ApplicationWizard: React.FC = ({ onClose={handleClose} dataQa="application-dialog" containerClassName="flex w-full flex-col pt-2 md:grow-0 xl:max-w-[720px] 2xl:max-w-[780px] !bg-layer-2" - dismissProps={modalDismissProps} + dismissProps={DISALLOW_CLICK_OUTSIDE} hideClose > {isLoading ? ( diff --git a/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationDetails.tsx b/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationDetails.tsx index bbc628deb8..cf5e6e0e19 100644 --- a/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationDetails.tsx +++ b/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationDetails.tsx @@ -1,4 +1,3 @@ -import { UseDismissProps } from '@floating-ui/react'; import { useCallback, useMemo } from 'react'; import { useSearchParams } from 'next/navigation'; @@ -10,6 +9,7 @@ import { ConversationsActions } from '@/src/store/conversations/conversations.re import { useAppDispatch, useAppSelector } from '@/src/store/hooks'; import { ModelsSelectors } from '@/src/store/models/models.reducers'; +import { ALLOW_CLICK_OUTSIDE } from '@/src/constants/dialogs'; import { MarketplaceQueryParams } from '@/src/constants/marketplace'; import Modal from '../../Common/Modal'; @@ -19,8 +19,6 @@ import { ApplicationDetailsHeader } from './ApplicationHeader'; import { PublishActions } from '@epam/ai-dial-shared'; -const modalDismissProps = { outsidePress: true } as UseDismissProps; - interface Props { isMobileView: boolean; entity: DialAIEntityModel; @@ -83,7 +81,7 @@ const ApplicationDetails = ({ overlayClassName="!z-40" containerClassName="flex w-full flex-col divide-y divide-tertiary divide-tertiary xl:max-w-[720px] max-w-[700px]" onClose={onClose} - dismissProps={modalDismissProps} + dismissProps={ALLOW_CLICK_OUTSIDE} > diff --git a/apps/chat/src/components/Marketplace/ApplicationLogs.tsx b/apps/chat/src/components/Marketplace/ApplicationLogs.tsx index f22bdd8b68..3f61a44207 100644 --- a/apps/chat/src/components/Marketplace/ApplicationLogs.tsx +++ b/apps/chat/src/components/Marketplace/ApplicationLogs.tsx @@ -1,4 +1,3 @@ -import { UseDismissProps } from '@floating-ui/react'; import { IconDownload, IconRefresh } from '@tabler/icons-react'; import React from 'react'; @@ -16,6 +15,8 @@ import { } from '@/src/store/application/application.reducers'; import { useAppDispatch, useAppSelector } from '@/src/store/hooks'; +import { ALLOW_CLICK_OUTSIDE } from '@/src/constants/dialogs'; + import Modal from '../Common/Modal'; import { Spinner } from '../Common/Spinner'; import Tooltip from '../Common/Tooltip'; @@ -116,8 +117,6 @@ const LogsFooter = ({ entityId }: { entityId: string }) => { ); }; -const modalDismissProps = { outsidePress: true } as UseDismissProps; - interface ApplicationLogsProps { entityId: string; isOpen: boolean; @@ -137,7 +136,7 @@ export const ApplicationLogs = ({ overlayClassName="!z-40" containerClassName="flex w-full flex-col min-h-[350px] xl:max-w-[820px] max-w-[800px]" onClose={onClose} - dismissProps={modalDismissProps} + dismissProps={ALLOW_CLICK_OUTSIDE} > diff --git a/apps/chat/src/components/Promptbar/components/PreviewPromptModal.tsx b/apps/chat/src/components/Promptbar/components/PreviewPromptModal.tsx index a9fd18b2a4..a2813d60f0 100644 --- a/apps/chat/src/components/Promptbar/components/PreviewPromptModal.tsx +++ b/apps/chat/src/components/Promptbar/components/PreviewPromptModal.tsx @@ -1,4 +1,3 @@ -import { UseDismissProps } from '@floating-ui/react'; import { IconFileArrowRight, IconTrashX } from '@tabler/icons-react'; import { MouseEventHandler, useCallback } from 'react'; @@ -23,6 +22,8 @@ import { } from '@/src/store/prompts/prompts.reducers'; import { PublicationActions } from '@/src/store/publication/publication.reducers'; +import { ALLOW_CLICK_OUTSIDE } from '@/src/constants/dialogs'; + import { NotFoundEntity } from '@/src/components/Common/NotFoundEntity'; import Tooltip from '@/src/components/Common/Tooltip'; @@ -33,11 +34,6 @@ import Modal from '../../Common/Modal'; import { PublishActions } from '@epam/ai-dial-shared'; -const modalDismissProps = { - outsidePress: true, - escapeKey: true, -} as UseDismissProps; - interface Props { isOpen: boolean; onDuplicate?: MouseEventHandler; @@ -112,7 +108,7 @@ export const PreviewPromptModal = ({ portalId="theme-main" containerClassName="inline-block w-full overflow-y-auto py-4 md:p-0 align-bottom transition-all xl:max-h-[800px] xl:max-w-[720px] 2xl:max-w-[1000px]" dataQa="preview-prompt-modal" - dismissProps={modalDismissProps} + dismissProps={ALLOW_CLICK_OUTSIDE} headingClassName={classNames( 'px-3 md:p-6', prompt.publicationInfo?.action === PublishActions.DELETE && diff --git a/apps/chat/src/constants/dialogs.ts b/apps/chat/src/constants/dialogs.ts new file mode 100644 index 0000000000..8edbba1d5c --- /dev/null +++ b/apps/chat/src/constants/dialogs.ts @@ -0,0 +1,11 @@ +import { UseDismissProps } from '@floating-ui/react'; + +export const ALLOW_CLICK_OUTSIDE = { + outsidePress: true, + escapeKey: true, +} as UseDismissProps; + +export const DISALLOW_CLICK_OUTSIDE = { + outsidePress: false, + escapeKey: false, +} as UseDismissProps;