@abtnode/ux 1.16.25-next-bc2f4c63 → 1.16.26-beta-e0056285

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 (85) hide show
  1. package/es/analytics/disk.js +8 -11
  2. package/es/analytics/memory.js +1 -2
  3. package/es/analytics/runtime.js +1 -2
  4. package/es/analytics/traffic.js +1 -2
  5. package/es/blocklet/actions.js +11 -1
  6. package/es/blocklet/component/add-component-core.js +8 -0
  7. package/es/blocklet/component/component-cell.js +2 -1
  8. package/es/blocklet/component/select-store.js +8 -4
  9. package/es/blocklet/disk-info.js +1 -1
  10. package/es/blocklet/icons.js +3 -1
  11. package/es/blocklet/overview.js +13 -7
  12. package/es/blocklet/publish/connect-store-list.js +62 -0
  13. package/es/blocklet/publish/create-release.js +192 -49
  14. package/es/blocklet/publish/index.js +0 -4
  15. package/es/blocklet/publish/project-list.js +133 -29
  16. package/es/blocklet/publish/release-list.js +19 -5
  17. package/es/blocklet/publish/resource.js +46 -34
  18. package/es/blocklet/publish/select-components.js +3 -3
  19. package/es/blocklet/router/rule-list.js +2 -1
  20. package/es/locales/ar.js +23 -10
  21. package/es/locales/de.js +22 -9
  22. package/es/locales/en.js +21 -10
  23. package/es/locales/es.js +22 -9
  24. package/es/locales/fr.js +22 -9
  25. package/es/locales/hi.js +22 -9
  26. package/es/locales/i18n.db +0 -0
  27. package/es/locales/id.js +23 -10
  28. package/es/locales/ja.js +23 -10
  29. package/es/locales/ko.js +23 -10
  30. package/es/locales/pt.js +22 -9
  31. package/es/locales/ru.js +22 -9
  32. package/es/locales/th.js +22 -9
  33. package/es/locales/vi.js +23 -10
  34. package/es/locales/zh-tw.js +22 -9
  35. package/es/locales/zh.js +27 -14
  36. package/es/store/add.js +1 -0
  37. package/es/store/delete.js +9 -4
  38. package/es/store/item.js +233 -36
  39. package/es/team/members/connections.js +2 -1
  40. package/es/team/members/member.js +2 -1
  41. package/es/util/index.js +8 -8
  42. package/lib/analytics/disk.js +7 -10
  43. package/lib/analytics/memory.js +5 -6
  44. package/lib/analytics/runtime.js +1 -2
  45. package/lib/analytics/traffic.js +2 -3
  46. package/lib/blocklet/actions.js +14 -2
  47. package/lib/blocklet/component/add-component-core.js +4 -1
  48. package/lib/blocklet/component/component-cell.js +2 -1
  49. package/lib/blocklet/component/select-store.js +8 -4
  50. package/lib/blocklet/disk-info.js +2 -2
  51. package/lib/blocklet/icons.js +3 -1
  52. package/lib/blocklet/overview.js +13 -7
  53. package/lib/blocklet/publish/connect-store-list.js +72 -0
  54. package/lib/blocklet/publish/create-release.js +194 -47
  55. package/lib/blocklet/publish/index.js +0 -4
  56. package/lib/blocklet/publish/project-list.js +133 -29
  57. package/lib/blocklet/publish/release-list.js +19 -5
  58. package/lib/blocklet/publish/resource.js +45 -33
  59. package/lib/blocklet/publish/select-components.js +3 -3
  60. package/lib/blocklet/router/rule-list.js +2 -1
  61. package/lib/locales/ar.js +23 -10
  62. package/lib/locales/de.js +22 -9
  63. package/lib/locales/en.js +21 -10
  64. package/lib/locales/es.js +22 -9
  65. package/lib/locales/fr.js +22 -9
  66. package/lib/locales/hi.js +22 -9
  67. package/lib/locales/i18n.db +0 -0
  68. package/lib/locales/id.js +23 -10
  69. package/lib/locales/ja.js +23 -10
  70. package/lib/locales/ko.js +23 -10
  71. package/lib/locales/pt.js +22 -9
  72. package/lib/locales/ru.js +22 -9
  73. package/lib/locales/th.js +22 -9
  74. package/lib/locales/vi.js +23 -10
  75. package/lib/locales/zh-tw.js +22 -9
  76. package/lib/locales/zh.js +27 -14
  77. package/lib/store/add.js +1 -0
  78. package/lib/store/delete.js +9 -4
  79. package/lib/store/item.js +233 -37
  80. package/lib/team/members/connections.js +2 -1
  81. package/lib/team/members/member.js +2 -1
  82. package/lib/util/index.js +14 -13
  83. package/package.json +17 -17
  84. package/es/blocklet/publish/create-project.js +0 -205
  85. package/lib/blocklet/publish/create-project.js +0 -215
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, lazy, useRef, useCallback } from 'react';
1
+ import { useState, useEffect, lazy, useRef, useCallback, useMemo } 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';
@@ -14,16 +14,19 @@ import IconButton from '@mui/material/IconButton';
14
14
  import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
