@blocklet/pages-kit-block-studio 0.4.66 → 0.4.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/middlewares/init-block-studio-router.js +14 -3
- package/lib/cjs/plugins/_theme.js +279 -241
- package/lib/cjs/tsconfig.tsbuildinfo +1 -1
- package/lib/cjs/utils/ts-morph-utils.js +63 -0
- package/lib/cjs/utils/zod-utils.js +0 -111
- package/lib/esm/middlewares/init-block-studio-router.js +15 -4
- package/lib/esm/plugins/_theme.js +280 -242
- package/lib/esm/tsconfig.tsbuildinfo +1 -1
- package/lib/esm/utils/ts-morph-utils.js +59 -0
- package/lib/esm/utils/zod-utils.js +0 -73
- package/lib/types/tsconfig.tsbuildinfo +1 -1
- package/lib/types/utils/ts-morph-utils.d.ts +9 -0
- package/lib/types/utils/zod-utils.d.ts +0 -16
- package/package.json +4 -4
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
// @ts-nocheck
|
|
4
|
+
// NOTICE: This file is very important, please do not change it!
|
|
5
|
+
// import BlockStudio from '@blocklet/pages-kit-block-studio/frontend';
|
|
6
|
+
// export default BlockStudio;
|
|
4
7
|
import { createAuthServiceSessionContext } from '@arcblock/did-connect/lib/Session';
|
|
5
8
|
import { LocaleProvider, useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
6
9
|
import Toast, { ToastProvider } from '@arcblock/ux/lib/Toast';
|
|
@@ -20,7 +23,7 @@ import { Alert, Box, Button, CircularProgress, Dialog, DialogContent, DialogTitl
|
|
|
20
23
|
import { useDebounceFn, useReactive } from 'ahooks';
|
|
21
24
|
import cloneDeep from 'lodash/cloneDeep';
|
|
22
25
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
23
|
-
import { Suspense, useCallback, useEffect, useMemo } from 'react';
|
|
26
|
+
import { Suspense, useCallback, useContext, useEffect, useMemo } from 'react';
|
|
24
27
|
import { DndProvider } from 'react-dnd';
|
|
25
28
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
26
29
|
import { Navigate, useLocation, useNavigate } from 'react-router-dom';
|
|
@@ -35,7 +38,11 @@ const api = createAxios({
|
|
|
35
38
|
}, {
|
|
36
39
|
componentDid: PAGES_KIT_BLOCK_STUDIO_BLOCKLET_DID,
|
|
37
40
|
});
|
|
38
|
-
const { SessionProvider, SessionContext
|
|
41
|
+
const { SessionProvider, SessionContext } = createAuthServiceSessionContext();
|
|
42
|
+
function useSessionContext() {
|
|
43
|
+
const info = useContext(SessionContext);
|
|
44
|
+
return info;
|
|
45
|
+
}
|
|
39
46
|
const LEFT_DRAWER_WIDTH = 200;
|
|
40
47
|
const RIGHT_DRAWER_WIDTH = 300;
|
|
41
48
|
const ComparisonPreviewDialog = ({ open, title, leftTitle, leftContent, rightTitle, rightContent, description = '确认后将更新配置。', loading, onConfirm, onClose, }) => {
|
|
@@ -77,7 +84,7 @@ function Layout({ loadState, loadedData }) {
|
|
|
77
84
|
updatedAt: '',
|
|
78
85
|
},
|
|
79
86
|
data: {},
|
|
80
|
-
|
|
87
|
+
allResources: {},
|
|
81
88
|
searchValue: '',
|
|
82
89
|
newBlockParams: {
|
|
83
90
|
name: '',
|
|
@@ -94,13 +101,18 @@ function Layout({ loadState, loadedData }) {
|
|
|
94
101
|
loading: false,
|
|
95
102
|
onConfirm: async () => { },
|
|
96
103
|
},
|
|
104
|
+
init: false,
|
|
105
|
+
allComponents: [],
|
|
97
106
|
});
|
|
98
107
|
const { locale } = useLocaleContext();
|
|
108
|
+
const { session } = useSessionContext();
|
|
99
109
|
const location = useLocation();
|
|
100
110
|
const navigate = useNavigate();
|
|
101
111
|
const staticData = useStaticData();
|
|
102
112
|
const { routes, firstRoute, currentPage } = useMemo(() => {
|
|
103
|
-
const routes = Object.keys(staticData)
|
|
113
|
+
const routes = Object.keys(staticData)
|
|
114
|
+
.sort((a, b) => a.localeCompare(b))
|
|
115
|
+
.filter((route) => staticData[route]?.main?.isDeleted !== true);
|
|
104
116
|
return {
|
|
105
117
|
routes,
|
|
106
118
|
firstRoute: routes.find((route) => route !== '404' && route !== '*'),
|
|
@@ -119,29 +131,14 @@ function Layout({ loadState, loadedData }) {
|
|
|
119
131
|
const response = await api.get(`/api/blocks?path=${encodeURIComponent(metadataPath)}`);
|
|
120
132
|
return response.data || {};
|
|
121
133
|
};
|
|
122
|
-
const
|
|
123
|
-
const response = await api.get('/api/blocks/
|
|
134
|
+
const getAllResources = async () => {
|
|
135
|
+
const response = await api.get('/api/blocks/resources');
|
|
136
|
+
return response.data || [];
|
|
137
|
+
};
|
|
138
|
+
const getAllComponents = async () => {
|
|
139
|
+
const response = await api.get('/api/blocks/components');
|
|
124
140
|
return response.data || [];
|
|
125
141
|
};
|
|
126
|
-
const debouncedUpdateMetadata = useDebounceFn(async (metadata) => {
|
|
127
|
-
const { metadataPath } = getStaticData() || {};
|
|
128
|
-
if (metadataPath) {
|
|
129
|
-
try {
|
|
130
|
-
const metdadataWithoutRenderer = cloneDeep(metadata);
|
|
131
|
-
delete metdadataWithoutRenderer.renderer;
|
|
132
|
-
await api.post('/api/blocks', {
|
|
133
|
-
path: metadataPath,
|
|
134
|
-
content: metdadataWithoutRenderer,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
console.error('Failed to write metadata:', error);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}, { wait: 500 });
|
|
142
|
-
useEffect(() => {
|
|
143
|
-
debouncedUpdateMetadata.run(state.metadata);
|
|
144
|
-
}, [state.metadata, debouncedUpdateMetadata]);
|
|
145
142
|
useEffect(() => {
|
|
146
143
|
if (currentPage && state.injectBlocks.length === 0) {
|
|
147
144
|
state.injectBlocks.push({
|
|
@@ -164,19 +161,46 @@ function Layout({ loadState, loadedData }) {
|
|
|
164
161
|
type: 'react-component',
|
|
165
162
|
},
|
|
166
163
|
};
|
|
164
|
+
state.init = true;
|
|
167
165
|
}
|
|
168
166
|
catch (error) {
|
|
169
167
|
console.error('Failed to fetch metadata:', error);
|
|
170
168
|
}
|
|
171
169
|
}
|
|
172
170
|
};
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
-
state.
|
|
171
|
+
const fetchAllResources = async () => {
|
|
172
|
+
const allResources = await getAllResources();
|
|
173
|
+
state.allResources = allResources;
|
|
174
|
+
};
|
|
175
|
+
const fetchAllComponents = async () => {
|
|
176
|
+
const allComponents = await getAllComponents();
|
|
177
|
+
state.allComponents = allComponents;
|
|
176
178
|
};
|
|
177
179
|
fetchMetadata();
|
|
178
|
-
|
|
180
|
+
fetchAllResources();
|
|
181
|
+
fetchAllComponents();
|
|
179
182
|
}, [location.pathname]); // 当路由变化时重新获取
|
|
183
|
+
const debouncedUpdateMetadata = useDebounceFn(async (metadata) => {
|
|
184
|
+
if (!state.init)
|
|
185
|
+
return;
|
|
186
|
+
const { metadataPath } = getStaticData() || {};
|
|
187
|
+
if (metadataPath) {
|
|
188
|
+
try {
|
|
189
|
+
const metdadataWithoutRenderer = cloneDeep(metadata);
|
|
190
|
+
delete metdadataWithoutRenderer.renderer;
|
|
191
|
+
await api.post('/api/blocks', {
|
|
192
|
+
path: metadataPath,
|
|
193
|
+
content: metdadataWithoutRenderer,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
console.error('Failed to write metadata:', error);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}, { wait: 500 });
|
|
201
|
+
useEffect(() => {
|
|
202
|
+
debouncedUpdateMetadata.run(state.metadata);
|
|
203
|
+
}, [state.metadata, debouncedUpdateMetadata]);
|
|
180
204
|
const mergedAllBlocks = useMemo(() => {
|
|
181
205
|
// Add all staticData code and importPath mappings
|
|
182
206
|
if (import.meta.env.DEV) {
|
|
@@ -194,13 +218,13 @@ function Layout({ loadState, loadedData }) {
|
|
|
194
218
|
};
|
|
195
219
|
}
|
|
196
220
|
return {
|
|
197
|
-
...state.
|
|
221
|
+
...state.allResources,
|
|
198
222
|
[state.metadata.id]: {
|
|
199
|
-
...state.
|
|
223
|
+
...state.allResources[state.metadata.id],
|
|
200
224
|
data: state.metadata,
|
|
201
225
|
},
|
|
202
226
|
};
|
|
203
|
-
}, [state.
|
|
227
|
+
}, [state.allResources, state.metadata, staticData]);
|
|
204
228
|
const onCloseCreateBlock = () => {
|
|
205
229
|
state.createBlockOpen = false;
|
|
206
230
|
state.newBlockParams = {
|
|
@@ -229,223 +253,237 @@ function Layout({ loadState, loadedData }) {
|
|
|
229
253
|
!location.search.includes('no-redirect=true')) {
|
|
230
254
|
return _jsx(Navigate, { to: `${firstRoute ?? '/'}`, replace: true });
|
|
231
255
|
}
|
|
232
|
-
return (_jsx(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
}, children: "Interface \u2192 Properties" }), _jsx(Button, { variant: "outlined", size: "small", color: "primary", onClick: async () => {
|
|
355
|
-
try {
|
|
356
|
-
const { dataPath } = getStaticData() || {};
|
|
357
|
-
if (!dataPath) {
|
|
358
|
-
Toast.error('无法找到组件路径');
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
Toast.info('正在生成TypeScript接口预览...');
|
|
362
|
-
const response = await api.post('/api/blocks/properties-to-interface', {
|
|
363
|
-
componentPath: dataPath,
|
|
364
|
-
});
|
|
365
|
-
if (response.data.success) {
|
|
366
|
-
const { currentInterface, newInterface } = response.data;
|
|
367
|
-
state.previewDialog = {
|
|
368
|
-
open: true,
|
|
369
|
-
title: 'Properties → Interface 预览',
|
|
370
|
-
leftTitle: '当前接口',
|
|
371
|
-
leftContent: currentInterface,
|
|
372
|
-
rightTitle: '新接口',
|
|
373
|
-
rightContent: newInterface,
|
|
374
|
-
description: '确认后将更新TypeScript接口。这将覆盖当前的接口定义。',
|
|
375
|
-
loading: false,
|
|
376
|
-
onConfirm: async () => {
|
|
377
|
-
state.previewDialog.loading = true;
|
|
378
|
-
try {
|
|
379
|
-
const updateResponse = await api.post('/api/blocks/properties-to-interface', {
|
|
380
|
-
componentPath: dataPath,
|
|
381
|
-
write: true,
|
|
382
|
-
});
|
|
383
|
-
if (updateResponse.data.success) {
|
|
384
|
-
Toast.success('TypeScript接口生成成功!');
|
|
385
|
-
state.previewDialog.open = false;
|
|
386
|
-
}
|
|
387
|
-
else {
|
|
388
|
-
throw new Error(updateResponse.data.error || '生成失败');
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
finally {
|
|
392
|
-
state.previewDialog.loading = false;
|
|
393
|
-
}
|
|
394
|
-
},
|
|
395
|
-
};
|
|
256
|
+
return (_jsx(DndProvider, { backend: HTML5Backend, children: _jsxs(StyledDashboard, { HeaderProps: {
|
|
257
|
+
// @ts-ignore
|
|
258
|
+
homeLink: joinURL(basename),
|
|
259
|
+
addons: (addons) => {
|
|
260
|
+
return [
|
|
261
|
+
_jsx(Button, { onClick: async () => {
|
|
262
|
+
if (!session?.user?.did) {
|
|
263
|
+
Toast.warning('请先连接钱包');
|
|
264
|
+
await session.login();
|
|
265
|
+
setTimeout(() => {
|
|
266
|
+
state.createResourceOpen = true;
|
|
267
|
+
}, 1000);
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
state.createResourceOpen = true;
|
|
271
|
+
}
|
|
272
|
+
}, children: "Create Resource" }, "logout"),
|
|
273
|
+
...addons,
|
|
274
|
+
];
|
|
275
|
+
},
|
|
276
|
+
}, MenusDrawerProps: { sx: { [`.${backdropClasses.root}`]: { top: 64 } } }, children: [_jsxs(Drawer, { variant: "permanent", sx: {
|
|
277
|
+
width: LEFT_DRAWER_WIDTH,
|
|
278
|
+
flexShrink: 0,
|
|
279
|
+
zIndex: 1000,
|
|
280
|
+
'& .MuiDrawer-paper': {
|
|
281
|
+
width: LEFT_DRAWER_WIDTH,
|
|
282
|
+
boxSizing: 'border-box',
|
|
283
|
+
position: 'relative',
|
|
284
|
+
height: '100%',
|
|
285
|
+
},
|
|
286
|
+
}, children: [_jsxs(Stack, { gap: 1, direction: "row", alignItems: "center", sx: { py: 2, pr: 1, pl: 0.5 }, children: [_jsx(TextField, { placeholder: "Search Blocks...", sx: { minWidth: 120 }, onChange: (e) => {
|
|
287
|
+
state.searchValue = e.target.value;
|
|
288
|
+
} }), _jsx(Button, { variant: "contained", sx: { minWidth: 'auto' }, onClick: () => {
|
|
289
|
+
state.createBlockOpen = true;
|
|
290
|
+
}, children: _jsx(AddIcon, { fontSize: "small" }) })] }), _jsx(List, { sx: { pr: 1, overflowY: 'auto' }, children: routes
|
|
291
|
+
.map((route) => {
|
|
292
|
+
const routeName = route;
|
|
293
|
+
const staticDataInRoute = staticData[route]?.main;
|
|
294
|
+
if (state.searchValue && !routeName?.toLowerCase().includes(state.searchValue?.toLowerCase())) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
if (!state.allComponents?.find(({ blockName }) => `/${blockName}` === routeName)) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
return (_jsx(ListItem, { disablePadding: true, children: _jsx(ListItemButton, { selected: currentPage.pageId === route, onClick: () => {
|
|
301
|
+
navigate(route);
|
|
302
|
+
}, sx: {
|
|
303
|
+
borderRadius: 1,
|
|
304
|
+
mb: 1,
|
|
305
|
+
width: '100%',
|
|
306
|
+
textOverflow: 'ellipsis',
|
|
307
|
+
whiteSpace: 'nowrap',
|
|
308
|
+
overflowX: 'hidden',
|
|
309
|
+
transition: 'all 0.3s ease',
|
|
310
|
+
'&.Mui-selected': {
|
|
311
|
+
backgroundColor: 'primary.main',
|
|
312
|
+
color: 'white',
|
|
313
|
+
'&:hover': {
|
|
314
|
+
backgroundColor: 'primary.main',
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
fontSize: '14px',
|
|
318
|
+
}, children: _jsx(Tooltip, { title: staticDataInRoute.blockName || routeName, children: _jsx("div", { style: {
|
|
319
|
+
width: '100%',
|
|
320
|
+
overflow: 'hidden',
|
|
321
|
+
textOverflow: 'ellipsis',
|
|
322
|
+
}, children: staticDataInRoute.blockName || routeName }) }) }) }, route));
|
|
323
|
+
})
|
|
324
|
+
.filter(Boolean) })] }), _jsx(Box, { sx: { flex: 1, overflowX: 'hidden', overflowY: getStaticData()?.isHtml ? 'hidden' : 'auto' }, children: _jsx(ThemeProvider, { theme: pagesTheme, children: _jsx(Suspense, { children: getRenderContent() }) }) }), _jsx(Drawer, { variant: "permanent", anchor: "right", sx: {
|
|
325
|
+
width: RIGHT_DRAWER_WIDTH,
|
|
326
|
+
flexShrink: 0,
|
|
327
|
+
zIndex: 1000,
|
|
328
|
+
'& .MuiDrawer-paper': {
|
|
329
|
+
width: RIGHT_DRAWER_WIDTH,
|
|
330
|
+
boxSizing: 'border-box',
|
|
331
|
+
position: 'relative',
|
|
332
|
+
height: '100%',
|
|
333
|
+
},
|
|
334
|
+
}, children: _jsxs(List, { sx: { display: 'flex', flexDirection: 'column', gap: 1 }, children: [_jsx(ListItem, { children: _jsx(Box, { sx: { width: '100%' }, children: _jsx(BasicInfo, { config: state.metadata }) }) }), _jsx(ListItem, { children: _jsxs(Box, { sx: { width: '100%' }, children: [_jsx(PropertiesConfig, { config: state.metadata, currentLocale: locale, defaultLocale: "en", allComponents: mergedAllBlocks, onUpdateConfig: (updater) => {
|
|
335
|
+
updater(state.metadata);
|
|
336
|
+
}, useI18nEditor: false }), _jsxs(Stack, { direction: "column", spacing: 1, sx: { mt: 1 }, children: [_jsx(Button, { variant: "contained", size: "small", color: "primary", onClick: async () => {
|
|
337
|
+
try {
|
|
338
|
+
const { dataPath } = getStaticData() || {};
|
|
339
|
+
if (!dataPath) {
|
|
340
|
+
Toast.error('无法找到组件路径');
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
Toast.info('正在分析组件接口...');
|
|
344
|
+
const response = await api.post('/api/blocks/interface-to-properties', {
|
|
345
|
+
componentPath: dataPath,
|
|
346
|
+
});
|
|
347
|
+
if (response.data.success) {
|
|
348
|
+
const { currentProperties, newProperties } = response.data;
|
|
349
|
+
state.previewDialog = {
|
|
350
|
+
open: true,
|
|
351
|
+
title: 'Interface → Properties 预览',
|
|
352
|
+
leftTitle: '当前 Properties',
|
|
353
|
+
leftContent: JSON.stringify(currentProperties, null, 2),
|
|
354
|
+
rightTitle: '新 Properties',
|
|
355
|
+
rightContent: JSON.stringify(newProperties, null, 2),
|
|
356
|
+
description: '确认后将更新metadata文件。这将保留现有配置值,但可能更改属性结构。',
|
|
357
|
+
loading: false,
|
|
358
|
+
onConfirm: async () => {
|
|
359
|
+
state.previewDialog.loading = true;
|
|
360
|
+
try {
|
|
361
|
+
const updateResponse = await api.post('/api/blocks/interface-to-properties', {
|
|
362
|
+
componentPath: dataPath,
|
|
363
|
+
write: true,
|
|
364
|
+
});
|
|
365
|
+
if (updateResponse.data.success) {
|
|
366
|
+
Toast.success('Metadata生成成功!');
|
|
367
|
+
// 更新当前的metadata状态
|
|
368
|
+
state.metadata = {
|
|
369
|
+
...updateResponse.data.metadata,
|
|
370
|
+
renderer: state.metadata.renderer,
|
|
371
|
+
};
|
|
372
|
+
state.previewDialog.open = false;
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
throw new Error(updateResponse.data.error || '生成失败');
|
|
376
|
+
}
|
|
396
377
|
}
|
|
397
|
-
|
|
398
|
-
|
|
378
|
+
finally {
|
|
379
|
+
state.previewDialog.loading = false;
|
|
399
380
|
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
// 不需要 propertiesValue
|
|
407
|
-
// propertiesValue={{}}
|
|
408
|
-
onChange: ({ key, value }) => {
|
|
409
|
-
state.data = {
|
|
410
|
-
...state.data,
|
|
411
|
-
[key]: value.value,
|
|
412
|
-
};
|
|
413
|
-
}, props: {
|
|
414
|
-
...state.data,
|
|
415
|
-
} }) }) }))] }) }), _jsx(CreateResource, { open: state.createResourceOpen, onClose: () => {
|
|
416
|
-
state.createResourceOpen = false;
|
|
417
|
-
} }), _jsxs(Dialog, { open: state.createBlockOpen, onClose: onCloseCreateBlock, children: [_jsx(DialogTitle, { children: "Create New Block" }), _jsx(DialogContent, { children: _jsxs(Stack, { spacing: 2, sx: { pt: 1, minWidth: 300 }, children: [_jsx(TextField, { autoFocus: true, required: true, label: "Name", fullWidth: true, value: state.newBlockParams.name, onChange: (e) => {
|
|
418
|
-
state.newBlockParams.name = e.target.value.replace(/[^a-zA-Z0-9-]/g, '');
|
|
419
|
-
} }), _jsx(TextField, { label: "Description", fullWidth: true, multiline: true, rows: 3, value: state.newBlockParams.description, onChange: (e) => {
|
|
420
|
-
state.newBlockParams.description = e.target.value;
|
|
421
|
-
} }), _jsx(Button, { variant: "contained", fullWidth: true, onClick: async () => {
|
|
422
|
-
if (!state.newBlockParams.name) {
|
|
423
|
-
Toast.warning('Block name is required');
|
|
424
|
-
return;
|
|
381
|
+
},
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
Toast.error(response.data.error || '预览失败');
|
|
386
|
+
}
|
|
425
387
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
})) {
|
|
430
|
-
Toast.warning('Block name already exists, please change it');
|
|
431
|
-
return;
|
|
388
|
+
catch (error) {
|
|
389
|
+
console.error('生成预览失败:', error);
|
|
390
|
+
Toast.error('生成预览失败');
|
|
432
391
|
}
|
|
392
|
+
}, children: "Interface \u2192 Properties" }), _jsx(Button, { variant: "outlined", size: "small", color: "primary", onClick: async () => {
|
|
433
393
|
try {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
394
|
+
const { dataPath } = getStaticData() || {};
|
|
395
|
+
if (!dataPath) {
|
|
396
|
+
Toast.error('无法找到组件路径');
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
Toast.info('正在生成TypeScript接口预览...');
|
|
400
|
+
const response = await api.post('/api/blocks/properties-to-interface', {
|
|
401
|
+
componentPath: dataPath,
|
|
402
|
+
});
|
|
403
|
+
if (response.data.success) {
|
|
404
|
+
const { currentInterface, newInterface } = response.data;
|
|
405
|
+
state.previewDialog = {
|
|
406
|
+
open: true,
|
|
407
|
+
title: 'Properties → Interface 预览',
|
|
408
|
+
leftTitle: '当前接口',
|
|
409
|
+
leftContent: currentInterface,
|
|
410
|
+
rightTitle: '新接口',
|
|
411
|
+
rightContent: newInterface,
|
|
412
|
+
description: '确认后将更新TypeScript接口。这将覆盖当前的接口定义。',
|
|
413
|
+
loading: false,
|
|
414
|
+
onConfirm: async () => {
|
|
415
|
+
state.previewDialog.loading = true;
|
|
416
|
+
try {
|
|
417
|
+
const updateResponse = await api.post('/api/blocks/properties-to-interface', {
|
|
418
|
+
componentPath: dataPath,
|
|
419
|
+
write: true,
|
|
420
|
+
});
|
|
421
|
+
if (updateResponse.data.success) {
|
|
422
|
+
Toast.success('TypeScript接口生成成功!');
|
|
423
|
+
state.previewDialog.open = false;
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
throw new Error(updateResponse.data.error || '生成失败');
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
finally {
|
|
430
|
+
state.previewDialog.loading = false;
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
Toast.error(response.data.error || '预览失败');
|
|
437
|
+
}
|
|
441
438
|
}
|
|
442
439
|
catch (error) {
|
|
443
|
-
console.error('
|
|
444
|
-
Toast.error('
|
|
440
|
+
console.error('生成接口预览失败:', error);
|
|
441
|
+
Toast.error('生成接口预览失败');
|
|
445
442
|
}
|
|
446
|
-
}, children: "
|
|
447
|
-
|
|
448
|
-
|
|
443
|
+
}, children: "Properties \u2192 Interface" })] })] }) }), state.metadata.id && (_jsx(ListItem, { children: _jsx(Box, { sx: { width: '100%' }, children: _jsx(ParametersConfig, { config: state.metadata, allComponents: mergedAllBlocks, defaultLocale: "en", locale: locale,
|
|
444
|
+
// 不需要 propertiesValue
|
|
445
|
+
// propertiesValue={{}}
|
|
446
|
+
onChange: ({ key, value }) => {
|
|
447
|
+
state.data = {
|
|
448
|
+
...state.data,
|
|
449
|
+
[key]: value.value,
|
|
450
|
+
};
|
|
451
|
+
}, props: {
|
|
452
|
+
...state.data,
|
|
453
|
+
} }) }) }))] }) }), _jsx(CreateResource, { open: state.createResourceOpen, onClose: () => {
|
|
454
|
+
state.createResourceOpen = false;
|
|
455
|
+
} }), _jsxs(Dialog, { open: state.createBlockOpen, onClose: onCloseCreateBlock, children: [_jsx(DialogTitle, { children: "Create New Block" }), _jsx(DialogContent, { children: _jsxs(Stack, { spacing: 2, sx: { pt: 1, minWidth: 300 }, children: [_jsx(TextField, { autoFocus: true, required: true, label: "Name", fullWidth: true, value: state.newBlockParams.name, onChange: (e) => {
|
|
456
|
+
state.newBlockParams.name = e.target.value.replace(/[^a-zA-Z0-9-]/g, '');
|
|
457
|
+
} }), _jsx(TextField, { label: "Description", fullWidth: true, multiline: true, rows: 3, value: state.newBlockParams.description, onChange: (e) => {
|
|
458
|
+
state.newBlockParams.description = e.target.value;
|
|
459
|
+
} }), _jsx(Button, { variant: "contained", fullWidth: true, onClick: async () => {
|
|
460
|
+
if (!state.newBlockParams.name) {
|
|
461
|
+
Toast.warning('Block name is required');
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (routes.some((route) => {
|
|
465
|
+
const staticDataInRoute = staticData[route]?.main;
|
|
466
|
+
return staticDataInRoute?.blockName?.toLowerCase() === state.newBlockParams.name.toLowerCase();
|
|
467
|
+
})) {
|
|
468
|
+
Toast.warning('Block name already exists, please change it');
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
try {
|
|
472
|
+
await api.post('/api/blocks/create', state.newBlockParams);
|
|
473
|
+
navigate(`/${state.newBlockParams.name}?no-redirect=true`);
|
|
474
|
+
// wait for the file to be created
|
|
475
|
+
setTimeout(() => {
|
|
476
|
+
window.location.reload();
|
|
477
|
+
}, 100);
|
|
478
|
+
onCloseCreateBlock();
|
|
479
|
+
}
|
|
480
|
+
catch (error) {
|
|
481
|
+
console.error('Failed to create block:', error);
|
|
482
|
+
Toast.error('Failed to create block');
|
|
483
|
+
}
|
|
484
|
+
}, children: "Create" })] }) })] }), _jsx(ComparisonPreviewDialog, { open: state.previewDialog.open, title: state.previewDialog.title, leftTitle: state.previewDialog.leftTitle, leftContent: state.previewDialog.leftContent, rightTitle: state.previewDialog.rightTitle, rightContent: state.previewDialog.rightContent, description: state.previewDialog.description, loading: state.previewDialog.loading, onConfirm: state.previewDialog.onConfirm, onClose: () => {
|
|
485
|
+
state.previewDialog.open = false;
|
|
486
|
+
} })] }) }));
|
|
449
487
|
}
|
|
450
488
|
const StyledDashboard = styled(Dashboard) `
|
|
451
489
|
.dashboard-content {
|
|
@@ -485,7 +523,7 @@ const StyledDashboard = styled(Dashboard) `
|
|
|
485
523
|
}
|
|
486
524
|
`;
|
|
487
525
|
function LayoutWrapper({ loadState, loadedData, ...rest }) {
|
|
488
|
-
return (_jsx(ToastProvider, { children: _jsx(LocaleProvider, { translations: translations, fallbackLocale: "en", children: _jsx(Layout, { loadState: loadState, loadedData: loadedData }) }) }));
|
|
526
|
+
return (_jsx(StyledEngineProvider, { injectFirst: true, children: _jsx(ThemeProvider, { theme: theme, children: _jsx(ToastProvider, { children: _jsx(LocaleProvider, { translations: translations, fallbackLocale: "en", children: _jsx(SessionProvider, { serviceHost: basename, protectedRoutes: [`${basename}/*`], children: _jsx(Layout, { loadState: loadState, loadedData: loadedData }) }) }) }) }) }));
|
|
489
527
|
}
|
|
490
528
|
export default LayoutWrapper;
|
|
491
529
|
function CreateResource({ open, onClose }) {
|