diff --git a/src/backend/langflow/api/v1/store.py b/src/backend/langflow/api/v1/store.py
index 2a2c1118f..e63b20aab 100644
--- a/src/backend/langflow/api/v1/store.py
+++ b/src/backend/langflow/api/v1/store.py
@@ -22,49 +22,53 @@ from langflow.services.store.service import StoreService
router = APIRouter(prefix="/store", tags=["Components Store"])
-def get_user_store_api_key(user: User = Depends(auth_utils.get_current_active_user)):
+def get_user_store_api_key(
+ user: User = Depends(auth_utils.get_current_active_user),
+ settings_service=Depends(get_settings_service),
+):
if not user.store_api_key:
raise HTTPException(
status_code=400, detail="You must have a store API key set."
)
- return user.store_api_key
+ decrypted = auth_utils.decrypt_api_key(user.store_api_key, settings_service)
+ return decrypted
def get_optional_user_store_api_key(
user: User = Depends(auth_utils.get_current_active_user),
+ settings_service=Depends(get_settings_service),
):
- return user.store_api_key
+ if not user.store_api_key:
+ return None
+ decrypted = auth_utils.decrypt_api_key(user.store_api_key, settings_service)
+ return decrypted
@router.post("/components/", response_model=ComponentResponse, status_code=201)
def create_component(
component: StoreComponentCreate,
store_service: StoreService = Depends(get_store_service),
- settings_service=Depends(get_settings_service),
store_api_Key: str = Depends(get_user_store_api_key),
):
try:
- decrypted = auth_utils.decrypt_api_key(store_api_Key, settings_service)
- return store_service.upload(decrypted, component)
+ return store_service.upload(store_api_Key, component)
except Exception as exc:
raise HTTPException(status_code=400, detail=str(exc))
@router.get("/components/", response_model=List[ListComponentResponse])
def list_components(
+ filter_by_user: bool = Query(False),
page: int = 1,
limit: int = 10,
store_service: StoreService = Depends(get_store_service),
store_api_Key: str = Depends(get_optional_user_store_api_key),
- settings_service=Depends(get_settings_service),
):
try:
fields = ["id", "name", "description", "user_created.name", "is_component"]
- if store_api_Key:
- decrypted = auth_utils.decrypt_api_key(store_api_Key, settings_service)
- else:
- decrypted = None
- result = store_service.list_components(decrypted, page, limit, fields=fields)
+ result = store_service.list_components(
+ store_api_Key, page, limit, fields=fields, filter_by_user=filter_by_user
+ )
return result
except Exception as exc:
raise HTTPException(status_code=400, detail=str(exc))
@@ -73,16 +77,13 @@ def list_components(
@router.get("/components/{component_id}", response_model=DownloadComponentResponse)
def read_component(
component_id: UUID,
- filter_by_user: bool = Query(False),
store_service: StoreService = Depends(get_store_service),
store_api_Key: str = Depends(get_user_store_api_key),
- settings_service=Depends(get_settings_service),
):
# If the component is from the store, we need to get it from the store
try:
- decrypted = auth_utils.decrypt_api_key(store_api_Key, settings_service)
- component = store_service.download(decrypted, component_id, filter_by_user)
+ component = store_service.download(store_api_Key, component_id)
except Exception as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@@ -102,6 +103,7 @@ async def search_endpoint(
date_from: Optional[datetime] = Query(None),
date_to: Optional[datetime] = Query(None),
sort: Optional[List[str]] = Query(None),
+ filter_by_user: bool = Query(False),
fields: Optional[List[str]] = Query(None),
store_service: "StoreService" = Depends(get_store_service),
store_api_Key: str = Depends(get_optional_user_store_api_key),
@@ -118,6 +120,7 @@ async def search_endpoint(
date_to=date_to,
sort=sort,
fields=fields,
+ filter_by_user=filter_by_user,
)
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc))
diff --git a/src/backend/langflow/services/store/service.py b/src/backend/langflow/services/store/service.py
index e827ad632..39d31996e 100644
--- a/src/backend/langflow/services/store/service.py
+++ b/src/backend/langflow/services/store/service.py
@@ -72,6 +72,7 @@ class StoreService(Service):
date_to: Optional[datetime] = None,
sort: Optional[List[str]] = ["-likes"],
fields: Optional[List[str]] = None,
+ filter_by_user: bool = False,
) -> List[ComponentResponse]:
# ?sort=sort,-date_created,author.name
@@ -104,34 +105,6 @@ class StoreService(Service):
if fields:
params["fields"] = ",".join(fields)
- results = self._get(self.components_url, api_key, params)
- return [ComponentResponse(**component) for component in results]
-
- def list_components(
- self,
- api_key: str,
- page: int = 1,
- limit: int = 10,
- fields: Optional[List[str]] = None,
- ) -> List[ListComponentResponse]:
- params = {"page": page, "limit": limit}
- # ?aggregate[count]=likes
- params["fields"] = (
- ",".join(fields)
- if fields
- else ",".join(["id", "name", "description", "count(likes)", "is_component"])
- )
-
- results = self._get(self.components_url, api_key, params)
- return [ListComponentResponse(**component) for component in results]
-
- def download(
- self, api_key: str, component_id: str, filter_by_user: bool
- ) -> DownloadComponentResponse:
- url = f"{self.components_url}/{component_id}"
- params = {
- "fields": ",".join(["id", "name", "description", "data", "is_component"])
- }
if filter_by_user:
params["deep"] = json.dumps(
{
@@ -140,6 +113,52 @@ class StoreService(Service):
}
}
)
+ else:
+ params["filter"] = json.dumps({"status": {"_eq": "public"}})
+
+ results = self._get(self.components_url, api_key, params)
+ return [ComponentResponse(**component) for component in results]
+
+ def list_components(
+ self,
+ api_key: str,
+ page: int = 1,
+ limit: int = 15,
+ fields: Optional[List[str]] = None,
+ filter_by_user: bool = False,
+ ) -> List[ListComponentResponse]:
+ params = {"page": page, "limit": limit}
+ # ?aggregate[count]=likes
+ params["fields"] = (
+ ",".join(fields)
+ if fields
+ else ",".join(["id", "name", "description", "count(likes)", "is_component"])
+ )
+ # Only public components or the ones created by the user
+ # check for "public" or "Public"
+
+ if filter_by_user:
+ params["deep"] = json.dumps(
+ {
+ "components": {
+ "_filter": {"user_created": {"token": {"_eq": api_key}}}
+ }
+ }
+ )
+ else:
+ params["filter"] = params["filter"] = json.dumps(
+ {"status": {"_in": ["public", "Public"]}}
+ )
+
+ results = self._get(self.components_url, api_key, params)
+ return [ListComponentResponse(**component) for component in results]
+
+ def download(self, api_key: str, component_id: str) -> DownloadComponentResponse:
+ url = f"{self.components_url}/{component_id}"
+ params = {
+ "fields": ",".join(["id", "name", "description", "data", "is_component"])
+ }
+
component = self._get(url, api_key, params)
self.call_webhook(api_key, self.webhook_url, component_id)
diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json
index 496d6c4f3..0bf66bdca 100644
--- a/src/frontend/package-lock.json
+++ b/src/frontend/package-lock.json
@@ -3796,9 +3796,9 @@
"integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g=="
},
"node_modules/@types/react": {
- "version": "18.2.31",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.31.tgz",
- "integrity": "sha512-c2UnPv548q+5DFh03y8lEDeMfDwBn9G3dRwfkrxQMo/dOtRHUUO57k6pHvBIfH/VF4Nh+98mZ5aaSe+2echD5g==",
+ "version": "18.2.32",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.32.tgz",
+ "integrity": "sha512-F0FVIZQ1x5Gxy/VYJb7XcWvCcHR28Sjwt1dXLspdIatfPq1MVACfnBDwKe6ANLxQ64riIJooXClpUR6oxTiepg==",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -4517,9 +4517,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001553",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz",
- "integrity": "sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A==",
+ "version": "1.0.30001554",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001554.tgz",
+ "integrity": "sha512-A2E3U//MBwbJVzebddm1YfNp7Nud5Ip+IPn4BozBmn4KqVX7AvluoIDFWjsv5OkGnKUXQVmMSoMKLa3ScCblcQ==",
"funding": [
{
"type": "opencollective",
@@ -10220,9 +10220,9 @@
}
},
"node_modules/tailwindcss": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.4.tgz",
- "integrity": "sha512-JXZNOkggUAc9T5E7nCrimoXHcSf9h3NWFe5sh36CGD/3M5TRLuQeFnQoDsit2uVTqgoOZHLx5rTykLUu16vsMQ==",
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
+ "integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
@@ -13755,9 +13755,9 @@
"integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g=="
},
"@types/react": {
- "version": "18.2.31",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.31.tgz",
- "integrity": "sha512-c2UnPv548q+5DFh03y8lEDeMfDwBn9G3dRwfkrxQMo/dOtRHUUO57k6pHvBIfH/VF4Nh+98mZ5aaSe+2echD5g==",
+ "version": "18.2.32",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.32.tgz",
+ "integrity": "sha512-F0FVIZQ1x5Gxy/VYJb7XcWvCcHR28Sjwt1dXLspdIatfPq1MVACfnBDwKe6ANLxQ64riIJooXClpUR6oxTiepg==",
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -14248,9 +14248,9 @@
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
},
"caniuse-lite": {
- "version": "1.0.30001553",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz",
- "integrity": "sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A=="
+ "version": "1.0.30001554",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001554.tgz",
+ "integrity": "sha512-A2E3U//MBwbJVzebddm1YfNp7Nud5Ip+IPn4BozBmn4KqVX7AvluoIDFWjsv5OkGnKUXQVmMSoMKLa3ScCblcQ=="
},
"ccount": {
"version": "2.0.1",
@@ -18070,9 +18070,9 @@
"integrity": "sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ=="
},
"tailwindcss": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.4.tgz",
- "integrity": "sha512-JXZNOkggUAc9T5E7nCrimoXHcSf9h3NWFe5sh36CGD/3M5TRLuQeFnQoDsit2uVTqgoOZHLx5rTykLUu16vsMQ==",
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
+ "integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==",
"requires": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
diff --git a/src/frontend/src/components/PaginatorComponent/index.tsx b/src/frontend/src/components/PaginatorComponent/index.tsx
index fa759a8bb..1840c4d0e 100644
--- a/src/frontend/src/components/PaginatorComponent/index.tsx
+++ b/src/frontend/src/components/PaginatorComponent/index.tsx
@@ -16,6 +16,7 @@ export default function PaginatorComponent({
rowsCount = [10, 20, 50, 100],
totalRowsCount = 0,
paginate,
+ storeComponent = false,
}: PaginatorComponentType) {
const [size, setPageSize] = useState(pageSize);
const [maxIndex, setMaxPageIndex] = useState(
@@ -30,7 +31,13 @@ export default function PaginatorComponent({
<>
-
+
- Page {pageIndex} of {maxIndex}
+ Page {pageIndex}
+ {!storeComponent && <> of {maxIndex}>}