Skip to content

Commit c2542e4

Browse files
authored
Merge pull request #699 from raheeliftikhar5/marketplace_endpoints
Apps Marketplace
2 parents 878dfaa + 61c166b commit c2542e4

35 files changed

+338
-45
lines changed
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 12 additions & 0 deletions
Loading
Lines changed: 16 additions & 0 deletions
Loading

client/packages/lowcoder-design/src/icons/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,13 @@ export { ReactComponent as HomeModuleIcon } from "./icon-application-module.svg"
176176
export { ReactComponent as HomeQueryLibraryIcon } from "./icon-application-query-library.svg";
177177
export { ReactComponent as HomeDataSourceIcon } from "./icon-application-datasource.svg";
178178
export { ReactComponent as RecyclerIcon } from "./icon-application-recycler.svg";
179+
export { ReactComponent as MarketplaceIcon } from "./icon-application-marketplace.svg";
179180
export { ReactComponent as HomeActiveIcon } from "./icon-application-home-active.svg";
180181
export { ReactComponent as HomeModuleActiveIcon } from "./icon-application-module-active.svg";
181182
export { ReactComponent as HomeQueryLibraryActiveIcon } from "./icon-application-query-library-active.svg";
182183
export { ReactComponent as HomeDataSourceActiveIcon } from "./icon-application-datasource-active.svg";
183184
export { ReactComponent as RecyclerActiveIcon } from "./icon-application-recycler-active.svg";
185+
export { ReactComponent as MarketplaceActiveIcon } from "./icon-application-marketplace-active.svg";
184186
export { ReactComponent as FavoritesIcon } from "./icon-application-favorites.svg";
185187
export { ReactComponent as HomeSettingIcon } from "./icon-application-setting.svg";
186188
export { ReactComponent as FolderIcon } from "./icon-application-folder.svg";

client/packages/lowcoder/src/api/applicationApi.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class ApplicationApi extends Api {
7878
static newURLPrefix = "/applications";
7979
static fetchHomeDataURL = "/v1/applications/home";
8080
static createApplicationURL = "/v1/applications";
81+
static fetchAllMarketplaceAppsURL = "/v1/applications/marketplace-apps";
8182
static deleteApplicationURL = (applicationId: string) => `/v1/applications/${applicationId}`;
8283
static getAppPublishInfoURL = (applicationId: string) => `/v1/applications/${applicationId}/view`;
8384
static getAppEditingInfoURL = (applicationId: string) => `/v1/applications/${applicationId}`;
@@ -92,6 +93,9 @@ class ApplicationApi extends Api {
9293
`/v1/applications/${applicationId}/permissions/${permissionId}`;
9394
static createFromTemplateURL = `/v1/applications/createFromTemplate`;
9495
static publicToAllURL = (applicationId: string) => `/applications/${applicationId}/public-to-all`;
96+
static publicToMarketplaceURL = (applicationId: string) => `/v1/applications/${applicationId}/public-to-marketplace`;
97+
static getMarketplaceAppURL = (applicationId: string) => `/v1/applications/${applicationId}/view_marketplace`;
98+
9599

96100
static fetchHomeData(request: HomeDataPayload): AxiosPromise<HomeDataResponse> {
97101
return Api.get(ApplicationApi.fetchHomeDataURL, request);
@@ -167,7 +171,9 @@ class ApplicationApi extends Api {
167171
const url =
168172
type === "published"
169173
? ApplicationApi.getAppPublishInfoURL(applicationId)
170-
: ApplicationApi.getAppEditingInfoURL(applicationId);
174+
: type === "view_marketplace"
175+
? ApplicationApi.getMarketplaceAppURL(applicationId)
176+
: ApplicationApi.getAppEditingInfoURL(applicationId);
171177
return Api.get(url);
172178
}
173179

@@ -211,6 +217,20 @@ class ApplicationApi extends Api {
211217
publicToAll: publicToAll,
212218
});
213219
}
220+
221+
static publicToMarketplace(appId: string, publicToMarketplace: boolean) {
222+
return Api.put(ApplicationApi.publicToMarketplaceURL(appId), {
223+
publicToMarketplace,
224+
});
225+
}
226+
227+
static fetchAllMarketplaceApps() {
228+
return Api.get(ApplicationApi.fetchAllMarketplaceAppsURL);
229+
}
230+
231+
static getMarketplaceApp(appId: string) {
232+
return Api.get(ApplicationApi.getMarketplaceAppURL(appId));
233+
}
214234
}
215235

216236
export default ApplicationApi;

client/packages/lowcoder/src/api/orgApi.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ export interface CreateOrgResponse extends ApiResponse {
2929
data: { orgId: string };
3030
}
3131

32+
export interface OrgAPIUsageResponse extends ApiResponse {
33+
data: number;
34+
}
35+
3236
export class OrgApi extends Api {
3337
static createGroupURL = "/v1/groups";
3438
static updateGroupURL = (groupId: string) => `/v1/groups/${groupId}/update`;
@@ -47,6 +51,7 @@ export class OrgApi extends Api {
4751
static createOrgURL = "/v1/organizations";
4852
static deleteOrgURL = (orgId: string) => `/v1/organizations/${orgId}`;
4953
static updateOrgURL = (orgId: string) => `/v1/organizations/${orgId}/update`;
54+
static fetchUsage = (orgId: string) => `/v1/organizations/${orgId}/api-usage`;
5055

5156
static createGroup(request: { name: string }): AxiosPromise<GenericApiResponse<OrgGroup>> {
5257
return Api.post(OrgApi.createGroupURL, request);
@@ -127,6 +132,10 @@ export class OrgApi extends Api {
127132
static updateOrg(request: UpdateOrgPayload): AxiosPromise<ApiResponse> {
128133
return Api.put(OrgApi.updateOrgURL(request.id), request);
129134
}
135+
136+
static fetchAPIUsage(orgId: string, lastMonthOnly?: boolean): AxiosPromise<ApiResponse> {
137+
return Api.get(OrgApi.fetchUsage(orgId), lastMonthOnly);
138+
}
130139
}
131140

132141
export default OrgApi;

client/packages/lowcoder/src/app.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
IMPORT_APP_FROM_TEMPLATE_URL,
1515
INVITE_LANDING_URL,
1616
isAuthUnRequired,
17+
MARKETPLACE_URL,
1718
ORG_AUTH_LOGIN_URL,
1819
ORG_AUTH_REGISTER_URL,
1920
QUERY_LIBRARY_URL,
@@ -138,6 +139,7 @@ class AppIndex extends React.Component<AppIndexProps, any> {
138139
FOLDER_URL,
139140
TRASH_URL,
140141
SETTING,
142+
MARKETPLACE_URL,
141143
]}
142144
// component={ApplicationListPage}
143145
component={ApplicationHome}

client/packages/lowcoder/src/components/PermissionDialog/AppPermissionDialog.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,33 @@ function AppShareView(props: {
197197
}) {
198198
const { applicationId, permissionInfo, isModule } = props;
199199
const [isPublic, setPublic] = useState(permissionInfo.publicToAll);
200+
const [isPublicToMarketplace, setPublicToMarketplace] = useState(permissionInfo.publicToMarketplace);
200201
const dispatch = useDispatch();
201202
useEffect(() => {
202203
setPublic(permissionInfo.publicToAll);
203204
}, [permissionInfo.publicToAll]);
205+
useEffect(() => {
206+
setPublicToMarketplace(permissionInfo.publicToMarketplace);
207+
}, [permissionInfo.publicToMarketplace]);
204208
return (
205209
<div style={{ marginBottom: "22px" }}>
210+
<PermissionSwitchWrapper>
211+
<TacoSwitch
212+
checked={isPublicToMarketplace}
213+
onChange={(checked) => {
214+
setPublicToMarketplace(checked);
215+
ApplicationApi.publicToMarketplace(applicationId, checked)
216+
.then((resp) => {
217+
validateResponse(resp);
218+
dispatch(updateAppPermissionInfo({ publicToMarketplace: checked }));
219+
})
220+
.catch((e) => {
221+
messageInstance.error(e.message);
222+
});
223+
}}
224+
label={isModule ? 'Public module to marketplace' : 'Public app to marketplace'}
225+
/>
226+
</PermissionSwitchWrapper>
206227
<PermissionSwitchWrapper>
207228
<TacoSwitch
208229
checked={isPublic}

client/packages/lowcoder/src/comps/comps/selectInputComp/segmentedControl.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ const SegmentedControlBasicComp = (function () {
7979
return new UICompBuilder(SegmentChildrenMap, (props) => {
8080
const [
8181
validateState,
82-
handleValidate,
8382
handleChange,
8483
] = useSelectInputValidate(props);
8584
return props.label({

client/packages/lowcoder/src/comps/comps/selectInputComp/selectInputConstants.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export const useSelectInputValidate = (props: ValidationParams) => {
9191

9292
return [
9393
validateState,
94-
handleValidate,
94+
// handleValidate,
9595
handleChange,
9696
] as const;
9797
};

client/packages/lowcoder/src/constants/applicationConstants.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const AppUILayoutType: Record<AppTypeEnum, UiLayoutType> = {
2020
[AppTypeEnum.MobileTabLayout]: "mobileTabLayout",
2121
};
2222

23-
export type ApplicationDSLType = "editing" | "published";
23+
export type ApplicationDSLType = "editing" | "published" | "view_marketplace";
2424
export type ApplicationRoleType = "viewer" | "editor" | "owner";
2525
export type ApplicationPermissionType = "USER" | "GROUP" | "ORG_ADMIN";
2626

@@ -36,6 +36,7 @@ export interface ApplicationMeta {
3636
containerSize?: { height: number; width: number };
3737
createBy: string;
3838
createAt: number;
39+
creatorEmail?: string;
3940
orgId: string;
4041
role: ApplicationRoleType;
4142
extra: ApplicationExtra;
@@ -80,9 +81,10 @@ export interface AppPermissionInfo {
8081
permissions: PermissionItem[];
8182
invitationCodes: AppInviteInfo[];
8283
publicToAll: boolean;
84+
publicToMarketplace: boolean;
8385
}
8486

85-
export type AppViewMode = "edit" | "preview" | "view";
87+
export type AppViewMode = "edit" | "preview" | "view" | "view_marketplace";
8688

8789
export type AppPathParams = {
8890
viewMode: AppViewMode;

client/packages/lowcoder/src/constants/reduxActionConstants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ export const ReduxActionTypes = {
100100
UPDATE_USER_PROFILE_SUCCESS: "UPDATE_USER_PROFILE_SUCCESS",
101101
UPLOAD_USER_HEAD_SUCCESS: "UPLOAD_USER_HEAD_SUCCESS", // update avatar
102102
MARK_USER_STATUS: "MARK_USER_STATUS",
103+
FETCH_ORG_API_USAGE: "FETCH_ORG_API_USAGE",
104+
FETCH_ORG_API_USAGE_SUCCESS: "FETCH_ORG_API_USAGE_SUCCESS",
103105

104106
/* home data */
105107
FETCH_HOME_DATA: "FETCH_HOME_DATA",
@@ -135,6 +137,8 @@ export const ReduxActionTypes = {
135137
FETCH_ALL_APPLICATIONS_SUCCESS: "FETCH_ALL_APPLICATIONS_SUCCESS",
136138
FETCH_ALL_MODULES_INIT: "FETCH_ALL_MODULES_INIT",
137139
FETCH_ALL_MODULES_SUCCESS: "FETCH_ALL_MODULES_SUCCESS",
140+
FETCH_ALL_MARKETPLACE_APPS: "FETCH_ALL_MARKETPLACE_APPS",
141+
FETCH_ALL_MARKETPLACE_APPS_SUCCESS: "FETCH_ALL_MARKETPLACE_APPS_SUCCESS",
138142

139143
/* user profile */
140144
SET_USER_PROFILE_SETTING_MODAL_VISIBLE: "SET_USER_PROFILE_SETTING_MODAL_VISIBLE",

client/packages/lowcoder/src/constants/routesURL.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const ORGANIZATION_SETTING_DETAIL = `${ORGANIZATION_SETTING}/:orgId`;
2121

2222
export const ALL_APPLICATIONS_URL = "/apps";
2323
export const MODULE_APPLICATIONS_URL = "/apps/module";
24+
export const MARKETPLACE_URL = `/marketplace`;
2425
export const DATASOURCE_URL = `/datasource`;
2526
export const DATASOURCE_CREATE_URL = `${DATASOURCE_URL}/new/:datasourceType`;
2627
export const DATASOURCE_EDIT_URL = `${DATASOURCE_URL}/:datasourceId`;

client/packages/lowcoder/src/i18n/locales/de.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2053,6 +2053,7 @@ export const de = {
20532053
"modules": "Module",
20542054
"module": "Modul",
20552055
"trash": "Papierkorb",
2056+
"marketplace": "Marktplatz",
20562057
"queryLibrary": "Abfragebibliothek",
20572058
"datasource": "Datenquellen",
20582059
"selectDatasourceType": "Datenquellentyp auswählen",

client/packages/lowcoder/src/i18n/locales/en.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2244,6 +2244,7 @@ export const en = {
22442244
"modules": "Modules",
22452245
"module": "Module",
22462246
"trash": "Trash",
2247+
"marketplace": "Marketplace",
22472248
"queryLibrary": "Query Library",
22482249
"datasource": "Data Sources",
22492250
"selectDatasourceType": "Select Data Source Type",

client/packages/lowcoder/src/i18n/locales/zh.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2123,6 +2123,7 @@ home: {
21232123
modules: "模块",
21242124
module: "模块",
21252125
trash: "回收站",
2126+
marketplace: "市场",
21262127
queryLibrary: "查询管理",
21272128
datasource: "数据源",
21282129
selectDatasourceType: "选择数据源类型",

client/packages/lowcoder/src/pages/ApplicationV2/HomeLayout.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,12 @@ export interface HomeRes {
238238
isEditable?: boolean;
239239
isManageable: boolean;
240240
isDeletable: boolean;
241+
isMarketplace?: boolean;
241242
}
242243

243244
export type HomeBreadcrumbType = { text: string; path: string };
244245

245-
export type HomeLayoutMode = "view" | "trash" | "module" | "folder" | "folders";
246+
export type HomeLayoutMode = "view" | "trash" | "module" | "folder" | "folders" | "marketplace";
246247

247248
export interface HomeLayoutProps {
248249
breadcrumb?: HomeBreadcrumbType[];
@@ -306,11 +307,12 @@ export function HomeLayout(props: HomeLayoutProps) {
306307
id: e.applicationId,
307308
name: e.name,
308309
type: HomeResTypeEnum[HomeResTypeEnum[e.applicationType] as HomeResKey],
309-
creator: e.createBy,
310+
creator: e?.creatorEmail ?? e.createBy,
310311
lastModifyTime: e.lastModifyTime,
311-
isEditable: canEditApp(user, e),
312-
isManageable: canManageApp(user, e),
313-
isDeletable: canEditApp(user, e),
312+
isEditable: mode !== 'marketplace' && canEditApp(user, e),
313+
isManageable: mode !== 'marketplace' && canManageApp(user, e),
314+
isDeletable: mode !== 'marketplace' && canEditApp(user, e),
315+
isMarketplace: mode === 'marketplace',
314316
}
315317
);
316318

@@ -387,7 +389,7 @@ export function HomeLayout(props: HomeLayoutProps) {
387389
onChange={(e) => setSearchValue(e.target.value)}
388390
style={{ width: "192px", height: "32px", margin: "0" }}
389391
/>
390-
{mode !== "trash" && user.orgDev && (
392+
{mode !== "trash" && mode !== "marketplace" && user.orgDev && (
391393
<CreateDropdown defaultVisible={showNewUserGuide(user)} mode={mode} />
392394
)}
393395
</OperationRightWrapper>
@@ -421,11 +423,13 @@ export function HomeLayout(props: HomeLayoutProps) {
421423
<div style={{ marginBottom: "16px" }}>
422424
{mode === "trash"
423425
? trans("home.trashEmpty")
426+
: mode === "marketplace"
427+
? "No apps in marketplace yet"
424428
: user.orgDev
425429
? trans("home.projectEmptyCanAdd")
426430
: trans("home.projectEmpty")}
427431
</div>
428-
{mode !== "trash" && user.orgDev && <CreateDropdown mode={mode} />}
432+
{mode !== "trash" && mode !== "marketplace" && user.orgDev && <CreateDropdown mode={mode} />}
429433
</EmptyView>
430434
)}
431435
</>

client/packages/lowcoder/src/pages/ApplicationV2/HomeResCard.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
handleAppEditClick,
1212
handleAppViewClick,
1313
handleFolderViewClick,
14+
handleMarketplaceAppViewClick,
1415
HomeResInfo,
1516
} from "../../util/homeResUtils";
1617
import { HomeResOptions } from "./HomeResOptions";
@@ -167,6 +168,7 @@ export function HomeResCard(props: { res: HomeRes; onMove: (res: HomeRes) => voi
167168
)}
168169
<CardInfo
169170
onClick={(e) => {
171+
console.log(res.isMarketplace);
170172
if (appNameEditing) {
171173
return;
172174
}
@@ -177,6 +179,10 @@ export function HomeResCard(props: { res: HomeRes; onMove: (res: HomeRes) => voi
177179
history.push(APPLICATION_VIEW_URL(res.id, "view"));
178180
return;
179181
}
182+
if(res.isMarketplace) {
183+
handleMarketplaceAppViewClick(res.id);
184+
return;
185+
}
180186
res.isEditable ? handleAppEditClick(e, res.id) : handleAppViewClick(res.id);
181187
}
182188
}}
@@ -211,6 +217,8 @@ export function HomeResCard(props: { res: HomeRes; onMove: (res: HomeRes) => voi
211217
onClick={() =>
212218
res.type === HomeResTypeEnum.Folder
213219
? handleFolderViewClick(res.id)
220+
: res.isMarketplace
221+
? handleMarketplaceAppViewClick(res.id)
214222
: handleAppViewClick(res.id)
215223
}
216224
>

0 commit comments

Comments
 (0)