fix(store.py): flatten the "tags" field in the list_components response to improve data structure and readability
feat(store.py): add new endpoint to get list of components liked by a user fix(store.py): add "downloads_count" field to the list_components response to display the number of downloads for each component fix(store.py): add "metadata" field to the list_components response to include additional metadata for each component fix(store.py): change the "user_created.name" field to "user_created.first_name" in the list_components response to display the first name of the user who created the component fix(store.py): change the "liked_by_count" field in the component response to be an integer instead of a list of UUIDs fix(store.py): change the "downloads_count" field in the component response to be an integer instead of a list of UUIDs fix(store.py): add "metadata" field to the component response to include additional metadata for each component fix(store.py): add "metadata" field to the store_component_create request schema to allow passing additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component fix(store.py): add "metadata" field to the download_component response schema to include additional metadata for a component
This commit is contained in:
commit
665dae87e5
9 changed files with 141 additions and 67 deletions
|
|
@ -12,6 +12,7 @@ from langflow.services.store.schema import (
|
||||||
ListComponentResponse,
|
ListComponentResponse,
|
||||||
StoreComponentCreate,
|
StoreComponentCreate,
|
||||||
TagResponse,
|
TagResponse,
|
||||||
|
UsersLikesResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||||
|
|
@ -77,11 +78,14 @@ def list_components(
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"user_created.name",
|
"user_created.first_name",
|
||||||
|
"user_created.id",
|
||||||
"is_component",
|
"is_component",
|
||||||
"tags.tags_id.name",
|
"tags.tags_id.name",
|
||||||
"tags.tags_id.id",
|
"tags.tags_id.id",
|
||||||
"count(liked_by)",
|
"count(liked_by)",
|
||||||
|
"count(downloads)",
|
||||||
|
"metadata",
|
||||||
]
|
]
|
||||||
result = store_service.query_components(
|
result = store_service.query_components(
|
||||||
store_api_Key,
|
store_api_Key,
|
||||||
|
|
@ -90,6 +94,9 @@ def list_components(
|
||||||
fields=fields,
|
fields=fields,
|
||||||
filter_by_user=filter_by_user,
|
filter_by_user=filter_by_user,
|
||||||
)
|
)
|
||||||
|
# tags comes as "tags" : [{"tags_id": {"name": "tag1", "id": 1}}]
|
||||||
|
# so we need to flatten it
|
||||||
|
|
||||||
return result
|
return result
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise HTTPException(status_code=400, detail=str(exc))
|
raise HTTPException(status_code=400, detail=str(exc))
|
||||||
|
|
@ -171,3 +178,14 @@ def get_tags(
|
||||||
return store_service.get_tags(store_api_Key)
|
return store_service.get_tags(store_api_Key)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise HTTPException(status_code=500, detail=str(exc))
|
raise HTTPException(status_code=500, detail=str(exc))
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/users/likes", response_model=List[UsersLikesResponse])
|
||||||
|
def get_list_of_components_liked_by_user(
|
||||||
|
store_service: StoreService = Depends(get_store_service),
|
||||||
|
store_api_Key: str = Depends(get_user_store_api_key),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
return store_service.get_user_likes(store_api_Key)
|
||||||
|
except Exception as exc:
|
||||||
|
raise HTTPException(status_code=500, detail=str(exc))
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,11 @@ class TagResponse(BaseModel):
|
||||||
name: Optional[str]
|
name: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
class UsersLikesResponse(BaseModel):
|
||||||
|
id: UUID
|
||||||
|
likes: Optional[List[UUID]]
|
||||||
|
|
||||||
|
|
||||||
class ComponentResponse(BaseModel):
|
class ComponentResponse(BaseModel):
|
||||||
id: UUID
|
id: UUID
|
||||||
status: Optional[str]
|
status: Optional[str]
|
||||||
|
|
@ -22,8 +27,14 @@ class ComponentResponse(BaseModel):
|
||||||
description: Optional[str]
|
description: Optional[str]
|
||||||
data: Optional[dict]
|
data: Optional[dict]
|
||||||
tags: Optional[List[int]]
|
tags: Optional[List[int]]
|
||||||
liked_by_count: Optional[List[UUID]]
|
liked_by_count: Optional[int]
|
||||||
|
downloads_count: Optional[int]
|
||||||
parent: Optional[UUID]
|
parent: Optional[UUID]
|
||||||
|
metadata: Optional[dict]
|
||||||
|
|
||||||
|
|
||||||
|
class TagsIdResponse(BaseModel):
|
||||||
|
tags_id: Optional[TagResponse]
|
||||||
|
|
||||||
|
|
||||||
class ListComponentResponse(BaseModel):
|
class ListComponentResponse(BaseModel):
|
||||||
|
|
@ -32,6 +43,10 @@ class ListComponentResponse(BaseModel):
|
||||||
description: Optional[str]
|
description: Optional[str]
|
||||||
liked_by_count: Optional[int]
|
liked_by_count: Optional[int]
|
||||||
is_component: Optional[bool]
|
is_component: Optional[bool]
|
||||||
|
metadata: Optional[dict]
|
||||||
|
user_created: Optional[dict]
|
||||||
|
tags: Optional[List[TagsIdResponse]] = None
|
||||||
|
downloads_count: Optional[int]
|
||||||
|
|
||||||
|
|
||||||
class DownloadComponentResponse(BaseModel):
|
class DownloadComponentResponse(BaseModel):
|
||||||
|
|
@ -40,6 +55,8 @@ class DownloadComponentResponse(BaseModel):
|
||||||
description: Optional[str]
|
description: Optional[str]
|
||||||
data: Optional[dict]
|
data: Optional[dict]
|
||||||
is_component: Optional[bool]
|
is_component: Optional[bool]
|
||||||
|
metadata: Optional[dict]
|
||||||
|
downloads_count: Optional[int]
|
||||||
|
|
||||||
|
|
||||||
class StoreComponentCreate(BaseModel):
|
class StoreComponentCreate(BaseModel):
|
||||||
|
|
@ -49,3 +66,4 @@ class StoreComponentCreate(BaseModel):
|
||||||
tags: Optional[List[str]]
|
tags: Optional[List[str]]
|
||||||
parent: Optional[UUID]
|
parent: Optional[UUID]
|
||||||
is_component: Optional[bool]
|
is_component: Optional[bool]
|
||||||
|
metadata: Optional[dict]
|
||||||
|
|
|
||||||
|
|
@ -152,27 +152,46 @@ class StoreService(Service):
|
||||||
",".join(fields)
|
",".join(fields)
|
||||||
if fields
|
if fields
|
||||||
else ",".join(
|
else ",".join(
|
||||||
["id", "name", "description", "count(liked_by)", "is_component"]
|
[
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"user_created.first_name",
|
||||||
|
"user_created.id",
|
||||||
|
"is_component",
|
||||||
|
"tags.tags_id.name",
|
||||||
|
"tags.tags_id.id",
|
||||||
|
"count(liked_by)",
|
||||||
|
"count(downloads)",
|
||||||
|
"metadata",
|
||||||
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# Only public components or the ones created by the user
|
# Only public components or the ones created by the user
|
||||||
# check for "public" or "Public"
|
# check for "public" or "Public"
|
||||||
|
|
||||||
if filter_by_user:
|
if filter_by_user:
|
||||||
params["deep"] = json.dumps(
|
user_data = self._get(
|
||||||
{
|
f"{self.base_url}/users/me", api_key, params={"fields": "id"}
|
||||||
"components": {
|
|
||||||
"_filter": {"user_created": {"token": {"_eq": api_key}}}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
params["filter"] = json.dumps({"user_created": {"_eq": user_data["id"]}})
|
||||||
|
# Get the
|
||||||
|
params.pop("page", None)
|
||||||
|
params.pop("limit", None)
|
||||||
|
|
||||||
|
params["fields"] = ["id"]
|
||||||
else:
|
else:
|
||||||
params["filter"] = params["filter"] = json.dumps(
|
params["filter"] = params["filter"] = json.dumps(
|
||||||
{"status": {"_in": ["public", "Public"]}}
|
{"status": {"_in": ["public", "Public"]}}
|
||||||
)
|
)
|
||||||
|
|
||||||
results = self._get(self.components_url, api_key, params)
|
results = self._get(self.components_url, api_key, params)
|
||||||
return [ListComponentResponse(**component) for component in results]
|
results_objects = [ListComponentResponse(**component) for component in results]
|
||||||
|
# Flatten the tags
|
||||||
|
for component in results_objects:
|
||||||
|
if component.tags:
|
||||||
|
component.tags = [tags_id.tags_id for tags_id in component.tags]
|
||||||
|
return results_objects
|
||||||
|
|
||||||
def download(self, api_key: str, component_id: str) -> DownloadComponentResponse:
|
def download(self, api_key: str, component_id: str) -> DownloadComponentResponse:
|
||||||
url = f"{self.components_url}/{component_id}"
|
url = f"{self.components_url}/{component_id}"
|
||||||
|
|
@ -216,3 +235,11 @@ class StoreService(Service):
|
||||||
params = {"fields": ",".join(["id", "name"])}
|
params = {"fields": ",".join(["id", "name"])}
|
||||||
tags = self._get(url, api_key, params)
|
tags = self._get(url, api_key, params)
|
||||||
return tags
|
return tags
|
||||||
|
|
||||||
|
def get_user_likes(self, api_key: str) -> List[Dict[str, Any]]:
|
||||||
|
url = f"{self.base_url}/users/me"
|
||||||
|
params = {
|
||||||
|
"fields": ",".join(["id", "likes"]),
|
||||||
|
}
|
||||||
|
likes = self._get(url, api_key, params)
|
||||||
|
return likes
|
||||||
|
|
|
||||||
24
src/frontend/package-lock.json
generated
24
src/frontend/package-lock.json
generated
|
|
@ -3796,9 +3796,9 @@
|
||||||
"integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g=="
|
"integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "18.2.32",
|
"version": "18.2.33",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.32.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.33.tgz",
|
||||||
"integrity": "sha512-F0FVIZQ1x5Gxy/VYJb7XcWvCcHR28Sjwt1dXLspdIatfPq1MVACfnBDwKe6ANLxQ64riIJooXClpUR6oxTiepg==",
|
"integrity": "sha512-v+I7S+hu3PIBoVkKGpSYYpiBT1ijqEzWpzQD62/jm4K74hPpSP7FF9BnKG6+fg2+62weJYkkBWDJlZt5JO/9hg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
"@types/scheduler": "*",
|
"@types/scheduler": "*",
|
||||||
|
|
@ -5237,9 +5237,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.566",
|
"version": "1.4.567",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.566.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.567.tgz",
|
||||||
"integrity": "sha512-mv+fAy27uOmTVlUULy15U3DVJ+jg+8iyKH1bpwboCRhtDC69GKf1PPTZvEIhCyDr81RFqfxZJYrbgp933a1vtg=="
|
"integrity": "sha512-8KR114CAYQ4/r5EIEsOmOMqQ9j0MRbJZR3aXD/KFA8RuKzyoUB4XrUCg+l8RUGqTVQgKNIgTpjaG8YHRPAbX2w=="
|
||||||
},
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
|
|
@ -13755,9 +13755,9 @@
|
||||||
"integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g=="
|
"integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g=="
|
||||||
},
|
},
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
"version": "18.2.32",
|
"version": "18.2.33",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.32.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.33.tgz",
|
||||||
"integrity": "sha512-F0FVIZQ1x5Gxy/VYJb7XcWvCcHR28Sjwt1dXLspdIatfPq1MVACfnBDwKe6ANLxQ64riIJooXClpUR6oxTiepg==",
|
"integrity": "sha512-v+I7S+hu3PIBoVkKGpSYYpiBT1ijqEzWpzQD62/jm4K74hPpSP7FF9BnKG6+fg2+62weJYkkBWDJlZt5JO/9hg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
"@types/scheduler": "*",
|
"@types/scheduler": "*",
|
||||||
|
|
@ -14768,9 +14768,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.4.566",
|
"version": "1.4.567",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.566.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.567.tgz",
|
||||||
"integrity": "sha512-mv+fAy27uOmTVlUULy15U3DVJ+jg+8iyKH1bpwboCRhtDC69GKf1PPTZvEIhCyDr81RFqfxZJYrbgp933a1vtg=="
|
"integrity": "sha512-8KR114CAYQ4/r5EIEsOmOMqQ9j0MRbJZR3aXD/KFA8RuKzyoUB4XrUCg+l8RUGqTVQgKNIgTpjaG8YHRPAbX2w=="
|
||||||
},
|
},
|
||||||
"emoji-regex": {
|
"emoji-regex": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { alertContext } from "../../../../contexts/alertContext";
|
||||||
import { AuthContext } from "../../../../contexts/authContext";
|
import { AuthContext } from "../../../../contexts/authContext";
|
||||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||||
import { getStoreComponents } from "../../../../controllers/API";
|
import { getStoreComponents } from "../../../../controllers/API";
|
||||||
import { FlowComponent } from "../../../../types/store";
|
import { storeComponent } from "../../../../types/store";
|
||||||
import { MarketCardComponent } from "../../../StorePage/components/market-card";
|
import { MarketCardComponent } from "../../../StorePage/components/market-card";
|
||||||
|
|
||||||
export default function SavedComponents(): JSX.Element {
|
export default function SavedComponents(): JSX.Element {
|
||||||
|
|
@ -18,7 +18,7 @@ export default function SavedComponents(): JSX.Element {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTabId("");
|
setTabId("");
|
||||||
}, []);
|
}, []);
|
||||||
const [data, setData] = useState<FlowComponent[]>([]);
|
const [data, setData] = useState<storeComponent[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [filteredCategories, setFilteredCategories] = useState(new Set());
|
const [filteredCategories, setFilteredCategories] = useState(new Set());
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Link, ToyBrick } from "lucide-react";
|
|
||||||
import { useContext, useEffect, useRef, useState } from "react";
|
import { useContext, useEffect, useRef, useState } from "react";
|
||||||
|
import ShadTooltip from "../../../components/ShadTooltipComponent";
|
||||||
import IconComponent from "../../../components/genericIconComponent";
|
import IconComponent from "../../../components/genericIconComponent";
|
||||||
import { Badge } from "../../../components/ui/badge";
|
import { Badge } from "../../../components/ui/badge";
|
||||||
import { Button } from "../../../components/ui/button";
|
import { Button } from "../../../components/ui/button";
|
||||||
|
|
@ -15,15 +15,15 @@ import { StoreContext } from "../../../contexts/storeContext";
|
||||||
import { TabsContext } from "../../../contexts/tabsContext";
|
import { TabsContext } from "../../../contexts/tabsContext";
|
||||||
import { getComponent, saveFlowStore } from "../../../controllers/API";
|
import { getComponent, saveFlowStore } from "../../../controllers/API";
|
||||||
import { FlowType } from "../../../types/flow";
|
import { FlowType } from "../../../types/flow";
|
||||||
import { FlowComponent } from "../../../types/store";
|
import { storeComponent } from "../../../types/store";
|
||||||
import cloneFLowWithParent from "../../../utils/storeUtils";
|
import cloneFLowWithParent from "../../../utils/storeUtils";
|
||||||
|
|
||||||
export const MarketCardComponent = ({ data }: { data: FlowComponent }) => {
|
export const MarketCardComponent = ({ data }: { data: storeComponent }) => {
|
||||||
const { savedFlows } = useContext(StoreContext);
|
const { savedFlows } = useContext(StoreContext);
|
||||||
const [added, setAdded] = useState(savedFlows.has(data.id) ? true : false);
|
const [added, setAdded] = useState(savedFlows.has(data.id) ? true : false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { addFlow } = useContext(TabsContext);
|
const { addFlow } = useContext(TabsContext);
|
||||||
const { setSuccessData } = useContext(alertContext);
|
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||||
const flowData = useRef<FlowType>();
|
const flowData = useRef<FlowType>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -42,9 +42,14 @@ export const MarketCardComponent = ({ data }: { data: FlowComponent }) => {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setAdded(true);
|
setAdded(true);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
setSuccessData({ title: "Component Added to account" });
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
setErrorData({
|
||||||
|
title: "Error on adding Component",
|
||||||
|
list: [error["response"]["data"]["detail"]],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
|
@ -69,28 +74,6 @@ export const MarketCardComponent = ({ data }: { data: FlowComponent }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFork(flowId: string, is_component: boolean) {
|
|
||||||
getComponent(flowId).then(
|
|
||||||
(res) => {
|
|
||||||
console.log(res);
|
|
||||||
const newFLow = cloneFLowWithParent(res.data, res.id, is_component);
|
|
||||||
console.log(newFLow);
|
|
||||||
saveFlowStore(newFLow).then(
|
|
||||||
(res) => {
|
|
||||||
console.log(JSON.parse(JSON.stringify(res)));
|
|
||||||
addFlow(true, newFLow);
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="group relative flex cursor-pointer flex-col justify-between overflow-hidden transition-all hover:shadow-md">
|
<Card className="group relative flex cursor-pointer flex-col justify-between overflow-hidden transition-all hover:shadow-md">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -143,12 +126,29 @@ export const MarketCardComponent = ({ data }: { data: FlowComponent }) => {
|
||||||
<div className=" flex items-center gap-3">
|
<div className=" flex items-center gap-3">
|
||||||
<Badge size="md" variant="outline">
|
<Badge size="md" variant="outline">
|
||||||
chain
|
chain
|
||||||
<Link className="ml-1.5 w-3 text-green-700" />
|
<IconComponent
|
||||||
|
name="Link"
|
||||||
|
className="ml-1.5 w-3 text-green-700"
|
||||||
|
/>
|
||||||
</Badge>
|
</Badge>
|
||||||
<span className="flex items-center gap-1.5 text-xs text-foreground">
|
<ShadTooltip content="Components">
|
||||||
<ToyBrick className="h-4 w-4" />
|
<span className="flex items-center gap-1.5 text-xs text-foreground">
|
||||||
123
|
<IconComponent name="ToyBrick" className="h-4 w-4" />
|
||||||
</span>
|
123
|
||||||
|
</span>
|
||||||
|
</ShadTooltip>
|
||||||
|
<ShadTooltip content="Favorites">
|
||||||
|
<span className="flex items-center gap-1.5 text-xs text-foreground">
|
||||||
|
<IconComponent name="Heart" className="h-4 w-4" />
|
||||||
|
{data.liked_by_count ?? 0}
|
||||||
|
</span>
|
||||||
|
</ShadTooltip>
|
||||||
|
<ShadTooltip content="Downloads">
|
||||||
|
<span className="flex items-center gap-1.5 text-xs text-foreground">
|
||||||
|
<IconComponent name="DownloadCloud" className="h-4 w-4" />
|
||||||
|
{data.downloads_count}
|
||||||
|
</span>
|
||||||
|
</ShadTooltip>
|
||||||
</div>
|
</div>
|
||||||
{/* {data.isChat ? (
|
{/* {data.isChat ? (
|
||||||
<Button size="sm" variant="outline">
|
<Button size="sm" variant="outline">
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import {
|
||||||
searchComponent,
|
searchComponent,
|
||||||
} from "../../controllers/API";
|
} from "../../controllers/API";
|
||||||
import StoreApiKeyModal from "../../modals/StoreApiKeyModal";
|
import StoreApiKeyModal from "../../modals/StoreApiKeyModal";
|
||||||
import { FlowComponent } from "../../types/store";
|
import { storeComponent } from "../../types/store";
|
||||||
import { cn } from "../../utils/utils";
|
import { cn } from "../../utils/utils";
|
||||||
import { MarketCardComponent } from "./components/market-card";
|
import { MarketCardComponent } from "./components/market-card";
|
||||||
export default function StorePage(): JSX.Element {
|
export default function StorePage(): JSX.Element {
|
||||||
|
|
@ -35,7 +35,7 @@ export default function StorePage(): JSX.Element {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTabId("");
|
setTabId("");
|
||||||
}, []);
|
}, []);
|
||||||
const [data, setData] = useState<FlowComponent[]>([]);
|
const [data, setData] = useState<storeComponent[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [search, setSearch] = useState(false);
|
const [search, setSearch] = useState(false);
|
||||||
const [filteredCategories, setFilteredCategories] = useState(new Set());
|
const [filteredCategories, setFilteredCategories] = useState(new Set());
|
||||||
|
|
@ -45,6 +45,7 @@ export default function StorePage(): JSX.Element {
|
||||||
const [totalRowsCount, setTotalRowsCount] = useState(0);
|
const [totalRowsCount, setTotalRowsCount] = useState(0);
|
||||||
const [size, setPageSize] = useState(10);
|
const [size, setPageSize] = useState(10);
|
||||||
const [index, setPageIndex] = useState(1);
|
const [index, setPageIndex] = useState(1);
|
||||||
|
const [errorApiKey, setErrorApiKey] = useState(false);
|
||||||
const { setSavedFlows } = useContext(StoreContext);
|
const { setSavedFlows } = useContext(StoreContext);
|
||||||
|
|
||||||
async function getSavedComponents() {
|
async function getSavedComponents() {
|
||||||
|
|
@ -58,10 +59,15 @@ export default function StorePage(): JSX.Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getSavedComponents().then((_) => handleGetComponents());
|
|
||||||
getNumberOfComponents().then((res) => {
|
getNumberOfComponents().then((res) => {
|
||||||
setTotalRowsCount(Number(res["count"]));
|
setTotalRowsCount(Number(res["count"]));
|
||||||
});
|
});
|
||||||
|
getSavedComponents()
|
||||||
|
.finally(() => handleGetComponents())
|
||||||
|
.catch((err) => {
|
||||||
|
setErrorApiKey(true);
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleGetComponents = () => {
|
const handleGetComponents = () => {
|
||||||
|
|
@ -138,7 +144,10 @@ export default function StorePage(): JSX.Element {
|
||||||
handleGetComponents();
|
handleGetComponents();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button variant="primary">
|
<Button
|
||||||
|
className={`${errorApiKey ? "animate-pulse border-error" : ""}`}
|
||||||
|
variant="primary"
|
||||||
|
>
|
||||||
<IconComponent name="Key" className="main-page-nav-button" />
|
<IconComponent name="Key" className="main-page-nav-button" />
|
||||||
API Key
|
API Key
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
export type FlowComponent = {
|
export type storeComponent = {
|
||||||
id: string;
|
id: string;
|
||||||
status: string;
|
|
||||||
sort: null | any;
|
|
||||||
user_created: string;
|
|
||||||
date_created: string;
|
|
||||||
user_updated: string;
|
|
||||||
date_updated: string;
|
|
||||||
is_component: boolean;
|
is_component: boolean;
|
||||||
|
tags: string[];
|
||||||
|
metadata?: {};
|
||||||
|
downloads_count: number;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
data: Object;
|
liked_by_count: number;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import {
|
||||||
GithubIcon,
|
GithubIcon,
|
||||||
Group,
|
Group,
|
||||||
Hammer,
|
Hammer,
|
||||||
|
Heart,
|
||||||
HelpCircle,
|
HelpCircle,
|
||||||
Home,
|
Home,
|
||||||
Info,
|
Info,
|
||||||
|
|
@ -75,6 +76,7 @@ import {
|
||||||
Store,
|
Store,
|
||||||
SunIcon,
|
SunIcon,
|
||||||
TerminalSquare,
|
TerminalSquare,
|
||||||
|
ToyBrick,
|
||||||
Trash2,
|
Trash2,
|
||||||
Undo,
|
Undo,
|
||||||
Ungroup,
|
Ungroup,
|
||||||
|
|
@ -334,4 +336,7 @@ export const nodeIconsLucide: iconsType = {
|
||||||
GitBranchPlus,
|
GitBranchPlus,
|
||||||
Loader2,
|
Loader2,
|
||||||
BookmarkPlus,
|
BookmarkPlus,
|
||||||
|
Heart,
|
||||||
|
Link,
|
||||||
|
ToyBrick,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue