diff --git a/packages/core/client/src/schema-component/antd/grid/Grid.tsx b/packages/core/client/src/schema-component/antd/grid/Grid.tsx index 734aa9e34f..082943cb7f 100644 --- a/packages/core/client/src/schema-component/antd/grid/Grid.tsx +++ b/packages/core/client/src/schema-component/antd/grid/Grid.tsx @@ -20,7 +20,6 @@ import { FilterBlockProvider } from '../../../filter-provider/FilterProvider'; import { NocoBaseRecursionField, RefreshComponentProvider, - useRefreshComponent, useRefreshFieldSchema, } from '../../../formily/NocoBaseRecursionField'; import { DndContext, DndContextProps } from '../../common/dnd-context'; @@ -379,11 +378,9 @@ export const Grid: any = observer( }, [fieldSchema, render, InitializerComponent, showDivider]); const refreshFieldSchema = useRefreshFieldSchema(); - const refreshComponent = useRefreshComponent(); const refresh = useCallback(() => { refreshFieldSchema?.(); - refreshComponent?.(); - }, [refreshComponent, refreshFieldSchema]); + }, [refreshFieldSchema]); return ( diff --git a/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/refresh.test.ts b/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/refresh.test.ts new file mode 100644 index 0000000000..8cc2b184c2 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/refresh.test.ts @@ -0,0 +1,34 @@ +/** + * 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 { expect, test } from '@nocobase/test/e2e'; +import { afterConfiguringTheModalWhenReopeningItTheContentShouldPersist } from './utils'; + +test.describe('refresh', () => { + test('After configuring the modal, when reopening it, the content should persist', async ({ mockPage, page }) => { + await mockPage(afterConfiguringTheModalWhenReopeningItTheContentShouldPersist).goto(); + + // 1. 点击 Bulk edit 按钮,打开弹窗 + await page.getByLabel('action-Action-Bulk edit-').click(); + + // 2. 新增一个表单区块 + await page.getByLabel('schema-initializer-Grid-popup').hover(); + await page.getByRole('menuitem', { name: 'form Form' }).click(); + + // 3. 新增一个名为 Nickname 的字段 + await page.getByLabel('schema-initializer-Grid-bulkEditForm:configureFields-users').hover(); + await page.getByRole('menuitem', { name: 'Nickname' }).click(); + + // 4. 关闭弹窗,然后再打开,刚才新增的字段应该还在 + await page.getByLabel('drawer-Action.Container-users-Bulk edit-mask').click(); + await page.getByLabel('action-Action-Bulk edit-').click(); + await expect(page.getByLabel('block-item-BulkEditField-').getByText('Nickname')).toBeVisible(); + await page.getByLabel('block-item-BulkEditField-').click(); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/utils.ts b/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/utils.ts index 3e67dc3ad2..d2068a7c82 100644 --- a/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/utils.ts +++ b/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/utils.ts @@ -1243,3 +1243,388 @@ export const theAddBlockButtonInDrawerShouldBeVisible = { 'x-index': 1, }, }; +export const afterConfiguringTheModalWhenReopeningItTheContentShouldPersist = { + pageSchema: { + type: 'void', + 'x-component': 'Page', + name: 'rjzvy4bmawn', + 'x-uid': '1rs9caegbf2', + 'x-async': false, + properties: { + tab: { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'page:addBlock', + properties: { + bmsmf8futai: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'x84k7qs6jko', + 'x-async': false, + 'x-index': 4, + }, + noe2oca30hc: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 't7jxa830ps6', + 'x-async': false, + 'x-index': 5, + }, + w2hnq7rau9p: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': '0fjjtg8z7ws', + 'x-async': false, + 'x-index': 7, + }, + fcfs4oot86g: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'nklv7lonpgn', + 'x-async': false, + 'x-index': 8, + }, + i22fydav355: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'fz4g6cr9jvr', + 'x-async': false, + 'x-index': 10, + }, + row_6u7y7uccrvz: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-index': 12, + 'x-uid': '7tzumo4nec7', + 'x-async': false, + }, + higfesvgj7g: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': '8hpa6qf3sez', + 'x-async': false, + 'x-index': 13, + }, + '37myao9n0wc': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'uw1dp2qxd3y', + 'x-async': false, + 'x-index': 14, + }, + uvfd76q4ye9: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'nc56fu33m42', + 'x-async': false, + 'x-index': 15, + }, + miidizeqgot: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'jf4qarrcs0z', + 'x-async': false, + 'x-index': 16, + }, + hxmr87i5imu: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'l3kdiqd9a7k', + 'x-async': false, + 'x-index': 17, + }, + pa8dwdi4h5a: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'uz5wcet83qn', + 'x-async': false, + 'x-index': 18, + }, + pno0a05tbnp: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'b4bakhhasp3', + 'x-async': false, + 'x-index': 19, + }, + uj09g5xgnr1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'qks035fnfl6', + 'x-async': false, + 'x-index': 20, + }, + giobcwj316k: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + 'x-uid': 'awwsb89nyso', + 'x-async': false, + 'x-index': 22, + }, + oznewtbvuyw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '1.6.11', + properties: { + bwtax0bnnp3: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '1.6.11', + properties: { + c0bypj7wg5q: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-use-decorator-props': 'useTableBlockDecoratorProps', + 'x-decorator-props': { + collection: 'users', + dataSource: 'main', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:table', + 'x-component': 'CardItem', + 'x-filter-targets': [], + 'x-app-version': '1.6.11', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'table:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-app-version': '1.6.11', + properties: { + '1dlvhzr308c': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Bulk edit")}}', + 'x-component': 'Action', + 'x-action': 'customize:bulkEdit', + 'x-action-settings': { + updateMode: 'selected', + }, + 'x-component-props': { + openMode: 'drawer', + icon: 'EditOutlined', + }, + 'x-align': 'right', + 'x-decorator': 'BulkEditActionDecorator', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:bulkEdit', + 'x-acl-action': 'update', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-app-version': '1.6.11', + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Bulk edit")}}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + 'x-app-version': '1.6.11', + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'popup:addTab', + 'x-initializer-props': { + gridInitializer: 'popup:bulkEdit:addBlock', + }, + 'x-app-version': '1.6.11', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Bulk edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + 'x-app-version': '1.6.11', + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'popup:bulkEdit:addBlock', + 'x-app-version': '1.6.11', + 'x-uid': '5ejbu8v5ol8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'gfheiqtl7f7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'if2rcx1dy2n', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'cxyi8q6lm3n', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vbvf13xq15t', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'amlzm32jhwg', + 'x-async': false, + 'x-index': 1, + }, + f232o2ds23n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'table:configureColumns', + 'x-component': 'TableV2', + 'x-use-component-props': 'useTableBlockProps', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + }, + 'x-app-version': '1.6.11', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-toolbar': 'TableColumnSchemaToolbar', + 'x-initializer': 'table:configureItemActions', + 'x-settings': 'fieldSettings:TableColumn', + 'x-toolbar-props': { + initializer: 'table:configureItemActions', + }, + 'x-app-version': '1.6.11', + properties: { + '153lpq30p5f': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-app-version': '1.6.11', + 'x-uid': '4mha1dmmyz9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'afmceivuaf0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'iu0xkmeuc5z', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'ylor106s9ok', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'rl50hidu14n', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xxhug2yumqf', + 'x-async': false, + 'x-index': 23, + }, + }, + name: 'h63eibc46on', + 'x-uid': 'u9g23o0ohgk', + 'x-async': true, + 'x-index': 1, + }, + }, + }, +}; diff --git a/packages/plugins/@nocobase/plugin-block-workbench/src/client/components/qrcode-scanner/index.tsx b/packages/plugins/@nocobase/plugin-block-workbench/src/client/components/qrcode-scanner/index.tsx index 15c46eb4ec..9365c8ee67 100644 --- a/packages/plugins/@nocobase/plugin-block-workbench/src/client/components/qrcode-scanner/index.tsx +++ b/packages/plugins/@nocobase/plugin-block-workbench/src/client/components/qrcode-scanner/index.tsx @@ -9,13 +9,13 @@ import { FileImageOutlined, LeftOutlined } from '@ant-design/icons'; import { useActionContext } from '@nocobase/client'; import { Html5Qrcode } from 'html5-qrcode'; -import React, { useEffect, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ScanBox } from './ScanBox'; import { useScanner } from './useScanner'; const qrcodeEleId = 'qrcode'; -export const QRCodeScannerInner = (props) => { +export const QRCodeScannerInner = ({ setVisible }) => { const containerRef = useRef(); const imgUploaderRef = useRef(); const { t } = useTranslation('block-workbench'); @@ -23,9 +23,17 @@ export const QRCodeScannerInner = (props) => { const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0); const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0); + const onScanSuccess = useCallback( + (text) => { + setVisible(false); + }, + [setVisible], + ); + const { startScanFile } = useScanner({ onScannerSizeChanged: setOriginVideoSize, elementId: qrcodeEleId, + onScanSuccess, }); const getBoxStyle = (): React.CSSProperties => { @@ -174,7 +182,7 @@ export const QRCodeScanner = (props) => { return visible && cameraAvaliable ? (
- + setVisible(false)} />
{t('Scan QR code')}
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 7e4e5eae0b..16568498ce 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 @@ -20,7 +20,7 @@ function removeStringIfStartsWith(text: string, prefix: string): string { return text; } -export function useScanner({ onScannerSizeChanged, elementId }) { +export function useScanner({ onScannerSizeChanged, elementId, onScanSuccess }) { const app = useApp(); const mobileManager = app.pm.get(MobileManager); const basename = mobileManager.mobileRouter.basename.replace(/\/+$/, ''); @@ -50,12 +50,17 @@ export function useScanner({ onScannerSizeChanged, elementId }) { }, }, (text) => { + if (text?.startsWith('http')) { + window.location.href = text; + return; + } navigate(removeStringIfStartsWith(text, basename)); + onScanSuccess && onScanSuccess(text); }, undefined, ); }, - [navigate, onScannerSizeChanged, viewPoint, basename], + [navigate, onScannerSizeChanged, viewPoint, basename, onScanSuccess], ); const stopScanner = useCallback(async (scanner: Html5Qrcode) => { const state = scanner.getState(); @@ -69,13 +74,18 @@ export function useScanner({ onScannerSizeChanged, elementId }) { await stopScanner(scanner); try { const { decodedText } = await scanner.scanFileV2(file, false); + if (decodedText?.startsWith('http')) { + window.location.href = decodedText; + return; + } navigate(removeStringIfStartsWith(decodedText, basename)); + onScanSuccess && onScanSuccess(decodedText); } catch (error) { alert(t('QR code recognition failed, please scan again')); startScanCamera(scanner); } }, - [stopScanner, scanner, navigate, basename, t, startScanCamera], + [stopScanner, scanner, navigate, basename, t, startScanCamera, onScanSuccess], ); useEffect(() => { diff --git a/packages/plugins/@nocobase/plugin-locale-tester/.npmignore b/packages/plugins/@nocobase/plugin-locale-tester/.npmignore new file mode 100644 index 0000000000..65f5e8779f --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/.npmignore @@ -0,0 +1,2 @@ +/node_modules +/src diff --git a/packages/plugins/@nocobase/plugin-locale-tester/README.md b/packages/plugins/@nocobase/plugin-locale-tester/README.md new file mode 100644 index 0000000000..cfac872027 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/README.md @@ -0,0 +1 @@ +# @nocobase/plugin-locale-tester diff --git a/packages/plugins/@nocobase/plugin-locale-tester/client.d.ts b/packages/plugins/@nocobase/plugin-locale-tester/client.d.ts new file mode 100644 index 0000000000..6c459cbac4 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/client.d.ts @@ -0,0 +1,2 @@ +export * from './dist/client'; +export { default } from './dist/client'; diff --git a/packages/plugins/@nocobase/plugin-locale-tester/client.js b/packages/plugins/@nocobase/plugin-locale-tester/client.js new file mode 100644 index 0000000000..b6e3be70e6 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/client.js @@ -0,0 +1 @@ +module.exports = require('./dist/client/index.js'); diff --git a/packages/plugins/@nocobase/plugin-locale-tester/package.json b/packages/plugins/@nocobase/plugin-locale-tester/package.json new file mode 100644 index 0000000000..fc75da2f54 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/package.json @@ -0,0 +1,14 @@ +{ + "name": "@nocobase/plugin-locale-tester", + "displayName": "Locale tester", + "displayName.zh-CN": "翻译测试工具", + "version": "1.7.0-alpha.10", + "homepage": "https://github.com/nocobase/locales", + "main": "dist/server/index.js", + "dependencies": {}, + "peerDependencies": { + "@nocobase/client": "1.x", + "@nocobase/server": "1.x", + "@nocobase/test": "1.x" + } +} diff --git a/packages/plugins/@nocobase/plugin-locale-tester/server.d.ts b/packages/plugins/@nocobase/plugin-locale-tester/server.d.ts new file mode 100644 index 0000000000..c41081ddc6 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/server.d.ts @@ -0,0 +1,2 @@ +export * from './dist/server'; +export { default } from './dist/server'; diff --git a/packages/plugins/@nocobase/plugin-locale-tester/server.js b/packages/plugins/@nocobase/plugin-locale-tester/server.js new file mode 100644 index 0000000000..972842039a --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/server.js @@ -0,0 +1 @@ +module.exports = require('./dist/server/index.js'); diff --git a/packages/plugins/@nocobase/plugin-locale-tester/src/client/client.d.ts b/packages/plugins/@nocobase/plugin-locale-tester/src/client/client.d.ts new file mode 100644 index 0000000000..4e96f83fa1 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/src/client/client.d.ts @@ -0,0 +1,249 @@ +/** + * 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. + */ + +// CSS modules +type CSSModuleClasses = { readonly [key: string]: string }; + +declare module '*.module.css' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.scss' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.sass' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.less' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.styl' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.stylus' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.pcss' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.module.sss' { + const classes: CSSModuleClasses; + export default classes; +} + +// CSS +declare module '*.css' { } +declare module '*.scss' { } +declare module '*.sass' { } +declare module '*.less' { } +declare module '*.styl' { } +declare module '*.stylus' { } +declare module '*.pcss' { } +declare module '*.sss' { } + +// Built-in asset types +// see `src/node/constants.ts` + +// images +declare module '*.apng' { + const src: string; + export default src; +} +declare module '*.png' { + const src: string; + export default src; +} +declare module '*.jpg' { + const src: string; + export default src; +} +declare module '*.jpeg' { + const src: string; + export default src; +} +declare module '*.jfif' { + const src: string; + export default src; +} +declare module '*.pjpeg' { + const src: string; + export default src; +} +declare module '*.pjp' { + const src: string; + export default src; +} +declare module '*.gif' { + const src: string; + export default src; +} +declare module '*.svg' { + const src: string; + export default src; +} +declare module '*.ico' { + const src: string; + export default src; +} +declare module '*.webp' { + const src: string; + export default src; +} +declare module '*.avif' { + const src: string; + export default src; +} + +// media +declare module '*.mp4' { + const src: string; + export default src; +} +declare module '*.webm' { + const src: string; + export default src; +} +declare module '*.ogg' { + const src: string; + export default src; +} +declare module '*.mp3' { + const src: string; + export default src; +} +declare module '*.wav' { + const src: string; + export default src; +} +declare module '*.flac' { + const src: string; + export default src; +} +declare module '*.aac' { + const src: string; + export default src; +} +declare module '*.opus' { + const src: string; + export default src; +} +declare module '*.mov' { + const src: string; + export default src; +} +declare module '*.m4a' { + const src: string; + export default src; +} +declare module '*.vtt' { + const src: string; + export default src; +} + +// fonts +declare module '*.woff' { + const src: string; + export default src; +} +declare module '*.woff2' { + const src: string; + export default src; +} +declare module '*.eot' { + const src: string; + export default src; +} +declare module '*.ttf' { + const src: string; + export default src; +} +declare module '*.otf' { + const src: string; + export default src; +} + +// other +declare module '*.webmanifest' { + const src: string; + export default src; +} +declare module '*.pdf' { + const src: string; + export default src; +} +declare module '*.txt' { + const src: string; + export default src; +} + +// wasm?init +declare module '*.wasm?init' { + const initWasm: (options?: WebAssembly.Imports) => Promise; + export default initWasm; +} + +// web worker +declare module '*?worker' { + const workerConstructor: { + new(options?: { name?: string }): Worker; + }; + export default workerConstructor; +} + +declare module '*?worker&inline' { + const workerConstructor: { + new(options?: { name?: string }): Worker; + }; + export default workerConstructor; +} + +declare module '*?worker&url' { + const src: string; + export default src; +} + +declare module '*?sharedworker' { + const sharedWorkerConstructor: { + new(options?: { name?: string }): SharedWorker; + }; + export default sharedWorkerConstructor; +} + +declare module '*?sharedworker&inline' { + const sharedWorkerConstructor: { + new(options?: { name?: string }): SharedWorker; + }; + export default sharedWorkerConstructor; +} + +declare module '*?sharedworker&url' { + const src: string; + export default src; +} + +declare module '*?raw' { + const src: string; + export default src; +} + +declare module '*?url' { + const src: string; + export default src; +} + +declare module '*?inline' { + const src: string; + export default src; +} diff --git a/packages/plugins/@nocobase/plugin-locale-tester/src/client/index.tsx b/packages/plugins/@nocobase/plugin-locale-tester/src/client/index.tsx new file mode 100644 index 0000000000..7ecfc9a69d --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/src/client/index.tsx @@ -0,0 +1,124 @@ +/** + * 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 { useForm } from '@formily/react'; +import { ActionProps, ISchema, Plugin, SchemaComponent, useAPIClient, useApp, useRequest } from '@nocobase/client'; +import { Alert, App as AntdApp, Card, Spin } from 'antd'; +import React from 'react'; +import { useT } from './locale'; + +function LocaleTester() { + const { data, loading } = useRequest({ + url: 'localeTester:get', + }); + const t = useT(); + + const schema: ISchema = { + type: 'void', + name: 'root', + properties: { + test: { + type: 'void', + 'x-component': 'FormV2', + properties: { + locale: { + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'Input.JSON', + 'x-component-props': { + autoSize: { minRows: 20, maxRows: 30 }, + }, + default: data?.data?.locale, + title: t('Translations'), + }, + button: { + type: 'void', + 'x-component': 'Action', + title: t('Submit'), + 'x-use-component-props': 'useSubmitActionProps', + }, + }, + }, + }, + }; + + const useSubmitActionProps = () => { + const form = useForm(); + const api = useAPIClient(); + const { message } = AntdApp.useApp(); + const app = useApp(); + + return { + type: 'primary', + htmlType: 'submit', + async onClick() { + await form.submit(); + const values = form.values; + await api.request({ + url: 'localeTester:updateOrCreate', + method: 'post', + params: { + filterKeys: ['id'], + }, + data: { + id: data?.data?.id, + locale: values.locale, + }, + }); + message.success(app.i18n.t('Saved successfully!')); + window.location.reload(); + }, + }; + }; + + if (loading) { + return ; + } + return ( + + nocobase/locales to get the language file that needs translation, then paste it below and provide the translation.`, + ), + }} + > + } + /> + + + ); +} + +export class PluginLocaleTesterClient extends Plugin { + async afterAdd() { + // await this.app.pm.add() + } + + async beforeLoad() {} + + // You can get and modify the app instance here + async load() { + this.app.pluginSettingsManager.add('locale-tester', { + title: this.t('Locale tester'), + icon: 'TranslationOutlined', + Component: LocaleTester, + }); + // this.app.addComponents({}) + // this.app.addScopes({}) + // this.app.addProvider() + // this.app.addProviders() + // this.app.router.add() + } +} + +export default PluginLocaleTesterClient; diff --git a/packages/plugins/@nocobase/plugin-locale-tester/src/client/locale.ts b/packages/plugins/@nocobase/plugin-locale-tester/src/client/locale.ts new file mode 100644 index 0000000000..84797b7d1b --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/src/client/locale.ts @@ -0,0 +1,21 @@ +/** + * 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. + */ + +// @ts-ignore +import pkg from './../../package.json'; +import { useApp } from '@nocobase/client'; + +export function useT() { + const app = useApp(); + return (str: string) => app.i18n.t(str, { ns: [pkg.name, 'client'] }); +} + +export function tStr(key: string) { + return `{{t(${JSON.stringify(key)}, { ns: ['${pkg.name}', 'client'], nsMode: 'fallback' })}}`; +} diff --git a/packages/plugins/@nocobase/plugin-locale-tester/src/index.ts b/packages/plugins/@nocobase/plugin-locale-tester/src/index.ts new file mode 100644 index 0000000000..be99a2ff1a --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/src/index.ts @@ -0,0 +1,11 @@ +/** + * 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. + */ + +export * from './server'; +export { default } from './server'; diff --git a/packages/plugins/@nocobase/plugin-locale-tester/src/locale/en-US.json b/packages/plugins/@nocobase/plugin-locale-tester/src/locale/en-US.json new file mode 100644 index 0000000000..cc8bcdd470 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/src/locale/en-US.json @@ -0,0 +1,5 @@ +{ + "Locale": "Locale", + "Locale tester": "Locale tester", + "Please go to nocobase/locales to get the language file that needs translation, then paste it below and provide the translation.": "Please go to nocobase/locales to get the language file that needs translation, then paste it below and provide the translation." +} \ No newline at end of file diff --git a/packages/plugins/@nocobase/plugin-locale-tester/src/locale/zh-CN.json b/packages/plugins/@nocobase/plugin-locale-tester/src/locale/zh-CN.json new file mode 100644 index 0000000000..d4074a2ae0 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/src/locale/zh-CN.json @@ -0,0 +1,5 @@ +{ + "Translations": "翻译", + "Locale tester": "翻译测试工具", + "Please go to nocobase/locales to get the language file that needs translation, then paste it below and provide the translation.": "请前往 nocobase/locales 获取需要翻译的语言文件,粘贴到下方并进行翻译。" +} \ No newline at end of file diff --git a/packages/plugins/@nocobase/plugin-locale-tester/src/server/collections/.gitkeep b/packages/plugins/@nocobase/plugin-locale-tester/src/server/collections/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/plugins/@nocobase/plugin-locale-tester/src/server/collections/localeTester.ts b/packages/plugins/@nocobase/plugin-locale-tester/src/server/collections/localeTester.ts new file mode 100644 index 0000000000..eceb54bbbc --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/src/server/collections/localeTester.ts @@ -0,0 +1,21 @@ +/** + * 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 { defineCollection } from '@nocobase/database'; + +export default defineCollection({ + name: 'localeTester', + autoGenId: true, + fields: [ + { + type: 'json', + name: 'locale', + }, + ], +}); diff --git a/packages/plugins/@nocobase/plugin-locale-tester/src/server/index.ts b/packages/plugins/@nocobase/plugin-locale-tester/src/server/index.ts new file mode 100644 index 0000000000..be989de7c3 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/src/server/index.ts @@ -0,0 +1,10 @@ +/** + * 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. + */ + +export { default } from './plugin'; diff --git a/packages/plugins/@nocobase/plugin-locale-tester/src/server/plugin.ts b/packages/plugins/@nocobase/plugin-locale-tester/src/server/plugin.ts new file mode 100644 index 0000000000..7c9367961a --- /dev/null +++ b/packages/plugins/@nocobase/plugin-locale-tester/src/server/plugin.ts @@ -0,0 +1,59 @@ +/** + * 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 { Plugin } from '@nocobase/server'; +import _ from 'lodash'; + +export class PluginLocaleTesterServer extends Plugin { + async afterAdd() {} + + async beforeLoad() { + this.app.acl.registerSnippet({ + name: `pm.${this.name}`, + actions: ['localeTester:*'], + }); + } + + async load() { + this.app.resourceManager.use(async (ctx, next) => { + await next(); + const { resourceName, actionName } = ctx.action; + if (resourceName === 'app' && actionName === 'getLang') { + const repository = this.db.getRepository('localeTester'); + const record = await repository.findOne(); + const locale = record?.locale || {}; + if (locale['cronstrue']) { + _.set(ctx.body, 'cronstrue', locale['cronstrue']); + } + if (locale['react-js-cron']) { + _.set(ctx.body, 'cron', locale['react-js-cron']); + } + Object.keys(locale).forEach((key) => { + if (key === 'cronstrue' || key === 'react-js-cron') { + return; + } + const value = locale[key]; + _.set(ctx.body, ['resources', key], value); + const k = key.replace('@nocobase/', '').replace('@nocobase/plugin-', ''); + _.set(ctx.body, ['resources', k], value); + }); + } + }); + } + + async install() {} + + async afterEnable() {} + + async afterDisable() {} + + async remove() {} +} + +export default PluginLocaleTesterServer; diff --git a/packages/presets/nocobase/package.json b/packages/presets/nocobase/package.json index 5c4b3b0e31..aa729ad907 100644 --- a/packages/presets/nocobase/package.json +++ b/packages/presets/nocobase/package.json @@ -44,6 +44,7 @@ "@nocobase/plugin-gantt": "1.7.0-alpha.10", "@nocobase/plugin-graph-collection-manager": "1.7.0-alpha.10", "@nocobase/plugin-kanban": "1.7.0-alpha.10", + "@nocobase/plugin-locale-tester": "1.7.0-alpha.10", "@nocobase/plugin-localization": "1.7.0-alpha.10", "@nocobase/plugin-logger": "1.7.0-alpha.10", "@nocobase/plugin-map": "1.7.0-alpha.10",