From a087797d7037c48c31dcf4389298dfdca102be9d Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Fri, 23 Feb 2024 20:13:09 +0500 Subject: [PATCH] separate marketplace apps in self hosting env --- .../icon-lowcoder-marketplace-active.svg | 12 ++++ .../src/icons/icon-lowcoder-marketplace.svg | 16 +++++ .../lowcoder-design/src/icons/index.ts | 2 + client/packages/lowcoder/src/app.tsx | 1 + .../src/constants/applicationConstants.ts | 2 + .../lowcoder/src/constants/routesURL.ts | 6 +- .../pages/ApplicationV2/MarketplaceView.tsx | 66 ++++++++++++++----- .../src/pages/ApplicationV2/index.tsx | 29 +++++++- 8 files changed, 114 insertions(+), 20 deletions(-) create mode 100644 client/packages/lowcoder-design/src/icons/icon-lowcoder-marketplace-active.svg create mode 100644 client/packages/lowcoder-design/src/icons/icon-lowcoder-marketplace.svg diff --git a/client/packages/lowcoder-design/src/icons/icon-lowcoder-marketplace-active.svg b/client/packages/lowcoder-design/src/icons/icon-lowcoder-marketplace-active.svg new file mode 100644 index 000000000..6550e65dc --- /dev/null +++ b/client/packages/lowcoder-design/src/icons/icon-lowcoder-marketplace-active.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/client/packages/lowcoder-design/src/icons/icon-lowcoder-marketplace.svg b/client/packages/lowcoder-design/src/icons/icon-lowcoder-marketplace.svg new file mode 100644 index 000000000..903bcc0f1 --- /dev/null +++ b/client/packages/lowcoder-design/src/icons/icon-lowcoder-marketplace.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/packages/lowcoder-design/src/icons/index.ts b/client/packages/lowcoder-design/src/icons/index.ts index 1862d85ae..6fdc18332 100644 --- a/client/packages/lowcoder-design/src/icons/index.ts +++ b/client/packages/lowcoder-design/src/icons/index.ts @@ -177,12 +177,14 @@ export { ReactComponent as HomeQueryLibraryIcon } from "./icon-application-query export { ReactComponent as HomeDataSourceIcon } from "./icon-application-datasource.svg"; export { ReactComponent as RecyclerIcon } from "./icon-application-recycler.svg"; export { ReactComponent as MarketplaceIcon } from "./icon-application-marketplace.svg"; +export { ReactComponent as LowcoderMarketplaceIcon } from "./icon-lowcoder-marketplace.svg"; export { ReactComponent as HomeActiveIcon } from "./icon-application-home-active.svg"; export { ReactComponent as HomeModuleActiveIcon } from "./icon-application-module-active.svg"; export { ReactComponent as HomeQueryLibraryActiveIcon } from "./icon-application-query-library-active.svg"; export { ReactComponent as HomeDataSourceActiveIcon } from "./icon-application-datasource-active.svg"; export { ReactComponent as RecyclerActiveIcon } from "./icon-application-recycler-active.svg"; export { ReactComponent as MarketplaceActiveIcon } from "./icon-application-marketplace-active.svg"; +export { ReactComponent as LowcoderMarketplaceActiveIcon } from "./icon-lowcoder-marketplace-active.svg"; export { ReactComponent as FavoritesIcon } from "./icon-application-favorites.svg"; export { ReactComponent as HomeSettingIcon } from "./icon-application-setting.svg"; export { ReactComponent as FolderIcon } from "./icon-application-folder.svg"; diff --git a/client/packages/lowcoder/src/app.tsx b/client/packages/lowcoder/src/app.tsx index 8b3a944f7..ec2aaa008 100644 --- a/client/packages/lowcoder/src/app.tsx +++ b/client/packages/lowcoder/src/app.tsx @@ -14,6 +14,7 @@ import { IMPORT_APP_FROM_TEMPLATE_URL, INVITE_LANDING_URL, isAuthUnRequired, + MARKETPLACE_TYPE_URL, MARKETPLACE_URL, ORG_AUTH_LOGIN_URL, ORG_AUTH_REGISTER_URL, diff --git a/client/packages/lowcoder/src/constants/applicationConstants.ts b/client/packages/lowcoder/src/constants/applicationConstants.ts index 40b38ee52..90130e18b 100644 --- a/client/packages/lowcoder/src/constants/applicationConstants.ts +++ b/client/packages/lowcoder/src/constants/applicationConstants.ts @@ -115,3 +115,5 @@ export type AppSnapshotList = { count: number; // total count list: AppSnapshot[]; }; + +export type MarketplaceType = "local" | "lowcoder"; diff --git a/client/packages/lowcoder/src/constants/routesURL.ts b/client/packages/lowcoder/src/constants/routesURL.ts index 1c21036ab..f2f2e7664 100644 --- a/client/packages/lowcoder/src/constants/routesURL.ts +++ b/client/packages/lowcoder/src/constants/routesURL.ts @@ -1,4 +1,4 @@ -import { AppViewMode } from "constants/applicationConstants"; +import { AppViewMode, MarketplaceType } from "constants/applicationConstants"; import { LocationDescriptor } from "history"; import { UserGuideLocationState } from "pages/tutorials/tutorialsConstant"; import { DatasourceType } from "@lowcoder-ee/constants/queryConstants"; @@ -43,10 +43,14 @@ export const LDAP_AUTH_LOGIN_URL = `${USER_AUTH_URL}/ldap/login`; export const INVITE_LANDING_URL = "/invite/:invitationId"; export const ORG_AUTH_LOGIN_URL = `/org/:orgId/auth/login`; export const ORG_AUTH_REGISTER_URL = `/org/:orgId/auth/register`; +export const MARKETPLACE_TYPE_URL = `${MARKETPLACE_URL}/:marketplaceType`; export const APPLICATION_VIEW_URL = (appId: string, viewMode: AppViewMode) => `${ALL_APPLICATIONS_URL}/${appId}/${viewMode}`; +export const MARKETPLACE_URL_BY_TYPE = (type: MarketplaceType) => + `${MARKETPLACE_URL}/${type}`; + export const isAuthUnRequired = (pathname: string): boolean => { return ( pathname.startsWith("/invite/") || diff --git a/client/packages/lowcoder/src/pages/ApplicationV2/MarketplaceView.tsx b/client/packages/lowcoder/src/pages/ApplicationV2/MarketplaceView.tsx index d518250d1..f8091174b 100644 --- a/client/packages/lowcoder/src/pages/ApplicationV2/MarketplaceView.tsx +++ b/client/packages/lowcoder/src/pages/ApplicationV2/MarketplaceView.tsx @@ -1,34 +1,66 @@ import { useEffect, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; import { HomeLayout } from "./HomeLayout"; -import { MARKETPLACE_URL } from "constants/routesURL"; -import { marketplaceSelector } from "redux/selectors/applicationSelector"; -import { fetchAllMarketplaceApps } from "redux/reduxActions/applicationActions"; +import { MARKETPLACE_TYPE_URL, MARKETPLACE_URL } from "constants/routesURL"; import { trans } from "../../i18n"; +import axios, { AxiosResponse } from "axios"; +import ApplicationApi from "@lowcoder-ee/api/applicationApi"; +import { ApplicationMeta, MarketplaceType } from "@lowcoder-ee/constants/applicationConstants"; +import { GenericApiResponse } from "@lowcoder-ee/api/apiResponses"; +import { validateResponse } from "@lowcoder-ee/api/apiUtils"; +import { messageInstance } from "lowcoder-design"; +import { matchPath } from "react-router"; +import log from "loglevel"; export function MarketplaceView() { - const [haveFetchedApps, setHaveFetchApps] = useState(false); + const [ marketplaceApps, setMarketplaceApps ] = useState>([]); + const marketplaceType = matchPath<{marketplaceType?: MarketplaceType}>(window.location.pathname, MARKETPLACE_TYPE_URL)?.params + .marketplaceType; + const isLowcoderMarketplace = marketplaceType === 'lowcoder'; + const marketplaceBreadcrumbText = !marketplaceType?.length + ? trans("home.marketplace") + : marketplaceType === 'lowcoder' + ? `${trans("home.marketplace")} (Lowcoder)` + : `${trans("home.marketplace")} (Local)`; - const dispatch = useDispatch(); - const marketplaceApps = useSelector(marketplaceSelector); + const fetchLowcoderMarketplaceApps = () => { + const http = axios.create({ + baseURL: 'https://api-service.lowcoder.cloud', + withCredentials: false, + }); + return http.get(`/api/v1/applications/marketplace-apps`); + }; - useEffect(() => { - if (!marketplaceApps.length && !haveFetchedApps) { - dispatch(fetchAllMarketplaceApps()); - setHaveFetchApps(true); + const fetchLocalMarketplaceApps = () => { + return ApplicationApi.fetchAllMarketplaceApps() + } + + const fetchMarketplaceApps = async () => { + try { + let response: AxiosResponse>; + if(isLowcoderMarketplace) { + response = await fetchLowcoderMarketplaceApps(); + } else { + response = await fetchLocalMarketplaceApps(); + } + + const isValidResponse: boolean = validateResponse(response); + if (isValidResponse) { + setMarketplaceApps(response.data.data); + } + } catch (error: any) { + messageInstance.error(error.message); + log.debug("fetch marketplace apps error: ", error); } - }, []); + } useEffect(() => { - if (marketplaceApps.length) { - setHaveFetchApps(true); - } - }, [marketplaceApps]) + fetchMarketplaceApps(); + }, [marketplaceType]); return ( ); diff --git a/client/packages/lowcoder/src/pages/ApplicationV2/index.tsx b/client/packages/lowcoder/src/pages/ApplicationV2/index.tsx index 2baac3259..c2d3c435e 100644 --- a/client/packages/lowcoder/src/pages/ApplicationV2/index.tsx +++ b/client/packages/lowcoder/src/pages/ApplicationV2/index.tsx @@ -5,6 +5,7 @@ import { FOLDER_URL_PREFIX, FOLDERS_URL, MARKETPLACE_URL, + MARKETPLACE_URL_BY_TYPE, MODULE_APPLICATIONS_URL, QUERY_LIBRARY_URL, SETTING, @@ -33,6 +34,8 @@ import { RecyclerIcon, MarketplaceIcon, MarketplaceActiveIcon, + LowcoderMarketplaceActiveIcon, + LowcoderMarketplaceIcon, } from "lowcoder-design"; import React, { useEffect, useState } from "react"; import { fetchAllApplications, fetchHomeData } from "redux/reduxActions/applicationActions"; @@ -245,6 +248,7 @@ export default function ApplicationHome() { const allAppCount = allApplications.length; const allFoldersCount = allFolders.length; const orgHomeId = "root"; + const isSelfHost = window.location.host !== 'app.lowcoder.cloud'; const handleFolderCreate = useCreateFolder(); @@ -357,8 +361,16 @@ export default function ApplicationHome() { visible: ({ user }) => user.orgDev, }, { - text: {trans("home.marketplace")}, - routePath: MARKETPLACE_URL, + text: ( + + { + isSelfHost + ? `${trans("home.marketplace")} (Local)` + : trans("home.marketplace") + } + + ), + routePath: isSelfHost ? MARKETPLACE_URL_BY_TYPE('local') : MARKETPLACE_URL, routePathExact: false, routeComp: MarketplaceView, icon: ({ selected, ...otherProps }) => @@ -369,6 +381,19 @@ export default function ApplicationHome() { ), visible: ({ user }) => user.orgDev, }, + { + text: {`${trans("home.marketplace")} (Lowcoder)`}, + routePath: MARKETPLACE_URL_BY_TYPE('lowcoder'), + routePathExact: false, + routeComp: MarketplaceView, + icon: ({ selected, ...otherProps }) => + selected ? ( + + ) : ( + + ), + visible: ({ user }) => user.orgDev && isSelfHost, + }, { text: {trans("home.trash")}, routePath: TRASH_URL,