@abtnode/ux 1.16.14-beta-ab7f615e → 1.16.14-beta-cb53c14b

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 (202) hide show
  1. package/es/actions.js +97 -0
  2. package/es/analytics/card.js +92 -0
  3. package/es/analytics/chart.js +96 -0
  4. package/es/analytics/cpu.js +36 -0
  5. package/es/analytics/disk.js +111 -0
  6. package/es/analytics/memory.js +72 -0
  7. package/es/analytics/runtime.js +173 -0
  8. package/es/analytics/traffic.js +259 -0
  9. package/es/blocklet/access/config-access.js +307 -0
  10. package/es/blocklet/access/index.js +216 -0
  11. package/es/blocklet/actions.js +474 -0
  12. package/es/blocklet/add-cert.js +177 -0
  13. package/es/blocklet/agreement-app.js +21 -0
  14. package/es/blocklet/agreement.js +127 -0
  15. package/es/blocklet/app-avatar.js +57 -0
  16. package/es/blocklet/audit-logs.js +259 -0
  17. package/es/blocklet/blocklet-source.js +48 -0
  18. package/es/blocklet/bundle-avatar.js +64 -0
  19. package/es/blocklet/component/add.js +1308 -0
  20. package/es/blocklet/component/configuration.js +122 -0
  21. package/es/blocklet/component/delete.js +134 -0
  22. package/es/blocklet/component/environment.js +370 -0
  23. package/es/blocklet/component/index.js +975 -0
  24. package/es/blocklet/component/line.js +20 -0
  25. package/es/blocklet/component/navigation/locale-tabs.js +225 -0
  26. package/es/blocklet/component/navigation/navigation-actions.js +112 -0
  27. package/es/blocklet/component/navigation/navigation-dialog.js +607 -0
  28. package/es/blocklet/component/navigation/navigation-preview.js +101 -0
  29. package/es/blocklet/component/navigation/simple-select.js +124 -0
  30. package/es/blocklet/component/select-store.js +155 -0
  31. package/es/blocklet/component/setting.js +109 -0
  32. package/es/blocklet/component/sortable-tree.js +126 -0
  33. package/es/blocklet/component/space-connector.js +199 -0
  34. package/es/blocklet/component/space-selector.js +178 -0
  35. package/es/blocklet/component/start.js +101 -0
  36. package/es/blocklet/component/store-blocklet-list.js +200 -0
  37. package/es/blocklet/component/switch-control.js +57 -0
  38. package/es/blocklet/config-navigation.js +331 -0
  39. package/es/blocklet/configuration.js +603 -0
  40. package/es/blocklet/disk-info.js +75 -0
  41. package/es/blocklet/icons.js +18 -0
  42. package/es/blocklet/install-from-url.js +337 -0
  43. package/es/blocklet/log.js +90 -0
  44. package/es/blocklet/migration.js +149 -0
  45. package/es/blocklet/mode.js +19 -0
  46. package/es/blocklet/notification/email.js +257 -0
  47. package/es/blocklet/notification/index.js +49 -0
  48. package/es/blocklet/oauth/auth0.js +145 -0
  49. package/es/blocklet/oauth/common-settings.js +133 -0
  50. package/es/blocklet/oauth/federated-detail-dialog.js +175 -0
  51. package/es/blocklet/oauth/federated-invite-dialog.js +83 -0
  52. package/es/blocklet/oauth/federated-join-dialog.js +111 -0
  53. package/es/blocklet/oauth/federated-site-list.js +338 -0
  54. package/es/blocklet/oauth/federated.js +81 -0
  55. package/es/blocklet/oauth/index.js +69 -0
  56. package/es/blocklet/overview.js +293 -0
  57. package/es/blocklet/page-group.js +19 -0
  58. package/es/blocklet/preferences/app-sk.js +142 -0
  59. package/es/blocklet/preferences/index.js +305 -0
  60. package/es/blocklet/purchase/common.js +95 -0
  61. package/es/blocklet/purchase/component-purchase.js +237 -0
  62. package/es/blocklet/purchase/index.js +4 -0
  63. package/es/blocklet/router/action/add-domain-alias.js +167 -0
  64. package/es/blocklet/router/action/add-rule.js +211 -0
  65. package/es/blocklet/router/action/config-routing-rule.js +232 -0
  66. package/es/blocklet/router/action/delete-domain-alias.js +99 -0
  67. package/es/blocklet/router/action/delete-rule.js +108 -0
  68. package/es/blocklet/router/action/update-rule.js +209 -0
  69. package/es/blocklet/router/domain-actions.js +64 -0
  70. package/es/blocklet/router/domain-status.js +88 -0
  71. package/es/blocklet/router/rule-actions.js +66 -0
  72. package/es/blocklet/router/rule-list.js +190 -0
  73. package/es/blocklet/router/util.js +131 -0
  74. package/es/blocklet/runtime-info.js +68 -0
  75. package/es/blocklet/status.js +91 -0
  76. package/es/blocklet/storage/action.js +134 -0
  77. package/es/blocklet/storage/backups.js +241 -0
  78. package/es/blocklet/storage/connect-to.js +373 -0
  79. package/es/blocklet/storage/connected.js +198 -0
  80. package/es/blocklet/storage/delete.js +113 -0
  81. package/es/blocklet/storage/disconnect.js +243 -0
  82. package/es/blocklet/storage/index.js +19 -0
  83. package/es/blocklet/storage/item.js +558 -0
  84. package/es/blocklet/storage/preview-nft.js +286 -0
  85. package/es/blocklet/transfer-owner.js +198 -0
  86. package/es/blocklet/types.js +18 -0
  87. package/es/blocklet/util.js +145 -0
  88. package/es/blocklet/version.js +141 -0
  89. package/es/card-selector.js +134 -0
  90. package/es/certificate.js +105 -0
  91. package/es/chain.js +13 -0
  92. package/es/click-to-copy.js +22 -0
  93. package/es/confirm.js +149 -0
  94. package/es/contexts/audit-log.js +152 -0
  95. package/es/contexts/blocklet.js +10 -0
  96. package/es/contexts/deleting-blocklets.js +70 -0
  97. package/es/contexts/node.js +17 -0
  98. package/es/contexts/session.js +8 -0
  99. package/es/contexts/team.js +10 -0
  100. package/es/delete-confirm.js +121 -0
  101. package/es/did-address.js +46 -0
  102. package/es/dot.js +14 -0
  103. package/es/exchange-passport.js +102 -0
  104. package/es/form/form-select-input.js +184 -0
  105. package/es/form/form-text-input.js +178 -0
  106. package/es/form/form-wrapper.js +88 -0
  107. package/es/form/input-triggers.js +98 -0
  108. package/es/form/required.js +8 -0
  109. package/es/hooks/blocklet.js +229 -0
  110. package/es/hooks/confirm.js +90 -0
  111. package/es/hooks/mobile-width.js +11 -0
  112. package/es/hooks/url-evaluation.js +155 -0
  113. package/es/hooks/use-app-logo.js +16 -0
  114. package/es/hooks/use-backup-progress.js +31 -0
  115. package/es/hooks/use-blocklet-info-for-connect-did-spaces.js +50 -0
  116. package/es/hooks/use-bundle-logo.js +27 -0
  117. package/es/hooks/use-navigation.js +347 -0
  118. package/es/hooks/use-passport-id.js +14 -0
  119. package/es/hooks/use-subscription.js +22 -0
  120. package/es/icons/empty-space-nft.svg +59 -0
  121. package/es/icons/empty-spaces-nft.svg +58 -0
  122. package/es/icons/long-arrow.svg +5 -0
  123. package/es/icons/space-connected.svg +3 -0
  124. package/es/icons/space-disconnect.svg +3 -0
  125. package/es/index.js +3 -0
  126. package/es/invitation/invitation-app.js +58 -0
  127. package/es/invitation/invitation-login.js +68 -0
  128. package/es/invitation/invitation-passport.js +144 -0
  129. package/es/invitation/invitation-receive.js +138 -0
  130. package/es/invitation/invitation-success.js +93 -0
  131. package/es/invitation/invitation-user.js +90 -0
  132. package/es/invitation/invitation.js +90 -0
  133. package/es/issue-passport.js +142 -0
  134. package/es/launch-blocklet/content-layout.js +58 -0
  135. package/es/launch-blocklet/page-header.js +43 -0
  136. package/es/layout/addon.js +114 -0
  137. package/es/layout/feedback.js +55 -0
  138. package/es/locales/en.js +1534 -0
  139. package/es/locales/index.js +9 -0
  140. package/es/locales/zh.js +1537 -0
  141. package/es/logs/clock.js +11 -0
  142. package/es/logs/download.js +132 -0
  143. package/es/logs/log-terminal.js +253 -0
  144. package/es/lost-passport.js +452 -0
  145. package/es/nav-logo.js +219 -0
  146. package/es/passport-tag.js +43 -0
  147. package/es/permission.js +57 -0
  148. package/es/relative-time.js +53 -0
  149. package/es/result-message.js +11 -0
  150. package/es/schema-form/color-input.js +98 -0
  151. package/es/schema-form/common-prop-types.js +13 -0
  152. package/es/schema-form/index.js +215 -0
  153. package/es/schema-form/passport-input.js +54 -0
  154. package/es/schema-form/text-input.js +57 -0
  155. package/es/store/add.js +179 -0
  156. package/es/store/delete.js +96 -0
  157. package/es/store/item.js +76 -0
  158. package/es/subscription.js +144 -0
  159. package/es/table-icons.js +34 -0
  160. package/es/table.js +52 -0
  161. package/es/tag.js +21 -0
  162. package/es/team/members/actions.js +89 -0
  163. package/es/team/members/index.js +636 -0
  164. package/es/team/members/invitations.js +188 -0
  165. package/es/team/members/invite-member.js +208 -0
  166. package/es/team/members/issue-passport.js +152 -0
  167. package/es/team/members/member.js +408 -0
  168. package/es/team/members/passport-issuances.js +155 -0
  169. package/es/team/members/passports.js +364 -0
  170. package/es/team/members/toggle-user-approval.js +122 -0
  171. package/es/team/members/transfer-node.js +256 -0
  172. package/es/team/members/util.js +14 -0
  173. package/es/team/passports/color.js +126 -0
  174. package/es/team/passports/detail.js +312 -0
  175. package/es/team/passports/index.js +282 -0
  176. package/es/team/passports/mutate-role.js +198 -0
  177. package/es/team/passports/trusted-factories.js +221 -0
  178. package/es/team/passports/trusted-factory.js +343 -0
  179. package/es/team/passports/trusted-issuer.js +296 -0
  180. package/es/team/passports/trusted-issuers.js +226 -0
  181. package/es/team/search-input.js +46 -0
  182. package/es/team/styles/dialog.js +72 -0
  183. package/es/team/styles/list-header.js +31 -0
  184. package/es/util/api.js +6 -0
  185. package/es/util/constants.js +2 -0
  186. package/es/util/index.js +598 -0
  187. package/es/util/mode.js +4 -0
  188. package/es/util/space-gateway.js +51 -0
  189. package/es/util/spaces.js +151 -0
  190. package/es/who-can-access/config.js +38 -0
  191. package/es/wrap-locale.js +15 -0
  192. package/lib/blocklet/component/space-connector.js +1 -1
  193. package/lib/blocklet/component/space-selector.js +1 -1
  194. package/lib/blocklet/storage/backups.js +1 -1
  195. package/lib/blocklet/storage/connect-to.js +1 -1
  196. package/lib/blocklet/storage/connected.js +1 -1
  197. package/lib/blocklet/storage/disconnect.js +1 -1
  198. package/lib/blocklet/storage/index.js +1 -1
  199. package/lib/blocklet/storage/item.js +1 -1
  200. package/lib/invitation/invitation-receive.js +1 -1
  201. package/lib/team/passports/trusted-factory.js +1 -1
  202. package/package.json +81 -18
