### What problem does this PR solve? Feat: Replace the submit form button with ButtonLoading #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.19.0
| import RaptorFormFields, { | import RaptorFormFields, { | ||||
| showRaptorParseConfiguration, | showRaptorParseConfiguration, | ||||
| } from '../parse-configuration/raptor-form-fields'; | } from '../parse-configuration/raptor-form-fields'; | ||||
| import { ButtonLoading } from '../ui/button'; | |||||
| import { Input } from '../ui/input'; | import { Input } from '../ui/input'; | ||||
| import { LoadingButton } from '../ui/loading-button'; | |||||
| import { RAGFlowSelect } from '../ui/select'; | import { RAGFlowSelect } from '../ui/select'; | ||||
| import { DynamicPageRange } from './dynamic-page-range'; | import { DynamicPageRange } from './dynamic-page-range'; | ||||
| import { useFetchParserListOnMount, useShowAutoKeywords } from './hooks'; | import { useFetchParserListOnMount, useShowAutoKeywords } from './hooks'; | ||||
| </form> | </form> | ||||
| </Form> | </Form> | ||||
| <DialogFooter> | <DialogFooter> | ||||
| <LoadingButton type="submit" form={FormId} loading={loading}> | |||||
| <ButtonLoading type="submit" form={FormId} loading={loading}> | |||||
| {t('common.save')} | {t('common.save')} | ||||
| </LoadingButton> | |||||
| </ButtonLoading> | |||||
| </DialogFooter> | </DialogFooter> | ||||
| </DialogContent> | </DialogContent> | ||||
| </Dialog> | </Dialog> |
| import { Button } from '@/components/ui/button'; | |||||
| import { ButtonLoading } from '@/components/ui/button'; | |||||
| import { | import { | ||||
| Dialog, | Dialog, | ||||
| DialogContent, | DialogContent, | ||||
| ); | ); | ||||
| } | } | ||||
| export function FileUploadDialog({ hideModal, onOk }: IModalProps<File[]>) { | |||||
| export function FileUploadDialog({ | |||||
| hideModal, | |||||
| onOk, | |||||
| loading, | |||||
| }: IModalProps<File[]>) { | |||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const [files, setFiles] = useState<File[]>([]); | const [files, setFiles] = useState<File[]>([]); | ||||
| </DialogHeader> | </DialogHeader> | ||||
| <UploaderTabs setFiles={setFiles}></UploaderTabs> | <UploaderTabs setFiles={setFiles}></UploaderTabs> | ||||
| <DialogFooter> | <DialogFooter> | ||||
| <Button | |||||
| type="submit" | |||||
| variant={'tertiary'} | |||||
| size={'sm'} | |||||
| onClick={handleOk} | |||||
| > | |||||
| <ButtonLoading type="submit" onClick={handleOk} loading={loading}> | |||||
| {t('common.save')} | {t('common.save')} | ||||
| </Button> | |||||
| </ButtonLoading> | |||||
| </DialogFooter> | </DialogFooter> | ||||
| </DialogContent> | </DialogContent> | ||||
| </Dialog> | </Dialog> |
| DialogHeader, | DialogHeader, | ||||
| DialogTitle, | DialogTitle, | ||||
| } from '@/components/ui/dialog'; | } from '@/components/ui/dialog'; | ||||
| import { LoadingButton } from '@/components/ui/loading-button'; | |||||
| import { IModalProps } from '@/interfaces/common'; | import { IModalProps } from '@/interfaces/common'; | ||||
| import { TagRenameId } from '@/pages/add-knowledge/constant'; | import { TagRenameId } from '@/pages/add-knowledge/constant'; | ||||
| import { ReactNode } from 'react'; | import { ReactNode } from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { ButtonLoading } from '../ui/button'; | |||||
| import { RenameForm } from './rename-form'; | import { RenameForm } from './rename-form'; | ||||
| export function RenameDialog({ | export function RenameDialog({ | ||||
| onOk={onOk} | onOk={onOk} | ||||
| ></RenameForm> | ></RenameForm> | ||||
| <DialogFooter> | <DialogFooter> | ||||
| <LoadingButton type="submit" form={TagRenameId} loading={loading}> | |||||
| <ButtonLoading type="submit" form={TagRenameId} loading={loading}> | |||||
| {t('common.save')} | {t('common.save')} | ||||
| </LoadingButton> | |||||
| </ButtonLoading> | |||||
| </DialogFooter> | </DialogFooter> | ||||
| </DialogContent> | </DialogContent> | ||||
| </Dialog> | </Dialog> |
| import * as React from 'react'; | import * as React from 'react'; | ||||
| import { cn } from '@/lib/utils'; | import { cn } from '@/lib/utils'; | ||||
| import { Loader2 } from 'lucide-react'; | |||||
| const buttonVariants = cva( | const buttonVariants = cva( | ||||
| 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', | 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', | ||||
| ); | ); | ||||
| Button.displayName = 'Button'; | Button.displayName = 'Button'; | ||||
| export const ButtonLoading = React.forwardRef< | |||||
| HTMLButtonElement, | |||||
| ButtonProps & { loading?: boolean } | |||||
| >( | |||||
| ( | |||||
| { | |||||
| className, | |||||
| variant, | |||||
| size, | |||||
| asChild = false, | |||||
| children, | |||||
| loading = false, | |||||
| disabled, | |||||
| ...props | |||||
| }, | |||||
| ref, | |||||
| ) => { | |||||
| const Comp = asChild ? Slot : 'button'; | |||||
| return ( | |||||
| <Comp | |||||
| className={cn(buttonVariants({ variant, size, className }))} | |||||
| ref={ref} | |||||
| {...props} | |||||
| disabled={loading || disabled} | |||||
| > | |||||
| {loading && <Loader2 className="animate-spin" />} | |||||
| {children} | |||||
| </Comp> | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| ButtonLoading.displayName = 'ButtonLoading'; | |||||
| export { Button, buttonVariants }; | export { Button, buttonVariants }; |
| DialogHeader, | DialogHeader, | ||||
| DialogTitle, | DialogTitle, | ||||
| } from '@/components/ui/dialog'; | } from '@/components/ui/dialog'; | ||||
| import { LoadingButton } from '@/components/ui/loading-button'; | |||||
| import { IModalProps } from '@/interfaces/common'; | import { IModalProps } from '@/interfaces/common'; | ||||
| import { TagRenameId } from '@/pages/add-knowledge/constant'; | import { TagRenameId } from '@/pages/add-knowledge/constant'; | ||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { useForm } from 'react-hook-form'; | import { useForm } from 'react-hook-form'; | ||||
| import { z } from 'zod'; | import { z } from 'zod'; | ||||
| import { ButtonLoading } from '@/components/ui/button'; | |||||
| import { | import { | ||||
| Form, | Form, | ||||
| FormControl, | FormControl, | ||||
| </form> | </form> | ||||
| </Form> | </Form> | ||||
| <DialogFooter> | <DialogFooter> | ||||
| <LoadingButton type="submit" form={TagRenameId} loading={loading}> | |||||
| <ButtonLoading type="submit" form={TagRenameId} loading={loading}> | |||||
| {t('common.save')} | {t('common.save')} | ||||
| </LoadingButton> | |||||
| </ButtonLoading> | |||||
| </DialogFooter> | </DialogFooter> | ||||
| </DialogContent> | </DialogContent> | ||||
| </Dialog> | </Dialog> |
| import { ButtonLoading } from '@/components/ui/button'; | |||||
| import { | import { | ||||
| Dialog, | Dialog, | ||||
| DialogContent, | DialogContent, | ||||
| FormLabel, | FormLabel, | ||||
| FormMessage, | FormMessage, | ||||
| } from '@/components/ui/form'; | } from '@/components/ui/form'; | ||||
| import { LoadingButton } from '@/components/ui/loading-button'; | |||||
| import { MultiSelect } from '@/components/ui/multi-select'; | import { MultiSelect } from '@/components/ui/multi-select'; | ||||
| import { useSelectKnowledgeOptions } from '@/hooks/knowledge-hooks'; | import { useSelectKnowledgeOptions } from '@/hooks/knowledge-hooks'; | ||||
| import { IModalProps } from '@/interfaces/common'; | import { IModalProps } from '@/interfaces/common'; | ||||
| onConnectToKnowledgeOk={onConnectToKnowledgeOk} | onConnectToKnowledgeOk={onConnectToKnowledgeOk} | ||||
| ></LinkToDatasetForm> | ></LinkToDatasetForm> | ||||
| <DialogFooter> | <DialogFooter> | ||||
| <LoadingButton | |||||
| type="submit" | |||||
| variant={'tertiary'} | |||||
| form={FormId} | |||||
| loading={loading} | |||||
| > | |||||
| <ButtonLoading type="submit" form={FormId} loading={loading}> | |||||
| <div className="flex gap-2 items-center"> | <div className="flex gap-2 items-center"> | ||||
| <Link2 /> Save | <Link2 /> Save | ||||
| </div> | </div> | ||||
| </LoadingButton> | |||||
| </ButtonLoading> | |||||
| </DialogFooter> | </DialogFooter> | ||||
| </DialogContent> | </DialogContent> | ||||
| </Dialog> | </Dialog> |
| AsyncTreeSelect, | AsyncTreeSelect, | ||||
| TreeNodeType, | TreeNodeType, | ||||
| } from '@/components/ui/async-tree-select'; | } from '@/components/ui/async-tree-select'; | ||||
| import { Button } from '@/components/ui/button'; | |||||
| import { ButtonLoading } from '@/components/ui/button'; | |||||
| import { | import { | ||||
| Dialog, | Dialog, | ||||
| DialogContent, | DialogContent, | ||||
| import { useCallback, useState } from 'react'; | import { useCallback, useState } from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| export function MoveDialog({ hideModal, onOk }: IModalProps<any>) { | |||||
| export function MoveDialog({ hideModal, onOk, loading }: IModalProps<any>) { | |||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const { fetchList } = useFetchPureFileList(); | const { fetchList } = useFetchPureFileList(); | ||||
| ></AsyncTreeSelect> | ></AsyncTreeSelect> | ||||
| </div> | </div> | ||||
| <DialogFooter> | <DialogFooter> | ||||
| <Button | |||||
| <ButtonLoading | |||||
| type="submit" | type="submit" | ||||
| onClick={handleSubmit} | onClick={handleSubmit} | ||||
| disabled={isEmpty(treeValue)} | disabled={isEmpty(treeValue)} | ||||
| loading={loading} | |||||
| > | > | ||||
| {t('common.save')} | {t('common.save')} | ||||
| </Button> | |||||
| </ButtonLoading> | |||||
| </DialogFooter> | </DialogFooter> | ||||
| </DialogContent> | </DialogContent> | ||||
| </Dialog> | </Dialog> |