output-panel.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. 'use client'
  2. import type { FC } from 'react'
  3. import { useMemo } from 'react'
  4. import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
  5. import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
  6. import { Markdown } from '@/app/components/base/markdown'
  7. import LoadingAnim from '@/app/components/base/chat/chat/loading-anim'
  8. import { FileList } from '@/app/components/base/file-uploader'
  9. import StatusContainer from '@/app/components/workflow/run/status-container'
  10. import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
  11. type OutputPanelProps = {
  12. isRunning?: boolean
  13. outputs?: any
  14. error?: string
  15. height?: number
  16. }
  17. const OutputPanel: FC<OutputPanelProps> = ({
  18. isRunning,
  19. outputs,
  20. error,
  21. height,
  22. }) => {
  23. const isTextOutput = useMemo(() => {
  24. return outputs && Object.keys(outputs).length === 1 && typeof outputs[Object.keys(outputs)[0]] === 'string'
  25. }, [outputs])
  26. const fileList = useMemo(() => {
  27. const fileList: any[] = []
  28. if (!outputs)
  29. return fileList
  30. if (Object.keys(outputs).length > 1)
  31. return fileList
  32. for (const key in outputs) {
  33. if (Array.isArray(outputs[key])) {
  34. outputs[key].map((output: any) => {
  35. if (output?.dify_model_identity === '__dify__file__')
  36. fileList.push(output)
  37. return null
  38. })
  39. }
  40. else if (outputs[key]?.dify_model_identity === '__dify__file__') {
  41. fileList.push(outputs[key])
  42. }
  43. }
  44. return getProcessedFilesFromResponse(fileList)
  45. }, [outputs])
  46. return (
  47. <div className='py-2'>
  48. {isRunning && (
  49. <div className='pt-4 pl-[26px]'>
  50. <LoadingAnim type='text' />
  51. </div>
  52. )}
  53. {!isRunning && error && (
  54. <div className='px-4'>
  55. <StatusContainer status='failed'>{error}</StatusContainer>
  56. </div>
  57. )}
  58. {!isRunning && !outputs && (
  59. <div className='px-4 py-2'>
  60. <Markdown content='No Output' />
  61. </div>
  62. )}
  63. {isTextOutput && (
  64. <div className='px-4 py-2'>
  65. <Markdown content={outputs[Object.keys(outputs)[0]] || ''} />
  66. </div>
  67. )}
  68. {fileList.length > 0 && (
  69. <div className='px-4 py-2'>
  70. <FileList
  71. files={fileList}
  72. showDeleteAction={false}
  73. showDownloadAction
  74. canPreview
  75. />
  76. </div>
  77. )}
  78. {outputs && Object.keys(outputs).length > 1 && height! > 0 && (
  79. <div className='flex flex-col gap-2'>
  80. <CodeEditor
  81. showFileList
  82. readOnly
  83. title={<div></div>}
  84. language={CodeLanguage.json}
  85. value={outputs}
  86. isJSONStringifyBeauty
  87. height={height ? (height - 16) / 2 : undefined}
  88. />
  89. </div>
  90. )}
  91. </div>
  92. )
  93. }
  94. export default OutputPanel