@@ -0,0 +1,229 @@
1
+ import { useState, useMemo, useEffect } from 'react';
2
+ import merge from 'lodash/merge';
3
+ import omit from 'lodash/omit';
4
+ import { BlockletEvents, fromBlockletStatus } from '@blocklet/constant';
5
+ import Toast from '@arcblock/ux/lib/Toast';
6
+ import { toSlotDomain, getBlockletUrlParams, getBlockletUrl } from '../util';
7
+ import { fixBlocklet } from '../blocklet/util';
8
+ import { useDomainsAccessibility } from './url-evaluation';
9
+
10
+ // eslint-disable-next-line import/prefer-default-export
11
+ export function useBlocklet({
12
+ did,
13
+ client,
14
+ useSubscription,
15
+ getIP,
16
+ useLocaleContext,
17
+ disableSubscription
18
+ }) {
19
+ const {
20
+ t,
21
+ locale
22
+ } = useLocaleContext();
23
+ const [error, setError] = useState(null);
24
+ const [loading, setLoading] = useState(false);
25
+ const [loadingRuntimeInfo, setLoadingRuntimeInfo] = useState(false);
26
+ const [blocklet, setBlocklet] = useState();
27
+ const [runtimeHistory, setRuntimeHistory] = useState({
28
+ cpu: [],
29
+ memory: []
30
+ });
31
+ const [domainStatus, setDomainStatus] = useState({});
32
+ const domainListStr = blocklet?.site?.domainAliases?.length ? JSON.stringify(blocklet.site.domainAliases.map(x => x.value)) : '';
33
+ const domains = useMemo(() => (blocklet?.site?.domainAliases || []).map(x => x.value), [domainListStr]); // eslint-disable-line
34
+
35
+ const {
36
+ domainsAccessibility,
37
+ recommendedDomain
38
+ } = useDomainsAccessibility(domains);
39
+ const refreshRuntimeInfo = async () => {
40
+ setLoadingRuntimeInfo(true);
41
+ try {
42
+ const {
43
+ blocklet: data
44
+ } = await client.getBlocklet({
45
+ input: {
46
+ did,
47
+ attachRuntimeInfo: true
48
+ }
49
+ });
50
+ await fixBlocklet(data, {
51
+ getIP
52
+ });
53
+ setBlocklet(data);
54
+ } catch (err) {
55
+ Toast.error(err.message);
56
+ } finally {
57
+ setLoadingRuntimeInfo(false);
58
+ }
59
+ };
60
+ const getRuntimeHistory = async () => {
61
+ try {
62
+ const data = await client.getBlockletRuntimeHistory({
63
+ input: {
64
+ did,
65
+ hours: 6
66
+ }
67
+ });
68
+ if (data) {
69
+ setRuntimeHistory({
70
+ cpu: data.history.map(x => ({
71
+ date: x.date,
72
+ value: x.cpu
73
+ })),
74
+ memory: data.history.map(x => ({
75
+ date: x.date,
76
+ value: x.mem
77
+ }))
78
+ });
79
+ }
80
+ } catch (err) {
81
+ Toast.error(err.message);
82
+ }
83
+ };
84
+ const refreshBlocklet = async ({
85
+ showError = true,
86
+ attachRuntimeInfo = true
87
+ } = {}) => {
88
+ if (loading) {
89
+ return;
90
+ }
91
+ try {
92
+ setLoading(true);
93
+ setError(null);
94
+ const {
95
+ blocklet: data
96
+ } = await client.getBlocklet({
97
+ input: {
98
+ did
99
+ }
100
+ });
101
+ if (data) {
102
+ setBlocklet(oldBlocklet => {
103
+ fixBlocklet(data, {
104
+ fixRuntime: 'merge-old',
105
+ oldBlocklet
106
+ });
107
+ return data;
108
+ });
109
+ setLoading(false);
110
+ if (attachRuntimeInfo) {
111
+ refreshRuntimeInfo();
112
+ getRuntimeHistory();
113
+ }
114
+ } else {
115
+ throw new Error(t('blocklet.notFound'));
116
+ }
117
+ } catch (err) {
118
+ setLoading(false);
119
+ setError(err);
120
+ if (showError) {
121
+ Toast.error(err.message);
122
+ }
123
+ }
124
+ };
125
+ const handleRefresh = data => {
126
+ if (data?.meta?.did === blocklet.meta.did) {
127
+ refreshBlocklet({
128
+ showError: false
129
+ });
130
+ }
131
+ };
132
+ const handleRefreshWithoutRuntime = data => {
133
+ if (data?.meta?.did === blocklet.meta.did) {
134
+ refreshBlocklet({
135
+ attachRuntimeInfo: false,
136
+ showError: false
137
+ });
138
+ }
139
+ };
140
+ const refreshDomainStatus = () => {
141
+ if (did && domainListStr) {
142
+ client.checkDomains({
143
+ input: {
144
+ did
145
+ }
146
+ }).catch(err => {
147
+ console.error(err);
148
+ });
149
+ }
150
+ };
151
+ const configNavigations = async value => {
152
+ const {
153
+ blocklet: data
154
+ } = await client.configNavigations({
155
+ input: {
156
+ did,
157
+ navigations: value
158
+ }
159
+ });
160
+ setBlocklet(data);
161
+ };
162
+ useEffect(() => {
163
+ if (domainListStr && !disableSubscription) {
164
+ refreshDomainStatus();
165
+ }
166
+ }, [domainListStr, disableSubscription]); // eslint-disable-line
167
+
168
+ useSubscription(BlockletEvents.domainStatus, data => {
169
+ setDomainStatus(pre => ({
170
+ ...pre,
171
+ [data.domain]: {
172
+ ...pre[data.domain],
173
+ ...data
174
+ }
175
+ }));
176
+ }, [blocklet?.meta?.did, !disableSubscription]);
177
+ useSubscription(BlockletEvents.statusChange, data => {
178
+ if (data?.meta?.did === blocklet.meta.did) {
179
+ setBlocklet(oldBlocklet => {
180
+ const newBlocklet = {
181
+ ...oldBlocklet
182
+ };
183
+ newBlocklet.status = fromBlockletStatus(data.status);
184
+ (newBlocklet.children || []).forEach(x => {
185
+ const y = data.children.find(z => z.meta?.did === x.meta?.did);
186
+ if (y) {
187
+ x.status = fromBlockletStatus(y.status);
188
+ }
189
+ });
190
+ return newBlocklet;
191
+ });
192
+ handleRefreshWithoutRuntime(data);
193
+ }
194
+ }, [blocklet?.meta?.did, !disableSubscription]); // eslint-disable-line prettier/prettier
195
+ useSubscription(BlockletEvents.storeChange, handleRefreshWithoutRuntime, [blocklet?.meta?.did, !disableSubscription]);
196
+ useSubscription(BlockletEvents.installed, handleRefresh, [blocklet?.meta?.did, !disableSubscription]);
197
+ useSubscription(BlockletEvents.upgraded, handleRefresh, [blocklet?.meta?.did, !disableSubscription]);
198
+ useSubscription(BlockletEvents.updated, handleRefresh, [blocklet?.meta?.did, !disableSubscription]);
199
+ const data = blocklet ? merge(blocklet, {
200
+ site: {
201
+ domainAliases: blocklet.site.domainAliases.map(x => {
202
+ const domain = x.value;
203
+ const key = toSlotDomain(domain);
204
+ x.domainStatus = omit(domainStatus[key], ['domain', 'meta']);
205
+ x.accessibility = omit(domainsAccessibility[domain], ['domain']);
206
+ x.href = getBlockletUrl({
207
+ blocklet,
208
+ domain: x,
209
+ params: getBlockletUrlParams(blocklet, locale)
210
+ });
211
+ return x;
212
+ })
213
+ }
214
+ }) : null;
215
+ return {
216
+ loading,
217
+ loadingRuntimeInfo,
218
+ error,
219
+ blocklet: data,
220
+ runtimeHistory,
221
+ recommendedDomain: recommendedDomain || '',
222
+ actions: {
223
+ refreshBlocklet,
224
+ refreshDomainStatus,
225
+ setBlocklet,
226
+ configNavigations
227
+ }
228
+ };
229
+ }
@@ -0,0 +1,90 @@
1
+ import { useContext, forwardRef, useRef, useImperativeHandle } from 'react';
2
+ import { Confirm } from '@arcblock/ux/lib/Dialog';
3
+ import { useMemoizedFn, useReactive } from 'ahooks';
4
+ import noop from 'lodash/noop';
5
+ import { LocaleContext } from '@arcblock/ux/lib/Locale/context';
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ const ConfirmHolder = /*#__PURE__*/forwardRef((props, ref) => {
8
+ const {
9
+ t
10
+ } = useContext(LocaleContext);
11
+ const state = useReactive({
12
+ show: false,
13
+ title: '',
14
+ content: '',
15
+ onConfirm: noop,
16
+ onCancel: noop
17
+ });
18
+ const open = useMemoizedFn((params = {}) => {
19
+ state.show = true;
20
+ state.title = params.title;
21
+ state.content = params.content;
22
+ state.onConfirm = params.onConfirm || noop;
23
+ state.onCancel = params.onCancel || noop;
24
+ });
25
+ const reset = useMemoizedFn(() => {
26
+ state.title = '';
27
+ state.content = '';
28
+ state.onConfirm = noop;
29
+ state.onCancel = noop;
30
+ });
31
+ const close = useMemoizedFn(() => {
32
+ state.show = false;
33
+ setTimeout(() => {
34
+ reset();
35
+ }, 300);
36
+ });
37
+ const onCancel = useMemoizedFn(() => {
38
+ close();
39
+ state?.onCancel();
40
+ }, []);
41
+ const onConfirm = useMemoizedFn(() => {
42
+ state?.onConfirm(close);
43
+ }, []);
44
+ useImperativeHandle(ref, () => {
45
+ return {
46
+ open,
47
+ close
48
+ };
49
+ }, [open, close]);
50
+ return /*#__PURE__*/_jsx(Confirm, {
51
+ open: state.show,
52
+ title: state.title,
53
+ onConfirm: onConfirm,
54
+ onCancel: onCancel,
55
+ confirmButton: {
56
+ text: t('common.confirm'),
57
+ props: {
58
+ variant: 'contained',
59
+ color: 'primary'
60
+ }
61
+ },
62
+ cancelButton: {
63
+ text: t('common.cancel'),
64
+ props: {
65
+ variant: 'outlined',
66
+ color: 'primary'
67
+ }
68
+ },
69
+ children: state.content
70
+ });
71
+ });
72
+ export default function useConfirm() {
73
+ const confirmRef = useRef(null);
74
+ const open = useMemoizedFn((...args) => {
75
+ confirmRef.current?.open(...args);
76
+ });
77
+ const close = useMemoizedFn((...args) => {
78
+ confirmRef.current?.close(...args);
79
+ });
80
+ const confirmApi = {
81
+ open,
82
+ close
83
+ };
84
+ return {
85
+ confirmHolder: /*#__PURE__*/_jsx(ConfirmHolder, {
86
+ ref: confirmRef
87
+ }),
88
+ confirmApi
89
+ };
90
+ }
@@ -0,0 +1,11 @@
1
+ import { useTheme } from '@mui/styles';
2
+ import useMediaQuery from '@mui/material/useMediaQuery';
3
+ function useMobileWidth() {
4
+ const theme = useTheme();
5
+ const isBreakpointsDownSm = useMediaQuery(theme.breakpoints.down('md'));
6
+ const minWidth = isBreakpointsDownSm ? 300 : theme.breakpoints.values.sm;
7
+ return {
8
+ minWidth
9
+ };
10
+ }
11
+ export default useMobileWidth;
@@ -0,0 +1,155 @@
1
+ import { useState, useEffect, useMemo, useRef, useContext } from 'react';
2
+ import joinUrl from 'url-join';
3
+ import memoize from 'lodash/memoize';
4
+ import { WELLKNOWN_PING_PREFIX } from '@abtnode/constant';
5
+ import { evaluateURLs } from '@abtnode/util/lib/url-evaluation';
6
+ import defaultCheckAccessible from '@abtnode/util/lib/url-evaluation/check-accessible-browser';
7
+ import { LocaleContext } from '@arcblock/ux/lib/Locale/context';
8
+ import { getAccessUrl, getBlockletUrlParams, getBlockletUrls } from '../util';
9
+
10
+ // 如果同一个页面中存在多个部分同时对同一个 url 检测 url 可访问性, 避免造成重复请求
11
+ const ping = memoize(url => {
12
+ const {
13
+ origin,
14
+ hostname
15
+ } = new URL(url);
16
+ if (hostname === window.location.hostname) {
17
+ return true;
18
+ }
19
+ return defaultCheckAccessible(joinUrl(origin, WELLKNOWN_PING_PREFIX));
20
+ });
21
+
22
+ // url <-> evaluation cache
23
+ const CACHE = {};
24
+ export function useUrlEvaluation({
25
+ urls,
26
+ checkAccessible = defaultCheckAccessible,
27
+ disableCache = false
28
+ }) {
29
+ // 基于 CACHE 初始化该 hook 的状态
30
+ // FIXME: 最好解决源头的 material-table 渲染 BlockletInterface 时的 re-mount 问题 (#4897)
31
+ const initialCachedRef = useRef(urls.filter(url => CACHE[url]).map(url => CACHE[url]));
32
+ const allCached = initialCachedRef.current.length === urls.length;
33
+ const [urlsState, setUrlsState] = useState(allCached ? initialCachedRef.current : []);
34
+ const [loading, setLoading] = useState(!allCached);
35
+ const recommendedUrlState = useMemo(() => {
36
+ if (!loading && urlsState.length) {
37
+ return urlsState[0];
38
+ }
39
+ return null;
40
+ }, [urlsState, loading]);
41
+ useEffect(() => {
42
+ if (urls?.length > 0 && !allCached) {
43
+ const evaluate = async () => {
44
+ let results;
45
+ setLoading(true);
46
+ if (disableCache) {
47
+ results = await evaluateURLs(urls, {
48
+ checkAccessible
49
+ });
50
+ results.forEach(item => {
51
+ CACHE[item.url] = item;
52
+ });
53
+ } else {
54
+ const misses = await evaluateURLs(urls.filter(url => !CACHE[url]), {
55
+ checkAccessible
56
+ });
57
+ misses.forEach(item => {
58
+ CACHE[item.url] = item;
59
+ });
60
+ results = urls.map(url => CACHE[url]).sort((a, b) => b.score - a.score);
61
+ }
62
+ setUrlsState(results);
63
+ setLoading(false);
64
+ };
65
+ evaluate();
66
+ }
67
+ // eslint-disable-next-line react-hooks/exhaustive-deps
68
+ }, [urls, disableCache, allCached]);
69
+ return {
70
+ urlsState,
71
+ loading,
72
+ recommendedUrlState,
73
+ recommendedUrl: recommendedUrlState?.url
74
+ };
75
+ }
76
+
77
+ /**
78
+ * 主要对 blocklet 访问 urls 进行评估
79
+ * @param {object} blocklet
80
+ */
81
+ export function useBlockletUrlEvaluation(blocklet) {
82
+ const {
83
+ locale
84
+ } = useContext(LocaleContext);
85
+ const urls = useMemo(() => {
86
+ if (!blocklet) {
87
+ return [];
88
+ }
89
+ // getBlockletUrlParams 的调用是必须的, 会根据 blocklet 状态决定是否添加 "__start__" 参数, 以保证 blocklet 启动按钮可以正确的跳转到启动页面
90
+ return getBlockletUrls({
91
+ blocklet,
92
+ params: getBlockletUrlParams(blocklet, locale)
93
+ });
94
+ }, [blocklet, locale]);
95
+ const {
96
+ loading,
97
+ recommendedUrlState,
98
+ recommendedUrl
99
+ } = useUrlEvaluation({
100
+ urls,
101
+ checkAccessible: ping
102
+ });
103
+ return {
104
+ urls,
105
+ loading,
106
+ recommendedUrlState,
107
+ recommendedUrl
108
+ };
109
+ }
110
+
111
+ /**
112
+ * 主要对 blocklet domains 对应的 urls 进行评估, 配合 DomainStatusProvider 使用
113
+ * @param {string[]} domains
114
+ */
115
+ export function useDomainsAccessibility(domains) {
116
+ // 获取 blocklet domain 对应的访问 url
117
+ const urls = useMemo(() => domains.map(item => getAccessUrl(item)), [domains]);
118
+ const {
119
+ urlsState,
120
+ loading,
121
+ recommendedUrl
122
+ } = useUrlEvaluation({
123
+ urls,
124
+ checkAccessible: ping
125
+ });
126
+ let result;
127
+ if (loading) {
128
+ result = {
129
+ domainsAccessibility: domains.reduce((acc, cur) => ({
130
+ ...acc,
131
+ [cur]: {
132
+ loading: true
133
+ }
134
+ }), {}),
135
+ recommendedDomain: null
136
+ };
137
+ } else {
138
+ const domainsAccessibility = urlsState.reduce((acc, cur) => {
139
+ // 检测对象是 domain, 但检测可访问性用的是 domain 对应的 ping url, 所以需要取 hostname 作为结果
140
+ const domain = new URL(cur.url).hostname;
141
+ acc[domain] = {
142
+ ...cur,
143
+ domain
144
+ };
145
+ return acc;
146
+ }, {});
147
+ // 从排好优先级的 urls 中选择第一个可访问的 url 作为 recommendedDomain (对于自定义域名, 可能存在评分最高但不可访问的情况) (#5195)
148
+ const accessibleUrl = urlsState.find(item => item.accessible)?.url || recommendedUrl;
149
+ result = {
150
+ domainsAccessibility,
151
+ recommendedDomain: accessibleUrl ? new URL(accessibleUrl).hostname : null
152
+ };
153
+ }
154
+ return result;
155
+ }
@@ -0,0 +1,16 @@
1
+ import joinUrl from 'url-join';
2
+ import { useNodeContext } from '../contexts/node';
3
+ import { isInstalling } from '../util';
4
+ export default function useAppLogo({
5
+ blocklet
6
+ }) {
7
+ const {
8
+ inService
9
+ } = useNodeContext();
10
+ const prefix = window.env?.apiPrefix || '/';
11
+ const search = `?v=${blocklet?.meta?.version}${isInstalling(blocklet?.status) ? '~' : ''}`;
12
+ const logoUrl = joinUrl(prefix, `/blocklet/logo/${inService ? '' : blocklet.meta.did}`, search);
13
+ return {
14
+ logoUrl
15
+ };
16
+ }
@@ -0,0 +1,31 @@
1
+ import { useState } from 'react';
2
+ import { BlockletEvents } from '@blocklet/constant';
3
+ import { useNodeContext } from '../contexts/node';
4
+
5
+ /**
6
+ * @description 实时显示备份的进度
7
+ * @param {{appDid: string}} {appDid}
8
+ * @return {{message: string, progress: number, completed: boolean}}
9
+ */
10
+ function useBackupProgress({
11
+ appDid
12
+ }) {
13
+ const [progress, setProgress] = useState({
14
+ message: '',
15
+ progress: 0,
16
+ completed: false
17
+ });
18
+ const node = useNodeContext();
19
+ const {
20
+ ws: {
21
+ useSubscription
22
+ }
23
+ } = node;
24
+ useSubscription(BlockletEvents.backupProgress, data => {
25
+ setProgress(() => ({
26
+ ...data
27
+ }));
28
+ }, [appDid]);
29
+ return progress;
30
+ }
31
+ export default useBackupProgress;
@@ -0,0 +1,50 @@
1
+ import { getAppDescription, getAppName } from '@blocklet/meta/lib/util';
2
+
3
+ /**
4
+ *
5
+ *
6
+ * @param {import('@abtnode/client').BlockletState} blocklet
7
+ * @return {{
8
+ * appDid: string,
9
+ * appName: string,
10
+ * appDescription: string,
11
+ * appUrl: string,
12
+ * scopes: string,
13
+ * referrer: string,
14
+ * isReady: string,
15
+ * }}
16
+ */
17
+ function useBlockletInfoForConnectDIDSpaces({
18
+ blocklet
19
+ }) {
20
+ const {
21
+ appDid
22
+ } = blocklet;
23
+ const appName = getAppName(blocklet);
24
+ const appDescription = getAppDescription(blocklet);
25
+ const appUrls = blocklet?.site?.domainAliases?.sort((a, b) => {
26
+ if (a.accessibility.accessible && b.accessibility.accessible) {
27
+ return +a.isProtected - +b.isProtected;
28
+ }
29
+ return +b.accessibility.accessible - +a.accessibility.accessible;
30
+ })?.map(domainAlias => {
31
+ const protocol = domainAlias?.domainStatus?.isHttps ? 'https://' : 'http://';
32
+ const value = domainAlias?.value;
33
+ return `${protocol}${value}`;
34
+ }).filter(Boolean);
35
+ const appUrl = appUrls?.[0];
36
+ const scopes = 'list:object read:object write:object';
37
+ const referrer = window.location.href;
38
+
39
+ // 授权的时候提供 appUrl, 因为 appUrl 可能很久都拿不到值,所以加一个 isReady 来表示就绪状态
40
+ return {
41
+ appDid,
42
+ appName,
43
+ appDescription,
44
+ appUrl,
45
+ scopes,
46
+ referrer,
47
+ isReady: Boolean(appUrl)
48
+ };
49
+ }
50
+ export default useBlockletInfoForConnectDIDSpaces;
@@ -0,0 +1,27 @@
1
+ import joinUrl from 'url-join';
2
+ import { WELLKNOWN_SERVICE_PATH_PREFIX } from '@abtnode/constant';
3
+ import { useNodeContext } from '../contexts/node';
4
+ import { formatRegistryLogoPath, APP_PREFIX, isDownloading } from '../util';
5
+ export default function useAvatar({
6
+ blocklet,
7
+ ancestors = []
8
+ }) {
9
+ const node = useNodeContext();
10
+ const {
11
+ inService
12
+ } = node;
13
+ const search = `?v=${blocklet?.meta?.version}${isDownloading(blocklet?.status) ? '~' : ''}`;
14
+ let logoUrl = inService ? joinUrl(APP_PREFIX, WELLKNOWN_SERVICE_PATH_PREFIX, '/blocklet/logo-bundle', search) : joinUrl(node.imgPrefix, 'blocklet.png');
15
+ if (blocklet.source === 'registry' && blocklet.deployedFrom && blocklet.meta.logo) {
16
+ logoUrl = joinUrl(blocklet.deployedFrom, formatRegistryLogoPath(blocklet.meta.bundleDid, blocklet.meta.logo), search);
17
+ } else {
18
+ const prefix = window.env.apiPrefix || '/';
19
+ const components = ancestors.concat(blocklet);
20
+ const list = inService ? components.slice(1) : components;
21
+ logoUrl = joinUrl(prefix, `/blocklet/logo-bundle${list.map(x => `/${x.meta.did}`).join('')}`, search);
22
+ }
23
+ return {
24
+ logoUrl,
25
+ inService
26
+ };
27
+ }