diff --git a/eslint-suppressions.json b/eslint-suppressions.json index fd915d809d..614dd0b633 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -570,30 +570,6 @@ "count": 2 } }, - "web/app/components/app/overview/customize/index.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, - "web/app/components/app/overview/embedded/index.tsx": { - "no-restricted-imports": { - "count": 1 - }, - "react/set-state-in-effect": { - "count": 1 - } - }, - "web/app/components/app/overview/settings/index.tsx": { - "no-restricted-imports": { - "count": 2 - }, - "react/set-state-in-effect": { - "count": 3 - }, - "regexp/no-unused-capturing-group": { - "count": 1 - } - }, "web/app/components/app/overview/trigger-card.tsx": { "ts/no-explicit-any": { "count": 1 diff --git a/web/app/components/app/overview/customize/__tests__/index.spec.tsx b/web/app/components/app/overview/customize/__tests__/index.spec.tsx index 0e065fcdfe..1f703afcd8 100644 --- a/web/app/components/app/overview/customize/__tests__/index.spec.tsx +++ b/web/app/components/app/overview/customize/__tests__/index.spec.tsx @@ -8,13 +8,6 @@ vi.mock('@/context/i18n', () => ({ useDocLink: () => mockDocLink, })) -// Mock window.open -const mockWindowOpen = vi.fn() -Object.defineProperty(window, 'open', { - value: mockWindowOpen, - writable: true, -}) - describe('CustomizeModal', () => { const defaultProps = { isShow: true, @@ -287,7 +280,7 @@ describe('CustomizeModal', () => { // User interactions tests - verify user actions trigger expected behaviors describe('User Interactions', () => { - it('should call window.open with doc link when way 2 button is clicked', async () => { + it('should render the API docs link for way 2', async () => { // Arrange const props = { ...defaultProps } @@ -298,16 +291,10 @@ describe('CustomizeModal', () => { expect(screen.getByText('appOverview.overview.appInfo.customize.way2.operation')).toBeInTheDocument() }) - const way2Button = screen.getByText('appOverview.overview.appInfo.customize.way2.operation').closest('button') - expect(way2Button).toBeInTheDocument() - fireEvent.click(way2Button!) - - // Assert - expect(mockWindowOpen).toHaveBeenCalledTimes(1) - expect(mockWindowOpen).toHaveBeenCalledWith( - expect.stringContaining('/use-dify/publish/developing-with-apis'), - '_blank', - ) + const way2Link = screen.getByRole('link', { name: /way2\.operation/i }) + expect(way2Link).toHaveAttribute('href', expect.stringContaining('/use-dify/publish/developing-with-apis')) + expect(way2Link).toHaveAttribute('target', '_blank') + expect(way2Link).toHaveAttribute('rel', 'noopener noreferrer') }) it('should call onClose when modal close button is clicked', async () => { diff --git a/web/app/components/app/overview/customize/index.tsx b/web/app/components/app/overview/customize/index.tsx index e4b8aabf69..46527c30f9 100644 --- a/web/app/components/app/overview/customize/index.tsx +++ b/web/app/components/app/overview/customize/index.tsx @@ -1,10 +1,9 @@ 'use client' import type { FC } from 'react' -import { ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline' import { Button } from '@langgenius/dify-ui/button' +import { Dialog, DialogCloseButton, DialogContent, DialogDescription, DialogTitle } from '@langgenius/dify-ui/dialog' import * as React from 'react' import { useTranslation } from 'react-i18next' -import Modal from '@/app/components/base/modal' import Tag from '@/app/components/base/tag' import { useDocLink } from '@/context/i18n' import { AppModeEnum } from '@/types/app' @@ -25,7 +24,7 @@ const StepNum: FC<{ children: React.ReactNode }> = ({ children }) => ( const GithubIcon = ({ className }: { className: string }) => { return ( - + ) @@ -43,90 +42,85 @@ const CustomizeModal: FC = ({ const { t } = useTranslation() const docLink = useDocLink() const isChatApp = mode === AppModeEnum.CHAT || mode === AppModeEnum.ADVANCED_CHAT + const apiDocLink = docLink('/use-dify/publish/developing-with-apis') return ( - -
- - {t(`${prefixCustomize}.way`, { ns: 'appOverview' })} - {' '} - 1 - -

