diff --git a/web/app/components/apps/__tests__/app-card.spec.tsx b/web/app/components/apps/__tests__/app-card.spec.tsx index c243efa1ea8..b3ed64d22bc 100644 --- a/web/app/components/apps/__tests__/app-card.spec.tsx +++ b/web/app/components/apps/__tests__/app-card.spec.tsx @@ -682,9 +682,13 @@ describe('AppCard', () => { }) it('should star the app from the card action without navigating', async () => { + const user = userEvent.setup() render() - fireEvent.click(screen.getByRole('button', { name: 'app.studio.starApp' })) + const starToggle = screen.getByRole('button', { name: 'app.studio.starApp' }) + expect(starToggle).toHaveAttribute('aria-pressed', 'false') + + await user.click(starToggle) await waitFor(() => { expect(mockStarAppMutation).toHaveBeenCalledWith({ @@ -695,10 +699,14 @@ describe('AppCard', () => { }) it('should unstar the app from the filled star action', async () => { + const user = userEvent.setup() const starredApp = createMockApp({ is_starred: true }) render() - fireEvent.click(screen.getByRole('button', { name: 'app.studio.unstarApp' })) + const starToggle = screen.getByRole('button', { name: 'app.studio.starApp' }) + expect(starToggle).toHaveAttribute('aria-pressed', 'true') + + await user.click(starToggle) await waitFor(() => { expect(mockUnstarAppMutation).toHaveBeenCalledWith({ @@ -724,13 +732,15 @@ describe('AppCard', () => { }) it('should show edit option when dropdown menu is opened', async () => { + const user = userEvent.setup() render() - fireEvent.click(getOperationsTrigger()) + await user.click(getOperationsTrigger()) await waitFor(() => { expect(screen.getByText('app.editApp')).toBeInTheDocument() }) + expect(mockPush).not.toHaveBeenCalled() }) it('should show duplicate option when dropdown menu is opened', async () => { diff --git a/web/app/components/apps/app-card/action-bar/index.tsx b/web/app/components/apps/app-card/action-bar/index.tsx index e96a19e5ea7..157744975c5 100644 --- a/web/app/components/apps/app-card/action-bar/index.tsx +++ b/web/app/components/apps/app-card/action-bar/index.tsx @@ -4,7 +4,7 @@ import type { AppPartial, EnvironmentVariableItemResponse, } from '@dify/contracts/api/console/apps/types.gen' -import type { FormEventHandler, MouseEvent } from 'react' +import type { FormEventHandler } from 'react' import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal' import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal' import { zIconType } from '@dify/contracts/api/console/apps/zod.gen' @@ -24,7 +24,9 @@ import { DropdownMenuTrigger, } from '@langgenius/dify-ui/dropdown-menu' import { Field, FieldControl, FieldLabel } from '@langgenius/dify-ui/field' +import { IconButton } from '@langgenius/dify-ui/icon-button' import { toast } from '@langgenius/dify-ui/toast' +import { Toggle } from '@langgenius/dify-ui/toggle' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' import { useMutation, useSuspenseQuery } from '@tanstack/react-query' import { useAtomValue } from 'jotai' @@ -311,13 +313,10 @@ export const AppCardActionBar = memo( } const handleToggleStar = useCallback( - (e: MouseEvent) => { - e.stopPropagation() - e.preventDefault() - + (pressed: boolean) => { if (isTogglingStar) return - const mutateStar = app.is_starred ? unstarApp : starApp + const mutateStar = pressed ? starApp : unstarApp try { mutateStar( { params: { app_id: app.id } }, @@ -338,7 +337,7 @@ export const AppCardActionBar = memo( ) } }, - [app.id, app.is_starred, isTogglingStar, starApp, t, unstarApp], + [app.id, isTogglingStar, starApp, t, unstarApp], ) const shouldShowEditOption = appACLCapabilities.canEdit @@ -359,6 +358,7 @@ export const AppCardActionBar = memo( const starActionLabel = app.is_starred ? t(($) => $['studio.unstarApp'], { ns: 'app' }) : t(($) => $['studio.starApp'], { ns: 'app' }) + const starToggleLabel = t(($) => $['studio.starApp'], { ns: 'app' }) return ( <> @@ -374,21 +374,23 @@ export const AppCardActionBar = memo( - - + onPressedChange={handleToggleStar} + render={ + + + + } + /> } /> {starActionLabel} @@ -400,33 +402,32 @@ export const AppCardActionBar = memo( onOpenChange={setIsOperationsMenuOpen} > $['operation.exporting'], { ns: 'common' }) - : t(($) => $['operation.moreActionsFor'], { - ns: 'common', - name: app.name, - }) + render={ + $['operation.exporting'], { ns: 'common' }) + : t(($) => $['operation.moreActionsFor'], { + ns: 'common', + name: app.name, + }) + } + disabled={isExporting} + className="data-popup-open:bg-state-base-hover" + > + + } - disabled={isExporting} - className={cn( - 'flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg hover:bg-state-base-hover focus-visible:ring-2 focus-visible:ring-state-accent-solid focus-visible:outline-hidden disabled:cursor-not-allowed data-popup-open:bg-state-base-hover', - )} - onClick={(e) => { - e.stopPropagation() - e.preventDefault() - }} - > - - + />