From 22344f6349ea7160c1662bc0c879fdb9e0c68a91 Mon Sep 17 00:00:00 2001 From: caoxing Date: Mon, 15 Jul 2024 11:20:46 +0800 Subject: [PATCH 1/9] fix: group color judgement error --- packages/sdk/src/components/group/Group.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk/src/components/group/Group.tsx b/packages/sdk/src/components/group/Group.tsx index d8e1ed0f3..0bb34fa69 100644 --- a/packages/sdk/src/components/group/Group.tsx +++ b/packages/sdk/src/components/group/Group.tsx @@ -24,7 +24,7 @@ export const Group = (props: IGroupProps) => { : t('group.label'); return { text, - isActive: text !== 'Group', + isActive: text !== t('group.label'), Icon: LayoutList, }; }, [groupLength, t]); From 94829254e806e6114bb9beeeacff7d1c9f4cdd68 Mon Sep 17 00:00:00 2001 From: caoxing Date: Mon, 15 Jul 2024 12:05:08 +0800 Subject: [PATCH 2/9] feat: notification i18n --- .../notifications/NotificationActionBar.tsx | 13 ++++++++++--- .../notifications/NotificationsManage.tsx | 13 ++++++++----- packages/common-i18n/src/locales/en/system.json | 10 ++++++++++ packages/common-i18n/src/locales/zh/system.json | 10 ++++++++++ 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/apps/nextjs-app/src/features/app/components/notifications/NotificationActionBar.tsx b/apps/nextjs-app/src/features/app/components/notifications/NotificationActionBar.tsx index 32278e7fb..8bc1de3a2 100644 --- a/apps/nextjs-app/src/features/app/components/notifications/NotificationActionBar.tsx +++ b/apps/nextjs-app/src/features/app/components/notifications/NotificationActionBar.tsx @@ -10,7 +10,9 @@ import { TooltipProvider, TooltipTrigger, } from '@teable/ui-lib'; +import { useTranslation } from 'next-i18next'; import React from 'react'; +import { systemConfig } from '@/features/i18n/system.config'; interface ActionBarProps { notifyStatus: NotificationStatesEnum; @@ -20,6 +22,7 @@ interface ActionBarProps { export const NotificationActionBar: React.FC = (props) => { const { notifyStatus, children, onStatusCheck } = props; + const { t } = useTranslation(systemConfig.i18nNamespaces); return ( @@ -45,8 +48,12 @@ export const NotificationActionBar: React.FC = (props) => { - Mark this notification as - {notifyStatus === NotificationStatesEnum.Unread ? ' read' : ' unread'} + {t('notification.markAs', { + status: + notifyStatus === NotificationStatesEnum.Unread + ? t('system:notification.read') + : t('system:notification.unread'), + })} @@ -60,7 +67,7 @@ export const NotificationActionBar: React.FC = (props) => { - Change page notification settings + {t('system:notification.changeSetting')} diff --git a/apps/nextjs-app/src/features/app/components/notifications/NotificationsManage.tsx b/apps/nextjs-app/src/features/app/components/notifications/NotificationsManage.tsx index e67d2c589..21941f5e7 100644 --- a/apps/nextjs-app/src/features/app/components/notifications/NotificationsManage.tsx +++ b/apps/nextjs-app/src/features/app/components/notifications/NotificationsManage.tsx @@ -10,12 +10,15 @@ import { useNotification } from '@teable/sdk'; import { ReactQueryKeys } from '@teable/sdk/config/react-query-keys'; import { Button, Popover, PopoverContent, PopoverTrigger } from '@teable/ui-lib'; import { cn } from '@teable/ui-lib/shadcn'; +import { useTranslation } from 'next-i18next'; import React, { useEffect, useState } from 'react'; +import { systemConfig } from '@/features/i18n/system.config'; import { NotificationList } from './NotificationList'; export const NotificationsManage: React.FC = () => { const queryClient = useQueryClient(); const notification = useNotification(); + const { t } = useTranslation(systemConfig.i18nNamespaces); const [isOpen, setOpen] = useState(false); const [unreadCount, setUnreadCount] = useState(0); @@ -83,7 +86,7 @@ export const NotificationsManage: React.FC = () => { }} > -

{num} new

+

{t('system:notification.new', { count: num })}

); @@ -133,14 +136,14 @@ export const NotificationsManage: React.FC = () => { }} > - Mark all as read + {t('system:notification.markAllAsRead')} ) : ( '' )}
-
Notifications
+
{t('system:notification.title')}
{renderNewButton()}
diff --git a/packages/common-i18n/src/locales/en/system.json b/packages/common-i18n/src/locales/en/system.json index 022055e67..aca2bde43 100644 --- a/packages/common-i18n/src/locales/en/system.json +++ b/packages/common-i18n/src/locales/en/system.json @@ -12,5 +12,15 @@ "paymentRequired": { "title": "402 - Subscription Upgrade Required", "description": "Your current subscription does not support access to this feature.

Please upgrade your subscription to continue." + }, + "notification": { + "title": "Notifications", + "unread": "Unread", + "read": "Read", + "markAs": "Mark this notification as {{status}}", + "markAllAsRead": "Mark all as read", + "noUnread": "No unread notifications", + "changeSetting": "Change page notification settings", + "new": "new {{count}}" } } diff --git a/packages/common-i18n/src/locales/zh/system.json b/packages/common-i18n/src/locales/zh/system.json index f0c3e79a1..ca368bc9b 100644 --- a/packages/common-i18n/src/locales/zh/system.json +++ b/packages/common-i18n/src/locales/zh/system.json @@ -12,5 +12,15 @@ "paymentRequired": { "title": "402 - 需要升级订阅", "description": "您当前的订阅计划不支持访问此功能,请升级您的订阅以继续使用" + }, + "notification": { + "title": "通知", + "unread": "未读", + "read": "已读", + "markAs": "将此通知标记为{{status}}", + "markAllAsRead": "全部标记为已读", + "noUnread": "没有未读通知", + "changeSetting": "更改页面通知设置", + "new": "新消息{{count}}条" } } From 6c716a95a2547f0ef0b564a3391d69d29066ba45 Mon Sep 17 00:00:00 2001 From: caoxing Date: Mon, 15 Jul 2024 12:19:54 +0800 Subject: [PATCH 3/9] feat: signup default spacesname support i18n --- .../src/features/auth/auth.controller.ts | 4 +++- .../src/features/auth/auth.service.ts | 22 +++++++++++-------- .../src/features/user/user.service.ts | 12 +++++----- .../src/features/auth/components/SignForm.tsx | 5 ++++- .../src/features/i18n/auth.config.ts | 4 ++-- .../common-i18n/src/locales/en/space.json | 1 + .../common-i18n/src/locales/zh/space.json | 1 + packages/openapi/src/auth/signup.ts | 4 +++- 8 files changed, 34 insertions(+), 19 deletions(-) diff --git a/apps/nestjs-backend/src/features/auth/auth.controller.ts b/apps/nestjs-backend/src/features/auth/auth.controller.ts index 5c991b83a..e4147b61f 100644 --- a/apps/nestjs-backend/src/features/auth/auth.controller.ts +++ b/apps/nestjs-backend/src/features/auth/auth.controller.ts @@ -47,7 +47,9 @@ export class AuthController { @Res({ passthrough: true }) res: Response, @Req() req: Express.Request ) { - const user = pickUserMe(await this.authService.signup(body.email, body.password)); + const user = pickUserMe( + await this.authService.signup(body.email, body.password, body.defaultSpaceName) + ); // set cookie, passport login await new Promise((resolve, reject) => { req.login(user, (err) => (err ? reject(err) : resolve())); diff --git a/apps/nestjs-backend/src/features/auth/auth.service.ts b/apps/nestjs-backend/src/features/auth/auth.service.ts index ed00f2ea4..31a3048e5 100644 --- a/apps/nestjs-backend/src/features/auth/auth.service.ts +++ b/apps/nestjs-backend/src/features/auth/auth.service.ts @@ -66,7 +66,7 @@ export class AuthService { return (await this.comparePassword(pass, password, salt)) ? { ...result, password } : null; } - async signup(email: string, password: string) { + async signup(email: string, password: string, defaultSpaceName?: string) { const user = await this.userService.getUserByEmail(email); if (user && (user.password !== null || user.accounts.length > 0)) { throw new HttpException(`User ${email} is already registered`, HttpStatus.BAD_REQUEST); @@ -83,14 +83,18 @@ export class AuthService { }, }); } - return await this.userService.createUserWithSettingCheck({ - id: generateUserId(), - name: email.split('@')[0], - email, - salt, - password: hashPassword, - lastSignTime: new Date().toISOString(), - }); + return await this.userService.createUserWithSettingCheck( + { + id: generateUserId(), + name: email.split('@')[0], + email, + salt, + password: hashPassword, + lastSignTime: new Date().toISOString(), + }, + undefined, + defaultSpaceName + ); }); } diff --git a/apps/nestjs-backend/src/features/user/user.service.ts b/apps/nestjs-backend/src/features/user/user.service.ts index d8280575f..dde52d47e 100644 --- a/apps/nestjs-backend/src/features/user/user.service.ts +++ b/apps/nestjs-backend/src/features/user/user.service.ts @@ -83,7 +83,8 @@ export class UserService { async createUserWithSettingCheck( user: Omit & { name?: string }, - account?: Omit + account?: Omit, + defaultSpaceName?: string ) { const setting = await this.prismaService.setting.findFirst({ select: { @@ -95,12 +96,13 @@ export class UserService { throw new BadRequestException('The current instance disallow sign up by the administrator'); } - return await this.createUser(user, account); + return await this.createUser(user, account, defaultSpaceName); } async createUser( user: Omit & { name?: string }, - account?: Omit + account?: Omit, + defaultSpaceName?: string ) { // defaults const defaultNotifyMeta: IUserNotifyMeta = { @@ -133,7 +135,7 @@ export class UserService { isAdmin: isAdmin ? true : null, }, }); - const { id, name } = newUser; + const { id } = newUser; if (account) { await this.prismaService.txClient().account.create({ data: { id: generateAccountId(), ...account, userId: id }, @@ -141,7 +143,7 @@ export class UserService { } await this.cls.runWith(this.cls.get(), async () => { this.cls.set('user.id', id); - await this.createSpaceBySignup({ name: `${name}'s space` }); + await this.createSpaceBySignup({ name: defaultSpaceName }); }); this.eventEmitterService.emitAsync(Events.USER_SIGNUP, new UserSignUpEvent(id)); return newUser; diff --git a/apps/nextjs-app/src/features/auth/components/SignForm.tsx b/apps/nextjs-app/src/features/auth/components/SignForm.tsx index 9347ff504..02c06172f 100644 --- a/apps/nextjs-app/src/features/auth/components/SignForm.tsx +++ b/apps/nextjs-app/src/features/auth/components/SignForm.tsx @@ -29,7 +29,10 @@ export const SignForm: FC = (props) => { return signin(form); } if (type === 'signup') { - return signup(form); + return signup({ + ...form, + defaultSpaceName: t('space:initialSpaceName', { name: form.email.split('@')[0] }), + }); } throw new Error('Invalid type'); }, diff --git a/apps/nextjs-app/src/features/i18n/auth.config.ts b/apps/nextjs-app/src/features/i18n/auth.config.ts index 988fc4072..f923c84e1 100644 --- a/apps/nextjs-app/src/features/i18n/auth.config.ts +++ b/apps/nextjs-app/src/features/i18n/auth.config.ts @@ -2,9 +2,9 @@ import type { I18nActiveNamespaces } from '@/lib/i18n'; export interface IAuthConfig { // Define namespaces in use in both the type and the config. - i18nNamespaces: I18nActiveNamespaces<'common' | 'auth'>; + i18nNamespaces: I18nActiveNamespaces<'common' | 'auth' | 'space'>; } export const authConfig: IAuthConfig = { - i18nNamespaces: ['common', 'auth'], + i18nNamespaces: ['common', 'auth', 'space'], }; diff --git a/packages/common-i18n/src/locales/en/space.json b/packages/common-i18n/src/locales/en/space.json index f80ca835d..b670b09b1 100644 --- a/packages/common-i18n/src/locales/en/space.json +++ b/packages/common-i18n/src/locales/en/space.json @@ -1,5 +1,6 @@ { "defaultSpaceName": "Space", + "initialSpaceName": "{{name}}'s space", "page": { "title": "Teable App" }, diff --git a/packages/common-i18n/src/locales/zh/space.json b/packages/common-i18n/src/locales/zh/space.json index 3bd554106..7953f7bf6 100644 --- a/packages/common-i18n/src/locales/zh/space.json +++ b/packages/common-i18n/src/locales/zh/space.json @@ -1,5 +1,6 @@ { "defaultSpaceName": "空间", + "initialSpaceName": "{{name}}的空间", "page": { "title": "Teable App" }, diff --git a/packages/openapi/src/auth/signup.ts b/packages/openapi/src/auth/signup.ts index 27317af17..05cf2fe86 100644 --- a/packages/openapi/src/auth/signup.ts +++ b/packages/openapi/src/auth/signup.ts @@ -6,7 +6,9 @@ import { signinSchema, signinVoSchema } from './signin'; export const SIGN_UP = '/auth/signup'; -export const signupSchema = signinSchema; +export const signupSchema = signinSchema.extend({ + defaultSpaceName: z.string().optional(), +}); export type ISignup = z.infer; From 04a1948a165f68e0b389bed004284bee6393fa49 Mon Sep 17 00:00:00 2001 From: caoxing Date: Mon, 15 Jul 2024 12:32:46 +0800 Subject: [PATCH 4/9] fix: space name cutting --- apps/nextjs-app/src/features/app/blocks/space/SpaceCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/nextjs-app/src/features/app/blocks/space/SpaceCard.tsx b/apps/nextjs-app/src/features/app/blocks/space/SpaceCard.tsx index 616f001c7..9d97d25fc 100644 --- a/apps/nextjs-app/src/features/app/blocks/space/SpaceCard.tsx +++ b/apps/nextjs-app/src/features/app/blocks/space/SpaceCard.tsx @@ -79,7 +79,7 @@ export const SpaceCard: FC = (props) => { onChange={(e) => setSpaceName(e.target.value)} onBlur={(e) => toggleUpdateSpace(e)} > - + {space.name} From 40257ed7a419ac244561036414d6d5460fd4302e Mon Sep 17 00:00:00 2001 From: caoxing Date: Mon, 15 Jul 2024 14:30:25 +0800 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20`sort`=E3=80=81`group`=20FieldSelec?= =?UTF-8?q?t=20alignment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/sdk/src/components/sort/SortItem.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/sdk/src/components/sort/SortItem.tsx b/packages/sdk/src/components/sort/SortItem.tsx index 118e8f325..2d43284aa 100644 --- a/packages/sdk/src/components/sort/SortItem.tsx +++ b/packages/sdk/src/components/sort/SortItem.tsx @@ -29,6 +29,7 @@ function SortItem(props: ISortItemProps) { value={fieldId} onSelect={(value) => selectHandler(ISortKey.FieldId, value)} excludedIds={selectedFields} + className="w-40" {...restProps} /> From 7bf9eafb6254d2f9ca941fba2505763b9ae88b39 Mon Sep 17 00:00:00 2001 From: caoxing Date: Mon, 15 Jul 2024 14:32:13 +0800 Subject: [PATCH 6/9] feat: signup api compatible api calling default space name --- apps/nestjs-backend/src/features/user/user.service.ts | 4 ++-- .../features/app/blocks/space/space-side-bar/SpaceList.tsx | 4 ++-- packages/common-i18n/src/locales/en/space.json | 1 - packages/common-i18n/src/locales/zh/space.json | 1 - 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/nestjs-backend/src/features/user/user.service.ts b/apps/nestjs-backend/src/features/user/user.service.ts index dde52d47e..50d06c6de 100644 --- a/apps/nestjs-backend/src/features/user/user.service.ts +++ b/apps/nestjs-backend/src/features/user/user.service.ts @@ -135,7 +135,7 @@ export class UserService { isAdmin: isAdmin ? true : null, }, }); - const { id } = newUser; + const { id, name } = newUser; if (account) { await this.prismaService.txClient().account.create({ data: { id: generateAccountId(), ...account, userId: id }, @@ -143,7 +143,7 @@ export class UserService { } await this.cls.runWith(this.cls.get(), async () => { this.cls.set('user.id', id); - await this.createSpaceBySignup({ name: defaultSpaceName }); + await this.createSpaceBySignup({ name: defaultSpaceName || `${name}'s space` }); }); this.eventEmitterService.emitAsync(Events.USER_SIGNUP, new UserSignUpEvent(id)); return newUser; diff --git a/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceList.tsx b/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceList.tsx index cff54c6bf..d1781de39 100644 --- a/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceList.tsx +++ b/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceList.tsx @@ -14,7 +14,7 @@ import { SpaceItem } from './SpaceItem'; export const SpaceList: FC = () => { const router = useRouter(); const { disallowSpaceCreation } = useSetting(); - const { t } = useTranslation('space'); + const { t } = useTranslation('common'); const queryClient = useQueryClient(); const { data: spaceList } = useQuery({ @@ -46,7 +46,7 @@ export const SpaceList: FC = () => { className="w-full" onClick={() => { const name = getUniqName( - t('defaultSpaceName'), + t('noun.space'), spaceList?.data?.length ? spaceList?.data.map((space) => space?.name) : [] ); addSpace({ name }); diff --git a/packages/common-i18n/src/locales/en/space.json b/packages/common-i18n/src/locales/en/space.json index b670b09b1..ed76e09d3 100644 --- a/packages/common-i18n/src/locales/en/space.json +++ b/packages/common-i18n/src/locales/en/space.json @@ -1,5 +1,4 @@ { - "defaultSpaceName": "Space", "initialSpaceName": "{{name}}'s space", "page": { "title": "Teable App" diff --git a/packages/common-i18n/src/locales/zh/space.json b/packages/common-i18n/src/locales/zh/space.json index 7953f7bf6..a8b7ddac5 100644 --- a/packages/common-i18n/src/locales/zh/space.json +++ b/packages/common-i18n/src/locales/zh/space.json @@ -1,5 +1,4 @@ { - "defaultSpaceName": "空间", "initialSpaceName": "{{name}}的空间", "page": { "title": "Teable App" From 5e5ee8f2ec075d9cfda91002b4e63a99a69a9d8a Mon Sep 17 00:00:00 2001 From: caoxing Date: Mon, 15 Jul 2024 15:11:27 +0800 Subject: [PATCH 7/9] chore: notification i18n name space to common from system --- .../notifications/NotificationActionBar.tsx | 9 ++++----- .../notifications/NotificationsManage.tsx | 13 ++++++------- packages/common-i18n/src/locales/en/common.json | 10 ++++++++++ packages/common-i18n/src/locales/en/system.json | 10 ---------- packages/common-i18n/src/locales/zh/common.json | 10 ++++++++++ packages/common-i18n/src/locales/zh/system.json | 10 ---------- 6 files changed, 30 insertions(+), 32 deletions(-) diff --git a/apps/nextjs-app/src/features/app/components/notifications/NotificationActionBar.tsx b/apps/nextjs-app/src/features/app/components/notifications/NotificationActionBar.tsx index 8bc1de3a2..3e121542f 100644 --- a/apps/nextjs-app/src/features/app/components/notifications/NotificationActionBar.tsx +++ b/apps/nextjs-app/src/features/app/components/notifications/NotificationActionBar.tsx @@ -12,7 +12,6 @@ import { } from '@teable/ui-lib'; import { useTranslation } from 'next-i18next'; import React from 'react'; -import { systemConfig } from '@/features/i18n/system.config'; interface ActionBarProps { notifyStatus: NotificationStatesEnum; @@ -22,7 +21,7 @@ interface ActionBarProps { export const NotificationActionBar: React.FC = (props) => { const { notifyStatus, children, onStatusCheck } = props; - const { t } = useTranslation(systemConfig.i18nNamespaces); + const { t } = useTranslation('common'); return ( @@ -51,8 +50,8 @@ export const NotificationActionBar: React.FC = (props) => { {t('notification.markAs', { status: notifyStatus === NotificationStatesEnum.Unread - ? t('system:notification.read') - : t('system:notification.unread'), + ? t('notification.read') + : t('notification.unread'), })} @@ -67,7 +66,7 @@ export const NotificationActionBar: React.FC = (props) => { - {t('system:notification.changeSetting')} + {t('notification.changeSetting')} diff --git a/apps/nextjs-app/src/features/app/components/notifications/NotificationsManage.tsx b/apps/nextjs-app/src/features/app/components/notifications/NotificationsManage.tsx index 21941f5e7..8d79b2311 100644 --- a/apps/nextjs-app/src/features/app/components/notifications/NotificationsManage.tsx +++ b/apps/nextjs-app/src/features/app/components/notifications/NotificationsManage.tsx @@ -12,13 +12,12 @@ import { Button, Popover, PopoverContent, PopoverTrigger } from '@teable/ui-lib' import { cn } from '@teable/ui-lib/shadcn'; import { useTranslation } from 'next-i18next'; import React, { useEffect, useState } from 'react'; -import { systemConfig } from '@/features/i18n/system.config'; import { NotificationList } from './NotificationList'; export const NotificationsManage: React.FC = () => { const queryClient = useQueryClient(); const notification = useNotification(); - const { t } = useTranslation(systemConfig.i18nNamespaces); + const { t } = useTranslation('common'); const [isOpen, setOpen] = useState(false); const [unreadCount, setUnreadCount] = useState(0); @@ -86,7 +85,7 @@ export const NotificationsManage: React.FC = () => { }} > -

{t('system:notification.new', { count: num })}

+

{t('notification.new', { count: num })}

); @@ -136,14 +135,14 @@ export const NotificationsManage: React.FC = () => { }} > - {t('system:notification.markAllAsRead')} + {t('notification.markAllAsRead')} ) : ( '' )}
-
{t('system:notification.title')}
+
{t('notification.title')}
{renderNewButton()}
diff --git a/packages/common-i18n/src/locales/en/common.json b/packages/common-i18n/src/locales/en/common.json index 0c41d9558..72e0af19c 100644 --- a/packages/common-i18n/src/locales/en/common.json +++ b/packages/common-i18n/src/locales/en/common.json @@ -218,5 +218,15 @@ "allowSpaceCreation": "Allow everyone to create new spaces", "allowSpaceCreationDescription": "Disabling this option will prevent users other than administrators from creating new spaces." } + }, + "notification": { + "title": "Notifications", + "unread": "Unread", + "read": "Read", + "markAs": "Mark this notification as {{status}}", + "markAllAsRead": "Mark all as read", + "noUnread": "No unread notifications", + "changeSetting": "Change page notification settings", + "new": "new {{count}}" } } diff --git a/packages/common-i18n/src/locales/en/system.json b/packages/common-i18n/src/locales/en/system.json index aca2bde43..022055e67 100644 --- a/packages/common-i18n/src/locales/en/system.json +++ b/packages/common-i18n/src/locales/en/system.json @@ -12,15 +12,5 @@ "paymentRequired": { "title": "402 - Subscription Upgrade Required", "description": "Your current subscription does not support access to this feature.

Please upgrade your subscription to continue." - }, - "notification": { - "title": "Notifications", - "unread": "Unread", - "read": "Read", - "markAs": "Mark this notification as {{status}}", - "markAllAsRead": "Mark all as read", - "noUnread": "No unread notifications", - "changeSetting": "Change page notification settings", - "new": "new {{count}}" } } diff --git a/packages/common-i18n/src/locales/zh/common.json b/packages/common-i18n/src/locales/zh/common.json index 39a02fda2..74fdb6e16 100644 --- a/packages/common-i18n/src/locales/zh/common.json +++ b/packages/common-i18n/src/locales/zh/common.json @@ -217,5 +217,15 @@ "allowSpaceCreation": "允许所有人创建新的空间", "allowSpaceCreationDescription": "关闭此选项将禁止除管理员以外的用户创建新的空间。" } + }, + "notification": { + "title": "通知", + "unread": "未读", + "read": "已读", + "markAs": "将此通知标记为{{status}}", + "markAllAsRead": "全部标记为已读", + "noUnread": "没有未读通知", + "changeSetting": "更改页面通知设置", + "new": "新消息{{count}}条" } } diff --git a/packages/common-i18n/src/locales/zh/system.json b/packages/common-i18n/src/locales/zh/system.json index ca368bc9b..f0c3e79a1 100644 --- a/packages/common-i18n/src/locales/zh/system.json +++ b/packages/common-i18n/src/locales/zh/system.json @@ -12,15 +12,5 @@ "paymentRequired": { "title": "402 - 需要升级订阅", "description": "您当前的订阅计划不支持访问此功能,请升级您的订阅以继续使用" - }, - "notification": { - "title": "通知", - "unread": "未读", - "read": "已读", - "markAs": "将此通知标记为{{status}}", - "markAllAsRead": "全部标记为已读", - "noUnread": "没有未读通知", - "changeSetting": "更改页面通知设置", - "new": "新消息{{count}}条" } } From 7e9f44a2f9e9a028e703335b224a9dd87c9e9b64 Mon Sep 17 00:00:00 2001 From: caoxing Date: Mon, 15 Jul 2024 17:12:38 +0800 Subject: [PATCH 8/9] feat: add import tips --- .../app/blocks/import-table/TableImport.tsx | 120 ++++++++++-------- .../inplace-panel/FieldSelector.tsx | 2 +- .../new-create-panel/FieldConfigPanel.tsx | 5 +- .../common-i18n/src/locales/en/table.json | 9 +- .../common-i18n/src/locales/zh/table.json | 10 +- packages/sdk/src/config/local-storage-keys.ts | 1 + 6 files changed, 88 insertions(+), 59 deletions(-) diff --git a/apps/nextjs-app/src/features/app/blocks/import-table/TableImport.tsx b/apps/nextjs-app/src/features/app/blocks/import-table/TableImport.tsx index 39b146688..c63139b0a 100644 --- a/apps/nextjs-app/src/features/app/blocks/import-table/TableImport.tsx +++ b/apps/nextjs-app/src/features/app/blocks/import-table/TableImport.tsx @@ -15,7 +15,7 @@ import { importTableFromFile, inplaceImportTableFromFile, } from '@teable/openapi'; -import { useBase } from '@teable/sdk'; +import { useBase, LocalStorageKeys } from '@teable/sdk'; import { Dialog, DialogContent, @@ -35,11 +35,14 @@ import { AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, + AlertDialogTrigger, + Checkbox, } from '@teable/ui-lib'; import { toast } from '@teable/ui-lib/shadcn/ui/sonner'; import { useRouter } from 'next/router'; import { useTranslation } from 'next-i18next'; import { useState, useRef, useCallback } from 'react'; +import { useLocalStorage } from 'react-use'; import { FieldConfigPanel, InplaceFieldConfigPanel } from './field-config-panel'; import { UploadPanel } from './upload-panel'; import { UrlPanel } from './UrlPanel'; @@ -68,7 +71,6 @@ export const TableImport = (props: ITableImportProps) => { const [step, setStep] = useState(Step.UPLOAD); const { children, open, onOpenChange, fileType, tableId } = props; const [errorMessage, setErrorMessage] = useState(''); - const [alterDialogVisible, setAlterDialogVisible] = useState(false); const [file, setFile] = useState(null); const [fileInfo, setFileInfo] = useState({} as IAnalyzeRo); const primitiveWorkSheets = useRef({}); @@ -78,10 +80,8 @@ export const TableImport = (props: ITableImportProps) => { sourceWorkSheetKey: '', sourceColumnMap: {}, }); - - const closeDialog = () => { - dialogOpenProxy(false); - }; + const [shouldAlert, setShouldAlert] = useLocalStorage(LocalStorageKeys.ImportAlert, true); + const [shouldTips, setShouldTips] = useState(false); const { mutateAsync: importNewTableFn, isLoading } = useMutation({ mutationFn: async ({ baseId, importRo }: { baseId: string; importRo: IImportOptionRo }) => { @@ -241,17 +241,6 @@ export const TableImport = (props: ITableImportProps) => { [fileType, t] ); - const dialogOpenProxy = useCallback( - (open: boolean) => { - if (!open && Step.CONFIG && isLoading) { - setAlterDialogVisible(true); - return; - } - onOpenChange?.(open); - }, - [isLoading, onOpenChange] - ); - const fieldChangeHandler = (value: IImportOptionRo['worksheets']) => { setWorkSheets(value); }; @@ -262,7 +251,7 @@ export const TableImport = (props: ITableImportProps) => { return ( <> - + onOpenChange?.(open)}> {children && {children}} {open && ( { {step === Step.CONFIG && (
- - + {shouldAlert ? ( + + + + + + + {t('table:import.title.tipsTitle')} + + {t('table:import.tips.importAlert')} + + +
+ { + setShouldTips(res); + }} + /> + +
+ + {t('table:import.menu.cancel')} + { + importTable(); + if (shouldTips) { + setShouldAlert(false); + } + }} + > + {t('table:import.title.confirm')} + + +
+
+ ) : ( + + )}
)}
)}
- - setAlterDialogVisible(open)} - > - - - {t('table:import.title.leaveTitle')} - {t('table:import.tips.leaveTip')} - - - {t('table:import.menu.cancel')} - { - onOpenChange?.(false); - }} - > - {t('table:import.menu.leave')} - - - - ); }; diff --git a/apps/nextjs-app/src/features/app/blocks/import-table/field-config-panel/inplace-panel/FieldSelector.tsx b/apps/nextjs-app/src/features/app/blocks/import-table/field-config-panel/inplace-panel/FieldSelector.tsx index 7c772a8ac..bbc056038 100644 --- a/apps/nextjs-app/src/features/app/blocks/import-table/field-config-panel/inplace-panel/FieldSelector.tsx +++ b/apps/nextjs-app/src/features/app/blocks/import-table/field-config-panel/inplace-panel/FieldSelector.tsx @@ -30,7 +30,7 @@ interface IFieldSelector { export function FieldSelector(props: IFieldSelector) { const { options, onSelect, value, disabled = false } = props; const [open, setOpen] = useState(false); - const { t } = useTranslation(['table']); + const { t } = useTranslation(['table', 'common']); const comOptions = useMemo(() => { const result = [...options]; diff --git a/apps/nextjs-app/src/features/app/blocks/import-table/field-config-panel/new-create-panel/FieldConfigPanel.tsx b/apps/nextjs-app/src/features/app/blocks/import-table/field-config-panel/new-create-panel/FieldConfigPanel.tsx index 749a9f62b..938ef5aef 100644 --- a/apps/nextjs-app/src/features/app/blocks/import-table/field-config-panel/new-create-panel/FieldConfigPanel.tsx +++ b/apps/nextjs-app/src/features/app/blocks/import-table/field-config-panel/new-create-panel/FieldConfigPanel.tsx @@ -104,11 +104,12 @@ const FieldConfigPanel = (props: IFieldConfigPanel) => { key={sheetKey} size="xs" onClick={() => setSelectedSheetKey(sheetKey)} - className={cn('w-20 shrink-0 cursor-pointer truncate rounded-sm', { + className={cn('max-w-32 shrink-0 cursor-pointer truncate rounded-sm px-2', { 'bg-secondary': sheetKey === selectedSheetKey, })} + title={workSheets[sheetKey].name} > - {workSheets[sheetKey].name} + {workSheets[sheetKey].name} ))} diff --git a/packages/common-i18n/src/locales/en/table.json b/packages/common-i18n/src/locales/en/table.json index 65ab664e8..e8c067e22 100644 --- a/packages/common-i18n/src/locales/en/table.json +++ b/packages/common-i18n/src/locales/en/table.json @@ -142,10 +142,11 @@ "importTitle": "Create a new table", "incrementImportTitle": "Import Into — ", "optionsTitle": "Import option", - "leaveTitle": "Are you sure to leave this page?", "primitiveFields": "Primitive Fields", "importFields": "Import Field", - "primaryField": "Primary Field" + "primaryField": "Primary Field", + "tipsTitle": "Tips", + "confirm": "Confirm and continue" }, "menu": { "addFromOtherSource": "Add from other sources", @@ -163,7 +164,9 @@ "analyzing": "analyzing", "notSupportFieldType": "Field type is not supported", "resultEmpty": "No results found.", - "searchPlaceholder": "Search import field" + "searchPlaceholder": "Search...", + "importAlert": "Once the import begins, it cannot be stopped until it is either successfully completed or terminated due to failure. The import result will be notify to you later. You'd better do not operate the table during the import, which may cause errors.", + "noTips": "I've know that, don't show again" }, "options": { "autoSelectFieldOptionName": "Auto-select field types", diff --git a/packages/common-i18n/src/locales/zh/table.json b/packages/common-i18n/src/locales/zh/table.json index 20ff22a7f..a7c73e22d 100644 --- a/packages/common-i18n/src/locales/zh/table.json +++ b/packages/common-i18n/src/locales/zh/table.json @@ -142,10 +142,11 @@ "importTitle": "创建一个新表格", "incrementImportTitle": "导入到 — ", "optionsTitle": "导入选项", - "leaveTitle": "确定离开此页面?", "primitiveFields": "原表字段", "importFields": "导入的字段", - "primaryField": "主键" + "primaryField": "主键", + "tipsTitle": "温馨提示", + "confirm": "确认并继续" }, "menu": { "addFromOtherSource": "从第三方资源导入", @@ -162,7 +163,10 @@ "fileExceedSizeTip": "该类型文件限制文件大小为", "analyzing": "分析中", "notSupportFieldType": "字段类型不支持", - "resultEmpty": "未查询到结果" + "resultEmpty": "未查询到结果", + "searchPlaceholder": "搜索...", + "importAlert": "一旦导入,不能中止,直到导入成功或失败中止,导入结果将会在推送到通知栏。导入期间,最好不要操作表格,可能会引起错误。", + "noTips": "我已知晓,不再提示" }, "options": { "autoSelectFieldOptionName": "自动预测类型", diff --git a/packages/sdk/src/config/local-storage-keys.ts b/packages/sdk/src/config/local-storage-keys.ts index c34c1054a..f9d646ae4 100644 --- a/packages/sdk/src/config/local-storage-keys.ts +++ b/packages/sdk/src/config/local-storage-keys.ts @@ -9,4 +9,5 @@ export enum LocalStorageKeys { ViewGridCollapsedGroup = 'ls_view_grid_collapsed_group', ViewKanbanCollapsedStack = 'ls_view_kanban_collapsed_stack', CompletedGuideMap = 'ls_completed_guide_map', + ImportAlert = 'ls_import_alert', } From 3e9c97752df79538b3bc80cd60d3817102e2e3ce Mon Sep 17 00:00:00 2001 From: caoxing Date: Mon, 15 Jul 2024 17:55:34 +0800 Subject: [PATCH 9/9] chore: reduce import tips complex judgement --- .../app/blocks/import-table/TableImport.tsx | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/apps/nextjs-app/src/features/app/blocks/import-table/TableImport.tsx b/apps/nextjs-app/src/features/app/blocks/import-table/TableImport.tsx index c63139b0a..539d0bbed 100644 --- a/apps/nextjs-app/src/features/app/blocks/import-table/TableImport.tsx +++ b/apps/nextjs-app/src/features/app/blocks/import-table/TableImport.tsx @@ -333,8 +333,8 @@ export const TableImport = (props: ITableImportProps) => { - {shouldAlert ? ( - + + {shouldAlert ? ( - - - {t('table:import.title.tipsTitle')} - - {t('table:import.tips.importAlert')} - - -
- { - setShouldTips(res); - }} - /> - -
- - {t('table:import.menu.cancel')} - { - importTable(); - if (shouldTips) { - setShouldAlert(false); - } - }} - > - {t('table:import.title.confirm')} - - -
-
- ) : ( - - )} + ) : ( + + )} + + + {t('table:import.title.tipsTitle')} + + {t('table:import.tips.importAlert')} + + +
+ { + setShouldTips(res); + }} + /> + +
+ + {t('table:import.menu.cancel')} + { + importTable(); + if (shouldTips) { + setShouldAlert(false); + } + }} + > + {t('table:import.title.confirm')} + + +
+
)}