feat: sentry 插件增加用户信息设置

pull/56/head
moonrailgun 2 years ago
parent b7de74ff1e
commit a81b9bfaad

@ -2,11 +2,17 @@ import { useEffect } from 'react';
import { useUpdateRef } from '../hooks/useUpdateRef';
import type { ChatMessage, SendMessagePayload } from '../model/message';
import { EventEmitter } from 'eventemitter-strict';
import type { UserBaseInfo } from '../model/user';
/**
*
*/
export interface SharedEventMap {
/**
*
*/
loginSuccess: (userInfo: UserBaseInfo) => void;
/**
*
*/

@ -274,6 +274,7 @@
"kea977d95": "The following users are offline",
"kec46a57f": "Add members",
"kecb51e2c": "Old password",
"kecbb0e45": "System",
"kecbd7449": "Delete",
"ked2baf28": "Loading...",
"ked5385d5": "Create Panel",

@ -274,6 +274,7 @@
"kea977d95": "以下用户已离线",
"kec46a57f": "添加成员",
"kecb51e2c": "旧密码",
"kecbb0e45": "系统",
"kecbd7449": "删除",
"ked2baf28": "加载中...",
"ked5385d5": "创建面板",

@ -1,7 +1,10 @@
import { request } from '../api/request';
import { buildCachedRequest } from '../cache/utils';
import { sharedEvent } from '../event';
import { SYSTEM_USERID } from '../utils/consts';
import { createAutoMergedRequest } from '../utils/request';
import _pick from 'lodash/pick';
import { t } from '../i18n';
export interface UserBaseInfo {
_id: string;
@ -24,12 +27,23 @@ export interface UserSettings {
messageListVirtualization?: boolean;
}
export function pickUserBaseInfo(userInfo: UserLoginInfo) {
return _pick(userInfo, [
'_id',
'email',
'nickname',
'discriminator',
'avatar',
'temporary',
]);
}
// 内置用户信息
const builtinUserInfo: Record<string, UserBaseInfo> = {
[SYSTEM_USERID]: {
_id: SYSTEM_USERID,
email: 'admin@msgbyte.com',
nickname: '系统',
nickname: t('系统'),
discriminator: '0000',
avatar: null,
temporary: false,
@ -58,6 +72,8 @@ export async function loginWithEmail(
password,
});
sharedEvent.emit('loginSuccess', pickUserBaseInfo(data));
return data;
}
@ -70,6 +86,8 @@ export async function loginWithToken(token: string): Promise<UserLoginInfo> {
token,
});
sharedEvent.emit('loginSuccess', pickUserBaseInfo(data));
return data;
}

