refactor: reduce menu bar rerenders (#7589)
* reduce menu bar rerenders * imports cleanup * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
8983516381
commit
2c2a348a2f
3 changed files with 73 additions and 31 deletions
|
|
@ -4,7 +4,6 @@ import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
|||
import useAddFlow from "@/hooks/flows/use-add-flow";
|
||||
import useSaveFlow from "@/hooks/flows/use-save-flow";
|
||||
import useUploadFlow from "@/hooks/flows/use-upload-flow";
|
||||
import { customStringify } from "@/utils/reactflowUtils";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
|
||||
import IconComponent from "@/components/common/genericIconComponent";
|
||||
|
|
@ -22,6 +21,7 @@ import { UPLOAD_ERROR_ALERT } from "@/constants/alerts_constants";
|
|||
import { SAVED_HOVER } from "@/constants/constants";
|
||||
import { useGetRefreshFlowsQuery } from "@/controllers/API/queries/flows/use-get-refresh-flows-query";
|
||||
import { useGetFoldersQuery } from "@/controllers/API/queries/folders/use-get-folders";
|
||||
import { useUnsavedChanges } from "@/hooks/useUnsavedChanges";
|
||||
import ExportModal from "@/modals/exportModal";
|
||||
import FlowLogsModal from "@/modals/flowLogsModal";
|
||||
import FlowSettingsModal from "@/modals/flowSettingsModal";
|
||||
|
|
@ -33,6 +33,7 @@ import { useShortcutsStore } from "@/stores/shortcuts";
|
|||
import { swatchColors } from "@/utils/styleUtils";
|
||||
import { cn, getNumberFromString } from "@/utils/utils";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useShallow } from "zustand/react/shallow";
|
||||
|
||||
export const MenuBar = ({}: {}): JSX.Element => {
|
||||
const shortcuts = useShortcutsStore((state) => state.shortcuts);
|
||||
|
|
@ -50,18 +51,36 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
const saveFlow = useSaveFlow();
|
||||
const queryClient = useQueryClient();
|
||||
const autoSaving = useFlowsManagerStore((state) => state.autoSaving);
|
||||
const currentFlow = useFlowStore((state) => state.currentFlow);
|
||||
const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow);
|
||||
const updatedAt = currentSavedFlow?.updated_at;
|
||||
const {
|
||||
currentFlowName,
|
||||
currentFlowId,
|
||||
currentFlowFolderId,
|
||||
currentFlowIcon,
|
||||
currentFlowGradient,
|
||||
} = useFlowStore(
|
||||
useShallow((state) => ({
|
||||
currentFlowName: state.currentFlow?.name,
|
||||
currentFlowId: state.currentFlow?.id,
|
||||
currentFlowFolderId: state.currentFlow?.folder_id,
|
||||
currentFlowIcon: state.currentFlow?.icon,
|
||||
currentFlowGradient: state.currentFlow?.gradient,
|
||||
})),
|
||||
);
|
||||
const { updated_at: updatedAt } = useFlowsManagerStore(
|
||||
useShallow((state) => ({
|
||||
updated_at: state.currentFlow?.updated_at,
|
||||
})),
|
||||
);
|
||||
const onFlowPage = useFlowStore((state) => state.onFlowPage);
|
||||
const setCurrentFlow = useFlowsManagerStore((state) => state.setCurrentFlow);
|
||||
const stopBuilding = useFlowStore((state) => state.stopBuilding);
|
||||
const [editingName, setEditingName] = useState(false);
|
||||
const [flowName, setFlowName] = useState(currentFlow?.name ?? "");
|
||||
const [flowName, setFlowName] = useState(currentFlowName ?? "");
|
||||
const [isInvalidName, setIsInvalidName] = useState(false);
|
||||
const nameInputRef = useRef<HTMLInputElement>(null);
|
||||
const [inputWidth, setInputWidth] = useState<number>(0);
|
||||
const measureRef = useRef<HTMLSpanElement>(null);
|
||||
const changesNotSaved = useUnsavedChanges();
|
||||
|
||||
const { data: folders, isFetched: isFoldersFetched } = useGetFoldersQuery();
|
||||
const flows = useFlowsManagerStore((state) => state.flows);
|
||||
|
|
@ -73,9 +92,9 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
flows.forEach((flow) => {
|
||||
tempNameList.push(flow.name);
|
||||
});
|
||||
setNameList(tempNameList.filter((name) => name !== currentFlow?.name));
|
||||
setNameList(tempNameList.filter((name) => name !== currentFlowName));
|
||||
}
|
||||
}, [flows, currentFlow?.name]);
|
||||
}, [flows, currentFlowName]);
|
||||
|
||||
useGetRefreshFlowsQuery(
|
||||
{
|
||||
|
|
@ -86,13 +105,10 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
);
|
||||
|
||||
const currentFolder = useMemo(
|
||||
() => folders?.find((f) => f.id === currentFlow?.folder_id),
|
||||
[folders, currentFlow?.folder_id],
|
||||
() => folders?.find((f) => f.id === currentFlowFolderId),
|
||||
[folders, currentFlowFolderId],
|
||||
);
|
||||
|
||||
const changesNotSaved =
|
||||
customStringify(currentFlow) !== customStringify(currentSavedFlow);
|
||||
|
||||
useEffect(() => {
|
||||
if (measureRef.current) {
|
||||
setInputWidth(measureRef.current.offsetWidth);
|
||||
|
|
@ -163,26 +179,29 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Escape") {
|
||||
setEditingName(false);
|
||||
setFlowName(currentFlow?.name ?? "");
|
||||
setFlowName(currentFlowName ?? "");
|
||||
setIsInvalidName(false);
|
||||
}
|
||||
if (e.key === "Enter") {
|
||||
nameInputRef.current?.blur();
|
||||
}
|
||||
},
|
||||
[currentFlow?.name],
|
||||
[currentFlowName],
|
||||
);
|
||||
|
||||
const handleNameSubmit = useCallback(() => {
|
||||
if (
|
||||
flowName.trim() !== "" &&
|
||||
flowName !== currentFlow?.name &&
|
||||
flowName !== currentFlowName &&
|
||||
!isInvalidName
|
||||
) {
|
||||
// Get a one-time snapshot of currentFlow using get()
|
||||
const currentFlowSnapshot = useFlowStore.getState().currentFlow;
|
||||
|
||||
const newFlow = {
|
||||
...currentFlow!,
|
||||
...currentFlowSnapshot!,
|
||||
name: flowName,
|
||||
id: currentFlow!.id,
|
||||
id: currentFlowId!,
|
||||
};
|
||||
setCurrentFlow(newFlow);
|
||||
saveFlow(newFlow)
|
||||
|
|
@ -194,22 +213,23 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
title: "Error updating flow name",
|
||||
list: [(error as Error).message],
|
||||
});
|
||||
setFlowName(currentFlow?.name ?? "");
|
||||
setFlowName(currentFlowName ?? "");
|
||||
});
|
||||
} else if (isInvalidName) {
|
||||
setErrorData({
|
||||
title: "Invalid flow name",
|
||||
list: ["Name already exists"],
|
||||
});
|
||||
setFlowName(currentFlow?.name ?? "");
|
||||
setFlowName(currentFlowName ?? "");
|
||||
} else {
|
||||
setFlowName(currentFlow?.name ?? "");
|
||||
setFlowName(currentFlowName ?? "");
|
||||
}
|
||||
setEditingName(false);
|
||||
setIsInvalidName(false);
|
||||
}, [
|
||||
flowName,
|
||||
currentFlow,
|
||||
currentFlowName,
|
||||
currentFlowId,
|
||||
setCurrentFlow,
|
||||
saveFlow,
|
||||
setSuccessData,
|
||||
|
|
@ -218,10 +238,10 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentFlow && !editingName) {
|
||||
setFlowName(currentFlow.name);
|
||||
if (currentFlowName && !editingName) {
|
||||
setFlowName(currentFlowName);
|
||||
}
|
||||
}, [currentFlow, editingName]);
|
||||
}, [currentFlowName, editingName]);
|
||||
|
||||
useEffect(() => {
|
||||
if (measureRef.current) {
|
||||
|
|
@ -230,12 +250,12 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
}, [flowName]);
|
||||
|
||||
const swatchIndex =
|
||||
(currentFlow?.gradient && !isNaN(parseInt(currentFlow?.gradient))
|
||||
? parseInt(currentFlow?.gradient)
|
||||
: getNumberFromString(currentFlow?.gradient ?? currentFlow?.id ?? "")) %
|
||||
(currentFlowGradient && !isNaN(parseInt(currentFlowGradient))
|
||||
? parseInt(currentFlowGradient)
|
||||
: getNumberFromString(currentFlowGradient ?? currentFlowId ?? "")) %
|
||||
swatchColors.length;
|
||||
|
||||
return currentFlow && onFlowPage ? (
|
||||
return currentFlowName && onFlowPage ? (
|
||||
<div
|
||||
className="flex w-full items-center justify-center gap-2"
|
||||
data-testid="menu_bar_wrapper"
|
||||
|
|
@ -270,7 +290,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
</div>
|
||||
<div className={cn(`flex rounded p-1`, swatchColors[swatchIndex])}>
|
||||
<IconComponent
|
||||
name={currentFlow?.icon ?? "Workflow"}
|
||||
name={currentFlowIcon ?? "Workflow"}
|
||||
className="h-3.5 w-3.5"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -305,7 +325,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
onKeyDown={handleKeyDown}
|
||||
onFocus={() => {
|
||||
setEditingName(true);
|
||||
setFlowName(currentFlow.name);
|
||||
setFlowName(currentFlowName);
|
||||
}}
|
||||
onBlur={handleNameSubmit}
|
||||
value={flowName}
|
||||
|
|
|
|||
18
src/frontend/src/hooks/useUnsavedChanges.ts
Normal file
18
src/frontend/src/hooks/useUnsavedChanges.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import useFlowStore from "../stores/flowStore";
|
||||
import useFlowsManagerStore from "../stores/flowsManagerStore";
|
||||
import { customStringify } from "../utils/reactflowUtils";
|
||||
|
||||
export function useUnsavedChanges() {
|
||||
const currentFlow = useFlowStore((state) => state.currentFlow);
|
||||
const savedFlow = useFlowsManagerStore((state) => state.currentFlow);
|
||||
|
||||
if (!currentFlow || !savedFlow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((currentFlow?.data?.nodes?.length ?? 0) > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return customStringify(currentFlow) !== customStringify(savedFlow);
|
||||
}
|
||||
|
|
@ -18,8 +18,12 @@ export default function FlowSettingsModal({
|
|||
flowData,
|
||||
details,
|
||||
}: FlowSettingsPropsType): JSX.Element {
|
||||
if (!open) return <></>;
|
||||
|
||||
const saveFlow = useSaveFlow();
|
||||
const currentFlow = useFlowStore((state) => state.currentFlow);
|
||||
const currentFlow = useFlowStore((state) =>
|
||||
flowData ? undefined : state.currentFlow,
|
||||
);
|
||||
const setCurrentFlow = useFlowStore((state) => state.setCurrentFlow);
|
||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||
const flows = useFlowsManagerStore((state) => state.flows);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue