From de6bfb0b716a1ebd9ce334217168cde69ea81b03 Mon Sep 17 00:00:00 2001 From: ajie Date: Sat, 17 May 2025 21:59:24 +0800 Subject: [PATCH 1/2] fix(importer): handle empty string cells during field import to prevent errors (#6880) --- .../interfaces/input-interface.test.ts | 69 +++++++++++++++++++ .../src/interfaces/input-interface.ts | 4 ++ 2 files changed, 73 insertions(+) create mode 100644 packages/core/database/src/__tests__/interfaces/input-interface.test.ts diff --git a/packages/core/database/src/__tests__/interfaces/input-interface.test.ts b/packages/core/database/src/__tests__/interfaces/input-interface.test.ts new file mode 100644 index 00000000000..75b2d221dbd --- /dev/null +++ b/packages/core/database/src/__tests__/interfaces/input-interface.test.ts @@ -0,0 +1,69 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +import { createMockDatabase, Database } from '@nocobase/database'; +import { InputInterface } from '../../interfaces/input-interface'; + +describe('input interface', () => { + let db: Database; + + beforeEach(async () => { + db = await createMockDatabase(); + await db.clean({ drop: true }); + }); + + afterEach(async () => { + await db.close(); + }); + + describe('validate', () => { + it('should validate string values', () => { + const inputInterface = new InputInterface({}); + expect(inputInterface.validate('test string')).toBe(true); + expect(inputInterface.validate('')).toBe(true); + }); + + it('should validate number values', () => { + const inputInterface = new InputInterface({}); + expect(inputInterface.validate(123)).toBe(true); + expect(inputInterface.validate(0)).toBe(true); + expect(inputInterface.validate(-10.5)).toBe(true); + }); + + it('should reject non-string and non-number values', () => { + const inputInterface = new InputInterface({}); + expect(inputInterface.validate(null)).toBe(false); + expect(inputInterface.validate(undefined)).toBe(false); + expect(inputInterface.validate({})).toBe(false); + expect(inputInterface.validate([])).toBe(false); + expect(inputInterface.validate(true)).toBe(false); + }); + }); + + describe('toValue', () => { + it('should convert valid values to string', () => { + const inputInterface = new InputInterface({}); + expect(inputInterface.toValue('test')).toBe('test'); + expect(inputInterface.toValue(123)).toBe('123'); + expect(inputInterface.toValue(-10.5)).toBe('-10.5'); + }); + + it('should handle null and undefined values by returning null', () => { + const inputInterface = new InputInterface({}); + expect(inputInterface.toValue(null)).toBeNull(); + expect(inputInterface.toValue(undefined)).toBeUndefined(); + }); + + it('should throw error for object values', () => { + const inputInterface = new InputInterface({}); + expect(() => inputInterface.toValue({})).toThrow('Invalid value, expected string'); + expect(() => inputInterface.toValue([])).toThrow('Invalid value, expected string'); + }); + }); +}); diff --git a/packages/core/database/src/interfaces/input-interface.ts b/packages/core/database/src/interfaces/input-interface.ts index 6ce0717ec45..3f46bc19dbe 100644 --- a/packages/core/database/src/interfaces/input-interface.ts +++ b/packages/core/database/src/interfaces/input-interface.ts @@ -12,6 +12,10 @@ import { BaseInterface } from './base-interface'; export class InputInterface extends BaseInterface { toValue(value) { + if (value === null || value === undefined || typeof value === 'string') { + return value; + } + if (this.validate(value)) { return value.toString(); } From 329efea17683894f9f913f87d6cb5984272c9160 Mon Sep 17 00:00:00 2001 From: Sheldon Guo Date: Sun, 18 May 2025 18:59:09 +0800 Subject: [PATCH 2/2] refactor(router): change router property to public and improve basename handling in useScanner (#6877) --- packages/core/client/src/application/RouterManager.tsx | 2 +- .../src/client/components/qrcode-scanner/useScanner.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/core/client/src/application/RouterManager.tsx b/packages/core/client/src/application/RouterManager.tsx index a8b08dafa0d..ea3a35bb4e1 100644 --- a/packages/core/client/src/application/RouterManager.tsx +++ b/packages/core/client/src/application/RouterManager.tsx @@ -49,7 +49,7 @@ export class RouterManager { protected routes: Record = {}; protected options: RouterOptions; public app: Application; - private router; + public router; get basename() { return this.router.basename; } diff --git a/packages/plugins/@nocobase/plugin-block-workbench/src/client/components/qrcode-scanner/useScanner.ts b/packages/plugins/@nocobase/plugin-block-workbench/src/client/components/qrcode-scanner/useScanner.ts index 16568498ce0..9d1e31f2ccc 100644 --- a/packages/plugins/@nocobase/plugin-block-workbench/src/client/components/qrcode-scanner/useScanner.ts +++ b/packages/plugins/@nocobase/plugin-block-workbench/src/client/components/qrcode-scanner/useScanner.ts @@ -23,7 +23,11 @@ function removeStringIfStartsWith(text: string, prefix: string): string { export function useScanner({ onScannerSizeChanged, elementId, onScanSuccess }) { const app = useApp(); const mobileManager = app.pm.get(MobileManager); - const basename = mobileManager.mobileRouter.basename.replace(/\/+$/, ''); + const { mobileRouter } = mobileManager; + const appRouter = app.router; + + const rawBasename = mobileRouter?.router ? mobileRouter?.basename : appRouter.basename; + const basename = rawBasename.replace(/\/+$/, ''); const [scanner, setScanner] = useState();