diff --git a/CHANGELOG.md b/CHANGELOG.md index 609fa97ad2..1091680211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v1.3.43-beta](https://github.com/nocobase/nocobase/compare/v1.3.42-beta...v1.3.43-beta) - 2024-11-05 + +### 🚀 Improvements + +- **[client]** numeric precision can be configured to 8 digits ([#5552](https://github.com/nocobase/nocobase/pull/5552)) by @chenos + +### 🐛 Bug Fixes + +- **[client]** Fix linkage style not updating in form. ([#5539](https://github.com/nocobase/nocobase/pull/5539)) by @sheldon66 + +- **[Auth: API keys]** Fix the URL path for API keys settings page ([#5562](https://github.com/nocobase/nocobase/pull/5562)) by @2013xile + +- **[Mobile]** Fix the issue of preview images being covered by page ([#5535](https://github.com/nocobase/nocobase/pull/5535)) by @zhangzhonghe + +- **[Block: Map]** resolve map rendering in sub-details and incorrect value display for empty fields ([#5526](https://github.com/nocobase/nocobase/pull/5526)) by @katherinehhh + +- **[Collection: Tree]** Fix errors when updating path collection ([#5551](https://github.com/nocobase/nocobase/pull/5551)) by @2013xile + ## [v1.3.42-beta](https://github.com/nocobase/nocobase/compare/v1.3.41-beta...v1.3.42-beta) - 2024-10-28 ### 🐛 Bug Fixes diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index f3b79a7ef3..3d87bbe809 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -5,6 +5,24 @@ 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), 并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。 +## [v1.3.43-beta](https://github.com/nocobase/nocobase/compare/v1.3.42-beta...v1.3.43-beta) - 2024-11-05 + +### 🚀 优化 + +- **[client]** 数字精确度支持配置 8 位数 ([#5552](https://github.com/nocobase/nocobase/pull/5552)) by @chenos + +### 🐛 修复 + +- **[client]** 修复联动样式在表单里不更新。 ([#5539](https://github.com/nocobase/nocobase/pull/5539)) by @sheldon66 + +- **[认证:API 密钥]** 修复 API keys 设置页面的 URL 路径 ([#5562](https://github.com/nocobase/nocobase/pull/5562)) by @2013xile + +- **[移动端]** 修复预览图片被页面覆盖的问题 ([#5535](https://github.com/nocobase/nocobase/pull/5535)) by @zhangzhonghe + +- **[区块:地图]** 子详情中地图字段,渲染地图不正确,应该显示坐标字符/详情区块,没有值的字段,会显示上一条数据的值 ([#5526](https://github.com/nocobase/nocobase/pull/5526)) by @katherinehhh + +- **[数据表:树]** 修复更新路径表时的报错 ([#5551](https://github.com/nocobase/nocobase/pull/5551)) by @2013xile + ## [v1.3.42-beta](https://github.com/nocobase/nocobase/compare/v1.3.41-beta...v1.3.42-beta) - 2024-10-28 ### 🐛 修复 diff --git a/lerna.json b/lerna.json index 9710afb03d..0ecbef7cdf 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,9 @@ "version": "1.4.0-alpha", "npmClient": "yarn", "useWorkspaces": true, - "npmClientArgs": ["--ignore-engines"], + "npmClientArgs": [ + "--ignore-engines" + ], "command": { "version": { "forcePublish": true, diff --git a/packages/core/app/client/.umirc.ts b/packages/core/app/client/.umirc.ts index e3c887a459..1eceaf186f 100644 --- a/packages/core/app/client/.umirc.ts +++ b/packages/core/app/client/.umirc.ts @@ -37,6 +37,7 @@ export default defineConfig({ `, }, ], + cacheDirectoryPath: process.env.APP_CLIENT_CACHE_DIR || `node_modules/.cache`, outputPath: path.resolve(__dirname, '../dist/client'), hash: true, alias: { diff --git a/packages/core/cli/src/commands/dev.js b/packages/core/cli/src/commands/dev.js index 8a805adb60..5eebb59003 100644 --- a/packages/core/cli/src/commands/dev.js +++ b/packages/core/cli/src/commands/dev.js @@ -38,16 +38,16 @@ module.exports = (cli) => { depth: 1, // 只监听第一层目录 }); + await fs.promises.mkdir(path.dirname(process.env.WATCH_FILE), { recursive: true }); + watcher .on('addDir', async (pathname) => { generatePlugins(); - const file = path.resolve(process.cwd(), 'storage/app.watch.ts'); - await fs.promises.writeFile(file, `export const watchId = '${uid()}';`, 'utf-8'); + await fs.promises.writeFile(process.env.WATCH_FILE, `export const watchId = '${uid()}';`, 'utf-8'); }) .on('unlinkDir', async (pathname) => { generatePlugins(); - const file = path.resolve(process.cwd(), 'storage/app.watch.ts'); - await fs.promises.writeFile(file, `export const watchId = '${uid()}';`, 'utf-8'); + await fs.promises.writeFile(process.env.WATCH_FILE, `export const watchId = '${uid()}';`, 'utf-8'); }); promptForTs(); diff --git a/packages/core/cli/src/util.js b/packages/core/cli/src/util.js index 4d58ecb894..bbf2f73d56 100644 --- a/packages/core/cli/src/util.js +++ b/packages/core/cli/src/util.js @@ -350,6 +350,7 @@ exports.initEnv = function initEnv() { LOGGER_BASE_PATH: 'storage/logs', APP_SERVER_BASE_URL: '', APP_PUBLIC_PATH: '/', + WATCH_FILE: resolve(process.cwd(), 'storage/app.watch.ts'), }; if ( diff --git a/packages/core/client/src/application/schema-initializer/components/SchemaInitializerItemGroup.tsx b/packages/core/client/src/application/schema-initializer/components/SchemaInitializerItemGroup.tsx index 2163255598..5a9baacc20 100644 --- a/packages/core/client/src/application/schema-initializer/components/SchemaInitializerItemGroup.tsx +++ b/packages/core/client/src/application/schema-initializer/components/SchemaInitializerItemGroup.tsx @@ -44,9 +44,14 @@ export const SchemaInitializerItemGroup: FC = ( /** * @internal */ + export const SchemaInitializerItemGroupInternal = () => { const itemConfig: any = useSchemaInitializerItem(); + const searchedChildren = useMenuSearch(itemConfig); + if (itemConfig.name !== 'displayFields') { + return ; + } /* eslint-disable react/no-children-prop */ return ; }; diff --git a/packages/core/client/src/application/schema-initializer/components/SchemaInitializerItemSearchFields.tsx b/packages/core/client/src/application/schema-initializer/components/SchemaInitializerItemSearchFields.tsx index 3f8866461e..b6016f57cd 100644 --- a/packages/core/client/src/application/schema-initializer/components/SchemaInitializerItemSearchFields.tsx +++ b/packages/core/client/src/application/schema-initializer/components/SchemaInitializerItemSearchFields.tsx @@ -11,6 +11,7 @@ import { uid } from '@formily/shared'; import { Divider, Empty, Input, MenuProps } from 'antd'; import React, { useEffect, useMemo, useState, useRef } from 'react'; import { useTranslation } from 'react-i18next'; +import { useCompile } from '../../../'; function getPrefixAndCompare(a, b) { const prefixA = a.replace(/-displayCollectionFields$/, ''); @@ -100,6 +101,7 @@ export const useMenuSearch = (props: { children: any[]; showType?: boolean; hide const { children, showType, hideSearch, name } = props; const items = children?.concat?.() || []; const [searchValue, setSearchValue] = useState(null); + const compile = useCompile(); // 处理搜索逻辑 const limitedSearchedItems = useMemo(() => { @@ -107,13 +109,14 @@ export const useMenuSearch = (props: { children: any[]; showType?: boolean; hide return items; } const lowerSearchValue = searchValue.toLocaleLowerCase(); - return items.filter( - (item) => - (item.label || item.title) && - String(item.label || item.title) + return items.filter((item) => { + return ( + (item.title || item.label) && + String(compile(item.title || item.label)) .toLocaleLowerCase() - .includes(lowerSearchValue), - ); + .includes(lowerSearchValue) + ); + }); }, [searchValue, items]); // 最终结果项 diff --git a/packages/core/client/src/locale/zh-CN.json b/packages/core/client/src/locale/zh-CN.json index 812e3cc6d2..1c7f1c6641 100644 --- a/packages/core/client/src/locale/zh-CN.json +++ b/packages/core/client/src/locale/zh-CN.json @@ -1023,5 +1023,6 @@ "When the Label exceeds the width": "字段标题超出宽度时", "Line break": "换行", "Ellipsis": "省略", - "Set block layout": "设置区块布局" + "Set block layout": "设置区块布局", + "Add & Update": "添加 & 更新" } diff --git a/packages/core/client/src/modules/actions/view-edit-popup/PopupActionInitializer.tsx b/packages/core/client/src/modules/actions/view-edit-popup/PopupActionInitializer.tsx index bd10a7a3b6..881e503410 100644 --- a/packages/core/client/src/modules/actions/view-edit-popup/PopupActionInitializer.tsx +++ b/packages/core/client/src/modules/actions/view-edit-popup/PopupActionInitializer.tsx @@ -53,7 +53,7 @@ export const PopupActionInitializer = (props) => { grid: { type: 'void', 'x-component': 'Grid', - 'x-initializer': 'popup:common:addBlock', + 'x-initializer': props?.['x-initializer'] || 'popup:common:addBlock', properties: {}, }, }, diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/TableActionInitializers.tsx b/packages/core/client/src/modules/blocks/data-blocks/table/TableActionInitializers.tsx index c31d340ede..dba31541c6 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/table/TableActionInitializers.tsx +++ b/packages/core/client/src/modules/blocks/data-blocks/table/TableActionInitializers.tsx @@ -42,6 +42,19 @@ const commonOptions = { }, useVisible: () => useActionAvailable('create'), }, + { + type: 'item', + title: "{{t('Popup')}}", + name: 'popup', + Component: 'PopupActionInitializer', + componentProps: { + 'x-component': 'Action', + 'x-initializer': 'page:addBlock', + }, + schema: { + 'x-align': 'right', + }, + }, { type: 'item', title: "{{t('Delete')}}", diff --git a/packages/core/client/src/pm/PluginForm/modal/PluginAddModal.tsx b/packages/core/client/src/pm/PluginForm/modal/PluginAddModal.tsx index c78190b725..7e2a7c1f05 100644 --- a/packages/core/client/src/pm/PluginForm/modal/PluginAddModal.tsx +++ b/packages/core/client/src/pm/PluginForm/modal/PluginAddModal.tsx @@ -27,7 +27,7 @@ export const PluginAddModal: FC = ({ onClose, isShow }) => { const [type, setType] = useState<'npm' | 'upload' | 'url'>('npm'); return ( - onClose()} footer={null} destroyOnClose title={t('Add & update')} width={580} open={isShow}> + onClose()} footer={null} destroyOnClose title={t('Add & Update')} width={580} open={isShow}> {/* */}
setType(e.target.value)}> diff --git a/packages/core/client/src/schema-component/antd/association-field/SubTable.tsx b/packages/core/client/src/schema-component/antd/association-field/SubTable.tsx index 0c512ac01b..0abb554a1d 100644 --- a/packages/core/client/src/schema-component/antd/association-field/SubTable.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/SubTable.tsx @@ -165,7 +165,7 @@ export const SubTable: any = observer( }; const getFilter = () => { const targetKey = collectionField?.targetKey || 'id'; - const list = (field.value || []).map((option) => option[targetKey]).filter(Boolean); + const list = (field.value || []).map((option) => option?.[targetKey]).filter(Boolean); const filter = list.length ? { $and: [{ [`${targetKey}.$ne`]: list }] } : {}; return filter; }; @@ -235,6 +235,7 @@ export const SubTable: any = observer( // 计算总页数,并跳转到最后一页 const totalPages = Math.ceil(field.value.length / (field.componentProps?.pageSize || 10)); setCurrentPage(totalPages); + return field.onInput(field.value); }} > {t('Add new')} diff --git a/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx b/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx index 3102eb0427..b4381b8534 100644 --- a/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx +++ b/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx @@ -86,7 +86,8 @@ const InternalRemoteSelect = withDynamicSchemaProps( const operator = useMemo(() => { if (targetField?.interface) { - return getInterface(targetField.interface)?.filterable?.operators[0].value || '$includes'; + const initialOperator = getInterface(targetField.interface)?.filterable?.operators[0].value || '$includes'; + return initialOperator !== '$eq' ? initialOperator : '$includes'; } return '$includes'; }, [targetField]); diff --git a/packages/core/client/src/schema-component/antd/table-v2/Table.tsx b/packages/core/client/src/schema-component/antd/table-v2/Table.tsx index c607623721..23e3eb7c4c 100644 --- a/packages/core/client/src/schema-component/antd/table-v2/Table.tsx +++ b/packages/core/client/src/schema-component/antd/table-v2/Table.tsx @@ -196,6 +196,9 @@ const useTableColumns = (props: { showDel?: any; isSubTable?: boolean }, paginat deleteCount: 1, }); field.value.splice(fieldIndex, 1); + setTimeout(() => { + field.value[field.value.length] = null; + }); return field.onInput(field.value); }); }} diff --git a/packages/core/server/src/application.ts b/packages/core/server/src/application.ts index 82476feed1..97b3e3ad76 100644 --- a/packages/core/server/src/application.ts +++ b/packages/core/server/src/application.ts @@ -237,6 +237,12 @@ export class Application exten } } + private static staticCommands = []; + + static addCommand(callback: (app: Application) => void) { + this.staticCommands.push(callback); + } + private _sqlLogger: Logger; get sqlLogger() { @@ -440,6 +446,10 @@ export class Application exten return packageJson.version; } + getPackageVersion() { + return packageJson.version; + } + /** * This method is deprecated and should not be used. * Use {@link #this.pm.addPreset()} instead. @@ -540,6 +550,11 @@ export class Application exten this._loaded = false; } + async createCacheManager() { + this._cacheManager = await createCacheManager(this, this.options.cacheManager); + return this._cacheManager; + } + async load(options?: LoadOptions) { if (this._loaded) { return; @@ -570,7 +585,7 @@ export class Application exten await this.cacheManager.close(); } - this._cacheManager = await createCacheManager(this, this.options.cacheManager); + this._cacheManager = await this.createCacheManager(); this.log.debug('init plugins'); this.setMaintainingMessage('init plugins'); @@ -1195,6 +1210,10 @@ export class Application exten registerCli(this); this._version = new ApplicationVersion(this); + + for (const callback of Application.staticCommands) { + callback(this); + } } protected createMainDataSource(options: ApplicationOptions) { diff --git a/packages/core/server/src/gateway/index.ts b/packages/core/server/src/gateway/index.ts index 7f65e72ded..2f0f323565 100644 --- a/packages/core/server/src/gateway/index.ts +++ b/packages/core/server/src/gateway/index.ts @@ -311,7 +311,7 @@ export class Gateway extends EventEmitter { if (!process.env.IS_DEV_CMD) { return; } - const file = resolve(process.cwd(), 'storage/app.watch.ts'); + const file = process.env.WATCH_FILE; if (!fs.existsSync(file)) { await fs.promises.writeFile(file, `export const watchId = '${uid()}';`, 'utf-8'); } diff --git a/packages/core/server/src/helper.ts b/packages/core/server/src/helper.ts index bb528af0fd..32067f0faa 100644 --- a/packages/core/server/src/helper.ts +++ b/packages/core/server/src/helper.ts @@ -16,7 +16,6 @@ import { randomUUID } from 'crypto'; import fs from 'fs'; import i18next from 'i18next'; import bodyParser from 'koa-bodyparser'; -import { resolve } from 'path'; import { createHistogram, RecordableHistogram } from 'perf_hooks'; import Application, { ApplicationOptions } from './application'; import { dataWrapping } from './middlewares/data-wrapping'; @@ -124,8 +123,7 @@ export const getCommandFullName = (command: Command) => { /* istanbul ignore next -- @preserve */ export const tsxRerunning = async () => { - const file = resolve(process.cwd(), 'storage/app.watch.ts'); - await fs.promises.writeFile(file, `export const watchId = '${uid()}';`, 'utf-8'); + await fs.promises.writeFile(process.env.WATCH_FILE, `export const watchId = '${uid()}';`, 'utf-8'); }; /* istanbul ignore next -- @preserve */ diff --git a/packages/core/server/src/plugin-manager/findPackageNames.ts b/packages/core/server/src/plugin-manager/findPackageNames.ts index bed5a95e91..573d53dd8e 100644 --- a/packages/core/server/src/plugin-manager/findPackageNames.ts +++ b/packages/core/server/src/plugin-manager/findPackageNames.ts @@ -32,6 +32,19 @@ async function trim(packageNames: string[]) { return names; } +const excludes = [ + '@nocobase/plugin-audit-logs', + '@nocobase/plugin-backup-restore', + '@nocobase/plugin-charts', + '@nocobase/plugin-disable-pm-add', + '@nocobase/plugin-mobile-client', + '@nocobase/plugin-mock-collections', + '@nocobase/plugin-multi-app-share-collection', + '@nocobase/plugin-notifications', + '@nocobase/plugin-snapshot-field', + '@nocobase/plugin-workflow-test', +]; + export async function findPackageNames() { const patterns = [ './packages/plugins/*/package.json', @@ -52,23 +65,11 @@ export async function findPackageNames() { return packageJson.name; }), ); - const excludes = [ - '@nocobase/plugin-audit-logs', - '@nocobase/plugin-backup-restore', - '@nocobase/plugin-charts', - '@nocobase/plugin-disable-pm-add', - '@nocobase/plugin-mobile-client', - '@nocobase/plugin-mock-collections', - '@nocobase/plugin-multi-app-share-collection', - '@nocobase/plugin-notifications', - '@nocobase/plugin-snapshot-field', - '@nocobase/plugin-workflow-test', - ]; const nocobasePlugins = await findNocobasePlugins(); const { APPEND_PRESET_BUILT_IN_PLUGINS = '', APPEND_PRESET_LOCAL_PLUGINS = '' } = process.env; return trim( - _.difference(packageNames, excludes) - .filter(Boolean) + packageNames + .filter((pkg) => pkg && !excludes.includes(pkg)) .concat(nocobasePlugins) .concat(splitNames(APPEND_PRESET_BUILT_IN_PLUGINS)) .concat(splitNames(APPEND_PRESET_LOCAL_PLUGINS)), @@ -89,7 +90,7 @@ async function findNocobasePlugins() { try { const packageJson = await getPackageJson(); const pluginNames = Object.keys(packageJson.dependencies).filter((name) => name.startsWith('@nocobase/plugin-')); - return trim(pluginNames); + return trim(pluginNames.filter((pkg) => pkg && !excludes.includes(pkg))); } catch (error) { return []; } diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts b/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts index fb627fdf2d..1d7fe8ea2a 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts @@ -13,7 +13,10 @@ import lodash from 'lodash'; import path from 'path'; import { ApplicationModel } from '../server'; -export type AppDbCreator = (app: Application, options?: Transactionable & { context?: any }) => Promise; +export type AppDbCreator = ( + app: Application, + options?: Transactionable & { context?: any; applicationModel?: ApplicationModel }, +) => Promise; export type AppOptionsFactory = (appName: string, mainApp: Application) => any; export type SubAppUpgradeHandler = (mainApp: Application) => Promise; @@ -189,13 +192,18 @@ export class PluginMultiAppManagerServer extends Plugin { appOptionsFactory: this.appOptionsFactory, }); - // create database - await this.appDbCreator(subApp, { - transaction, - context: options.context, - }); + const quickstart = async () => { + // create database + await this.appDbCreator(subApp, { + transaction, + applicationModel: model, + context: options.context, + }); - const startPromise = subApp.runCommand('start', '--quickstart'); + await subApp.runCommand('start', '--quickstart'); + }; + + const startPromise = quickstart(); if (options?.context?.waitSubAppInstall) { await startPromise; diff --git a/storage/.gitignore b/storage/.gitignore index 62d0d471f9..17d5242569 100644 --- a/storage/.gitignore +++ b/storage/.gitignore @@ -7,3 +7,4 @@ app-upgrading /verdaccio/storage libs scripts +.cache \ No newline at end of file