@abtnode/ux 1.16.17-beta-d282d63e → 1.16.17-beta-1cab4b42

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.
@@ -1,12 +1,35 @@
1
- /* eslint-disable no-unused-vars */
2
- /* eslint-disable react/no-unstable-nested-components */
3
- import { useState, useRef, useEffect } from 'react';
1
+ import { useState, useEffect, useMemo } from 'react';
4
2
  import PropTypes from 'prop-types';
5
3
  import styled from '@emotion/styled';
6
- import Box from '@mui/material/Box';
4
+ import difference from 'lodash/difference';
7
5
  import joinUrl from 'url-join';
6
+ import Box from '@mui/material/Box';
8
7
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
8
+ import Button from '@arcblock/ux/lib/Button';
9
+ import Toast from '@arcblock/ux/lib/Toast';
10
+ import Tree from './tree';
11
+ import { useNodeContext } from '../../contexts/node';
12
+ import { axios } from '../../util/api';
9
13
  import { jsx as _jsx } from "react/jsx-runtime";
14
+ import { jsxs as _jsxs } from "react/jsx-runtime";
15
+ const fillParent = (nodes, parentId) => {
16
+ nodes.forEach(node => {
17
+ if (parentId) {
18
+ node.parent = parentId;
19
+ }
20
+ (node.children || []).forEach(child => {
21
+ child.parent = node.id;
22
+ fillParent(child.children || [], child.id);
23
+ });
24
+ });
25
+ return nodes;
26
+ };
27
+ const checkDiff = (a, b) => {
28
+ if (a.length !== b.length) {
29
+ return true;
30
+ }
31
+ return !!difference(a, b || []).length;
32
+ };
10
33
  export default function Resource({
11
34
  app,
12
35
  component,
@@ -17,20 +40,81 @@ export default function Resource({
17
40
  t,
18
41
  locale
19
42
  } = useLocaleContext();
20
- const iframeRef = useRef(null);
43
+ const {
44
+ api
45
+ } = useNodeContext();
46
+ const [resources, setResources] = useState([]);
47
+ const [selectedResourceIds, setSelectedResourceIds] = useState([]);
48
+ const [savedResourceIds, setSavedResourceIds] = useState([]);
49
+ const [loading, setLoading] = useState(false);
21
50
  const releaseId = release.id;
22
51
  const readonly = release.status === 'published';
23
52
  const {
24
- resourceExportPage = '/'
53
+ resourceExportApi = '/'
25
54
  } = component?.meta.capabilities || {};
26
- const url = new URL(joinUrl('http://127.0.0.1', component.mountPoint, resourceExportPage).replace(/\/+/g, '/'));
27
- url.searchParams.set('projectId', projectId);
28
- url.searchParams.set('releaseId', releaseId);
29
- url.searchParams.set('local', locale);
30
- if (readonly) {
31
- url.searchParams.set('readonly', '1');
32
- }
33
- const src = `${url.pathname}${url.search}`;
55
+ const hasDiff = useMemo(() => checkDiff(savedResourceIds, selectedResourceIds), [savedResourceIds, selectedResourceIds]);
56
+ const urlObj = new URL(joinUrl('http://127.0.0.1', component.mountPoint, resourceExportApi || '/').replace(/\/+/g, '/'));
57
+ urlObj.searchParams.set('projectId', projectId);
58
+ urlObj.searchParams.set('releaseId', releaseId);
59
+ urlObj.searchParams.set('local', locale);
60
+ const url = `${urlObj.pathname}${urlObj.search}`;
61
+ const saveSelected = async data => {
62
+ try {
63
+ await api.updateSelectedResources({
64
+ input: {
65
+ did: app.meta.did,
66
+ projectId,
67
+ releaseId,
68
+ componentDid: component.meta.did,
69
+ resources: data
70
+ }
71
+ });
72
+ setSavedResourceIds(data);
73
+ } catch (err) {
74
+ Toast.error(err.message);
75
+ }
76
+ };
77
+ const onSave = async () => {
78
+ const params = selectedResourceIds;
79
+ try {
80
+ setLoading(true);
81
+ await axios.post(url, {
82
+ resources: params,
83
+ projectId,
84
+ releaseId,
85
+ locale
86
+ });
87
+ Toast.success(t('common.saveSuccess'));
88
+ setLoading(false);
89
+ saveSelected(selectedResourceIds);
90
+ } catch (err) {
91
+ setLoading(false);
92
+ Toast.error(err.message);
93
+ }
94
+ };
95
+ useEffect(() => {
96
+ axios.get(url).then(res => {
97
+ const tree = fillParent(res.data?.resources || []);
98
+ setResources(tree);
99
+ }).catch(err => {
100
+ Toast.error(err.message);
101
+ });
102
+ api.getSelectedResources({
103
+ input: {
104
+ did: app.meta.did,
105
+ projectId,
106
+ releaseId,
107
+ componentDid: component.meta.did
108
+ }
109
+ }).then(res => {
110
+ const list = res?.resources || [];
111
+ setSelectedResourceIds(list);
112
+ setSavedResourceIds(list);
113
+ }).catch(err => {
114
+ Toast.error(err.message);
115
+ });
116
+ // eslint-disable-next-line react-hooks/exhaustive-deps
117
+ }, [url]);
34
118
  if (component.status !== 'running') {
35
119
  return /*#__PURE__*/_jsx(Container, {
36
120
  children: /*#__PURE__*/_jsx(Box, {
@@ -42,12 +126,23 @@ export default function Resource({
42
126
  });
43
127
  }
44
128
  return /*#__PURE__*/_jsx(Container, {
45
- children: /*#__PURE__*/_jsx("iframe", {
46
- ref: iframeRef,
47
- title: component.meta.title,
48
- src: src,
49
- width: "100%",
50
- height: "600px"
129
+ children: /*#__PURE__*/_jsxs(Box, {
130
+ children: [/*#__PURE__*/_jsx(Tree, {
131
+ data: resources,
132
+ value: selectedResourceIds,
133
+ onChange: data => {
134
+ setSelectedResourceIds(data);
135
+ },
136
+ disabled: loading || readonly
137
+ }), !readonly && /*#__PURE__*/_jsx(Box, {
138
+ className: "footer",
139
+ children: /*#__PURE__*/_jsx(Button, {
140
+ variant: "contained",
141
+ disabled: loading || !hasDiff,
142
+ onClick: () => onSave(),
143
+ children: t('common.save')
144
+ })
145
+ })]
51
146
  })
52
147
  });
53
148
  }
@@ -66,7 +161,19 @@ Resource.defaultProps = {
66
161
  }
67
162
  };
68
163
  const Container = styled(Box)`
69
- iframe {
70
- border: none;
164
+ border: 1px solid #ccc;
165
+ border-radius: 4px;
166
+ padding: 16px;
167
+ padding-bottom: 0px;
168
+ max-height: 600px;
169
+ overflow-y: auto;
170
+ .footer {
171
+ border-top: 1px solid #ddd;
172
+ display: flex;
173
+ padding: 12px 0;
174
+ margin-top: 12px;
175
+ position: sticky;
176
+ bottom: 0;
177
+ background: #fff;
71
178
  }
72
179
  `;
@@ -0,0 +1,235 @@
1
+ import PropTypes from 'prop-types';
2
+ import styled from '@emotion/styled';
3
+ import classnames from 'classnames';
4
+ import isUrl from 'is-url';
5
+ import Box from '@mui/material/Box';
6
+ import FormControlLabel from '@mui/material/FormControlLabel';
7
+ import TreeView from '@mui/lab/TreeView';
8
+ import TreeItem from '@mui/lab/TreeItem';
9
+ import Checkbox from '@mui/material/Checkbox';
10
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
11
+ import ChevronRightIcon from '@mui/icons-material/ChevronRight';
12
+ import OpenInNewIcon from '@mui/icons-material/OpenInNew';
13
+ import { Icon } from '@iconify/react';
14
+
15
+ // BFS algorithm to find node by his ID
16
+ import { jsx as _jsx } from "react/jsx-runtime";
17
+ import { jsxs as _jsxs } from "react/jsx-runtime";
18
+ const bfsSearch = (graph, targetId) => {
19
+ const queue = [...graph];
20
+ while (queue.length > 0) {
21
+ const currNode = queue.shift();
22
+ if (currNode.id === targetId) {
23
+ return currNode;
24
+ }
25
+ if (currNode.children) {
26
+ queue.push(...currNode.children);
27
+ }
28
+ }
29
+ return []; // Target node not found
30
+ };
31
+
32
+ function ResourceIcon({
33
+ icon
34
+ }) {
35
+ if (!icon) {
36
+ return null;
37
+ }
38
+ if (isUrl(icon)) {
39
+ return /*#__PURE__*/_jsx("img", {
40
+ className: "resource-icon",
41
+ src: icon,
42
+ alt: "icon"
43
+ });
44
+ }
45
+ return /*#__PURE__*/_jsx(Icon, {
46
+ className: "resource-icon",
47
+ icon: icon
48
+ });
49
+ }
50
+ ResourceIcon.propTypes = {
51
+ icon: PropTypes.string
52
+ };
53
+ ResourceIcon.defaultProps = {
54
+ icon: ''
55
+ };
56
+ export default function Tree({
57
+ disabled,
58
+ data,
59
+ onChange,
60
+ value
61
+ }) {
62
+ const selectedNodes = value;
63
+
64
+ // Retrieve all ids from node to his children's
65
+ function getAllIds(node, idList = []) {
66
+ idList.push(node.id);
67
+ if (node.children) {
68
+ node.children.forEach(child => getAllIds(child, idList));
69
+ }
70
+ return idList;
71
+ }
72
+ // Get IDs of all children from specific node
73
+ const getAllChild = id => {
74
+ return getAllIds(bfsSearch(data, id));
75
+ };
76
+
77
+ // Get all father IDs from specific node
78
+ const getAllFathers = (id, list = []) => {
79
+ const node = bfsSearch(data, id);
80
+ if (node.parent) {
81
+ list.push(node.parent);
82
+ return getAllFathers(node.parent, list);
83
+ }
84
+ return list;
85
+ };
86
+ function isAllChildrenChecked(node, list) {
87
+ const allChild = getAllChild(node.id);
88
+ const nodeIdIndex = allChild.indexOf(node.id);
89
+ allChild.splice(nodeIdIndex, 1);
90
+ return allChild.every(nodeId => selectedNodes.concat(list).includes(nodeId));
91
+ }
92
+ const handleNodeSelect = (event, nodeId) => {
93
+ event.stopPropagation();
94
+ const allChild = getAllChild(nodeId);
95
+ const fathers = getAllFathers(nodeId);
96
+ if (selectedNodes.includes(nodeId)) {
97
+ // Need to de-check
98
+ const newValue = selectedNodes.filter(id => !allChild.concat(fathers).includes(id));
99
+ onChange(newValue);
100
+ } else {
101
+ // Need to check
102
+ const ToBeChecked = allChild;
103
+ for (let i = 0; i < fathers.length; ++i) {
104
+ if (isAllChildrenChecked(bfsSearch(data, fathers[i]), ToBeChecked)) {
105
+ ToBeChecked.push(fathers[i]);
106
+ }
107
+ }
108
+ onChange([...selectedNodes].concat(ToBeChecked));
109
+ }
110
+ };
111
+ const stopExpand = event => {
112
+ // prevent the click event from propagating to the checkbox
113
+ event.stopPropagation();
114
+ };
115
+ const hadChildren = data.some(node => node.children?.length > 0);
116
+ const renderTree = node => /*#__PURE__*/_jsx(TreeItem, {
117
+ nodeId: node.id,
118
+ label: /*#__PURE__*/_jsx(FormControlLabel, {
119
+ onClick: stopExpand,
120
+ control: /*#__PURE__*/_jsx(Checkbox, {
121
+ size: "small",
122
+ checked: selectedNodes.indexOf(node.id) !== -1,
123
+ tabIndex: -1,
124
+ disableRipple: true,
125
+ onClick: event => handleNodeSelect(event, node.id),
126
+ disabled: disabled
127
+ }),
128
+ label: /*#__PURE__*/_jsxs(Box, {
129
+ className: "content",
130
+ children: [/*#__PURE__*/_jsxs(Box, {
131
+ display: "flex",
132
+ alignItems: "center",
133
+ children: [node.icon && /*#__PURE__*/_jsx(ResourceIcon, {
134
+ icon: node.icon
135
+ }), /*#__PURE__*/_jsx(Box, {
136
+ className: "name",
137
+ children: node.name
138
+ }), node.url && /*#__PURE__*/_jsx("a", {
139
+ href: node.url,
140
+ target: "_blank",
141
+ rel: "noreferrer",
142
+ className: "link",
143
+ children: /*#__PURE__*/_jsx(OpenInNewIcon, {
144
+ className: "link-icon"
145
+ })
146
+ })]
147
+ }), !!node.description && /*#__PURE__*/_jsx(Box, {
148
+ className: "description",
149
+ children: node.description
150
+ })]
151
+ })
152
+ }),
153
+ children: Array.isArray(node.children) ? node.children.map(renderTree) : null
154
+ }, node.id);
155
+ return /*#__PURE__*/_jsx(StyledTreeView, {
156
+ className: classnames(!hadChildren && 'no-children'),
157
+ multiSelect: true,
158
+ defaultCollapseIcon: /*#__PURE__*/_jsx(ExpandMoreIcon, {}),
159
+ defaultExpandIcon: /*#__PURE__*/_jsx(ChevronRightIcon, {}),
160
+ selected: selectedNodes,
161
+ children: data.map(node => renderTree(node))
162
+ });
163
+ }
164
+ Tree.propTypes = {
165
+ data: PropTypes.array,
166
+ value: PropTypes.array,
167
+ onChange: PropTypes.func,
168
+ disabled: PropTypes.bool
169
+ };
170
+ Tree.defaultProps = {
171
+ data: [],
172
+ value: [],
173
+ onChange: () => {},
174
+ disabled: false
175
+ };
176
+ const StyledTreeView = styled(TreeView)`
177
+ &.no-children {
178
+ .MuiTreeItem-content {
179
+ padding: 0;
180
+ .MuiTreeItem-iconContainer {
181
+ display: none;
182
+ }
183
+ .MuiTreeItem-label {
184
+ padding-left: 0;
185
+ }
186
+ }
187
+ }
188
+ .MuiTreeItem-content {
189
+ align-items: flex-start;
190
+ .MuiTreeItem-iconContainer {
191
+ transform: translateY(10px);
192
+ }
193
+ &.Mui-selected {
194
+ background-color: transparent;
195
+ }
196
+ }
197
+ .MuiTreeItem-label {
198
+ cursor: default;
199
+ }
200
+ .MuiFormControlLabel-root {
201
+ align-items: flex-start;
202
+ }
203
+ .content {
204
+ padding-top: 6px;
205
+ }
206
+ .name {
207
+ font-size: 16px;
208
+ font-weight: 700;
209
+ }
210
+ .resource-icon {
211
+ margin-right: 2px;
212
+ font-size: 16px;
213
+ }
214
+ img.resource-icon {
215
+ width: 1rem;
216
+ height: 1rem;
217
+ }
218
+ .link {
219
+ margin-left: 8px;
220
+ font-size: 16px;
221
+ color: ${({
222
+ theme
223
+ }) => theme.palette.primary.main};
224
+ display: flex;
225
+ }
226
+ .link-icon {
227
+ font-size: inherit;
228
+ }
229
+ .description {
230
+ font-size: 14px;
231
+ color: ${({
232
+ theme
233
+ }) => theme.palette.text.secondary};
234
+ }
235
+ `;
@@ -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
  })]