feat: add loading state to regenerate and generate buttons in JSON schema generator

This commit is contained in:
twwu 2025-03-27 11:39:20 +08:00
parent e5e9ab0adb
commit b52a0d6fa5
4 changed files with 44 additions and 31 deletions

View File

@ -9,6 +9,7 @@ import { getValidationErrorMessage, validateSchemaAgainstDraft7 } from '../../..
type GeneratedResultProps = { type GeneratedResultProps = {
schema: SchemaRoot schema: SchemaRoot
isGenerating: boolean
onBack: () => void onBack: () => void
onRegenerate: () => void onRegenerate: () => void
onClose: () => void onClose: () => void
@ -17,6 +18,7 @@ type GeneratedResultProps = {
const GeneratedResult: FC<GeneratedResultProps> = ({ const GeneratedResult: FC<GeneratedResultProps> = ({
schema, schema,
isGenerating,
onBack, onBack,
onRegenerate, onRegenerate,
onClose, onClose,
@ -87,7 +89,13 @@ const GeneratedResult: FC<GeneratedResultProps> = ({
<span>{t('workflow.nodes.llm.jsonSchema.back')}</span> <span>{t('workflow.nodes.llm.jsonSchema.back')}</span>
</Button> </Button>
<div className='flex items-center gap-x-2'> <div className='flex items-center gap-x-2'>
<Button variant='secondary' className='flex items-center gap-x-0.5' onClick={onRegenerate}> <Button
variant='secondary'
className='flex items-center gap-x-0.5'
onClick={onRegenerate}
disabled={isGenerating}
loading={isGenerating}
>
<RiSparklingLine className='h-4 w-4' /> <RiSparklingLine className='h-4 w-4' />
<span>{t('workflow.nodes.llm.jsonSchema.regenerate')}</span> <span>{t('workflow.nodes.llm.jsonSchema.regenerate')}</span>
</Button> </Button>

View File

@ -97,7 +97,7 @@ export const JsonSchemaGenerator: FC<JsonSchemaGeneratorProps> = ({
) )
}, []) }, [])
const { mutateAsync: generateStructuredOutputRules } = useGenerateStructuredOutputRules() const { mutateAsync: generateStructuredOutputRules, isPending: isGenerating } = useGenerateStructuredOutputRules()
const generateSchema = useCallback(async () => { const generateSchema = useCallback(async () => {
const { output, error } = await generateStructuredOutputRules({ instruction, model_config: model! }) const { output, error } = await generateStructuredOutputRules({ instruction, model_config: model! })
@ -159,6 +159,7 @@ export const JsonSchemaGenerator: FC<JsonSchemaGeneratorProps> = ({
<PromptEditor <PromptEditor
instruction={instruction} instruction={instruction}
model={model} model={model}
isGenerating={isGenerating}
onInstructionChange={setInstruction} onInstructionChange={setInstruction}
onCompletionParamsChange={handleCompletionParamsChange} onCompletionParamsChange={handleCompletionParamsChange}
onGenerate={handleGenerate} onGenerate={handleGenerate}
@ -169,6 +170,7 @@ export const JsonSchemaGenerator: FC<JsonSchemaGeneratorProps> = ({
{view === GeneratorView.result && ( {view === GeneratorView.result && (
<GeneratedResult <GeneratedResult
schema={schema!} schema={schema!}
isGenerating={isGenerating}
onBack={goBackToPromptEditor} onBack={goBackToPromptEditor}
onRegenerate={handleRegenerate} onRegenerate={handleRegenerate}
onApply={handleApply} onApply={handleApply}

View File

@ -19,6 +19,7 @@ export type ModelInfo = {
type PromptEditorProps = { type PromptEditorProps = {
instruction: string instruction: string
model: Model model: Model
isGenerating: boolean
onInstructionChange: (instruction: string) => void onInstructionChange: (instruction: string) => void
onCompletionParamsChange: (newParams: FormValue) => void onCompletionParamsChange: (newParams: FormValue) => void
onModelChange: (model: ModelInfo) => void onModelChange: (model: ModelInfo) => void
@ -29,6 +30,7 @@ type PromptEditorProps = {
const PromptEditor: FC<PromptEditorProps> = ({ const PromptEditor: FC<PromptEditorProps> = ({
instruction, instruction,
model, model,
isGenerating,
onInstructionChange, onInstructionChange,
onCompletionParamsChange, onCompletionParamsChange,
onClose, onClose,
@ -96,6 +98,8 @@ const PromptEditor: FC<PromptEditorProps> = ({
variant='primary' variant='primary'
className='flex items-center gap-x-0.5' className='flex items-center gap-x-0.5'
onClick={onGenerate} onClick={onGenerate}
disabled={isGenerating}
loading={isGenerating}
> >
<RiSparklingFill className='h-4 w-4' /> <RiSparklingFill className='h-4 w-4' />
<span>{t('workflow.nodes.llm.jsonSchema.generate')}</span> <span>{t('workflow.nodes.llm.jsonSchema.generate')}</span>

View File

@ -1,5 +1,4 @@
import React, { type FC, useCallback, useState } from 'react' import React, { type FC, useCallback, useState } from 'react'
import { RiArrowDownDoubleLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Divider from '@/app/components/base/divider' import Divider from '@/app/components/base/divider'
import Textarea from '@/app/components/base/textarea' import Textarea from '@/app/components/base/textarea'
@ -18,7 +17,7 @@ const AdvancedOptions: FC<AdvancedOptionsProps> = ({
options, options,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false) // const [showAdvancedOptions, setShowAdvancedOptions] = useState(false)
const [enumValue, setEnumValue] = useState(options.enum) const [enumValue, setEnumValue] = useState(options.enum)
const handleEnumChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => { const handleEnumChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
@ -29,13 +28,13 @@ const AdvancedOptions: FC<AdvancedOptionsProps> = ({
onChange({ enum: e.target.value }) onChange({ enum: e.target.value })
}, [onChange]) }, [onChange])
const handleToggleAdvancedOptions = useCallback(() => { // const handleToggleAdvancedOptions = useCallback(() => {
setShowAdvancedOptions(prev => !prev) // setShowAdvancedOptions(prev => !prev)
}, []) // }, [])
return ( return (
<div className='border-t border-divider-subtle'> <div className='border-t border-divider-subtle'>
{showAdvancedOptions ? ( {/* {showAdvancedOptions ? ( */}
<div className='flex flex-col gap-y-1 px-2 py-1.5'> <div className='flex flex-col gap-y-1 px-2 py-1.5'>
<div className='flex w-full items-center gap-x-2'> <div className='flex w-full items-center gap-x-2'>
<span className='system-2xs-medium-uppercase text-text-tertiary'> <span className='system-2xs-medium-uppercase text-text-tertiary'>
@ -59,7 +58,7 @@ const AdvancedOptions: FC<AdvancedOptionsProps> = ({
/> />
</div> </div>
</div> </div>
) : ( {/* ) : (
<button <button
type='button' type='button'
className='flex items-center gap-x-0.5 pb-1 pl-1.5 pr-2 pt-2' className='flex items-center gap-x-0.5 pb-1 pl-1.5 pr-2 pt-2'
@ -70,7 +69,7 @@ const AdvancedOptions: FC<AdvancedOptionsProps> = ({
{t('workflow.nodes.llm.jsonSchema.showAdvancedOptions')} {t('workflow.nodes.llm.jsonSchema.showAdvancedOptions')}
</span> </span>
</button> </button>
)} )} */}
</div> </div>
) )
} }