@abtnode/ux 1.16.19-beta-710018ca → 1.16.19-beta-ba354e01

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.
Files changed (57) hide show
  1. package/es/blocklet/component/add-component-core.js +49 -36
  2. package/es/blocklet/component/button.js +12 -0
  3. package/es/blocklet/component/did-space/connect-to.js +355 -0
  4. package/es/blocklet/component/did-space/connected.js +42 -0
  5. package/es/blocklet/component/did-space/delete.js +104 -0
  6. package/es/blocklet/component/did-space/disconnect.js +230 -0
  7. package/es/blocklet/component/did-space/index.js +73 -0
  8. package/es/blocklet/component/did-space/item.js +233 -0
  9. package/es/blocklet/component/index.js +3 -3
  10. package/es/blocklet/component/step-actions.js +99 -0
  11. package/es/blocklet/publish/create-project.js +1 -1
  12. package/es/blocklet/publish/create-release.js +39 -20
  13. package/es/blocklet/publish/index.js +15 -2
  14. package/es/blocklet/publish/project-list.js +32 -1
  15. package/es/blocklet/publish/release-list.js +1 -0
  16. package/es/blocklet/publish/resource.js +2 -13
  17. package/es/blocklet/publish/tree.js +4 -0
  18. package/es/blocklet/resource-type.js +34 -0
  19. package/es/blocklet/storage/connect-to.js +11 -15
  20. package/es/contexts/config-space.js +160 -0
  21. package/es/hooks/use-mobile.js +17 -0
  22. package/es/hooks/use-storage-endpoint.js +23 -0
  23. package/es/images.js +48 -0
  24. package/es/locales/en.js +5 -0
  25. package/es/locales/zh.js +5 -0
  26. package/es/util/constants.js +2 -1
  27. package/es/util/index.js +5 -1
  28. package/es/util/spaces.js +66 -5
  29. package/lib/blocklet/component/add-component-core.js +59 -45
  30. package/lib/blocklet/component/button.js +23 -0
  31. package/lib/blocklet/component/did-space/connect-to.js +362 -0
  32. package/lib/blocklet/component/did-space/connected.js +49 -0
  33. package/lib/blocklet/component/did-space/delete.js +111 -0
  34. package/lib/blocklet/component/did-space/disconnect.js +241 -0
  35. package/lib/blocklet/component/did-space/index.js +82 -0
  36. package/lib/blocklet/component/did-space/item.js +197 -0
  37. package/lib/blocklet/component/index.js +3 -3
  38. package/lib/blocklet/component/step-actions.js +63 -0
  39. package/lib/blocklet/publish/create-project.js +1 -1
  40. package/lib/blocklet/publish/create-release.js +39 -19
  41. package/lib/blocklet/publish/index.js +18 -4
  42. package/lib/blocklet/publish/project-list.js +32 -1
  43. package/lib/blocklet/publish/release-list.js +1 -0
  44. package/lib/blocklet/publish/resource.js +1 -12
  45. package/lib/blocklet/publish/tree.js +45 -38
  46. package/lib/blocklet/resource-type.js +51 -0
  47. package/lib/blocklet/storage/connect-to.js +11 -15
  48. package/lib/contexts/config-space.js +169 -0
  49. package/lib/hooks/use-mobile.js +24 -0
  50. package/lib/hooks/use-storage-endpoint.js +28 -0
  51. package/lib/images.js +51 -0
  52. package/lib/locales/en.js +5 -0
  53. package/lib/locales/zh.js +5 -0
  54. package/lib/util/constants.js +4 -2
  55. package/lib/util/index.js +8 -2
  56. package/lib/util/spaces.js +69 -3
  57. package/package.json +11 -7
