fix: create app from template modal has no backdrop (#36987)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Joel 2026-06-03 14:14:46 +08:00 committed by GitHub
parent b96ea94505
commit 86af36429d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 22 additions and 29 deletions

View File

@ -2413,11 +2413,6 @@
"count": 2
}
},
"web/app/components/explore/create-app-modal/index.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"web/app/components/explore/try-app/tab.tsx": {
"erasable-syntax-only/enums": {
"count": 1

View File

@ -1,6 +1,6 @@
import type { CreateAppModalProps } from '../index'
import type { UsagePlanInfo } from '@/app/components/billing/type'
import { act, fireEvent, render, screen } from '@testing-library/react'
import { act, fireEvent, render, screen, waitFor, within } from '@testing-library/react'
import * as React from 'react'
import { createMockPlan, createMockPlanTotal, createMockPlanUsage } from '@/__mocks__/provider-context'
import { Plan } from '@/app/components/billing/type'
@ -107,13 +107,19 @@ const setup = async (overrides: Partial<CreateAppModalProps> = {}) => {
const getAppIconTrigger = (): HTMLElement => {
const nameInput = screen.getByPlaceholderText('app.newApp.appNamePlaceholder')
const iconRow = nameInput.parentElement?.parentElement
const iconRow = nameInput.parentElement
const iconTrigger = iconRow?.firstElementChild
if (!(iconTrigger instanceof HTMLElement))
throw new Error('Failed to locate app icon trigger')
return iconTrigger
}
const openAppIconPicker = () => {
fireEvent.click(getAppIconTrigger())
return screen.getByRole('dialog', { name: 'app.iconPicker.emoji' })
}
describe('CreateAppModal', () => {
beforeEach(() => {
vi.clearAllMocks()
@ -322,13 +328,15 @@ describe('CreateAppModal', () => {
appIconUrl: 'https://example.com/icon.png',
})
fireEvent.click(getAppIconTrigger())
const pickerDialog = openAppIconPicker()
expect(screen.getByRole('button', { name: 'app.iconPicker.cancel' }))!.toBeInTheDocument()
expect(within(pickerDialog).getByRole('button', { name: 'app.iconPicker.cancel' }))!.toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: 'app.iconPicker.cancel' }))
fireEvent.click(within(pickerDialog).getByRole('button', { name: 'app.iconPicker.cancel' }))
expect(screen.queryByRole('button', { name: 'app.iconPicker.cancel' })).not.toBeInTheDocument()
await waitFor(() => {
expect(screen.queryByRole('button', { name: 'app.iconPicker.cancel' })).not.toBeInTheDocument()
})
})
it('should update icon payload when selecting emoji and confirming', async () => {
@ -340,16 +348,11 @@ describe('CreateAppModal', () => {
appIconUrl: 'https://example.com/icon.png',
})
fireEvent.click(getAppIconTrigger())
const pickerDialog = openAppIconPicker()
const categoryLabel = screen.getByText('people')
const emojiGrid = categoryLabel.nextElementSibling
const clickableEmojiWrapper = emojiGrid?.firstElementChild
if (!(clickableEmojiWrapper instanceof HTMLElement))
throw new Error('Failed to locate emoji wrapper')
fireEvent.click(clickableEmojiWrapper)
fireEvent.click(within(pickerDialog).getByRole('button', { name: '😀' }))
fireEvent.click(screen.getByRole('button', { name: 'app.iconPicker.ok' }))
fireEvent.click(within(pickerDialog).getByRole('button', { name: 'app.iconPicker.ok' }))
fireEvent.click(screen.getByRole('button', { name: /common\.operation\.create/ }))
await act(async () => {
@ -378,15 +381,10 @@ describe('CreateAppModal', () => {
appIconBackground: '#FFEAD5',
})
fireEvent.click(getAppIconTrigger())
const pickerDialog = openAppIconPicker()
const colorOption = Array.from(document.querySelectorAll('[style^="background:"]'))
.find(element => element.getAttribute('style')?.includes('#E4FBCC'))
if (!(colorOption instanceof HTMLElement) || !(colorOption.parentElement instanceof HTMLElement))
throw new Error('Failed to locate background color option')
fireEvent.click(colorOption.parentElement)
fireEvent.click(screen.getByRole('button', { name: 'app.iconPicker.ok' }))
fireEvent.click(within(pickerDialog).getByRole('button', { name: '#E4FBCC' }))
fireEvent.click(within(pickerDialog).getByRole('button', { name: 'app.iconPicker.ok' }))
fireEvent.click(screen.getByRole('button', { name: /common\.operation\.create/ }))
await act(async () => {

View File

@ -2,6 +2,7 @@
import type { AppIconType } from '@/types/app'
import { Button } from '@langgenius/dify-ui/button'
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@langgenius/dify-ui/dialog'
import { Input } from '@langgenius/dify-ui/input'
import { Kbd, KbdGroup } from '@langgenius/dify-ui/kbd'
import { Switch } from '@langgenius/dify-ui/switch'
import { Textarea } from '@langgenius/dify-ui/textarea'
@ -12,7 +13,6 @@ import * as React from 'react'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import AppIcon from '@/app/components/base/app-icon'
import Input from '@/app/components/base/input'
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
import { useProviderContext } from '@/context/provider-context'
import { AppModeEnum } from '@/types/app'
@ -114,7 +114,7 @@ const CreateAppModal = ({
return (
<>
<Dialog open={show} onOpenChange={open => !open && onHide()} disablePointerDismissal>
<DialogContent className="px-8">
<DialogContent backdropProps={{ forceRender: true }} className="px-8">
<DialogCloseButton />
{isEditModal && (
<DialogTitle className="mb-9 text-xl leading-[30px] font-semibold text-text-primary">{t('editAppTitle', { ns: 'app' })}</DialogTitle>