15
15
  import InputAdornment from '@mui/material/InputAdornment';
16
16
  import Spinner from '@mui/material/CircularProgress';
17
- import Dialog from '@mui/material/Dialog';
17
+ import MaterialDialog from '@mui/material/Dialog';
18
+ import DidConnect from '@arcblock/did-connect/lib/Connect';
18
19
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
19
20
  import Button from '@arcblock/ux/lib/Button';
20
21
  import Toast from '@arcblock/ux/lib/Toast';
21
22
  import Empty from '@arcblock/ux/lib/Empty';
22
23
  import Tabs from '@arcblock/ux/lib/Tabs';
24
+ import Dialog from '@arcblock/ux/lib/Dialog';
23
25
  import Alert from '@arcblock/ux/lib/Alert';
24
26
  import { PROJECT } from '@blocklet/constant';
25
- import { WELLKNOWN_SERVICE_PATH_PREFIX } from '@abtnode/constant';
27
+ import { WELLKNOWN_SERVICE_PATH_PREFIX, UNOWNED_DID } from '@abtnode/constant';
26
28
  import BlockletBundleAvatar from '../bundle-avatar';
29
+ import { useSessionContext } from '../../contexts/session';
27
30
  import { useNodeContext } from '../../contexts/node';
28
31
  import { useBlockletContext } from '../../contexts/blocklet';
29
32
  import EmptySpinner from '../../empty-spinner';
@@ -31,6 +34,7 @@ import ClickToCopy from '../../click-to-copy';
31
34
  import { formatError } from '../../util';
32
35
  import Resource from './resource';
33
36
  import SelectComponents from './select-components';
37
+ import ConnectStoreList from './connect-store-list';
34
38
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
35
39
  const allowedFileTypes = ['image/*', '.jpg', '.jpeg', '.png', '.gif', '.svg'];
36
40
  const maxFileSize = 1024 * 1024 * 10; // 10 MB
@@ -103,13 +107,14 @@ const addComponentTabs = ({
103
107
  });
104
108
  };
