@blocklet/ui-react 2.9.51 → 2.9.53
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.
- package/es/@types/index.d.ts +3 -5
- package/es/Dashboard/index.d.ts +5 -6
- package/es/Dashboard/index.js +5 -5
- package/es/Footer/index.js +2 -2
- package/es/Header/index.js +5 -5
- package/es/UserCenter/components/notification.js +1 -1
- package/es/UserCenter/components/passport.js +1 -2
- package/es/UserCenter/components/privacy.js +1 -1
- package/es/UserCenter/components/settings.js +9 -1
- package/es/UserCenter/components/storage/connect-to.d.ts +1 -1
- package/es/UserCenter/components/storage/connect-to.js +9 -3
- package/es/UserCenter/components/storage/connected.d.ts +1 -1
- package/es/UserCenter/components/storage/connected.js +5 -2
- package/es/UserCenter/components/storage/delete.d.ts +1 -1
- package/es/UserCenter/components/storage/delete.js +4 -1
- package/es/UserCenter/components/storage/index.js +4 -2
- package/es/UserCenter/components/storage/item.js +7 -12
- package/es/UserCenter/components/user-center.d.ts +2 -2
- package/es/UserCenter/components/user-center.js +15 -6
- package/es/UserCenter/libs/locales.d.ts +54 -0
- package/es/UserCenter/libs/locales.js +56 -2
- package/es/UserSessions/components/user-session-info.d.ts +6 -0
- package/es/UserSessions/components/user-session-info.js +58 -0
- package/es/UserSessions/components/user-sessions.d.ts +9 -0
- package/es/UserSessions/components/user-sessions.js +255 -0
- package/es/UserSessions/index.d.ts +1 -0
- package/es/UserSessions/index.js +1 -0
- package/es/UserSessions/libs/locales.d.ts +52 -0
- package/es/UserSessions/libs/locales.js +52 -0
- package/es/UserSessions/libs/utils.d.ts +2 -0
- package/es/UserSessions/libs/utils.js +73 -0
- package/es/blocklets.js +6 -6
- package/es/common/header-addons.d.ts +3 -4
- package/es/common/header-addons.js +4 -4
- package/es/contexts/config-user-space.js +2 -2
- package/es/index.d.ts +1 -0
- package/es/index.js +1 -0
- package/es/types.d.ts +2 -2
- package/es/types.js +2 -2
- package/lib/@types/index.d.ts +3 -5
- package/lib/Dashboard/index.d.ts +5 -6
- package/lib/Dashboard/index.js +4 -4
- package/lib/Footer/index.js +1 -1
- package/lib/Header/index.js +4 -4
- package/lib/UserCenter/components/notification.js +1 -1
- package/lib/UserCenter/components/passport.js +1 -2
- package/lib/UserCenter/components/privacy.js +1 -1
- package/lib/UserCenter/components/settings.js +10 -1
- package/lib/UserCenter/components/storage/connect-to.d.ts +1 -1
- package/lib/UserCenter/components/storage/connect-to.js +3 -3
- package/lib/UserCenter/components/storage/connected.d.ts +1 -1
- package/lib/UserCenter/components/storage/connected.js +1 -1
- package/lib/UserCenter/components/storage/delete.d.ts +1 -1
- package/lib/UserCenter/components/storage/index.js +22 -17
- package/lib/UserCenter/components/storage/item.js +1 -13
- package/lib/UserCenter/components/user-center.d.ts +2 -2
- package/lib/UserCenter/components/user-center.js +20 -10
- package/lib/UserCenter/libs/locales.d.ts +54 -0
- package/lib/UserCenter/libs/locales.js +56 -2
- package/lib/UserSessions/components/user-session-info.d.ts +6 -0
- package/lib/UserSessions/components/user-session-info.js +68 -0
- package/lib/UserSessions/components/user-sessions.d.ts +9 -0
- package/lib/UserSessions/components/user-sessions.js +282 -0
- package/lib/UserSessions/index.d.ts +1 -0
- package/lib/UserSessions/index.js +13 -0
- package/lib/UserSessions/libs/locales.d.ts +52 -0
- package/lib/UserSessions/libs/locales.js +58 -0
- package/lib/UserSessions/libs/utils.d.ts +2 -0
- package/lib/UserSessions/libs/utils.js +80 -0
- package/lib/blocklets.js +6 -6
- package/lib/common/header-addons.d.ts +3 -4
- package/lib/common/header-addons.js +3 -3
- package/lib/contexts/config-user-space.js +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +12 -0
- package/lib/types.d.ts +2 -2
- package/lib/types.js +3 -3
- package/package.json +14 -6
- package/src/@types/index.ts +3 -5
- package/src/Dashboard/index.jsx +7 -3
- package/src/Footer/index.jsx +2 -2
- package/src/Header/index.jsx +5 -3
- package/src/Icon/index.jsx +1 -0
- package/src/UserCenter/components/notification.tsx +2 -2
- package/src/UserCenter/components/passport.tsx +1 -2
- package/src/UserCenter/components/privacy.tsx +1 -1
- package/src/UserCenter/components/settings.tsx +15 -2
- package/src/UserCenter/components/storage/connect-to.tsx +17 -11
- package/src/UserCenter/components/storage/connected.tsx +9 -3
- package/src/UserCenter/components/storage/delete.tsx +8 -2
- package/src/UserCenter/components/storage/index.tsx +17 -13
- package/src/UserCenter/components/storage/item.tsx +8 -15
- package/src/UserCenter/components/storage/preview-nft.tsx +1 -1
- package/src/UserCenter/components/user-center.tsx +21 -14
- package/src/UserCenter/components/webhook-item.tsx +1 -1
- package/src/UserCenter/libs/locales.ts +54 -0
- package/src/UserSessions/components/user-session-info.tsx +52 -0
- package/src/UserSessions/components/user-sessions.tsx +276 -0
- package/src/UserSessions/index.tsx +1 -0
- package/src/UserSessions/libs/locales.ts +52 -0
- package/src/UserSessions/libs/utils.ts +82 -0
- package/src/blocklets.js +6 -6
- package/src/common/header-addons.jsx +2 -2
- package/src/contexts/config-user-space.tsx +12 -11
- package/src/index.ts +1 -0
- package/src/{UserCenter/libs → libs}/client.ts +1 -0
- package/src/libs/spaces.tsx +2 -2
- package/src/types.js +2 -2
- /package/es/{UserCenter/libs → libs}/client.d.ts +0 -0
- /package/es/{UserCenter/libs → libs}/client.js +0 -0
- /package/lib/{UserCenter/libs → libs}/client.d.ts +0 -0
- /package/lib/{UserCenter/libs → libs}/client.js +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { User } from '../../@types';
|
|
3
|
+
export default function UserSessions({ user, showAction, showUser, }: {
|
|
4
|
+
readonly user: User & {
|
|
5
|
+
userSessions?: any[];
|
|
6
|
+
};
|
|
7
|
+
readonly showAction?: boolean;
|
|
8
|
+
readonly showUser?: boolean;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import Datatable from "@arcblock/ux/lib/Datatable";
|
|
3
|
+
import { useCreation, useMemoizedFn, useRequest } from "ahooks";
|
|
4
|
+
import { translate } from "@arcblock/ux/lib/Locale/util";
|
|
5
|
+
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
6
|
+
import RelativeTime from "@arcblock/ux/lib/RelativeTime";
|
|
7
|
+
import sortBy from "lodash/sortBy";
|
|
8
|
+
import UAParser from "ua-parser-js";
|
|
9
|
+
import { getVisitorId } from "@arcblock/ux/lib/Util";
|
|
10
|
+
import { useConfirm } from "@arcblock/ux/lib/Dialog";
|
|
11
|
+
import pAll from "p-all";
|
|
12
|
+
import { Box, Button, Tooltip, Typography } from "@mui/material";
|
|
13
|
+
import UserSessionInfo from "./user-session-info.js";
|
|
14
|
+
import { client } from "../../libs/client.js";
|
|
15
|
+
import { translations } from "../libs/locales.js";
|
|
16
|
+
import { batchIp2Region } from "../libs/utils.js";
|
|
17
|
+
const parseUa = (ua) => {
|
|
18
|
+
const parser = new UAParser(ua, {
|
|
19
|
+
// eslint-disable-next-line no-useless-escape
|
|
20
|
+
browser: [[/(ArcWallet)\/([\w\.]+)/i], [UAParser.BROWSER.NAME, UAParser.BROWSER.VERSION]]
|
|
21
|
+
});
|
|
22
|
+
const result = parser.getResult();
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
export default function UserSessions({
|
|
26
|
+
user,
|
|
27
|
+
showAction = true,
|
|
28
|
+
showUser = true
|
|
29
|
+
}) {
|
|
30
|
+
const currentVisitorId = getVisitorId();
|
|
31
|
+
const { locale } = useLocaleContext();
|
|
32
|
+
const { confirmApi, confirmHolder } = useConfirm();
|
|
33
|
+
const t = useMemoizedFn((key, data = {}) => {
|
|
34
|
+
return translate(translations, key, locale, "en", data);
|
|
35
|
+
});
|
|
36
|
+
const getData = useMemoizedFn(async () => {
|
|
37
|
+
let data = user?.userSessions;
|
|
38
|
+
if (!data) {
|
|
39
|
+
data = await client.userSession.getUserSessions({ did: user.did });
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const ipIndexList = data?.map((x, index) => [index, x.lastLoginIp]).filter((x) => !!x[1]);
|
|
43
|
+
const ipList = ipIndexList?.map((x) => x[1]);
|
|
44
|
+
const result = await batchIp2Region(ipList);
|
|
45
|
+
for (let index = 0; index < result.length; index++) {
|
|
46
|
+
const x = result[index];
|
|
47
|
+
const ipIndexItem = ipIndexList[index];
|
|
48
|
+
const dataItem = data[ipIndexItem[0]];
|
|
49
|
+
dataItem.ipRegion = x;
|
|
50
|
+
}
|
|
51
|
+
} catch (e) {
|
|
52
|
+
console.warn("Failed to convert ip to region");
|
|
53
|
+
console.error(e);
|
|
54
|
+
}
|
|
55
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
56
|
+
return sortBy(data, (x) => {
|
|
57
|
+
if (x.visitorId === currentVisitorId) {
|
|
58
|
+
return -1;
|
|
59
|
+
}
|
|
60
|
+
return now - new Date(x.updatedAt).getTime();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
const pageState = useRequest(getData);
|
|
64
|
+
const safeData = useCreation(() => {
|
|
65
|
+
return pageState.data || [];
|
|
66
|
+
}, [pageState.data]);
|
|
67
|
+
const ipRegionMap = useCreation(() => {
|
|
68
|
+
return safeData.reduce((acc, x) => {
|
|
69
|
+
acc[x.lastLoginIp] = x.ipRegion;
|
|
70
|
+
return acc;
|
|
71
|
+
}, {});
|
|
72
|
+
}, [safeData]);
|
|
73
|
+
const logout = useMemoizedFn(({ visitorId }) => {
|
|
74
|
+
confirmApi.open({
|
|
75
|
+
title: t("logoutThisSession"),
|
|
76
|
+
content: t("logoutThisSessionConfirm"),
|
|
77
|
+
confirmButtonText: t("confirm"),
|
|
78
|
+
cancelButtonText: t("cancel"),
|
|
79
|
+
onConfirm: async () => {
|
|
80
|
+
await client.user.logout({ visitorId });
|
|
81
|
+
pageState.refresh();
|
|
82
|
+
confirmApi.close();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
const otherUserSessions = useCreation(() => {
|
|
87
|
+
const list = safeData.filter((x) => x.visitorId !== currentVisitorId);
|
|
88
|
+
return list;
|
|
89
|
+
}, [safeData]);
|
|
90
|
+
const logoutAll = useMemoizedFn(() => {
|
|
91
|
+
confirmApi.open({
|
|
92
|
+
title: t("logoutAllSession"),
|
|
93
|
+
content: t("logoutAllSessionConfirm"),
|
|
94
|
+
confirmButtonText: t("confirm"),
|
|
95
|
+
cancelButtonText: t("cancel"),
|
|
96
|
+
onConfirm: async () => {
|
|
97
|
+
const list = otherUserSessions.map((x) => {
|
|
98
|
+
return () => client.user.logout({ visitorId: x.visitorId });
|
|
99
|
+
});
|
|
100
|
+
await pAll(list, {
|
|
101
|
+
concurrency: 3,
|
|
102
|
+
stopOnError: false
|
|
103
|
+
});
|
|
104
|
+
pageState.refresh();
|
|
105
|
+
confirmApi.close();
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
const customButtons = [];
|
|
110
|
+
if (showAction) {
|
|
111
|
+
customButtons.push(
|
|
112
|
+
/* @__PURE__ */ jsx(Tooltip, { title: t("logoutAllTips"), children: /* @__PURE__ */ jsx(
|
|
113
|
+
Button,
|
|
114
|
+
{
|
|
115
|
+
sx: { ml: 0.5 },
|
|
116
|
+
size: "small",
|
|
117
|
+
variant: "contained",
|
|
118
|
+
color: "error",
|
|
119
|
+
onClick: logoutAll,
|
|
120
|
+
disabled: otherUserSessions.length === 0,
|
|
121
|
+
children: t("logoutAll")
|
|
122
|
+
}
|
|
123
|
+
) }, "logoutAll")
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
const tableOptions = useCreation(() => {
|
|
127
|
+
return {
|
|
128
|
+
// viewColumns: false,
|
|
129
|
+
search: false,
|
|
130
|
+
sort: false,
|
|
131
|
+
download: false,
|
|
132
|
+
filter: false,
|
|
133
|
+
print: false,
|
|
134
|
+
expandableRowsOnClick: false,
|
|
135
|
+
searchDebounceTime: 600
|
|
136
|
+
};
|
|
137
|
+
}, []);
|
|
138
|
+
const columns = [
|
|
139
|
+
{
|
|
140
|
+
label: t("platform"),
|
|
141
|
+
name: "platform",
|
|
142
|
+
options: {
|
|
143
|
+
customBodyRenderLite: (rawIndex) => {
|
|
144
|
+
const x = safeData[rawIndex];
|
|
145
|
+
const result = parseUa(x.ua);
|
|
146
|
+
return /* @__PURE__ */ jsx(Box, { children: [result.os?.name, result.os?.version].filter(Boolean).join("/") || t("unknown") });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
label: t("deviceType"),
|
|
152
|
+
name: "deviceType",
|
|
153
|
+
options: {
|
|
154
|
+
customBodyRenderLite: (rawIndex) => {
|
|
155
|
+
const x = safeData[rawIndex];
|
|
156
|
+
const result = parseUa(x.ua);
|
|
157
|
+
return /* @__PURE__ */ jsx(Box, { children: [result.browser?.name, result.browser?.version].filter(Boolean).join("/") || t("unknown") });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
label: t("walletOS"),
|
|
163
|
+
name: "walletOS",
|
|
164
|
+
options: {
|
|
165
|
+
customBodyRenderLite: (rawIndex) => {
|
|
166
|
+
const x = safeData[rawIndex];
|
|
167
|
+
return /* @__PURE__ */ jsx(Box, { children: x.extra?.walletOS || t("unknown") });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
showUser && {
|
|
172
|
+
label: t("user"),
|
|
173
|
+
name: "user",
|
|
174
|
+
options: {
|
|
175
|
+
customBodyRenderLite: (rawIndex) => {
|
|
176
|
+
const x = safeData[rawIndex];
|
|
177
|
+
return /* @__PURE__ */ jsx(UserSessionInfo, { sessionUser: x.user, user });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
label: t("updatedAt"),
|
|
183
|
+
name: "updatedAt",
|
|
184
|
+
options: {
|
|
185
|
+
customBodyRenderLite: (rawIndex) => {
|
|
186
|
+
const x = safeData[rawIndex];
|
|
187
|
+
return /* @__PURE__ */ jsx(RelativeTime, { value: x.updatedAt, relativeRange: 3 * 86400 * 1e3, locale });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
label: t("lastLoginIp"),
|
|
193
|
+
name: "lastLoginIp",
|
|
194
|
+
options: {
|
|
195
|
+
customBodyRenderLite: (rawIndex) => {
|
|
196
|
+
const x = safeData[rawIndex];
|
|
197
|
+
return /* @__PURE__ */ jsx(Box, { children: ipRegionMap[x.lastLoginIp] ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
198
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", children: ipRegionMap[x.lastLoginIp] }),
|
|
199
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "grey", children: x.lastLoginIp || t("unknown") })
|
|
200
|
+
] }) : /* @__PURE__ */ jsx(Typography, { children: x.lastLoginIp || t("unknown") }) });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
showAction && {
|
|
205
|
+
label: t("actions"),
|
|
206
|
+
name: "actions",
|
|
207
|
+
options: {
|
|
208
|
+
customBodyRenderLite: (rawIndex) => {
|
|
209
|
+
const x = safeData[rawIndex];
|
|
210
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
|
|
211
|
+
Button,
|
|
212
|
+
{
|
|
213
|
+
sx: {
|
|
214
|
+
whiteSpace: "nowrap",
|
|
215
|
+
fontSize: "12px",
|
|
216
|
+
px: 1
|
|
217
|
+
},
|
|
218
|
+
disabled: currentVisitorId === x.visitorId,
|
|
219
|
+
variant: "outlined",
|
|
220
|
+
size: "small",
|
|
221
|
+
color: "error",
|
|
222
|
+
onClick: () => logout({ visitorId: x.visitorId }),
|
|
223
|
+
children: currentVisitorId === x.visitorId ? t("currentSession") : t("logout")
|
|
224
|
+
}
|
|
225
|
+
) });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
].filter(Boolean);
|
|
230
|
+
return /* @__PURE__ */ jsxs(
|
|
231
|
+
Box,
|
|
232
|
+
{
|
|
233
|
+
sx: {
|
|
234
|
+
".MuiTableCell-head": {
|
|
235
|
+
whiteSpace: "nowrap",
|
|
236
|
+
fontWeight: "bold"
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
children: [
|
|
240
|
+
confirmHolder,
|
|
241
|
+
/* @__PURE__ */ jsx(
|
|
242
|
+
Datatable,
|
|
243
|
+
{
|
|
244
|
+
locale,
|
|
245
|
+
data: safeData,
|
|
246
|
+
columns,
|
|
247
|
+
customButtons,
|
|
248
|
+
options: tableOptions,
|
|
249
|
+
loading: pageState.loading
|
|
250
|
+
}
|
|
251
|
+
)
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
);
|
|
255
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as UserSessions } from './components/user-sessions';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as UserSessions } from "./components/user-sessions.js";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export declare const translations: {
|
|
2
|
+
zh: {
|
|
3
|
+
confirm: string;
|
|
4
|
+
cancel: string;
|
|
5
|
+
visitorId: string;
|
|
6
|
+
deviceType: string;
|
|
7
|
+
platform: string;
|
|
8
|
+
walletOS: string;
|
|
9
|
+
role: string;
|
|
10
|
+
fullname: string;
|
|
11
|
+
email: string;
|
|
12
|
+
avatar: string;
|
|
13
|
+
user: string;
|
|
14
|
+
updatedAt: string;
|
|
15
|
+
lastLoginIp: string;
|
|
16
|
+
actions: string;
|
|
17
|
+
logoutAll: string;
|
|
18
|
+
logoutAllTips: string;
|
|
19
|
+
logout: string;
|
|
20
|
+
currentSession: string;
|
|
21
|
+
unknown: string;
|
|
22
|
+
logoutThisSession: string;
|
|
23
|
+
logoutThisSessionConfirm: string;
|
|
24
|
+
logoutAllSession: string;
|
|
25
|
+
logoutAllSessionConfirm: string;
|
|
26
|
+
};
|
|
27
|
+
en: {
|
|
28
|
+
confirm: string;
|
|
29
|
+
cancel: string;
|
|
30
|
+
visitorId: string;
|
|
31
|
+
deviceType: string;
|
|
32
|
+
platform: string;
|
|
33
|
+
walletOS: string;
|
|
34
|
+
role: string;
|
|
35
|
+
fullname: string;
|
|
36
|
+
email: string;
|
|
37
|
+
avatar: string;
|
|
38
|
+
user: string;
|
|
39
|
+
updatedAt: string;
|
|
40
|
+
actions: string;
|
|
41
|
+
lastLoginIp: string;
|
|
42
|
+
logoutAll: string;
|
|
43
|
+
logoutAllTips: string;
|
|
44
|
+
logout: string;
|
|
45
|
+
currentSession: string;
|
|
46
|
+
unknown: string;
|
|
47
|
+
logoutThisSession: string;
|
|
48
|
+
logoutThisSessionConfirm: string;
|
|
49
|
+
logoutAllSession: string;
|
|
50
|
+
logoutAllSessionConfirm: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const translations = {
|
|
2
|
+
zh: {
|
|
3
|
+
confirm: "\u786E\u8BA4",
|
|
4
|
+
cancel: "\u53D6\u6D88",
|
|
5
|
+
visitorId: "\u8BBE\u5907\u6807\u8BC6",
|
|
6
|
+
deviceType: "\u8BBE\u5907\u7C7B\u578B",
|
|
7
|
+
platform: "\u64CD\u4F5C\u7CFB\u7EDF",
|
|
8
|
+
walletOS: "\u94B1\u5305\u7C7B\u578B",
|
|
9
|
+
role: "\u89D2\u8272",
|
|
10
|
+
fullname: "\u59D3\u540D",
|
|
11
|
+
email: "\u90AE\u7BB1",
|
|
12
|
+
avatar: "\u5934\u50CF",
|
|
13
|
+
user: "\u7528\u6237",
|
|
14
|
+
updatedAt: "\u6700\u8FD1\u6D3B\u52A8\u65F6\u95F4",
|
|
15
|
+
lastLoginIp: "\u6700\u8FD1\u6D3B\u52A8\u5730\u5740",
|
|
16
|
+
actions: "\u64CD\u4F5C",
|
|
17
|
+
logoutAll: "\u6CE8\u9500\u6240\u6709\u4F1A\u8BDD",
|
|
18
|
+
logoutAllTips: "\u4E0D\u4F1A\u6CE8\u9500\u5F53\u524D\u4F1A\u8BDD",
|
|
19
|
+
logout: "\u6CE8\u9500",
|
|
20
|
+
currentSession: "\u5F53\u524D\u4F1A\u8BDD",
|
|
21
|
+
unknown: "\u672A\u77E5",
|
|
22
|
+
logoutThisSession: "\u6CE8\u9500\u6307\u5B9A\u4F1A\u8BDD",
|
|
23
|
+
logoutThisSessionConfirm: "\u786E\u5B9A\u8981\u6CE8\u9500\u6B64\u4F1A\u8BDD\u5417?",
|
|
24
|
+
logoutAllSession: "\u6CE8\u9500\u6240\u6709\u4F1A\u8BDD",
|
|
25
|
+
logoutAllSessionConfirm: "\u786E\u5B9A\u8981\u6CE8\u9500\u6240\u6709\u4F1A\u8BDD\u5417?"
|
|
26
|
+
},
|
|
27
|
+
en: {
|
|
28
|
+
confirm: "Confirm",
|
|
29
|
+
cancel: "Cancel",
|
|
30
|
+
visitorId: "Device ID",
|
|
31
|
+
deviceType: "Device Type",
|
|
32
|
+
platform: "Platform",
|
|
33
|
+
walletOS: "Wallet OS",
|
|
34
|
+
role: "Role",
|
|
35
|
+
fullname: "Fullname",
|
|
36
|
+
email: "Email",
|
|
37
|
+
avatar: "Avatar",
|
|
38
|
+
user: "User",
|
|
39
|
+
updatedAt: "Last Active Time",
|
|
40
|
+
actions: "Actions",
|
|
41
|
+
lastLoginIp: "Last Login IP",
|
|
42
|
+
logoutAll: "Logout all",
|
|
43
|
+
logoutAllTips: "Will not logout current session",
|
|
44
|
+
logout: "Logout",
|
|
45
|
+
currentSession: "Current Session",
|
|
46
|
+
unknown: "Unknown",
|
|
47
|
+
logoutThisSession: "Logout this session",
|
|
48
|
+
logoutThisSessionConfirm: "Are you sure to logout this session?",
|
|
49
|
+
logoutAllSession: "Logout all sessions",
|
|
50
|
+
logoutAllSessionConfirm: "Are you sure to logout all sessions?"
|
|
51
|
+
}
|
|
52
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const RESERVED_IP = "Reserved IP";
|
|
2
|
+
const IP_REGION_CACHE = "ip-region-cache";
|
|
3
|
+
async function getIpRegionFromIpApi(ip) {
|
|
4
|
+
const url = `https://ipapi.co/${ip}/json/`;
|
|
5
|
+
const result = await fetch(url);
|
|
6
|
+
const data = await result.json();
|
|
7
|
+
let region = "";
|
|
8
|
+
if (data.error) {
|
|
9
|
+
if (data.reserved) {
|
|
10
|
+
region = RESERVED_IP;
|
|
11
|
+
}
|
|
12
|
+
} else {
|
|
13
|
+
region = [data.country_name, data.region, data.city].filter(Boolean).join("/");
|
|
14
|
+
}
|
|
15
|
+
return region;
|
|
16
|
+
}
|
|
17
|
+
async function getIpRegionFromIpSb(ip) {
|
|
18
|
+
const url = `https://api.ip.sb/geoip/${ip}`;
|
|
19
|
+
const result = await fetch(url);
|
|
20
|
+
const data = await result.json();
|
|
21
|
+
let region = "";
|
|
22
|
+
if (data.error) {
|
|
23
|
+
if (data.reserved) {
|
|
24
|
+
region = RESERVED_IP;
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
region = [data.country, data.region, data.city].filter(Boolean).join("/");
|
|
28
|
+
}
|
|
29
|
+
return region;
|
|
30
|
+
}
|
|
31
|
+
export async function ip2Region(ip) {
|
|
32
|
+
let region = "";
|
|
33
|
+
let ipRegionCache = {};
|
|
34
|
+
try {
|
|
35
|
+
const tmpCache = localStorage.getItem(IP_REGION_CACHE);
|
|
36
|
+
if (tmpCache) {
|
|
37
|
+
ipRegionCache = JSON.parse(tmpCache);
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
ipRegionCache = {};
|
|
41
|
+
}
|
|
42
|
+
if (ipRegionCache[ip]) {
|
|
43
|
+
region = ipRegionCache[ip];
|
|
44
|
+
} else {
|
|
45
|
+
try {
|
|
46
|
+
region = await getIpRegionFromIpSb(ip);
|
|
47
|
+
} catch {
|
|
48
|
+
console.warn("Fail to get ip region from ip.sb");
|
|
49
|
+
}
|
|
50
|
+
if (!region) {
|
|
51
|
+
try {
|
|
52
|
+
region = await getIpRegionFromIpApi(ip);
|
|
53
|
+
} catch {
|
|
54
|
+
console.warn("Fail to get ip region from ip-api.co");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (region) {
|
|
59
|
+
const ipList = Object.keys(ipRegionCache);
|
|
60
|
+
if (ipList.length > 100) {
|
|
61
|
+
delete ipRegionCache[ipList[0]];
|
|
62
|
+
}
|
|
63
|
+
if (ipRegionCache[ip]) {
|
|
64
|
+
delete ipRegionCache[ip];
|
|
65
|
+
}
|
|
66
|
+
ipRegionCache[ip] = region;
|
|
67
|
+
localStorage.setItem(IP_REGION_CACHE, JSON.stringify(ipRegionCache));
|
|
68
|
+
}
|
|
69
|
+
return region;
|
|
70
|
+
}
|
|
71
|
+
export async function batchIp2Region(ips) {
|
|
72
|
+
return Promise.all(ips.map((ip) => ip2Region(ip)));
|
|
73
|
+
}
|
package/es/blocklets.js
CHANGED
|
@@ -28,30 +28,30 @@ export const getLocalizedNavigation = (navigation, locale = 'en') => {
|
|
|
28
28
|
return navigation;
|
|
29
29
|
}
|
|
30
30
|
// eslint-disable-next-line no-shadow
|
|
31
|
-
const getTitle = (title,
|
|
31
|
+
const getTitle = (title, _locale) => {
|
|
32
32
|
if (typeof title === 'string') {
|
|
33
33
|
return title;
|
|
34
34
|
}
|
|
35
35
|
if (typeof title === 'object') {
|
|
36
|
-
return title[
|
|
36
|
+
return title[_locale] || title?.en || title?.zh;
|
|
37
37
|
}
|
|
38
38
|
return title;
|
|
39
39
|
};
|
|
40
40
|
// eslint-disable-next-line no-shadow
|
|
41
|
-
const getLink = (link,
|
|
41
|
+
const getLink = (link, _locale) => {
|
|
42
42
|
if (typeof link === 'string') {
|
|
43
43
|
// http[s] 开头的 url
|
|
44
44
|
if (isUrl(link)) {
|
|
45
45
|
const url = new URL(link);
|
|
46
|
-
url.searchParams.set('locale',
|
|
46
|
+
url.searchParams.set('locale', _locale);
|
|
47
47
|
return url.href;
|
|
48
48
|
}
|
|
49
49
|
const url = new URL(link, window.location.origin);
|
|
50
|
-
url.searchParams.set('locale',
|
|
50
|
+
url.searchParams.set('locale', _locale);
|
|
51
51
|
return url.pathname + url.search;
|
|
52
52
|
}
|
|
53
53
|
if (typeof link === 'object') {
|
|
54
|
-
return link[
|
|
54
|
+
return link[_locale] || link?.en || link?.zh;
|
|
55
55
|
}
|
|
56
56
|
return link;
|
|
57
57
|
};
|
|
@@ -7,16 +7,15 @@ declare namespace HeaderAddons {
|
|
|
7
7
|
namespace propTypes {
|
|
8
8
|
export let formattedBlocklet: any;
|
|
9
9
|
export let addons: any;
|
|
10
|
-
export { sessionManagerProps };
|
|
10
|
+
export { SessionManagerProps as sessionManagerProps };
|
|
11
11
|
}
|
|
12
12
|
namespace defaultProps {
|
|
13
13
|
let addons_1: null;
|
|
14
14
|
export { addons_1 as addons };
|
|
15
|
-
export namespace
|
|
15
|
+
export namespace sessionManagerProps {
|
|
16
16
|
let showRole: boolean;
|
|
17
17
|
}
|
|
18
|
-
export { sessionManagerProps_1 as sessionManagerProps };
|
|
19
18
|
}
|
|
20
19
|
}
|
|
21
20
|
export default HeaderAddons;
|
|
22
|
-
import {
|
|
21
|
+
import { SessionManagerProps } from '../types';
|
|
@@ -8,9 +8,9 @@ import SessionUser from "@arcblock/ux/lib/SessionUser";
|
|
|
8
8
|
import SessionBlocklet from "@arcblock/ux/lib/SessionBlocklet";
|
|
9
9
|
import LocaleSelector from "@arcblock/ux/lib/Locale/selector";
|
|
10
10
|
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
11
|
-
import {
|
|
11
|
+
import { SessionManagerProps } from "../types.js";
|
|
12
12
|
import { getLocalizedNavigation, filterNavByRole } from "../blocklets.js";
|
|
13
|
-
export default function HeaderAddons({ formattedBlocklet, addons, sessionManagerProps
|
|
13
|
+
export default function HeaderAddons({ formattedBlocklet, addons, sessionManagerProps }) {
|
|
14
14
|
const sessionCtx = useContext(SessionContext);
|
|
15
15
|
const { locale } = useLocaleContext() || {};
|
|
16
16
|
const { enableConnect = true, enableLocale = true } = formattedBlocklet;
|
|
@@ -48,7 +48,7 @@ export default function HeaderAddons({ formattedBlocklet, addons, sessionManager
|
|
|
48
48
|
locale,
|
|
49
49
|
menu,
|
|
50
50
|
showRole: true,
|
|
51
|
-
...
|
|
51
|
+
...sessionManagerProps
|
|
52
52
|
},
|
|
53
53
|
"session-user"
|
|
54
54
|
)
|
|
@@ -73,7 +73,7 @@ HeaderAddons.propTypes = {
|
|
|
73
73
|
// - PropTypes.func: 可以把自定义 addons 插在 session-manager 或 locale-selector (如果存在的话) 前/中/后
|
|
74
74
|
// - PropTypes.node: 将 addons 原样传给 UX Header 组件
|
|
75
75
|
addons: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
|
|
76
|
-
sessionManagerProps
|
|
76
|
+
sessionManagerProps: SessionManagerProps
|
|
77
77
|
};
|
|
78
78
|
HeaderAddons.defaultProps = {
|
|
79
79
|
addons: null,
|
|
@@ -17,13 +17,13 @@ function ConfigUserSpaceProvider({ children }) {
|
|
|
17
17
|
const deleteSpaceGateway = async () => {
|
|
18
18
|
setSpaceGateway(void 0);
|
|
19
19
|
};
|
|
20
|
+
const settingStorageEndpoint = (endpoint) => {
|
|
21
|
+
};
|
|
20
22
|
const updateSpaceGateway = async (x) => {
|
|
21
23
|
setSpaceGateway(x);
|
|
22
24
|
session.refresh();
|
|
23
25
|
await settingStorageEndpoint(x.endpoint);
|
|
24
26
|
};
|
|
25
|
-
const settingStorageEndpoint = (endpoint) => {
|
|
26
|
-
};
|
|
27
27
|
const hasStorageEndpoint = Boolean(storageEndpoint && spaceGateway);
|
|
28
28
|
return /* @__PURE__ */ jsx(
|
|
29
29
|
Provider,
|
package/es/index.d.ts
CHANGED
|
@@ -5,3 +5,4 @@ export { default as Icon } from './Icon';
|
|
|
5
5
|
export { default as ComponentInstaller } from './ComponentInstaller';
|
|
6
6
|
export { default as useComponentInstaller } from './ComponentInstaller/use-component-installed';
|
|
7
7
|
export * from './UserCenter';
|
|
8
|
+
export * from './UserSessions';
|
package/es/index.js
CHANGED
|
@@ -5,3 +5,4 @@ export { default as Icon } from "./Icon/index.js";
|
|
|
5
5
|
export { default as ComponentInstaller } from "./ComponentInstaller/index.js";
|
|
6
6
|
export { default as useComponentInstaller } from "./ComponentInstaller/use-component-installed.js";
|
|
7
7
|
export * from "./UserCenter/index.js";
|
|
8
|
+
export * from "./UserSessions/index.js";
|
package/es/types.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const
|
|
2
|
-
export const
|
|
1
|
+
export const BlockletMetaProps: any;
|
|
2
|
+
export const SessionManagerProps: any;
|
package/es/types.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable import/prefer-default-export */
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
|
|
4
|
-
export const
|
|
4
|
+
export const BlockletMetaProps = PropTypes.shape({
|
|
5
5
|
appLogo: PropTypes.node,
|
|
6
6
|
appName: PropTypes.string,
|
|
7
7
|
theme: PropTypes.shape({
|
|
@@ -24,7 +24,7 @@ export const blockletMetaProps = PropTypes.shape({
|
|
|
24
24
|
),
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
export const
|
|
27
|
+
export const SessionManagerProps = PropTypes.shape({
|
|
28
28
|
showText: PropTypes.bool,
|
|
29
29
|
showRole: PropTypes.bool,
|
|
30
30
|
switchDid: PropTypes.bool,
|
package/lib/@types/index.d.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import type { Axios } from 'axios';
|
|
2
|
+
import type { UserPublicInfo } from '@blocklet/js-sdk';
|
|
2
3
|
export type SessionContext = {
|
|
3
4
|
session: Session;
|
|
4
5
|
api: Axios;
|
|
5
6
|
};
|
|
6
|
-
export type User = {
|
|
7
|
-
did: string;
|
|
8
|
-
fullName: string;
|
|
7
|
+
export type User = UserPublicInfo & {
|
|
9
8
|
role: string;
|
|
10
|
-
avatar: string;
|
|
11
9
|
email?: string;
|
|
12
10
|
phone?: string;
|
|
13
11
|
sourceProvider?: string;
|
|
@@ -15,7 +13,7 @@ export type User = {
|
|
|
15
13
|
lastLoginIp?: string;
|
|
16
14
|
createdAt?: string;
|
|
17
15
|
passports?: any[];
|
|
18
|
-
didSpace
|
|
16
|
+
didSpace?: Record<string, any>;
|
|
19
17
|
};
|
|
20
18
|
export type UserCenterTab = {
|
|
21
19
|
value: string;
|
package/lib/Dashboard/index.d.ts
CHANGED
|
@@ -13,11 +13,11 @@ declare function Dashboard({ meta, fallbackUrl, invalidPathFallback, headerAddon
|
|
|
13
13
|
}): import("react").JSX.Element | null;
|
|
14
14
|
declare namespace Dashboard {
|
|
15
15
|
namespace propTypes {
|
|
16
|
-
export {
|
|
16
|
+
export { BlockletMetaProps as meta };
|
|
17
17
|
export let fallbackUrl: any;
|
|
18
18
|
export let invalidPathFallback: any;
|
|
19
19
|
export let headerAddons: any;
|
|
20
|
-
export { sessionManagerProps };
|
|
20
|
+
export { SessionManagerProps as sessionManagerProps };
|
|
21
21
|
export let links: any;
|
|
22
22
|
}
|
|
23
23
|
namespace defaultProps {
|
|
@@ -27,15 +27,14 @@ declare namespace Dashboard {
|
|
|
27
27
|
export { invalidPathFallback_1 as invalidPathFallback };
|
|
28
28
|
let headerAddons_1: undefined;
|
|
29
29
|
export { headerAddons_1 as headerAddons };
|
|
30
|
-
export namespace
|
|
30
|
+
export namespace sessionManagerProps {
|
|
31
31
|
let showRole: boolean;
|
|
32
32
|
function onLogout(): void;
|
|
33
33
|
}
|
|
34
|
-
export { sessionManagerProps_1 as sessionManagerProps };
|
|
35
34
|
let links_1: never[];
|
|
36
35
|
export { links_1 as links };
|
|
37
36
|
}
|
|
38
37
|
}
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
38
|
+
import { BlockletMetaProps } from '../types';
|
|
39
|
+
import { SessionManagerProps } from '../types';
|
|
41
40
|
import { publicPath } from '../blocklets';
|