{t(`${prefixCustomize}.way1.name`, { ns: 'appOverview' })}

-
- 1 -
-
{t(`${prefixCustomize}.way1.step1`, { ns: 'appOverview' })}
-
{t(`${prefixCustomize}.way1.step1Tip`, { ns: 'appOverview' })}
- - - +
-
-
- 2 -
-
{t(`${prefixCustomize}.way1.step2`, { ns: 'appOverview' })}
-
{t(`${prefixCustomize}.way1.step2Tip`, { ns: 'appOverview' })}
- - - +
- -
- 3 -
-
{t(`${prefixCustomize}.way1.step3`, { ns: 'appOverview' })}
-
{t(`${prefixCustomize}.way1.step3Tip`, { ns: 'appOverview' })}
-
-              NEXT_PUBLIC_APP_ID=
-              {`'${appId}'`}
-              {' '}
-              
- NEXT_PUBLIC_APP_KEY= - {'\'\''} - {' '} -
- NEXT_PUBLIC_API_URL= - {`'${api_base_url}'`} -
+
+ 3 +
+
{t(`${prefixCustomize}.way1.step3`, { ns: 'appOverview' })}
+
{t(`${prefixCustomize}.way1.step3Tip`, { ns: 'appOverview' })}
+
+                NEXT_PUBLIC_APP_ID=
+                {`'${appId}'`}
+                {' '}
+                
+ NEXT_PUBLIC_APP_KEY= + {'\'\''} + {' '} +
+ NEXT_PUBLIC_API_URL= + {`'${api_base_url}'`} +
+
-
-
-
- - {t(`${prefixCustomize}.way`, { ns: 'appOverview' })} - {' '} - 2 - -

{t(`${prefixCustomize}.way2.name`, { ns: 'appOverview' })}

- -
- + +
+ + {t(`${prefixCustomize}.way`, { ns: 'appOverview' })} + {' '} + 2 + +

{t(`${prefixCustomize}.way2.name`, { ns: 'appOverview' })}

+ +
+ + ) } diff --git a/web/app/components/app/overview/embedded/index.tsx b/web/app/components/app/overview/embedded/index.tsx index e810c7f1eb..12203178f1 100644 --- a/web/app/components/app/overview/embedded/index.tsx +++ b/web/app/components/app/overview/embedded/index.tsx @@ -1,17 +1,13 @@ import type { SiteInfo } from '@/models/share' import { cn } from '@langgenius/dify-ui/cn' +import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@langgenius/dify-ui/dialog' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' -import { - RiClipboardFill, - RiClipboardLine, -} from '@remixicon/react' import copy from 'copy-to-clipboard' import * as React from 'react' -import { useEffect, useState } from 'react' +import { useState } from 'react' import { useTranslation } from 'react-i18next' import ActionButton from '@/app/components/base/action-button' import { useThemeContext } from '@/app/components/base/chat/embedded-chatbot/theme/theme-context' -import Modal from '@/app/components/base/modal' import { IS_CE_EDITION } from '@/config' import { useAppContext } from '@/context/app-context' import { basePath } from '@/utils/var' @@ -86,16 +82,18 @@ const prefixEmbedded = 'overview.appInfo.embedded' type Option = keyof typeof OPTION_MAP -type OptionStatus = { - iframe: boolean - scripts: boolean - chromePlugin: boolean +const OPTIONS: Option[] = ['iframe', 'scripts', 'chromePlugin'] + +const optionIconClassName: Record = { + iframe: style.iframeIcon!, + scripts: style.scriptsIcon!, + chromePlugin: style.chromePluginIcon!, } const Embedded = ({ siteInfo, isShow, onClose, appBaseUrl, accessToken, className }: Props) => { const { t } = useTranslation() const [option, setOption] = useState