105
109
  const pickParams = (release, app) => {
106
- const params = pick(release, ['blockletVersion', 'blockletTitle', 'blockletDescription', 'blockletLogo', 'blockletIntroduction', 'blockletScreenshots', 'blockletComponents', 'note']);
110
+ const params = pick(release, ['blockletVersion', 'blockletTitle', 'blockletDescription', 'blockletLogo', 'blockletIntroduction', 'blockletScreenshots', 'blockletComponents', 'publishedStoreIds', 'note']);
107
111
  params.blockletScreenshots ||= [];
112
+ params.publishedStoreIds ||= [];
108
113
  if (!params.blockletComponents) {
109
114
  params.blockletComponents = (app.children || []).map(x => ({
110
115
  did: x.meta.did,
111
- included: true,
112
- required: true
116
+ included: false,
117
+ required: false
113
118
  }));
114
119
  } else {
115
120
  params.blockletComponents = params.blockletComponents.map(x => ({
@@ -126,11 +131,15 @@ export default function CreateRelease({
126
131
  const {
127
132
  projectId,
128
133
  releaseId: inputReleaseId,
129
- componentDid
134
+ componentDid = ''
130
135
  } = useParams();
131
136
  const {
132
- t
137
+ t,
138
+ locale
133
139
  } = useLocaleContext();
140
+ const {
141
+ api: sessionApi
142
+ } = useSessionContext();
134
143
  const {
135
144
  blocklet
136
145
  } = useBlockletContext();
@@ -144,10 +153,12 @@ export default function CreateRelease({
144
153
  } = useNodeContext();
145
154
  const uploaderLogoRef = useRef(null);
146
155
  const uploaderScreenshotRef = useRef(null);
147
- const [projectType, setProjectType] = useState();
148
156
  const [installResourceTip, setInstallResourceTip] = useState();
157
+ const [openConnect, setOpenConnect] = useState(false);
158
+ const [showStoreDialog, setShowStoreDialog] = useState(false);
149
159
  const releaseId = inputReleaseId === 'create' ? '' : inputReleaseId;
150
160
  const mode = inputReleaseId === 'create' ? 'create' : 'edit';
161
+ const projectType = useMemo(() => params?.blockletComponents?.some(x => x.included) ? 'pack' : 'resource', [params?.blockletComponents]);
151
162
  const tabs = [];
152
163
  const resourceComponents = (blocklet?.children || []).filter(x => x.meta.resource?.exportApi).filter(x => !componentDid || x.meta.did === componentDid);
153
164
  resourceComponents.forEach(item => {
@@ -161,9 +172,18 @@ export default function CreateRelease({
161
172
  const [tab, setTab] = useState(tabs[0]?.value);
162
173
  const isPublished = release?.status === 'published';
163
174
  const readOnly = isPublished;
164
- const getProject = ({
165
- typeOnly
166
- } = {}) => {
175
+ const getProject = () => {
176
+ if (projectId === UNOWNED_DID) {
177
+ setParams({
178
+ blockletVersion: '1.0.0',
179
+ blockletTitle: ''
180
+ });
181
+ return;
182
+ }
183
+ if (!projectId) {
184
+ Toast.error(t('blocklet.publish.errorTip.noDid'));
185
+ return;
186
+ }
167
187
  api.getProject({
168
188
  input: {
169
189
  did: blocklet.meta.did,
@@ -172,17 +192,16 @@ export default function CreateRelease({
172
192
  }).then(res => {
173
193
  setLoading(false);
174
194
  const data = res.project || {};
175
- if (typeOnly) {
176
- setProjectType(data.type);
177
- return;
178
- }
179
195
  if (!data.blockletVersion) {
180
196
  data.blockletVersion = '1.0.0';
181
197
  } else if (semver.valid(data.blockletVersion)) {
182
198
  data.blockletVersion = semver.inc(data.blockletVersion, 'patch');
183
199
  }
184
- setParams(pickParams(data, blocklet));
185
- setProjectType(data.type);
200
+ const theParams = pickParams(data, blocklet);
201
+ if (theParams.blockletTitle === projectId.slice(0, 8)) {
202
+ theParams.blockletTitle = '';
203
+ }
204
+ setParams(theParams);
186
205
  }).catch(err => {
187
206
  setLoading(false);
188
207
  Toast.error(formatError(err));
@@ -211,19 +230,17 @@ export default function CreateRelease({
211
230
  return;
212
231
  }
213
232
  getRelease();
214
- getProject({
215
- typeOnly: true
216
- });
217
233
  }
218
234
  if (mode === 'create') {
219
235
  getProject();
220
236
  }
221
237
  // eslint-disable-next-line react-hooks/exhaustive-deps
222
238
  }, [mode, releaseId]);
223
- useEffect(() => {
224
- getData();
225
- }, [getData]);
226
239
  const onRelease = status => {
240
+ if (!projectId || projectId === UNOWNED_DID) {
241
+ Toast.error(t('blocklet.publish.errorTip.noDid'));
242
+ return;
243
+ }
227
244
  const errors = validateParams(params, status, t);
228
245
  if (errors) {
229
246
  Toast.error(errors.map(x => x.message).join('; '));
@@ -248,11 +265,7 @@ export default function CreateRelease({
248
265
  _params.blockletDescription = (_params.blockletDescription || '').trim();
249
266
  _params.blockletIntroduction = (_params.blockletIntroduction || '').trim();
250
267
  _params.note = (_params.note || '').trim();
251
- if (projectType === 'pack') {
252
- _params.blockletComponents = (_params.blockletComponents || []).filter(x => x.included).map(x => pick(x, ['did', 'required'])).map(JSON.stringify);
253
- } else {
254
- delete _params.blockletComponents;
255
- }
268
+ _params.blockletComponents = (_params.blockletComponents || []).filter(x => x.included).map(x => pick(x, ['did', 'required'])).map(JSON.stringify);
256
269
  setCreateLoading(status);
257
270
  setLoading(true);
258
271
  api.createRelease({
@@ -291,12 +304,96 @@ export default function CreateRelease({
291
304
  }
292
305
  });
293
306
  };
307
+ const handleDidConnectShow = e => {
308
+ e.preventDefault();
309
+ e.stopPropagation();
310
+ if (!params.blockletTitle) {
311
+ setParamsErrTip({
312
+ blockletTitle: t('blocklet.publish.errorTip.noTitle')
313
+ });
314
+ Toast.error(t('blocklet.publish.errorTip.noTitle'));
315
+ return;
316
+ }
317
+ if (!projectId || projectId === UNOWNED_DID) {
318
+ setOpenConnect(true);
319
+ }
320
+ };
321
+ const handleDidConnectClose = () => {
322
+ setOpenConnect(false);
323
+ };
324
+ const handleChangeSelectedComponents = data => {
325
+ setParams({
326
+ blockletComponents: data
327
+ });
328
+ };
329
+ const handleCreateBlockletDidError = err => {
330
+ Toast.error(err.message);
331
+ setOpenConnect(false);
332
+ };
333
+ const handleCreate = nextProjectDid => {
334
+ if (!nextProjectDid) {
335
+ Toast.error(t('blocklet.publish.errorTip.noDid'));
336
+ return;
337
+ }
338
+ setLoading(true);
339
+ api.createProject({
340
+ input: {
341
+ did: blocklet.meta.did,
342
+ blockletTitle: params.blockletTitle || nextProjectDid.slice(0, 9),
343
+ blockletDid: nextProjectDid,
344
+ type: params.blockletComponents?.length > 0 ? 'pack' : 'resource',
345
+ componentDid
346
+ }
347
+ }).then(() => {
348
+ setLoading(false);
349
+ navigate(window.location.pathname.replace(`${UNOWNED_DID}/create`, `${nextProjectDid}/create`), {
350
+ replace: true
351
+ });
352
+ }).catch(err => {
353
+ setLoading(false);
354
+ Toast.error(err.message);
355
+ });
356
+ };
357
+ const handleCreateBlockletDidSuccess = result => {
358
+ const did = result?.blockletWallet?.address;
359
+ if (!did) {
360
+ Toast.error('Empty Blocklet DID');
361
+ } else {
362
+ handleCreate(did);
363
+ }
364
+ setOpenConnect(false);
365
+ };
366
+ useEffect(() => {
367
+ getData();
368
+ }, [getData]);
294
369
  if (!params && loading) {
295
370
  return /*#__PURE__*/_jsx(EmptySpinner, {});
296
371
  }
297
372
  if (!params) {
298
373
  return null;
299
374
  }
375
+ const connect = openConnect ? /*#__PURE__*/_jsx(DidConnect, {
376
+ open: true,
377
+ popup: true,
378
+ onClose: handleDidConnectClose,
379
+ action: "gen-blocklet-key-pair",
380
+ locale: locale,
381
+ checkFn: sessionApi.get,
382
+ saveConnect: false,
383
+ forceConnected: false,
384
+ checkTimeout: 5 * 60 * 1000,
385
+ onSuccess: handleCreateBlockletDidSuccess,
386
+ onError: handleCreateBlockletDidError,
387
+ extraParams: {
388
+ did: blocklet.meta.did
389
+ },
390
+ messages: {
391
+ title: t('blocklet.publish.connect.title'),
392
+ scan: t('blocklet.publish.connect.scan'),
393
+ confirm: t('blocklet.publish.connect.confirm'),
394
+ success: t('blocklet.publish.connect.success')
395
+ }
396
+ }) : null;
300
397
  const uploadLogoPrefix = `${WELLKNOWN_SERVICE_PATH_PREFIX}/api/project/${blocklet.meta.did}/${projectId}/logo/upload`;
301
398
  const uploadScreenshotPrefix = `${WELLKNOWN_SERVICE_PATH_PREFIX}/api/project/${blocklet.meta.did}/${projectId}/screenshot/upload`;
302
399
  const logoUrl = params?.blockletLogo ? `${uploadLogoPrefix}/${params.blockletLogo}` : `${WELLKNOWN_SERVICE_PATH_PREFIX}/static/images/logo.png`;
@@ -307,7 +404,7 @@ export default function CreateRelease({
307
404
  error: paramsErrTip.blockletResource,
308
405
  app: blocklet,
309
406
  component: item,
310
- projectId: projectId,
407
+ projectId: projectId === UNOWNED_DID ? '' : projectId,
311
408
  release: {
312
409
  ...release,
313
410
  id: releaseId
@@ -357,8 +454,8 @@ export default function CreateRelease({
357
454
  marginRight: 8
358
455
  },
359
456
  onClick: () => setInstallResourceTip(blockletMetaUrl),
360
- children: t('common.install')
361
- }), /*#__PURE__*/_jsx(Dialog, {
457
+ children: t('blocklet.publish.copyInstallUrl')
458
+ }), /*#__PURE__*/_jsx(MaterialDialog, {
362
459
  fullWidth: true,
363
460
  maxWidth: "sm",
364
461
  open: installResourceTip,
@@ -398,7 +495,7 @@ export default function CreateRelease({
398
495
  }
399
496
  return /*#__PURE__*/_jsxs(Main, {
400
497
  ...rest,
401
- children: [/*#__PURE__*/_jsxs(Box, {
498
+ children: [connect, /*#__PURE__*/_jsxs(Box, {
402
499
  className: "sticky-header",
403
500
  children: [/*#__PURE__*/_jsxs(Breadcrumbs, {
404
501
  className: "breadcrumbs",
@@ -432,6 +529,9 @@ export default function CreateRelease({
432
529
  }), /*#__PURE__*/_jsxs(Button, {
433
530
  variant: "contained",
434
531
  disabled: loading || createLoading,
532
+ style: {
533
+ marginRight: 12
534
+ },
435
535
  onClick: () => onRelease(PROJECT.RELEASE_STATUS.published),
436
536
  children: [createLoading === PROJECT.RELEASE_STATUS.published && /*#__PURE__*/_jsx(Spinner, {
437
537
  size: 14,
@@ -443,23 +543,24 @@ export default function CreateRelease({
443
543
  })]
444
544
  }), isPublished && /*#__PURE__*/_jsxs(_Fragment, {
445
545
  children: [installButton, /*#__PURE__*/_jsx(Button, {
446
- variant: "contained",
546
+ variant: "outlined",
547
+ style: {
548
+ marginRight: 12
549
+ },
447
550
  children: /*#__PURE__*/_jsx("a", {
448
551
  href: joinUrl(`${WELLKNOWN_SERVICE_PATH_PREFIX}/api/project/${blocklet.meta.did}/${projectId}/${releaseId}/download/${(release.files || [])[0]}`),
449
552
  children: t('common.download')
450
553
  })
554
+ }), /*#__PURE__*/_jsx(Button, {
555
+ variant: "contained",
556
+ onClick: () => setShowStoreDialog(true),
557
+ children: t('common.uploadToStore')
451
558
  })]
452
559
  })]
453
560
  })]
454
561
  }), /*#__PURE__*/_jsxs(Box, {
455
- children: [projectType === 'pack' && /*#__PURE__*/_jsx(Alert, {
456
- type: "info",
457
- style: {
458
- width: '100%'
459
- },
460
- children: t('blocklet.publish.packTip')
461
- }), /*#__PURE__*/_jsx(Box, {
462
- pt: 3
562
+ children: [/*#__PURE__*/_jsx(Box, {
563
+ pt: 5
463
564
  }), /*#__PURE__*/_jsxs(Box, {
464
565
  display: "flex",
465
566
  className: "section",
@@ -493,6 +594,31 @@ export default function CreateRelease({
493
594
  },
494
595
  error: !!paramsErrTip.blockletTitle,
495
596
  helperText: paramsErrTip.blockletTitle || ''
597
+ }), /*#__PURE__*/_jsx(TextField, {
598
+ required: true,
599
+ label: "Blocklet DID",
600
+ fullWidth: true,
601
+ readonly: true,
602
+ disabled: projectId !== UNOWNED_DID,
603
+ autoComplete: "off",
604
+ variant: "outlined",
605
+ onClick: handleDidConnectShow,
606
+ onInput: handleDidConnectShow,
607
+ InputProps: {
608
+ 'data-cy': 'export-blocklet-did',
609
+ endAdornment: projectId === UNOWNED_DID && /*#__PURE__*/_jsx(InputAdornment, {
610
+ position: "end",
611
+ children: /*#__PURE__*/_jsx(Button, {
612
+ onClick: handleDidConnectShow,
613
+ children: t('common.create')
614
+ })
615
+ })
616
+ },
617
+ helperText: "",
618
+ value: projectId === UNOWNED_DID ? '' : projectId,
619
+ sx: {
620
+ mt: 3
621
+ }
496
622
  }), /*#__PURE__*/_jsx(TextField, {
497
623
  label: `Blocklet ${t('common.description')}`,
498
624
  placeholder: `Blocklet ${t('common.description')}`,
@@ -778,7 +904,7 @@ export default function CreateRelease({
778
904
  children: resourceContent
779
905
  })]
780
906
  })]
781
- }), projectType === 'pack' && /*#__PURE__*/_jsxs(Box, {
907
+ }), /*#__PURE__*/_jsxs(Box, {
782
908
  display: "flex",
783
909
  mt: 3,
784
910
  className: "section full-width",
@@ -795,15 +921,32 @@ export default function CreateRelease({
795
921
  children: /*#__PURE__*/_jsx(SelectComponents, {
796
922
  disabled: loading || readOnly,
797
923
  app: blocklet,
798
- value: params.blockletComponents,
799
- onChange: data => {
800
- setParams({
801
- blockletComponents: data
802
- });
803
- }
924
+ value: params.blockletComponents || [],
925
+ onChange: handleChangeSelectedComponents
804
926
  })
805
927
  })]
928
+ }), projectType === 'pack' && /*#__PURE__*/_jsx(Alert, {
929
+ type: "info",
930
+ style: {
931
+ width: '100%'
932
+ },
933
+ children: t('blocklet.publish.packTip')
806
934
  })]
935
+ }), /*#__PURE__*/_jsx(Dialog, {
936
+ title: t('common.connectToStore'),
937
+ disableEscapeKeyDown: true,
938
+ disablePortal: false,
939
+ fullWidth: true,
940
+ open: showStoreDialog,
941
+ onClose: () => setShowStoreDialog(false),
942
+ children: /*#__PURE__*/_jsx(ConnectStoreList, {
943
+ blocklet: blocklet,
944
+ releaseType: params.blockletComponents?.length > 0 ? 'pack' : 'resource',
945
+ projectId: projectId,
946
+ releaseId: releaseId,
947
+ onPublish: getRelease,
948
+ publishedStoreIds: release?.publishedStoreIds
949
+ })
807
950
  })]
808
951
  });
809
952
  }
@@ -5,7 +5,6 @@ import styled from '@emotion/styled';
5
5
  import Box from '@mui/material/Box';
6
6
  import { useBlockletContext } from '../../contexts/blocklet';
7
7
  import ProjectList from './project-list';
8
- import CreateProject from './create-project';
9
8
  import ReleasesList from './release-list';
10
9
  import CreateRelease from './create-release';
11
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -45,9 +44,6 @@ export default function BlockletPublish({
45
44
  children: [/*#__PURE__*/_jsx(Route, {
46
45
  path: "/",
47
46
  element: /*#__PURE__*/_jsx(ProjectList, {})
48
- }), /*#__PURE__*/_jsx(Route, {
49
- path: "/create",
50
- element: /*#__PURE__*/_jsx(CreateProject, {})
51
47
  }), /*#__PURE__*/_jsx(Route, {
52
48
  path: "/:projectId",
53
49
  element: /*#__PURE__*/_jsx(ReleasesList, {})
@@ -1,16 +1,23 @@
1
1
  /* eslint-disable react/no-unstable-nested-components */
2
2
  import React, { useState, useEffect } from 'react';
3
- import { Link, useParams } from 'react-router-dom';
3
+ import { Link, useNavigate, useParams } from 'react-router-dom';
4
4
  import styled from '@emotion/styled';
5
+ import joinUrl from 'url-join';
5
6
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
6
7
  import Box from '@mui/material/Box';
8
+ import AddIcon from '@mui/icons-material/Add';
7
9
  import IconButton from '@mui/material/IconButton';
10
+ import LibraryAddIcon from '@mui/icons-material/LibraryAdd';
8
11
  import DeleteIcon from '@mui/icons-material/Delete';
12
+ import InstallDesktopIcon from '@mui/icons-material/InstallDesktop';
13
+ import DownloadIcon from '@mui/icons-material/Download';
14
+ import { WELLKNOWN_SERVICE_PATH_PREFIX, UNOWNED_DID } from '@abtnode/constant';
9
15
  import Datatable from '@arcblock/ux/lib/Datatable';
10
16
  import Button from '@arcblock/ux/lib/Button';
11
17
  import Toast from '@arcblock/ux/lib/Toast';
12
18
  import Tag from '@arcblock/ux/lib/Tag';
13
19
  import RelativeTime from '@arcblock/ux/lib/RelativeTime';
20
+ import { Tooltip } from '@mui/material';
14
21
  import { useBlockletContext } from '../../contexts/blocklet';
15
22
  import { useNodeContext } from '../../contexts/node';
16
23
  import EmptySpinner from '../../empty-spinner';
@@ -18,7 +25,9 @@ import DidAddress from '../../did-address';
18
25
  import Confirm from '../../confirm';
19
26
  import BlockletBundleAvatar from '../bundle-avatar';
20
27
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
28
+ const serverEndpoint = window.env?.serverEndpoint;
21
29
  export default function ProjectList() {
30
+ const navigate = useNavigate();
22
31
  const {
23
32
  t,
24
33
  locale
@@ -50,6 +59,11 @@ export default function ProjectList() {
50
59
  Toast.error(err.message);
51
60
  });
52
61
  };
62
+ const handleNewBlocklet = () => {
63
+ navigate(`${UNOWNED_DID}/create`, {
64
+ replace: true
65
+ });
66
+ };
53
67
  const onDeleteProject = project => {
54
68
  setDeleteConfirm(project);
55
69
  };
@@ -76,7 +90,15 @@ export default function ProjectList() {
76
90
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
77
91
 
78
92
  if (!projects && loading) {
79
- return /*#__PURE__*/_jsx(EmptySpinner, {});
93
+ return /*#__PURE__*/_jsx(Box, {
94
+ sx: {
95
+ display: 'flex',
96
+ justifyContent: 'center',
97
+ alignItems: 'center',
98
+ marginTop: '40px'
99
+ },
100
+ children: /*#__PURE__*/_jsx(EmptySpinner, {})
101
+ });
80
102
  }
81
103
  if (!projects) {
82
104
  return null;
@@ -101,12 +123,10 @@ export default function ProjectList() {
101
123
  mb: 3
102
124
  },
103
125
  children: t('blocklet.publish.createBlockletTip')
104
- }), /*#__PURE__*/_jsx(Link, {
105
- to: "create",
106
- children: /*#__PURE__*/_jsx(Button, {
107
- variant: "contained",
108
- children: t('blocklet.publish.createBlocklet')
109
- })
126
+ }), /*#__PURE__*/_jsx(Button, {
127
+ onClick: handleNewBlocklet,
128
+ variant: "contained",
129
+ children: t('blocklet.publish.createBlocklet')
110
130
  })]
111
131
  });
112
132
  }
@@ -191,34 +211,118 @@ export default function ProjectList() {
191
211
  options: {
192
212
  customBodyRenderLite: rawIndex => {
193
213
  const project = projects[rawIndex];
194
- return /*#__PURE__*/_jsx(Box, {
214
+ let installUrl = '';
215
+ let downloadUrl = '';
216
+ if (project.lastReleaseId) {
217
+ const blockletMetaUrl = joinUrl(serverEndpoint, `/api/project/${blocklet.meta.did}/${project.id}/${project.lastReleaseId}/release/blocklet.json`);
218
+ const url = new URL(serverEndpoint);
219
+ url.pathname = joinUrl(url.pathname, '/launch-blocklet/agreement');
220
+ url.searchParams.set('blocklet_meta_url', blockletMetaUrl);
221
+ installUrl = url.href;
222
+ downloadUrl = joinUrl(`${WELLKNOWN_SERVICE_PATH_PREFIX}/api/project/${blocklet.meta.did}/${project.id}/${project.lastReleaseId}/download/${(project.lastReleaseFiles || [])[0]}`);
223
+ }
224
+ return /*#__PURE__*/_jsxs(Box, {
195
225
  display: "flex",
196
- children: /*#__PURE__*/_jsx(IconButton, {
197
- color: "error",
198
- "aria-label": "delete",
199
- onClick: () => onDeleteProject(project),
200
- children: /*#__PURE__*/_jsx(DeleteIcon, {
201
- sx: {
202
- fontSize: 18
203
- }
226
+ children: [/*#__PURE__*/_jsx(Link, {
227
+ to: `${project.id}/create`,
228
+ children: /*#__PURE__*/_jsx(Tooltip, {
229
+ title: t('blocklet.publish.createRelease'),
230
+ placement: "top",
231
+ children: /*#__PURE__*/_jsx(IconButton, {
232
+ color: "primary",
233
+ "aria-label": "create",
234
+ children: /*#__PURE__*/_jsx(LibraryAddIcon, {
235
+ sx: {
236
+ fontSize: 18
237
+ }
238
+ })
239
+ })
240
+ })
241
+ }), !!project.lastReleaseId && project.type === 'pack' && /*#__PURE__*/_jsx(Tooltip, {
242
+ title: t('blocklet.publish.install', {
243
+ name: project.blockletTitle
244
+ }),
245
+ placement: "top",
246
+ children: /*#__PURE__*/_jsx(IconButton, {
247
+ color: "secondary",
248
+ "aria-label": "create",
249
+ children: /*#__PURE__*/_jsx("a", {
250
+ style: {
251
+ display: 'flex'
252
+ },
253
+ href: installUrl,
254
+ target: "_blank",
255
+ rel: "noreferrer",
256
+ children: /*#__PURE__*/_jsx(InstallDesktopIcon, {
257
+ sx: {
258
+ fontSize: 18
259
+ }
260
+ })
261
+ })
262
+ })
263
+ }), !!project.lastReleaseId && /*#__PURE__*/_jsx(Tooltip, {
264
+ title: t('blocklet.publish.download', {
265
+ name: project.blockletTitle
266
+ }),
267
+ placement: "top",
268
+ children: /*#__PURE__*/_jsx(IconButton, {
269
+ color: "primary",
270
+ "aria-label": "create",
271
+ children: /*#__PURE__*/_jsx("a", {
272
+ style: {
273
+ display: 'flex'
274
+ },
275
+ href: downloadUrl,
276
+ children: /*#__PURE__*/_jsx(DownloadIcon, {
277
+ sx: {
278
+ fontSize: 18
279
+ }
280
+ })
281
+ })
282
+ })
283
+ }), /*#__PURE__*/_jsx(Tooltip, {
284
+ title: t('blocklet.publish.delete', {
285
+ name: project.blockletTitle
286
+ }),
287
+ placement: "top",
288
+ children: /*#__PURE__*/_jsx(IconButton, {
289
+ color: "primary",
290
+ "aria-label": "delete",
291
+ onClick: () => onDeleteProject(project),
292
+ children: /*#__PURE__*/_jsx(DeleteIcon, {
293
+ sx: {
294
+ fontSize: 18
295
+ }
296
+ })
204
297
  })
205
- })
298
+ })]
206
299
  });
207
300
  }
208
301
  }
209
302
  }].filter(Boolean);
210
303
  return /*#__PURE__*/_jsxs(Main, {
211
- children: [/*#__PURE__*/_jsx(Box, {
212
- sx: {
213
- textAlign: 'right'
214
- },
215
- children: /*#__PURE__*/_jsx(Link, {
216
- to: "create",
217
- children: /*#__PURE__*/_jsx(Button, {
218
- variant: "contained",
219
- children: t('blocklet.publish.createBlocklet')
220
- })
221
- })
304
+ children: [/*#__PURE__*/_jsxs(Box, {
305
+ display: "flex",
306
+ justifyContent: "space-between",
307
+ alignItems: "center",
308
+ children: [/*#__PURE__*/_jsx(Box, {
309
+ sx: {
310
+ fontSize: '1.2rem',
311
+ fontWeight: 'bold'
312
+ },
313
+ children: t('blocklet.publish.productListTitle')
314
+ }), /*#__PURE__*/_jsxs(Button, {
315
+ onClick: handleNewBlocklet,
316
+ variant: "contained",
317
+ children: [/*#__PURE__*/_jsx(AddIcon, {
318
+ style: {
319
+ fontSize: '1.3em',
320
+ marginRight: 4
321
+ }
322
+ }), t('blocklet.publish.createBlocklet')]
323
+ })]
324
+ }), /*#__PURE__*/_jsx(Box, {
325
+ mt: 3
222
326
  }), /*#__PURE__*/_jsx(Datatable, {
223
327
  className: "main-table",
224
328
  locale: locale,