Fixed glitches that don't affect usability (#1800)

* Fixed bug of main page showing Empty page before showing components

* Added timeout to generic icon lazy loading

* Create an abort signal for the program to not fetch twice at the beginning

* Removed global variables functionality at tweaks
This commit is contained in:
Lucas Oliveira 2024-04-30 21:33:30 +02:00 committed by GitHub
commit ee6aa0c6dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 112 additions and 107 deletions

View file

@ -63,9 +63,10 @@ export default function App() {
}, [dark]);
useEffect(() => {
const abortController = new AbortController();
const isLoginPage = location.pathname.includes("login");
autoLogin()
autoLogin(abortController.signal)
.then(async (user) => {
if (user && user["access_token"]) {
user["refresh_token"] = "auto";
@ -76,31 +77,44 @@ export default function App() {
await Promise.all([refreshStars(), refreshVersion(), fetchData()]);
}
})
.catch(async () => {
setAutoLogin(false);
if (isAuthenticated && !isLoginPage) {
getUser();
await Promise.all([refreshStars(), refreshVersion(), fetchData()]);
} else {
setLoading(false);
useFlowsManagerStore.setState({ isLoading: false });
.catch(async (error) => {
if (error.name !== "CanceledError") {
setAutoLogin(false);
if (isAuthenticated && !isLoginPage) {
getUser();
await Promise.all([refreshStars(), refreshVersion(), fetchData()]);
} else {
setLoading(false);
useFlowsManagerStore.setState({ isLoading: false });
}
}
});
}, [isAuthenticated]);
/*
Abort the request as it isn't needed anymore, the component being
unmounted. It helps avoid, among other things, the well-known "can't
perform a React state update on an unmounted component" warning.
*/
return () => abortController.abort();
}, []);
const fetchData = async () => {
if (isAuthenticated) {
try {
await getTypes();
refreshFlows();
const res = await getGlobalVariables();
setGlobalVariables(res);
checkHasStore();
fetchApiData();
} catch (error) {
console.error("Failed to fetch data:", error);
return new Promise<void>(async (resolve, reject) => {
if (isAuthenticated) {
try {
await getTypes();
await refreshFlows();
const res = await getGlobalVariables();
setGlobalVariables(res);
checkHasStore();
fetchApiData();
resolve();
} catch (error) {
console.error("Failed to fetch data:", error);
reject();
}
}
}
});
};
useEffect(() => {

View file

@ -39,8 +39,8 @@ import { classNames } from "../../utils/utils";
import ShadTooltip from "../ShadTooltipComponent";
import DictComponent from "../dictComponent";
import IconComponent from "../genericIconComponent";
import InputGlobalComponent from "../inputGlobalComponent";
import KeypairListComponent from "../keypairListComponent";
import InputComponent from "../inputComponent";
export default function CodeTabsComponent({
flow,
@ -351,31 +351,38 @@ export default function CodeTabsComponent({
/>
</div>
) : (
<InputGlobalComponent
<InputComponent
editNode={true}
disabled={false}
password={
node.data.node.template[
templateField
].password ?? false
}
value={
!node.data.node.template[
templateField
].value ||
node.data.node.template[
templateField
].value === ""
? ""
: node.data.node
.template[
templateField
].value
}
onChange={(target) => {
if (node.data) {
setNode(
node.data.id,
(oldNode) => {
let newNode =
cloneDeep(
oldNode
);
newNode.data = {
...newNode.data,
};
newNode.data.node.template[
templateField
].value = target;
return newNode;
}
);
}
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList![
i
].data.node.template[
templateField
].value = target;
return newInputList;
});
tweaks.buildTweakObject!(
node["data"]["id"],
target,
@ -384,25 +391,6 @@ export default function CodeTabsComponent({
]
);
}}
setDb={(value) => {
setNode(
node.data.id,
(oldNode) => {
let newNode =
cloneDeep(oldNode);
newNode.data = {
...newNode.data,
};
newNode.data.node.template[
templateField
].load_from_db =
value;
return newNode;
}
);
}}
name={templateField}
data={node.data}
/>
)}
</div>

View file

@ -5,6 +5,8 @@ import { nodeIconsLucide } from "../../utils/styleUtils";
import { cn } from "../../utils/utils";
import Loading from "../ui/loading";
import { useEffect, useState } from "react";
const ForwardedIconComponent = memo(
forwardRef(
(
@ -18,9 +20,18 @@ const ForwardedIconComponent = memo(
}: IconComponentProps,
ref
) => {
const [showFallback, setShowFallback] = useState(false);
useEffect(() => {
const timer = setTimeout(() => {
setShowFallback(true);
}, 30);
return () => clearTimeout(timer);
}, []);
let TargetIcon = nodeIconsLucide[name];
if (!TargetIcon) {
// check if name exists in dynamicIconImports
if (!dynamicIconImports[name]) {
TargetIcon = nodeIconsLucide["unknown"];
} else TargetIcon = lazy(dynamicIconImports[name]);
@ -35,11 +46,15 @@ const ForwardedIconComponent = memo(
if (!TargetIcon) {
return null; // Render nothing until the icon is loaded
}
const fallback = (
const fallback = showFallback ? (
<div className={cn(className, "flex items-center justify-center")}>
<Loading />
</div>
) : (
<div className={className}></div>
);
return (
<Suspense fallback={fallback}>
<TargetIcon

View file

@ -406,9 +406,11 @@ export async function onLogin(user: LoginType) {
}
}
export async function autoLogin() {
export async function autoLogin(abortSignal) {
try {
const response = await api.get(`${BASE_URL_API}auto_login`);
const response = await api.get(`${BASE_URL_API}auto_login`, {
signal: abortSignal,
});
if (response.status === 200) {
const data = response.data;

View file

@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import PaginatorComponent from "../../../../components/PaginatorComponent";
import CollectionCardComponent from "../../../../components/cardComponent";
@ -24,43 +24,36 @@ export default function ComponentsComponent({
const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow);
const removeFlow = useFlowsManagerStore((state) => state.removeFlow);
const isLoading = useFlowsManagerStore((state) => state.isLoading);
const setExamples = useFlowsManagerStore((state) => state.setExamples);
const flows = useFlowsManagerStore((state) => state.flows);
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData);
const [pageSize, setPageSize] = useState(20);
const [pageIndex, setPageIndex] = useState(1);
const [loadingScreen, setLoadingScreen] = useState(true);
const navigate = useNavigate();
useEffect(() => {
if (isLoading) return;
let all = flows
.filter((f) => (f.is_component ?? false) === is_component)
.sort((a, b) => {
if (a?.updated_at && b?.updated_at) {
return (
new Date(b?.updated_at!).getTime() -
new Date(a?.updated_at!).getTime()
);
} else if (a?.updated_at && !b?.updated_at) {
return 1;
} else if (!a?.updated_at && b?.updated_at) {
return -1;
} else {
return (
new Date(b?.date_created!).getTime() -
new Date(a?.date_created!).getTime()
);
}
});
const start = (pageIndex - 1) * pageSize;
const end = start + pageSize;
setData(all.slice(start, end));
}, [flows, isLoading, pageIndex, pageSize]);
const [data, setData] = useState<FlowType[]>([]);
const all: FlowType[] = flows
.filter((f) => (f.is_component ?? false) === is_component)
.sort((a, b) => {
if (a?.updated_at && b?.updated_at) {
return (
new Date(b?.updated_at!).getTime() -
new Date(a?.updated_at!).getTime()
);
} else if (a?.updated_at && !b?.updated_at) {
return 1;
} else if (!a?.updated_at && b?.updated_at) {
return -1;
} else {
return (
new Date(b?.date_created!).getTime() -
new Date(a?.date_created!).getTime()
);
}
});
const start = (pageIndex - 1) * pageSize;
const end = start + pageSize;
const data: FlowType[] = all.slice(start, end);
const name = is_component ? "Component" : "Flow";
@ -149,7 +142,7 @@ export default function ComponentsComponent({
resetFilter();
}}
key={idx}
data={item}
data={{ is_component: item.is_component ?? false, ...item }}
disabled={isLoading}
button={
!is_component ? (

View file

@ -1,5 +1,4 @@
import { useEffect } from "react";
import { Route, Routes, useNavigate } from "react-router-dom";
import { Navigate, Route, Routes } from "react-router-dom";
import { ProtectedAdminRoute } from "./components/authAdminGuard";
import { ProtectedRoute } from "./components/authGuard";
import { ProtectedLoginRoute } from "./components/authLoginGuard";
@ -19,13 +18,6 @@ import LoginPage from "./pages/loginPage";
import SignUp from "./pages/signUpPage";
const Router = () => {
const navigate = useNavigate();
useEffect(() => {
// Redirect from root to /flows
if (window.location.pathname === "/") {
navigate("/flows");
}
}, [navigate]);
return (
<Routes>
<Route
@ -36,6 +28,7 @@ const Router = () => {
</ProtectedRoute>
}
>
<Route index element={<Navigate replace to={"flows"} />} />
<Route
path="flows"
element={<ComponentsComponent key="flows" is_component={false} />}