Implement "In Progress" Status for Component Building (#1449)

This pull request introduces a new "In Progress" status for the
component building process within our application. This status will
bridge the gap between "Not Started" and "Completed," providing more
granular visibility into the component's lifecycle.
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-02-20 11:33:57 -03:00 committed by GitHub
commit 98ae37f24e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 138 additions and 43 deletions

View file

@ -7,6 +7,7 @@ import InputComponent from "../../components/inputComponent";
import { Button } from "../../components/ui/button";
import { Textarea } from "../../components/ui/textarea";
import { priorityFields } from "../../constants/constants";
import { BuildStatus } from "../../constants/enums";
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
@ -71,7 +72,6 @@ export default function GenericNode({
setHandles(count);
}
useEffect(() => {
countHandles();
}, [data, data.node]);
@ -157,6 +157,78 @@ export default function GenericNode({
);
};
const getIconPlayOrPauseComponent = (name, className) => (
<IconComponent
name={name}
className={`absolute h-5 stroke-2 ${className} ml-0.5`}
/>
);
const getStatusClassName = (
validationStatus: validationStatusType | null,
isBuilding: boolean
) => {
if (validationStatus && validationStatus.valid) {
return "green-status";
} else if (validationStatus && !validationStatus.valid) {
return "red-status";
} else if (!validationStatus || isBuilding) {
return "yellow-status";
} else {
return "status-build-animation";
}
};
const renderIconPlayOrPauseComponents = (
buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null,
isBuilding: boolean
) => {
if (buildStatus === BuildStatus.BUILDING) {
return getIconPlayOrPauseComponent("Square", "red-status");
} else {
const className = getStatusClassName(validationStatus, isBuilding);
return <>{getIconPlayOrPauseComponent("Play", className)}</>;
}
};
const getSpecificClassFromBuildStatus = (
buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null
) => {
if (
buildStatus === BuildStatus.BUILDED &&
validationStatus &&
!validationStatus.valid
) {
return "border-none ring ring-red-300";
} else if (buildStatus === BuildStatus.BUILDING) {
return "border-none ring";
} else {
return "";
}
};
const getNodeBorderClassName = (
selected: boolean,
showNode: boolean,
buildStatus: BuildStatus | undefined,
validationStatus: validationStatusType | null
) => {
return classNames(
getBaseBorderClass(selected),
getNodeSizeClass(showNode),
"generic-node-div",
getSpecificClassFromBuildStatus(buildStatus, validationStatus)
);
};
const getBaseBorderClass = (selected) =>
selected ? "border border-ring" : "border";
const getNodeSizeClass = (showNode) =>
showNode ? "w-96 rounded-lg" : "w-26 h-26 rounded-full";
return (
<>
<NodeToolbar>
@ -181,10 +253,11 @@ export default function GenericNode({
</NodeToolbar>
<div
className={classNames(
selected ? "border border-ring" : "border",
showNode ? " w-96 rounded-lg" : " w-26 h-26 rounded-full",
"generic-node-div"
className={getNodeBorderClassName(
selected,
showNode,
data?.build_status,
validationStatus
)}
>
{data.node?.beta && showNode && (
@ -396,7 +469,8 @@ export default function GenericNode({
<div>
<Tooltip
title={
isBuilding ? (
isBuilding ||
data?.build_status === BuildStatus.BUILDING ? (
<span>Building...</span>
) : !validationStatus ? (
<span className="flex">
@ -421,33 +495,11 @@ export default function GenericNode({
}
>
<div className="generic-node-status-position flex items-center justify-center">
<IconComponent
name="Play"
className={classNames(
validationStatus && validationStatus.valid
? "green-status"
: "status-build-animation",
"absolute h-5 stroke-2"
)}
/>
<IconComponent
name="AlertCircle"
className={classNames(
validationStatus && !validationStatus.valid
? "red-status"
: "status-build-animation",
"absolute h-5 stroke-2"
)}
/>
<IconComponent
name="Play"
className={classNames(
!validationStatus || isBuilding
? "yellow-status"
: "status-build-animation",
"absolute h-5 stroke-2"
)}
/>
{renderIconPlayOrPauseComponents(
data?.build_status,
validationStatus,
isBuilding
)}
</div>
</Tooltip>
</div>

View file

@ -6,3 +6,9 @@ export enum TypeModal {
TEXT = 1,
PROMPT = 2,
}
export enum BuildStatus {
BUILDING = "BUILDING",
TO_BUILD = "TO_BUILD",
BUILDED = "BUILDED",
}

View file

@ -205,7 +205,6 @@ export default function FormModal({
if (Array.isArray(data) && data.length > 0) {
//set chat history
setChatHistory((_) => {
console.log(data);
let newChatHistory: ChatMessageType[] = [];
for (let i = 0; i < data.length; i++) {
if (data[i].type === "prompt" && data[i].prompt) {

View file

@ -11,6 +11,7 @@ import {
} from "reactflow";
import { create } from "zustand";
import { INPUT_TYPES, OUTPUT_TYPES } from "../constants/constants";
import { BuildStatus } from "../constants/enums";
import { getFlowPool, updateFlowInDatabase } from "../controllers/API";
import {
NodeDataType,
@ -380,6 +381,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
const setNoticeData = useAlertStore.getState().setNoticeData;
function handleBuildUpdate(data: any) {
get().addDataToFlowPool(data.data[data.id], data.id);
useFlowStore.getState().updateBuildStatus([data.id], BuildStatus.BUILDED);
}
await updateFlowInDatabase({
data: {
@ -403,9 +405,14 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
}
},
onBuildUpdate: handleBuildUpdate,
onBuildError: (title, list) => {
onBuildError: (title, list, idList) => {
useFlowStore.getState().updateBuildStatus(idList, BuildStatus.BUILDED);
setErrorData({ list, title });
},
onBuildStart: (idList) => {
useFlowStore.getState().updateBuildStatus(idList, BuildStatus.BUILDING);
},
});
},
getFlow: () => {
@ -415,6 +422,15 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
viewport: get().reactFlowInstance?.getViewport()!,
};
},
updateBuildStatus: (nodeIdList: string[], status: BuildStatus) => {
nodeIdList.forEach((id) => {
const nodeToUpdate = get().nodes.find((node) => node.id === id);
if (nodeToUpdate) {
nodeToUpdate.data.build_status = status;
get().setNodes(get().nodes);
}
});
},
}));
export default useFlowStore;

View file

@ -1,4 +1,5 @@
import { Edge, Node, Viewport } from "reactflow";
import { BuildStatus } from "../../constants/enums";
import { FlowType } from "../flow";
//kind and class are just representative names to represent the actual structure of the object received by the API
export type APIDataType = { [key: string]: APIKindType };
@ -36,6 +37,7 @@ export type APIClassType = {
| CustomFieldsType
| boolean
| undefined;
build_status?: BuildStatus;
};
export type TemplateVariableType = {

View file

@ -625,7 +625,7 @@ export type crashComponentPropsType = {
export type validationStatusType = {
id: string;
data: object;
data: object | any;
params: string;
progress: number;
valid: boolean;

View file

@ -1,4 +1,5 @@
import { ReactFlowJsonObject, XYPosition } from "reactflow";
import { BuildStatus } from "../../constants/enums";
import { APIClassType } from "../api/index";
export type FlowType = {
@ -26,6 +27,7 @@ export type NodeDataType = {
node?: APIClassType;
id: string;
output_types?: string[];
build_status?: BuildStatus;
};
// FlowStyleType is the type of the style object that is used to style the
// Flow card with an emoji and a color.

View file

@ -7,6 +7,7 @@ import {
ReactFlowInstance,
Viewport,
} from "reactflow";
import { BuildStatus } from "../../../constants/enums";
import { FlowState } from "../../tabs";
export type chatInputType = {
@ -85,4 +86,5 @@ export type FlowStoreType = {
unselectAll: () => void;
buildFlow: (nodeId?: string) => Promise<void>;
getFlow: () => { nodes: Node[]; edges: Edge[]; viewport: Viewport };
updateBuildStatus: (nodeId: string[], status: BuildStatus) => void;
};

View file

@ -1,5 +1,7 @@
import { AxiosError } from "axios";
import { BuildStatus } from "../constants/enums";
import { getVerticesOrder, postBuildVertex } from "../controllers/API";
import useFlowStore from "../stores/flowStore";
import { VertexBuildTypeAPI } from "../types/api";
type BuildVerticesParams = {
@ -8,7 +10,8 @@ type BuildVerticesParams = {
onProgressUpdate?: (progress: number) => void; // Replace number with the actual type if it's not a number
onBuildUpdate?: (data: any) => void; // Replace any with the actual type of data
onBuildComplete?: (allNodesValid: boolean) => void;
onBuildError?: (title, list) => void;
onBuildError?: (title, list, idList: string[]) => void;
onBuildStart?: (idList: string[]) => void;
};
export async function buildVertices({
@ -18,10 +21,12 @@ export async function buildVertices({
onBuildUpdate,
onBuildComplete,
onBuildError,
onBuildStart,
}: BuildVerticesParams) {
let orderResponse = await getVerticesOrder(flowId, nodeId);
let verticesOrder: Array<Array<string>> = orderResponse.data.ids;
let vertices: Array<Array<string>> = [];
if (nodeId) {
for (let i = 0; i < verticesOrder.length; i += 1) {
const innerArray = verticesOrder[i];
@ -40,10 +45,13 @@ export async function buildVertices({
vertices = verticesOrder;
}
// Set each vertex state to building
const verticesIds = vertices.flatMap((v) => v);
useFlowStore.getState().updateBuildStatus(verticesIds, BuildStatus.TO_BUILD);
// Set each vertex state to building
const buildResults: Array<boolean> = [];
for (let i = 0; i < vertices.length; i += 1) {
if (onBuildStart) onBuildStart(vertices[i]);
await Promise.all(
vertices[i].map(async (id) => {
try {
@ -54,7 +62,11 @@ export async function buildVertices({
let data = {};
if (!buildData.valid) {
if (onBuildError) {
onBuildError("Error Building Component", [buildData.params]);
onBuildError(
"Error Building Component",
[buildData.params],
verticesIds
);
}
}
data[buildData.id] = buildData;
@ -64,10 +76,14 @@ export async function buildVertices({
} catch (error) {
if (onBuildError) {
console.log(error);
onBuildError("Error Building Component", [
(error as AxiosError<any>).response?.data?.detail ??
"Unknown Error",
]);
onBuildError(
"Error Building Component",
[
(error as AxiosError<any>).response?.data?.detail ??
"Unknown Error",
],
verticesIds
);
}
}
})