feat: Add loading state and skeleton UI for FlowPage sidebar (#6738)

* feat: Add loading state and skeleton UI for FlowPage sidebar

* fix: Improve UI components with minor styling and z-index adjustments

* refactor: Simplify SkeletonGroup component and update FlowPage sidebar loading state

* refactor: Adjust SkeletonGroup rendering and FlowPage sidebar styling

* refactor: Remove z-index from PageComponent loading state

* refactor: Update FlowPage sidebar skeleton height class
This commit is contained in:
Deon Sanchez 2025-02-21 11:43:00 -07:00 committed by GitHub
commit feff8b681e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 85 additions and 34 deletions

View file

@ -0,0 +1,20 @@
import { Skeleton } from "@/components/ui/skeleton";
import { cn } from "@/utils/utils";
const SkeletonGroup = ({
count = 2,
className = "",
}: {
count?: number;
className?: string;
}) => {
return (
<>
{Array.from({ length: count }, (_, i) => (
<Skeleton key={i} className={cn("w-full", className)} />
))}
</>
);
};
export default SkeletonGroup;

View file

@ -79,7 +79,13 @@ const edgeTypes = {
default: DefaultEdge,
};
export default function Page({ view }: { view?: boolean }): JSX.Element {
export default function Page({
view,
setIsLoading,
}: {
view?: boolean;
setIsLoading: (isLoading: boolean) => void;
}): JSX.Element {
const uploadFlow = useUploadFlow();
const autoSaveFlow = useAutoSaveFlow();
const types = useTypesStore((state) => state.types);
@ -184,6 +190,10 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
Object.keys(types).length > 0 &&
!isFetching;
useEffect(() => {
setIsLoading(!showCanvas);
}, [showCanvas]);
useEffect(() => {
useFlowStore.setState({ autoSaveFlow });
}, [autoSaveFlow]);

View file

@ -7,6 +7,7 @@ const SidebarMenuButtons = ({
hasStore = false,
customComponent,
addComponent,
isLoading = false,
}) => {
return (
<>
@ -37,6 +38,7 @@ const SidebarMenuButtons = ({
<SidebarMenuButton asChild>
<Button
unstyled
disabled={isLoading}
onClick={() => {
if (customComponent) {
addComponent(customComponent, "CustomComponent");

View file

@ -4,6 +4,7 @@ import {
SidebarFooter,
useSidebar,
} from "@/components/ui/sidebar";
import SkeletonGroup from "@/components/ui/skeletonGroup";
import { useAddComponent } from "@/hooks/useAddComponent";
import { useShortcutsStore } from "@/stores/shortcuts";
import { useStoreStore } from "@/stores/storeStore";
@ -44,7 +45,7 @@ interface FlowSidebarComponentProps {
setShowLegacy: (value: boolean) => void;
}
export function FlowSidebarComponent() {
export function FlowSidebarComponent({ isLoading }: { isLoading?: boolean }) {
const { data, templates } = useTypesStore(
useCallback(
(state) => ({
@ -322,39 +323,55 @@ export function FlowSidebarComponent() {
setFilterData={setFilterData}
data={data}
/>
<SidebarContent>
{hasResults ? (
{isLoading ? (
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-1 p-3">
<SkeletonGroup count={13} className="my-0.5 h-7" />
</div>
<div className="h-8" />
<div className="flex flex-col gap-1 px-3 pt-2">
<SkeletonGroup count={21} className="my-0.5 h-7" />
</div>
</div>
) : (
<>
<CategoryGroup
dataFilter={dataFilter}
sortedCategories={sortedCategories}
CATEGORIES={CATEGORIES}
openCategories={openCategories}
setOpenCategories={setOpenCategories}
search={search}
nodeColors={nodeColors}
chatInputAdded={chatInputAdded}
onDragStart={onDragStart}
sensitiveSort={sensitiveSort}
/>
{hasBundleItems && (
<MemoizedSidebarGroup
BUNDLES={BUNDLES}
search={search}
sortedCategories={sortedCategories}
dataFilter={dataFilter}
nodeColors={nodeColors}
chatInputAdded={chatInputAdded}
onDragStart={onDragStart}
sensitiveSort={sensitiveSort}
openCategories={openCategories}
setOpenCategories={setOpenCategories}
handleKeyDownInput={handleKeyDownInput}
/>
{hasResults ? (
<>
<CategoryGroup
dataFilter={dataFilter}
sortedCategories={sortedCategories}
CATEGORIES={CATEGORIES}
openCategories={openCategories}
setOpenCategories={setOpenCategories}
search={search}
nodeColors={nodeColors}
chatInputAdded={chatInputAdded}
onDragStart={onDragStart}
sensitiveSort={sensitiveSort}
/>
{hasBundleItems && (
<MemoizedSidebarGroup
BUNDLES={BUNDLES}
search={search}
sortedCategories={sortedCategories}
dataFilter={dataFilter}
nodeColors={nodeColors}
chatInputAdded={chatInputAdded}
onDragStart={onDragStart}
sensitiveSort={sensitiveSort}
openCategories={openCategories}
setOpenCategories={setOpenCategories}
handleKeyDownInput={handleKeyDownInput}
/>
)}
</>
) : (
<NoResultsMessage onClearSearch={handleClearSearch} />
)}
</>
) : (
<NoResultsMessage onClearSearch={handleClearSearch} />
)}
</SidebarContent>
<SidebarFooter className="border-t p-4 py-3">
@ -362,6 +379,7 @@ export function FlowSidebarComponent() {
hasStore={hasStore}
customComponent={customComponent}
addComponent={addComponent}
isLoading={isLoading}
/>
</SidebarFooter>
</Sidebar>

View file

@ -6,7 +6,7 @@ import { useIsMobile } from "@/hooks/use-mobile";
import { SaveChangesModal } from "@/modals/saveChangesModal";
import useAlertStore from "@/stores/alertStore";
import { customStringify } from "@/utils/reactflowUtils";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useBlocker, useParams } from "react-router-dom";
import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
@ -18,6 +18,7 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
const currentFlow = useFlowStore((state) => state.currentFlow);
const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow);
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const [isLoading, setIsLoading] = useState(false);
const changesNotSaved =
customStringify(currentFlow) !== customStringify(currentSavedFlow) &&
@ -154,10 +155,10 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
{currentFlow && (
<div className="flex h-full overflow-hidden">
<SidebarProvider width="17.5rem" defaultOpen={!isMobile}>
{!view && <FlowSidebarComponent />}
{!view && <FlowSidebarComponent isLoading={isLoading} />}
<main className="flex w-full overflow-hidden">
<div className="h-full w-full">
<Page />
<Page setIsLoading={setIsLoading} />
</div>
</main>
</SidebarProvider>