@abtnode/ux 1.16.17-beta-5d4664f8 → 1.16.17-beta-2ac96448
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/blocklet/configuration.js +169 -32
- package/es/blocklet/publish/create-release.js +1 -1
- package/es/blocklet/storage/auto-backup.js +55 -0
- package/es/blocklet/storage/connected.js +6 -0
- package/es/contexts/blocklet-storage.js +28 -1
- package/es/hooks/use-app-logo.js +20 -4
- package/es/hooks/use-auto-backup.js +33 -0
- package/es/locales/en.js +11 -4
- package/es/locales/zh.js +11 -4
- package/es/util/index.js +2 -1
- package/lib/blocklet/configuration.js +141 -33
- package/lib/blocklet/publish/create-release.js +1 -1
- package/lib/blocklet/storage/auto-backup.js +64 -0
- package/lib/blocklet/storage/connected.js +6 -0
- package/lib/contexts/blocklet-storage.js +28 -1
- package/lib/hooks/use-app-logo.js +21 -4
- package/lib/hooks/use-auto-backup.js +43 -0
- package/lib/locales/en.js +11 -4
- package/lib/locales/zh.js +11 -4
- package/lib/util/index.js +4 -2
- package/package.json +8 -8
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import React, { useState, useContext } from 'react';
|
|
1
|
+
import React, { useState, useContext, lazy, useRef } from 'react';
|
|
2
2
|
import styled from '@emotion/styled';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import get from 'lodash/get';
|
|
5
5
|
import isEqual from 'lodash/isEqual';
|
|
6
|
+
import classnames from 'classnames';
|
|
7
|
+
import joinUrl from 'url-join';
|
|
6
8
|
import Box from '@mui/material/Box';
|
|
7
9
|
import Switch from '@mui/material/Switch';
|
|
8
10
|
import Divider from '@mui/material/Divider';
|
|
9
11
|
import { LocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
10
12
|
import Button from '@arcblock/ux/lib/Button';
|
|
11
13
|
import LoopIcon from '@mui/icons-material/Loop';
|
|
14
|
+
import Avatar from '@mui/material/Avatar';
|
|
12
15
|
import { EVENTS } from '@abtnode/constant';
|
|
13
16
|
import { BLOCKLET_CONFIGURABLE_KEY, SUPPORTED_LANGUAGES } from '@blocklet/constant';
|
|
14
17
|
import { getWhoCanAccess } from '@blocklet/meta/lib/util';
|
|
@@ -22,19 +25,34 @@ import Permission, { withPermission } from '../permission';
|
|
|
22
25
|
import ClearCache from '../clear-cache';
|
|
23
26
|
import AppSk from './preferences/app-sk';
|
|
24
27
|
import TransferOwner from './transfer-owner';
|
|
28
|
+
import useAppLogo from '../hooks/use-app-logo';
|
|
25
29
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
26
30
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
27
31
|
const languages = Object.keys(SUPPORTED_LANGUAGES).map(x => ({
|
|
28
32
|
code: x,
|
|
29
33
|
name: SUPPORTED_LANGUAGES[x].nativeName
|
|
30
34
|
}));
|
|
35
|
+
|
|
36
|
+
// eslint-disable-next-line import/no-unresolved
|
|
37
|
+
const UploaderComponent = /*#__PURE__*/lazy(() => import('@blocklet/uploader/react').then(res => ({
|
|
38
|
+
default: res.Uploader
|
|
39
|
+
})));
|
|
40
|
+
const uploadPrefix = '/blocklet/logo/upload';
|
|
31
41
|
function BlockletEnvironment({
|
|
32
42
|
blocklet,
|
|
33
43
|
onUpdate,
|
|
34
44
|
hasPermission,
|
|
35
45
|
...rest
|
|
36
46
|
}) {
|
|
37
|
-
const
|
|
47
|
+
const {
|
|
48
|
+
api,
|
|
49
|
+
inService,
|
|
50
|
+
prefix,
|
|
51
|
+
getSessionInHeader,
|
|
52
|
+
ws: {
|
|
53
|
+
useSubscription
|
|
54
|
+
}
|
|
55
|
+
} = useNodeContext();
|
|
38
56
|
const {
|
|
39
57
|
t
|
|
40
58
|
} = useContext(LocaleContext);
|
|
@@ -44,12 +62,28 @@ function BlockletEnvironment({
|
|
|
44
62
|
const whoCanAccess = getWhoCanAccess(blocklet);
|
|
45
63
|
const publicToStore = blocklet?.settings?.publicToStore;
|
|
46
64
|
const disabled = loading || !hasPermission;
|
|
65
|
+
const uploaderLogoRef = useRef(null);
|
|
47
66
|
const {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
67
|
+
logoUrl,
|
|
68
|
+
rectLogoUrl,
|
|
69
|
+
faviconUrl
|
|
70
|
+
} = useAppLogo({
|
|
71
|
+
blocklet
|
|
72
|
+
});
|
|
73
|
+
const [apiPathProps, setApiPathProps] = useState();
|
|
74
|
+
const uploadLogoPrefix = joinUrl(prefix, uploadPrefix, 'square', blocklet.meta.did);
|
|
75
|
+
const uploadLogoRectPrefix = joinUrl(prefix, uploadPrefix, 'rect', blocklet.meta.did);
|
|
76
|
+
const uploadLogoFaviconPrefix = joinUrl(prefix, uploadPrefix, 'favicon', blocklet.meta.did);
|
|
77
|
+
const openUploader = uploaderPrefix => {
|
|
78
|
+
if (!hasPermission) {
|
|
79
|
+
return;
|
|
51
80
|
}
|
|
52
|
-
|
|
81
|
+
setApiPathProps({
|
|
82
|
+
uploader: uploaderPrefix,
|
|
83
|
+
disableMediaKitPrefix: true
|
|
84
|
+
});
|
|
85
|
+
uploaderLogoRef.current.open();
|
|
86
|
+
};
|
|
53
87
|
const {
|
|
54
88
|
did
|
|
55
89
|
} = blocklet.meta;
|
|
@@ -71,10 +105,6 @@ function BlockletEnvironment({
|
|
|
71
105
|
const deletable = !customDelete || customDelete.value === 'yes';
|
|
72
106
|
const customLanguages = blocklet.environments.find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LANGUAGES);
|
|
73
107
|
const customUrl = blocklet.environments.find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_URL);
|
|
74
|
-
const customLogoSquare = blocklet.environments.find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_SQUARE);
|
|
75
|
-
const customLogoRect = blocklet.environments.find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_RECT);
|
|
76
|
-
const customLogoFavicon = blocklet.environments.find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_FAVICON);
|
|
77
|
-
const customLogoDeprecated = blocklet.environments.find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO);
|
|
78
108
|
const copyrightOwner = blocklet.environments.find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_COPYRIGHT_OWNER);
|
|
79
109
|
const copyrightYear = blocklet.environments.find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_COPYRIGHT_YEAR);
|
|
80
110
|
const configurableEnvs = [{
|
|
@@ -89,22 +119,6 @@ function BlockletEnvironment({
|
|
|
89
119
|
key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_URL,
|
|
90
120
|
description: t('blocklet.config.appUrl'),
|
|
91
121
|
value: customUrl ? customUrl.value : ''
|
|
92
|
-
}, {
|
|
93
|
-
key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_SQUARE,
|
|
94
|
-
description: t('blocklet.config.logoSquare'),
|
|
95
|
-
value: customLogoSquare ? customLogoSquare.value : ''
|
|
96
|
-
}, {
|
|
97
|
-
key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_RECT,
|
|
98
|
-
description: t('blocklet.config.logoRect'),
|
|
99
|
-
value: customLogoRect ? customLogoRect.value : ''
|
|
100
|
-
}, {
|
|
101
|
-
key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_FAVICON,
|
|
102
|
-
description: t('blocklet.config.logoFavicon'),
|
|
103
|
-
value: customLogoFavicon ? customLogoFavicon.value : ''
|
|
104
|
-
}, {
|
|
105
|
-
key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO,
|
|
106
|
-
description: t('blocklet.config.logo'),
|
|
107
|
-
value: customLogoDeprecated ? customLogoDeprecated.value : ''
|
|
108
122
|
}, {
|
|
109
123
|
key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_COPYRIGHT_OWNER,
|
|
110
124
|
description: t('blocklet.config.copyrightOwner'),
|
|
@@ -135,7 +149,7 @@ function BlockletEnvironment({
|
|
|
135
149
|
} = e.target;
|
|
136
150
|
const {
|
|
137
151
|
blocklet: data
|
|
138
|
-
} = await
|
|
152
|
+
} = await api.configPublicToStore({
|
|
139
153
|
input: {
|
|
140
154
|
did: blocklet.meta.did,
|
|
141
155
|
publicToStore: checked
|
|
@@ -167,7 +181,7 @@ function BlockletEnvironment({
|
|
|
167
181
|
setLoading(true);
|
|
168
182
|
const {
|
|
169
183
|
blocklet: data
|
|
170
|
-
} = await
|
|
184
|
+
} = await api.configBlocklet({
|
|
171
185
|
input: {
|
|
172
186
|
did: blocklet.meta.did,
|
|
173
187
|
configs: params
|
|
@@ -191,7 +205,7 @@ function BlockletEnvironment({
|
|
|
191
205
|
} = e.target;
|
|
192
206
|
const {
|
|
193
207
|
blocklet: data
|
|
194
|
-
} = await
|
|
208
|
+
} = await api.configBlocklet({
|
|
195
209
|
input: {
|
|
196
210
|
did: blocklet.meta.did,
|
|
197
211
|
configs: [{
|
|
@@ -216,7 +230,7 @@ function BlockletEnvironment({
|
|
|
216
230
|
try {
|
|
217
231
|
setLoading(true);
|
|
218
232
|
const corsAllowedOrigins = newValue.length ? newValue : ['__none__'];
|
|
219
|
-
await
|
|
233
|
+
await api.updateRoutingSite({
|
|
220
234
|
input: {
|
|
221
235
|
id: site.id,
|
|
222
236
|
corsAllowedOrigins,
|
|
@@ -239,7 +253,7 @@ function BlockletEnvironment({
|
|
|
239
253
|
try {
|
|
240
254
|
const {
|
|
241
255
|
blocklet: data
|
|
242
|
-
} = await
|
|
256
|
+
} = await api.configBlocklet({
|
|
243
257
|
input: {
|
|
244
258
|
did: blocklet.meta.did,
|
|
245
259
|
configs: [{
|
|
@@ -255,6 +269,11 @@ function BlockletEnvironment({
|
|
|
255
269
|
setLoading(false);
|
|
256
270
|
}
|
|
257
271
|
};
|
|
272
|
+
const uploaderStyle = {
|
|
273
|
+
'&::after': {
|
|
274
|
+
content: `"${t('common.switch')}"`
|
|
275
|
+
}
|
|
276
|
+
};
|
|
258
277
|
return /*#__PURE__*/_jsxs(Div, {
|
|
259
278
|
...rest,
|
|
260
279
|
children: [configurableEnvs.map(item => /*#__PURE__*/_jsxs(Box, {
|
|
@@ -275,6 +294,95 @@ function BlockletEnvironment({
|
|
|
275
294
|
onSubmit: value => onSubmitConfig(item.key, value)
|
|
276
295
|
})]
|
|
277
296
|
})), /*#__PURE__*/_jsx(Box, {
|
|
297
|
+
className: "config-form",
|
|
298
|
+
component: Divider,
|
|
299
|
+
my: 3
|
|
300
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
301
|
+
className: "config-label",
|
|
302
|
+
fontSize: 14,
|
|
303
|
+
mb: 1,
|
|
304
|
+
sx: {
|
|
305
|
+
flexGrow: 0,
|
|
306
|
+
width: 'auto'
|
|
307
|
+
},
|
|
308
|
+
children: t('blocklet.config.logoSquare')
|
|
309
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
310
|
+
className: classnames('uploader-wrapper', hasPermission && 'enabled'),
|
|
311
|
+
sx: uploaderStyle,
|
|
312
|
+
onClick: () => openUploader(uploadLogoPrefix),
|
|
313
|
+
children: /*#__PURE__*/_jsx(Avatar, {
|
|
314
|
+
sx: {
|
|
315
|
+
height: 80,
|
|
316
|
+
width: 80
|
|
317
|
+
},
|
|
318
|
+
variant: "square",
|
|
319
|
+
alt: "Blocklet Logo",
|
|
320
|
+
src: logoUrl
|
|
321
|
+
})
|
|
322
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
323
|
+
className: "config-label",
|
|
324
|
+
fontSize: 14,
|
|
325
|
+
mt: 4,
|
|
326
|
+
children: t('blocklet.config.logoRect')
|
|
327
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
328
|
+
mb: 1.5,
|
|
329
|
+
className: "config-desc",
|
|
330
|
+
children: t('blocklet.config.logoRectDesc')
|
|
331
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
332
|
+
className: classnames('uploader-wrapper', hasPermission && 'enabled'),
|
|
333
|
+
sx: uploaderStyle,
|
|
334
|
+
onClick: () => openUploader(uploadLogoRectPrefix),
|
|
335
|
+
children: /*#__PURE__*/_jsx("img", {
|
|
336
|
+
alt: "Blocklet Rect Logo",
|
|
337
|
+
src: rectLogoUrl,
|
|
338
|
+
style: {
|
|
339
|
+
height: '80px'
|
|
340
|
+
}
|
|
341
|
+
})
|
|
342
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
343
|
+
className: "config-label",
|
|
344
|
+
fontSize: 14,
|
|
345
|
+
mt: 4,
|
|
346
|
+
children: t('blocklet.config.logoFavicon')
|
|
347
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
348
|
+
mb: 1.5,
|
|
349
|
+
className: "config-desc",
|
|
350
|
+
children: t('blocklet.config.logoFaviconDesc')
|
|
351
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
352
|
+
sx: {
|
|
353
|
+
display: 'inline-flex',
|
|
354
|
+
cursor: hasPermission ? 'pointer' : 'default'
|
|
355
|
+
},
|
|
356
|
+
onClick: () => openUploader(uploadLogoFaviconPrefix),
|
|
357
|
+
children: /*#__PURE__*/_jsx(Avatar, {
|
|
358
|
+
variant: "square",
|
|
359
|
+
sx: {
|
|
360
|
+
width: 20,
|
|
361
|
+
height: 20
|
|
362
|
+
},
|
|
363
|
+
alt: "Blocklet Favicon Logo",
|
|
364
|
+
src: faviconUrl
|
|
365
|
+
})
|
|
366
|
+
}), /*#__PURE__*/_jsx(UploaderComponent, {
|
|
367
|
+
id: "\u200Buploader-logo",
|
|
368
|
+
ref: uploaderLogoRef,
|
|
369
|
+
popup: true,
|
|
370
|
+
onUploadFinish: () => {
|
|
371
|
+
uploaderLogoRef.current.close();
|
|
372
|
+
},
|
|
373
|
+
plugins: [],
|
|
374
|
+
apiPathProps: apiPathProps,
|
|
375
|
+
coreProps: {
|
|
376
|
+
restrictions: {
|
|
377
|
+
allowedFileTypes: ['image/*', '.jpg', '.jpeg', '.png', '.gif', '.svg'],
|
|
378
|
+
maxFileSize: 1024 * 1024 * 10,
|
|
379
|
+
maxNumberOfFiles: 1
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
tusProps: {
|
|
383
|
+
headers: getSessionInHeader
|
|
384
|
+
}
|
|
385
|
+
}, "uploader-logo"), /*#__PURE__*/_jsx(Box, {
|
|
278
386
|
className: "config-form",
|
|
279
387
|
children: whoCanAccess === 'all' && blocklet.source === 'registry' && /*#__PURE__*/_jsxs(Box, {
|
|
280
388
|
className: "config-item",
|
|
@@ -485,7 +593,6 @@ const Div = styled.div`
|
|
|
485
593
|
flex-shrink: 0;
|
|
486
594
|
padding: 0 24px;
|
|
487
595
|
transform: translate(0, 0);
|
|
488
|
-
max-height: 60vh;
|
|
489
596
|
}
|
|
490
597
|
}
|
|
491
598
|
|
|
@@ -509,4 +616,34 @@ const Div = styled.div`
|
|
|
509
616
|
.form-item {
|
|
510
617
|
margin-top: 0;
|
|
511
618
|
}
|
|
619
|
+
|
|
620
|
+
.uploader-wrapper {
|
|
621
|
+
display: inline-flex;
|
|
622
|
+
position: relative;
|
|
623
|
+
font-size: 0px;
|
|
624
|
+
&.enabled {
|
|
625
|
+
cursor: pointer;
|
|
626
|
+
}
|
|
627
|
+
&::after {
|
|
628
|
+
display: none;
|
|
629
|
+
}
|
|
630
|
+
&.enabled::after {
|
|
631
|
+
display: block;
|
|
632
|
+
opacity: 0;
|
|
633
|
+
position: absolute;
|
|
634
|
+
bottom: 0;
|
|
635
|
+
background: rgba(0, 0, 0, 0.2);
|
|
636
|
+
left: 0;
|
|
637
|
+
right: 0;
|
|
638
|
+
height: 2.2em;
|
|
639
|
+
color: white;
|
|
640
|
+
text-align: center;
|
|
641
|
+
font-size: 12px;
|
|
642
|
+
line-height: 2em;
|
|
643
|
+
transition: opacity 0.3s ease;
|
|
644
|
+
}
|
|
645
|
+
&:hover::after {
|
|
646
|
+
opacity: 1;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
512
649
|
`;
|
|
@@ -582,7 +582,7 @@ export default function CreateRelease({
|
|
|
582
582
|
maxNumberOfFiles: 1
|
|
583
583
|
}
|
|
584
584
|
}
|
|
585
|
-
}, "uploader-
|
|
585
|
+
}, "uploader-logo"), /*#__PURE__*/_jsx(UploaderComponent, {
|
|
586
586
|
id: "\u200Buploader-screenshot",
|
|
587
587
|
ref: uploaderScreenshotRef,
|
|
588
588
|
popup: true,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Typography } from '@mui/material';
|
|
3
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
4
|
+
import Toast from '@arcblock/ux/lib/Toast';
|
|
5
|
+
import SwitchControl from '../component/switch-control';
|
|
6
|
+
import { useBlockletStorageContext } from '../../contexts/blocklet-storage';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description
|
|
10
|
+
* @param {{
|
|
11
|
+
* style: import('react').CSSProperties
|
|
12
|
+
* }} {...rest}
|
|
13
|
+
* @return {*}
|
|
14
|
+
*/
|
|
15
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
16
|
+
function AutoBackup({
|
|
17
|
+
...rest
|
|
18
|
+
}) {
|
|
19
|
+
const {
|
|
20
|
+
t
|
|
21
|
+
} = useLocaleContext();
|
|
22
|
+
const {
|
|
23
|
+
autoBackup,
|
|
24
|
+
updateAutoBackup
|
|
25
|
+
} = useBlockletStorageContext();
|
|
26
|
+
const configAutoBackup = async () => {
|
|
27
|
+
try {
|
|
28
|
+
const enabled = !autoBackup.enabled;
|
|
29
|
+
await updateAutoBackup({
|
|
30
|
+
enabled
|
|
31
|
+
});
|
|
32
|
+
Toast.success(enabled ? t('storage.spaces.autoBackup.enabled') : t('storage.spaces.autoBackup.disabled'));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
Toast.error(error.message);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
return /*#__PURE__*/_jsx(SwitchControl, {
|
|
38
|
+
checked: Boolean(autoBackup?.enabled),
|
|
39
|
+
onChange: configAutoBackup,
|
|
40
|
+
name: "enableWelcomePage",
|
|
41
|
+
labelProps: {
|
|
42
|
+
label: /*#__PURE__*/_jsx(Typography, {
|
|
43
|
+
marginRight: "8px",
|
|
44
|
+
children: /*#__PURE__*/_jsx("span", {
|
|
45
|
+
children: t('storage.spaces.autoBackup.title')
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
},
|
|
49
|
+
style: {
|
|
50
|
+
...rest.style
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
AutoBackup.propTypes = {};
|
|
55
|
+
export default AutoBackup;
|
|
@@ -9,6 +9,7 @@ import { useBlockletContext } from '../../contexts/blocklet';
|
|
|
9
9
|
import { useNodeContext } from '../../contexts/node';
|
|
10
10
|
import DiskInfo from '../disk-info';
|
|
11
11
|
import { useBlockletStorageContext } from '../../contexts/blocklet-storage';
|
|
12
|
+
import AutoBackup from './auto-backup';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* @typedef {{
|
|
@@ -72,7 +73,12 @@ function Connected() {
|
|
|
72
73
|
children: [/*#__PURE__*/_jsx(Typography, {
|
|
73
74
|
fontSize: "1.2rem",
|
|
74
75
|
fontWeight: "bold",
|
|
76
|
+
flexGrow: 1,
|
|
75
77
|
children: t('storage.spaces.connected.title')
|
|
78
|
+
}), /*#__PURE__*/_jsx(AutoBackup, {
|
|
79
|
+
style: {
|
|
80
|
+
marginRight: '32px'
|
|
81
|
+
}
|
|
76
82
|
}), /*#__PURE__*/_jsx(ConnectTo, {})]
|
|
77
83
|
}), /*#__PURE__*/_jsx(Box, {
|
|
78
84
|
children: shouldShowLoading ? /*#__PURE__*/_jsx(Box, {
|
|
@@ -9,10 +9,12 @@ import useSpaceGateways from '../hooks/use-space-gateways';
|
|
|
9
9
|
import { useNodeContext } from './node';
|
|
10
10
|
import useBackupProgress from '../hooks/use-backup-progress';
|
|
11
11
|
import useBackups from '../hooks/use-backups';
|
|
12
|
+
import { useAutoBackup } from '../hooks/use-auto-backup';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* @typedef {import('../blocklet/storage/connected').SpaceGateway} SpaceGateway
|
|
15
16
|
* @typedef {import('@abtnode/client').Backup} Backup
|
|
17
|
+
* @typedef {import('@abtnode/client').AutoBackup} AutoBackup
|
|
16
18
|
*/
|
|
17
19
|
|
|
18
20
|
/**
|
|
@@ -25,12 +27,14 @@ import useBackups from '../hooks/use-backups';
|
|
|
25
27
|
* refreshSpaceGateways: () => void,
|
|
26
28
|
* spaceGatewaysLoading: boolean,
|
|
27
29
|
* spaceGatewayIsSelected: (spaceGateway: SpaceGateway) => boolean,
|
|
30
|
+
* updateAutoBackup: (autoBackup: { enabled: boolean }) => Promise<void>,
|
|
28
31
|
*
|
|
29
32
|
* backupEndpoint: string,
|
|
30
33
|
* backupProgress: any,
|
|
31
34
|
* backups: Backup[],
|
|
32
35
|
* backupsLoading: boolean,
|
|
33
36
|
* refreshBackupEndpoint: () => void,
|
|
37
|
+
* autoBackup: AutoBackup,
|
|
34
38
|
* }} BlockletStorageContextType
|
|
35
39
|
*/
|
|
36
40
|
|
|
@@ -78,6 +82,10 @@ function BlockletStorageProvider({
|
|
|
78
82
|
setLoading: setBackupsLoading
|
|
79
83
|
});
|
|
80
84
|
const [selectedSpaceGateway, setSelectedSpaceGateway] = useState(spaceGateways?.find(x => x.endpoint === backupEndpoint));
|
|
85
|
+
const [autoBackupRefresh, setAutoBackupRefresh] = useState(false);
|
|
86
|
+
const autoBackup = useAutoBackup({
|
|
87
|
+
deps: [autoBackupRefresh]
|
|
88
|
+
});
|
|
81
89
|
|
|
82
90
|
/**
|
|
83
91
|
* @description
|
|
@@ -172,9 +180,26 @@ function BlockletStorageProvider({
|
|
|
172
180
|
* @param {SpaceGateway} spaceGateway
|
|
173
181
|
*/
|
|
174
182
|
const spaceGatewayIsSelected = spaceGateway => spaceGateway?.endpoint === backupEndpoint;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @description
|
|
186
|
+
* @param {AutoBackup} value
|
|
187
|
+
*/
|
|
188
|
+
const updateAutoBackup = async value => {
|
|
189
|
+
await api.updateAutoBackup({
|
|
190
|
+
input: {
|
|
191
|
+
did: blocklet.meta.did,
|
|
192
|
+
autoBackup: value
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
refreshAutoBackup();
|
|
196
|
+
};
|
|
175
197
|
const refreshBackupEndpoint = () => {
|
|
176
198
|
setBackupEndpointRefresh(p => !p);
|
|
177
199
|
};
|
|
200
|
+
const refreshAutoBackup = () => {
|
|
201
|
+
setAutoBackupRefresh(x => !x);
|
|
202
|
+
};
|
|
178
203
|
return /*#__PURE__*/_jsx(Provider, {
|
|
179
204
|
value: {
|
|
180
205
|
spaceGateways,
|
|
@@ -185,11 +210,13 @@ function BlockletStorageProvider({
|
|
|
185
210
|
refreshSpaceGateways,
|
|
186
211
|
spaceGatewaysLoading,
|
|
187
212
|
spaceGatewayIsSelected,
|
|
213
|
+
updateAutoBackup,
|
|
188
214
|
backupEndpoint,
|
|
189
215
|
backupProgress,
|
|
190
216
|
backups,
|
|
191
217
|
backupsLoading,
|
|
192
|
-
refreshBackupEndpoint
|
|
218
|
+
refreshBackupEndpoint,
|
|
219
|
+
autoBackup
|
|
193
220
|
},
|
|
194
221
|
children: children
|
|
195
222
|
});
|
package/es/hooks/use-app-logo.js
CHANGED
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
import joinUrl from 'url-join';
|
|
2
|
+
import { BLOCKLET_CONFIGURABLE_KEY } from '@blocklet/constant';
|
|
2
3
|
import { useNodeContext } from '../contexts/node';
|
|
3
|
-
import { isInstalling } from '../util';
|
|
4
|
+
import { isInstalling, getLogoHash } from '../util';
|
|
5
|
+
const getSearch = (blocklet, customLogo) => {
|
|
6
|
+
let search = '?v=';
|
|
7
|
+
if (customLogo) {
|
|
8
|
+
search += getLogoHash(customLogo);
|
|
9
|
+
} else {
|
|
10
|
+
search += `${blocklet?.meta?.version}${isInstalling(blocklet?.status) ? '~' : ''}`;
|
|
11
|
+
}
|
|
12
|
+
return search;
|
|
13
|
+
};
|
|
4
14
|
export default function useAppLogo({
|
|
5
15
|
blocklet
|
|
6
16
|
}) {
|
|
7
17
|
const {
|
|
8
18
|
inService
|
|
9
19
|
} = useNodeContext();
|
|
20
|
+
const customLogo = (blocklet?.environments || []).find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_SQUARE)?.value;
|
|
21
|
+
const customRectLogo = (blocklet?.environments || []).find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_RECT)?.value;
|
|
22
|
+
const customFavicon = (blocklet?.environments || []).find(x => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_FAVICON)?.value;
|
|
10
23
|
const prefix = window.env?.apiPrefix || '/';
|
|
11
|
-
const
|
|
12
|
-
const
|
|
24
|
+
const logoUrl = joinUrl(prefix, `/blocklet/logo/${inService ? '' : blocklet.meta.did}`, getSearch(blocklet, customLogo));
|
|
25
|
+
const rectLogoUrl = joinUrl(prefix, `/blocklet/logo-rect/${inService ? '' : blocklet.meta.did}`, getSearch(blocklet, customRectLogo));
|
|
26
|
+
const faviconUrl = joinUrl(prefix, `/blocklet/logo-favicon/${inService ? '' : blocklet.meta.did}`, getSearch(blocklet, customFavicon));
|
|
13
27
|
return {
|
|
14
|
-
logoUrl
|
|
28
|
+
logoUrl,
|
|
29
|
+
rectLogoUrl,
|
|
30
|
+
faviconUrl
|
|
15
31
|
};
|
|
16
32
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export */
|
|
2
|
+
import { useAsyncEffect } from 'ahooks';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { useBlockletContext } from '../contexts/blocklet';
|
|
5
|
+
import { useNodeContext } from '../contexts/node';
|
|
6
|
+
export function useAutoBackup({
|
|
7
|
+
deps
|
|
8
|
+
} = {
|
|
9
|
+
deps: []
|
|
10
|
+
}) {
|
|
11
|
+
/** @type {{ blocklet: import('@abtnode/client').BlockletState }} */
|
|
12
|
+
const {
|
|
13
|
+
blocklet
|
|
14
|
+
} = useBlockletContext();
|
|
15
|
+
/** @type {{api: import('@abtnode/client')}} */
|
|
16
|
+
const {
|
|
17
|
+
api
|
|
18
|
+
} = useNodeContext();
|
|
19
|
+
const [autoBackup, setAutoBackup] = useState(null);
|
|
20
|
+
useAsyncEffect(async () => {
|
|
21
|
+
if (blocklet?.meta?.did) {
|
|
22
|
+
const {
|
|
23
|
+
autoBackup: data
|
|
24
|
+
} = await api.getAutoBackup({
|
|
25
|
+
input: {
|
|
26
|
+
did: blocklet.meta.did
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
setAutoBackup(data);
|
|
30
|
+
}
|
|
31
|
+
}, [blocklet?.meta?.did].concat(deps));
|
|
32
|
+
return autoBackup;
|
|
33
|
+
}
|
package/es/locales/en.js
CHANGED
|
@@ -278,6 +278,7 @@ module.exports = {
|
|
|
278
278
|
succeeded: 'Succeeded',
|
|
279
279
|
subscription: 'Subscription',
|
|
280
280
|
support: 'Support',
|
|
281
|
+
switch: 'Switch',
|
|
281
282
|
team: 'Team',
|
|
282
283
|
the: 'The',
|
|
283
284
|
timeAgo: '{time} ago',
|
|
@@ -391,10 +392,11 @@ module.exports = {
|
|
|
391
392
|
name: 'Blocklet Name',
|
|
392
393
|
description: 'Blocklet Description',
|
|
393
394
|
sk: 'Secret key for the blocklet wallet',
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
logoFavicon: '
|
|
395
|
+
logoSquare: 'App Logo',
|
|
396
|
+
logoRect: 'Rect logo',
|
|
397
|
+
logoRectDesc: 'Usually displayed at the top of the page, default to app logo',
|
|
398
|
+
logoFavicon: 'Favicon',
|
|
399
|
+
logoFaviconDesc: "Usually displayed in the browser's address bar or tab page, default to app logo",
|
|
398
400
|
clusterSize: 'Instance count when run this blocklet in cluster mode',
|
|
399
401
|
copyrightOwner: 'Copyright Owner (Display in footer)',
|
|
400
402
|
copyrightYear: 'Copyright Year (Display in footer)',
|
|
@@ -1437,6 +1439,11 @@ module.exports = {
|
|
|
1437
1439
|
title: 'Backup',
|
|
1438
1440
|
records: 'Backup Records'
|
|
1439
1441
|
},
|
|
1442
|
+
autoBackup: {
|
|
1443
|
+
title: 'Auto backup',
|
|
1444
|
+
enabled: 'Automatic backup is on',
|
|
1445
|
+
disabled: 'Automatic backup is off'
|
|
1446
|
+
},
|
|
1440
1447
|
backupSuccessfully: 'Backup successfully',
|
|
1441
1448
|
restore: 'Restore',
|
|
1442
1449
|
restoreSuccessfully: 'Restore successfully',
|
package/es/locales/zh.js
CHANGED
|
@@ -283,6 +283,7 @@ module.exports = {
|
|
|
283
283
|
succeeded: '成功',
|
|
284
284
|
subscription: '订阅',
|
|
285
285
|
support: '服务支持',
|
|
286
|
+
switch: '切换',
|
|
286
287
|
team: '团队',
|
|
287
288
|
the: '此',
|
|
288
289
|
timeAgo: '{time}前',
|
|
@@ -395,10 +396,11 @@ module.exports = {
|
|
|
395
396
|
name: '应用名称',
|
|
396
397
|
description: '应用描述',
|
|
397
398
|
sk: '应用账户私钥',
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
logoFavicon: '
|
|
399
|
+
logoSquare: '应用 Logo',
|
|
400
|
+
logoRect: '横版 Logo',
|
|
401
|
+
logoRectDesc: '通常显示在页面顶部,默认和应用 Logo 相同',
|
|
402
|
+
logoFavicon: 'Favicon',
|
|
403
|
+
logoFaviconDesc: '通常显示在浏览器的地址栏或标签页中,默认和应用 Logo 相同',
|
|
402
404
|
clusterSize: '以 Cluster 模式启动时的实例数量',
|
|
403
405
|
copyrightOwner: '版权所有者 (展示在页脚中)',
|
|
404
406
|
copyrightYear: '版权年份 (展示在页脚中)',
|
|
@@ -1441,6 +1443,11 @@ module.exports = {
|
|
|
1441
1443
|
title: '备份',
|
|
1442
1444
|
records: '备份记录'
|
|
1443
1445
|
},
|
|
1446
|
+
autoBackup: {
|
|
1447
|
+
title: '自动备份',
|
|
1448
|
+
enabled: '自动备份已开启',
|
|
1449
|
+
disabled: '自动备份已关闭'
|
|
1450
|
+
},
|
|
1444
1451
|
backupSuccessfully: '备份成功',
|
|
1445
1452
|
restore: '还原',
|
|
1446
1453
|
restoreSuccessfully: '还原成功',
|
package/es/util/index.js
CHANGED
|
@@ -614,4 +614,5 @@ export const getSubscriptionURL = async ({
|
|
|
614
614
|
return joinUrl(baseUrl, `/${nftId}/subscription?locale=${locale}&return-url=${encodeURIComponent(window.location.href)}`);
|
|
615
615
|
};
|
|
616
616
|
export const nanoid = (length = 16) => [...Array(length)].map(() => Math.random().toString(36)[2]).join('');
|
|
617
|
-
export const getSystemDomains = domains => domains.filter(x => x.isProtected);
|
|
617
|
+
export const getSystemDomains = domains => domains.filter(x => x.isProtected);
|
|
618
|
+
export const getLogoHash = logo => encodeURIComponent((logo || '').split('/').slice(-1)[0].slice(0, 7));
|