feat(Builder): Limit Output preview size (#7554)
* feat(Builder): Limit Output preview size * fix indentpull/7564/head^2
parent
77034f2df0
commit
03ea51b266
|
@ -1,8 +1,9 @@
|
|||
import React, { useState, useEffect, FC, memo } from 'react';
|
||||
import React, { useState, useEffect, FC, memo, useRef } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import 'reactflow/dist/style.css';
|
||||
import './customnode.css';
|
||||
import ModalComponent from './ModalComponent';
|
||||
import InputModalComponent from './InputModalComponent';
|
||||
import OutputModalComponent from './OutputModalComponent';
|
||||
import { Button } from './ui/button';
|
||||
import { Input } from './ui/input';
|
||||
import { BlockSchema } from '@/lib/types';
|
||||
|
@ -33,6 +34,8 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => {
|
|||
const [activeKey, setActiveKey] = useState<string | null>(null);
|
||||
const [modalValue, setModalValue] = useState<string>('');
|
||||
const [errors, setErrors] = useState<{ [key: string]: string | null }>({});
|
||||
const [isOutputModalOpen, setIsOutputModalOpen] = useState(false);
|
||||
const outputDataRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (data.output_data || data.status) {
|
||||
|
@ -400,6 +403,16 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => {
|
|||
return Object.values(newErrors).every((error) => error === null);
|
||||
};
|
||||
|
||||
const handleOutputClick = () => {
|
||||
setIsOutputModalOpen(true);
|
||||
setModalValue(typeof data.output_data === 'object' ? JSON.stringify(data.output_data, null, 2) : data.output_data);
|
||||
};
|
||||
|
||||
const isTextTruncated = (element: HTMLElement | null): boolean => {
|
||||
if (!element) return false;
|
||||
return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`custom-node dark-theme ${data.status === 'RUNNING' ? 'running' : data.status === 'COMPLETED' ? 'completed' : data.status === 'FAILED' ? 'failed' : ''}`}>
|
||||
<div className="mb-2">
|
||||
|
@ -423,16 +436,24 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => {
|
|||
</div>
|
||||
</div>
|
||||
{isOutputOpen && (
|
||||
<div className="node-output">
|
||||
<div className="node-output" onClick={handleOutputClick}>
|
||||
<p>
|
||||
<strong>Status:</strong>{' '}
|
||||
{typeof data.status === 'object' ? JSON.stringify(data.status) : data.status || 'N/A'}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Output Data:</strong>{' '}
|
||||
{typeof data.output_data === 'object'
|
||||
{(() => {
|
||||
const outputText = typeof data.output_data === 'object'
|
||||
? JSON.stringify(data.output_data)
|
||||
: data.output_data || 'N/A'}
|
||||
: data.output_data;
|
||||
|
||||
if (!outputText) return 'No output data';
|
||||
|
||||
return outputText.length > 100
|
||||
? `${outputText.slice(0, 100)}... Press To Read More`
|
||||
: outputText;
|
||||
})()}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
@ -446,13 +467,18 @@ const CustomNode: FC<NodeProps<CustomNodeData>> = ({ data, id }) => {
|
|||
</>
|
||||
)}
|
||||
</div>
|
||||
<ModalComponent
|
||||
<InputModalComponent
|
||||
isOpen={isModalOpen}
|
||||
onClose={() => setIsModalOpen(false)}
|
||||
onSave={handleModalSave}
|
||||
value={modalValue}
|
||||
key={activeKey}
|
||||
/>
|
||||
<OutputModalComponent
|
||||
isOpen={isOutputModalOpen}
|
||||
onClose={() => setIsOutputModalOpen(false)}
|
||||
value={modalValue}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ interface ModalProps {
|
|||
value: string;
|
||||
}
|
||||
|
||||
const ModalComponent: FC<ModalProps> = ({ isOpen, onClose, onSave, value }) => {
|
||||
const InputModalComponent: FC<ModalProps> = ({ isOpen, onClose, onSave, value }) => {
|
||||
const [tempValue, setTempValue] = React.useState(value);
|
||||
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
|
@ -50,4 +50,4 @@ const ModalComponent: FC<ModalProps> = ({ isOpen, onClose, onSave, value }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default ModalComponent;
|
||||
export default InputModalComponent;
|
|
@ -0,0 +1,43 @@
|
|||
import React, { FC, useEffect } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { Button } from './ui/button';
|
||||
import { Textarea } from './ui/textarea';
|
||||
|
||||
interface OutputModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const OutputModalComponent: FC<OutputModalProps> = ({ isOpen, onClose, value }) => {
|
||||
const [tempValue, setTempValue] = React.useState(value);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setTempValue(value);
|
||||
}
|
||||
}, [isOpen, value]);
|
||||
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createPortal(
|
||||
<div className="fixed inset-0 bg-white bg-opacity-60 flex justify-center items-center z-50">
|
||||
<div className="bg-white p-5 rounded-lg w-[1000px] max-w-[100%]">
|
||||
<center><h1 style={{ color: 'black' }}>Full Output</h1></center>
|
||||
<Textarea
|
||||
className="w-full h-[400px] p-2.5 rounded border border-[#dfdfdf] text-black bg-[#dfdfdf]"
|
||||
value={tempValue}
|
||||
readOnly
|
||||
/>
|
||||
<div className="flex justify-end gap-2.5 mt-2.5">
|
||||
<Button onClick={onClose}>Close</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
document.body
|
||||
);
|
||||
};
|
||||
|
||||
export default OutputModalComponent;
|
Loading…
Reference in New Issue