@@ -0,0 +1,99 @@
1
+ import styled from '@emotion/styled';
2
+ import PropTypes from 'prop-types';
3
+ import Box from '@mui/material/Box';
4
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
5
+ import Button from './button';
6
+ import useMobile from '../../hooks/use-mobile';
7
+ import { hasRequiredSteps } from '../../util';
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ import { jsxs as _jsxs } from "react/jsx-runtime";
10
+ export default function StepActions({
11
+ blocklet,
12
+ onStartNow,
13
+ children,
14
+ disabled
15
+ }) {
16
+ const {
17
+ t
18
+ } = useLocaleContext();
19
+ const isMobile = useMobile();
20
+ if (!blocklet || hasRequiredSteps(blocklet.meta)) {
21
+ return /*#__PURE__*/_jsx(Center, {
22
+ children: children
23
+ });
24
+ }
25
+ return /*#__PURE__*/_jsxs(Between, {
26
+ isMobile: isMobile,
27
+ children: [/*#__PURE__*/_jsx(Button, {
28
+ className: "start-now",
29
+ variant: "contained",
30
+ color: "primary",
31
+ disabled: disabled,
32
+ onClick: () => onStartNow(),
33
+ children: t('setup.startNow')
34
+ }), /*#__PURE__*/_jsx(Box, {
35
+ display: "flex",
36
+ alignItems: "center",
37
+ children: children
38
+ })]
39
+ });
40
+ }
41
+ StepActions.propTypes = {
42
+ blocklet: PropTypes.object,
43
+ onStartNow: PropTypes.func,
44
+ children: PropTypes.any,
45
+ disabled: PropTypes.bool
46
+ };
47
+ StepActions.defaultProps = {
48
+ blocklet: null,
49
+ onStartNow: () => {},
50
+ children: null,
51
+ disabled: false
52
+ };
53
+ const Center = styled(Box)`
54
+ width: 100%;
55
+ margin-top: auto;
56
+ padding-top: 24px;
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ .bottom-button {
61
+ min-width: 200px;
62
+ }
63
+ ${props => props.theme.breakpoints.down('md')} {
64
+ .bottom-button {
65
+ width: 100%;
66
+ }
67
+ }
68
+ `;
69
+ const Between = styled(Box)`
70
+ padding-top: 24px;
71
+ margin-top: auto;
72
+ width: 100%;
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: space-between;
76
+ .start-now {
77
+ min-width: 140px;
78
+ }
79
+ .bottom-button {
80
+ min-width: 120px;
81
+ }
82
+ ${props => props.theme.breakpoints.down('lg')} {
83
+ width: 100%;
84
+ }
85
+
86
+ ${props => props.theme.breakpoints.down('md')} {
87
+ .start-now {
88
+ min-width: inherit;
89
+ }
90
+ .bottom-button {
91
+ min-width: 100px;
92
+ }
93
+ }
94
+
95
+ ${props => props.isMobile} {
96
+ justify-content: space-between;
97
+ gap: '32px',
98
+ }}
99
+ `;
@@ -53,7 +53,7 @@ export default function CreateProject({
53
53
  const [blockletDid, setBlockletDid] = useState();
54
54
  const [openConnect, setOpenConnect] = useState(false);
55
55
  const {
56
- componentDid
56
+ componentDid = ''
57
57
  } = useParams();
58
58
  const handleCreateBlockletDidError = err => {
59
59
  Toast.error(err.message);
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, lazy, useRef } from 'react';
1
+ import { useState, useEffect, lazy, useRef, useCallback } from 'react';
2
2
  import { Link, useNavigate, useParams } from 'react-router-dom';
3
3
  import styled from '@emotion/styled';
4
4
  import useSetState from 'react-use/lib/useSetState';
@@ -13,6 +13,7 @@ import Box from '@mui/material/Box';
13
13
  import IconButton from '@mui/material/IconButton';
14
14
  import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
15
15
  import InputAdornment from '@mui/material/InputAdornment';
16
+ import Spinner from '@mui/material/CircularProgress';
16
17
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
17
18
  import Button from '@arcblock/ux/lib/Button';
18
19
  import Toast from '@arcblock/ux/lib/Toast';
@@ -120,6 +121,7 @@ export default function CreateRelease({
120
121
  const [params, setParams] = useSetState(null);
121
122
  const [paramsErrTip, setParamsErrTip] = useState({});
122
123
  const [loading, setLoading] = useState(false);
124
+ const [createLoading, setCreateLoading] = useState(false);
123
125
  const [release, setRelease] = useState(null);
124
126
  const {
125
127
  api
@@ -177,7 +179,7 @@ export default function CreateRelease({
177
179
  Toast.error(formatError(err));
178
180
  });
179
181
  };
180
- const getData = () => {
182
+ const getData = useCallback(() => {
181
183
  if (mode === 'edit') {
182
184
  if (!releaseId) {
183
185
  Toast.error('Empty release id');
@@ -188,11 +190,11 @@ export default function CreateRelease({
188
190
  if (mode === 'create') {
189
191
  getProject();
190
192
  }
191
- };
193
+ // eslint-disable-next-line react-hooks/exhaustive-deps
194
+ }, [mode, releaseId]);
192
195
  useEffect(() => {
193
196
  getData();
194
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
195
-
197
+ }, [getData]);
196
198
  const onRelease = status => {
197
199
  const errors = validateParams(params, status, t);
198
200
  if (errors) {
@@ -218,6 +220,8 @@ export default function CreateRelease({
218
220
  _params.blockletDescription = (_params.blockletDescription || '').trim();
219
221
  _params.blockletIntroduction = (_params.blockletIntroduction || '').trim();
220
222
  _params.note = (_params.note || '').trim();
223
+ setCreateLoading(status);
224
+ setLoading(true);
221
225
  api.createRelease({
222
226
  input: {
223
227
  ..._params,
@@ -226,21 +230,25 @@ export default function CreateRelease({
226
230
  releaseId,
227
231
  status
228
232
  }
229
- }).then(() => {
233
+ }).then(res => {
234
+ setCreateLoading(false);
235
+ setLoading(false);
230
236
  if (status === 'draft') {
231
- Toast.success('Save draft success');
232
- if (mode === 'create') {
233
- navigate(`../${projectId}`, {
234
- replace: true
235
- });
236
- }
237
+ Toast.success(t('blocklet.publish.saveDraftSuccess'));
237
238
  } else {
238
- Toast.success('Create Release success');
239
- navigate(`../${projectId}`, {
239
+ Toast.success(t('blocklet.publish.createReleaseSuccess'));
240
+ }
241
+ if (mode === 'create') {
242
+ const id = res?.release?.id;
243
+ navigate(`../${projectId}/${id}`, {
240
244
  replace: true
241
245
  });
246
+ } else {
247
+ getRelease();
242
248
  }
243
249
  }).catch(err => {
250
+ setCreateLoading(false);
251
+ setLoading(false);
244
252
  Toast.error(formatError(err));
245
253
  });
246
254
  };
@@ -295,19 +303,30 @@ export default function CreateRelease({
295
303
  }), /*#__PURE__*/_jsxs(Box, {
296
304
  display: "flex",
297
305
  children: [!isPublished && /*#__PURE__*/_jsxs(_Fragment, {
298
- children: [/*#__PURE__*/_jsx(Button, {
306
+ children: [/*#__PURE__*/_jsxs(Button, {
299
307
  variant: "outlined",
300
- disabled: loading,
308
+ disabled: loading || createLoading,
301
309
  onClick: () => onRelease(PROJECT.RELEASE_STATUS.draft),
302
310
  style: {
303
311
  marginRight: 12
304
312
  },
305
- children: t('blocklet.publish.saveDraft')
306
- }), /*#__PURE__*/_jsx(Button, {
313
+ children: [createLoading === PROJECT.RELEASE_STATUS.draft && /*#__PURE__*/_jsx(Spinner, {
314
+ size: 14,
315
+ sx: {
316
+ mr: 0.5
317
+ }
318
+ }), t('blocklet.publish.saveDraft')]
319
+ }), /*#__PURE__*/_jsxs(Button, {
307
320
  variant: "contained",
308
- disabled: loading,
321
+ disabled: loading || createLoading,
309
322
  onClick: () => onRelease(PROJECT.RELEASE_STATUS.published),
310
- children: t('common.release')
323
+ children: [createLoading === PROJECT.RELEASE_STATUS.published && /*#__PURE__*/_jsx(Spinner, {
324
+ size: 14,
325
+ sx: {
326
+ mr: 0.5
327
+ },
328
+ color: "inherit"
329
+ }), t('common.release')]
311
330
  })]
312
331
  }), isPublished && /*#__PURE__*/_jsx(Button, {
313
332
  variant: "contained",
@@ -1,4 +1,5 @@
1
1
  import React, { useEffect } from 'react';
2
+ import PropTypes from 'prop-types';
2
3
  import { Routes, Route, useLocation, useParams } from 'react-router-dom';
3
4
  import styled from '@emotion/styled';
4
5
  import Box from '@mui/material/Box';
@@ -9,7 +10,9 @@ import ReleasesList from './release-list';
9
10
  import CreateRelease from './create-release';
10
11
  import { jsx as _jsx } from "react/jsx-runtime";
11
12
  import { jsxs as _jsxs } from "react/jsx-runtime";
12
- export default function BlockletPublish() {
13
+ export default function BlockletPublish({
14
+ padding
15
+ }) {
13
16
  const {
14
17
  blocklet
15
18
  } = useBlockletContext();
@@ -33,7 +36,12 @@ export default function BlockletPublish() {
33
36
  if (!blocklet) {
34
37
  return null;
35
38
  }
39
+ const style = {};
40
+ if (padding) {
41
+ style.padding = padding;
42
+ }
36
43
  return /*#__PURE__*/_jsx(Main, {
44
+ style: style,
37
45
  children: /*#__PURE__*/_jsxs(Routes, {
38
46
  children: [/*#__PURE__*/_jsx(Route, {
39
47
  path: "/",
@@ -51,7 +59,12 @@ export default function BlockletPublish() {
51
59
  })
52
60
  });
53
61
  }
54
- BlockletPublish.propTypes = {};
62
+ BlockletPublish.propTypes = {
63
+ padding: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
64
+ };
65
+ BlockletPublish.defaultProps = {
66
+ padding: ''
67
+ };
55
68
  const Main = styled(Box)`
56
69
  a {
57
70
  color: ${({
@@ -16,6 +16,7 @@ import { useNodeContext } from '../../contexts/node';
16
16
  import EmptySpinner from '../../empty-spinner';
17
17
  import DidAddress from '../../did-address';
18
18
  import Confirm from '../../confirm';
19
+ import BlockletBundleAvatar from '../bundle-avatar';
19
20
  import { jsx as _jsx } from "react/jsx-runtime";
20
21
  import { jsxs as _jsxs } from "react/jsx-runtime";
21
22
  export default function ProjectList() {
@@ -65,6 +66,7 @@ export default function ProjectList() {
65
66
  setLoading(false);
66
67
  getProjects();
67
68
  Toast.success(t('common.removeSuccess'));
69
+ setDeleteConfirm(null);
68
70
  }).catch(err => {
69
71
  setLoading(false);
70
72
  Toast.error(err.message);
@@ -144,6 +146,35 @@ export default function ProjectList() {
144
146
  }) : '';
145
147
  }
146
148
  }
149
+ }, componentDid ? null : {
150
+ label: t('common.scope'),
151
+ name: 'componentDid',
152
+ options: {
153
+ customBodyRender: value => {
154
+ const component = (blocklet.children || []).find(x => x.meta.did === value);
155
+ if (!component) {
156
+ return '';
157
+ }
158
+ return /*#__PURE__*/_jsxs(Box, {
159
+ display: "flex",
160
+ alignItems: "center",
161
+ justifyContent: "flex-start",
162
+ children: [/*#__PURE__*/_jsx(BlockletBundleAvatar, {
163
+ size: 14,
164
+ blocklet: component,
165
+ ancestors: [blocklet]
166
+ }), /*#__PURE__*/_jsx(Box, {
167
+ ml: 0.5,
168
+ sx: {
169
+ ml: 0.5,
170
+ color: 'text.primary',
171
+ fontSize: 14
172
+ },
173
+ children: component.meta.title
174
+ })]
175
+ }, value);
176
+ }
177
+ }
147
178
  }, {
148
179
  label: t('common.updatedAt'),
149
180
  name: 'updatedAt',
@@ -176,7 +207,7 @@ export default function ProjectList() {
176
207
  });
177
208
  }
178
209
  }
179
- }];
210
+ }].filter(Boolean);
180
211
  return /*#__PURE__*/_jsxs(Main, {
181
212
  children: [/*#__PURE__*/_jsx(Box, {
182
213
  sx: {
@@ -98,6 +98,7 @@ export default function ReleaseList() {
98
98
  setLoading(false);
99
99
  getReleases();
100
100
  Toast.success(t('common.removeSuccess'));
101
+ setDeleteConfirm(null);
101
102
  }).catch(err => {
102
103
  setLoading(false);
103
104
  Toast.error(err.message);
@@ -1,7 +1,6 @@
1
- import { useState, useEffect, useMemo } from 'react';
1
+ import { useState, useEffect } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import styled from '@emotion/styled';
4
- import difference from 'lodash/difference';
5
4
  import joinUrl from 'url-join';
6
5
  import Box from '@mui/material/Box';
7
6
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
@@ -24,12 +23,6 @@ const fillParent = (nodes, parentId) => {
24
23
  });
25
24
  return nodes;
26
25
  };
27
- const checkDiff = (a, b) => {
28
- if (a.length !== b.length) {
29
- return true;
30
- }
31
- return !!difference(a, b || []).length;
32
- };
33
26
  export default function Resource({
34
27
  app,
35
28
  component,
@@ -45,14 +38,12 @@ export default function Resource({
45
38
  } = useNodeContext();
46
39
  const [resources, setResources] = useState([]);
47
40
  const [selectedResourceIds, setSelectedResourceIds] = useState([]);
48
- const [savedResourceIds, setSavedResourceIds] = useState([]);
49
41
  const [loading, setLoading] = useState(false);
50
42
  const releaseId = release.id;
51
43
  const readonly = release.status === 'published';
52
44
  const {
53
45
  resourceExportApi = '/'
54
46
  } = component?.meta.capabilities || {};
55
- const hasDiff = useMemo(() => checkDiff(savedResourceIds, selectedResourceIds), [savedResourceIds, selectedResourceIds]);
56
47
  const urlObj = new URL(joinUrl('http://127.0.0.1', component.mountPoint, resourceExportApi || '/').replace(/\/+/g, '/'));
57
48
  urlObj.searchParams.set('projectId', projectId);
58
49
  urlObj.searchParams.set('releaseId', releaseId);
@@ -69,7 +60,6 @@ export default function Resource({
69
60
  resources: data
70
61
  }
71
62
  });
72
- setSavedResourceIds(data);
73
63
  } catch (err) {
74
64
  Toast.error(err.message);
75
65
  }
@@ -109,7 +99,6 @@ export default function Resource({
109
99
  }).then(res => {
110
100
  const list = res?.resources || [];
111
101
  setSelectedResourceIds(list);
112
- setSavedResourceIds(list);
113
102
  }).catch(err => {
114
103
  Toast.error(err.message);
115
104
  });
@@ -138,7 +127,7 @@ export default function Resource({
138
127
  className: "footer",
139
128
  children: /*#__PURE__*/_jsx(Button, {
140
129
  variant: "contained",
141
- disabled: loading || !hasDiff,
130
+ disabled: loading,
142
131
  onClick: () => onSave(),
143
132
  children: t('common.save')
144
133
  })
@@ -11,6 +11,7 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
11
11
  import ChevronRightIcon from '@mui/icons-material/ChevronRight';
12
12
  import OpenInNewIcon from '@mui/icons-material/OpenInNew';
13
13
  import { Icon } from '@iconify/react';
14
+ import Images from '../../images';
14
15
 
15
16
  // BFS algorithm to find node by his ID
16
17
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -147,6 +148,9 @@ export default function Tree({
147
148
  }), !!node.description && /*#__PURE__*/_jsx(Box, {
148
149
  className: "description",
149
150
  children: node.description
151
+ }), !!node.images?.length && /*#__PURE__*/_jsx(Images, {
152
+ className: "images",
153
+ data: node.images
150
154
  })]
151
155
  })
152
156
  }),
@@ -0,0 +1,34 @@
1
+ import { useMemo } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import uniq from 'lodash/uniq';
4
+ import upperFirst from 'lodash/upperFirst';
5
+ import Box from '@mui/material/Box';
6
+ import Tag from '@arcblock/ux/lib/Tag';
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ export default function ResourceType({
9
+ blocklet,
10
+ ...rest
11
+ }) {
12
+ const types = useMemo(() => {
13
+ return uniq((blocklet?.meta?.resources || []).map(x => upperFirst(x.split('.').slice(-1)[0])).filter(Boolean));
14
+ }, [blocklet]);
15
+ const style = {
16
+ color: '#FFF',
17
+ backgroundColor: '#5B9BD5',
18
+ marginRight: '4px'
19
+ };
20
+ return /*#__PURE__*/_jsx(Box, {
21
+ display: "flex",
22
+ mr: "-4px",
23
+ ...rest,
24
+ children: types.map(x => /*#__PURE__*/_jsx(Tag, {
25
+ type: "custom",
26
+ style: style,
27
+ children: x
28
+ }, x))
29
+ });
30
+ }
31
+ ResourceType.propTypes = {
32
+ blocklet: PropTypes.object.isRequired
33
+ };
34
+ ResourceType.defaultProps = {};
@@ -14,7 +14,7 @@ import { axios } from '../../util/api';
14
14
  import { formatError, getWebWalletUrl } from '../../util';
15
15
  import { useNodeContext } from '../../contexts/node';
16
16
  import useBlockletInfoForConnectDIDSpaces from '../../hooks/use-blocklet-info-for-connect-did-spaces';
17
- import { extraDIDSpacesCoreUrl, getDIDSpaceDidFromEndpoint, isValidSpaceGatewayUrl } from '../../util/spaces';
17
+ import { extraDIDSpacesCoreUrl, getDIDSpaceDidFromEndpoint, getSpaceGatewayUrl, isValidSpaceGatewayUrl } from '../../util/spaces';
18
18
  import { useBlockletStorageContext } from '../../contexts/blocklet-storage';
19
19
  /**
20
20
  * @description
@@ -148,12 +148,8 @@ function ConnectTo({
148
148
  name,
149
149
  did
150
150
  }) => {
151
- let normalizeUrl = endpoint?.replace(/\/api\/.+/, '')?.trim()?.replace(/\/$/, '');
152
- if (!normalizeUrl.startsWith('http')) {
153
- // eslint-disable-next-line no-param-reassign
154
- normalizeUrl = `https://${normalizeUrl}`;
155
- }
156
- if (!(await isValidSpaceGatewayUrl(normalizeUrl))) {
151
+ const spaceGatewayUrl = await getSpaceGatewayUrl(endpoint);
152
+ if (!(await isValidSpaceGatewayUrl(spaceGatewayUrl))) {
157
153
  toast.error(t('storage.spaces.gateway.add.invalidUrl'));
158
154
  return;
159
155
  }
@@ -167,7 +163,7 @@ function ConnectTo({
167
163
  const spaceGateway = {
168
164
  name,
169
165
  did,
170
- url: normalizeUrl,
166
+ url: spaceGatewayUrl,
171
167
  endpoint
172
168
  };
173
169
  await addSpaceGateway(spaceGateway, endpoint);
@@ -193,19 +189,19 @@ function ConnectTo({
193
189
  const handleUseSpaceGatewayConnect = async () => {
194
190
  try {
195
191
  setLoading(true);
196
- const tempUrl = url.startsWith('http') ? url : `https://${url}`;
197
- const fullUrl = extraDIDSpacesCoreUrl(tempUrl);
198
- const spaceDid = new URL(tempUrl).searchParams.get('spaceDid');
199
- if (!(await isValidSpaceGatewayUrl(fullUrl))) {
192
+ const spaceGatewayUrl = await getSpaceGatewayUrl(url);
193
+ const didSpacesCoreUrl = extraDIDSpacesCoreUrl(spaceGatewayUrl);
194
+ const spaceDid = new URL(spaceGatewayUrl).searchParams.get('spaceDid');
195
+ if (!(await isValidSpaceGatewayUrl(didSpacesCoreUrl))) {
200
196
  throw new Error(t('storage.spaces.gateway.add.invalidUrl'));
201
197
  }
202
198
  setAuthorizeConnect(preValue => ({
203
199
  ...preValue,
204
200
  open: true,
205
- prefix: joinUrl(fullUrl, 'space/api/did'),
206
- baseUrl: new URL(fullUrl).origin,
201
+ prefix: joinUrl(didSpacesCoreUrl, 'space/api/did'),
202
+ baseUrl: new URL(didSpacesCoreUrl).origin,
207
203
  checkFn: axios.create({
208
- baseURL: joinUrl(fullUrl, 'space')
204
+ baseURL: joinUrl(didSpacesCoreUrl, 'space')
209
205
  }).get,
210
206
  extraParams: {
211
207
  appDid: blockletInfo.appDid,
@@ -0,0 +1,160 @@
1
+ import { createContext, useContext, useEffect, useState } from 'react';
2
+ import { node } from 'prop-types';
3
+ import { isEmpty, merge } from 'lodash';
4
+ import { BLOCKLET_CONFIGURABLE_KEY } from '@blocklet/constant';
5
+ import { useAsyncEffect } from 'ahooks';
6
+ import Toast from '@arcblock/ux/lib/Toast';
7
+ import { useNodeContext } from './node';
8
+ import { getSpaceGateway, getSpaceNameByEndpoint } from '../util/spaces';
9
+ import { useBlockletContext } from './blocklet';
10
+ import useStorageEndpoint from '../hooks/use-storage-endpoint';
11
+
12
+ /**
13
+ * @typedef {{
14
+ * did: string,
15
+ * url: string,
16
+ * name: string,
17
+ * endpoint: string,
18
+ * }} SpaceGateway
19
+ */
20
+
21
+ /**
22
+ * @typedef {{
23
+ * loading: boolean,
24
+ * spaceGateway: SpaceGateway,
25
+ * deleteSpaceGateway: (spaceGateway: SpaceGateway) => void | Promise<void>,
26
+ * updateSpaceGateway: (updateSpaceGateway: SpaceGateway) => void | Promise<void>,
27
+ * storageEndpoint: string,
28
+ * settingStorageEndpoint: (endpoint: string) => void | Promise<void>,
29
+ * hasStorageEndpoint: boolean,
30
+ * }} ConfigSpaceContextType
31
+ */
32
+
33
+ /** @type {import('react').Context<ConfigSpaceContextType>} */
34
+ import { jsx as _jsx } from "react/jsx-runtime";
35
+ const ConfigSpaceContext = /*#__PURE__*/createContext({});
36
+ const {
37
+ Provider,
38
+ Consumer
39
+ } = ConfigSpaceContext;
40
+
41
+ /**
42
+ * @description
43
+ * @param {{
44
+ * children: React.ReactNode,
45
+ * }} { children }
46
+ * @return {any}
47
+ */
48
+ function ConfigSpaceProvider({
49
+ children
50
+ }) {
51
+ const [loading, setLoading] = useState(false);
52
+ const [spaceGateway, setSpaceGateway] = useState(null);
53
+ /**
54
+ * @type {{
55
+ * blocklet: import('@abtnode/client').BlockletState,
56
+ * actions: { refreshBlocklet: Function }
57
+ * }}
58
+ */
59
+ const {
60
+ blocklet,
61
+ actions: {
62
+ refreshBlocklet
63
+ }
64
+ } = useBlockletContext();
65
+ const {
66
+ storageEndpoint
67
+ } = useStorageEndpoint();
68
+ const {
69
+ api: nodeApi
70
+ } = useNodeContext();
71
+ useAsyncEffect(async () => {
72
+ try {
73
+ setLoading(true);
74
+ if (isEmpty(storageEndpoint)) {
75
+ setSpaceGateway(null);
76
+ return;
77
+ }
78
+ const $spaceGateway = await getSpaceGateway(storageEndpoint);
79
+ setSpaceGateway($spaceGateway);
80
+ } catch (error) {
81
+ console.error(error);
82
+ Toast.error(error.message);
83
+ } finally {
84
+ setLoading(false);
85
+ }
86
+ }, [storageEndpoint]);
87
+
88
+ /**
89
+ * @description
90
+ * @param {SpaceGateway} spaceGateway
91
+ */
92
+ const deleteSpaceGateway = () => {
93
+ setSpaceGateway(null);
94
+ refreshBlocklet();
95
+ };
96
+
97
+ /**
98
+ * @description
99
+ * @param {SpaceGateway} x
100
+ */
101
+ const updateSpaceGateway = async x => {
102
+ setSpaceGateway(x);
103
+ // eslint-disable-next-line no-use-before-define
104
+ await settingStorageEndpoint(x.endpoint);
105
+ refreshBlocklet();
106
+ };
107
+
108
+ /**
109
+ * @description
110
+ * @param {string} endpoint
111
+ */
112
+ const settingStorageEndpoint = async endpoint => {
113
+ await nodeApi.configBlocklet({
114
+ input: {
115
+ did: [blocklet.meta.did],
116
+ configs: [{
117
+ key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SPACE_ENDPOINT,
118
+ value: endpoint
119
+ }]
120
+ }
121
+ });
122
+ refreshBlocklet();
123
+ };
124
+ useEffect(() => {
125
+ async function syncSpaceGateway() {
126
+ if (!spaceGateway) {
127
+ return;
128
+ }
129
+ const name = await getSpaceNameByEndpoint(spaceGateway.endpoint, spaceGateway.name);
130
+ const latestSpaceGateway = merge(spaceGateway, {
131
+ name
132
+ });
133
+ setSpaceGateway(latestSpaceGateway);
134
+ }
135
+ syncSpaceGateway();
136
+ // eslint-disable-next-line react-hooks/exhaustive-deps
137
+ }, []);
138
+ const hasStorageEndpoint = Boolean(storageEndpoint && spaceGateway);
139
+ return /*#__PURE__*/_jsx(Provider, {
140
+ value: {
141
+ loading,
142
+ spaceGateway,
143
+ deleteSpaceGateway,
144
+ updateSpaceGateway,
145
+ storageEndpoint,
146
+ settingStorageEndpoint,
147
+ hasStorageEndpoint
148
+ },
149
+ children: children
150
+ });
151
+ }
152
+ ConfigSpaceProvider.propTypes = {
153
+ children: node.isRequired
154
+ };
155
+ ConfigSpaceProvider.defaultProps = {};
156
+ function useConfigSpaceContext() {
157
+ const res = useContext(ConfigSpaceContext);
158
+ return res;
159
+ }
160
+ export { ConfigSpaceContext, ConfigSpaceProvider, Consumer as ConfigSpaceConsumer, useConfigSpaceContext };