@ -1,5 +1,6 @@
import * as Sentry from '@sentry/react';
import { BrowserTracing } from '@sentry/tracing';
import { sharedEvent } from '@capital/common';
Sentry.init({
dsn: 'https://177fd98a1e9e4deba84146a769633c32@o4504196236836864.ingest.sentry.io/4504196241293312',
@ -10,3 +11,13 @@ Sentry.init({
// We recommend adjusting this value in production
tracesSampleRate: 1.0,
});
sharedEvent.on('loginSuccess', (userInfo) => {
Sentry.setUser({
id: userInfo._id,
email: userInfo.email,
username: `${userInfo.nickname}#${userInfo.discriminator}`,
avatar: userInfo.avatar,
temporary: userInfo.temporary,
});
});

@ -1,2 +1,419 @@
declare module '@capital/common';
declare module '@capital/component';
/* eslint-disable @typescript-eslint/no-explicit-any */
/// <reference types="react" />
/**
* Tailchat
*
* : pnpm run plugins:declaration:generate
*/
/**
* Tailchat
*/
declare module '@capital/common' {
export const useGroupPanelParams: any;
/**
*
* @deprecated @capital/component
*/
export const openModal: (
content: React.ReactNode,
props?: {
/**
*
* @default false
*/
closable?: boolean;
/**
*
*/
maskClosable?: boolean;
/**
* modal
*/
onCloseModal?: () => void;
}
) => number;
/**
* @deprecated @capital/component
*/
export const closeModal: any;
/**
* @deprecated @capital/component
*/
export const ModalWrapper: any;
/**
* @deprecated @capital/component
*/
export const useModalContext: any;
/**
* @deprecated @capital/component
*/
export const openConfirmModal: any;
/**
* @deprecated @capital/component
*/
export const openReconfirmModal: any;
/**
* @deprecated @capital/component
*/
export const Loadable: any;
export const getGlobalState: any;
export const useGlobalSocketEvent: <T>(
eventName: string,
callback: (data: T) => void
) => void;
export const getJWTUserInfo: () => Promise<{
_id?: string;
nickname?: string;
email?: string;
avatar?: string;
}>;
export const dataUrlToFile: any;
export const urlSearchStringify: any;
export const urlSearchParse: any;
export const appendUrlSearch: any;
export const getServiceWorkerRegistration: any;
export const getServiceUrl: () => string;
export const getCachedUserInfo: (
userId: string,
refetch?: boolean
) => Promise<{
_id: string;
email: string;
nickname: string;
discriminator: string;
avatar: string | null;
temporary: boolean;
}>;
export const getCachedConverseInfo: any;
/**
*
* @example
* localTrans({'zh-CN': '你好', 'en-US': 'Hello'});
*
* @param trans
*/
export const localTrans: (trans: Record<'zh-CN' | 'en-US', string>) => string;
export const getLanguage: any;
export const sharedEvent: any;
export const useAsync: any;
export const useAsyncFn: any;
export const useAsyncRefresh: <T extends (...args: any[]) => Promise<any>>(
fn: T,
deps?: React.DependencyList
) => [{ loading: boolean; value?: any; error?: Error }, T];
export const useAsyncRequest: <T extends (...args: any[]) => Promise<any>>(
fn: T,
deps?: React.DependencyList
) => [{ loading: boolean; value?: any }, T];
export const uploadFile: any;
export const showToasts: (
message: string,
type?: 'info' | 'success' | 'error' | 'warning'
) => void;
export const showSuccessToasts: any;
export const showErrorToasts: (error: any) => void;
export const fetchAvailableServices: any;
export const isValidStr: (str: any) => str is string;
export const useGroupPanelInfo: any;
export const sendMessage: any;
export const showMessageTime: any;
export const useLocation: any;
export const useNavigate: any;
export const createFastFormSchema: any;
export const fieldSchema: any;
export const useCurrentUserInfo: any;
export const createPluginRequest: (pluginName: string) => {
get: (actionName: string, config?: any) => Promise<any>;
post: (actionName: string, data?: any, config?: any) => Promise<any>;
};
export const postRequest: any;
export const pluginCustomPanel: any;
export const regCustomPanel: any;
export const pluginGroupPanel: any;
export const regGroupPanel: any;
export const messageInterpreter: any;
export const regMessageInterpreter: any;
export const getMessageRender: any;
export const regMessageRender: any;
export const getMessageTextDecorators: any;
export const regMessageTextDecorators: any;
export const ChatInputActionContextProps: any;
export const pluginChatInputActions: any;
export const regChatInputAction: any;
export const regSocketEventListener: (item: {
eventName: string;
eventFn: (...args: any[]) => void;
}) => void;
export const pluginColorScheme: any;
export const regPluginColorScheme: any;
export const pluginInspectServices: any;
export const regInspectService: any;
export const pluginMessageExtraParsers: any;
export const regMessageExtraParser: any;
export const pluginRootRoute: any;
export const regPluginRootRoute: any;
export const pluginPanelActions: any;
export const regPluginPanelAction: any;
export const pluginPermission: any;
export const regPluginPermission: (permission: {
/**
* key,
* , : plugin.com.msgbyte.github.manage
*/
key: string;
/**
*
*/
title: string;
/**
*
*/
desc: string;
/**
*
*/
default: boolean;
/**
*
*/
required?: string[];
}) => void;
export const pluginGroupPanelBadges: any;
export const regGroupPanelBadge: any;
export const pluginGroupTextPanelExtraMenus: any;
export const regPluginGroupTextPanelExtraMenu: any;
export const useGroupIdContext: () => string;
export const useGroupPanelContext: () => {
groupId: string;
panelId: string;
} | null;
export const useSocketContext: any;
}
/**
* Tailchat
*/
declare module '@capital/component' {
export const Button: any;
export const Checkbox: any;
export const Input: any;
export const Divider: any;
export const Space: any;
export const Menu: any;
export const Table: any;
export const Switch: any;
export const Tooltip: any;
/**
* @link https://ant.design/components/notification-cn/
*/
export const notification: any;
export const Empty: React.FC<
React.PropsWithChildren<{
prefixCls?: string;
className?: string;
style?: React.CSSProperties;
imageStyle?: React.CSSProperties;
image?: React.ReactNode;
description?: React.ReactNode;
}>
>;
export const Avatar: any;
export const SensitiveText: React.FC<{ className?: string; text: string }>;
export const TextArea: any;
export const Image: any;
export const Icon: React.FC<{ icon: string } & React.SVGProps<SVGSVGElement>>;
export const IconBtn: React.FC<{
icon: string;
className?: string;
iconClassName?: string;
size?: 'small' | 'middle' | 'large';
shape?: 'circle' | 'square';
title?: string;
onClick?: React.MouseEventHandler<HTMLElement>;
}>;
export const PillTabs: any;
export const PillTabPane: any;
export const LoadingSpinner: React.FC<{ tip?: string }>;
export const WebFastForm: any;
export const WebMetaForm: any;
export const createMetaFormSchema: any;
export const metaFormFieldSchema: any;
export const FullModalField: any;
export const DefaultFullModalInputEditorRender: any;
export const DefaultFullModalTextAreaEditorRender: any;
export const openModal: (
content: React.ReactNode,
props?: {
/**
*
* @default false
*/
closable?: boolean;
/**
*
*/
maskClosable?: boolean;
/**
* modal
*/
onCloseModal?: () => void;
}
) => number;
export const closeModal: any;
export const ModalWrapper: any;
export const useModalContext: any;
export const openConfirmModal: any;
export const openReconfirmModal: any;
export const Loadable: any;
export const Loading: React.FC<{
spinning: boolean;
className?: string;
style?: React.CSSProperties;
children?: React.ReactNode;
}>;
export const LoadingOnFirst: React.FC<{
spinning: boolean;
className?: string;
style?: React.CSSProperties;
children?: React.ReactNode;
}>;
export const SidebarView: any;
export const GroupPanelSelector: any;
export const Emoji: any;
export const PortalAdd: any;
export const PortalRemove: any;
export const ErrorBoundary: any;
export const UserAvatar: any;
export const UserName: React.FC<{
userId: string;
className?: string;
}>;
export const Markdown: any;
}

@ -1,4 +1,4 @@
import { loginWithToken, UserLoginInfo } from 'tailchat-shared';
import { UserLoginInfo, model } from 'tailchat-shared';
import _isNil from 'lodash/isNil';
import { getUserJWT } from './jwt-helper';
@ -29,7 +29,7 @@ export async function tryAutoLogin(): Promise<UserLoginInfo> {
}
console.debug('正在尝试使用Token登录');
userLoginInfo = await loginWithToken(token);
userLoginInfo = await model.user.loginWithToken(token);
if (userLoginInfo === null) {
throw new Error('Token 内容不合法');
}

Loading…
Cancel
Save