@abtnode/ux 1.16.17-beta-d282d63e → 1.16.17-beta-4f13d99d

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.
@@ -4,13 +4,13 @@ import MenuItem from '@mui/material/MenuItem';
4
4
  import TextField from '@mui/material/TextField';
5
5
  import Typography from '@mui/material/Typography';
6
6
  import Breadcrumbs from '@mui/material/Breadcrumbs';
7
+ import InputAdornment from '@mui/material/InputAdornment';
7
8
  import styled from '@emotion/styled';
8
9
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
9
10
  import Box from '@mui/material/Box';
10
11
  import Button from '@arcblock/ux/lib/Button';
11
12
  import DidConnect from '@arcblock/did-connect/lib/Connect';
12
13
  import Toast from '@arcblock/ux/lib/Toast';
13
- import DidAddress from '../../did-address';
14
14
  import { useNodeContext } from '../../contexts/node';
15
15
  import { useBlockletContext } from '../../contexts/blocklet';
16
16
  import { useSessionContext } from '../../contexts/session';
@@ -66,6 +66,14 @@ export default function CreateProject({
66
66
  setOpenConnect(false);
67
67
  };
68
68
  const onCreate = () => {
69
+ if (!blockletDid) {
70
+ Toast.error(t('blocklet.publish.errorTip.noDid'));
71
+ return;
72
+ }
73
+ if (!blockletTitle) {
74
+ Toast.error(t('blocklet.publish.errorTip.noTitle'));
75
+ return;
76
+ }
69
77
  setLoading(true);
70
78
  api.createProject({
71
79
  input: {
@@ -100,26 +108,29 @@ export default function CreateProject({
100
108
  style: {
101
109
  maxWidth: 500
102
110
  },
103
- children: [/*#__PURE__*/_jsxs(Box, {
111
+ children: [/*#__PURE__*/_jsx(TextField, {
112
+ required: true,
104
113
  sx: {
105
- mb: 3
114
+ mb: 4
106
115
  },
107
- display: "flex",
108
- alignItems: "center",
109
- children: [/*#__PURE__*/_jsxs(Typography, {
110
- variant: "h6",
111
- sx: {
112
- mr: 3
113
- },
114
- children: ["Blocklet DID:", ' ']
115
- }), blockletDid ? /*#__PURE__*/_jsx(DidAddress, {
116
- size: 14,
117
- responsive: true,
118
- did: blockletDid
119
- }) : /*#__PURE__*/_jsx(Button, {
120
- onClick: () => setOpenConnect(true),
121
- children: t('blocklet.publish.createBlockletDid')
122
- })]
116
+ label: "Blocklet DID",
117
+ fullWidth: true,
118
+ readonly: true,
119
+ autoComplete: "off",
120
+ variant: "outlined",
121
+ onClick: () => !blockletDid && setOpenConnect(true),
122
+ InputProps: {
123
+ 'data-cy': 'export-blocklet-did',
124
+ endAdornment: /*#__PURE__*/_jsx(InputAdornment, {
125
+ position: "end",
126
+ children: /*#__PURE__*/_jsx(Button, {
127
+ onClick: () => setOpenConnect(true),
128
+ children: t(blockletDid ? 'common.update' : 'common.create')
129
+ })
130
+ })
131
+ },
132
+ helperText: "",
133
+ value: blockletDid || ''
123
134
  }), openConnect && /*#__PURE__*/_jsx(DidConnect, {
124
135
  open: true,
125
136
  popup: true,
@@ -142,10 +153,11 @@ export default function CreateProject({
142
153
  success: t('blocklet.publish.connect.success')
143
154
  }
144
155
  }), /*#__PURE__*/_jsx(TextField, {
156
+ required: true,
145
157
  label: `Blocklet ${t('common.title')}`,
146
158
  autoComplete: "off",
147
159
  variant: "outlined",
148
- inputProps: {
160
+ InputProps: {
149
161
  'data-cy': 'export-blocklet-title'
150
162
  },
151
163
  fullWidth: true,
@@ -173,7 +185,7 @@ export default function CreateProject({
173
185
  })]
174
186
  }), /*#__PURE__*/_jsx(Button, {
175
187
  variant: "contained",
176
- disabled: loading || !blockletDid || !blockletTitle,
188
+ disabled: loading,
177
189
  onClick: onCreate,
178
190
  children: t('common.create')
179
191
  })]
@@ -12,6 +12,7 @@ import Breadcrumbs from '@mui/material/Breadcrumbs';
12
12
  import Box from '@mui/material/Box';
13
13
  import IconButton from '@mui/material/IconButton';
14
14
  import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
15
+ import InputAdornment from '@mui/material/InputAdornment';
15
16
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
16
17
  import Button from '@arcblock/ux/lib/Button';
17
18
  import Toast from '@arcblock/ux/lib/Toast';
@@ -23,15 +24,53 @@ import BlockletBundleAvatar from '../bundle-avatar';
23
24
  import { useNodeContext } from '../../contexts/node';
24
25
  import { useBlockletContext } from '../../contexts/blocklet';
25
26
  import EmptySpinner from '../../empty-spinner';
27
+ import { formatError } from '../../util';
26
28
  import Resource from './resource';
27
-
28
- // eslint-disable-next-line import/no-unresolved
29
29
  import { jsx as _jsx } from "react/jsx-runtime";
30
30
  import { jsxs as _jsxs } from "react/jsx-runtime";
31
31
  import { Fragment as _Fragment } from "react/jsx-runtime";
32
+ const allowedFileTypes = ['image/*', '.jpg', '.jpeg', '.png', '.gif', '.svg'];
33
+ const maxFileSize = 1024 * 1024 * 10; // 10 MB
34
+
35
+ // eslint-disable-next-line import/no-unresolved
32
36
  const UploaderComponent = /*#__PURE__*/lazy(() => import('@blocklet/uploader/react').then(res => ({
33
37
  default: res.Uploader
34
38
  })));
39
+ const validateParams = (params, status, t) => {
40
+ const errors = [];
41
+ if (!params.blockletTitle) {
42
+ errors.push({
43
+ param: 'blockletTitle',
44
+ message: t('blocklet.publish.errorTip.noTitle')
45
+ });
46
+ }
47
+ if (!params.blockletVersion) {
48
+ errors.push({
49
+ param: 'blockletVersion',
50
+ message: t('blocklet.publish.errorTip.noVersion')
51
+ });
52
+ } else if (!semver.valid(params.blockletVersion)) {
53
+ errors.push({
54
+ param: 'blockletVersion',
55
+ message: 'Invalid Blocklet Version'
56
+ });
57
+ }
58
+ if (status === PROJECT.RELEASE_STATUS.published) {
59
+ if (!params.blockletDescription) {
60
+ errors.push({
61
+ param: 'blockletDescription',
62
+ message: t('blocklet.publish.errorTip.noDescription')
63
+ });
64
+ }
65
+ if (!params.note) {
66
+ errors.push({
67
+ param: 'note',
68
+ message: t('blocklet.publish.errorTip.noNote')
69
+ });
70
+ }
71
+ }
72
+ return errors.length ? errors : null;
73
+ };
35
74
  const addComponentTabs = ({
36
75
  tabs,
37
76
  blocklet,
@@ -59,7 +98,11 @@ const addComponentTabs = ({
59
98
  value: key
60
99
  });
61
100
  };
62
- const pickParams = release => pick(release, ['blockletVersion', 'blockletTitle', 'blockletDescription', 'blockletLogo', 'blockletIntroduction', 'blockletScreenshots', 'note']);
101
+ const pickParams = release => {
102
+ const params = pick(release, ['blockletVersion', 'blockletTitle', 'blockletDescription', 'blockletLogo', 'blockletIntroduction', 'blockletScreenshots', 'note']);
103
+ params.blockletScreenshots ||= [];
104
+ return params;
105
+ };
63
106
  export default function CreateRelease({
64
107
  ...rest
65
108
  }) {
@@ -75,6 +118,7 @@ export default function CreateRelease({
75
118
  blocklet
76
119
  } = useBlockletContext();
77
120
  const [params, setParams] = useSetState(null);
121
+ const [paramsErrTip, setParamsErrTip] = useState({});
78
122
  const [loading, setLoading] = useState(false);
79
123
  const [release, setRelease] = useState(null);
80
124
  const {
@@ -114,7 +158,7 @@ export default function CreateRelease({
114
158
  setParams(pickParams(data));
115
159
  }).catch(err => {
116
160
  setLoading(false);
117
- Toast.error(err.message);
161
+ Toast.error(formatError(err));
118
162
  });
119
163
  };
120
164
  const getRelease = () => {
@@ -130,7 +174,7 @@ export default function CreateRelease({
130
174
  setRelease(res?.release);
131
175
  }).catch(err => {
132
176
  setLoading(false);
133
- Toast.error(err.message);
177
+ Toast.error(formatError(err));
134
178
  });
135
179
  };
136
180
  const getData = () => {
@@ -150,30 +194,24 @@ export default function CreateRelease({
150
194
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
151
195
 
152
196
  const onRelease = status => {
153
- if (!params.blockletTitle) {
154
- Toast.error(t('blocklet.publish.errorTip.noTitle'));
155
- return;
156
- }
157
- if (!params.blockletVersion) {
158
- Toast.error(t('blocklet.publish.errorTip.noVersion'));
197
+ const errors = validateParams(params, status, t);
198
+ if (errors) {
199
+ Toast.error(errors.map(x => x.message).join('; '));
200
+ setParamsErrTip(errors.reduce((acc, x) => ({
201
+ ...acc,
202
+ [x.param]: x.message
203
+ }), {}));
159
204
  return;
160
205
  }
161
- if (status === PROJECT.RELEASE_STATUS.published) {
162
- if (!params.blockletDescription) {
163
- Toast.error(t('blocklet.publish.errorTip.noDescription'));
164
- return;
165
- }
166
- if (!params.note) {
167
- Toast.error(t('blocklet.publish.errorTip.noNote'));
168
- return;
169
- }
170
- }
171
206
  const _params = {
172
207
  ...params
173
208
  };
174
209
  _params.blockletVersion = semver.valid(_params.blockletVersion);
175
210
  if (!_params.blockletVersion) {
176
211
  Toast.error('Invalid Blocklet Version');
212
+ setParamsErrTip({
213
+ blockletVersion: 'Invalid Blocklet Version'
214
+ });
177
215
  return;
178
216
  }
179
217
  _params.blockletTitle = (_params.blockletTitle || '').trim();
@@ -203,7 +241,7 @@ export default function CreateRelease({
203
241
  });
204
242
  }
205
243
  }).catch(err => {
206
- Toast.error(err.message);
244
+ Toast.error(formatError(err));
207
245
  });
208
246
  };
209
247
  if (!params && loading) {
@@ -295,7 +333,7 @@ export default function CreateRelease({
295
333
  children: [/*#__PURE__*/_jsx(TextField, {
296
334
  label: `Blocklet ${t('common.title')}`,
297
335
  placeholder: `Blocklet ${t('common.title')}`,
298
- inputProps: {
336
+ InputProps: {
299
337
  'data-cy': 'blocklet-title',
300
338
  readOnly
301
339
  },
@@ -304,14 +342,19 @@ export default function CreateRelease({
304
342
  fullWidth: true,
305
343
  value: params.blockletTitle || '',
306
344
  onChange: e => {
345
+ setParamsErrTip({
346
+ blockletTitle: ''
347
+ });
307
348
  setParams({
308
349
  blockletTitle: e.target.value
309
350
  });
310
- }
351
+ },
352
+ error: !!paramsErrTip.blockletTitle,
353
+ helperText: paramsErrTip.blockletTitle || ''
311
354
  }), /*#__PURE__*/_jsx(TextField, {
312
355
  label: `Blocklet ${t('common.description')}`,
313
356
  placeholder: `Blocklet ${t('common.description')}`,
314
- inputProps: {
357
+ InputProps: {
315
358
  'data-cy': 'blocklet-description',
316
359
  readOnly
317
360
  },
@@ -320,31 +363,45 @@ export default function CreateRelease({
320
363
  fullWidth: true,
321
364
  value: params.blockletDescription || '',
322
365
  onChange: e => {
366
+ setParamsErrTip({
367
+ blockletDescription: ''
368
+ });
323
369
  setParams({
324
370
  blockletDescription: e.target.value
325
371
  });
326
372
  },
373
+ error: !!paramsErrTip.blockletDescription,
374
+ helperText: paramsErrTip.blockletDescription || '',
327
375
  sx: {
328
376
  mt: 3
329
377
  }
330
378
  }), /*#__PURE__*/_jsx(TextField, {
331
379
  label: `Blocklet ${t('common.introduction')}`,
332
380
  placeholder: `Blocklet ${t('common.introduction')}`,
333
- inputProps: {
381
+ InputProps: {
334
382
  'data-cy': 'export-blocklet-introduction',
335
- readOnly
383
+ readOnly,
384
+ endAdornment: /*#__PURE__*/_jsxs(InputAdornment, {
385
+ position: "end",
386
+ children: [params?.blockletIntroduction?.length || 0, " / ", PROJECT.MAX_INTRO_LENGTH]
387
+ })
336
388
  },
337
389
  autoComplete: "off",
338
390
  variant: "outlined",
339
391
  fullWidth: true,
340
392
  multiline: true,
341
- rows: 4,
393
+ minRows: 4,
342
394
  value: params.blockletIntroduction || '',
343
395
  onChange: e => {
396
+ setParamsErrTip({
397
+ blockletIntroduction: ''
398
+ });
344
399
  setParams({
345
- blockletIntroduction: e.target.value
400
+ blockletIntroduction: e.target.value.slice(0, PROJECT.MAX_INTRO_LENGTH)
346
401
  });
347
402
  },
403
+ error: !!paramsErrTip.blockletIntroduction,
404
+ helperText: paramsErrTip.blockletIntroduction || '',
348
405
  sx: {
349
406
  mt: 3
350
407
  }
@@ -365,7 +422,7 @@ export default function CreateRelease({
365
422
  children: [/*#__PURE__*/_jsx(TextField, {
366
423
  label: `Blocklet ${t('common.version')}`,
367
424
  placeholder: `Blocklet ${t('common.version')}`,
368
- inputProps: {
425
+ InputProps: {
369
426
  'data-cy': 'blocklet-version',
370
427
  readOnly
371
428
  },
@@ -374,27 +431,41 @@ export default function CreateRelease({
374
431
  fullWidth: true,
375
432
  value: params.blockletVersion,
376
433
  onChange: e => {
434
+ setParamsErrTip({
435
+ blockletVersion: ''
436
+ });
377
437
  setParams({
378
438
  blockletVersion: e.target.value
379
439
  });
380
- }
440
+ },
441
+ error: !!paramsErrTip.blockletVersion,
442
+ helperText: paramsErrTip.blockletVersion || ''
381
443
  }), /*#__PURE__*/_jsx(TextField, {
382
444
  label: t('blocklet.publish.releaseNote'),
383
445
  autoComplete: "off",
384
446
  variant: "outlined",
385
- inputProps: {
447
+ InputProps: {
386
448
  'data-cy': 'release-note',
387
- readOnly
449
+ readOnly,
450
+ endAdornment: /*#__PURE__*/_jsxs(InputAdornment, {
451
+ position: "end",
452
+ children: [params?.note?.length || 0, " / ", PROJECT.MAX_NOTE_LENGTH]
453
+ })
388
454
  },
389
455
  fullWidth: true,
390
456
  multiline: true,
391
- rows: 4,
457
+ minRows: 4,
392
458
  value: params.note,
393
459
  onChange: e => {
460
+ setParamsErrTip({
461
+ note: ''
462
+ });
394
463
  setParams({
395
- note: e.target.value
464
+ note: e.target.value.slice(0, PROJECT.MAX_NOTE_LENGTH)
396
465
  });
397
466
  },
467
+ error: !!paramsErrTip.note,
468
+ helperText: paramsErrTip.note || '',
398
469
  sx: {
399
470
  mt: 3
400
471
  }
@@ -494,11 +565,19 @@ export default function CreateRelease({
494
565
  setParams({
495
566
  blockletLogo: result.data.filename
496
567
  });
568
+ uploaderLogoRef.current.close();
497
569
  },
498
- plugins: ['ImageEditor', 'Url', 'Webcam'],
570
+ plugins: [],
499
571
  apiPathProps: {
500
572
  uploader: uploadLogoPrefix,
501
573
  disableMediaKitPrefix: true
574
+ },
575
+ coreProps: {
576
+ restrictions: {
577
+ allowedFileTypes,
578
+ maxFileSize,
579
+ maxNumberOfFiles: 1
580
+ }
502
581
  }
503
582
  }, "uploader-screenshot"), /*#__PURE__*/_jsx(UploaderComponent, {
504
583
  id: "\u200Buploader-screenshot",
@@ -510,11 +589,19 @@ export default function CreateRelease({
510
589
  setParams({
511
590
  blockletScreenshots
512
591
  });
592
+ uploaderScreenshotRef.current.close();
513
593
  },
514
- plugins: ['ImageEditor', 'Url', 'Webcam'],
594
+ plugins: [],
515
595
  apiPathProps: {
516
596
  uploader: uploadScreenshotPrefix,
517
597
  disableMediaKitPrefix: true
598
+ },
599
+ coreProps: {
600
+ restrictions: {
601
+ allowedFileTypes,
602
+ maxFileSize,
603
+ maxNumberOfFiles: 5 - screenshotUrls.length
604
+ }
518
605
  }
519
606
  }, "uploader-screenshot")]
520
607
  }), /*#__PURE__*/_jsxs(Box, {
@@ -640,4 +727,11 @@ const Main = styled.div`
640
727
  color: inherit;
641
728
  }
642
729
  }
730
+ .MuiInputBase-multiline .MuiInputAdornment-positionEnd {
731
+ align-self: flex-end;
732
+ .MuiTypography-root {
733
+ font-size: 0.8rem;
734
+ }
735
+ font-size: 0.8rem;
736
+ }
643
737
  `;
@@ -9,6 +9,8 @@ import DeleteIcon from '@mui/icons-material/Delete';
9
9
  import Datatable from '@arcblock/ux/lib/Datatable';
10
10
  import Button from '@arcblock/ux/lib/Button';
11
11
  import Toast from '@arcblock/ux/lib/Toast';
12
+ import Tag from '@arcblock/ux/lib/Tag';
13
+ import RelativeTime from '@arcblock/ux/lib/RelativeTime';
12
14
  import { useBlockletContext } from '../../contexts/blocklet';
13
15
  import { useNodeContext } from '../../contexts/node';
14
16
  import EmptySpinner from '../../empty-spinner';
@@ -104,7 +106,7 @@ export default function ProjectList() {
104
106
  });
105
107
  }
106
108
  const columns = [{
107
- label: t('common.name'),
109
+ label: 'Blocklet',
108
110
  name: 'blockletTitle',
109
111
  options: {
110
112
  customBodyRenderLite: rawIndex => {
@@ -116,7 +118,7 @@ export default function ProjectList() {
116
118
  }
117
119
  }
118
120
  }, {
119
- label: t('common.address'),
121
+ label: 'DID',
120
122
  name: 'blockletDid',
121
123
  options: {
122
124
  customBodyRender: e => {
@@ -127,6 +129,28 @@ export default function ProjectList() {
127
129
  });
128
130
  }
129
131
  }
132
+ }, {
133
+ label: 'Version',
134
+ name: 'blockletVersion',
135
+ options: {
136
+ customBodyRender: value => {
137
+ return value ? /*#__PURE__*/_jsx(Tag, {
138
+ type: "success",
139
+ children: value
140
+ }) : '';
141
+ }
142
+ }
143
+ }, {
144
+ label: t('common.updatedAt'),
145
+ name: 'updatedAt',
146
+ options: {
147
+ customBodyRender: value => {
148
+ return /*#__PURE__*/_jsx(RelativeTime, {
149
+ value: Number(value),
150
+ locale: locale
151
+ });
152
+ }
153
+ }
130
154
  }, {
131
155
  label: t('common.actions'),
132
156
  name: 'actions',
@@ -16,6 +16,8 @@ import { WELLKNOWN_SERVICE_PATH_PREFIX } from '@abtnode/constant';
16
16
  import Button from '@arcblock/ux/lib/Button';
17
17
  import Toast from '@arcblock/ux/lib/Toast';
18
18
  import Tag from '@arcblock/ux/lib/Tag';
19
+ import RelativeTime from '@arcblock/ux/lib/RelativeTime';
20
+ import { PROJECT } from '@blocklet/constant';
19
21
  import { useBlockletContext } from '../../contexts/blocklet';
20
22
  import { useNodeContext } from '../../contexts/node';
21
23
  import EmptySpinner from '../../empty-spinner';
@@ -187,6 +189,21 @@ export default function ReleaseList() {
187
189
  });
188
190
  }
189
191
  }
192
+ }, {
193
+ label: t('common.lastPublishedAt'),
194
+ name: 'updatedAt',
195
+ options: {
196
+ customBodyRenderLite: rawIndex => {
197
+ const release = releases[rawIndex];
198
+ if (release.status !== PROJECT.RELEASE_STATUS.published) {
199
+ return '';
200
+ }
201
+ return /*#__PURE__*/_jsx(RelativeTime, {
202
+ value: Number(release.updatedAt),
203
+ locale: locale
204
+ });
205
+ }
206
+ }
190
207
  }, {
191
208
  label: t('common.actions'),
192
209
  name: 'actions',
@@ -195,11 +212,15 @@ export default function ReleaseList() {
195
212
  const release = releases[rawIndex];
196
213
  return /*#__PURE__*/_jsxs(Box, {
197
214
  display: "flex",
215
+ alignItems: "center",
198
216
  children: [/*#__PURE__*/_jsx(IconButton, {
199
217
  color: "primary",
200
218
  "aria-label": "download",
201
219
  disabled: release.status !== 'published',
202
220
  children: release.status === 'published' ? /*#__PURE__*/_jsx("a", {
221
+ style: {
222
+ display: 'flex'
223
+ },
203
224
  href: joinUrl(`${WELLKNOWN_SERVICE_PATH_PREFIX}/api/project/${blocklet.meta.did}/${project.id}/${release.id}/download/${(release.files || [])[0]}`),
204
225
  children: /*#__PURE__*/_jsx(DownloadIcon, {
205
226
  sx: {
@@ -2,6 +2,7 @@
2
2
  import { ROUTING_RULE_TYPES, DEFAULT_IP_DOMAIN_SUFFIX, DOMAIN_FOR_IP_SITE_REGEXP, DOMAIN_FOR_DEFAULT_SITE, DOMAIN_FOR_IP_SITE } from '@abtnode/constant';
3
3
  import isPathPrefixEqual from '@abtnode/util/lib/is-path-prefix-equal';
4
4
  import { BLOCKLET_DYNAMIC_PATH_PREFIX } from '@blocklet/constant';
5
+ import hasStartEngine from '@blocklet/meta/lib/has-start-engine';
5
6
  const validateRuleByServiceType = (params, localeContext) => {
6
7
  if (params.type === ROUTING_RULE_TYPES.REDIRECT) {
7
8
  if (!params.url) {
@@ -74,7 +75,7 @@ export const validatePathPrefix = ({
74
75
  }) => {
75
76
  // validate children
76
77
  if (curBlocklet) {
77
- let exist = (curBlocklet.children || []).find(x => isPathPrefixEqual(x.mountPoint, params.pathPrefix));
78
+ let exist = (curBlocklet.children || []).find(x => hasStartEngine(x.meta) && isPathPrefixEqual(x.mountPoint, params.pathPrefix));
78
79
  if (curBlocklet.meta.group !== 'gateway' && params.pathPrefix === '/') {
79
80
  exist = '/';
80
81
  }
package/es/locales/en.js CHANGED
@@ -632,6 +632,7 @@ module.exports = {
632
632
  saveDraft: 'Save Draft',
633
633
  releaseNote: 'Release Note',
634
634
  errorTip: {
635
+ noDid: 'Blocklet DID is required',
635
636
  noTitle: 'Blocklet Title is required',
636
637
  noVersion: 'Blocklet Version is required',
637
638
  noDescription: 'Blocklet Description is required',
@@ -1313,7 +1314,8 @@ module.exports = {
1313
1314
  launchFailed: 'Failed to launch the app, please try again',
1314
1315
  installedButStopped: 'The app is installed successfully, but cannot be started. You can start it manually after resolving blocking issues',
1315
1316
  installedButError: 'The app is successfully installed, but failed to start',
1316
- restoreFailed: 'Failed to restore app, please try again'
1317
+ restoreFailed: 'Failed to restore app, please try again',
1318
+ resourceBlocklet: 'Resource Blocklet cannot be installed as an application, you can mount this blocklet into existing applications.'
1317
1319
  },
1318
1320
  steps: {
1319
1321
  introduction: 'Introduction',
package/es/locales/zh.js CHANGED
@@ -639,6 +639,7 @@ module.exports = {
639
639
  saveDraft: '保存草稿',
640
640
  releaseNote: '发布说明',
641
641
  errorTip: {
642
+ noDid: '请填写 Blocklet DID',
642
643
  noTitle: '请填写 Blocklet 名称',
643
644
  noVersion: '请填写 Blocklet 版本号',
644
645
  noDescription: '请填写 Blocklet 描述',
@@ -1318,7 +1319,8 @@ module.exports = {
1318
1319
  launchFailed: '启动应用失败,请重试',
1319
1320
  installedButStopped: '应用安装成功,但是无法启动,解决启动问题之后后可手动启动',
1320
1321
  installedButError: '应用已经安装,但是运行出错了',
1321
- restoreFailed: '还原应用失败,请重试'
1322
+ restoreFailed: '还原应用失败,请重试',
1323
+ resourceBlocklet: '资源 Blocklet 无法作为应用被安装,你可以将该 Blocklet 挂载到现有的应用中。'
1322
1324
  },
1323
1325
  steps: {
1324
1326
  introduction: '简介',
@@ -2,6 +2,7 @@ import { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
4
4
  import Toast from '@arcblock/ux/lib/Toast';
5
+ import { hasActiveOwnerPassport } from '@abtnode/util/lib/passport';
5
6
  import Confirm from '../../confirm';
6
7
  import { useNodeContext } from '../../contexts/node';
7
8
  import { useTeamContext } from '../../contexts/team';
@@ -82,7 +83,9 @@ export default function ToggleUserApproval({
82
83
  color: user.approved ? 'error' : 'primary'
83
84
  };
84
85
  let can;
85
- if (!inService) {
86
+ if (hasActiveOwnerPassport(user)) {
87
+ can = false;
88
+ } else if (!inService) {
86
89
  can = nodeInfo.nodeOwner && !isNodeOwner(nodeInfo, user.did) && !isSelf(session.user, user.did);
87
90
  } else {
88
91
  can = !isSelf(session.user, user.did);
@@ -10,13 +10,13 @@ var _MenuItem = _interopRequireDefault(require("@mui/material/MenuItem"));
10
10
  var _TextField = _interopRequireDefault(require("@mui/material/TextField"));
11
11
  var _Typography = _interopRequireDefault(require("@mui/material/Typography"));
12
12
  var _Breadcrumbs = _interopRequireDefault(require("@mui/material/Breadcrumbs"));
13
+ var _InputAdornment = _interopRequireDefault(require("@mui/material/InputAdornment"));
13
14
  var _styled = _interopRequireDefault(require("@emotion/styled"));
14
15
  var _context = require("@arcblock/ux/lib/Locale/context");
15
16
  var _Box = _interopRequireDefault(require("@mui/material/Box"));
16
17
  var _Button = _interopRequireDefault(require("@arcblock/ux/lib/Button"));
17
18
  var _Connect = _interopRequireDefault(require("@arcblock/did-connect/lib/Connect"));
18
19
  var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
19
- var _didAddress = _interopRequireDefault(require("../../did-address"));
20
20
  var _node = require("../../contexts/node");
21
21
  var _blocklet = require("../../contexts/blocklet");
22
22
  var _session = require("../../contexts/session");
@@ -80,6 +80,14 @@ function CreateProject(_ref) {
80
80
  setOpenConnect(false);
81
81
  };
82
82
  const onCreate = () => {
83
+ if (!blockletDid) {
84
+ _Toast.default.error(t('blocklet.publish.errorTip.noDid'));
85
+ return;
86
+ }
87
+ if (!blockletTitle) {
88
+ _Toast.default.error(t('blocklet.publish.errorTip.noTitle'));
89
+ return;
90
+ }
83
91
  setLoading(true);
84
92
  api.createProject({
85
93
  input: {
@@ -113,26 +121,29 @@ function CreateProject(_ref) {
113
121
  style: {
114
122
  maxWidth: 500
115
123
  },
116
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
124
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
125
+ required: true,
117
126
  sx: {
118
- mb: 3
127
+ mb: 4
119
128
  },
120
- display: "flex",
121
- alignItems: "center",
122
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_Typography.default, {
123
- variant: "h6",
124
- sx: {
125
- mr: 3
126
- },
127
- children: ["Blocklet DID:", ' ']
128
- }), blockletDid ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_didAddress.default, {
129
- size: 14,
130
- responsive: true,
131
- did: blockletDid
132
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
133
- onClick: () => setOpenConnect(true),
134
- children: t('blocklet.publish.createBlockletDid')
135
- })]
129
+ label: "Blocklet DID",
130
+ fullWidth: true,
131
+ readonly: true,
132
+ autoComplete: "off",
133
+ variant: "outlined",
134
+ onClick: () => !blockletDid && setOpenConnect(true),
135
+ InputProps: {
136
+ 'data-cy': 'export-blocklet-did',
137
+ endAdornment: /*#__PURE__*/(0, _jsxRuntime.jsx)(_InputAdornment.default, {
138
+ position: "end",
139
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
140
+ onClick: () => setOpenConnect(true),
141
+ children: t(blockletDid ? 'common.update' : 'common.create')
142
+ })
143
+ })
144
+ },
145
+ helperText: "",
146
+ value: blockletDid || ''
136
147
  }), openConnect && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Connect.default, {
137
148
  open: true,
138
149
  popup: true,
@@ -155,10 +166,11 @@ function CreateProject(_ref) {
155
166
  success: t('blocklet.publish.connect.success')
156
167
  }
157
168
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
169
+ required: true,
158
170
  label: "Blocklet ".concat(t('common.title')),
159
171
  autoComplete: "off",
160
172
  variant: "outlined",
161
- inputProps: {
173
+ InputProps: {
162
174
  'data-cy': 'export-blocklet-title'
163
175
  },
164
176
  fullWidth: true,
@@ -186,7 +198,7 @@ function CreateProject(_ref) {
186
198
  })]
187
199
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
188
200
  variant: "contained",
189
- disabled: loading || !blockletDid || !blockletTitle,
201
+ disabled: loading,
190
202
  onClick: onCreate,
191
203
  children: t('common.create')
192
204
  })]
@@ -18,6 +18,7 @@ var _Breadcrumbs = _interopRequireDefault(require("@mui/material/Breadcrumbs"));
18
18
  var _Box = _interopRequireDefault(require("@mui/material/Box"));
19
19
  var _IconButton = _interopRequireDefault(require("@mui/material/IconButton"));
20
20
  var _DeleteOutline = _interopRequireDefault(require("@mui/icons-material/DeleteOutline"));
21
+ var _InputAdornment = _interopRequireDefault(require("@mui/material/InputAdornment"));
21
22
  var _context = require("@arcblock/ux/lib/Locale/context");
22
23
  var _Button = _interopRequireDefault(require("@arcblock/ux/lib/Button"));
23
24
  var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
@@ -29,6 +30,7 @@ var _bundleAvatar = _interopRequireDefault(require("../bundle-avatar"));
29
30
  var _node = require("../../contexts/node");
30
31
  var _blocklet = require("../../contexts/blocklet");
31
32
  var _emptySpinner = _interopRequireDefault(require("../../empty-spinner"));
33
+ var _util = require("../../util");
32
34
  var _resource = _interopRequireDefault(require("./resource"));
33
35
  var _jsxRuntime = require("react/jsx-runtime");
34
36
  var _templateObject;
@@ -41,10 +43,49 @@ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typ
41
43
  function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
42
44
  function _objectDestructuringEmpty(obj) { if (obj == null) throw new TypeError("Cannot destructure " + obj); }
43
45
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
44
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } // eslint-disable-next-line import/no-unresolved
46
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
47
+ const allowedFileTypes = ['image/*', '.jpg', '.jpeg', '.png', '.gif', '.svg'];
48
+ const maxFileSize = 1024 * 1024 * 10; // 10 MB
49
+
50
+ // eslint-disable-next-line import/no-unresolved
45
51
  const UploaderComponent = /*#__PURE__*/(0, _react.lazy)(() => Promise.resolve().then(() => _interopRequireWildcard(require('@blocklet/uploader/react'))).then(res => ({
46
52
  default: res.Uploader
47
53
  })));
54
+ const validateParams = (params, status, t) => {
55
+ const errors = [];
56
+ if (!params.blockletTitle) {
57
+ errors.push({
58
+ param: 'blockletTitle',
59
+ message: t('blocklet.publish.errorTip.noTitle')
60
+ });
61
+ }
62
+ if (!params.blockletVersion) {
63
+ errors.push({
64
+ param: 'blockletVersion',
65
+ message: t('blocklet.publish.errorTip.noVersion')
66
+ });
67
+ } else if (!_semver.default.valid(params.blockletVersion)) {
68
+ errors.push({
69
+ param: 'blockletVersion',
70
+ message: 'Invalid Blocklet Version'
71
+ });
72
+ }
73
+ if (status === _constant.PROJECT.RELEASE_STATUS.published) {
74
+ if (!params.blockletDescription) {
75
+ errors.push({
76
+ param: 'blockletDescription',
77
+ message: t('blocklet.publish.errorTip.noDescription')
78
+ });
79
+ }
80
+ if (!params.note) {
81
+ errors.push({
82
+ param: 'note',
83
+ message: t('blocklet.publish.errorTip.noNote')
84
+ });
85
+ }
86
+ }
87
+ return errors.length ? errors : null;
88
+ };
48
89
  const addComponentTabs = _ref => {
49
90
  let {
50
91
  tabs,
@@ -73,9 +114,13 @@ const addComponentTabs = _ref => {
73
114
  value: key
74
115
  });
75
116
  };
76
- const pickParams = release => (0, _pick.default)(release, ['blockletVersion', 'blockletTitle', 'blockletDescription', 'blockletLogo', 'blockletIntroduction', 'blockletScreenshots', 'note']);
117
+ const pickParams = release => {
118
+ const params = (0, _pick.default)(release, ['blockletVersion', 'blockletTitle', 'blockletDescription', 'blockletLogo', 'blockletIntroduction', 'blockletScreenshots', 'note']);
119
+ params.blockletScreenshots || (params.blockletScreenshots = []);
120
+ return params;
121
+ };
77
122
  function CreateRelease(_ref2) {
78
- var _tabs$;
123
+ var _tabs$, _params$blockletIntro, _params$note;
79
124
  let rest = Object.assign({}, (_objectDestructuringEmpty(_ref2), _ref2));
80
125
  const navigate = (0, _reactRouterDom.useNavigate)();
81
126
  const {
@@ -89,6 +134,7 @@ function CreateRelease(_ref2) {
89
134
  blocklet
90
135
  } = (0, _blocklet.useBlockletContext)();
91
136
  const [params, setParams] = (0, _useSetState.default)(null);
137
+ const [paramsErrTip, setParamsErrTip] = (0, _react.useState)({});
92
138
  const [loading, setLoading] = (0, _react.useState)(false);
93
139
  const [release, setRelease] = (0, _react.useState)(null);
94
140
  const {
@@ -128,7 +174,7 @@ function CreateRelease(_ref2) {
128
174
  setParams(pickParams(data));
129
175
  }).catch(err => {
130
176
  setLoading(false);
131
- _Toast.default.error(err.message);
177
+ _Toast.default.error((0, _util.formatError)(err));
132
178
  });
133
179
  };
134
180
  const getRelease = () => {
@@ -144,7 +190,7 @@ function CreateRelease(_ref2) {
144
190
  setRelease(res === null || res === void 0 ? void 0 : res.release);
145
191
  }).catch(err => {
146
192
  setLoading(false);
147
- _Toast.default.error(err.message);
193
+ _Toast.default.error((0, _util.formatError)(err));
148
194
  });
149
195
  };
150
196
  const getData = () => {
@@ -164,28 +210,21 @@ function CreateRelease(_ref2) {
164
210
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
165
211
 
166
212
  const onRelease = status => {
167
- if (!params.blockletTitle) {
168
- _Toast.default.error(t('blocklet.publish.errorTip.noTitle'));
213
+ const errors = validateParams(params, status, t);
214
+ if (errors) {
215
+ _Toast.default.error(errors.map(x => x.message).join('; '));
216
+ setParamsErrTip(errors.reduce((acc, x) => _objectSpread(_objectSpread({}, acc), {}, {
217
+ [x.param]: x.message
218
+ }), {}));
169
219
  return;
170
220
  }
171
- if (!params.blockletVersion) {
172
- _Toast.default.error(t('blocklet.publish.errorTip.noVersion'));
173
- return;
174
- }
175
- if (status === _constant.PROJECT.RELEASE_STATUS.published) {
176
- if (!params.blockletDescription) {
177
- _Toast.default.error(t('blocklet.publish.errorTip.noDescription'));
178
- return;
179
- }
180
- if (!params.note) {
181
- _Toast.default.error(t('blocklet.publish.errorTip.noNote'));
182
- return;
183
- }
184
- }
185
221
  const _params = _objectSpread({}, params);
186
222
  _params.blockletVersion = _semver.default.valid(_params.blockletVersion);
187
223
  if (!_params.blockletVersion) {
188
224
  _Toast.default.error('Invalid Blocklet Version');
225
+ setParamsErrTip({
226
+ blockletVersion: 'Invalid Blocklet Version'
227
+ });
189
228
  return;
190
229
  }
191
230
  _params.blockletTitle = (_params.blockletTitle || '').trim();
@@ -214,7 +253,7 @@ function CreateRelease(_ref2) {
214
253
  });
215
254
  }
216
255
  }).catch(err => {
217
- _Toast.default.error(err.message);
256
+ _Toast.default.error((0, _util.formatError)(err));
218
257
  });
219
258
  };
220
259
  if (!params && loading) {
@@ -304,7 +343,7 @@ function CreateRelease(_ref2) {
304
343
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
305
344
  label: "Blocklet ".concat(t('common.title')),
306
345
  placeholder: "Blocklet ".concat(t('common.title')),
307
- inputProps: {
346
+ InputProps: {
308
347
  'data-cy': 'blocklet-title',
309
348
  readOnly
310
349
  },
@@ -313,14 +352,19 @@ function CreateRelease(_ref2) {
313
352
  fullWidth: true,
314
353
  value: params.blockletTitle || '',
315
354
  onChange: e => {
355
+ setParamsErrTip({
356
+ blockletTitle: ''
357
+ });
316
358
  setParams({
317
359
  blockletTitle: e.target.value
318
360
  });
319
- }
361
+ },
362
+ error: !!paramsErrTip.blockletTitle,
363
+ helperText: paramsErrTip.blockletTitle || ''
320
364
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
321
365
  label: "Blocklet ".concat(t('common.description')),
322
366
  placeholder: "Blocklet ".concat(t('common.description')),
323
- inputProps: {
367
+ InputProps: {
324
368
  'data-cy': 'blocklet-description',
325
369
  readOnly
326
370
  },
@@ -329,31 +373,45 @@ function CreateRelease(_ref2) {
329
373
  fullWidth: true,
330
374
  value: params.blockletDescription || '',
331
375
  onChange: e => {
376
+ setParamsErrTip({
377
+ blockletDescription: ''
378
+ });
332
379
  setParams({
333
380
  blockletDescription: e.target.value
334
381
  });
335
382
  },
383
+ error: !!paramsErrTip.blockletDescription,
384
+ helperText: paramsErrTip.blockletDescription || '',
336
385
  sx: {
337
386
  mt: 3
338
387
  }
339
388
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
340
389
  label: "Blocklet ".concat(t('common.introduction')),
341
390
  placeholder: "Blocklet ".concat(t('common.introduction')),
342
- inputProps: {
391
+ InputProps: {
343
392
  'data-cy': 'export-blocklet-introduction',
344
- readOnly
393
+ readOnly,
394
+ endAdornment: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_InputAdornment.default, {
395
+ position: "end",
396
+ children: [(params === null || params === void 0 ? void 0 : (_params$blockletIntro = params.blockletIntroduction) === null || _params$blockletIntro === void 0 ? void 0 : _params$blockletIntro.length) || 0, " / ", _constant.PROJECT.MAX_INTRO_LENGTH]
397
+ })
345
398
  },
346
399
  autoComplete: "off",
347
400
  variant: "outlined",
348
401
  fullWidth: true,
349
402
  multiline: true,
350
- rows: 4,
403
+ minRows: 4,
351
404
  value: params.blockletIntroduction || '',
352
405
  onChange: e => {
406
+ setParamsErrTip({
407
+ blockletIntroduction: ''
408
+ });
353
409
  setParams({
354
- blockletIntroduction: e.target.value
410
+ blockletIntroduction: e.target.value.slice(0, _constant.PROJECT.MAX_INTRO_LENGTH)
355
411
  });
356
412
  },
413
+ error: !!paramsErrTip.blockletIntroduction,
414
+ helperText: paramsErrTip.blockletIntroduction || '',
357
415
  sx: {
358
416
  mt: 3
359
417
  }
@@ -374,7 +432,7 @@ function CreateRelease(_ref2) {
374
432
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
375
433
  label: "Blocklet ".concat(t('common.version')),
376
434
  placeholder: "Blocklet ".concat(t('common.version')),
377
- inputProps: {
435
+ InputProps: {
378
436
  'data-cy': 'blocklet-version',
379
437
  readOnly
380
438
  },
@@ -383,27 +441,41 @@ function CreateRelease(_ref2) {
383
441
  fullWidth: true,
384
442
  value: params.blockletVersion,
385
443
  onChange: e => {
444
+ setParamsErrTip({
445
+ blockletVersion: ''
446
+ });
386
447
  setParams({
387
448
  blockletVersion: e.target.value
388
449
  });
389
- }
450
+ },
451
+ error: !!paramsErrTip.blockletVersion,
452
+ helperText: paramsErrTip.blockletVersion || ''
390
453
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextField.default, {
391
454
  label: t('blocklet.publish.releaseNote'),
392
455
  autoComplete: "off",
393
456
  variant: "outlined",
394
- inputProps: {
457
+ InputProps: {
395
458
  'data-cy': 'release-note',
396
- readOnly
459
+ readOnly,
460
+ endAdornment: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_InputAdornment.default, {
461
+ position: "end",
462
+ children: [(params === null || params === void 0 ? void 0 : (_params$note = params.note) === null || _params$note === void 0 ? void 0 : _params$note.length) || 0, " / ", _constant.PROJECT.MAX_NOTE_LENGTH]
463
+ })
397
464
  },
398
465
  fullWidth: true,
399
466
  multiline: true,
400
- rows: 4,
467
+ minRows: 4,
401
468
  value: params.note,
402
469
  onChange: e => {
470
+ setParamsErrTip({
471
+ note: ''
472
+ });
403
473
  setParams({
404
- note: e.target.value
474
+ note: e.target.value.slice(0, _constant.PROJECT.MAX_NOTE_LENGTH)
405
475
  });
406
476
  },
477
+ error: !!paramsErrTip.note,
478
+ helperText: paramsErrTip.note || '',
407
479
  sx: {
408
480
  mt: 3
409
481
  }
@@ -503,11 +575,19 @@ function CreateRelease(_ref2) {
503
575
  setParams({
504
576
  blockletLogo: result.data.filename
505
577
  });
578
+ uploaderLogoRef.current.close();
506
579
  },
507
- plugins: ['ImageEditor', 'Url', 'Webcam'],
580
+ plugins: [],
508
581
  apiPathProps: {
509
582
  uploader: uploadLogoPrefix,
510
583
  disableMediaKitPrefix: true
584
+ },
585
+ coreProps: {
586
+ restrictions: {
587
+ allowedFileTypes,
588
+ maxFileSize,
589
+ maxNumberOfFiles: 1
590
+ }
511
591
  }
512
592
  }, "uploader-screenshot"), /*#__PURE__*/(0, _jsxRuntime.jsx)(UploaderComponent, {
513
593
  id: "\u200Buploader-screenshot",
@@ -520,11 +600,19 @@ function CreateRelease(_ref2) {
520
600
  setParams({
521
601
  blockletScreenshots
522
602
  });
603
+ uploaderScreenshotRef.current.close();
523
604
  },
524
- plugins: ['ImageEditor', 'Url', 'Webcam'],
605
+ plugins: [],
525
606
  apiPathProps: {
526
607
  uploader: uploadScreenshotPrefix,
527
608
  disableMediaKitPrefix: true
609
+ },
610
+ coreProps: {
611
+ restrictions: {
612
+ allowedFileTypes,
613
+ maxFileSize,
614
+ maxNumberOfFiles: 5 - screenshotUrls.length
615
+ }
528
616
  }
529
617
  }, "uploader-screenshot")]
530
618
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
@@ -559,7 +647,7 @@ function CreateRelease(_ref2) {
559
647
  }
560
648
  CreateRelease.propTypes = {};
561
649
  CreateRelease.defaultProps = {};
562
- const Main = _styled.default.div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n .sticky-header {\n margin-top: -12px;\n padding: 12px 0;\n position: sticky;\n top: 0;\n z-index: 99;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background-color: #fff;\n padding-bottom: 12px;\n border-bottom: ", ";\n }\n .screenshot {\n margin-bottom: 16px;\n max-width: 200px;\n max-height: 140px;\n width: 200px;\n height: 140px;\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: #eee;\n margin-right: 16px;\n position: relative;\n .action {\n visibility: hidden;\n position: absolute;\n top: 0px;\n right: 0px;\n background-color: rgba(0, 0, 0, 0.2);\n color: rgba(255, 255, 255, 0.8);\n }\n &:hover .action {\n visibility: visible;\n }\n }\n .screenshot img {\n width: 100%; /* \u56FE\u50CF\u5BBD\u5EA6\u586B\u5145\u5BB9\u5668 */\n height: auto; /* \u56FE\u50CF\u9AD8\u5EA6\u81EA\u9002\u5E94 */\n }\n .section {\n max-width: 800px;\n &.full-width {\n max-width: 100%;\n }\n .MuiTypography-h3 {\n font-size: 1.1rem;\n font-weight: 700;\n }\n .left {\n flex-shrink: 0;\n width: 140px;\n }\n .MuiTabs-root {\n margin-top: 8px;\n transform: translateX(-16px);\n .MuiButtonBase-root .text {\n color: ", ";\n }\n .MuiButtonBase-root.Mui-selected .text {\n color: ", ";\n }\n }\n .MuiTabs-indicator {\n display: none;\n }\n .MuiTypography-subtitle1 {\n width: 120px;\n font-weight: 700;\n font-size: 1rem;\n ", " {\n width: 80px;\n }\n }\n }\n .MuiButtonBase-root {\n a {\n color: inherit;\n }\n }\n"])), _ref3 => {
650
+ const Main = _styled.default.div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n .sticky-header {\n margin-top: -12px;\n padding: 12px 0;\n position: sticky;\n top: 0;\n z-index: 99;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background-color: #fff;\n padding-bottom: 12px;\n border-bottom: ", ";\n }\n .screenshot {\n margin-bottom: 16px;\n max-width: 200px;\n max-height: 140px;\n width: 200px;\n height: 140px;\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: #eee;\n margin-right: 16px;\n position: relative;\n .action {\n visibility: hidden;\n position: absolute;\n top: 0px;\n right: 0px;\n background-color: rgba(0, 0, 0, 0.2);\n color: rgba(255, 255, 255, 0.8);\n }\n &:hover .action {\n visibility: visible;\n }\n }\n .screenshot img {\n width: 100%; /* \u56FE\u50CF\u5BBD\u5EA6\u586B\u5145\u5BB9\u5668 */\n height: auto; /* \u56FE\u50CF\u9AD8\u5EA6\u81EA\u9002\u5E94 */\n }\n .section {\n max-width: 800px;\n &.full-width {\n max-width: 100%;\n }\n .MuiTypography-h3 {\n font-size: 1.1rem;\n font-weight: 700;\n }\n .left {\n flex-shrink: 0;\n width: 140px;\n }\n .MuiTabs-root {\n margin-top: 8px;\n transform: translateX(-16px);\n .MuiButtonBase-root .text {\n color: ", ";\n }\n .MuiButtonBase-root.Mui-selected .text {\n color: ", ";\n }\n }\n .MuiTabs-indicator {\n display: none;\n }\n .MuiTypography-subtitle1 {\n width: 120px;\n font-weight: 700;\n font-size: 1rem;\n ", " {\n width: 80px;\n }\n }\n }\n .MuiButtonBase-root {\n a {\n color: inherit;\n }\n }\n .MuiInputBase-multiline .MuiInputAdornment-positionEnd {\n align-self: flex-end;\n .MuiTypography-root {\n font-size: 0.8rem;\n }\n font-size: 0.8rem;\n }\n"])), _ref3 => {
563
651
  let {
564
652
  theme
565
653
  } = _ref3;
@@ -14,6 +14,8 @@ var _Delete = _interopRequireDefault(require("@mui/icons-material/Delete"));
14
14
  var _Datatable = _interopRequireDefault(require("@arcblock/ux/lib/Datatable"));
15
15
  var _Button = _interopRequireDefault(require("@arcblock/ux/lib/Button"));
16
16
  var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
17
+ var _Tag = _interopRequireDefault(require("@arcblock/ux/lib/Tag"));
18
+ var _RelativeTime = _interopRequireDefault(require("@arcblock/ux/lib/RelativeTime"));
17
19
  var _blocklet = require("../../contexts/blocklet");
18
20
  var _node = require("../../contexts/node");
19
21
  var _emptySpinner = _interopRequireDefault(require("../../empty-spinner"));
@@ -114,7 +116,7 @@ function ProjectList() {
114
116
  });
115
117
  }
116
118
  const columns = [{
117
- label: t('common.name'),
119
+ label: 'Blocklet',
118
120
  name: 'blockletTitle',
119
121
  options: {
120
122
  customBodyRenderLite: rawIndex => {
@@ -126,7 +128,7 @@ function ProjectList() {
126
128
  }
127
129
  }
128
130
  }, {
129
- label: t('common.address'),
131
+ label: 'DID',
130
132
  name: 'blockletDid',
131
133
  options: {
132
134
  customBodyRender: e => {
@@ -137,6 +139,28 @@ function ProjectList() {
137
139
  });
138
140
  }
139
141
  }
142
+ }, {
143
+ label: 'Version',
144
+ name: 'blockletVersion',
145
+ options: {
146
+ customBodyRender: value => {
147
+ return value ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tag.default, {
148
+ type: "success",
149
+ children: value
150
+ }) : '';
151
+ }
152
+ }
153
+ }, {
154
+ label: t('common.updatedAt'),
155
+ name: 'updatedAt',
156
+ options: {
157
+ customBodyRender: value => {
158
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_RelativeTime.default, {
159
+ value: Number(value),
160
+ locale: locale
161
+ });
162
+ }
163
+ }
140
164
  }, {
141
165
  label: t('common.actions'),
142
166
  name: 'actions',
@@ -21,6 +21,8 @@ var _constant = require("@abtnode/constant");
21
21
  var _Button = _interopRequireDefault(require("@arcblock/ux/lib/Button"));
22
22
  var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
23
23
  var _Tag = _interopRequireDefault(require("@arcblock/ux/lib/Tag"));
24
+ var _RelativeTime = _interopRequireDefault(require("@arcblock/ux/lib/RelativeTime"));
25
+ var _constant2 = require("@blocklet/constant");
24
26
  var _blocklet = require("../../contexts/blocklet");
25
27
  var _node = require("../../contexts/node");
26
28
  var _emptySpinner = _interopRequireDefault(require("../../empty-spinner"));
@@ -196,6 +198,21 @@ function ReleaseList() {
196
198
  });
197
199
  }
198
200
  }
201
+ }, {
202
+ label: t('common.lastPublishedAt'),
203
+ name: 'updatedAt',
204
+ options: {
205
+ customBodyRenderLite: rawIndex => {
206
+ const release = releases[rawIndex];
207
+ if (release.status !== _constant2.PROJECT.RELEASE_STATUS.published) {
208
+ return '';
209
+ }
210
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_RelativeTime.default, {
211
+ value: Number(release.updatedAt),
212
+ locale: locale
213
+ });
214
+ }
215
+ }
199
216
  }, {
200
217
  label: t('common.actions'),
201
218
  name: 'actions',
@@ -204,11 +221,15 @@ function ReleaseList() {
204
221
  const release = releases[rawIndex];
205
222
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Box.default, {
206
223
  display: "flex",
224
+ alignItems: "center",
207
225
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_IconButton.default, {
208
226
  color: "primary",
209
227
  "aria-label": "download",
210
228
  disabled: release.status !== 'published',
211
229
  children: release.status === 'published' ? /*#__PURE__*/(0, _jsxRuntime.jsx)("a", {
230
+ style: {
231
+ display: 'flex'
232
+ },
212
233
  href: (0, _urlJoin.default)("".concat(_constant.WELLKNOWN_SERVICE_PATH_PREFIX, "/api/project/").concat(blocklet.meta.did, "/").concat(project.id, "/").concat(release.id, "/download/").concat((release.files || [])[0])),
213
234
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Download.default, {
214
235
  sx: {
@@ -7,6 +7,7 @@ exports.validateSite = exports.validateRule = exports.validatePathPrefix = expor
7
7
  var _constant = require("@abtnode/constant");
8
8
  var _isPathPrefixEqual = _interopRequireDefault(require("@abtnode/util/lib/is-path-prefix-equal"));
9
9
  var _constant2 = require("@blocklet/constant");
10
+ var _hasStartEngine = _interopRequireDefault(require("@blocklet/meta/lib/has-start-engine"));
10
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
12
  /* eslint-disable import/prefer-default-export */
12
13
 
@@ -86,7 +87,7 @@ const validatePathPrefix = _ref => {
86
87
  } = _ref;
87
88
  // validate children
88
89
  if (curBlocklet) {
89
- let exist = (curBlocklet.children || []).find(x => (0, _isPathPrefixEqual.default)(x.mountPoint, params.pathPrefix));
90
+ let exist = (curBlocklet.children || []).find(x => (0, _hasStartEngine.default)(x.meta) && (0, _isPathPrefixEqual.default)(x.mountPoint, params.pathPrefix));
90
91
  if (curBlocklet.meta.group !== 'gateway' && params.pathPrefix === '/') {
91
92
  exist = '/';
92
93
  }
package/lib/locales/en.js CHANGED
@@ -634,6 +634,7 @@ module.exports = {
634
634
  saveDraft: 'Save Draft',
635
635
  releaseNote: 'Release Note',
636
636
  errorTip: {
637
+ noDid: 'Blocklet DID is required',
637
638
  noTitle: 'Blocklet Title is required',
638
639
  noVersion: 'Blocklet Version is required',
639
640
  noDescription: 'Blocklet Description is required',
@@ -1315,7 +1316,8 @@ module.exports = {
1315
1316
  launchFailed: 'Failed to launch the app, please try again',
1316
1317
  installedButStopped: 'The app is installed successfully, but cannot be started. You can start it manually after resolving blocking issues',
1317
1318
  installedButError: 'The app is successfully installed, but failed to start',
1318
- restoreFailed: 'Failed to restore app, please try again'
1319
+ restoreFailed: 'Failed to restore app, please try again',
1320
+ resourceBlocklet: 'Resource Blocklet cannot be installed as an application, you can mount this blocklet into existing applications.'
1319
1321
  },
1320
1322
  steps: {
1321
1323
  introduction: 'Introduction',
package/lib/locales/zh.js CHANGED
@@ -641,6 +641,7 @@ module.exports = {
641
641
  saveDraft: '保存草稿',
642
642
  releaseNote: '发布说明',
643
643
  errorTip: {
644
+ noDid: '请填写 Blocklet DID',
644
645
  noTitle: '请填写 Blocklet 名称',
645
646
  noVersion: '请填写 Blocklet 版本号',
646
647
  noDescription: '请填写 Blocklet 描述',
@@ -1320,7 +1321,8 @@ module.exports = {
1320
1321
  launchFailed: '启动应用失败,请重试',
1321
1322
  installedButStopped: '应用安装成功,但是无法启动,解决启动问题之后后可手动启动',
1322
1323
  installedButError: '应用已经安装,但是运行出错了',
1323
- restoreFailed: '还原应用失败,请重试'
1324
+ restoreFailed: '还原应用失败,请重试',
1325
+ resourceBlocklet: '资源 Blocklet 无法作为应用被安装,你可以将该 Blocklet 挂载到现有的应用中。'
1324
1326
  },
1325
1327
  steps: {
1326
1328
  introduction: '简介',
@@ -8,6 +8,7 @@ var _react = require("react");
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var _context = require("@arcblock/ux/lib/Locale/context");
10
10
  var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
11
+ var _passport = require("@abtnode/util/lib/passport");
11
12
  var _confirm = _interopRequireDefault(require("../../confirm"));
12
13
  var _node = require("../../contexts/node");
13
14
  var _team = require("../../contexts/team");
@@ -88,7 +89,9 @@ function ToggleUserApproval(_ref) {
88
89
  color: user.approved ? 'error' : 'primary'
89
90
  };
90
91
  let can;
91
- if (!inService) {
92
+ if ((0, _passport.hasActiveOwnerPassport)(user)) {
93
+ can = false;
94
+ } else if (!inService) {
92
95
  can = nodeInfo.nodeOwner && !isNodeOwner(nodeInfo, user.did) && !isSelf(session.user, user.did);
93
96
  } else {
94
97
  can = !isSelf(session.user, user.did);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abtnode/ux",
3
- "version": "1.16.17-beta-d282d63e",
3
+ "version": "1.16.17-beta-4f13d99d",
4
4
  "description": "UX components shared across abtnode packages",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -27,24 +27,24 @@
27
27
  "author": "linchen <linchen1987@foxmail.com> (http://github.com/linchen1987)",
28
28
  "license": "Apache-2.0",
29
29
  "dependencies": {
30
- "@abtnode/auth": "1.16.17-beta-d282d63e",
31
- "@abtnode/constant": "1.16.17-beta-d282d63e",
32
- "@abtnode/util": "1.16.17-beta-d282d63e",
30
+ "@abtnode/auth": "1.16.17-beta-4f13d99d",
31
+ "@abtnode/constant": "1.16.17-beta-4f13d99d",
32
+ "@abtnode/util": "1.16.17-beta-4f13d99d",
33
33
  "@ahooksjs/use-url-state": "^3.5.1",
34
- "@arcblock/did": "^1.18.91",
35
- "@arcblock/did-connect": "^2.7.25",
34
+ "@arcblock/did": "^1.18.92",
35
+ "@arcblock/did-connect": "^2.7.27",
36
36
  "@arcblock/did-motif": "^1.1.13",
37
- "@arcblock/icons": "^2.7.25",
38
- "@arcblock/nft-display": "2.7.25",
39
- "@arcblock/react-hooks": "^2.7.25",
40
- "@arcblock/terminal": "^2.7.25",
41
- "@arcblock/ux": "^2.7.25",
42
- "@blocklet/constant": "1.16.17-beta-d282d63e",
43
- "@blocklet/launcher-layout": "2.2.19",
37
+ "@arcblock/icons": "^2.7.27",
38
+ "@arcblock/nft-display": "2.7.27",
39
+ "@arcblock/react-hooks": "^2.7.27",
40
+ "@arcblock/terminal": "^2.7.27",
41
+ "@arcblock/ux": "^2.7.27",
42
+ "@blocklet/constant": "1.16.17-beta-4f13d99d",
43
+ "@blocklet/launcher-layout": "2.2.21",
44
44
  "@blocklet/list": "^0.12.45",
45
- "@blocklet/meta": "1.16.17-beta-d282d63e",
46
- "@blocklet/ui-react": "^2.7.25",
47
- "@blocklet/uploader": "^0.0.24",
45
+ "@blocklet/meta": "1.16.17-beta-4f13d99d",
46
+ "@blocklet/ui-react": "^2.7.27",
47
+ "@blocklet/uploader": "^0.0.26",
48
48
  "@emotion/react": "^11.10.4",
49
49
  "@emotion/styled": "^11.10.4",
50
50
  "@iconify/react": "^4.0.0",
@@ -54,7 +54,7 @@
54
54
  "@mui/material": "^5.14.10",
55
55
  "@mui/styles": "^5.14.10",
56
56
  "@mui/x-date-pickers": "^6.14.0",
57
- "@ocap/client": "1.18.91",
57
+ "@ocap/client": "1.18.92",
58
58
  "@uiw/react-markdown-preview": "4.0.6",
59
59
  "ahooks": "^3.7.1",
60
60
  "axios": "^0.27.2",
@@ -100,7 +100,7 @@
100
100
  "babel-plugin-inline-react-svg": "^1.1.2",
101
101
  "glob": "^10.3.3"
102
102
  },
103
- "gitHead": "b675be55d76903e8b92d98cfca7d960fcfedd98f",
103
+ "gitHead": "005478c4b14448f2ae896ae363972afbde1d7e7b",
104
104
  "exports": {
105
105
  ".": {
106
106
  "import": "./es/index.js",