@arcblock/ux 2.7.15 → 2.7.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/es/Dialog/confirm.js +10 -8
  2. package/es/Img/index.js +7 -7
  3. package/es/SessionManager/account-item.js +133 -0
  4. package/es/SessionManager/add-account-item.js +100 -0
  5. package/es/SessionManager/federated-login-detecter.js +37 -33
  6. package/es/SessionManager/index.js +119 -259
  7. package/es/SessionManager/manage-accounts.js +156 -0
  8. package/es/SessionManager/manage-blocklet.js +70 -0
  9. package/es/SessionManager/menu-accordion.js +104 -0
  10. package/es/SessionManager/translation.js +52 -0
  11. package/es/SessionManager/use-config.js +34 -0
  12. package/es/SessionManager/user-info.js +147 -0
  13. package/es/SessionManager/user-popper.js +10 -53
  14. package/es/SessionManager/utils.js +2 -0
  15. package/es/Typography/index.js +89 -0
  16. package/es/Util/federated.js +65 -0
  17. package/es/Util/index.js +7 -0
  18. package/lib/Dialog/confirm.js +9 -7
  19. package/lib/Img/index.js +7 -7
  20. package/lib/SessionManager/account-item.js +141 -0
  21. package/lib/SessionManager/add-account-item.js +108 -0
  22. package/lib/SessionManager/federated-login-detecter.js +38 -33
  23. package/lib/SessionManager/index.js +122 -272
  24. package/lib/SessionManager/manage-accounts.js +168 -0
  25. package/lib/SessionManager/manage-blocklet.js +86 -0
  26. package/lib/SessionManager/menu-accordion.js +112 -0
  27. package/lib/SessionManager/translation.js +59 -0
  28. package/lib/SessionManager/use-config.js +41 -0
  29. package/lib/SessionManager/user-info.js +163 -0
  30. package/lib/SessionManager/user-popper.js +8 -8
  31. package/lib/SessionManager/utils.js +16 -0
  32. package/lib/Typography/index.js +100 -0
  33. package/lib/Util/federated.js +85 -0
  34. package/lib/Util/index.js +11 -2
  35. package/package.json +12 -5
  36. package/src/Dialog/confirm.js +9 -6
  37. package/src/Img/index.js +5 -5
  38. package/src/SessionManager/account-item.jsx +109 -0
  39. package/src/SessionManager/add-account-item.jsx +97 -0
  40. package/src/SessionManager/federated-login-detecter.jsx +42 -29
  41. package/src/SessionManager/index.jsx +131 -259
  42. package/src/SessionManager/manage-accounts.jsx +157 -0
  43. package/src/SessionManager/manage-blocklet.jsx +70 -0
  44. package/src/SessionManager/menu-accordion.jsx +94 -0
  45. package/src/SessionManager/translation.js +52 -0
  46. package/src/SessionManager/use-config.js +33 -0
  47. package/src/SessionManager/user-info.jsx +116 -0
  48. package/src/SessionManager/user-popper.jsx +6 -51
  49. package/src/SessionManager/utils.js +3 -0
  50. package/src/Typography/index.jsx +79 -0
  51. package/src/Util/federated.js +73 -0
  52. package/src/Util/index.js +8 -0
  53. /package/src/Avatar/{did-motif.js → did-motif.jsx} +0 -0
  54. /package/src/Avatar/{index.js → index.jsx} +0 -0
  55. /package/src/Header/{auto-hidden.js → auto-hidden.jsx} +0 -0
  56. /package/src/Header/{header.js → header.jsx} +0 -0
  57. /package/src/Header/{responsive-header.js → responsive-header.jsx} +0 -0
@@ -1,10 +1,11 @@
1
1
  import PropTypes from 'prop-types';
2
- import { useCallback, useState } from 'react';
2
+ import { useCallback } from 'react';
3
3
  import Box from '@mui/material/Box';
4
4
  import Chip from '@mui/material/Chip';
5
5
  import Divider from '@mui/material/Divider';
