Merge branch 'cz/mergeAll' of https://github.com/langflow-ai/langflow into cz/mergeAll
This commit is contained in:
commit
817f85cfaf
11 changed files with 78 additions and 20 deletions
|
|
@ -1,10 +1,12 @@
|
||||||
|
import TableAutoCellRender from "../tableComponent/components/tableAutoCellRender";
|
||||||
|
|
||||||
export default function ArrayReader({ array }: { array: any[] }): JSX.Element {
|
export default function ArrayReader({ array }: { array: any[] }): JSX.Element {
|
||||||
//TODO check array type
|
//TODO check array type
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ul>
|
<ul>
|
||||||
{array.map((item, index) => (
|
{array.map((item, index) => (
|
||||||
<li key={index}>{item}</li>
|
<li key={index}>{<TableAutoCellRender value={item} />}</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@ function RecordsOutputComponent({
|
||||||
rows: any;
|
rows: any;
|
||||||
columnMode?: "intersection" | "union";
|
columnMode?: "intersection" | "union";
|
||||||
}) {
|
}) {
|
||||||
|
console.log("rows", rows);
|
||||||
const columns = extractColumnsFromRows(rows, columnMode);
|
const columns = extractColumnsFromRows(rows, columnMode);
|
||||||
|
console.log("columns", columns);
|
||||||
|
|
||||||
const columnDefs = columns.map((col, idx) => ({
|
const columnDefs = columns.map((col, idx) => ({
|
||||||
...col,
|
...col,
|
||||||
|
|
|
||||||
|
|
@ -9,20 +9,17 @@ import { Badge } from "../../../ui/badge";
|
||||||
|
|
||||||
export default function TableAutoCellRender({
|
export default function TableAutoCellRender({
|
||||||
value,
|
value,
|
||||||
}: CustomCellRendererProps) {
|
}: CustomCellRendererProps | { value: any }) {
|
||||||
function getCellType() {
|
function getCellType() {
|
||||||
switch (typeof value) {
|
switch (typeof value) {
|
||||||
case "object":
|
case "object":
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
return String(value);
|
return String(value);
|
||||||
} else if (Array.isArray(value)) {
|
} else if (Array.isArray(value)) {
|
||||||
return <ArrayReader array={value} />;
|
return <ObjectRender object={value} />;
|
||||||
} else if (value.definitions) {
|
|
||||||
// use a custom render defined by the sender
|
|
||||||
} else {
|
} else {
|
||||||
return <ObjectRender object={value} />;
|
return <ObjectRender object={value} />;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case "string":
|
case "string":
|
||||||
if (isTimeStampString(value)) {
|
if (isTimeStampString(value)) {
|
||||||
return <DateReader date={value} />;
|
return <DateReader date={value} />;
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,20 @@ const UploadFileButton = ({
|
||||||
fileInputRef,
|
fileInputRef,
|
||||||
handleFileChange,
|
handleFileChange,
|
||||||
handleButtonClick,
|
handleButtonClick,
|
||||||
|
lockChat,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
|
disabled={lockChat}
|
||||||
type="file"
|
type="file"
|
||||||
ref={fileInputRef}
|
ref={fileInputRef}
|
||||||
style={{ display: "none" }}
|
style={{ display: "none" }}
|
||||||
onChange={handleFileChange}
|
onChange={handleFileChange}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
className="font-bold text-white transition-all hover:text-muted-foreground"
|
disabled={lockChat}
|
||||||
|
className={`font-bold text-white transition-all ${lockChat ? "cursor-not-allowed" : "hover:text-muted-foreground"}`}
|
||||||
onClick={handleButtonClick}
|
onClick={handleButtonClick}
|
||||||
variant="none"
|
variant="none"
|
||||||
size="none"
|
size="none"
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,30 @@
|
||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
import useFileUpload from "./use-file-upload";
|
import useFileUpload from "./use-file-upload";
|
||||||
|
import useAlertStore from "../../../../../../stores/alertStore";
|
||||||
|
|
||||||
|
const fsErrorText =
|
||||||
|
"Please ensure your file has one of the following extensions:";
|
||||||
|
const snErrorTxt = "png, jpg, jpeg, gif, bmp, webp";
|
||||||
|
|
||||||
export const useHandleFileChange = (setFiles, currentFlowId) => {
|
export const useHandleFileChange = (setFiles, currentFlowId) => {
|
||||||
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
const handleFileChange = async (
|
const handleFileChange = async (
|
||||||
event: React.ChangeEvent<HTMLInputElement>,
|
event: React.ChangeEvent<HTMLInputElement>,
|
||||||
) => {
|
) => {
|
||||||
const fileInput = event.target;
|
const fileInput = event.target;
|
||||||
const file = fileInput.files?.[0];
|
const file = fileInput.files?.[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
|
const allowedExtensions = ["png", "jpg", "jpeg", "gif", "bmp", "webp"];
|
||||||
|
const fileExtension = file.name.split(".").pop()?.toLowerCase();
|
||||||
|
|
||||||
|
if (!fileExtension || !allowedExtensions.includes(fileExtension)) {
|
||||||
|
setErrorData({
|
||||||
|
title: "Error uploading file",
|
||||||
|
list: [fsErrorText, snErrorTxt],
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 10 }); // Increase the length to ensure uniqueness
|
const uid = new ShortUniqueId({ length: 10 }); // Increase the length to ensure uniqueness
|
||||||
const id = uid();
|
const id = uid();
|
||||||
const type = file.type.split("/")[0];
|
const type = file.type.split("/")[0];
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,19 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
import useFileUpload from "./use-file-upload";
|
import useFileUpload from "./use-file-upload";
|
||||||
|
import useAlertStore from "../../../../../../stores/alertStore";
|
||||||
|
|
||||||
const useUpload = (uploadFile, currentFlowId, setFiles) => {
|
const fsErrorText =
|
||||||
|
"Please ensure your file has one of the following extensions:";
|
||||||
|
const snErrorTxt = "png, jpg, jpeg, gif, bmp, webp";
|
||||||
|
|
||||||
|
const useUpload = (uploadFile, currentFlowId, setFiles, lockChat) => {
|
||||||
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handlePaste = (event: ClipboardEvent): void => {
|
const handlePaste = (event: ClipboardEvent): void => {
|
||||||
|
if (lockChat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const items = event.clipboardData?.items;
|
const items = event.clipboardData?.items;
|
||||||
if (items) {
|
if (items) {
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
|
@ -12,6 +21,23 @@ const useUpload = (uploadFile, currentFlowId, setFiles) => {
|
||||||
const uid = new ShortUniqueId({ length: 3 });
|
const uid = new ShortUniqueId({ length: 3 });
|
||||||
const blob = items[i].getAsFile();
|
const blob = items[i].getAsFile();
|
||||||
if (blob) {
|
if (blob) {
|
||||||
|
const allowedExtensions = [
|
||||||
|
"png",
|
||||||
|
"jpg",
|
||||||
|
"jpeg",
|
||||||
|
"gif",
|
||||||
|
"bmp",
|
||||||
|
"webp",
|
||||||
|
];
|
||||||
|
const fileExtension = blob.name.split(".").pop()?.toLowerCase();
|
||||||
|
|
||||||
|
if (!fileExtension || !allowedExtensions.includes(fileExtension)) {
|
||||||
|
setErrorData({
|
||||||
|
title: "Error uploading file",
|
||||||
|
list: [fsErrorText, snErrorTxt],
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
const id = uid();
|
const id = uid();
|
||||||
setFiles((prevFiles) => [
|
setFiles((prevFiles) => [
|
||||||
...prevFiles,
|
...prevFiles,
|
||||||
|
|
@ -27,7 +53,7 @@ const useUpload = (uploadFile, currentFlowId, setFiles) => {
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener("paste", handlePaste);
|
document.removeEventListener("paste", handlePaste);
|
||||||
};
|
};
|
||||||
}, [uploadFile, currentFlowId]);
|
}, [uploadFile, currentFlowId, lockChat]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export default function ChatInput({
|
||||||
|
|
||||||
useFocusOnUnlock(lockChat, inputRef);
|
useFocusOnUnlock(lockChat, inputRef);
|
||||||
useAutoResizeTextArea(chatValue, inputRef);
|
useAutoResizeTextArea(chatValue, inputRef);
|
||||||
useUpload(uploadFile, currentFlowId, setFiles);
|
useUpload(uploadFile, currentFlowId, setFiles, lockChat || saveLoading);
|
||||||
const { handleFileChange } = useHandleFileChange(setFiles, currentFlowId);
|
const { handleFileChange } = useHandleFileChange(setFiles, currentFlowId);
|
||||||
|
|
||||||
const send = () => {
|
const send = () => {
|
||||||
|
|
@ -92,8 +92,11 @@ export default function ChatInput({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="absolute bottom-2 left-4">
|
<div
|
||||||
|
className={`absolute bottom-2 left-4 ${lockChat || saveLoading ? "cursor-not-allowed" : ""}`}
|
||||||
|
>
|
||||||
<UploadFileButton
|
<UploadFileButton
|
||||||
|
lockChat={lockChat || saveLoading}
|
||||||
fileInputRef={fileInputRef}
|
fileInputRef={fileInputRef}
|
||||||
handleFileChange={handleFileChange}
|
handleFileChange={handleFileChange}
|
||||||
handleButtonClick={handleButtonClick}
|
handleButtonClick={handleButtonClick}
|
||||||
|
|
@ -110,7 +113,7 @@ export default function ChatInput({
|
||||||
key={file.id}
|
key={file.id}
|
||||||
onDelete={() => {
|
onDelete={() => {
|
||||||
setFiles((prev: FilePreviewType[]) =>
|
setFiles((prev: FilePreviewType[]) =>
|
||||||
prev.filter((f) => f.id !== file.id)
|
prev.filter((f) => f.id !== file.id),
|
||||||
);
|
);
|
||||||
// TODO: delete file on backend
|
// TODO: delete file on backend
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import ForwardedIconComponent from "../../../../../../../components/genericIconComponent";
|
import ForwardedIconComponent from "../../../../../../../components/genericIconComponent";
|
||||||
|
import { Button } from "../../../../../../../components/ui/button";
|
||||||
|
|
||||||
export default function DownloadButton({
|
export default function DownloadButton({
|
||||||
isHovered,
|
isHovered,
|
||||||
|
|
@ -10,14 +11,18 @@ export default function DownloadButton({
|
||||||
if (isHovered) {
|
if (isHovered) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`absolute right-1 top-1 rounded-bl-lg bg-muted text-sm font-bold text-foreground `}
|
className={`absolute right-1 top-1 rounded-md bg-muted text-sm font-bold text-foreground `}
|
||||||
>
|
>
|
||||||
<button className="px-2 py-1 text-ring " onClick={handleDownload}>
|
<Button
|
||||||
|
variant={"none"}
|
||||||
|
className="bg-transparent px-2 py-1 text-ring"
|
||||||
|
onClick={handleDownload}
|
||||||
|
>
|
||||||
<ForwardedIconComponent
|
<ForwardedIconComponent
|
||||||
name="DownloadCloud"
|
name="DownloadCloud"
|
||||||
className="h-5 w-5 text-current hover:scale-110"
|
className="h-5 w-5 bg-transparent text-current hover:scale-110"
|
||||||
/>
|
/>
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import DownloadButton from "./components/downloadButton/downloadButton";
|
||||||
import getClasses from "./utils/get-classes";
|
import getClasses from "./utils/get-classes";
|
||||||
import handleDownload from "./utils/handle-download";
|
import handleDownload from "./utils/handle-download";
|
||||||
|
|
||||||
const imgTypes = new Set(["png", "jpg"]);
|
const imgTypes = new Set(["png", "jpg", "jpeg", "gif", "webp", "image"]);
|
||||||
|
|
||||||
export default function FileCard({
|
export default function FileCard({
|
||||||
fileName,
|
fileName,
|
||||||
|
|
@ -29,7 +29,7 @@ export default function FileCard({
|
||||||
|
|
||||||
const imgSrc = `${BACKEND_URL.slice(
|
const imgSrc = `${BACKEND_URL.slice(
|
||||||
0,
|
0,
|
||||||
BACKEND_URL.length - 1
|
BACKEND_URL.length - 1,
|
||||||
)}${BASE_URL_API}files/images/${content}`;
|
)}${BASE_URL_API}files/images/${content}`;
|
||||||
|
|
||||||
if (showFile) {
|
if (showFile) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import IconComponent, {
|
||||||
import { Skeleton } from "../../../../../components/ui/skeleton";
|
import { Skeleton } from "../../../../../components/ui/skeleton";
|
||||||
import formatFileName from "./utils/format-file-name";
|
import formatFileName from "./utils/format-file-name";
|
||||||
|
|
||||||
|
const supImgFiles = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "image"];
|
||||||
|
|
||||||
export default function FilePreview({
|
export default function FilePreview({
|
||||||
error,
|
error,
|
||||||
file,
|
file,
|
||||||
|
|
@ -16,7 +18,8 @@ export default function FilePreview({
|
||||||
error: boolean;
|
error: boolean;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
}) {
|
}) {
|
||||||
const isImage = file.type.toLowerCase().includes("image");
|
const fileType = file.type.toLowerCase();
|
||||||
|
const isImage = supImgFiles.some((type) => fileType.includes(type));
|
||||||
|
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { ColDef, ColGroupDef } from "ag-grid-community";
|
import { ColDef, ColGroupDef } from "ag-grid-community";
|
||||||
import clsx, { ClassValue } from "clsx";
|
import clsx, { ClassValue } from "clsx";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
import TableAutoCellRender from "../components/tableComponent/components/tableAutoCellRender";
|
|
||||||
import { APIDataType, TemplateVariableType } from "../types/api";
|
import { APIDataType, TemplateVariableType } from "../types/api";
|
||||||
import {
|
import {
|
||||||
groupedObjType,
|
groupedObjType,
|
||||||
|
|
@ -10,6 +9,7 @@ import {
|
||||||
} from "../types/components";
|
} from "../types/components";
|
||||||
import { NodeType } from "../types/flow";
|
import { NodeType } from "../types/flow";
|
||||||
import { FlowState } from "../types/tabs";
|
import { FlowState } from "../types/tabs";
|
||||||
|
import TableAutoCellRender from "../components/tableComponent/components/tableAutoCellRender";
|
||||||
|
|
||||||
export function classNames(...classes: Array<string>): string {
|
export function classNames(...classes: Array<string>): string {
|
||||||
return classes.filter(Boolean).join(" ");
|
return classes.filter(Boolean).join(" ");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue