Skip to content

Commit 96cbee6

Browse files
added feature to export public app
1 parent af394ac commit 96cbee6

File tree

3 files changed

+52
-3
lines changed

3 files changed

+52
-3
lines changed

client/packages/lowcoder/src/pages/common/headerStartDropdown.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { trans, transToNode } from "i18n";
1313
import { exportApplicationAsJSONFile } from "pages/ApplicationV2/components/AppImport";
1414
import { useContext, useMemo, useState } from "react";
1515
import { useDispatch, useSelector } from "react-redux";
16-
import { currentApplication } from "redux/selectors/applicationSelector";
16+
import { currentApplication, isPublicApplication } from "redux/selectors/applicationSelector";
1717
import { showAppSnapshotSelector } from "redux/selectors/appSnapshotSelector";
1818
import styled from "styled-components";
1919
import history from "util/history";
@@ -74,9 +74,10 @@ export function HeaderStartDropdown(props: { setEdit: () => void, isViewMarketpl
7474
const showAppSnapshot = useSelector(showAppSnapshotSelector);
7575
const applicationId = useApplicationId();
7676
const application = useSelector(currentApplication);
77+
const isPublicApp = useSelector(isPublicApplication);
7778
const [showCopyModal, setShowCopyModal] = useState(false);
7879
const dispatch = useDispatch();
79-
const { appType } = useContext(ExternalEditorContext);
80+
const { appType, exportPublicAppToJson } = useContext(ExternalEditorContext);
8081
const isModule = appType === AppTypeEnum.Module;
8182

8283
const isEditable = canEditApp(user, application);
@@ -137,6 +138,9 @@ export function HeaderStartDropdown(props: { setEdit: () => void, isViewMarketpl
137138
if (e.key === "edit") {
138139
props.setEdit();
139140
} else if (e.key === "export") {
141+
if (isPublicApp && exportPublicAppToJson) {
142+
return exportPublicAppToJson?.();
143+
}
140144
exportApplicationAsJSONFile(applicationId);
141145
} else if (e.key === "duplicate") {
142146
setShowCopyModal(true);

client/packages/lowcoder/src/pages/editor/appEditorInternal.tsx

+44-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AppSummaryInfo, updateApplication } from "redux/reduxActions/applicationActions";
22
import { useDispatch, useSelector } from "react-redux";
33
import { getExternalEditorState } from "redux/selectors/configSelectors";
4-
import { useEffect, useMemo, useState } from "react";
4+
import { useCallback, useEffect, useMemo, useState } from "react";
55
import {
66
ExternalEditorContext,
77
ExternalEditorContextState,
@@ -26,6 +26,7 @@ import { RootCompInstanceType } from "./useRootCompInstance";
2626
import { getCurrentUser } from "redux/selectors/usersSelectors";
2727
import React from "react";
2828
import { isEqual } from "lodash";
29+
import { isPublicApplication } from "@lowcoder-ee/redux/selectors/applicationSelector";
2930

3031
/**
3132
* FIXME: optimize the logic of saving comps
@@ -88,6 +89,40 @@ function useSaveComp(
8889
}, [comp, applicationId, readOnly, dispatch]);
8990
}
9091

92+
const exportAppToJson = (appDSL?: any) => {
93+
if (!appDSL) return;
94+
95+
const id = `t--export-app-link`;
96+
const existingLink = document.getElementById(id);
97+
existingLink && existingLink.remove();
98+
const link = document.createElement("a");
99+
const time = new Date().getTime();
100+
101+
const applicationName = `test_app_${time}`;
102+
const exportObj = {
103+
applicationInfo: {
104+
name: 'Test App',
105+
createAt: time,
106+
createBy: '',
107+
applicationId: '',
108+
applicationType: AppTypeEnum.Application,
109+
},
110+
applicationDSL: appDSL,
111+
};
112+
const blob = new Blob([JSON.stringify(exportObj)], {
113+
type: "application/json",
114+
});
115+
const url = URL.createObjectURL(blob);
116+
link.href = url;
117+
link.download = applicationName + ".json";
118+
link.id = id;
119+
document.body.appendChild(link);
120+
link.click();
121+
link.remove();
122+
URL.revokeObjectURL(url);
123+
return;
124+
}
125+
91126
interface AppEditorInternalViewProps {
92127
readOnly: boolean;
93128
blockEditing?: boolean;
@@ -100,6 +135,7 @@ interface AppEditorInternalViewProps {
100135
export const AppEditorInternalView = React.memo((props: AppEditorInternalViewProps) => {
101136
const isUserViewMode = useUserViewMode();
102137
const extraExternalEditorState = useSelector(getExternalEditorState);
138+
const isPublicApp = useSelector(isPublicApplication);
103139
const dispatch = useDispatch();
104140
const { readOnly, blockEditing, appInfo, compInstance, fetchApplication } = props;
105141

@@ -111,6 +147,11 @@ export const AppEditorInternalView = React.memo((props: AppEditorInternalViewPro
111147
appType: AppTypeEnum.Application,
112148
});
113149

150+
const exportPublicAppToJson = useCallback(() => {
151+
const appDsl = compInstance.comp?.toJsonValue();
152+
exportAppToJson(appDsl);
153+
}, [compInstance.comp])
154+
114155
useEffect(() => {
115156
setExternalEditorState((s) => ({
116157
...s,
@@ -121,9 +162,11 @@ export const AppEditorInternalView = React.memo((props: AppEditorInternalViewPro
121162
hideHeader: window.location.pathname.split("/")[3] === "admin",
122163
blockEditing,
123164
fetchApplication: fetchApplication,
165+
exportPublicAppToJson: isPublicApp ? exportPublicAppToJson : undefined,
124166
...extraExternalEditorState,
125167
}));
126168
}, [
169+
exportPublicAppToJson,
127170
compInstance?.history,
128171
extraExternalEditorState,
129172
readOnly,

client/packages/lowcoder/src/util/context/ExternalEditorContext.ts

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export interface ExternalEditorContextState {
4747
*/
4848
fetchApplication?: () => void;
4949

50+
exportPublicAppToJson?: () => void;
51+
5052
changeExternalState?: (state: Partial<ExternalEditorContextState>) => void;
5153
}
5254

0 commit comments

Comments
 (0)