6
- import SvgIcon from '@mui/material/SvgIcon';
7
- import ShieldCheck from 'mdi-material-ui/ShieldCheck';
6
+ import ShieldCheckIcon from '@iconify-icons/mdi/shield-check';
7
+ import { Icon } from '@iconify/react';
8
+ import { useCreation, useReactive } from 'ahooks';
8
9
 
9
10
  import UserPopper from './user-popper';
10
11
  import DidAvatar from '../Avatar';
@@ -39,10 +40,13 @@ const translations = {
39
40
  };
40
41
 
41
42
  export default function FederatedLoginDetecter({ session, anchorEl, dark, locale: _locale }) {
42
- const [federatedLoginOpen, setFederatedLoginOpen] = useState(true);
43
+ const state = useReactive({
44
+ open: true,
45
+ });
43
46
 
44
- const siteInfo = session.federatedMaster?.site;
45
- const userInfo = session.federatedMaster?.user;
47
+ const federatedMaster = useCreation(() => {
48
+ return session.federatedMaster;
49
+ }, [session?.federatedMaster]);
46
50
 
47
51
  const localeList = Object.keys(translations);
48
52
  const locale = localeList.includes(_locale) ? _locale : localeList[0];
@@ -53,19 +57,19 @@ export default function FederatedLoginDetecter({ session, anchorEl, dark, locale
53
57
  if (err) {
54
58
  Toast.error(err || translations[_locale].loginFederatedFailed);
55
59
  } else {
56
- setFederatedLoginOpen(false);
60
+ state.open = false;
57
61
  }
58
62
  },
59
63
  {
60
- provider: 'federated',
61
- mode: userInfo ? 'auto' : 'manual',
64
+ sourceAppPid: federatedMaster?.site?.appPid,
65
+ mode: federatedMaster?.user ? 'auto' : 'manual',
62
66
  }
63
67
  );
64
- }, [session, userInfo, _locale]);
68
+ }, [session, federatedMaster?.site?.appPid, federatedMaster?.user, _locale, state]);
65
69
 
66
70
  let appLogoUrl;
