mirror of
https://github.com/nocobase/nocobase
synced 2024-11-16 01:17:43 +00:00
Merge branch 'next' into 730
This commit is contained in:
commit
7d8818271c
18
CHANGELOG.md
18
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
|
||||
|
@ -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
|
||||
|
||||
### 🐛 修复
|
||||
|
@ -2,7 +2,9 @@
|
||||
"version": "1.4.0-alpha",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"npmClientArgs": ["--ignore-engines"],
|
||||
"npmClientArgs": [
|
||||
"--ignore-engines"
|
||||
],
|
||||
"command": {
|
||||
"version": {
|
||||
"forcePublish": true,
|
||||
|
@ -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: {
|
||||
|
@ -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();
|
||||
|
@ -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 (
|
||||
|
@ -44,9 +44,14 @@ export const SchemaInitializerItemGroup: FC<SchemaInitializerItemGroupProps> = (
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
||||
export const SchemaInitializerItemGroupInternal = () => {
|
||||
const itemConfig: any = useSchemaInitializerItem<SchemaInitializerItemGroupProps>();
|
||||
|
||||
const searchedChildren = useMenuSearch(itemConfig);
|
||||
if (itemConfig.name !== 'displayFields') {
|
||||
return <SchemaInitializerItemGroup {...itemConfig} />;
|
||||
}
|
||||
/* eslint-disable react/no-children-prop */
|
||||
return <SchemaInitializerItemGroup {...itemConfig} children={searchedChildren} />;
|
||||
};
|
||||
|
@ -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]);
|
||||
|
||||
// 最终结果项
|
||||
|
@ -1023,5 +1023,6 @@
|
||||
"When the Label exceeds the width": "字段标题超出宽度时",
|
||||
"Line break": "换行",
|
||||
"Ellipsis": "省略",
|
||||
"Set block layout": "设置区块布局"
|
||||
"Set block layout": "设置区块布局",
|
||||
"Add & Update": "添加 & 更新"
|
||||
}
|
||||
|
@ -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: {},
|
||||
},
|
||||
},
|
||||
|
@ -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')}}",
|
||||
|
@ -27,7 +27,7 @@ export const PluginAddModal: FC<IPluginFormProps> = ({ onClose, isShow }) => {
|
||||
const [type, setType] = useState<'npm' | 'upload' | 'url'>('npm');
|
||||
|
||||
return (
|
||||
<Modal onCancel={() => onClose()} footer={null} destroyOnClose title={t('Add & update')} width={580} open={isShow}>
|
||||
<Modal onCancel={() => onClose()} footer={null} destroyOnClose title={t('Add & Update')} width={580} open={isShow}>
|
||||
{/* <label style={{ fontWeight: 'bold' }}>{t('Source')}:</label> */}
|
||||
<div style={{ marginTop: theme.marginLG, marginBottom: theme.marginLG }}>
|
||||
<Radio.Group optionType="button" defaultValue={type} onChange={(e) => setType(e.target.value)}>
|
||||
|
@ -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')}
|
||||
|
@ -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]);
|
||||
|
@ -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);
|
||||
});
|
||||
}}
|
||||
|
@ -237,6 +237,12 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> 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<StateT = DefaultState, ContextT = DefaultContext> 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<StateT = DefaultState, ContextT = DefaultContext> 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<StateT = DefaultState, ContextT = DefaultContext> 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<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
registerCli(this);
|
||||
|
||||
this._version = new ApplicationVersion(this);
|
||||
|
||||
for (const callback of Application.staticCommands) {
|
||||
callback(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected createMainDataSource(options: ApplicationOptions) {
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 [];
|
||||
}
|
||||
|
@ -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<void>;
|
||||
export type AppDbCreator = (
|
||||
app: Application,
|
||||
options?: Transactionable & { context?: any; applicationModel?: ApplicationModel },
|
||||
) => Promise<void>;
|
||||
export type AppOptionsFactory = (appName: string, mainApp: Application) => any;
|
||||
export type SubAppUpgradeHandler = (mainApp: Application) => Promise<void>;
|
||||
|
||||
@ -189,13 +192,18 @@ export class PluginMultiAppManagerServer extends Plugin {
|
||||
appOptionsFactory: this.appOptionsFactory,
|
||||
});
|
||||
|
||||
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;
|
||||
|
1
storage/.gitignore
vendored
1
storage/.gitignore
vendored
@ -7,3 +7,4 @@ app-upgrading
|
||||
/verdaccio/storage
|
||||
libs
|
||||
scripts
|
||||
.cache
|
Loading…
Reference in New Issue
Block a user