mirror of
https://github.com/langgenius/dify.git
synced 2026-06-24 13:01:16 +08:00
feat(web): remove snippet edit prompts
This commit is contained in:
parent
b0d6567a63
commit
6928c1b4ab
@ -1,46 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { expectLoadingButton } from '@/test/button'
|
||||
import SaveBeforeLeavingDialog from '../save-before-leaving-dialog'
|
||||
|
||||
describe('SaveBeforeLeavingDialog', () => {
|
||||
it('should render the trigger and call discard or save actions', async () => {
|
||||
const user = userEvent.setup()
|
||||
const onDiscard = vi.fn()
|
||||
const onSave = vi.fn()
|
||||
|
||||
render(
|
||||
<SaveBeforeLeavingDialog
|
||||
open
|
||||
trigger={<button type="button">leave snippet</button>}
|
||||
onDiscard={onDiscard}
|
||||
onSave={onSave}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('snippet.saveBeforeLeavingTitle')).toBeInTheDocument()
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'snippet.doNotSave' }))
|
||||
await user.click(screen.getByRole('button', { name: 'snippet.saveAndExit' }))
|
||||
|
||||
expect(onDiscard).toHaveBeenCalledTimes(1)
|
||||
expect(onSave).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should disable destructive and save actions according to dialog state', () => {
|
||||
render(
|
||||
<SaveBeforeLeavingDialog
|
||||
open
|
||||
disabled
|
||||
saveDisabled
|
||||
loading
|
||||
onDiscard={vi.fn()}
|
||||
onSave={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByRole('button', { name: 'snippet.continueEditing' })).toBeDisabled()
|
||||
expect(screen.getByRole('button', { name: 'snippet.doNotSave' })).toBeDisabled()
|
||||
expectLoadingButton(screen.getByRole('button', { name: 'snippet.saveAndExit' }))
|
||||
})
|
||||
})
|
||||
@ -41,22 +41,14 @@ describe('SnippetChildren', () => {
|
||||
|
||||
it('should render snippet header and workflow panel with forwarded props', () => {
|
||||
const callbacks = {
|
||||
onCancel: vi.fn(),
|
||||
onEdit: vi.fn(),
|
||||
onExitEditing: vi.fn(),
|
||||
onExitEditingWithoutSave: vi.fn(),
|
||||
onPublish: vi.fn(),
|
||||
onSaveAndExitEditing: vi.fn(),
|
||||
}
|
||||
|
||||
render(
|
||||
<SnippetChildren
|
||||
snippetId="snippet-1"
|
||||
fields={fields}
|
||||
canDiscardChanges
|
||||
canSave
|
||||
hasDraftChanges
|
||||
isEditing
|
||||
isPublishing={false}
|
||||
{...callbacks}
|
||||
/>,
|
||||
@ -66,10 +58,7 @@ describe('SnippetChildren', () => {
|
||||
expect(screen.getByTestId('snippet-workflow-panel')).toBeInTheDocument()
|
||||
expect(capturedHeaderProps).toEqual(expect.objectContaining({
|
||||
snippetId: 'snippet-1',
|
||||
canDiscardChanges: true,
|
||||
canSave: true,
|
||||
hasDraftChanges: true,
|
||||
isEditing: true,
|
||||
isPublishing: false,
|
||||
...callbacks,
|
||||
}))
|
||||
|
||||
@ -1,78 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import type { ReactElement } from 'react'
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogActions,
|
||||
AlertDialogCancelButton,
|
||||
AlertDialogConfirmButton,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from '@langgenius/dify-ui/alert-dialog'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type SaveBeforeLeavingDialogProps = {
|
||||
open?: boolean
|
||||
onOpenChange?: (open: boolean) => void
|
||||
trigger?: ReactElement
|
||||
disabled?: boolean
|
||||
saveDisabled?: boolean
|
||||
loading?: boolean
|
||||
onDiscard: () => void | Promise<void>
|
||||
onSave: () => void | Promise<void>
|
||||
}
|
||||
|
||||
const SaveBeforeLeavingDialog = ({
|
||||
open,
|
||||
onOpenChange,
|
||||
trigger,
|
||||
disabled,
|
||||
saveDisabled,
|
||||
loading,
|
||||
onDiscard,
|
||||
onSave,
|
||||
}: SaveBeforeLeavingDialogProps) => {
|
||||
const { t } = useTranslation('snippet')
|
||||
|
||||
return (
|
||||
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
||||
{trigger && (
|
||||
<AlertDialogTrigger render={trigger} />
|
||||
)}
|
||||
<AlertDialogContent className="w-165">
|
||||
<div className="space-y-2 p-8 pb-12">
|
||||
<AlertDialogTitle className="title-2xl-semi-bold text-text-primary">
|
||||
{t('saveBeforeLeavingTitle')}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription className="system-md-regular text-text-secondary">
|
||||
{t('saveBeforeLeavingDescription')}
|
||||
</AlertDialogDescription>
|
||||
</div>
|
||||
<AlertDialogActions className="px-8 pt-0">
|
||||
<AlertDialogCancelButton disabled={disabled || loading}>
|
||||
{t('continueEditing')}
|
||||
</AlertDialogCancelButton>
|
||||
<AlertDialogConfirmButton
|
||||
tone="destructive"
|
||||
disabled={disabled || loading}
|
||||
onClick={onDiscard}
|
||||
>
|
||||
{t('doNotSave')}
|
||||
</AlertDialogConfirmButton>
|
||||
<AlertDialogConfirmButton
|
||||
tone="default"
|
||||
loading={loading}
|
||||
disabled={disabled || saveDisabled || loading}
|
||||
onClick={onSave}
|
||||
>
|
||||
{t('saveAndExit')}
|
||||
</AlertDialogConfirmButton>
|
||||
</AlertDialogActions>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default SaveBeforeLeavingDialog
|
||||
@ -1,29 +0,0 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import CancelChanges from '../cancel-changes'
|
||||
|
||||
describe('CancelChanges', () => {
|
||||
it('should render editing state without discard action when changes cannot be discarded', () => {
|
||||
render(<CancelChanges canDiscardChanges={false} onCancel={vi.fn()} />)
|
||||
|
||||
expect(screen.queryByRole('button', { name: 'snippet.discardDraft' })).not.toBeInTheDocument()
|
||||
expect(screen.getByText('snippet.editingDraft')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should confirm before discarding draft changes', async () => {
|
||||
const user = userEvent.setup()
|
||||
const onCancel = vi.fn().mockResolvedValue(undefined)
|
||||
|
||||
render(<CancelChanges canDiscardChanges onCancel={onCancel} />)
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'snippet.discardDraft' }))
|
||||
|
||||
expect(screen.getByText('snippet.discardChangesTitle')).toBeInTheDocument()
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'snippet.discardChanges' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(onCancel).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,81 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogActions,
|
||||
AlertDialogCancelButton,
|
||||
AlertDialogConfirmButton,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from '@langgenius/dify-ui/alert-dialog'
|
||||
import { memo, useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type CancelChangesProps = {
|
||||
canDiscardChanges: boolean
|
||||
onCancel: () => void | Promise<void>
|
||||
}
|
||||
|
||||
const CancelChanges = ({
|
||||
canDiscardChanges,
|
||||
onCancel,
|
||||
}: CancelChangesProps) => {
|
||||
const { t } = useTranslation('snippet')
|
||||
const [open, setOpen] = useState(false)
|
||||
const [isDiscarding, setIsDiscarding] = useState(false)
|
||||
|
||||
const handleDiscardChanges = useCallback(async () => {
|
||||
setIsDiscarding(true)
|
||||
try {
|
||||
await onCancel()
|
||||
setOpen(false)
|
||||
}
|
||||
finally {
|
||||
setIsDiscarding(false)
|
||||
}
|
||||
}, [onCancel])
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 system-sm-regular">
|
||||
{canDiscardChanges && (
|
||||
<>
|
||||
<AlertDialog open={open} onOpenChange={setOpen}>
|
||||
<AlertDialogTrigger
|
||||
className="system-sm-semibold text-text-accent hover:text-text-accent-secondary"
|
||||
>
|
||||
{t('discardDraft')}
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent className="w-160">
|
||||
<div className="space-y-2 p-8 pb-12">
|
||||
<AlertDialogTitle className="title-2xl-semi-bold text-text-primary">
|
||||
{t('discardChangesTitle')}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription className="system-md-regular text-text-secondary">
|
||||
{t('discardChangesDescription')}
|
||||
</AlertDialogDescription>
|
||||
</div>
|
||||
<AlertDialogActions className="px-8 pt-0">
|
||||
<AlertDialogCancelButton disabled={isDiscarding}>
|
||||
{t('continueEditing')}
|
||||
</AlertDialogCancelButton>
|
||||
<AlertDialogConfirmButton
|
||||
loading={isDiscarding}
|
||||
disabled={isDiscarding}
|
||||
onClick={handleDiscardChanges}
|
||||
>
|
||||
{t('discardChanges')}
|
||||
</AlertDialogConfirmButton>
|
||||
</AlertDialogActions>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
<span className="text-text-quaternary">·</span>
|
||||
</>
|
||||
)}
|
||||
<span className="text-text-tertiary">{t('editingDraft')}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(CancelChanges)
|
||||
Loading…
Reference in New Issue
Block a user