@blocklet/ui-react 2.9.29 → 2.9.30
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/es/ComponentInstaller/index.d.ts +30 -0
- package/es/ComponentInstaller/index.js +41 -153
- package/es/ComponentInstaller/installer-item.d.ts +21 -0
- package/es/ComponentInstaller/installer-item.js +139 -0
- package/es/ComponentInstaller/use-component-installed.d.ts +3 -6
- package/es/ComponentInstaller/use-component-installed.js +41 -23
- package/lib/ComponentInstaller/index.d.ts +30 -0
- package/lib/ComponentInstaller/index.js +56 -173
- package/lib/ComponentInstaller/installer-item.d.ts +21 -0
- package/lib/ComponentInstaller/installer-item.js +161 -0
- package/lib/ComponentInstaller/use-component-installed.d.ts +3 -6
- package/lib/ComponentInstaller/use-component-installed.js +34 -21
- package/package.json +4 -4
- package/src/ComponentInstaller/index.jsx +50 -149
- package/src/ComponentInstaller/installer-item.jsx +131 -0
- package/src/ComponentInstaller/use-component-installed.js +41 -23
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { Button, Box, ClickAwayListener, Fade, Paper } from '@mui/material';
|
|
2
|
-
import { Icon } from '@iconify/react';
|
|
3
|
-
import { temp as colors } from '@arcblock/ux/lib/Colors';
|
|
4
1
|
import { SessionContext } from '@arcblock/did-connect/lib/Session';
|
|
5
|
-
import {
|
|
2
|
+
import { temp as colors } from '@arcblock/ux/lib/Colors';
|
|
3
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
4
|
+
import { translate } from '@arcblock/ux/lib/Locale/util';
|
|
6
5
|
import SessionPermission from '@arcblock/ux/lib/SessionPermission';
|
|
7
|
-
import
|
|
6
|
+
import { Icon } from '@iconify/react';
|
|
7
|
+
import CloseIcon from '@mui/icons-material/Close';
|
|
8
|
+
import { Box, ClickAwayListener, Fade, IconButton, Paper } from '@mui/material';
|
|
8
9
|
import { useMemoizedFn } from 'ahooks';
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
10
|
+
import PropTypes from 'prop-types';
|
|
11
|
+
import { useContext } from 'react';
|
|
12
|
+
import InstallerItem from './installer-item';
|
|
12
13
|
import translations from './locales';
|
|
14
|
+
import useComponentInstalled from './use-component-installed';
|
|
13
15
|
|
|
14
16
|
function ComponentInstaller({
|
|
15
17
|
warnIcon,
|
|
@@ -28,32 +30,17 @@ function ComponentInstaller({
|
|
|
28
30
|
const t = useMemoizedFn((key, data = {}) => {
|
|
29
31
|
return translate(translations, key, locale, 'en', data);
|
|
30
32
|
});
|
|
31
|
-
const { installed,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
33
|
+
const { installed, optComponents, installStatus, definedInBlockletYML } = useComponentInstalled({
|
|
34
|
+
did,
|
|
35
|
+
onInstalled,
|
|
36
|
+
onError,
|
|
37
|
+
});
|
|
37
38
|
const sessionCtx = useContext(SessionContext);
|
|
38
39
|
|
|
39
|
-
const handleInstall = () => {
|
|
40
|
-
window.open(installUrl, '_blank');
|
|
41
|
-
};
|
|
42
|
-
|
|
43
40
|
const handleClose = () => {
|
|
44
41
|
onClose?.(false);
|
|
45
42
|
};
|
|
46
43
|
|
|
47
|
-
const handleOpenStore = () => {
|
|
48
|
-
window.open(storeUrl, '_blank');
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const handleRefresh = () => {
|
|
52
|
-
window.location.reload();
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const size = 60;
|
|
56
|
-
|
|
57
44
|
if (disabled) {
|
|
58
45
|
return children;
|
|
59
46
|
}
|
|
@@ -73,11 +60,8 @@ function ComponentInstaller({
|
|
|
73
60
|
{fallback}
|
|
74
61
|
{children({
|
|
75
62
|
hasPermission,
|
|
76
|
-
|
|
63
|
+
optComponents,
|
|
77
64
|
installStatus,
|
|
78
|
-
handleOpenStore,
|
|
79
|
-
handleInstall,
|
|
80
|
-
handleRefresh,
|
|
81
65
|
})}
|
|
82
66
|
</>
|
|
83
67
|
);
|
|
@@ -104,7 +88,7 @@ function ComponentInstaller({
|
|
|
104
88
|
zIndex: 3000,
|
|
105
89
|
borderRadius: 3,
|
|
106
90
|
width: 400,
|
|
107
|
-
maxWidth:
|
|
91
|
+
maxWidth: '90vw',
|
|
108
92
|
borderColor: colors.lineStep,
|
|
109
93
|
border: '0 !important',
|
|
110
94
|
fontSize: '14px',
|
|
@@ -118,6 +102,7 @@ function ComponentInstaller({
|
|
|
118
102
|
padding: '20px 24px',
|
|
119
103
|
marginLeft: 0,
|
|
120
104
|
display: 'flex',
|
|
105
|
+
alignItems: 'center',
|
|
121
106
|
flexDirection: 'row',
|
|
122
107
|
justifyContent: 'flex-start',
|
|
123
108
|
}}>
|
|
@@ -125,18 +110,17 @@ function ComponentInstaller({
|
|
|
125
110
|
<Box sx={{ marginLeft: 1, fontSize: '16px', fontWeight: 'bold' }}>
|
|
126
111
|
{t('componentInstallerTitle')}
|
|
127
112
|
</Box>
|
|
113
|
+
<Box sx={{ flex: 1 }} />
|
|
114
|
+
{onClose ? (
|
|
115
|
+
<IconButton variant="outlined" className="button" onClick={handleClose}>
|
|
116
|
+
<CloseIcon />
|
|
117
|
+
</IconButton>
|
|
118
|
+
) : null}
|
|
128
119
|
</Box>
|
|
129
120
|
<Box sx={{ width: '100%', height: '1px', backgroundColor: colors.gray6 }} />
|
|
130
121
|
<Box sx={{ padding: '20px 24px', marginTop: 0 }}>
|
|
131
122
|
{t('componentInstallerNoDefinedInBlockletYML')}: {did}
|
|
132
123
|
</Box>
|
|
133
|
-
<Box sx={{ padding: '0px 24px' }}>
|
|
134
|
-
{onClose ? (
|
|
135
|
-
<Button sx={{ marginBottom: 2 }} variant="outlined" className="button" onClick={handleClose}>
|
|
136
|
-
{t('componentInstallerClose')}
|
|
137
|
-
</Button>
|
|
138
|
-
) : null}
|
|
139
|
-
</Box>
|
|
140
124
|
</Box>
|
|
141
125
|
) : (
|
|
142
126
|
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
|
@@ -146,128 +130,40 @@ function ComponentInstaller({
|
|
|
146
130
|
marginLeft: 0,
|
|
147
131
|
display: 'flex',
|
|
148
132
|
flexDirection: 'row',
|
|
133
|
+
alignItems: 'center',
|
|
149
134
|
justifyContent: 'flex-start',
|
|
150
135
|
}}>
|
|
151
136
|
{warnIcon || <Icon icon="mdi:warning-box" style={{ color: 'yellowgreen', fontSize: 24 }} />}
|
|
152
137
|
<Box sx={{ marginLeft: 1, fontSize: '16px', fontWeight: 'bold' }}>
|
|
153
138
|
{t('componentInstallerTitle')}
|
|
154
139
|
</Box>
|
|
140
|
+
<Box sx={{ flex: 1 }} />
|
|
141
|
+
{onClose ? (
|
|
142
|
+
<IconButton variant="outlined" className="button" onClick={handleClose}>
|
|
143
|
+
<CloseIcon />
|
|
144
|
+
</IconButton>
|
|
145
|
+
) : null}
|
|
155
146
|
</Box>
|
|
156
147
|
<Box sx={{ width: '100%', height: '1px', backgroundColor: colors.gray6 }} />
|
|
157
|
-
<Box
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
alt={optionalComponent.meta.title}
|
|
171
|
-
/>
|
|
172
|
-
<Box
|
|
173
|
-
sx={{
|
|
174
|
-
display: 'flex',
|
|
175
|
-
flexDirection: 'column',
|
|
176
|
-
justifyContent: 'start',
|
|
177
|
-
alignItems: 'start',
|
|
178
|
-
marginLeft: 2,
|
|
179
|
-
}}>
|
|
180
|
-
<Box
|
|
181
|
-
sx={{
|
|
182
|
-
fontSize: '16px',
|
|
183
|
-
fontWeight: 'bold',
|
|
184
|
-
cursor: 'pointer',
|
|
185
|
-
'.link-icon': {
|
|
186
|
-
opacity: 0,
|
|
187
|
-
},
|
|
188
|
-
':hover .link-icon': {
|
|
189
|
-
opacity: 1,
|
|
190
|
-
},
|
|
191
|
-
}}
|
|
192
|
-
onClick={handleOpenStore}>
|
|
193
|
-
{optionalComponent.meta.title}
|
|
194
|
-
<Box
|
|
195
|
-
sx={{
|
|
196
|
-
paddingLeft: 1,
|
|
197
|
-
fontSize: '13px',
|
|
198
|
-
fontWeight: '400',
|
|
199
|
-
}}
|
|
200
|
-
component="span">
|
|
201
|
-
{optionalComponent.meta.version}
|
|
202
|
-
<Icon
|
|
203
|
-
className="link-icon"
|
|
204
|
-
icon="fluent:open-20-filled"
|
|
205
|
-
style={{
|
|
206
|
-
color: colors.primaryBase,
|
|
207
|
-
fontSize: 16,
|
|
208
|
-
transform: 'translate(6px, 3px)',
|
|
209
|
-
transition: 'all 0.3s',
|
|
210
|
-
}}
|
|
211
|
-
/>
|
|
212
|
-
</Box>
|
|
213
|
-
</Box>
|
|
214
|
-
<Box sx={{ marginTop: 0, opacity: 0.7 }}>{optionalComponent.meta.description}</Box>
|
|
215
|
-
<Box sx={{ display: hasPermission ? 'flex' : 'none', flexDirection: 'row', gap: 1 }}>
|
|
216
|
-
{installStatus ? (
|
|
217
|
-
<Box sx={{ marginTop: 2, opacity: 0.7 }}>
|
|
218
|
-
{installStatusDone ? (
|
|
219
|
-
<Button key="refresh" variant="contained" onClick={handleRefresh}>
|
|
220
|
-
{t('componentInstallerRefresh')}
|
|
221
|
-
</Button>
|
|
222
|
-
) : (
|
|
223
|
-
<Button
|
|
224
|
-
key="status"
|
|
225
|
-
disabled
|
|
226
|
-
sx={{ color: '#333' }}
|
|
227
|
-
startIcon={
|
|
228
|
-
<Icon icon="line-md:loading-loop" style={{ color: '#333', fontSize: 16 }} />
|
|
229
|
-
}
|
|
230
|
-
variant="contained">
|
|
231
|
-
{installStatus}
|
|
232
|
-
</Button>
|
|
233
|
-
)}
|
|
234
|
-
</Box>
|
|
235
|
-
) : (
|
|
236
|
-
<Button
|
|
237
|
-
key="install"
|
|
238
|
-
sx={{ marginTop: 2 }}
|
|
239
|
-
variant="contained"
|
|
240
|
-
className="button"
|
|
241
|
-
onClick={handleInstall}>
|
|
242
|
-
{t('componentInstallerInstall')}
|
|
243
|
-
</Button>
|
|
244
|
-
)}
|
|
245
|
-
{onClose ? (
|
|
246
|
-
<Button sx={{ marginTop: 2 }} variant="outlined" className="button" onClick={handleClose}>
|
|
247
|
-
{t('componentInstallerClose')}
|
|
248
|
-
</Button>
|
|
249
|
-
) : null}
|
|
250
|
-
</Box>
|
|
251
|
-
{installStatusDone ? (
|
|
252
|
-
<Box sx={{ marginTop: 2, opacity: 0.7 }}>{t('componentInstallerSuccessInstalled')}</Box>
|
|
253
|
-
) : null}
|
|
254
|
-
</Box>
|
|
148
|
+
<Box sx={{ maxHeight: '70vh', overflowY: 'auto' }}>
|
|
149
|
+
{optComponents.map((optionalComponent, index) => {
|
|
150
|
+
return (
|
|
151
|
+
<InstallerItem
|
|
152
|
+
t={t}
|
|
153
|
+
key={optionalComponent.meta?.did || index}
|
|
154
|
+
hasPermission={hasPermission}
|
|
155
|
+
index={index}
|
|
156
|
+
optionalComponent={optionalComponent}
|
|
157
|
+
installStatus={installStatus[optionalComponent.meta?.did]}
|
|
158
|
+
/>
|
|
159
|
+
);
|
|
160
|
+
})}
|
|
255
161
|
</Box>
|
|
256
|
-
|
|
257
162
|
{hasPermission ? null : (
|
|
258
163
|
<>
|
|
259
164
|
<Box sx={{ width: '100%', height: '1px', backgroundColor: colors.gray6 }} />
|
|
260
165
|
<Box sx={{ padding: '20px 24px' }}>
|
|
261
166
|
<Box sx={{ opacity: 1 }}>{t('componentInstallerSuggestions')}</Box>
|
|
262
|
-
{onClose ? (
|
|
263
|
-
<Button
|
|
264
|
-
sx={{ marginTop: 2, alignSelf: 'flex-start' }}
|
|
265
|
-
variant="outlined"
|
|
266
|
-
className="button"
|
|
267
|
-
onClick={handleClose}>
|
|
268
|
-
{t('componentInstallerClose')}
|
|
269
|
-
</Button>
|
|
270
|
-
) : null}
|
|
271
167
|
</Box>
|
|
272
168
|
</>
|
|
273
169
|
)}
|
|
@@ -286,7 +182,7 @@ function ComponentInstaller({
|
|
|
286
182
|
ComponentInstaller.propTypes = {
|
|
287
183
|
disabled: PropTypes.bool,
|
|
288
184
|
warnIcon: PropTypes.node,
|
|
289
|
-
did: PropTypes.string.isRequired,
|
|
185
|
+
did: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]).isRequired,
|
|
290
186
|
noPermissionMute: PropTypes.bool,
|
|
291
187
|
onInstalled: PropTypes.func,
|
|
292
188
|
onError: PropTypes.func,
|
|
@@ -318,5 +214,10 @@ export default function WrapComponentInstaller(props) {
|
|
|
318
214
|
}
|
|
319
215
|
|
|
320
216
|
WrapComponentInstaller.propTypes = {
|
|
217
|
+
...ComponentInstaller.propTypes,
|
|
321
218
|
children: PropTypes.any.isRequired,
|
|
322
219
|
};
|
|
220
|
+
|
|
221
|
+
WrapComponentInstaller.defaultProps = {
|
|
222
|
+
...ComponentInstaller.defaultProps,
|
|
223
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { temp as colors } from '@arcblock/ux/lib/Colors';
|
|
2
|
+
import { Icon } from '@iconify/react';
|
|
3
|
+
import { Box, Button } from '@mui/material';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
|
|
6
|
+
export default function InstallerItem({ optionalComponent, index, installStatus, hasPermission, t }) {
|
|
7
|
+
const handleInstall = () => {
|
|
8
|
+
window.open(optionalComponent?.installUrl, '_blank');
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const handleOpenStore = () => {
|
|
12
|
+
window.open(optionalComponent?.storeUrl, '_blank');
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const handleRefresh = () => {
|
|
16
|
+
window.location.reload();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const installStatusDone = installStatus === 'stopped' || installStatus === 'running';
|
|
20
|
+
const size = 60;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Box>
|
|
24
|
+
{index === 0 ? null : <Box sx={{ width: '100%', height: '1px', backgroundColor: colors.gray6 }} />}
|
|
25
|
+
<Box
|
|
26
|
+
sx={{
|
|
27
|
+
padding: '20px 24px',
|
|
28
|
+
paddingTop: 0.5,
|
|
29
|
+
marginTop: 2,
|
|
30
|
+
display: 'flex',
|
|
31
|
+
flexDirection: 'row',
|
|
32
|
+
justifyContent: 'start',
|
|
33
|
+
alignItems: 'flex-start',
|
|
34
|
+
}}>
|
|
35
|
+
<img
|
|
36
|
+
style={{ width: size, height: size, minWidth: size, minHeight: size }}
|
|
37
|
+
src={optionalComponent.logoUrl}
|
|
38
|
+
alt={optionalComponent.meta.title}
|
|
39
|
+
/>
|
|
40
|
+
<Box
|
|
41
|
+
sx={{
|
|
42
|
+
display: 'flex',
|
|
43
|
+
flexDirection: 'column',
|
|
44
|
+
justifyContent: 'start',
|
|
45
|
+
alignItems: 'start',
|
|
46
|
+
marginLeft: 2,
|
|
47
|
+
}}>
|
|
48
|
+
<Box
|
|
49
|
+
sx={{
|
|
50
|
+
fontSize: '16px',
|
|
51
|
+
fontWeight: 'bold',
|
|
52
|
+
cursor: 'pointer',
|
|
53
|
+
'.link-icon': {
|
|
54
|
+
opacity: 0,
|
|
55
|
+
},
|
|
56
|
+
':hover .link-icon': {
|
|
57
|
+
opacity: 1,
|
|
58
|
+
},
|
|
59
|
+
}}
|
|
60
|
+
onClick={() => handleOpenStore(optionalComponent.meta?.did)}>
|
|
61
|
+
{optionalComponent.meta.title}
|
|
62
|
+
<Box
|
|
63
|
+
sx={{
|
|
64
|
+
paddingLeft: 1,
|
|
65
|
+
fontSize: '13px',
|
|
66
|
+
fontWeight: '400',
|
|
67
|
+
}}
|
|
68
|
+
component="span">
|
|
69
|
+
{optionalComponent.meta.version}
|
|
70
|
+
<Icon
|
|
71
|
+
className="link-icon"
|
|
72
|
+
icon="fluent:open-20-filled"
|
|
73
|
+
style={{
|
|
74
|
+
color: colors.primaryBase,
|
|
75
|
+
fontSize: 16,
|
|
76
|
+
transform: 'translate(6px, 3px)',
|
|
77
|
+
transition: 'all 0.3s',
|
|
78
|
+
}}
|
|
79
|
+
/>
|
|
80
|
+
</Box>
|
|
81
|
+
</Box>
|
|
82
|
+
<Box sx={{ marginTop: 0, opacity: 0.7 }}>{optionalComponent.meta.description}</Box>
|
|
83
|
+
<Box sx={{ display: hasPermission ? 'flex' : 'none', flexDirection: 'row', gap: 1 }}>
|
|
84
|
+
{installStatus ? (
|
|
85
|
+
<Box sx={{ marginTop: 2, opacity: 0.7 }}>
|
|
86
|
+
{installStatusDone ? (
|
|
87
|
+
<Button key="refresh" variant="contained" onClick={handleRefresh}>
|
|
88
|
+
{t('componentInstallerRefresh')}
|
|
89
|
+
</Button>
|
|
90
|
+
) : (
|
|
91
|
+
<Button
|
|
92
|
+
key="status"
|
|
93
|
+
disabled
|
|
94
|
+
sx={{ color: '#333' }}
|
|
95
|
+
startIcon={<Icon icon="line-md:loading-loop" style={{ color: '#333', fontSize: 16 }} />}
|
|
96
|
+
variant="contained">
|
|
97
|
+
{installStatus}
|
|
98
|
+
</Button>
|
|
99
|
+
)}
|
|
100
|
+
</Box>
|
|
101
|
+
) : (
|
|
102
|
+
<Button
|
|
103
|
+
key="install"
|
|
104
|
+
sx={{ marginTop: 2 }}
|
|
105
|
+
variant="contained"
|
|
106
|
+
className="button"
|
|
107
|
+
onClick={() => handleInstall(optionalComponent.meta?.did)}>
|
|
108
|
+
{t('componentInstallerInstall')}
|
|
109
|
+
</Button>
|
|
110
|
+
)}
|
|
111
|
+
</Box>
|
|
112
|
+
{installStatusDone ? (
|
|
113
|
+
<Box sx={{ marginTop: 2, opacity: 0.7 }}>{t('componentInstallerSuccessInstalled')}</Box>
|
|
114
|
+
) : null}
|
|
115
|
+
</Box>
|
|
116
|
+
</Box>
|
|
117
|
+
</Box>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
InstallerItem.propTypes = {
|
|
122
|
+
t: PropTypes.func.isRequired,
|
|
123
|
+
optionalComponent: PropTypes.object.isRequired,
|
|
124
|
+
index: PropTypes.number.isRequired,
|
|
125
|
+
installStatus: PropTypes.string,
|
|
126
|
+
hasPermission: PropTypes.bool.isRequired,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
InstallerItem.defaultProps = {
|
|
130
|
+
installStatus: '',
|
|
131
|
+
};
|
|
@@ -1,32 +1,48 @@
|
|
|
1
1
|
import { AUTH_SERVICE_PREFIX } from '@arcblock/did-connect/lib/constant';
|
|
2
|
-
import { useMemo, useRef, useState
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import urlJoin from 'url-join';
|
|
4
4
|
|
|
5
|
+
const parseDidToSet = (did) => {
|
|
6
|
+
if (typeof did === 'string') {
|
|
7
|
+
return new Set(did.split(';;'));
|
|
8
|
+
}
|
|
9
|
+
return new Set(did);
|
|
10
|
+
};
|
|
11
|
+
|
|
5
12
|
function useComponentInstalled({ did, onInstalled, onError }) {
|
|
6
|
-
const
|
|
13
|
+
const didKeys = Array.isArray(did) ? did.join(';;') : did;
|
|
14
|
+
const [installStatus, setInstallStatus] = useState({});
|
|
7
15
|
const onInstalledRef = useRef({ onInstalled, onError });
|
|
8
16
|
onInstalledRef.current = { onInstalled, onError };
|
|
9
17
|
|
|
10
18
|
const { optionalComponents, componentMountPoints } = window.blocklet;
|
|
11
19
|
|
|
12
|
-
const
|
|
20
|
+
const optComponents = useMemo(() => {
|
|
13
21
|
if (!optionalComponents || !optionalComponents.length) {
|
|
14
22
|
return null;
|
|
15
23
|
}
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
const didSet = parseDidToSet(didKeys);
|
|
25
|
+
const components = optionalComponents.filter((c) => didSet.has(c.meta.did));
|
|
26
|
+
(components ? onInstalledRef.current.onError : onInstalledRef.current.onInstalled)?.(components);
|
|
27
|
+
return components;
|
|
28
|
+
}, [didKeys, optionalComponents]);
|
|
20
29
|
|
|
21
30
|
const definedInBlockletYML = useMemo(() => {
|
|
22
|
-
if (
|
|
31
|
+
if (optComponents.length) {
|
|
23
32
|
return true;
|
|
24
33
|
}
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
const didSet = parseDidToSet(didKeys);
|
|
35
|
+
return (componentMountPoints || []).find((item) => didSet.has(item.did));
|
|
36
|
+
}, [optComponents, componentMountPoints, didKeys]);
|
|
27
37
|
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
optComponents.forEach((item) => {
|
|
39
|
+
item.storeUrl = urlJoin(item.meta.homepage, 'blocklets', item.meta.did);
|
|
40
|
+
item.installUrl = urlJoin(
|
|
41
|
+
window.blocklet.appUrl,
|
|
42
|
+
AUTH_SERVICE_PREFIX,
|
|
43
|
+
`/admin/components?install-component=${item.meta.did}`
|
|
44
|
+
);
|
|
45
|
+
});
|
|
30
46
|
|
|
31
47
|
useEffect(() => {
|
|
32
48
|
const handle = (event) => {
|
|
@@ -36,33 +52,35 @@ function useComponentInstalled({ did, onInstalled, onError }) {
|
|
|
36
52
|
|
|
37
53
|
if (event.data?.kind === 'component-installer' && event.data?.blocklet?.children) {
|
|
38
54
|
let hasChild = false;
|
|
55
|
+
const didSet = parseDidToSet(didKeys);
|
|
39
56
|
event.data?.blocklet?.children.forEach((item) => {
|
|
40
|
-
if (item.meta?.did
|
|
57
|
+
if (didSet.has(item.meta?.did)) {
|
|
41
58
|
hasChild = true;
|
|
42
|
-
setInstallStatus(
|
|
59
|
+
setInstallStatus((value) => {
|
|
60
|
+
return {
|
|
61
|
+
...value,
|
|
62
|
+
[item.meta?.did]: item.status || 'waiting',
|
|
63
|
+
};
|
|
64
|
+
});
|
|
43
65
|
}
|
|
44
66
|
});
|
|
45
67
|
if (!hasChild) {
|
|
46
|
-
setInstallStatus(
|
|
68
|
+
setInstallStatus({});
|
|
47
69
|
}
|
|
48
70
|
}
|
|
49
71
|
};
|
|
72
|
+
|
|
50
73
|
window.addEventListener('message', handle);
|
|
51
74
|
return () => {
|
|
52
75
|
window.removeEventListener('message', handle);
|
|
53
76
|
};
|
|
54
|
-
}, [
|
|
55
|
-
|
|
56
|
-
const installStatusDone = installStatus === 'stopped' || installStatus === 'running';
|
|
77
|
+
}, [didKeys]);
|
|
57
78
|
|
|
58
79
|
return {
|
|
59
|
-
|
|
60
|
-
installed: !
|
|
61
|
-
installUrl,
|
|
62
|
-
storeUrl,
|
|
80
|
+
optComponents,
|
|
81
|
+
installed: !optComponents.length && definedInBlockletYML,
|
|
63
82
|
installStatus,
|
|
64
83
|
setInstallStatus,
|
|
65
|
-
installStatusDone,
|
|
66
84
|
definedInBlockletYML,
|
|
67
85
|
};
|
|
68
86
|
}
|