67
- if (siteInfo) {
68
- appLogoUrl = new URL(siteInfo.appLogo, siteInfo.appUrl);
71
+ if (federatedMaster?.site) {
72
+ appLogoUrl = new URL(federatedMaster.site.appLogo, federatedMaster.site.appUrl);
69
73
  appLogoUrl.searchParams.set('imageFilter', 'resize');
70
74
  // HACK: 保持跟其他地方使用的尺寸一致,可以复用同一资源的缓存,减少网络请求
71
75
  appLogoUrl.searchParams.set('w', '80');
@@ -73,26 +77,35 @@ export default function FederatedLoginDetecter({ session, anchorEl, dark, locale
73
77
  }
74
78
 
75
79
  return (
76
- siteInfo && (
80
+ federatedMaster?.site && (
77
81
  <UserPopper
78
- open={federatedLoginOpen}
82
+ open={state.open}
79
83
  anchorEl={anchorEl}
80
84
  dark={dark}
81
85
  autoClose={false}
82
- onClose={() => setFederatedLoginOpen(false)}>
86
+ onClose={() => {
87
+ state.open = false;
88
+ }}>
83
89
  <Box p={2}>
84
- {siteInfo && (
90
+ {federatedMaster.site && (
85
91
  <Box display="flex" alignItems="center">
86
- <Box component="img" mr={2} src={appLogoUrl.href} alt={siteInfo.appName} width="30px" height="30px" />
92
+ <Box
93
+ component="img"
94
+ mr={2}
95
+ src={appLogoUrl.href}
96
+ alt={federatedMaster.site.appName}
97
+ width="30px"
98
+ height="30px"
99
+ />
87
100
  <Box sx={{ maxWidth: '260px' }}>
88
101
  {translations[locale].useToConnect({
89
102
  master: (
90
103
  <Box
91
104
  component="a"
92
- href={siteInfo.appUrl}
105
+ href={federatedMaster.site.appUrl}
93
106
  target="_blank"
94
107
  sx={{ textDecoration: 'none', fontWeight: 'bold', color: 'primary.main', fontSize: '1.2em' }}>
95
- {siteInfo.appName}
108
+ {federatedMaster.site.appName}
96
109
  </Box>
97
110
  ),
98
111
  member: window.blocklet.appName,
@@ -100,34 +113,34 @@ export default function FederatedLoginDetecter({ session, anchorEl, dark, locale
100
113
  </Box>
101
114
  </Box>
102
115
  )}
103
- {siteInfo && userInfo && <Divider style={{ margin: '15px 0 10px 0' }} />}
104
- {userInfo && (
116
+ {federatedMaster?.site && federatedMaster?.user && <Divider style={{ margin: '15px 0 10px 0' }} />}
117
+ {federatedMaster?.user && (
105
118
  <Box display="flex" alignItems="center">
106
119
  <DidAvatar
107
120
  variant="circle"
108
- did={userInfo.did}
109
- src={getUserAvatar(userInfo.avatar)}
121
+ did={federatedMaster.user.did}
122
+ src={getUserAvatar(federatedMaster.user.avatar)}
110
123
  size={28}
111
124
  shape="circle"
112
125
  />
113
126
  <Box ml={2}>
114
127
  <Box display="flex" justifyContent="space-between" alignItems="center">
115
- <Box fontSize={18}>{userInfo.fullName}</Box>
116
- {userInfo.role?.toUpperCase() && (
128
+ <Box fontSize={18}>{federatedMaster.user.fullName}</Box>
129
+ {federatedMaster.user.role?.toUpperCase() && (
117
130
  <Chip
118
- label={userInfo.role?.toUpperCase()}
131
+ label={federatedMaster.user.role?.toUpperCase()}
119
132
  size="small"
120
133
  variant="outlined"
121
134
  sx={{ height: 'auto', marginRight: 0, fontSize: 12 }}
122
- icon={<SvgIcon component={ShieldCheck} style={{ fontSize: '14px' }} />}
135
+ icon={<Icon icon={ShieldCheckIcon} fontSize={14} />}
123
136
  />
124
137
  )}
125
138
  </Box>
126
- <DidAddress responsive={false}>{userInfo.did}</DidAddress>
139
+ <DidAddress responsive={false}>{federatedMaster.user.did}</DidAddress>
127
140
  </Box>
128
141
  </Box>
129
142
  )}
130
- {siteInfo && (
143
+ {federatedMaster?.site && (
131
144
  <Box display="flex" justifyContent="center" mt={2}>
132
145
  <Button variant="contained" size="small" onClick={onLoginFederated}>
133
146
  {translations[locale].connect}
@@ -1,60 +1,25 @@
1
- /* eslint-disable react/no-array-index-key */
1
+ /* eslint-disable react/prop-types */
2
2
  /* eslint-disable react/jsx-no-bind */
3
- import { useMemo, useRef, useState } from 'react';
3
+ import { useEffect, useMemo, useRef, useState } from 'react';
4
4
  import PropTypes from 'prop-types';
5
- import { Box, IconButton, MenuList, MenuItem, SvgIcon, Button, Chip, Link, CircularProgress } from '@mui/material';
6
- import SwitchProfileIcon from '@mui/icons-material/PersonOutline';
7
- import BindWalletIcon from '@mui/icons-material/Link';
8
- import SwitchPassportIcon from '@mui/icons-material/VpnKeyOutlined';
9
- import ShieldCheck from 'mdi-material-ui/ShieldCheck';
5
+ import { Box, IconButton, MenuList, Button, CircularProgress, Divider } from '@mui/material';
10
6
  import AccountIcon from '@arcblock/icons/lib/Account';
11
- import OpenInIcon from '@arcblock/icons/lib/OpenIn';
12
- import DisconnectIcon from '@arcblock/icons/lib/Disconnect';
13
- import SwitchDidIcon from '@arcblock/icons/lib/Switch';
14
- import useBrowser from '@arcblock/react-hooks/lib/useBrowser';
15
7
  import noop from 'lodash/noop';
16
- import isEmpty from 'lodash/isEmpty';
8
+ import cloneDeep from 'lodash/cloneDeep';
9
+ import { useLatest, useMemoizedFn } from 'ahooks';
17
10
 
18
11
  import DidAvatar from '../Avatar';
19
- import DidAddress from '../Address';
20
- import { getUserAvatar } from '../Util';
12
+ import { getUserAvatar, sleep } from '../Util';
21
13
  import FederatedLoginDetecter from './federated-login-detecter';
22
14
  import UserPopper from './user-popper';
23
-
24
- const translations = {
25
- en: {
26
- account: 'account',
27
- switchDid: 'Switch DID',
28
- switchTo: 'Switch to',
29
- switchProfile: 'Switch Profile',
30
- switchPassport: 'Switch Passport',
31
- disconnect: 'Disconnect',
32
- connect: 'Connect',
33
- openInWallet: 'Open DID Wallet',
34
- alreadyBindOAuth: 'Already bind Auth0',
35
- bind: 'Bind ',
36
- thirdParty: 'Third Party Login',
37
- connectedWith: 'Connected with',
38
- },
39
- zh: {
40
- account: '账号',
41
- switchDid: '切换账户',
42
- switchTo: '切换至',
43
- switchProfile: '切换用户信息',
44
- switchPassport: '切换通行证',
45
- disconnect: '退出',
46
- connect: '登录',
47
- openInWallet: '打开 DID 钱包',
48
- // NOTE: 目前只有 Auth0,展示出具体的第三方名字会更好
49
- alreadyBindOAuth: '已绑定 Auth0 账号',
50
- bind: '绑定',
51
- thirdParty: '第三方登录',
52
- connectedWith: '连接至',
53
- },
54
- };
55
-
56
- const getConnectedAccounts = (user) => user?.connectedAccounts || user?.extraConfigs?.connectedAccounts || [];
57
- const getSourceProvider = (user) => user?.sourceProvider || user?.extraConfigs?.sourceProvider || 'wallet';
15
+ import UserInfo from './user-info';
16
+ import { translate } from '../Locale/util';
17
+ import ManageAccounts from './manage-accounts';
18
+ import ManageBlocklet from './manage-blocklet';
19
+ import { translations } from './translation';
20
+ import { getConnectedAccounts, getSourceProvider } from './utils';
21
+ import useConfig from './use-config';
22
+ import { getCurrentApp, getFederatedApp } from '../Util/federated';
58
23
 
59
24
  function SessionManager({
60
25
  session,
@@ -75,27 +40,28 @@ function SessionManager({
75
40
  menuRender,
76
41
  dark,
77
42
  size,
43
+ showManageBlocklet,
78
44
  ...rest
79
45
  }) {
80
- const translation = translations[locale] || translations.en;
46
+ const latestSession = useLatest(session);
47
+ const { connectAccount, config, setConfig } = useConfig();
48
+ const t = useMemoizedFn((key, data = {}) => {
49
+ return translate(translations, key, locale, 'en', data);
50
+ });
81
51
  const userAnchorRef = useRef(null);
82
- // eslint-disable-next-line react/prop-types
83
- const { logoutOAuth, bindOAuth, configs: oauthConfigs, switchOAuthPassport } = session.useOAuth();
52
+ const { logoutOAuth, switchOAuthPassport } = session.useOAuth();
84
53
  const [userOpen, setUserOpen] = useState(false);
85
54
 
86
55
  // base64 img maybe have some blank char, need encodeURIComponent to transform it
87
56
  const avatar = getUserAvatar(session.user?.avatar?.replace(/\s/g, encodeURIComponent(' ')));
88
- const currentRole = useMemo(
89
- () => session.user?.passports?.find((item) => item.name === session.user.role),
90
- [session.user]
91
- );
92
- const browser = useBrowser();
93
- // eslint-disable-next-line react/prop-types
94
- const { walletDid } = session.useDid({ session });
95
57
 
96
58
  const isRawWalletAccount = getSourceProvider(session.user) === 'wallet';
97
59
  const connectedAccounts = getConnectedAccounts(session.user);
98
- const federatedAccount = connectedAccounts.find((item) => item.provider === 'federated');
60
+
61
+ const isFirstLoading = useMemo(() => {
62
+ return session?.initialized === false && session?.loading === true;
63
+ }, [session?.initialized, session?.loading]);
64
+
99
65
  let hasBindWallet = false;
100
66
  let hasBindAccount = false;
101
67
  if (isRawWalletAccount) {
@@ -108,20 +74,38 @@ function SessionManager({
108
74
  hasBindWallet = true;
109
75
  }
110
76
 
111
- const oauthConfigList = Object.entries(oauthConfigs)
112
- .map(([key, value]) => {
113
- return { ...value, provider: key };
114
- })
115
- .filter((item) => item.enabled);
116
-
117
- const isFirstLoading = useMemo(() => {
118
- // eslint-disable-next-line react/prop-types
119
- return session?.initialized === false && session?.loading === true;
120
- // eslint-disable-next-line react/prop-types
121
- }, [session?.initialized, session?.loading]);
77
+ const _connectAccount = useMemoizedFn(async () => {
78
+ // HACK: 强制等待组件渲染一轮,以拿到最新的 session 值
79
+ await sleep();
80
+ if (!latestSession.current?.user) {
81
+ return;
82
+ }
83
+ if (typeof window === 'undefined') {
84
+ return;
85
+ }
86
+ const blocklet = window?.blocklet;
87
+ const currentApp = getCurrentApp(blocklet);
88
+ const masterApp = getFederatedApp(blocklet);
89
+ const targetApp = latestSession.current.user.sourceAppPid ? masterApp : currentApp;
90
+ if (targetApp) {
91
+ const loginAccount = {
92
+ did: latestSession.current.user.did,
93
+ avatar: latestSession.current.user.avatar,
94
+ provider: latestSession.current.provider,
95
+ ...targetApp,
96
+ };
97
+ connectAccount(loginAccount);
98
+ }
99
+ });
122
100
 
123
- const masterSiteInfo = window.blocklet?.settings?.federated?.master;
124
- const currentSiteInfo = window.blocklet;
101
+ // HACK: 用于处理 统一登录 的自动登录情况,添加一个已连接的账号
102
+ // 同时可用于以前的站点,会自动生成一个已连接的账号
103
+ useEffect(() => {
104
+ if (session.user) {
105
+ _connectAccount();
106
+ }
107
+ // eslint-disable-next-line react-hooks/exhaustive-deps
108
+ }, [session.user]);
125
109
 
126
110
  if (!session.user) {
127
111
  return (
@@ -137,7 +121,7 @@ function SessionManager({
137
121
  {...rest}
138
122
  data-cy="sessionManager-login">
139
123
  {isFirstLoading ? <CircularProgress /> : <AccountIcon />}
140
- <span style={{ lineHeight: '25px' }}>{translation.connect}</span>
124
+ <span style={{ lineHeight: '25px' }}>{t('connect')}</span>
141
125
  </Button>
142
126
  ) : (
143
127
  <IconButton
@@ -167,16 +151,23 @@ function SessionManager({
167
151
  setUserOpen((prevOpen) => !prevOpen);
168
152
  }
169
153
 
154
+ function close() {
155
+ setUserOpen(false);
156
+ }
157
+
170
158
  function onCloseUser(e) {
171
159
  if (userAnchorRef.current && userAnchorRef.current.contains(e.target)) {
172
160
  return;
173
161
  }
174
- setUserOpen(false);
162
+ close();
175
163
  }
176
164
 
177
165
  function _onLogin() {
178
166
  if (!isFirstLoading) {
179
- session.login(onLogin);
167
+ session.login((...args) => {
168
+ _connectAccount();
169
+ onLogin(...args);
170
+ });
180
171
  }
181
172
  }
182
173
  function _onLogout() {
@@ -189,7 +180,7 @@ function SessionManager({
189
180
  console.error(err);
190
181
  })
191
182
  .finally(() => {
192
- setUserOpen(false);
183
+ close();
193
184
  });
194
185
  });
195
186
  }
@@ -197,58 +188,27 @@ function SessionManager({
197
188
  * @name 切换账户
198
189
  * @description 该功能仅在登录后才能使用,目前仅用于切换普通登录和统一登录的账户,所以会增加一些与统一登录相关的逻辑
199
190
  */
200
- function _onSwitchDid() {
201
- const { provider, user } = session;
202
- if (!user) return;
203
- let targetProvider = provider;
204
- if (provider === 'federated') {
205
- targetProvider = 'wallet';
206
- } else if (['auth0', 'wallet'].includes(provider)) {
207
- targetProvider = 'federated';
208
- }
209
- session.switchDid(
210
- (...args) => {
211
- setUserOpen(false);
212
- onSwitchDid(...args);
213
- },
214
- {
215
- provider: targetProvider,
216
- providerMode: 'paramsFirst',
217
- }
218
- );
219
- }
191
+
220
192
  function _onSwitchProfile() {
221
193
  session.switchProfile((...args) => {
222
- setUserOpen(false);
194
+ close();
223
195
  onSwitchProfile(...args);
224
196
  });
225
197
  }
198
+
226
199
  function _onSwitchPassport() {
227
200
  const { user, provider } = session;
228
- if (!isRawWalletAccount && provider !== 'federated') {
201
+ if (['auth0'].includes(provider)) {
229
202
  switchOAuthPassport(user);
230
203
  } else {
231
- setUserOpen(false);
204
+ close();
232
205
  session.switchPassport((...args) => {
233
- setUserOpen(false);
206
+ close();
234
207
  onSwitchPassport(...args);
235
208
  });
236
209
  }
237
210
  }
238
211
 
239
- function _onBindWallet() {
240
- setUserOpen(false);
241
- // FIXME: @zhanghan 暂时切换回 isRawWalletAccount 的方式来判断,在 did-connect 改版时,简化这里的关系判断
242
- if (!isRawWalletAccount) {
243
- session.bindWallet((...args) => {
244
- setUserOpen(false);
245
- onBindWallet(...args);
246
- });
247
- } else {
248
- bindOAuth();
249
- }
250
- }
251
-
252
212
  return (
253
213
  <>
254
214
  <IconButton
@@ -265,151 +225,61 @@ function SessionManager({
265
225
 
266
226
  <UserPopper open={userOpen} onClose={onCloseUser} anchorEl={userAnchorRef.current} dark={dark}>
267
227
  <MenuList sx={{ p: 0 }}>
268
- <div className="session-manager-user">
269
- <div className="session-manager-user-name" role="button" aria-label="User info panel">
270
- <span>{session.user.fullName}</span>
271
- {!!showRole && (currentRole?.title || session.user?.role.toUpperCase()) && (
272
- <Chip
273
- label={currentRole?.title || session.user?.role.toUpperCase()}
274
- size="small"
275
- variant="outlined"
276
- sx={{ height: 'auto', marginRight: 0 }}
277
- icon={<SvgIcon component={ShieldCheck} size="small" />}
278
- />
279
- )}
280
- </div>
281
- <div className="session-manager-id-list" aria-label="User DID list">
282
- {walletDid && (
283
- <div className="session-manager-id-item">
284
- <DidAddress responsive={false}>{walletDid}</DidAddress>
285
- </div>
286
- )}
287
- {federatedAccount && (
288
- <div className="session-manager-id-item">
289
- <DidAddress responsive={false}>{federatedAccount.did}</DidAddress>
290
- </div>
291
- )}
292
- {session?.user?.email && (
293
- <div className="session-manager-id-item">
294
- <DidAddress responsive={false}>{session.user.email}</DidAddress>
295
- </div>
296
- )}
297
- </div>
298
- </div>
299
- {Array.isArray(menu) &&
300
- menu.map((menuItem, index) => {
301
- const { svgIcon, ...menuProps } = menuItem;
302
- return (
303
- <MenuItem
304
- key={index}
305
- className="session-manager-menu-item"
306
- {...{
307
- ...menuProps,
308
- icon: undefined,
309
- label: undefined,
310
- }}>
311
- {svgIcon
312
- ? svgIcon && <SvgIcon component={svgIcon} className="session-manager-menu-icon" />
313
- : menuItem.icon}
314
- {menuItem.label}
315
- </MenuItem>
316
- );
317
- })}
318
- {menuRender({
319
- classes: {
320
- menuItem: 'session-manager-menu-item',
321
- menuIcon: 'session-manager-menu-icon',
322
- },
323
- })}
324
- {!browser.wallet && (
325
- <MenuItem
326
- component="a"
327
- className="session-manager-menu-item"
328
- data-cy="sessionManager-openInWallet"
329
- href="https://www.abtwallet.io/"
330
- aria-label={translation.openInWallet}
331
- target="_blank">
332
- <SvgIcon component={OpenInIcon} className="session-manager-menu-icon" />
333
- {translation.openInWallet}
334
- </MenuItem>
335
- )}
336
- {!isEmpty(masterSiteInfo) && !!switchDid && (
337
- <MenuItem
338
- className="session-manager-menu-item"
339
- onClick={_onSwitchDid}
340
- aria-label={translation.switchDid}
341
- data-cy="sessionManager-switch-trigger">
342
- <SvgIcon component={SwitchDidIcon} className="session-manager-menu-icon" />
343
- <Box sx={{ whiteSpace: 'normal', wordBreak: 'break-all' }}>
344
- {translation.switchTo}
345
- {session.provider === 'federated' ? (
346
- <Link
347
- mx={1}
348
- href={currentSiteInfo.appUrl}
349
- underline="hover"
350
- target="_blank"
351
- title={currentSiteInfo.appName}
352
- aria-label="Open current site url">
353
- {currentSiteInfo.appName}
354
- </Link>
355
- ) : (
356
- <Link
357
- mx={1}
358
- href={masterSiteInfo.appUrl}
359
- underline="hover"
360
- target="_blank"
361
- title={masterSiteInfo.appName}
362
- aria-label="Open federated master site url">
363
- {masterSiteInfo.appName}
364
- </Link>
365
- )}
366
- {translation.account}
367
- </Box>
368
- </MenuItem>
369
- )}
370
- {/* NOTE: federated 登录方式不允许切换 profile */}
371
- {!!switchProfile && hasBindWallet && session.provider !== 'federated' && (
372
- <MenuItem
373
- className="session-manager-menu-item"
374
- onClick={_onSwitchProfile}
375
- aria-label={translation.switchProfile}
376
- data-cy="sessionManager-switch-profile-trigger">
377
- <SvgIcon component={SwitchProfileIcon} className="session-manager-menu-icon" />
378
- {translation.switchProfile}
379
- </MenuItem>
380
- )}
381
- {!!switchPassport && (
382
- <MenuItem
383
- className="session-manager-menu-item"
384
- onClick={_onSwitchPassport}
385
- aria-label={translation.switchPassport}
386
- data-cy="sessionManager-switch-passport-trigger">
387
- <SvgIcon component={SwitchPassportIcon} className="session-manager-menu-icon" />
388
- {translation.switchPassport}
389
- </MenuItem>
390
- )}
391
- {oauthConfigList.length > 0 && !hasBindAccount && session.provider !== 'federated' && (
392
- <MenuItem
393
- className="session-manager-menu-item"
394
- onClick={_onBindWallet}
395
- aria-label={
396
- !isRawWalletAccount ? `${translation.bind}DID Wallet` : `${translation.bind}${translation.thirdParty}`
397
- }
398
- data-cy="sessionManager-bind-trigger">
399
- <SvgIcon component={BindWalletIcon} className="session-manager-menu-icon" />
400
- {!isRawWalletAccount ? `${translation.bind}DID Wallet` : `${translation.bind}${translation.thirdParty}`}
401
- </MenuItem>
402
- )}
228
+ <UserInfo
229
+ session={session}
230
+ size={size}
231
+ locale={locale}
232
+ onSwitchProfile={() => {
233
+ close();
234
+ _onSwitchProfile();
235
+ }}
236
+ onSwitchPassport={() => {
237
+ close();
238
+ _onSwitchPassport();
239
+ }}
240
+ close={close}
241
+ switchProfile={switchProfile}
242
+ hasBindWallet={hasBindWallet}
243
+ />
244
+
245
+ <Divider />
246
+
247
+ <ManageAccounts
248
+ session={session}
249
+ locale={locale}
250
+ onBindWallet={onBindWallet}
251
+ onSwitchDid={onSwitchDid}
252
+ connectAccount={_connectAccount}
253
+ close={close}
254
+ hasBindAccount={hasBindAccount}
255
+ onLogout={_onLogout}
256
+ expanded={config.expandAccount}
257
+ onExpand={(value) => {
258
+ const cloneConfig = cloneDeep(config);
259
+ cloneConfig.expandAccount = value;
260
+ setConfig(cloneConfig);
261
+ }}
262
+ />
403
263
 
404
- <MenuItem
405
- className="session-manager-menu-item"
406
- onClick={_onLogout}
407
- disabled={disableLogout}
408
- aria-label="Logout account"
409
- data-cy="sessionManager-logout-trigger">
410
- <SvgIcon component={DisconnectIcon} className="session-manager-menu-icon" />
411
- {translation.disconnect}
412
- </MenuItem>
264
+ {/* 为了避免控制台出现警告,采用数组的方式 */}
265
+ {/* MUI:The Menu component doesn't accept a Fragment as a child. Consider providing an array instead. */}
266
+ {showManageBlocklet
267
+ ? [
268
+ <Divider key="divider" />,
269
+ <ManageBlocklet
270
+ key="manageBlocklet"
271
+ menu={menu}
272
+ menuRender={menuRender}
273
+ locale={locale}
274
+ expanded={config.expandBlocklet}
275
+ onExpand={(value) => {
276
+ const cloneConfig = cloneDeep(config);
277
+ cloneConfig.expandBlocklet = value;
278
+ setConfig(cloneConfig);
279
+ }}
280
+ />,
281
+ ]
282
+ : null}
413
283
  </MenuList>
414
284
  </UserPopper>
415
285
  </>
@@ -419,7 +289,7 @@ function SessionManager({
419
289
  SessionManager.propTypes = {
420
290
  session: PropTypes.shape({
421
291
  federatedMaster: PropTypes.object,
422
- provider: PropTypes.oneOf(['wallet', 'federated', 'auth0', '']),
292
+ provider: PropTypes.oneOf(['wallet', 'auth0', '']),
423
293
  user: PropTypes.shape({
424
294
  did: PropTypes.string.isRequired,
425
295
  role: PropTypes.string.isRequired,
@@ -468,6 +338,7 @@ SessionManager.propTypes = {
468
338
  menuRender: PropTypes.func,
469
339
  dark: PropTypes.bool,
470
340
  size: PropTypes.number,
341
+ showManageBlocklet: PropTypes.bool,
471
342
  };
472
343
 
473
344
  SessionManager.defaultProps = {
@@ -488,6 +359,7 @@ SessionManager.defaultProps = {
488
359
  onBindWallet: noop,
489
360
  dark: false,
490
361
  size: 24,
362
+ showManageBlocklet: true,
491
363
  };
492
364
 
493
365
  export default SessionManager;