refactor: Reduce errors on types

This commit is contained in:
Igor Carvalho 2023-08-02 19:08:39 -03:00
commit 5e65397773
34 changed files with 193 additions and 182 deletions

View file

@ -40,13 +40,13 @@ export default function ParameterComponent({
info = "",
}: ParameterComponentType): JSX.Element {
const ref = useRef<HTMLDivElement>(null);
const refHtml = useRef(null);
const infoHtml = useRef(null);
const refHtml = useRef<HTMLDivElement>(null);
const infoHtml = useRef<HTMLDivElement>(null);
const updateNodeInternals = useUpdateNodeInternals();
const [position, setPosition] = useState(0);
const { setTabsState, tabId, save, flows } = useContext(TabsContext);
const flow = flows.find((f) => f.id === tabId).data?.nodes ?? null;
const flow = flows.find((f) => f.id === tabId)?.data?.nodes ?? null;
// Update component position
useEffect(() => {
@ -68,7 +68,7 @@ export default function ParameterComponent({
const handleOnNewValue = (newValue: string | string[] | boolean): void => {
let newData = cloneDeep(data);
newData.node.template[name].value = newValue;
newData.node!.template[name].value = newValue;
setData(newData);
// Set state to pending
setTabsState((prev) => {
@ -99,6 +99,7 @@ export default function ParameterComponent({
function renderTooltips() {
let groupedObj = groupByFamily(myData, tooltipTitle, left, flow);
console.log(groupedObj)
if (groupedObj && groupedObj.length > 0) {
refHtml.current = groupedObj.map((item, i) => {
@ -207,7 +208,7 @@ export default function ParameterComponent({
position={left ? Position.Left : Position.Right}
id={id}
isValidConnection={(connection) =>
isValidConnection(connection, reactFlowInstance)
isValidConnection(connection, reactFlowInstance!)
}
className={classNames(
left ? "-ml-0.5 " : "-mr-0.5 ",
@ -255,7 +256,7 @@ export default function ParameterComponent({
<div className="mt-2 w-full">
<ToggleShadComponent
disabled={disabled}
enabled={data.node.template[name].value ?? false}
enabled={data.node?.template[name].value ?? false}
setEnabled={(t) => {
handleOnNewValue(t);
}}
@ -283,7 +284,7 @@ export default function ParameterComponent({
) : left === true && type === "code" ? (
<div className="mt-2 w-full">
<CodeAreaComponent
dynamic={data.node.template[name].dynamic ?? false}
dynamic={data.node?.template[name].dynamic ?? false}
setNodeClass={(nodeClass) => {
data.node = nodeClass;
}}
@ -302,7 +303,7 @@ export default function ParameterComponent({
fileTypes={data.node?.template[name].fileTypes}
suffixes={data.node?.template[name].suffixes}
onFileChange={(t: string) => {
data.node.template[name].file_path = t;
data.node!.template[name].file_path = t;
save();
}}
></InputFileComponent>

View file

@ -13,6 +13,7 @@ import { cleanEdges } from "../../utils/reactflowUtils";
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
import { classNames, toTitleCase } from "../../utils/utils";
import ParameterComponent from "./components/parameterComponent";
import { validationStatusType } from "../../types/components";
export default function GenericNode({
data: olddata,
@ -26,7 +27,7 @@ export default function GenericNode({
const updateNodeInternals = useUpdateNodeInternals();
const { types, deleteNode, reactFlowInstance } = useContext(typesContext);
const name = nodeIconsLucide[data.type] ? data.type : types[data.type];
const [validationStatus, setValidationStatus] = useState(null);
const [validationStatus, setValidationStatus] = useState<validationStatusType | null>(null);
// State for outline color
const { sseData, isBuilding } = useSSE();
useEffect(() => {
@ -77,7 +78,7 @@ export default function GenericNode({
"generic-node-div"
)}
>
{data.node.beta && (
{data.node?.beta && (
<div className="beta-badge-wrapper">
<div className="beta-badge-content">BETA</div>
</div>
@ -114,6 +115,7 @@ export default function GenericNode({
</span>
) : (
<div className="max-h-96 overflow-auto">
{typeof validationStatus.params === "string"
? validationStatus.params
.split("\n")
@ -160,16 +162,16 @@ export default function GenericNode({
<div className="generic-node-desc-text">{data.node?.description}</div>
<>
{Object.keys(data.node.template)
{Object.keys(data.node!.template)
.filter((t) => t.charAt(0) !== "_")
.map((t: string, idx) => (
<div key={idx}>
{data.node.template[t].show &&
!data.node.template[t].advanced ? (
{data.node!.template[t].show &&
!data.node!.template[t].advanced ? (
<ParameterComponent
key={
(data.node.template[t].input_types?.join(";") ??
data.node.template[t].type) +
(data.node!.template[t].input_types?.join(";") ??
data.node!.template[t].type) +
"|" +
t +
"|" +
@ -178,8 +180,8 @@ export default function GenericNode({
data={data}
setData={setData}
color={
nodeColors[types[data.node?.template[t].type]] ??
nodeColors[data.node?.template[t].type] ??
nodeColors[types[data.node?.template[t].type!]] ??
nodeColors[data.node?.template[t].type!] ??
nodeColors.unknown
}
title={
@ -215,14 +217,14 @@ export default function GenericNode({
))}
<div
className={classNames(
Object.keys(data.node.template).length < 1 ? "hidden" : "",
Object.keys(data.node!.template).length < 1 ? "hidden" : "",
"flex-max-width justify-center"
)}
>
{" "}
</div>
<ParameterComponent
key={[data.type, data.id, ...data.node.base_classes].join("|")}
key={[data.type, data.id, ...data.node!.base_classes].join("|")}
data={data}
setData={setData}
color={nodeColors[types[data.type]] ?? nodeColors.unknown}
@ -232,7 +234,7 @@ export default function GenericNode({
: data.type
}
tooltipTitle={data.node?.base_classes.join("\n")}
id={[data.type, data.id, ...data.node.base_classes].join("|")}
id={[data.type, data.id, ...data.node!.base_classes].join("|")}
type={data.node?.base_classes.join("|")}
left={false}
/>

View file

@ -29,7 +29,7 @@ export default function AccordionComponent({
}
function handleClick(): void {
value === "" ? setValue(keyValue) : setValue("");
value === "" ? setValue(keyValue!) : setValue("");
}
return (
@ -40,7 +40,7 @@ export default function AccordionComponent({
value={value}
onValueChange={setValue}
>
<AccordionItem value={keyValue} className="border-b">
<AccordionItem value={keyValue!} className="border-b">
<AccordionTrigger
onClick={() => {
handleClick();

View file

@ -18,7 +18,7 @@ export const EditFlowSettings: React.FC<InputProps> = ({
updateFlow,
}: InputProps): JSX.Element => {
const [isMaxLength, setIsMaxLength] = useState(false);
const nameLists = useRef([]);
const nameLists = useRef<string[]>([]);
useEffect(() => {
readFlowsFromDatabase().then((flows) => {
flows.forEach((flow) => {
@ -47,7 +47,7 @@ export const EditFlowSettings: React.FC<InputProps> = ({
);
const handleDescriptionChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
flows.find((f) => f.id === tabId).description = event.target.value;
flows.find((f) => f.id === tabId)!.description = event.target.value;
setDesc(flows.find((f) => f.id === tabId)?.description);
setDescription(event.target.value);
};

View file

@ -5,14 +5,14 @@ export default function RadialProgressComponent({
color,
}: RadialProgressType): JSX.Element {
const style = {
"--value": value * 100,
"--value": value! * 100,
"--size": "1.5rem",
"--thickness": "2px",
} as React.CSSProperties;
return (
<div className={"radial-progress " + color} style={style}>
<strong className="text-[8px]">{Math.trunc(value * 100)}%</strong>
<strong className="text-[8px]">{Math.trunc(value! * 100)}%</strong>
</div>
);
}

View file

@ -27,7 +27,7 @@ const TooltipReact: FC<TooltipProps> = ({
content={content}
className={classNames(
"z-[9999] !bg-white !text-xs !font-normal !text-foreground !opacity-100 !shadow-md",
className
className!
)}
place={position}
clickable={clickable}

View file

@ -36,7 +36,7 @@ export default function BuildTrigger({
if (isBuilding) {
return;
}
const errors = validateNodes(reactFlowInstance);
const errors = validateNodes(reactFlowInstance!);
if (errors.length > 0) {
setErrorData({
title: "Oops! Looks like you missed something",

View file

@ -48,7 +48,7 @@ export default function Chat({ flow }: ChatType): JSX.Element {
useEffect(() => {
const prevNodes = prevNodesRef.current;
const currentNodes = nodes.map((node: NodeType) =>
_.cloneDeep(node.data.node.template)
_.cloneDeep(node.data.node?.template)
);
if (
tabsState &&
@ -63,7 +63,7 @@ export default function Chat({ flow }: ChatType): JSX.Element {
tabsState[flow.id] &&
tabsState[flow.id].formKeysData &&
tabsState[flow.id].formKeysData.input_keys &&
Object.keys(tabsState[flow.id].formKeysData.input_keys).length > 0
Object.keys(tabsState[flow.id].formKeysData.input_keys!).length > 0
) {
setCanOpen(true);
} else {

View file

@ -33,7 +33,7 @@ export default function CodeAreaComponent({
dynamic={dynamic}
value={myValue}
nodeClass={nodeClass}
setNodeClass={setNodeClass}
setNodeClass={setNodeClass!}
setValue={(t: string) => {
setMyValue(t);
onChange(t);

View file

@ -43,7 +43,7 @@ export default function CodeTabsComponent({
}: codeTabsPropsType) {
const [isCopied, setIsCopied] = useState<Boolean>(false);
const [data, setData] = useState(flow ? flow["data"]["nodes"] : null);
const [openAccordion, setOpenAccordion] = useState([]);
const [openAccordion, setOpenAccordion] = useState<string[]>([]);
const { dark } = useContext(darkContext);
useEffect(() => {
@ -89,8 +89,8 @@ export default function CodeTabsComponent({
};
function openAccordions() {
let accordionsToOpen = [];
tweaks?.tweak.current.forEach((el) => {
let accordionsToOpen: string[] = [];
tweaks?.tweak!.current.forEach((el) => {
Object.keys(el).forEach((key) => {
if (Object.keys(el[key]).length > 0) {
accordionsToOpen.push(key);
@ -190,7 +190,7 @@ export default function CodeTabsComponent({
>
{data?.map((t: any, index) => (
<div className="px-3" key={index}>
{tweaks?.tweaksList.current.includes(t["data"]["id"]) && (
{tweaks?.tweaksList!.current.includes(t["data"]["id"]) && (
<AccordionComponent
trigger={t["data"]["id"]}
open={openAccordion}
@ -261,14 +261,14 @@ export default function CodeTabsComponent({
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
newInputList![
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
tweaks.buildTweakObject!(
t["data"]["id"],
k,
t.data.node.template[n]
@ -278,7 +278,7 @@ export default function CodeTabsComponent({
) : t.data.node.template[n]
.multiline ? (
<ShadTooltip
content={tweaks.buildContent(
content={tweaks.buildContent!(
t.data.node.template[n]
.value
)}
@ -303,14 +303,14 @@ export default function CodeTabsComponent({
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
newInputList![
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
tweaks.buildTweakObject!(
t["data"]["id"],
k,
t.data.node
@ -342,14 +342,14 @@ export default function CodeTabsComponent({
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
newInputList![
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
tweaks.buildTweakObject!(
t["data"]["id"],
k,
t.data.node.template[n]
@ -371,14 +371,14 @@ export default function CodeTabsComponent({
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
newInputList![
index
].data.node.template[
n
].value = e;
return newInputList;
});
tweaks.buildTweakObject(
tweaks.buildTweakObject!(
t["data"]["id"],
e,
t.data.node.template[n]
@ -391,7 +391,7 @@ export default function CodeTabsComponent({
) : t.data.node.template[n].type ===
"file" ? (
<ShadTooltip
content={tweaks.buildContent(
content={tweaks.buildContent!(
!t.data.node.template[n]
.value ||
t.data.node.template[n]
@ -447,14 +447,14 @@ export default function CodeTabsComponent({
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
newInputList![
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
tweaks.buildTweakObject!(
t["data"]["id"],
k,
t.data.node.template[n]
@ -478,14 +478,14 @@ export default function CodeTabsComponent({
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
newInputList![
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
tweaks.buildTweakObject!(
t["data"]["id"],
k,
t.data.node.template[n]
@ -521,14 +521,14 @@ export default function CodeTabsComponent({
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
newInputList![
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
tweaks.buildTweakObject!(
t["data"]["id"],
k,
t.data.node.template[n]
@ -539,7 +539,7 @@ export default function CodeTabsComponent({
) : t.data.node.template[n].type ===
"prompt" ? (
<ShadTooltip
content={tweaks.buildContent(
content={tweaks.buildContent!(
!t.data.node.template[n]
.value ||
t.data.node.template[n]
@ -567,14 +567,14 @@ export default function CodeTabsComponent({
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
newInputList![
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
tweaks.buildTweakObject!(
t["data"]["id"],
k,
t.data.node.template[n]
@ -586,8 +586,8 @@ export default function CodeTabsComponent({
) : t.data.node.template[n].type ===
"code" ? (
<ShadTooltip
content={tweaks.buildContent(
tweaks.getValue(
content={tweaks.buildContent!(
tweaks.getValue!(
t.data.node.template[n]
.value,
t.data,
@ -613,14 +613,14 @@ export default function CodeTabsComponent({
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
newInputList![
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
tweaks.buildTweakObject!(
t["data"]["id"],
k,
t.data.node.template[n]
@ -646,7 +646,7 @@ export default function CodeTabsComponent({
</AccordionComponent>
)}
{tweaks?.tweaksList.current.length === 0 && (
{tweaks?.tweaksList!.current.length === 0 && (
<>
<div className="pt-3">
No tweaks are available for this flow.

View file

@ -26,7 +26,7 @@ export const MenuBar = ({ flows, tabId }: menuBarPropsType): JSX.Element => {
function handleAddFlow() {
try {
addFlow(null, true).then((id) => {
addFlow(null!, true).then((id) => {
navigate("/flow/" + id);
});
// saveFlowStyleInDataBase();
@ -46,7 +46,7 @@ export const MenuBar = ({ flows, tabId }: menuBarPropsType): JSX.Element => {
<DropdownMenuTrigger asChild>
<Button asChild variant="primary" size="sm">
<div className="header-menu-bar-display">
<div className="header-menu-flow-name">{current_flow.name}</div>
<div className="header-menu-flow-name">{current_flow!.name}</div>
<IconComponent name="ChevronDown" className="h-4 w-4" />
</div>
</Button>

View file

@ -23,9 +23,9 @@ export default function PromptAreaComponent({
useEffect(() => {
if (value !== "" && !editNode) {
postValidatePrompt(field_name, value, nodeClass).then((apiReturn) => {
postValidatePrompt(field_name!, value, nodeClass!).then((apiReturn) => {
if (apiReturn.data) {
setNodeClass(apiReturn.data.frontend_node);
setNodeClass!(apiReturn.data.frontend_node);
// need to update reactFlowInstance to re-render the nodes.
}
});

View file

@ -10,13 +10,13 @@ export const darkContext = createContext<darkContextType>(initialValue);
export function DarkProvider({ children }) {
const [dark, setDark] = useState(
JSON.parse(window.localStorage.getItem("isDark")) ?? false
JSON.parse(window.localStorage.getItem("isDark")!) ?? false
);
useEffect(() => {
if (dark) {
document.getElementById("body").classList.add("dark");
document.getElementById("body")!.classList.add("dark");
} else {
document.getElementById("body").classList.remove("dark");
document.getElementById("body")!.classList.remove("dark");
}
window.localStorage.setItem("isDark", dark.toString());
}, [dark]);

View file

@ -153,11 +153,11 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}
function updateDisplay_name(node: NodeType, template: APIClassType) {
node.data.node.display_name = template["display_name"] || node.data.type;
node.data.node!.display_name = template["display_name"] || node.data.type;
}
function updateNodeDocumentation(node: NodeType, template: APIClassType) {
node.data.node.documentation = template["documentation"];
node.data.node!.documentation = template["documentation"];
}
function processFlowNodes(flow) {
@ -180,7 +180,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}
function updateNodeBaseClasses(node: NodeType, template: APIClassType) {
node.data.node.base_classes = template["base_classes"];
node.data.node!.base_classes = template["base_classes"];
}
function updateNodeEdges(
@ -191,7 +191,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
flow.data.edges.forEach((edge) => {
if (edge.source === node.id) {
edge.sourceHandle = edge.sourceHandle
.split("|")
?.split("|")
.slice(0, 2)
.concat(template["base_classes"])
.join("|");
@ -200,13 +200,13 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}
function updateNodeDescription(node: NodeType, template: APIClassType) {
node.data.node.description = template["description"];
node.data.node!.description = template["description"];
}
function updateNodeTemplate(node: NodeType, template: APIClassType) {
node.data.node.template = updateTemplate(
node.data.node!.template = updateTemplate(
template["template"] as unknown as APITemplateType,
node.data.node.template as APITemplateType
node.data.node!.template as APITemplateType
);
}
@ -241,7 +241,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
link.download = `${
flowName && flowName != ""
? flowName
: flows.find((f) => f.id === tabId).name
: flows.find((f) => f.id === tabId)!.name
}.json`;
// simulate a click on the link element to trigger the download
@ -293,10 +293,10 @@ export function TabsProvider({ children }: { children: ReactNode }) {
input.onchange = (e: Event) => {
// check if the file type is application/json
if (
(e.target as HTMLInputElement).files[0].type === "application/json"
(e.target as HTMLInputElement).files![0].type === "application/json"
) {
// get the file from the file input
const currentfile = (e.target as HTMLInputElement).files[0];
const currentfile = (e.target as HTMLInputElement).files![0];
// read the file as text
currentfile.text().then((text) => {
// parse the text into a JSON object
@ -318,9 +318,9 @@ export function TabsProvider({ children }: { children: ReactNode }) {
// add a change event listener to the file input
input.onchange = (e: Event) => {
// check if the file type is application/json
if ((e.target as HTMLInputElement).files[0].type === "application/json") {
if ((e.target as HTMLInputElement).files![0].type === "application/json") {
// get the file from the file input
const file = (e.target as HTMLInputElement).files[0];
const file = (e.target as HTMLInputElement).files![0];
// read the file as text
const formData = new FormData();
formData.append("file", file);
@ -357,8 +357,8 @@ export function TabsProvider({ children }: { children: ReactNode }) {
let minimumX = Infinity;
let minimumY = Infinity;
let idsMap = {};
let nodes = reactFlowInstance.getNodes();
let edges = reactFlowInstance.getEdges();
let nodes = reactFlowInstance!.getNodes();
let edges = reactFlowInstance!.getEdges();
selectionInstance.nodes.forEach((n) => {
if (n.position.y < minimumY) {
minimumY = n.position.y;
@ -369,8 +369,8 @@ export function TabsProvider({ children }: { children: ReactNode }) {
});
const insidePosition = position.paneX
? { x: position.paneX + position.x, y: position.paneY + position.y }
: reactFlowInstance.project({ x: position.x, y: position.y });
? { x: position.paneX + position.x, y: position.paneY! + position.y }
: reactFlowInstance!.project({ x: position.x, y: position.y });
selectionInstance.nodes.forEach((n: NodeType) => {
// Generate a unique node ID
@ -396,7 +396,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
.map((e) => ({ ...e, selected: false }))
.concat({ ...newNode, selected: false });
});
reactFlowInstance.setNodes(nodes);
reactFlowInstance!.setNodes(nodes);
selectionInstance.edges.forEach((e) => {
let source = idsMap[e.source];
@ -436,13 +436,13 @@ export function TabsProvider({ children }: { children: ReactNode }) {
edges.map((e) => ({ ...e, selected: false }))
);
});
reactFlowInstance.setEdges(edges);
reactFlowInstance!.setEdges(edges);
}
const addFlow = async (
flow?: FlowType,
newProject?: Boolean
): Promise<String> => {
): Promise<String | undefined> => {
if (newProject) {
let flowData = extractDataFromFlow(flow);
if (flowData.description == "") {
@ -475,7 +475,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}
} else {
paste(
{ nodes: flow.data.nodes, edges: flow.data.edges },
{ nodes: flow!.data.nodes, edges: flow!.data.edges },
{ x: 10, y: 10 }
);
}

View file

@ -69,7 +69,7 @@ export function TypesProvider({ children }: { children: ReactNode }) {
);
}
// Clear the interval if successful.
clearInterval(intervalId);
clearInterval(intervalId!);
} catch (error) {
console.error("An error has occurred while fetching types.");
}
@ -80,18 +80,18 @@ export function TypesProvider({ children }: { children: ReactNode }) {
return () => {
// This will clear the interval when the component unmounts, or when the dependencies of the useEffect hook change.
clearInterval(intervalId);
clearInterval(intervalId!);
// Indicate that the component has been unmounted.
isMounted = false;
};
}, []);
function deleteNode(idx: string) {
reactFlowInstance.setNodes(
reactFlowInstance.getNodes().filter((n: Node) => n.id !== idx)
reactFlowInstance!.setNodes(
reactFlowInstance!.getNodes().filter((n: Node) => n.id !== idx)
);
reactFlowInstance.setEdges(
reactFlowInstance
reactFlowInstance!.setEdges(
reactFlowInstance!
.getEdges()
.filter((ns) => ns.source !== idx && ns.target !== idx)
);

View file

@ -16,7 +16,7 @@ function ApiInterceptor() {
const interceptor = api.interceptors.response.use(
(response) => response,
async (error: AxiosError) => {
if (URL_EXCLUDED_FROM_ERROR_RETRIES.includes(error.config?.url)) {
if (URL_EXCLUDED_FROM_ERROR_RETRIES.includes(error.config?.url!)) {
return Promise.reject(error);
}
let retryCount = 0;
@ -25,7 +25,7 @@ function ApiInterceptor() {
await sleep(5000); // Sleep for 5 seconds
retryCount++;
try {
const response = await axios.request(error.config);
const response = await axios.request(error.config!);
return response;
} catch (error) {
if (retryCount === 3) {

View file

@ -1,9 +1,9 @@
import React, { forwardRef } from "react";
import { ReactComponent as PowerPointSVG } from "./PowerPoint.svg";
import SvgPowerPoint from "./PowerPoint";
export const PowerPointIcon = forwardRef<
SVGSVGElement,
React.PropsWithChildren<{}>
>((props, ref) => {
return <PowerPointSVG ref={ref} {...props} />;
return <SvgPowerPoint ref={ref} {...props} />;
});

View file

@ -55,7 +55,7 @@ const EditNodeModal = forwardRef(
function changeAdvanced(n: string): void {
setMyData((old) => {
let newData = cloneDeep(old);
newData.node.template[n].advanced = !newData.node.template[n].advanced;
newData.node!.template[n].advanced = !newData.node!.template[n].advanced;
return newData;
});
}
@ -66,7 +66,7 @@ const EditNodeModal = forwardRef(
) => {
setMyData((old) => {
let newData = cloneDeep(old);
newData.node.template[name].value = newValue;
newData.node!.template[name].value = newValue;
return newData;
});
};
@ -78,7 +78,7 @@ const EditNodeModal = forwardRef(
return (
<BaseModal size="large-h-full" open={modalOpen} setOpen={setModalOpen}>
<BaseModal.Trigger>{children}</BaseModal.Trigger>
<BaseModal.Header description={myData.node?.description}>
<BaseModal.Header description={myData.node?.description!}>
<span className="pr-2">{myData.type}</span>
<Badge variant="secondary">ID: {myData.id}</Badge>
</BaseModal.Header>
@ -113,7 +113,7 @@ const EditNodeModal = forwardRef(
</TableRow>
</TableHeader>
<TableBody className="p-0">
{Object.keys(myData.node.template)
{Object.keys(myData.node!.template)
.filter(
(t) =>
t.charAt(0) !== "_" &&
@ -158,7 +158,7 @@ const EditNodeModal = forwardRef(
value={
myData.node.template[n].value ?? ""
}
onChange={(t: string) => {
onChange={(t: string | string[]) => {
handleOnNewValue(t, n);
}}
/>
@ -233,7 +233,7 @@ const EditNodeModal = forwardRef(
editNode={true}
disabled={disabled}
value={myData.node.template[n].value ?? ""}
onChange={(t: string) => {
onChange={(t: string | string[]) => {
handleOnNewValue(t, n);
}}
fileTypes={
@ -241,7 +241,7 @@ const EditNodeModal = forwardRef(
}
suffixes={myData.node.template[n].suffixes}
onFileChange={(t: string) => {
data.node.template[n].file_path = t;
data.node!.template[n].file_path = t;
}}
></InputFileComponent>
</div>
@ -256,7 +256,7 @@ const EditNodeModal = forwardRef(
myData.node = nodeClass;
}}
value={myData.node.template[n].value ?? ""}
onChange={(t: string) => {
onChange={(t: string | string[]) => {
handleOnNewValue(t, n);
}}
/>
@ -265,7 +265,7 @@ const EditNodeModal = forwardRef(
<div className="mx-auto">
<CodeAreaComponent
dynamic={
data.node.template[n].dynamic ?? false
data.node!.template[n].dynamic ?? false
}
setNodeClass={(nodeClass) => {
data.node = nodeClass;
@ -274,7 +274,7 @@ const EditNodeModal = forwardRef(
disabled={disabled}
editNode={true}
value={myData.node.template[n].value ?? ""}
onChange={(t: string) => {
onChange={(t: string | string[]) => {
handleOnNewValue(t, n);
}}
/>

View file

@ -75,7 +75,7 @@ export default function ModalField({
<TextAreaComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
onChange={(t: string | string[]) => {
data.node.template[name].value = t;
}}
/>
@ -136,7 +136,7 @@ export default function ModalField({
<InputFileComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
onChange={(t: string | string[]) => {
data.node.template[name].value = t;
}}
fileTypes={data.node.template[name].fileTypes}
@ -152,7 +152,7 @@ export default function ModalField({
field_name={name}
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
onChange={(t: string | string[]) => {
data.node.template[name].value = t;
}}
/>
@ -167,7 +167,7 @@ export default function ModalField({
nodeClass={data.node}
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
onChange={(t: string | string[]) => {
data.node.template[name].value = t;
}}
/>

View file

@ -28,16 +28,16 @@ export default function CodeAreaModal({
const [code, setCode] = useState(value);
const { dark } = useContext(darkContext);
const { reactFlowInstance } = useContext(typesContext);
const [height, setHeight] = useState(null);
const [height, setHeight] = useState<string | null>(null);
const { setErrorData, setSuccessData } = useContext(alertContext);
const [error, setError] = useState<{
detail: { error: string; traceback: string };
}>(null);
detail: { error: string | undefined; traceback: string | undefined };
} | null>(null);
useEffect(() => {
// if nodeClass.template has more fields other than code and dynamic is true
// do not run handleClick
if (dynamic && Object.keys(nodeClass.template).length > 2) {
if (dynamic && Object.keys(nodeClass!.template).length > 2) {
return;
}
processCode();
@ -84,7 +84,7 @@ export default function CodeAreaModal({
}
function processDynamicField() {
postCustomComponent(code, nodeClass)
postCustomComponent(code, nodeClass!)
.then((apiReturn) => {
const { data } = apiReturn;
if (data) {

View file

@ -31,8 +31,8 @@ const ExportModal = forwardRef(
</BaseModal.Header>
<BaseModal.Content>
<EditFlowSettings
name={name}
description={description}
name={name!}
description={description!}
flows={flows}
tabId={tabId}
setName={setName}
@ -57,14 +57,14 @@ const ExportModal = forwardRef(
onClick={() => {
if (checked)
downloadFlow(
flows.find((f) => f.id === tabId),
name,
flows.find((f) => f.id === tabId)!,
name!,
description
);
else
downloadFlow(
removeApiKeys(flows.find((f) => f.id === tabId)),
name,
removeApiKeys(flows.find((f) => f.id === tabId)!),
name!,
description
);
setOpen(false);

View file

@ -17,17 +17,17 @@ export default function FlowSettingsModal({
const { flows, tabId, updateFlow, setTabsState, saveFlow } =
useContext(TabsContext);
const maxLength = 50;
const [name, setName] = useState(flows.find((f) => f.id === tabId).name);
const [name, setName] = useState(flows.find((f) => f.id === tabId)!.name);
const [description, setDescription] = useState(
flows.find((f) => f.id === tabId).description
flows.find((f) => f.id === tabId)!.description
);
const [invalidName, setInvalidName] = useState(false);
function handleClick(): void {
let savedFlow = flows.find((f) => f.id === tabId);
savedFlow.name = name;
savedFlow.description = description;
saveFlow(savedFlow);
savedFlow!.name = name;
savedFlow!.description = description;
saveFlow(savedFlow!);
setSuccessData({ title: "Changes saved successfully" });
setOpen(false);
}

View file

@ -45,11 +45,11 @@ export default function FormModal({
const inputKeys = formKeysData.input_keys;
const handleKeys = formKeysData.handle_keys;
const keyToUse = Object.keys(inputKeys).find(
(k) => !handleKeys?.some((j) => j === k) && inputKeys[k] === ""
const keyToUse = Object.keys(inputKeys!).find(
(k) => !handleKeys?.some((j) => j === k) && inputKeys![k] === ""
);
return inputKeys[keyToUse];
return inputKeys![keyToUse!];
} catch (error) {
console.error(error);
// return a sensible default or `undefined` if no default is possible
@ -68,10 +68,10 @@ export default function FormModal({
const tabsStateFlowId = tabsState[flow.id];
const tabsStateFlowIdFormKeysData = tabsStateFlowId.formKeysData;
const [chatKey, setChatKey] = useState(
Object.keys(tabsState[flow.id].formKeysData.input_keys).find(
Object.keys(tabsState[flow.id].formKeysData.input_keys!).find(
(k) =>
!tabsState[flow.id].formKeysData.handle_keys.some((j) => j === k) &&
tabsState[flow.id].formKeysData.input_keys[k] === ""
!tabsState[flow.id].formKeysData.handle_keys!.some((j) => j === k) &&
tabsState[flow.id].formKeysData.input_keys![k] === ""
)
);
@ -211,7 +211,7 @@ export default function FormModal({
});
}
if (data.type === "start") {
addChatHistory("", false, chatKey);
addChatHistory("", false, chatKey!);
isStream = true;
}
if (data.type === "end") {
@ -335,16 +335,16 @@ export default function FormModal({
}, [open]);
function sendMessage(): void {
let nodeValidationErrors = validateNodes(reactFlowInstance);
let nodeValidationErrors = validateNodes(reactFlowInstance!);
if (nodeValidationErrors.length === 0) {
setLockChat(true);
let inputs = tabsState[id.current].formKeysData.input_keys;
setChatValue("");
const message = inputs;
addChatHistory(
message,
message!,
true,
chatKey,
chatKey!,
tabsState[flow.id].formKeysData.template
);
sendAll({
@ -357,7 +357,7 @@ export default function FormModal({
setTabsState((old) => {
if (!chatKey) return old;
let newTabsState = _.cloneDeep(old);
newTabsState[id.current].formKeysData.input_keys[chatKey] = "";
newTabsState[id.current].formKeysData.input_keys![chatKey] = "";
return newTabsState;
});
} else {
@ -376,9 +376,9 @@ export default function FormModal({
function handleOnCheckedChange(checked: boolean, i: string) {
if (checked === true) {
setChatKey(i);
setChatValue(tabsState[flow.id].formKeysData.input_keys[i]);
setChatValue(tabsState[flow.id].formKeysData.input_keys![i]);
} else {
setChatKey(null);
setChatKey(null!);
setChatValue("");
}
}
@ -422,7 +422,7 @@ export default function FormModal({
</div>
</div>
{Object.keys(tabsState[id.current].formKeysData.input_keys).map(
{Object.keys(tabsState[id.current].formKeysData.input_keys!).map(
(i, k) => (
<div className="file-component-accordion-div" key={k}>
<AccordionComponent
@ -465,12 +465,12 @@ export default function FormModal({
<Textarea
className="custom-scroll"
value={
tabsState[id.current].formKeysData.input_keys[i]
tabsState[id.current].formKeysData.input_keys![i]
}
onChange={(e) => {
setTabsState((old) => {
let newTabsState = _.cloneDeep(old);
newTabsState[id.current].formKeysData.input_keys[
newTabsState[id.current].formKeysData.input_keys![
i
] = e.target.value;
return newTabsState;
@ -578,7 +578,7 @@ export default function FormModal({
setChatValue(value);
setTabsState((old) => {
let newTabsState = _.cloneDeep(old);
newTabsState[id.current].formKeysData.input_keys[
newTabsState[id.current].formKeysData.input_keys![
chatKey
] = value;
return newTabsState;

View file

@ -39,7 +39,7 @@ export default function GenericModal({
const [myModalType] = useState(type);
const [inputValue, setInputValue] = useState(value);
const [isEdit, setIsEdit] = useState(true);
const [wordsHighlight, setWordsHighlight] = useState([]);
const [wordsHighlight, setWordsHighlight] = useState<string[]>([]);
const { setErrorData, setSuccessData, setNoticeData } =
useContext(alertContext);
const ref = useRef();
@ -48,14 +48,14 @@ export default function GenericModal({
function checkVariables(valueToCheck: string): void {
const regex = /\{([^{}]+)\}/g;
const matches = [];
const matches: string[] = [];
let match;
while ((match = regex.exec(valueToCheck))) {
matches.push(`{${match[1]}}`);
}
let invalid_chars = [];
let fixed_variables = [];
let invalid_chars: string[] = [];
let fixed_variables: string[] = [];
let input_variables = matches;
for (let variable of input_variables) {
let new_var = variable;
@ -120,7 +120,7 @@ export default function GenericModal({
}
function validatePrompt(closeModal: boolean): void {
postValidatePrompt(field_name, inputValue, nodeClass)
postValidatePrompt(field_name, inputValue, nodeClass!)
.then((apiReturn) => {
if (apiReturn.data) {
let inputVariables = apiReturn.data.input_variables ?? [];
@ -134,7 +134,7 @@ export default function GenericModal({
setSuccessData({
title: "Prompt is ready",
});
setNodeClass(apiReturn.data?.frontend_node);
setNodeClass!(apiReturn.data?.frontend_node);
setModalOpen(closeModal);
setValue(inputValue);
}

View file

@ -57,7 +57,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
const [position, setPosition] = useState({ x: 0, y: 0 });
const [lastSelection, setLastSelection] =
useState<OnSelectionChangeParams>(null);
useState<OnSelectionChangeParams | null>(null);
useEffect(() => {
// this effect is used to attach the global event handlers
@ -281,7 +281,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
setNodes((nds) => nds.concat(newNode));
} else if (event.dataTransfer.types.some((t) => t === "Files")) {
takeSnapshot();
uploadFlow(false, event.dataTransfer.files.item(0));
uploadFlow(false, event.dataTransfer.files.item(0)!);
}
},
// Specify dependencies for useCallback
@ -314,7 +314,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
const onEdgeUpdate = useCallback(
(oldEdge: Edge, newConnection: Connection) => {
if (isValidConnection(newConnection, reactFlowInstance)) {
if (isValidConnection(newConnection, reactFlowInstance!)) {
edgeUpdateSuccessful.current = true;
setEdges((els) => updateEdge(oldEdge, newConnection, els));
}
@ -404,7 +404,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
[&>button]:border-b-border hover:[&>button]:bg-border"
></Controls>
</ReactFlow>
<Chat flow={flow} reactFlowInstance={reactFlowInstance} />
<Chat flow={flow} reactFlowInstance={reactFlowInstance!} />
</div>
) : (
<></>

View file

@ -120,7 +120,7 @@ export default function ExtraSidebar(): JSX.Element {
"extra-side-bar-buttons " + (isPending ? "" : "button-disable")
}
onClick={(event) => {
saveFlow(flow);
saveFlow(flow!);
setSuccessData({ title: "Changes saved successfully" });
}}
>

View file

@ -13,7 +13,7 @@ export default function NodeToolbarComponent({
deleteNode,
}: nodeToolbarPropsType): JSX.Element {
const [nodeLength, setNodeLength] = useState(
Object.keys(data.node.template).filter(
Object.keys(data.node!.template).filter(
(t) =>
t.charAt(0) !== "_" &&
data.node?.template[t].show &&

View file

@ -10,7 +10,7 @@ export default function FlowPage(): JSX.Element {
// Set flow tab id
useEffect(() => {
setTabId(id);
setTabId(id!);
}, [id]);
// Initialize state variable for the version
@ -26,7 +26,7 @@ export default function FlowPage(): JSX.Element {
{flows.length > 0 &&
tabId !== "" &&
flows.findIndex((flow) => flow.id === tabId) !== -1 && (
<Page flow={flows.find((flow) => flow.id === tabId)} />
<Page flow={flows.find((flow) => flow.id === tabId)!} />
)}
<a
target={"_blank"}

View file

@ -45,7 +45,7 @@ export default function HomePage(): JSX.Element {
<Button
variant="primary"
onClick={() => {
addFlow(null, true).then((id) => {
addFlow(null!, true).then((id) => {
navigate("/flow/" + id);
});
}}

View file

@ -180,7 +180,7 @@ export type InputProps = {
invalidName: boolean;
setName: (name: string) => void;
setDescription: (description: string) => void;
updateFlow: (flow: { id: string; name: string }) => void;
updateFlow: (flow: { id: string; name: string; }) => void;
setInvalidName: (invalidName: boolean) => void;
};
@ -208,7 +208,6 @@ export interface languageMap {
}
export type groupedObjType = {
component: string;
family: string;
type: string;
};
@ -384,6 +383,7 @@ type tabsArrayType = {
language: string;
mode: string;
name: string;
description: string;
};
type getValueNodeType = {
@ -427,3 +427,10 @@ export type crashComponentPropsType = {
};
resetErrorBoundary: (args) => void;
};
export type validationStatusType = {
id: string;
params: string;
progress: number;
valid: boolean;
};

View file

@ -11,7 +11,7 @@ export type FlowType = {
export type NodeType = {
id: string;
type?: string;
position: XYPosition;
position: XYPosition | undefined;
data: NodeDataType;
};
export type NodeDataType = {

View file

@ -38,7 +38,7 @@ export function cleanEdges({
const id = [
sourceNode.data.type,
sourceNode.data.id,
...sourceNode.data.node?.base_classes,
...sourceNode.data.node?.base_classes!,
].join("|");
if (id !== sourceHandle) {
newEdges = newEdges.filter((e) => e.id !== edge.id);
@ -69,7 +69,7 @@ export function isValidConnection(
) ||
targetHandle?.split("|")[0] === "str"
) {
let targetNode = reactFlowInstance?.getNode(target)?.data?.node;
let targetNode = reactFlowInstance?.getNode(target!)?.data?.node;
if (!targetNode) {
if (
!reactFlowInstance
@ -79,11 +79,11 @@ export function isValidConnection(
return true;
}
} else if (
(!targetNode.template[targetHandle?.split("|")[1]].list &&
(!targetNode.template[targetHandle?.split("|")[1]!].list &&
!reactFlowInstance
.getEdges()
.find((e) => e.targetHandle === targetHandle)) ||
targetNode.template[targetHandle?.split("|")[1]].list
targetNode.template[targetHandle?.split("|")[1]!].list
) {
return true;
}

View file

@ -5,6 +5,7 @@ import { IVarHighlightType, groupDataType, groupedObjType, tweakType } from "../
import { FlowType, NodeType } from "../types/flow";
import { TabsState } from "../types/tabs";
import { buildTweaks } from "./reactflowUtils";
import { APIClassType, APIObjectType } from "../types/api";
export function classNames(...classes: Array<string>): string {
return classes.filter(Boolean).join(" ");
@ -88,10 +89,10 @@ export function checkUpperWords(str: string): string {
export const isWrappedWithClass = (event: any, className: string | undefined) =>
event.target.closest(`.${className}`);
export function groupByFamily(data: groupDataType, baseClasses: string, left: boolean, flow?: NodeType[]): groupedObjType[] {
export function groupByFamily(data, baseClasses: string, left: boolean, flow?: NodeType[]): groupedObjType[] {
const baseClassesSet = new Set(baseClasses.split("\n"));
let arrOfPossibleInputs = [];
let arrOfPossibleOutputs = [];
let arrOfPossibleInputs: Array<{ category: string; nodes: string[]; full: boolean; }> = [];
let arrOfPossibleOutputs: Array<{ category: string; nodes: string[]; full: boolean; }> = [];
let checkedNodes = new Map();
const excludeTypes = new Set([
"str",
@ -116,26 +117,26 @@ export function groupByFamily(data: groupDataType, baseClasses: string, left: bo
checkedNodes.set(nodeData.type, {
hasBaseClassInTemplate:
foundNode?.hasBaseClassInTemplate ||
Object.values(nodeData.node.template).some(checkBaseClass),
Object.values(nodeData.node!.template).some(checkBaseClass),
hasBaseClassInBaseClasses:
foundNode?.hasBaseClassInBaseClasses ||
nodeData.node.base_classes.some((t) => baseClassesSet.has(t)),
nodeData.node!.base_classes.some((t) => baseClassesSet.has(t)),
});
}
}
for (const [d, nodes] of Object.entries(data)) {
let tempInputs = [],
tempOutputs = [];
let tempInputs: string[] = [],
tempOutputs: string[] = [];
for (const [n, node] of Object.entries(nodes)) {
let foundNode = checkedNodes.get(n);
if (!foundNode) {
foundNode = {
hasBaseClassInTemplate: Object.values(node.template).some(
hasBaseClassInTemplate: Object.values(node!.template).some(
checkBaseClass
),
hasBaseClassInBaseClasses: node.base_classes.some((t) =>
hasBaseClassInBaseClasses: node!.base_classes.some((t) =>
baseClassesSet.has(t)
),
};
@ -177,7 +178,7 @@ export function buildInputs(tabsState: TabsState, id: string): string {
tabsState[id] &&
tabsState[id].formKeysData &&
tabsState[id].formKeysData.input_keys &&
Object.keys(tabsState[id].formKeysData.input_keys).length > 0
Object.keys(tabsState[id].formKeysData.input_keys!).length > 0
? JSON.stringify(tabsState[id].formKeysData.input_keys)
: '{"input": "message"}';
}
@ -265,7 +266,7 @@ export function getPythonApiCode(
// node.data.id
// }
const tweaks = buildTweaks(flow);
const inputs = buildInputs(tabsState, flow.id);
const inputs = buildInputs(tabsState!, flow.id);
return `import requests
from typing import Optional
@ -317,7 +318,7 @@ export function getCurlCode(
): string {
const flowId = flow.id;
const tweaks = buildTweaks(flow);
const inputs = buildInputs(tabsState, flow.id);
const inputs = buildInputs(tabsState!, flow.id);
return `curl -X POST \\
${window.location.protocol}//${
@ -343,7 +344,7 @@ export function getPythonCode(
): string {
const flowName = flow.name;
const tweaks = buildTweaks(flow);
const inputs = buildInputs(tabsState, flow.id);
const inputs = buildInputs(tabsState!, flow.id);
return `from langflow import load_flow_from_json
TWEAKS = ${
tweak && tweak.length > 0
@ -364,7 +365,7 @@ flow(inputs)`;
export function getWidgetCode(flow: FlowType, tabsState?: TabsState): string {
const flowId = flow.id;
const flowName = flow.name;
const inputs = buildInputs(tabsState, flow.id);
const inputs = buildInputs(tabsState!, flow.id);
return `<script src="https://cdn.jsdelivr.net/gh/logspace-ai/langflow-embedded-chat@main/dist/build/static/js/bundle.min.js"></script>
@ -375,10 +376,10 @@ chat_input_field: Input key that you want the chat to send the user message with
window_title="${flowName}"
flow_id="${flowId}"
${
tabsState[flow.id] && tabsState[flow.id].formKeysData
tabsState![flow.id] && tabsState![flow.id].formKeysData
? `chat_inputs='${inputs}'
chat_input_field="${
Object.keys(tabsState[flow.id].formKeysData.input_keys)[0]
Object.keys(tabsState![flow.id].formKeysData.input_keys!)[0]
}"
`
: ""

View file

@ -6,7 +6,7 @@
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",