Modularized components page and made it similar to LangStore
This commit is contained in:
parent
d07090f27c
commit
422e4bd5a0
6 changed files with 164 additions and 154 deletions
|
|
@ -1,16 +1,13 @@
|
|||
import { useState } from "react";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import { SkeletonCardComponent } from "../skeletonCardComponent";
|
||||
|
||||
export default function CardsWrapComponent({
|
||||
onFileDrop,
|
||||
children,
|
||||
isLoading,
|
||||
dragMessage,
|
||||
}: {
|
||||
onFileDrop?: (e: any) => void;
|
||||
children: JSX.Element | JSX.Element[];
|
||||
isLoading: boolean;
|
||||
dragMessage?: string;
|
||||
}) {
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
|
@ -59,17 +56,7 @@ export default function CardsWrapComponent({
|
|||
{dragMessage ? dragMessage : "Drop your file here"}
|
||||
</>
|
||||
) : (
|
||||
<div className="main-page-flows-display">
|
||||
{isLoading ? (
|
||||
<>
|
||||
<SkeletonCardComponent />
|
||||
<SkeletonCardComponent />
|
||||
<SkeletonCardComponent />
|
||||
</>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</div>
|
||||
children
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export default function PageLayout({
|
|||
<div className="flex h-screen w-full flex-col">
|
||||
<Header />
|
||||
<div className="flex h-full w-full flex-col justify-between overflow-auto bg-background px-16">
|
||||
<div className="flex w-full items-center justify-between space-y-0.5 py-8 pb-2">
|
||||
<div className="flex w-full items-center justify-between gap-4 space-y-0.5 py-8 pb-2">
|
||||
<div className="flex w-full flex-col">
|
||||
<h2 className="text-2xl font-bold tracking-tight">{title}</h2>
|
||||
<p className="text-muted-foreground">{description}</p>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,43 @@
|
|||
import { useContext } from "react";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import PaginatorComponent from "../../../../components/PaginatorComponent";
|
||||
import CollectionCardComponent from "../../../../components/cardComponent";
|
||||
import CardsWrapComponent from "../../../../components/cardsWrapComponent";
|
||||
import IconComponent from "../../../../components/genericIconComponent";
|
||||
import { SkeletonCardComponent } from "../../../../components/skeletonCardComponent";
|
||||
import { Button } from "../../../../components/ui/button";
|
||||
import { alertContext } from "../../../../contexts/alertContext";
|
||||
import { FlowsContext } from "../../../../contexts/flowsContext";
|
||||
import { FlowType } from "../../../../types/flow";
|
||||
|
||||
export default function ComponentsComponent() {
|
||||
export default function ComponentsComponent({
|
||||
is_component = true,
|
||||
}: {
|
||||
is_component?: boolean;
|
||||
}) {
|
||||
const { flows, removeFlow, uploadFlow, isLoading } = useContext(FlowsContext);
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
const [pageIndex, setPageIndex] = useState(1);
|
||||
const [allData, setAllData] = useState(
|
||||
flows.filter((f) => f.is_component === is_component)
|
||||
);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
setAllData(flows.filter((f) => f.is_component === is_component));
|
||||
}, [flows]);
|
||||
|
||||
useEffect(() => {
|
||||
const start = (pageIndex - 1) * pageSize;
|
||||
const end = start + pageSize;
|
||||
setData(allData.slice(start, end));
|
||||
}, [pageIndex, pageSize, allData]);
|
||||
|
||||
const [data, setData] = useState<FlowType[]>([]);
|
||||
|
||||
const name = is_component ? "Component" : "Flow";
|
||||
|
||||
const onFileDrop = (e) => {
|
||||
e.preventDefault();
|
||||
|
|
@ -25,20 +56,74 @@ export default function ComponentsComponent() {
|
|||
return (
|
||||
<CardsWrapComponent
|
||||
onFileDrop={onFileDrop}
|
||||
isLoading={isLoading && flows.length == 0}
|
||||
dragMessage={"Drop your component here"}
|
||||
dragMessage={`Drag your ${name} here`}
|
||||
>
|
||||
{flows
|
||||
.filter((flow) => flow.is_component)
|
||||
.map((flow, idx) => (
|
||||
<CollectionCardComponent
|
||||
key={idx}
|
||||
data={flow}
|
||||
onDelete={() => {
|
||||
removeFlow(flow.id);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<div className="flex h-full w-full flex-col justify-between">
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<div className="grid w-full gap-4 md:grid-cols-2 lg:grid-cols-2">
|
||||
{!isLoading || data?.length > 0 ? (
|
||||
data
|
||||
?.sort(
|
||||
(a, b) =>
|
||||
new Date(b?.date_created!).getTime() -
|
||||
new Date(a?.date_created!).getTime()
|
||||
)
|
||||
.map((item, idx) => (
|
||||
<CollectionCardComponent
|
||||
onDelete={() => {
|
||||
removeFlow(item.id);
|
||||
}}
|
||||
key={idx}
|
||||
data={item}
|
||||
disabled={isLoading}
|
||||
button={
|
||||
!is_component ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="whitespace-nowrap "
|
||||
onClick={() => {
|
||||
navigate("/flow/" + item.id);
|
||||
}}
|
||||
>
|
||||
<IconComponent
|
||||
name="ExternalLink"
|
||||
className="main-page-nav-button"
|
||||
/>
|
||||
Edit Flow
|
||||
</Button>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
/>
|
||||
))
|
||||
) : !isLoading && data?.length === 0 ? (
|
||||
<>You haven't created {name}s yet.</>
|
||||
) : (
|
||||
<>
|
||||
<SkeletonCardComponent />
|
||||
<SkeletonCardComponent />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{!isLoading && allData.length > 0 && (
|
||||
<div className="relative py-6">
|
||||
<PaginatorComponent
|
||||
storeComponent={true}
|
||||
pageIndex={pageIndex}
|
||||
pageSize={pageSize}
|
||||
rowsCount={[10, 20, 50, 100]}
|
||||
totalRowsCount={allData.length}
|
||||
paginate={(pageSize, pageIndex) => {
|
||||
setPageIndex(pageIndex);
|
||||
setPageSize(pageSize);
|
||||
}}
|
||||
></PaginatorComponent>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardsWrapComponent>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
import { useContext } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import CollectionCardComponent from "../../../../components/cardComponent";
|
||||
import CardsWrapComponent from "../../../../components/cardsWrapComponent";
|
||||
import IconComponent from "../../../../components/genericIconComponent";
|
||||
import { Button } from "../../../../components/ui/button";
|
||||
import { alertContext } from "../../../../contexts/alertContext";
|
||||
import { FlowsContext } from "../../../../contexts/flowsContext";
|
||||
|
||||
export default function FlowsComponent() {
|
||||
const { uploadFlow, removeFlow, flows, isLoading } = useContext(FlowsContext);
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
|
||||
const onFileDrop = (e) => {
|
||||
e.preventDefault();
|
||||
if (e.dataTransfer.types.some((types) => types === "Files")) {
|
||||
if (e.dataTransfer.files.item(0).type === "application/json") {
|
||||
uploadFlow(true, e.dataTransfer.files.item(0)!);
|
||||
} else {
|
||||
setErrorData({
|
||||
title: "Invalid file type",
|
||||
list: ["Please upload a JSON file"],
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<CardsWrapComponent
|
||||
onFileDrop={onFileDrop}
|
||||
dragMessage={"Drag your flow here"}
|
||||
isLoading={isLoading && flows.length == 0}
|
||||
>
|
||||
{flows
|
||||
.filter((flow) => !flow.is_component)
|
||||
.reverse()
|
||||
.map((flow, idx) => (
|
||||
<CollectionCardComponent
|
||||
key={idx}
|
||||
data={flow}
|
||||
button={
|
||||
<Link to={"/flow/" + flow.id}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="whitespace-nowrap "
|
||||
>
|
||||
<IconComponent
|
||||
name="ExternalLink"
|
||||
className="main-page-nav-button"
|
||||
/>
|
||||
Edit Flow
|
||||
</Button>
|
||||
</Link>
|
||||
}
|
||||
onDelete={() => {
|
||||
removeFlow(flow.id);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</CardsWrapComponent>
|
||||
);
|
||||
}
|
||||
|
|
@ -2,10 +2,9 @@ import { useContext, useEffect } from "react";
|
|||
import { Outlet, useNavigate } from "react-router-dom";
|
||||
import DropdownButton from "../../components/DropdownButtonComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import Header from "../../components/headerComponent";
|
||||
import PageLayout from "../../components/pageLayout";
|
||||
import SidebarNav from "../../components/sidebarComponent";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { Separator } from "../../components/ui/separator";
|
||||
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { FlowsContext } from "../../contexts/flowsContext";
|
||||
|
|
@ -24,10 +23,18 @@ export default function HomePage(): JSX.Element {
|
|||
const dropdownOptions = [
|
||||
{
|
||||
name: "Import from JSON",
|
||||
onBtnClick: () =>
|
||||
uploadFlow(true).then((id) => {
|
||||
navigate("/flow/" + id);
|
||||
}),
|
||||
onBtnClick: () => {
|
||||
try {
|
||||
uploadFlow(true).then((id) => {
|
||||
navigate("/flow/" + id);
|
||||
});
|
||||
} catch (error: any) {
|
||||
setErrorData({
|
||||
title: "Invalid file type",
|
||||
list: [error],
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
const sidebarNavItems = [
|
||||
|
|
@ -49,61 +56,49 @@ export default function HomePage(): JSX.Element {
|
|||
|
||||
// Personal flows display
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<div className="main-page-panel">
|
||||
<div className="main-page-nav-arrangement">
|
||||
<span className="main-page-nav-title">
|
||||
<IconComponent name="Home" className="w-6" />
|
||||
{USER_PROJECTS_HEADER}
|
||||
</span>
|
||||
<div className="button-div-style">
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
downloadFlows();
|
||||
}}
|
||||
>
|
||||
<IconComponent name="Download" className="main-page-nav-button" />
|
||||
Download Collection
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
uploadFlows();
|
||||
}}
|
||||
>
|
||||
<IconComponent name="Upload" className="main-page-nav-button" />
|
||||
Upload Collection
|
||||
</Button>
|
||||
<DropdownButton
|
||||
firstButtonName="New Project"
|
||||
onFirstBtnClick={() => {
|
||||
addFlow(true).then((id) => {
|
||||
navigate("/flow/" + id);
|
||||
});
|
||||
}}
|
||||
options={dropdownOptions}
|
||||
/>
|
||||
</div>
|
||||
<PageLayout
|
||||
title={USER_PROJECTS_HEADER}
|
||||
description="Manage your personal projects. Download or upload your collection."
|
||||
button={
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
downloadFlows();
|
||||
}}
|
||||
>
|
||||
<IconComponent name="Download" className="main-page-nav-button" />
|
||||
Download Collection
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
uploadFlows();
|
||||
}}
|
||||
>
|
||||
<IconComponent name="Upload" className="main-page-nav-button" />
|
||||
Upload Collection
|
||||
</Button>
|
||||
<DropdownButton
|
||||
firstButtonName="New Project"
|
||||
onFirstBtnClick={() => {
|
||||
addFlow(true).then((id) => {
|
||||
navigate("/flow/" + id);
|
||||
});
|
||||
}}
|
||||
options={dropdownOptions}
|
||||
/>
|
||||
</div>
|
||||
<span className="main-page-description-text">
|
||||
Manage your personal projects. Download or upload your collection.
|
||||
</span>
|
||||
<Separator className="my-6" />
|
||||
<div className="flex flex-col space-y-8 lg:flex-row lg:space-x-8 lg:space-y-0">
|
||||
<aside className="space-y-6 lg:w-1/5">
|
||||
{/* <Input placeholder="Search" onChange={(e) => {}} /> */}
|
||||
<SidebarNav
|
||||
items={sidebarNavItems}
|
||||
secondaryItems={sidebarNavItems}
|
||||
/>
|
||||
</aside>
|
||||
<div className="w-full flex-1">
|
||||
<Outlet />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="flex h-full w-full space-y-8 lg:flex-row lg:space-x-8 lg:space-y-0">
|
||||
<aside className="flex h-full flex-col space-y-6 lg:w-1/5">
|
||||
<SidebarNav items={sidebarNavItems} />
|
||||
</aside>
|
||||
<div className="h-full w-full flex-1">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import ApiKeysPage from "./pages/ApiKeysPage";
|
|||
import FlowPage from "./pages/FlowPage";
|
||||
import HomePage from "./pages/MainPage";
|
||||
import ComponentsComponent from "./pages/MainPage/components/components";
|
||||
import FlowsComponent from "./pages/MainPage/components/flows";
|
||||
import ProfileSettingsPage from "./pages/ProfileSettingsPage";
|
||||
import StorePage from "./pages/StorePage";
|
||||
import ViewPage from "./pages/ViewPage";
|
||||
|
|
@ -37,8 +36,14 @@ const Router = () => {
|
|||
</ProtectedRoute>
|
||||
}
|
||||
>
|
||||
<Route path="flows" element={<FlowsComponent />} />
|
||||
<Route path="components" element={<ComponentsComponent />} />
|
||||
<Route
|
||||
path="flows"
|
||||
element={<ComponentsComponent key="flows" is_component={false} />}
|
||||
/>
|
||||
<Route
|
||||
path="components"
|
||||
element={<ComponentsComponent key="components" />}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
path="/store"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue