mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-07 22:49:26 +08:00
Merge branch 'develop' of github.com:nocobase/nocobase into feat-main-datasource-mssql
This commit is contained in:
commit
b93d3bc01d
19
CHANGELOG.md
19
CHANGELOG.md
@ -5,6 +5,25 @@ 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/)
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [v1.6.10](https://github.com/nocobase/nocobase/compare/v1.6.9...v1.6.10) - 2025-03-25
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- **[client]**
|
||||||
|
- Unable to use 'Current User' variable when adding a link page ([#6536](https://github.com/nocobase/nocobase/pull/6536)) by @zhangzhonghe
|
||||||
|
|
||||||
|
- field assignment with null value is ineffective ([#6549](https://github.com/nocobase/nocobase/pull/6549)) by @katherinehhh
|
||||||
|
|
||||||
|
- `yarn doc` command error ([#6540](https://github.com/nocobase/nocobase/pull/6540)) by @gchust
|
||||||
|
|
||||||
|
- Remove the 'Allow multiple selection' option from dropdown single-select fields in filter forms ([#6515](https://github.com/nocobase/nocobase/pull/6515)) by @zhangzhonghe
|
||||||
|
|
||||||
|
- Relational field's data range linkage is not effective ([#6530](https://github.com/nocobase/nocobase/pull/6530)) by @zhangzhonghe
|
||||||
|
|
||||||
|
- **[Collection: Tree]** Migration issue for plugin-collection-tree ([#6537](https://github.com/nocobase/nocobase/pull/6537)) by @2013xile
|
||||||
|
|
||||||
|
- **[Action: Custom request]** Unable to download UTF-8 encoded files ([#6541](https://github.com/nocobase/nocobase/pull/6541)) by @2013xile
|
||||||
|
|
||||||
## [v1.6.9](https://github.com/nocobase/nocobase/compare/v1.6.8...v1.6.9) - 2025-03-23
|
## [v1.6.9](https://github.com/nocobase/nocobase/compare/v1.6.8...v1.6.9) - 2025-03-23
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
@ -5,6 +5,25 @@
|
|||||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
||||||
并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。
|
并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。
|
||||||
|
|
||||||
|
## [v1.6.10](https://github.com/nocobase/nocobase/compare/v1.6.9...v1.6.10) - 2025-03-25
|
||||||
|
|
||||||
|
### 🐛 修复
|
||||||
|
|
||||||
|
- **[client]**
|
||||||
|
- 添加链接页面时,无法使用“当前用户”变量 ([#6536](https://github.com/nocobase/nocobase/pull/6536)) by @zhangzhonghe
|
||||||
|
|
||||||
|
- 字段赋值对字段进行“空值”赋值无效 ([#6549](https://github.com/nocobase/nocobase/pull/6549)) by @katherinehhh
|
||||||
|
|
||||||
|
- `yarn doc` 命令报错 ([#6540](https://github.com/nocobase/nocobase/pull/6540)) by @gchust
|
||||||
|
|
||||||
|
- 筛选表单中,移除下拉单选字段的“允许多选”选项 ([#6515](https://github.com/nocobase/nocobase/pull/6515)) by @zhangzhonghe
|
||||||
|
|
||||||
|
- 关系字段的数据范围联动不生效 ([#6530](https://github.com/nocobase/nocobase/pull/6530)) by @zhangzhonghe
|
||||||
|
|
||||||
|
- **[数据表:树]** 树表插件的迁移脚本问题 ([#6537](https://github.com/nocobase/nocobase/pull/6537)) by @2013xile
|
||||||
|
|
||||||
|
- **[操作:自定义请求]** 无法下载utf8编码的文件 ([#6541](https://github.com/nocobase/nocobase/pull/6541)) by @2013xile
|
||||||
|
|
||||||
## [v1.6.9](https://github.com/nocobase/nocobase/compare/v1.6.8...v1.6.9) - 2025-03-23
|
## [v1.6.9](https://github.com/nocobase/nocobase/compare/v1.6.8...v1.6.9) - 2025-03-23
|
||||||
|
|
||||||
### 🐛 修复
|
### 🐛 修复
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"useWorkspaces": true,
|
"useWorkspaces": true,
|
||||||
"npmClientArgs": ["--ignore-engines"],
|
"npmClientArgs": ["--ignore-engines"],
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/acl",
|
"name": "@nocobase/acl",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/resourcer": "1.7.0-alpha.4",
|
"@nocobase/resourcer": "1.7.0-beta.9",
|
||||||
"@nocobase/utils": "1.7.0-alpha.4",
|
"@nocobase/utils": "1.7.0-beta.9",
|
||||||
"minimatch": "^5.1.1"
|
"minimatch": "^5.1.1"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/actions",
|
"name": "@nocobase/actions",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/cache": "1.7.0-alpha.4",
|
"@nocobase/cache": "1.7.0-beta.9",
|
||||||
"@nocobase/database": "1.7.0-alpha.4",
|
"@nocobase/database": "1.7.0-beta.9",
|
||||||
"@nocobase/resourcer": "1.7.0-alpha.4"
|
"@nocobase/resourcer": "1.7.0-beta.9"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/app",
|
"name": "@nocobase/app",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/database": "1.7.0-alpha.4",
|
"@nocobase/database": "1.7.0-beta.9",
|
||||||
"@nocobase/preset-nocobase": "1.7.0-alpha.4",
|
"@nocobase/preset-nocobase": "1.7.0-beta.9",
|
||||||
"@nocobase/server": "1.7.0-alpha.4"
|
"@nocobase/server": "1.7.0-beta.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nocobase/client": "1.7.0-alpha.4"
|
"@nocobase/client": "1.7.0-beta.9"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/auth",
|
"name": "@nocobase/auth",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/actions": "1.7.0-alpha.4",
|
"@nocobase/actions": "1.7.0-beta.9",
|
||||||
"@nocobase/cache": "1.7.0-alpha.4",
|
"@nocobase/cache": "1.7.0-beta.9",
|
||||||
"@nocobase/database": "1.7.0-alpha.4",
|
"@nocobase/database": "1.7.0-beta.9",
|
||||||
"@nocobase/resourcer": "1.7.0-alpha.4",
|
"@nocobase/resourcer": "1.7.0-beta.9",
|
||||||
"@nocobase/utils": "1.7.0-alpha.4",
|
"@nocobase/utils": "1.7.0-beta.9",
|
||||||
"@types/jsonwebtoken": "^8.5.8",
|
"@types/jsonwebtoken": "^8.5.8",
|
||||||
"jsonwebtoken": "^8.5.1"
|
"jsonwebtoken": "^8.5.1"
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/build",
|
"name": "@nocobase/build",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "Library build tool based on rollup.",
|
"description": "Library build tool based on rollup.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
|
4
packages/core/cache/package.json
vendored
4
packages/core/cache/package.json
vendored
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/cache",
|
"name": "@nocobase/cache",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/lock-manager": "1.7.0-alpha.4",
|
"@nocobase/lock-manager": "1.7.0-beta.9",
|
||||||
"bloom-filters": "^3.0.1",
|
"bloom-filters": "^3.0.1",
|
||||||
"cache-manager": "^5.2.4",
|
"cache-manager": "^5.2.4",
|
||||||
"cache-manager-redis-yet": "^4.1.2"
|
"cache-manager-redis-yet": "^4.1.2"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/cli",
|
"name": "@nocobase/cli",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./src/index.js",
|
"main": "./src/index.js",
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"nocobase": "./bin/index.js"
|
"nocobase": "./bin/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/app": "1.7.0-alpha.4",
|
"@nocobase/app": "1.7.0-beta.9",
|
||||||
"@types/fs-extra": "^11.0.1",
|
"@types/fs-extra": "^11.0.1",
|
||||||
"@umijs/utils": "3.5.20",
|
"@umijs/utils": "3.5.20",
|
||||||
"chalk": "^4.1.1",
|
"chalk": "^4.1.1",
|
||||||
@ -25,7 +25,7 @@
|
|||||||
"tsx": "^4.19.0"
|
"tsx": "^4.19.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nocobase/devtools": "1.7.0-alpha.4"
|
"@nocobase/devtools": "1.7.0-beta.9"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/client",
|
"name": "@nocobase/client",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"module": "es/index.mjs",
|
"module": "es/index.mjs",
|
||||||
@ -27,9 +27,9 @@
|
|||||||
"@formily/reactive-react": "^2.2.27",
|
"@formily/reactive-react": "^2.2.27",
|
||||||
"@formily/shared": "^2.2.27",
|
"@formily/shared": "^2.2.27",
|
||||||
"@formily/validator": "^2.2.27",
|
"@formily/validator": "^2.2.27",
|
||||||
"@nocobase/evaluators": "1.7.0-alpha.4",
|
"@nocobase/evaluators": "1.7.0-beta.9",
|
||||||
"@nocobase/sdk": "1.7.0-alpha.4",
|
"@nocobase/sdk": "1.7.0-beta.9",
|
||||||
"@nocobase/utils": "1.7.0-alpha.4",
|
"@nocobase/utils": "1.7.0-beta.9",
|
||||||
"ahooks": "^3.7.2",
|
"ahooks": "^3.7.2",
|
||||||
"antd": "5.24.2",
|
"antd": "5.24.2",
|
||||||
"antd-style": "3.7.1",
|
"antd-style": "3.7.1",
|
||||||
|
@ -102,44 +102,46 @@ export const SettingsCenterConfigure = () => {
|
|||||||
expandable={{
|
expandable={{
|
||||||
defaultExpandAllRows: true,
|
defaultExpandAllRows: true,
|
||||||
}}
|
}}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: 'title',
|
{
|
||||||
title: t('Plugin name'),
|
dataIndex: 'title',
|
||||||
render: (value) => {
|
title: t('Plugin name'),
|
||||||
return compile(value);
|
render: (value) => {
|
||||||
|
return compile(value);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
dataIndex: 'accessible',
|
||||||
dataIndex: 'accessible',
|
title: (
|
||||||
title: (
|
<>
|
||||||
<>
|
<Checkbox
|
||||||
<Checkbox
|
checked={allChecked}
|
||||||
checked={allChecked}
|
onChange={async () => {
|
||||||
onChange={async () => {
|
const values = allAclSnippets.map((v) => '!' + v);
|
||||||
const values = allAclSnippets.map((v) => '!' + v);
|
if (!allChecked) {
|
||||||
if (!allChecked) {
|
await resource.remove({
|
||||||
await resource.remove({
|
values,
|
||||||
values,
|
});
|
||||||
});
|
} else {
|
||||||
} else {
|
await resource.add({
|
||||||
await resource.add({
|
values,
|
||||||
values,
|
});
|
||||||
});
|
}
|
||||||
}
|
refresh();
|
||||||
refresh();
|
message.success(t('Saved successfully'));
|
||||||
message.success(t('Saved successfully'));
|
}}
|
||||||
}}
|
/>{' '}
|
||||||
/>{' '}
|
{t('Accessible')}
|
||||||
{t('Accessible')}
|
</>
|
||||||
</>
|
),
|
||||||
),
|
render: (_, record) => {
|
||||||
render: (_, record) => {
|
const checked = !snippets.includes('!' + record.aclSnippet);
|
||||||
const checked = !snippets.includes('!' + record.aclSnippet);
|
return <Checkbox checked={checked} onChange={() => handleChange(checked, record)} />;
|
||||||
return <Checkbox checked={checked} onChange={() => handleChange(checked, record)} />;
|
},
|
||||||
},
|
},
|
||||||
},
|
] as TableProps['columns']
|
||||||
] as TableProps['columns']}
|
}
|
||||||
dataSource={settings
|
dataSource={settings
|
||||||
.filter((v) => {
|
.filter((v) => {
|
||||||
return v.isTopLevel !== false;
|
return v.isTopLevel !== false;
|
||||||
|
@ -121,40 +121,42 @@ export const MenuConfigure = () => {
|
|||||||
expandable={{
|
expandable={{
|
||||||
defaultExpandAllRows: true,
|
defaultExpandAllRows: true,
|
||||||
}}
|
}}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: 'title',
|
{
|
||||||
title: t('Menu item title'),
|
dataIndex: 'title',
|
||||||
},
|
title: t('Menu item title'),
|
||||||
{
|
|
||||||
dataIndex: 'accessible',
|
|
||||||
title: (
|
|
||||||
<>
|
|
||||||
<Checkbox
|
|
||||||
checked={allChecked}
|
|
||||||
onChange={async (value) => {
|
|
||||||
if (allChecked) {
|
|
||||||
await resource.set({
|
|
||||||
values: [],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await resource.set({
|
|
||||||
values: allUids,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
refresh();
|
|
||||||
message.success(t('Saved successfully'));
|
|
||||||
}}
|
|
||||||
/>{' '}
|
|
||||||
{t('Accessible')}
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
render: (_, schema: { uid: string }) => {
|
|
||||||
const checked = uids.includes(schema.uid);
|
|
||||||
return <Checkbox checked={checked} onChange={() => handleChange(checked, schema)} />;
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
] as TableProps['columns']}
|
dataIndex: 'accessible',
|
||||||
|
title: (
|
||||||
|
<>
|
||||||
|
<Checkbox
|
||||||
|
checked={allChecked}
|
||||||
|
onChange={async (value) => {
|
||||||
|
if (allChecked) {
|
||||||
|
await resource.set({
|
||||||
|
values: [],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await resource.set({
|
||||||
|
values: allUids,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
message.success(t('Saved successfully'));
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
|
{t('Accessible')}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
render: (_, schema: { uid: string }) => {
|
||||||
|
const checked = uids.includes(schema.uid);
|
||||||
|
return <Checkbox checked={checked} onChange={() => handleChange(checked, schema)} />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
] as TableProps['columns']
|
||||||
|
}
|
||||||
dataSource={translateTitle(items)}
|
dataSource={translateTitle(items)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -105,48 +105,50 @@ export const RolesResourcesActions = connect((props) => {
|
|||||||
className={antTableCell}
|
className={antTableCell}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: 'displayName',
|
{
|
||||||
title: t('Action display name'),
|
dataIndex: 'displayName',
|
||||||
render: (value) => compile(value),
|
title: t('Action display name'),
|
||||||
},
|
render: (value) => compile(value),
|
||||||
{
|
},
|
||||||
dataIndex: 'onNewRecord',
|
{
|
||||||
title: t('Action type'),
|
dataIndex: 'onNewRecord',
|
||||||
render: (onNewRecord) =>
|
title: t('Action type'),
|
||||||
onNewRecord ? (
|
render: (onNewRecord) =>
|
||||||
<Tag color={'green'}>{t('Action on new records')}</Tag>
|
onNewRecord ? (
|
||||||
) : (
|
<Tag color={'green'}>{t('Action on new records')}</Tag>
|
||||||
<Tag color={'geekblue'}>{t('Action on existing records')}</Tag>
|
) : (
|
||||||
),
|
<Tag color={'geekblue'}>{t('Action on existing records')}</Tag>
|
||||||
},
|
),
|
||||||
{
|
},
|
||||||
dataIndex: 'enabled',
|
{
|
||||||
title: t('Allow'),
|
dataIndex: 'enabled',
|
||||||
render: (enabled, action) => (
|
title: t('Allow'),
|
||||||
<Checkbox
|
render: (enabled, action) => (
|
||||||
checked={enabled}
|
<Checkbox
|
||||||
onChange={() => {
|
checked={enabled}
|
||||||
toggleAction(action.name);
|
onChange={() => {
|
||||||
}}
|
toggleAction(action.name);
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataIndex: 'scope',
|
|
||||||
title: t('Data scope'),
|
|
||||||
render: (value, action) =>
|
|
||||||
!action.onNewRecord && (
|
|
||||||
<ScopeSelect
|
|
||||||
value={value}
|
|
||||||
onChange={(scope) => {
|
|
||||||
setScope(action.name, scope);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
] as TableProps['columns']}
|
{
|
||||||
|
dataIndex: 'scope',
|
||||||
|
title: t('Data scope'),
|
||||||
|
render: (value, action) =>
|
||||||
|
!action.onNewRecord && (
|
||||||
|
<ScopeSelect
|
||||||
|
value={value}
|
||||||
|
onChange={(scope) => {
|
||||||
|
setScope(action.name, scope);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
] as TableProps['columns']
|
||||||
|
}
|
||||||
dataSource={availableActions?.map((item) => {
|
dataSource={availableActions?.map((item) => {
|
||||||
let enabled = false;
|
let enabled = false;
|
||||||
let scope = null;
|
let scope = null;
|
||||||
@ -169,60 +171,62 @@ export const RolesResourcesActions = connect((props) => {
|
|||||||
className={antTableCell}
|
className={antTableCell}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
dataSource={fieldPermissions}
|
dataSource={fieldPermissions}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: ['uiSchema', 'title'],
|
{
|
||||||
title: t('Field display name'),
|
dataIndex: ['uiSchema', 'title'],
|
||||||
render: (value) => compile(value),
|
title: t('Field display name'),
|
||||||
},
|
render: (value) => compile(value),
|
||||||
...availableActionsWithFields.map((action) => {
|
},
|
||||||
const checked = allChecked?.[action.name];
|
...availableActionsWithFields.map((action) => {
|
||||||
return {
|
const checked = allChecked?.[action.name];
|
||||||
dataIndex: action.name,
|
return {
|
||||||
title: (
|
dataIndex: action.name,
|
||||||
<>
|
title: (
|
||||||
|
<>
|
||||||
|
<Checkbox
|
||||||
|
checked={checked}
|
||||||
|
onChange={() => {
|
||||||
|
const item = actionMap[action.name] || {
|
||||||
|
name: action.name,
|
||||||
|
};
|
||||||
|
if (checked) {
|
||||||
|
item.fields = [];
|
||||||
|
} else {
|
||||||
|
item.fields = collectionFields?.map?.((item) => item.name);
|
||||||
|
}
|
||||||
|
actionMap[action.name] = item;
|
||||||
|
onChange(Object.values(actionMap));
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
|
{compile(action.displayName)}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
render: (checked, field) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={checked}
|
checked={checked}
|
||||||
|
aria-label={`${action.name}_checkbox`}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
const item = actionMap[action.name] || {
|
const item = actionMap[action.name] || {
|
||||||
name: action.name,
|
name: action.name,
|
||||||
};
|
};
|
||||||
|
const fields: string[] = item.fields || [];
|
||||||
if (checked) {
|
if (checked) {
|
||||||
item.fields = [];
|
const index = fields.indexOf(field.name);
|
||||||
|
fields.splice(index, 1);
|
||||||
} else {
|
} else {
|
||||||
item.fields = collectionFields?.map?.((item) => item.name);
|
fields.push(field.name);
|
||||||
}
|
}
|
||||||
|
item.fields = fields;
|
||||||
actionMap[action.name] = item;
|
actionMap[action.name] = item;
|
||||||
onChange(Object.values(actionMap));
|
onChange(Object.values(actionMap));
|
||||||
}}
|
}}
|
||||||
/>{' '}
|
/>
|
||||||
{compile(action.displayName)}
|
),
|
||||||
</>
|
};
|
||||||
),
|
}),
|
||||||
render: (checked, field) => (
|
] as TableProps['columns']
|
||||||
<Checkbox
|
}
|
||||||
checked={checked}
|
|
||||||
aria-label={`${action.name}_checkbox`}
|
|
||||||
onChange={() => {
|
|
||||||
const item = actionMap[action.name] || {
|
|
||||||
name: action.name,
|
|
||||||
};
|
|
||||||
const fields: string[] = item.fields || [];
|
|
||||||
if (checked) {
|
|
||||||
const index = fields.indexOf(field.name);
|
|
||||||
fields.splice(index, 1);
|
|
||||||
} else {
|
|
||||||
fields.push(field.name);
|
|
||||||
}
|
|
||||||
item.fields = fields;
|
|
||||||
actionMap[action.name] = item;
|
|
||||||
onChange(Object.values(actionMap));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
] as TableProps['columns']}
|
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</FormLayout>
|
</FormLayout>
|
||||||
|
@ -55,62 +55,64 @@ export const StrategyActions = connect((props) => {
|
|||||||
size={'small'}
|
size={'small'}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
rowKey={'name'}
|
rowKey={'name'}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: 'displayName',
|
{
|
||||||
title: t('Action display name'),
|
dataIndex: 'displayName',
|
||||||
render: (value) => compile(value),
|
title: t('Action display name'),
|
||||||
},
|
render: (value) => compile(value),
|
||||||
{
|
},
|
||||||
dataIndex: 'onNewRecord',
|
{
|
||||||
title: t('Action type'),
|
dataIndex: 'onNewRecord',
|
||||||
render: (onNewRecord) =>
|
title: t('Action type'),
|
||||||
onNewRecord ? (
|
render: (onNewRecord) =>
|
||||||
<Tag color={'green'}>{t('Action on new records')}</Tag>
|
onNewRecord ? (
|
||||||
) : (
|
<Tag color={'green'}>{t('Action on new records')}</Tag>
|
||||||
<Tag color={'geekblue'}>{t('Action on existing records')}</Tag>
|
) : (
|
||||||
),
|
<Tag color={'geekblue'}>{t('Action on existing records')}</Tag>
|
||||||
},
|
),
|
||||||
{
|
},
|
||||||
dataIndex: 'enabled',
|
{
|
||||||
title: t('Allow'),
|
dataIndex: 'enabled',
|
||||||
render: (enabled, action) => (
|
title: t('Allow'),
|
||||||
<Checkbox
|
render: (enabled, action) => (
|
||||||
checked={enabled}
|
<Checkbox
|
||||||
aria-label={`${action.name}_checkbox`}
|
checked={enabled}
|
||||||
onChange={(e) => {
|
aria-label={`${action.name}_checkbox`}
|
||||||
if (enabled) {
|
onChange={(e) => {
|
||||||
delete scopes[action.name];
|
if (enabled) {
|
||||||
} else {
|
delete scopes[action.name];
|
||||||
scopes[action.name] = 'all';
|
} else {
|
||||||
}
|
scopes[action.name] = 'all';
|
||||||
onChange(toFieldValue(scopes));
|
}
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataIndex: 'scope',
|
|
||||||
title: t('Data scope'),
|
|
||||||
render: (scope, action) =>
|
|
||||||
!action.onNewRecord && (
|
|
||||||
<Select
|
|
||||||
data-testid="select-data-scope"
|
|
||||||
popupMatchSelectWidth={false}
|
|
||||||
size={'small'}
|
|
||||||
value={scope}
|
|
||||||
options={[
|
|
||||||
{ label: t('All records'), value: 'all' },
|
|
||||||
{ label: t('Own records'), value: 'own' },
|
|
||||||
]}
|
|
||||||
onChange={(value) => {
|
|
||||||
scopes[action.name] = value;
|
|
||||||
onChange(toFieldValue(scopes));
|
onChange(toFieldValue(scopes));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
] as TableProps['columns']}
|
{
|
||||||
|
dataIndex: 'scope',
|
||||||
|
title: t('Data scope'),
|
||||||
|
render: (scope, action) =>
|
||||||
|
!action.onNewRecord && (
|
||||||
|
<Select
|
||||||
|
data-testid="select-data-scope"
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
size={'small'}
|
||||||
|
value={scope}
|
||||||
|
options={[
|
||||||
|
{ label: t('All records'), value: 'all' },
|
||||||
|
{ label: t('Own records'), value: 'own' },
|
||||||
|
]}
|
||||||
|
onChange={(value) => {
|
||||||
|
scopes[action.name] = value;
|
||||||
|
onChange(toFieldValue(scopes));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
] as TableProps['columns']
|
||||||
|
}
|
||||||
dataSource={availableActions?.map((item) => {
|
dataSource={availableActions?.map((item) => {
|
||||||
let scope = 'all';
|
let scope = 'all';
|
||||||
let enabled = false;
|
let enabled = false;
|
||||||
|
@ -167,7 +167,7 @@ export function useCollectValuesToSubmit() {
|
|||||||
if (parsedValue !== null && parsedValue !== undefined) {
|
if (parsedValue !== null && parsedValue !== undefined) {
|
||||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||||
}
|
}
|
||||||
} else if (value != null && value !== '') {
|
} else if (value !== '') {
|
||||||
assignedValues[key] = value;
|
assignedValues[key] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -203,6 +203,12 @@ export function useCollectValuesToSubmit() {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function interpolateVariables(str: string, scope: Record<string, any>): string {
|
||||||
|
return str.replace(/\{\{\s*([a-zA-Z0-9_$-.]+?)\s*\}\}/g, (_, key) => {
|
||||||
|
return scope[key] !== undefined ? String(scope[key]) : '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const useCreateActionProps = () => {
|
export const useCreateActionProps = () => {
|
||||||
const filterByTk = useFilterByTk();
|
const filterByTk = useFilterByTk();
|
||||||
const record = useCollectionRecord();
|
const record = useCollectionRecord();
|
||||||
@ -219,11 +225,20 @@ export const useCreateActionProps = () => {
|
|||||||
const collectValues = useCollectValuesToSubmit();
|
const collectValues = useCollectValuesToSubmit();
|
||||||
const action = record.isNew ? actionField.componentProps.saveMode || 'create' : 'update';
|
const action = record.isNew ? actionField.componentProps.saveMode || 'create' : 'update';
|
||||||
const filterKeys = actionField.componentProps.filterKeys?.checked || [];
|
const filterKeys = actionField.componentProps.filterKeys?.checked || [];
|
||||||
|
const localVariables = useLocalVariables();
|
||||||
|
const variables = useVariables();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async onClick() {
|
async onClick() {
|
||||||
const { onSuccess, skipValidator, triggerWorkflows } = actionSchema?.['x-action-settings'] ?? {};
|
const { onSuccess, skipValidator, triggerWorkflows } = actionSchema?.['x-action-settings'] ?? {};
|
||||||
const { manualClose, redirecting, redirectTo, successMessage, actionAfterSuccess } = onSuccess || {};
|
const {
|
||||||
|
manualClose,
|
||||||
|
redirecting,
|
||||||
|
redirectTo: rawRedirectTo,
|
||||||
|
successMessage,
|
||||||
|
actionAfterSuccess,
|
||||||
|
} = onSuccess || {};
|
||||||
|
|
||||||
if (!skipValidator) {
|
if (!skipValidator) {
|
||||||
await form.submit();
|
await form.submit();
|
||||||
}
|
}
|
||||||
@ -241,6 +256,15 @@ export const useCreateActionProps = () => {
|
|||||||
: undefined,
|
: undefined,
|
||||||
updateAssociationValues,
|
updateAssociationValues,
|
||||||
});
|
});
|
||||||
|
let redirectTo = rawRedirectTo;
|
||||||
|
if (rawRedirectTo) {
|
||||||
|
const { exp, scope: expScope } = await replaceVariables(rawRedirectTo, {
|
||||||
|
variables,
|
||||||
|
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(data?.data?.data, {}) }],
|
||||||
|
});
|
||||||
|
redirectTo = interpolateVariables(exp, expScope);
|
||||||
|
}
|
||||||
|
|
||||||
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
||||||
setVisible?.(false);
|
setVisible?.(false);
|
||||||
}
|
}
|
||||||
@ -338,7 +362,7 @@ export const useAssociationCreateActionProps = () => {
|
|||||||
if (parsedValue) {
|
if (parsedValue) {
|
||||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||||
}
|
}
|
||||||
} else if (value != null && value !== '') {
|
} else if (value !== '') {
|
||||||
assignedValues[key] = value;
|
assignedValues[key] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -588,7 +612,13 @@ export const useCustomizeUpdateActionProps = () => {
|
|||||||
skipValidator,
|
skipValidator,
|
||||||
triggerWorkflows,
|
triggerWorkflows,
|
||||||
} = actionSchema?.['x-action-settings'] ?? {};
|
} = actionSchema?.['x-action-settings'] ?? {};
|
||||||
const { manualClose, redirecting, redirectTo, successMessage, actionAfterSuccess } = onSuccess || {};
|
const {
|
||||||
|
manualClose,
|
||||||
|
redirecting,
|
||||||
|
redirectTo: rawRedirectTo,
|
||||||
|
successMessage,
|
||||||
|
actionAfterSuccess,
|
||||||
|
} = onSuccess || {};
|
||||||
const assignedValues = {};
|
const assignedValues = {};
|
||||||
const waitList = Object.keys(originalAssignedValues).map(async (key) => {
|
const waitList = Object.keys(originalAssignedValues).map(async (key) => {
|
||||||
const value = originalAssignedValues[key];
|
const value = originalAssignedValues[key];
|
||||||
@ -605,7 +635,7 @@ export const useCustomizeUpdateActionProps = () => {
|
|||||||
if (parsedValue) {
|
if (parsedValue) {
|
||||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||||
}
|
}
|
||||||
} else if (value != null && value !== '') {
|
} else if (value !== '') {
|
||||||
assignedValues[key] = value;
|
assignedValues[key] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -614,7 +644,7 @@ export const useCustomizeUpdateActionProps = () => {
|
|||||||
if (skipValidator === false) {
|
if (skipValidator === false) {
|
||||||
await form.submit();
|
await form.submit();
|
||||||
}
|
}
|
||||||
await resource.update({
|
const result = await resource.update({
|
||||||
filterByTk,
|
filterByTk,
|
||||||
values: { ...assignedValues },
|
values: { ...assignedValues },
|
||||||
// TODO(refactor): should change to inject by plugin
|
// TODO(refactor): should change to inject by plugin
|
||||||
@ -622,6 +652,16 @@ export const useCustomizeUpdateActionProps = () => {
|
|||||||
? triggerWorkflows.map((row) => [row.workflowKey, row.context].filter(Boolean).join('!')).join(',')
|
? triggerWorkflows.map((row) => [row.workflowKey, row.context].filter(Boolean).join('!')).join(',')
|
||||||
: undefined,
|
: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let redirectTo = rawRedirectTo;
|
||||||
|
if (rawRedirectTo) {
|
||||||
|
const { exp, scope: expScope } = await replaceVariables(rawRedirectTo, {
|
||||||
|
variables,
|
||||||
|
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(result?.data?.data?.[0], {}) }],
|
||||||
|
});
|
||||||
|
redirectTo = interpolateVariables(exp, expScope);
|
||||||
|
}
|
||||||
|
|
||||||
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
||||||
setVisible?.(false);
|
setVisible?.(false);
|
||||||
}
|
}
|
||||||
@ -708,7 +748,7 @@ export const useCustomizeBulkUpdateActionProps = () => {
|
|||||||
if (parsedValue) {
|
if (parsedValue) {
|
||||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||||
}
|
}
|
||||||
} else if (value != null && value !== '') {
|
} else if (value !== '') {
|
||||||
assignedValues[key] = value;
|
assignedValues[key] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -913,7 +953,13 @@ export const useUpdateActionProps = () => {
|
|||||||
skipValidator,
|
skipValidator,
|
||||||
triggerWorkflows,
|
triggerWorkflows,
|
||||||
} = actionSchema?.['x-action-settings'] ?? {};
|
} = actionSchema?.['x-action-settings'] ?? {};
|
||||||
const { manualClose, redirecting, redirectTo, successMessage, actionAfterSuccess } = onSuccess || {};
|
const {
|
||||||
|
manualClose,
|
||||||
|
redirecting,
|
||||||
|
redirectTo: rawRedirectTo,
|
||||||
|
successMessage,
|
||||||
|
actionAfterSuccess,
|
||||||
|
} = onSuccess || {};
|
||||||
const assignedValues = {};
|
const assignedValues = {};
|
||||||
const waitList = Object.keys(originalAssignedValues).map(async (key) => {
|
const waitList = Object.keys(originalAssignedValues).map(async (key) => {
|
||||||
const value = originalAssignedValues[key];
|
const value = originalAssignedValues[key];
|
||||||
@ -930,7 +976,7 @@ export const useUpdateActionProps = () => {
|
|||||||
if (parsedValue) {
|
if (parsedValue) {
|
||||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||||
}
|
}
|
||||||
} else if (value != null && value !== '') {
|
} else if (value !== '') {
|
||||||
assignedValues[key] = value;
|
assignedValues[key] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -952,7 +998,7 @@ export const useUpdateActionProps = () => {
|
|||||||
actionField.data = field.data || {};
|
actionField.data = field.data || {};
|
||||||
actionField.data.loading = true;
|
actionField.data.loading = true;
|
||||||
try {
|
try {
|
||||||
await resource.update({
|
const result = await resource.update({
|
||||||
filterByTk,
|
filterByTk,
|
||||||
values: {
|
values: {
|
||||||
...values,
|
...values,
|
||||||
@ -971,6 +1017,15 @@ export const useUpdateActionProps = () => {
|
|||||||
if (callBack) {
|
if (callBack) {
|
||||||
callBack?.();
|
callBack?.();
|
||||||
}
|
}
|
||||||
|
let redirectTo = rawRedirectTo;
|
||||||
|
if (rawRedirectTo) {
|
||||||
|
const { exp, scope: expScope } = await replaceVariables(rawRedirectTo, {
|
||||||
|
variables,
|
||||||
|
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(result?.data?.data?.[0], {}) }],
|
||||||
|
});
|
||||||
|
redirectTo = interpolateVariables(exp, expScope);
|
||||||
|
}
|
||||||
|
|
||||||
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
||||||
setVisible?.(false);
|
setVisible?.(false);
|
||||||
}
|
}
|
||||||
|
@ -157,6 +157,8 @@ export const useCollectionFilterOptions = (collection: any, dataSource?: string)
|
|||||||
const option = {
|
const option = {
|
||||||
name: field.name,
|
name: field.name,
|
||||||
title: field?.uiSchema?.title || field.name,
|
title: field?.uiSchema?.title || field.name,
|
||||||
|
label: field?.uiSchema?.title || field.name,
|
||||||
|
value: field.name,
|
||||||
schema: field?.uiSchema,
|
schema: field?.uiSchema,
|
||||||
operators:
|
operators:
|
||||||
operators?.filter?.((operator) => {
|
operators?.filter?.((operator) => {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1094,5 +1094,6 @@
|
|||||||
"Font Size(px)": "字体大小(像素)",
|
"Font Size(px)": "字体大小(像素)",
|
||||||
"Font Weight": "字体粗细",
|
"Font Weight": "字体粗细",
|
||||||
"Font Style": "字体样式",
|
"Font Style": "字体样式",
|
||||||
"Italic": "斜体"
|
"Italic": "斜体",
|
||||||
|
"Response record":"响应结果记录"
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,10 @@ export const getAllowMultiple = (params?: { title: string }) => {
|
|||||||
return {
|
return {
|
||||||
name: 'allowMultiple',
|
name: 'allowMultiple',
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
|
useVisible() {
|
||||||
|
const isAssociationField = useIsAssociationField();
|
||||||
|
return isAssociationField;
|
||||||
|
},
|
||||||
useComponentProps() {
|
useComponentProps() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
|
@ -14,6 +14,14 @@ import React, { useCallback, useContext } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Router } from 'react-router-dom';
|
import { Router } from 'react-router-dom';
|
||||||
import { SchemaInitializerItem } from '../../application';
|
import { SchemaInitializerItem } from '../../application';
|
||||||
|
import {
|
||||||
|
CollectionManagerProvider,
|
||||||
|
useCollectionManager,
|
||||||
|
} from '../../data-source/collection/CollectionManagerProvider';
|
||||||
|
import {
|
||||||
|
DataSourceManagerProvider,
|
||||||
|
useDataSourceManager,
|
||||||
|
} from '../../data-source/data-source/DataSourceManagerProvider';
|
||||||
import { useGlobalTheme } from '../../global-theme';
|
import { useGlobalTheme } from '../../global-theme';
|
||||||
import { NocoBaseDesktopRouteType } from '../../route-switch/antd/admin-layout/convertRoutesToSchema';
|
import { NocoBaseDesktopRouteType } from '../../route-switch/antd/admin-layout/convertRoutesToSchema';
|
||||||
import {
|
import {
|
||||||
@ -34,6 +42,8 @@ export const LinkMenuItem = () => {
|
|||||||
const { urlSchema, paramsSchema } = useURLAndHTMLSchema();
|
const { urlSchema, paramsSchema } = useURLAndHTMLSchema();
|
||||||
const parentRoute = useParentRoute();
|
const parentRoute = useParentRoute();
|
||||||
const { createRoute } = useNocoBaseRoutes();
|
const { createRoute } = useNocoBaseRoutes();
|
||||||
|
const dm = useDataSourceManager();
|
||||||
|
const cm = useCollectionManager();
|
||||||
|
|
||||||
const handleClick = useCallback(async () => {
|
const handleClick = useCallback(async () => {
|
||||||
const values = await FormDialog(
|
const values = await FormDialog(
|
||||||
@ -41,31 +51,35 @@ export const LinkMenuItem = () => {
|
|||||||
() => {
|
() => {
|
||||||
const history = createMemoryHistory();
|
const history = createMemoryHistory();
|
||||||
return (
|
return (
|
||||||
<Router location={history.location} navigator={history}>
|
<DataSourceManagerProvider dataSourceManager={dm}>
|
||||||
<SchemaComponentOptions scope={options.scope} components={{ ...options.components }}>
|
<CollectionManagerProvider instance={cm} dataSource={cm?.dataSource?.key}>
|
||||||
<FormLayout layout={'vertical'}>
|
<Router location={history.location} navigator={history}>
|
||||||
<SchemaComponent
|
<SchemaComponentOptions scope={options.scope} components={{ ...options.components }}>
|
||||||
schema={{
|
<FormLayout layout={'vertical'}>
|
||||||
properties: {
|
<SchemaComponent
|
||||||
title: {
|
schema={{
|
||||||
title: t('Menu item title'),
|
properties: {
|
||||||
required: true,
|
title: {
|
||||||
'x-component': 'Input',
|
title: t('Menu item title'),
|
||||||
'x-decorator': 'FormItem',
|
required: true,
|
||||||
},
|
'x-component': 'Input',
|
||||||
icon: {
|
'x-decorator': 'FormItem',
|
||||||
title: t('Icon'),
|
},
|
||||||
'x-component': 'IconPicker',
|
icon: {
|
||||||
'x-decorator': 'FormItem',
|
title: t('Icon'),
|
||||||
},
|
'x-component': 'IconPicker',
|
||||||
href: urlSchema,
|
'x-decorator': 'FormItem',
|
||||||
params: paramsSchema,
|
},
|
||||||
},
|
href: urlSchema,
|
||||||
}}
|
params: paramsSchema,
|
||||||
/>
|
},
|
||||||
</FormLayout>
|
}}
|
||||||
</SchemaComponentOptions>
|
/>
|
||||||
</Router>
|
</FormLayout>
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
</Router>
|
||||||
|
</CollectionManagerProvider>
|
||||||
|
</DataSourceManagerProvider>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
theme,
|
theme,
|
||||||
|
@ -127,25 +127,27 @@ function BulkEnableButton({ plugins = [] }) {
|
|||||||
}}
|
}}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
title: t('Plugin'),
|
{
|
||||||
dataIndex: 'displayName',
|
title: t('Plugin'),
|
||||||
ellipsis: true,
|
dataIndex: 'displayName',
|
||||||
},
|
ellipsis: true,
|
||||||
{
|
},
|
||||||
title: t('Description'),
|
{
|
||||||
dataIndex: 'description',
|
title: t('Description'),
|
||||||
ellipsis: true,
|
dataIndex: 'description',
|
||||||
width: 300,
|
ellipsis: true,
|
||||||
},
|
width: 300,
|
||||||
{
|
},
|
||||||
title: t('Package name'),
|
{
|
||||||
dataIndex: 'packageName',
|
title: t('Package name'),
|
||||||
width: 300,
|
dataIndex: 'packageName',
|
||||||
ellipsis: true,
|
width: 300,
|
||||||
},
|
ellipsis: true,
|
||||||
] as TableProps['columns']}
|
},
|
||||||
|
] as TableProps['columns']
|
||||||
|
}
|
||||||
dataSource={items}
|
dataSource={items}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -88,7 +88,7 @@ export const SettingsCenterDropdown = () => {
|
|||||||
<Button
|
<Button
|
||||||
data-testid="plugin-settings-button"
|
data-testid="plugin-settings-button"
|
||||||
icon={<SettingOutlined style={{ color: token.colorTextHeaderMenu }} />}
|
icon={<SettingOutlined style={{ color: token.colorTextHeaderMenu }} />}
|
||||||
// title={t('All plugin settings')}
|
// title={t('All plugin settings')}
|
||||||
/>
|
/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
|
@ -52,6 +52,7 @@ import { KeepAlive } from './KeepAlive';
|
|||||||
import { NocoBaseDesktopRoute, NocoBaseDesktopRouteType } from './convertRoutesToSchema';
|
import { NocoBaseDesktopRoute, NocoBaseDesktopRouteType } from './convertRoutesToSchema';
|
||||||
import { MenuSchemaToolbar, ResetThemeTokenAndKeepAlgorithm } from './menuItemSettings';
|
import { MenuSchemaToolbar, ResetThemeTokenAndKeepAlgorithm } from './menuItemSettings';
|
||||||
import { userCenterSettings } from './userCenterSettings';
|
import { userCenterSettings } from './userCenterSettings';
|
||||||
|
import { createGlobalStyle, createStyles } from 'antd-style';
|
||||||
|
|
||||||
export { KeepAlive, NocoBaseDesktopRouteType };
|
export { KeepAlive, NocoBaseDesktopRouteType };
|
||||||
|
|
||||||
@ -268,7 +269,7 @@ const GroupItem: FC<{ item: any }> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const WithTooltip: FC<{ title: string; hidden: boolean }> = (props) => {
|
const WithTooltip: FC<{ title: string; hidden: boolean }> = (props) => {
|
||||||
const { inHeader } = useContext(headerContext);
|
const { inHeader } = useContext(HeaderContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RouteContext.Consumer>
|
<RouteContext.Consumer>
|
||||||
@ -406,7 +407,7 @@ const contentStyle = {
|
|||||||
paddingInline: 0,
|
paddingInline: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const headerContext = React.createContext<{ inHeader: boolean }>({ inHeader: false });
|
const HeaderContext = React.createContext<{ inHeader: boolean }>({ inHeader: false });
|
||||||
|
|
||||||
const popoverStyle = css`
|
const popoverStyle = css`
|
||||||
.ant-popover-inner {
|
.ant-popover-inner {
|
||||||
@ -495,9 +496,38 @@ const collapsedButtonRender = (collapsed, dom) => {
|
|||||||
return <CollapsedButton collapsed={collapsed}>{dom}</CollapsedButton>;
|
return <CollapsedButton collapsed={collapsed}>{dom}</CollapsedButton>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这个问题源自 antd 的一个 bug,等 antd 修复了这个问题后,可以删除这个样式。
|
||||||
|
* - issue: https://github.com/ant-design/pro-components/issues/8593
|
||||||
|
* - issue: https://github.com/ant-design/pro-components/issues/8522
|
||||||
|
* - issue: https://github.com/ant-design/pro-components/issues/8432
|
||||||
|
*/
|
||||||
|
const useHeaderStyle = createStyles(({ token }: any) => {
|
||||||
|
return {
|
||||||
|
headerPopup: {
|
||||||
|
'&.ant-menu-submenu-popup>.ant-menu': {
|
||||||
|
backgroundColor: `${token.colorBgHeader}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
headerMenuActive: {
|
||||||
|
'& .ant-menu-submenu-selected>.ant-menu-submenu-title': {
|
||||||
|
color: token.colorTextHeaderMenuActive,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
const headerContextValue = { inHeader: true };
|
const headerContextValue = { inHeader: true };
|
||||||
|
const HeaderWrapper: FC = (props) => {
|
||||||
|
const { styles } = useHeaderStyle();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={styles.headerMenuActive}>
|
||||||
|
<HeaderContext.Provider value={headerContextValue}>{props.children}</HeaderContext.Provider>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
const headerRender = (props: HeaderViewProps, defaultDom: React.ReactNode) => {
|
const headerRender = (props: HeaderViewProps, defaultDom: React.ReactNode) => {
|
||||||
return <headerContext.Provider value={headerContextValue}>{defaultDom}</headerContext.Provider>;
|
return <HeaderWrapper>{defaultDom}</HeaderWrapper>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const IsMobileLayoutContext = React.createContext<{
|
const IsMobileLayoutContext = React.createContext<{
|
||||||
@ -531,6 +561,7 @@ export const InternalAdminLayout = () => {
|
|||||||
const doNotChangeCollapsedRef = useRef(false);
|
const doNotChangeCollapsedRef = useRef(false);
|
||||||
const { t } = useMenuTranslation();
|
const { t } = useMenuTranslation();
|
||||||
const designable = isMobileLayout ? false : _designable;
|
const designable = isMobileLayout ? false : _designable;
|
||||||
|
const { styles } = useHeaderStyle();
|
||||||
|
|
||||||
const route = useMemo(() => {
|
const route = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
@ -544,7 +575,7 @@ export const InternalAdminLayout = () => {
|
|||||||
colorBgHeader: token.colorBgHeader,
|
colorBgHeader: token.colorBgHeader,
|
||||||
colorTextMenu: token.colorTextHeaderMenu,
|
colorTextMenu: token.colorTextHeaderMenu,
|
||||||
colorTextMenuSelected: token.colorTextHeaderMenuActive,
|
colorTextMenuSelected: token.colorTextHeaderMenuActive,
|
||||||
colorTextMenuActive: token.colorTextHeaderMenuActive,
|
colorTextMenuActive: token.colorTextHeaderMenuHover,
|
||||||
colorBgMenuItemHover: token.colorBgHeaderMenuHover,
|
colorBgMenuItemHover: token.colorBgHeaderMenuHover,
|
||||||
colorBgMenuItemSelected: token.colorBgHeaderMenuActive,
|
colorBgMenuItemSelected: token.colorBgHeaderMenuActive,
|
||||||
heightLayoutHeader: 46,
|
heightLayoutHeader: 46,
|
||||||
@ -591,6 +622,12 @@ export const InternalAdminLayout = () => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const menuProps = useMemo(() => {
|
||||||
|
return {
|
||||||
|
overflowedIndicatorPopupClassName: styles.headerPopup,
|
||||||
|
};
|
||||||
|
}, [styles.headerPopup]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DndContext onDragEnd={onDragEnd}>
|
<DndContext onDragEnd={onDragEnd}>
|
||||||
<ProLayout
|
<ProLayout
|
||||||
@ -612,6 +649,7 @@ export const InternalAdminLayout = () => {
|
|||||||
onCollapse={onCollapse}
|
onCollapse={onCollapse}
|
||||||
collapsed={collapsed}
|
collapsed={collapsed}
|
||||||
onPageChange={onPageChange}
|
onPageChange={onPageChange}
|
||||||
|
menuProps={menuProps}
|
||||||
>
|
>
|
||||||
<RouteContext.Consumer>
|
<RouteContext.Consumer>
|
||||||
{(value: RouteContextType) => {
|
{(value: RouteContextType) => {
|
||||||
|
@ -34,6 +34,8 @@ import {
|
|||||||
import { DefaultValueProvider } from '../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
import { DefaultValueProvider } from '../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
||||||
import { useLinkageAction } from './hooks';
|
import { useLinkageAction } from './hooks';
|
||||||
import { requestSettingsSchema } from './utils';
|
import { requestSettingsSchema } from './utils';
|
||||||
|
import { useAfterSuccessOptions } from './hooks/useGetAfterSuccessVariablesOptions';
|
||||||
|
import { useGlobalVariable } from '../../../application/hooks/useGlobalVariable';
|
||||||
|
|
||||||
const MenuGroup = (props) => {
|
const MenuGroup = (props) => {
|
||||||
return props.children;
|
return props.children;
|
||||||
@ -280,11 +282,24 @@ export function SkipValidation() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fieldNames = {
|
||||||
|
value: 'value',
|
||||||
|
label: 'label',
|
||||||
|
};
|
||||||
|
const useVariableProps = (environmentVariables) => {
|
||||||
|
const scope = useAfterSuccessOptions();
|
||||||
|
return {
|
||||||
|
scope: [environmentVariables, ...scope].filter(Boolean),
|
||||||
|
fieldNames,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export function AfterSuccess() {
|
export function AfterSuccess() {
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { onSuccess } = fieldSchema?.['x-action-settings'] || {};
|
const { onSuccess } = fieldSchema?.['x-action-settings'] || {};
|
||||||
|
const environmentVariables = useGlobalVariable('$env');
|
||||||
return (
|
return (
|
||||||
<SchemaSettingsModalItem
|
<SchemaSettingsModalItem
|
||||||
title={t('After successful submission')}
|
title={t('After successful submission')}
|
||||||
@ -363,8 +378,9 @@ export function AfterSuccess() {
|
|||||||
redirectTo: {
|
redirectTo: {
|
||||||
title: t('Link'),
|
title: t('Link'),
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Input',
|
'x-component': 'Variable.TextArea',
|
||||||
'x-component-props': {},
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
'x-use-component-props': () => useVariableProps(environmentVariables),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as ISchema
|
} as ISchema
|
||||||
|
@ -16,16 +16,19 @@ import Action from './Action';
|
|||||||
import { ComposedAction } from './types';
|
import { ComposedAction } from './types';
|
||||||
import { Icon } from '../../../icon';
|
import { Icon } from '../../../icon';
|
||||||
|
|
||||||
const WrapperComponent = ({ component: Component = 'a', icon, onlyIcon, children, ...restProps }: any) => {
|
const WrapperComponent = React.forwardRef(
|
||||||
return (
|
({ component: Component = 'a', icon, onlyIcon, children, ...restProps }: any, ref) => {
|
||||||
<Component {...restProps}>
|
return (
|
||||||
<Tooltip title={restProps.title}>
|
<Component ref={ref} {...restProps}>
|
||||||
<span style={{ marginRight: 3 }}>{icon && typeof icon === 'string' ? <Icon type={icon} /> : icon}</span>
|
<Tooltip title={restProps.title}>
|
||||||
</Tooltip>
|
<span style={{ marginRight: 3 }}>{icon && typeof icon === 'string' ? <Icon type={icon} /> : icon}</span>
|
||||||
{onlyIcon ? children[1] : children}
|
</Tooltip>
|
||||||
</Component>
|
{onlyIcon ? children[1] : children}
|
||||||
);
|
</Component>
|
||||||
};
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
WrapperComponent.displayName = 'WrapperComponentLink';
|
||||||
|
|
||||||
export const ActionLink: ComposedAction = withDynamicSchemaProps(
|
export const ActionLink: ComposedAction = withDynamicSchemaProps(
|
||||||
observer((props: any) => {
|
observer((props: any) => {
|
||||||
@ -34,6 +37,7 @@ export const ActionLink: ComposedAction = withDynamicSchemaProps(
|
|||||||
{...props}
|
{...props}
|
||||||
component={props.component || WrapperComponent}
|
component={props.component || WrapperComponent}
|
||||||
className={classnames('nb-action-link', props.className)}
|
className={classnames('nb-action-link', props.className)}
|
||||||
|
isLink
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
@ -247,7 +247,6 @@ const InternalAction: React.FC<InternalActionProps> = observer(function Com(prop
|
|||||||
const aclCtx = useACLActionParamsContext();
|
const aclCtx = useACLActionParamsContext();
|
||||||
const { run, element, disabled: disableAction } = useAction?.(actionCallback) || ({} as any);
|
const { run, element, disabled: disableAction } = useAction?.(actionCallback) || ({} as any);
|
||||||
const disabled = form.disabled || field.disabled || field.data?.disabled || propsDisabled || disableAction;
|
const disabled = form.disabled || field.disabled || field.data?.disabled || propsDisabled || disableAction;
|
||||||
|
|
||||||
const buttonStyle = useMemo(() => {
|
const buttonStyle = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
...style,
|
...style,
|
||||||
@ -538,6 +537,7 @@ const RenderButtonInner = observer(
|
|||||||
Designer: React.ElementType;
|
Designer: React.ElementType;
|
||||||
designerProps: any;
|
designerProps: any;
|
||||||
title: string;
|
title: string;
|
||||||
|
isLink?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
designable,
|
designable,
|
||||||
@ -558,6 +558,7 @@ const RenderButtonInner = observer(
|
|||||||
Designer,
|
Designer,
|
||||||
designerProps,
|
designerProps,
|
||||||
title,
|
title,
|
||||||
|
isLink,
|
||||||
...others
|
...others
|
||||||
} = props;
|
} = props;
|
||||||
const debouncedClick = useCallback(
|
const debouncedClick = useCallback(
|
||||||
@ -583,7 +584,7 @@ const RenderButtonInner = observer(
|
|||||||
|
|
||||||
const actionTitle = title || field?.title;
|
const actionTitle = title || field?.title;
|
||||||
const { opacity, ...restButtonStyle } = buttonStyle;
|
const { opacity, ...restButtonStyle } = buttonStyle;
|
||||||
|
const linkStyle = isLink && opacity ? { opacity } : undefined;
|
||||||
return (
|
return (
|
||||||
<SortableItem
|
<SortableItem
|
||||||
role="button"
|
role="button"
|
||||||
@ -592,9 +593,9 @@ const RenderButtonInner = observer(
|
|||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
loading={field?.data?.loading || loading}
|
loading={field?.data?.loading || loading}
|
||||||
icon={typeof icon === 'string' ? <Icon style={{ opacity }} type={icon} /> : icon}
|
icon={typeof icon === 'string' ? <Icon type={icon} style={linkStyle} /> : icon}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
style={restButtonStyle}
|
style={isLink ? restButtonStyle : buttonStyle}
|
||||||
onClick={process.env.__E2E__ ? handleButtonClick : debouncedClick} // E2E 中的点击操作都是很快的,如果加上 debounce 会导致 E2E 测试失败
|
onClick={process.env.__E2E__ ? handleButtonClick : debouncedClick} // E2E 中的点击操作都是很快的,如果加上 debounce 会导致 E2E 测试失败
|
||||||
component={tarComponent || Button}
|
component={tarComponent || Button}
|
||||||
className={classnames(componentCls, hashId, className, 'nb-action')}
|
className={classnames(componentCls, hashId, className, 'nb-action')}
|
||||||
@ -602,7 +603,7 @@ const RenderButtonInner = observer(
|
|||||||
title={actionTitle}
|
title={actionTitle}
|
||||||
>
|
>
|
||||||
{actionTitle && (
|
{actionTitle && (
|
||||||
<span className={icon ? 'nb-action-title' : null} style={{ opacity }}>
|
<span className={icon ? 'nb-action-title' : null} style={linkStyle}>
|
||||||
{actionTitle}
|
{actionTitle}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* 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 { useMemo } from 'react';
|
||||||
|
import { useCollection_deprecated, useCollectionFilterOptions } from '../../../../collection-manager';
|
||||||
|
import { useCollectionRecordData } from '../../../../data-source';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useCompile } from '../../../';
|
||||||
|
import { useBlockContext } from '../../../../block-provider/BlockProvider';
|
||||||
|
import { usePopupVariable } from '../../../../schema-settings/VariableInput/hooks';
|
||||||
|
import { useCurrentRoleVariable } from '../../../../schema-settings/VariableInput/hooks';
|
||||||
|
|
||||||
|
export const useAfterSuccessOptions = () => {
|
||||||
|
const collection = useCollection_deprecated();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const fieldsOptions = useCollectionFilterOptions(collection);
|
||||||
|
const userFieldOptions = useCollectionFilterOptions('users', 'main');
|
||||||
|
const compile = useCompile();
|
||||||
|
const recordData = useCollectionRecordData();
|
||||||
|
const { name: blockType } = useBlockContext() || {};
|
||||||
|
const [fields, userFields] = useMemo(() => {
|
||||||
|
return [compile(fieldsOptions), compile(userFieldOptions)];
|
||||||
|
}, [fieldsOptions, userFieldOptions]);
|
||||||
|
const { settings: popupRecordSettings, shouldDisplayPopupRecord } = usePopupVariable();
|
||||||
|
const { currentRoleSettings } = useCurrentRoleVariable();
|
||||||
|
const record = useCollectionRecordData();
|
||||||
|
return useMemo(() => {
|
||||||
|
return [
|
||||||
|
(record || blockType === 'form') && {
|
||||||
|
value: '$record',
|
||||||
|
label: t('Response record', { ns: 'client' }),
|
||||||
|
children: [...fields],
|
||||||
|
},
|
||||||
|
recordData && {
|
||||||
|
value: 'currentRecord',
|
||||||
|
label: t('Current record', { ns: 'client' }),
|
||||||
|
children: [...fields],
|
||||||
|
},
|
||||||
|
shouldDisplayPopupRecord && {
|
||||||
|
...popupRecordSettings,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'currentUser',
|
||||||
|
label: t('Current user', { ns: 'client' }),
|
||||||
|
children: userFields,
|
||||||
|
},
|
||||||
|
currentRoleSettings,
|
||||||
|
{
|
||||||
|
value: 'currentTime',
|
||||||
|
label: t('Current time', { ns: 'client' }),
|
||||||
|
children: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: '$nToken',
|
||||||
|
label: 'API token',
|
||||||
|
children: null,
|
||||||
|
},
|
||||||
|
].filter(Boolean);
|
||||||
|
}, [recordData, t, fields, blockType, userFields]);
|
||||||
|
};
|
@ -16,5 +16,6 @@ export * from './hooks/useGetAriaLabelOfAction';
|
|||||||
export * from './hooks/useGetAriaLabelOfDrawer';
|
export * from './hooks/useGetAriaLabelOfDrawer';
|
||||||
export * from './hooks/useGetAriaLabelOfModal';
|
export * from './hooks/useGetAriaLabelOfModal';
|
||||||
export * from './hooks/useGetAriaLabelOfPopover';
|
export * from './hooks/useGetAriaLabelOfPopover';
|
||||||
|
export * from './hooks/useGetAfterSuccessVariablesOptions';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
export * from './zIndexContext';
|
export * from './zIndexContext';
|
||||||
|
@ -14,22 +14,22 @@ import { uid } from '@formily/shared';
|
|||||||
import { Space, message } from 'antd';
|
import { Space, message } from 'antd';
|
||||||
import { isEqual } from 'lodash';
|
import { isEqual } from 'lodash';
|
||||||
import { isFunction } from 'mathjs';
|
import { isFunction } from 'mathjs';
|
||||||
import React, { useEffect, useState, useContext } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
ClearCollectionFieldContext,
|
ClearCollectionFieldContext,
|
||||||
NocoBaseRecursionField,
|
NocoBaseRecursionField,
|
||||||
RecordProvider,
|
RecordProvider,
|
||||||
|
SchemaComponentContext,
|
||||||
useAPIClient,
|
useAPIClient,
|
||||||
useCollectionRecordData,
|
useCollectionRecordData,
|
||||||
SchemaComponentContext,
|
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { Action } from '../action';
|
import { VariablePopupRecordProvider } from '../../../modules/variable/variablesProvider/VariablePopupRecordProvider';
|
||||||
import { isVariable } from '../../../variables/utils/isVariable';
|
import { isVariable } from '../../../variables/utils/isVariable';
|
||||||
import { getInnermostKeyAndValue } from '../../common/utils/uitls';
|
import { getInnermostKeyAndValue } from '../../common/utils/uitls';
|
||||||
|
import { Action } from '../action';
|
||||||
import { RemoteSelect, RemoteSelectProps } from '../remote-select';
|
import { RemoteSelect, RemoteSelectProps } from '../remote-select';
|
||||||
import useServiceOptions, { useAssociationFieldContext } from './hooks';
|
import useServiceOptions, { useAssociationFieldContext } from './hooks';
|
||||||
import { VariablePopupRecordProvider } from '../../../modules/variable/variablesProvider/VariablePopupRecordProvider';
|
|
||||||
|
|
||||||
export const AssociationFieldAddNewer = (props) => {
|
export const AssociationFieldAddNewer = (props) => {
|
||||||
const schemaComponentCtxValue = useContext(SchemaComponentContext);
|
const schemaComponentCtxValue = useContext(SchemaComponentContext);
|
||||||
|
@ -158,7 +158,10 @@ export const InternalPicker = observer(
|
|||||||
}),
|
}),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
const newSchema = useMemo(() => isMobileLayout ? transformMultiColumnToSingleColumn(fieldSchema) : fieldSchema, [isMobileLayout, fieldSchema]);
|
const newSchema = useMemo(
|
||||||
|
() => (isMobileLayout ? transformMultiColumnToSingleColumn(fieldSchema) : fieldSchema),
|
||||||
|
[isMobileLayout, fieldSchema],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PopupSettingsProvider enableURL={false}>
|
<PopupSettingsProvider enableURL={false}>
|
||||||
|
@ -144,8 +144,14 @@ const ToManyNester = observer(
|
|||||||
const update = useUpdate();
|
const update = useUpdate();
|
||||||
const { isMobileLayout } = useMobileLayout();
|
const { isMobileLayout } = useMobileLayout();
|
||||||
|
|
||||||
const newSchema = useMemo(() => isMobileLayout ? transformMultiColumnToSingleColumn(fieldSchema) : fieldSchema, [isMobileLayout, fieldSchema]);
|
const newSchema = useMemo(
|
||||||
const newParentSchema = useMemo(() => isMobileLayout ? transformMultiColumnToSingleColumn(fieldSchema.parent) : fieldSchema.parent, [isMobileLayout, fieldSchema.parent]);
|
() => (isMobileLayout ? transformMultiColumnToSingleColumn(fieldSchema) : fieldSchema),
|
||||||
|
[isMobileLayout, fieldSchema],
|
||||||
|
);
|
||||||
|
const newParentSchema = useMemo(
|
||||||
|
() => (isMobileLayout ? transformMultiColumnToSingleColumn(fieldSchema.parent) : fieldSchema.parent),
|
||||||
|
[isMobileLayout, fieldSchema.parent],
|
||||||
|
);
|
||||||
|
|
||||||
const refreshComponent = useRefreshComponent();
|
const refreshComponent = useRefreshComponent();
|
||||||
const refresh = useCallback(() => {
|
const refresh = useCallback(() => {
|
||||||
|
@ -60,6 +60,7 @@ export function useAssociationFieldContext<F extends GeneralField>() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用于获取关系字段请求数据时所需的一些参数
|
||||||
export default function useServiceOptions(props) {
|
export default function useServiceOptions(props) {
|
||||||
const { action = 'list', service, useOriginalFilter } = props;
|
const { action = 'list', service, useOriginalFilter } = props;
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
@ -86,24 +87,24 @@ export default function useServiceOptions(props) {
|
|||||||
mergeFilter([
|
mergeFilter([
|
||||||
isOToAny && !isInFilterFormBlock(fieldSchema) && collectionField?.foreignKey && !useOriginalFilter
|
isOToAny && !isInFilterFormBlock(fieldSchema) && collectionField?.foreignKey && !useOriginalFilter
|
||||||
? {
|
? {
|
||||||
[collectionField.foreignKey]: {
|
[collectionField.foreignKey]: {
|
||||||
$is: null,
|
$is: null,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
parsedFilterParams,
|
parsedFilterParams,
|
||||||
]),
|
]),
|
||||||
isOToAny &&
|
isOToAny &&
|
||||||
sourceValue !== undefined &&
|
sourceValue !== undefined &&
|
||||||
sourceValue !== null &&
|
sourceValue !== null &&
|
||||||
!isInFilterFormBlock(fieldSchema) &&
|
!isInFilterFormBlock(fieldSchema) &&
|
||||||
collectionField?.foreignKey &&
|
collectionField?.foreignKey &&
|
||||||
!useOriginalFilter
|
!useOriginalFilter
|
||||||
? {
|
? {
|
||||||
[collectionField.foreignKey]: {
|
[collectionField.foreignKey]: {
|
||||||
$eq: sourceValue,
|
$eq: sourceValue,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
// params?.filter && value?.length
|
// params?.filter && value?.length
|
||||||
// ? {
|
// ? {
|
||||||
|
@ -50,7 +50,7 @@ describe('CollectionSelect', () => {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-label="block-item-demo title"
|
aria-label="block-item-demo title"
|
||||||
class="nb-block-item nb-form-item css-9qorhu ant-nb-block-item css-dev-only-do-not-override-11aiz3o"
|
class="nb-block-item nb-form-item css-9qorhu ant-nb-block-item css-dev-only-do-not-override-1rquknz"
|
||||||
role="button"
|
role="button"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -191,7 +191,7 @@ describe('CollectionSelect', () => {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-label="block-item-demo title"
|
aria-label="block-item-demo title"
|
||||||
class="nb-block-item nb-form-item css-9qorhu ant-nb-block-item css-dev-only-do-not-override-11aiz3o"
|
class="nb-block-item nb-form-item css-9qorhu ant-nb-block-item css-dev-only-do-not-override-1rquknz"
|
||||||
role="button"
|
role="button"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -92,7 +92,7 @@ export const useGetFilterFieldOptions = () => {
|
|||||||
|
|
||||||
const getOptions = (fields, depth, usedInVariable?: boolean) => {
|
const getOptions = (fields, depth, usedInVariable?: boolean) => {
|
||||||
const options = [];
|
const options = [];
|
||||||
fields.forEach((field) => {
|
fields?.forEach((field) => {
|
||||||
const option = field2option(field, depth, usedInVariable);
|
const option = field2option(field, depth, usedInVariable);
|
||||||
if (option) {
|
if (option) {
|
||||||
options.push(option);
|
options.push(option);
|
||||||
|
@ -52,7 +52,10 @@ const FormComponent: React.FC<FormProps> = (props) => {
|
|||||||
labelWrap = true,
|
labelWrap = true,
|
||||||
} = cardItemSchema?.['x-component-props'] || {};
|
} = cardItemSchema?.['x-component-props'] || {};
|
||||||
const { isMobileLayout } = useMobileLayout();
|
const { isMobileLayout } = useMobileLayout();
|
||||||
const newSchema = useMemo(() => isMobileLayout ? transformMultiColumnToSingleColumn(fieldSchema) : fieldSchema, [fieldSchema, isMobileLayout]);
|
const newSchema = useMemo(
|
||||||
|
() => (isMobileLayout ? transformMultiColumnToSingleColumn(fieldSchema) : fieldSchema),
|
||||||
|
[fieldSchema, isMobileLayout],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FieldContext.Provider value={undefined}>
|
<FieldContext.Provider value={undefined}>
|
||||||
@ -81,12 +84,7 @@ const FormComponent: React.FC<FormProps> = (props) => {
|
|||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
<NocoBaseRecursionField
|
<NocoBaseRecursionField basePath={f.address} schema={newSchema} onlyRenderProperties isUseFormilyField />
|
||||||
basePath={f.address}
|
|
||||||
schema={newSchema}
|
|
||||||
onlyRenderProperties
|
|
||||||
isUseFormilyField
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</FormLayout>
|
</FormLayout>
|
||||||
</FormContext.Provider>
|
</FormContext.Provider>
|
||||||
@ -104,19 +102,17 @@ const FormDecorator: React.FC<FormProps> = (props) => {
|
|||||||
const f = useAttach(form.createVoidField({ ...field.props, basePath: '' }));
|
const f = useAttach(form.createVoidField({ ...field.props, basePath: '' }));
|
||||||
const Component = useComponent(fieldSchema['x-component'], Def);
|
const Component = useComponent(fieldSchema['x-component'], Def);
|
||||||
const { isMobileLayout } = useMobileLayout();
|
const { isMobileLayout } = useMobileLayout();
|
||||||
const newSchema = useMemo(() => isMobileLayout ? transformMultiColumnToSingleColumn(fieldSchema) : fieldSchema, [fieldSchema, isMobileLayout]);
|
const newSchema = useMemo(
|
||||||
|
() => (isMobileLayout ? transformMultiColumnToSingleColumn(fieldSchema) : fieldSchema),
|
||||||
|
[fieldSchema, isMobileLayout],
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<FieldContext.Provider value={undefined}>
|
<FieldContext.Provider value={undefined}>
|
||||||
<FormContext.Provider value={form}>
|
<FormContext.Provider value={form}>
|
||||||
<FormLayout layout={'vertical'} {...others}>
|
<FormLayout layout={'vertical'} {...others}>
|
||||||
<FieldContext.Provider value={f}>
|
<FieldContext.Provider value={f}>
|
||||||
<Component {...field.componentProps}>
|
<Component {...field.componentProps}>
|
||||||
<NocoBaseRecursionField
|
<NocoBaseRecursionField basePath={f.address} schema={newSchema} onlyRenderProperties isUseFormilyField />
|
||||||
basePath={f.address}
|
|
||||||
schema={newSchema}
|
|
||||||
onlyRenderProperties
|
|
||||||
isUseFormilyField
|
|
||||||
/>
|
|
||||||
</Component>
|
</Component>
|
||||||
</FieldContext.Provider>
|
</FieldContext.Provider>
|
||||||
{/* <FieldContext.Provider value={f}>{children}</FieldContext.Provider> */}
|
{/* <FieldContext.Provider value={f}>{children}</FieldContext.Provider> */}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
# Page
|
|
||||||
|
|
||||||
Can be used in conjunction with DocumentTitleProvider to display the page title on document.title.
|
|
||||||
|
|
||||||
<code src="./demos/demo1.tsx"></code>
|
|
@ -1,5 +0,0 @@
|
|||||||
# Page
|
|
||||||
|
|
||||||
可以与 DocumentTitleProvider 搭配使用,将 page title 显示在 document.title 上。
|
|
||||||
|
|
||||||
<code src="./demos/demo1.tsx"></code>
|
|
@ -343,14 +343,14 @@ export const TableBlockDesigner = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<SchemaSettingsConnectDataBlocks type={FilterBlockType.TABLE} emptyDescription={t('No blocks to connect')} />
|
<SchemaSettingsConnectDataBlocks type={FilterBlockType.TABLE} emptyDescription={t('No blocks to connect')} />
|
||||||
{supportTemplate && <SchemaSettingsDivider />}
|
{/* {supportTemplate && <SchemaSettingsDivider />}
|
||||||
{supportTemplate && (
|
{supportTemplate && (
|
||||||
<SchemaSettingsTemplate
|
<SchemaSettingsTemplate
|
||||||
componentName={`${componentNamePrefix}Table`}
|
componentName={`${componentNamePrefix}Table`}
|
||||||
collectionName={name}
|
collectionName={name}
|
||||||
resourceName={defaultResource}
|
resourceName={defaultResource}
|
||||||
/>
|
/>
|
||||||
)}
|
)} */}
|
||||||
<SchemaSettingsDivider />
|
<SchemaSettingsDivider />
|
||||||
<SchemaSettingsRemove
|
<SchemaSettingsRemove
|
||||||
removeParentsIfNoChildren
|
removeParentsIfNoChildren
|
||||||
|
@ -233,10 +233,10 @@ describe('Table.settings', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
title: 'Save as template',
|
// title: 'Save as template',
|
||||||
type: 'modal',
|
// type: 'modal',
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
title: 'Delete',
|
title: 'Delete',
|
||||||
type: 'delete',
|
type: 'delete',
|
||||||
@ -299,7 +299,12 @@ describe('Table.settings', () => {
|
|||||||
|
|
||||||
test('menu list', async () => {
|
test('menu list', async () => {
|
||||||
await renderSettings(getRenderSettingsOptions());
|
await renderSettings(getRenderSettingsOptions());
|
||||||
await checkTableSettings();
|
await checkTableSettings([
|
||||||
|
{
|
||||||
|
title: 'Save as template',
|
||||||
|
type: 'modal',
|
||||||
|
},
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('old schema', async () => {
|
test('old schema', async () => {
|
||||||
|
@ -45,9 +45,9 @@ export const Sortable = (props: any) => {
|
|||||||
const { draggable, droppable } = useContext(SortableContext);
|
const { draggable, droppable } = useContext(SortableContext);
|
||||||
const { isOver, setNodeRef } = droppable;
|
const { isOver, setNodeRef } = droppable;
|
||||||
const droppableStyle = { ...style };
|
const droppableStyle = { ...style };
|
||||||
|
const isLinkComponent = component === 'a' || component?.displayName === 'WrapperComponentLink';
|
||||||
if (isOver && draggable?.active?.id !== droppable?.over?.id) {
|
if (isOver && draggable?.active?.id !== droppable?.over?.id) {
|
||||||
droppableStyle[component === 'a' ? 'color' : 'background'] = getComputedColor(token.colorSettings);
|
droppableStyle[isLinkComponent ? 'color' : 'background'] = getComputedColor(token.colorSettings);
|
||||||
Object.assign(droppableStyle, overStyle);
|
Object.assign(droppableStyle, overStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +118,6 @@ export const SortableItem: React.FC<SortableItemProps> = React.memo((props) => {
|
|||||||
if (designable) {
|
if (designable) {
|
||||||
return <InternalSortableItem {...props} />;
|
return <InternalSortableItem {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return React.createElement(
|
return React.createElement(
|
||||||
component || 'div',
|
component || 'div',
|
||||||
_.omit(others, ['children', 'schema', 'overStyle', 'openMode', 'id', 'eid', 'removeParentsIfNoChildren']),
|
_.omit(others, ['children', 'schema', 'overStyle', 'openMode', 'id', 'eid', 'removeParentsIfNoChildren']),
|
||||||
|
@ -267,6 +267,13 @@ function FinallyButton({
|
|||||||
}) {
|
}) {
|
||||||
const { getCollection } = useCollectionManager_deprecated();
|
const { getCollection } = useCollectionManager_deprecated();
|
||||||
const aclCtx = useACLActionParamsContext();
|
const aclCtx = useACLActionParamsContext();
|
||||||
|
const buttonStyle = useMemo(() => {
|
||||||
|
const shouldApplyOpacity = designable && (field?.data?.hidden || !aclCtx);
|
||||||
|
const opacityValue = componentType !== 'link' ? (shouldApplyOpacity ? 0.1 : 1) : 1;
|
||||||
|
return {
|
||||||
|
opacity: opacityValue,
|
||||||
|
};
|
||||||
|
}, [designable, field?.data?.hidden, aclCtx, componentType]);
|
||||||
|
|
||||||
if (inheritsCollections?.length > 0) {
|
if (inheritsCollections?.length > 0) {
|
||||||
if (!linkageFromForm) {
|
if (!linkageFromForm) {
|
||||||
@ -276,6 +283,7 @@ function FinallyButton({
|
|||||||
danger={props.danger}
|
danger={props.danger}
|
||||||
type={componentType}
|
type={componentType}
|
||||||
icon={<DownOutlined />}
|
icon={<DownOutlined />}
|
||||||
|
style={{ ...props?.style, ...buttonStyle }}
|
||||||
buttonsRender={([leftButton, rightButton]) => [
|
buttonsRender={([leftButton, rightButton]) => [
|
||||||
React.cloneElement(leftButton as React.ReactElement<any, string>, {
|
React.cloneElement(leftButton as React.ReactElement<any, string>, {
|
||||||
style: props?.style,
|
style: props?.style,
|
||||||
@ -296,7 +304,13 @@ function FinallyButton({
|
|||||||
) : (
|
) : (
|
||||||
<Dropdown menu={menu}>
|
<Dropdown menu={menu}>
|
||||||
{
|
{
|
||||||
<Button aria-label={props['aria-label']} icon={icon} type={componentType} danger={props.danger}>
|
<Button
|
||||||
|
aria-label={props['aria-label']}
|
||||||
|
icon={icon}
|
||||||
|
type={componentType}
|
||||||
|
danger={props.danger}
|
||||||
|
style={{ ...props?.style, ...buttonStyle }}
|
||||||
|
>
|
||||||
{props.children} <DownOutlined />
|
{props.children} <DownOutlined />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
@ -321,6 +335,7 @@ function FinallyButton({
|
|||||||
style={{
|
style={{
|
||||||
display: !designable && field?.data?.hidden && 'none',
|
display: !designable && field?.data?.hidden && 'none',
|
||||||
opacity: designable && field?.data?.hidden && 0.1,
|
opacity: designable && field?.data?.hidden && 0.1,
|
||||||
|
...buttonStyle,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
@ -342,7 +357,7 @@ function FinallyButton({
|
|||||||
...props?.style,
|
...props?.style,
|
||||||
display: !designable && field?.data?.hidden && 'none',
|
display: !designable && field?.data?.hidden && 'none',
|
||||||
opacity: designable && field?.data?.hidden && 0.1,
|
opacity: designable && field?.data?.hidden && 0.1,
|
||||||
height: '100%',
|
...buttonStyle,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.onlyIcon ? props?.children?.[1] : props?.children}
|
{props.onlyIcon ? props?.children?.[1] : props?.children}
|
||||||
|
@ -57,16 +57,6 @@ export const useLinkageCollectionFieldOptions = (collectionName: string, readPre
|
|||||||
if (nested || children || ['formula', 'richText', 'sequence'].includes(fieldInterface.name)) {
|
if (nested || children || ['formula', 'richText', 'sequence'].includes(fieldInterface.name)) {
|
||||||
return operator?.value !== ActionType.Value && operator?.value !== ActionType.Options;
|
return operator?.value !== ActionType.Value && operator?.value !== ActionType.Options;
|
||||||
}
|
}
|
||||||
if (!['select', 'radioGroup', 'multipleSelect', 'checkboxGroup'].includes(fieldInterface.name)) {
|
|
||||||
return operator?.value !== ActionType.Options;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
!['date', 'datetime', 'dateOnly', 'datetimeNoTz', 'unixTimestamp', 'createdAt', 'updatedAt'].includes(
|
|
||||||
fieldInterface.name,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return operator?.value !== ActionType.DateScope;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}) || [],
|
}) || [],
|
||||||
};
|
};
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
import { useField } from '@formily/react';
|
import { useField } from '@formily/react';
|
||||||
import { useEffect, useContext } from 'react';
|
import { useEffect, useContext } from 'react';
|
||||||
import { LinkageLogicContext } from './context';
|
import { LinkageLogicContext } from './context';
|
||||||
|
import { ActionType } from './type';
|
||||||
|
|
||||||
const findOption = (dataIndex = [], options) => {
|
const findOption = (dataIndex = [], options) => {
|
||||||
let items = options;
|
let items = options;
|
||||||
@ -45,9 +46,34 @@ export const useValues = (options) => {
|
|||||||
field.data = field.data || {};
|
field.data = field.data || {};
|
||||||
const operators = option?.operators;
|
const operators = option?.operators;
|
||||||
field.data.operators = operators?.filter((v) => {
|
field.data.operators = operators?.filter((v) => {
|
||||||
if (dataIndex.length > 1) {
|
const isOptionField = ['select', 'radioGroup', 'multipleSelect', 'checkboxGroup'].includes(
|
||||||
return !['value', 'dateScope', 'options'].includes(v.value);
|
option?.interface || '',
|
||||||
|
);
|
||||||
|
const isDateField = [
|
||||||
|
'date',
|
||||||
|
'datetime',
|
||||||
|
'dateOnly',
|
||||||
|
'datetimeNoTz',
|
||||||
|
'unixTimestamp',
|
||||||
|
'createdAt',
|
||||||
|
'updatedAt',
|
||||||
|
].includes(option?.interface || '');
|
||||||
|
|
||||||
|
// 如果 多个字段,则排除 Value、DateScope、Options
|
||||||
|
if (dataIndex.length > 1 && [ActionType.Value, ActionType.DateScope, ActionType.Options].includes(v.value)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 非选项字段,去掉 Options
|
||||||
|
if (!isOptionField && v.value === ActionType.Options) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非时间字段,去掉 DateScope
|
||||||
|
if (!isDateField && v.value === ActionType.DateScope) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
field.data.schema = option?.schema;
|
field.data.schema = option?.schema;
|
||||||
|
@ -18,7 +18,6 @@ import { getDataSourceHeaders } from '../data-source/utils';
|
|||||||
import { useCompile } from '../schema-component';
|
import { useCompile } from '../schema-component';
|
||||||
import useBuiltInVariables from './hooks/useBuiltinVariables';
|
import useBuiltInVariables from './hooks/useBuiltinVariables';
|
||||||
import { VariableOption, VariablesContextType } from './types';
|
import { VariableOption, VariablesContextType } from './types';
|
||||||
import { cacheLazyLoadedValues, getCachedLazyLoadedValues } from './utils/cacheLazyLoadedValues';
|
|
||||||
import { filterEmptyValues } from './utils/filterEmptyValues';
|
import { filterEmptyValues } from './utils/filterEmptyValues';
|
||||||
import { getAction } from './utils/getAction';
|
import { getAction } from './utils/getAction';
|
||||||
import { getPath } from './utils/getPath';
|
import { getPath } from './utils/getPath';
|
||||||
@ -144,14 +143,13 @@ const VariablesProvider = ({ children, filterVariables }: any) => {
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
clearRequested(url);
|
clearRequested(url);
|
||||||
const value = data.data.data;
|
const value = data.data.data;
|
||||||
cacheLazyLoadedValues(item, currentVariablePath, value);
|
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
stashRequested(url, result);
|
stashRequested(url, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getCachedLazyLoadedValues(item, currentVariablePath) || item?.[key];
|
return item?.[key];
|
||||||
});
|
});
|
||||||
current = removeThroughCollectionFields(_.flatten(await Promise.all(result)), associationField);
|
current = removeThroughCollectionFields(_.flatten(await Promise.all(result)), associationField);
|
||||||
} else if (
|
} else if (
|
||||||
@ -180,17 +178,9 @@ const VariablesProvider = ({ children, filterVariables }: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const value = data.data.data;
|
const value = data.data.data;
|
||||||
if (!getCachedLazyLoadedValues(current, currentVariablePath)) {
|
|
||||||
// Cache the API response data to avoid repeated requests
|
|
||||||
cacheLazyLoadedValues(current, currentVariablePath, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
current = removeThroughCollectionFields(value, associationField);
|
current = removeThroughCollectionFields(value, associationField);
|
||||||
} else {
|
} else {
|
||||||
current = removeThroughCollectionFields(
|
current = removeThroughCollectionFields(getValuesByPath(current, key), associationField);
|
||||||
getCachedLazyLoadedValues(current, currentVariablePath) || getValuesByPath(current, key),
|
|
||||||
associationField,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (associationField?.target) {
|
if (associationField?.target) {
|
||||||
@ -359,13 +349,8 @@ export default VariablesProvider;
|
|||||||
function shouldToRequest(value, variableCtx: Record<string, any>, variablePath: string) {
|
function shouldToRequest(value, variableCtx: Record<string, any>, variablePath: string) {
|
||||||
let result = false;
|
let result = false;
|
||||||
|
|
||||||
if (getCachedLazyLoadedValues(variableCtx, variablePath)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// value may be a reactive object, using untracked to avoid unexpected autorun
|
// value may be a reactive object, using untracked to avoid unexpected autorun
|
||||||
untracked(() => {
|
untracked(() => {
|
||||||
// fix https://nocobase.height.app/T-2502
|
|
||||||
// Compatible with `xxx to many` and `xxx to one` subform fields and subtable fields
|
// Compatible with `xxx to many` and `xxx to one` subform fields and subtable fields
|
||||||
if (JSON.stringify(value) === '[{}]' || JSON.stringify(value) === '{}') {
|
if (JSON.stringify(value) === '[{}]' || JSON.stringify(value) === '{}') {
|
||||||
result = true;
|
result = true;
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const cache = new Map<Record<string, any>, any>();
|
|
||||||
|
|
||||||
export const cacheLazyLoadedValues = (variableCtx: Record<string, any>, variablePath: string, value: any) => {
|
|
||||||
const cachedValue = cache.get(variableCtx);
|
|
||||||
|
|
||||||
if (cachedValue) {
|
|
||||||
cachedValue[variablePath] = value;
|
|
||||||
} else {
|
|
||||||
cache.set(variableCtx, { [variablePath]: value });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getCachedLazyLoadedValues = (variableCtx: Record<string, any>, variablePath: string) => {
|
|
||||||
const cachedValue = cache.get(variableCtx);
|
|
||||||
return cachedValue?.[variablePath];
|
|
||||||
};
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "create-nocobase-app",
|
"name": "create-nocobase-app",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/data-source-manager",
|
"name": "@nocobase/data-source-manager",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/actions": "1.7.0-alpha.4",
|
"@nocobase/actions": "1.7.0-beta.9",
|
||||||
"@nocobase/cache": "1.7.0-alpha.4",
|
"@nocobase/cache": "1.7.0-beta.9",
|
||||||
"@nocobase/database": "1.7.0-alpha.4",
|
"@nocobase/database": "1.7.0-beta.9",
|
||||||
"@nocobase/resourcer": "1.7.0-alpha.4",
|
"@nocobase/resourcer": "1.7.0-beta.9",
|
||||||
"@nocobase/utils": "1.7.0-alpha.4",
|
"@nocobase/utils": "1.7.0-beta.9",
|
||||||
"@types/jsonwebtoken": "^8.5.8",
|
"@types/jsonwebtoken": "^8.5.8",
|
||||||
"jsonwebtoken": "^8.5.1"
|
"jsonwebtoken": "^8.5.1"
|
||||||
},
|
},
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/database",
|
"name": "@nocobase/database",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/logger": "1.7.0-alpha.4",
|
"@nocobase/logger": "1.7.0-beta.9",
|
||||||
"@nocobase/utils": "1.7.0-alpha.4",
|
"@nocobase/utils": "1.7.0-beta.9",
|
||||||
"async-mutex": "^0.3.2",
|
"async-mutex": "^0.3.2",
|
||||||
"chalk": "^4.1.1",
|
"chalk": "^4.1.1",
|
||||||
"cron-parser": "4.4.0",
|
"cron-parser": "4.4.0",
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/devtools",
|
"name": "@nocobase/devtools",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./src/index.js",
|
"main": "./src/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/build": "1.7.0-alpha.4",
|
"@nocobase/build": "1.7.0-beta.9",
|
||||||
"@nocobase/client": "1.7.0-alpha.4",
|
"@nocobase/client": "1.7.0-beta.9",
|
||||||
"@nocobase/test": "1.7.0-alpha.4",
|
"@nocobase/test": "1.7.0-beta.9",
|
||||||
"@types/koa": "^2.15.0",
|
"@types/koa": "^2.15.0",
|
||||||
"@types/koa-bodyparser": "^4.3.4",
|
"@types/koa-bodyparser": "^4.3.4",
|
||||||
"@types/lodash": "^4.14.177",
|
"@types/lodash": "^4.14.177",
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/evaluators",
|
"name": "@nocobase/evaluators",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formulajs/formulajs": "4.4.9",
|
"@formulajs/formulajs": "4.4.9",
|
||||||
"@nocobase/utils": "1.7.0-alpha.4",
|
"@nocobase/utils": "1.7.0-beta.9",
|
||||||
"mathjs": "^10.6.0"
|
"mathjs": "^10.6.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/lock-manager",
|
"name": "@nocobase/lock-manager",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nocobase/utils": "1.7.0-alpha.4",
|
"@nocobase/utils": "1.7.0-beta.9",
|
||||||
"async-mutex": "^0.5.0"
|
"async-mutex": "^0.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/logger",
|
"name": "@nocobase/logger",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "nocobase logging library",
|
"description": "nocobase logging library",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/resourcer",
|
"name": "@nocobase/resourcer",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/utils": "1.7.0-alpha.4",
|
"@nocobase/utils": "1.7.0-beta.9",
|
||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
"koa-compose": "^4.1.0",
|
"koa-compose": "^4.1.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/sdk",
|
"name": "@nocobase/sdk",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/server",
|
"name": "@nocobase/server",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
@ -10,19 +10,19 @@
|
|||||||
"@koa/cors": "^5.0.0",
|
"@koa/cors": "^5.0.0",
|
||||||
"@koa/multer": "^3.0.2",
|
"@koa/multer": "^3.0.2",
|
||||||
"@koa/router": "^9.4.0",
|
"@koa/router": "^9.4.0",
|
||||||
"@nocobase/acl": "1.7.0-alpha.4",
|
"@nocobase/acl": "1.7.0-beta.9",
|
||||||
"@nocobase/actions": "1.7.0-alpha.4",
|
"@nocobase/actions": "1.7.0-beta.9",
|
||||||
"@nocobase/auth": "1.7.0-alpha.4",
|
"@nocobase/auth": "1.7.0-beta.9",
|
||||||
"@nocobase/cache": "1.7.0-alpha.4",
|
"@nocobase/cache": "1.7.0-beta.9",
|
||||||
"@nocobase/data-source-manager": "1.7.0-alpha.4",
|
"@nocobase/data-source-manager": "1.7.0-beta.9",
|
||||||
"@nocobase/database": "1.7.0-alpha.4",
|
"@nocobase/database": "1.7.0-beta.9",
|
||||||
"@nocobase/evaluators": "1.7.0-alpha.4",
|
"@nocobase/evaluators": "1.7.0-beta.9",
|
||||||
"@nocobase/lock-manager": "1.7.0-alpha.4",
|
"@nocobase/lock-manager": "1.7.0-beta.9",
|
||||||
"@nocobase/logger": "1.7.0-alpha.4",
|
"@nocobase/logger": "1.7.0-beta.9",
|
||||||
"@nocobase/resourcer": "1.7.0-alpha.4",
|
"@nocobase/resourcer": "1.7.0-beta.9",
|
||||||
"@nocobase/sdk": "1.7.0-alpha.4",
|
"@nocobase/sdk": "1.7.0-beta.9",
|
||||||
"@nocobase/telemetry": "1.7.0-alpha.4",
|
"@nocobase/telemetry": "1.7.0-beta.9",
|
||||||
"@nocobase/utils": "1.7.0-alpha.4",
|
"@nocobase/utils": "1.7.0-beta.9",
|
||||||
"@types/decompress": "4.2.7",
|
"@types/decompress": "4.2.7",
|
||||||
"@types/ini": "^1.3.31",
|
"@types/ini": "^1.3.31",
|
||||||
"@types/koa-send": "^4.1.3",
|
"@types/koa-send": "^4.1.3",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/telemetry",
|
"name": "@nocobase/telemetry",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"description": "nocobase telemetry library",
|
"description": "nocobase telemetry library",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
@ -11,7 +11,7 @@
|
|||||||
"directory": "packages/telemetry"
|
"directory": "packages/telemetry"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/utils": "1.7.0-alpha.4",
|
"@nocobase/utils": "1.7.0-beta.9",
|
||||||
"@opentelemetry/api": "^1.7.0",
|
"@opentelemetry/api": "^1.7.0",
|
||||||
"@opentelemetry/instrumentation": "^0.46.0",
|
"@opentelemetry/instrumentation": "^0.46.0",
|
||||||
"@opentelemetry/resources": "^1.19.0",
|
"@opentelemetry/resources": "^1.19.0",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/test",
|
"name": "@nocobase/test",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"module": "./src/index.ts",
|
"module": "./src/index.ts",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
@ -51,7 +51,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@faker-js/faker": "8.1.0",
|
"@faker-js/faker": "8.1.0",
|
||||||
"@nocobase/server": "1.7.0-alpha.4",
|
"@nocobase/server": "1.7.0-beta.9",
|
||||||
"@playwright/test": "^1.45.3",
|
"@playwright/test": "^1.45.3",
|
||||||
"@testing-library/jest-dom": "^6.4.2",
|
"@testing-library/jest-dom": "^6.4.2",
|
||||||
"@testing-library/react": "^14.0.0",
|
"@testing-library/react": "^14.0.0",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/utils",
|
"name": "@nocobase/utils",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
|
@ -37,7 +37,7 @@ vi.mock('@formily/json-schema', () => {
|
|||||||
const result = { ...schema, parent };
|
const result = { ...schema, parent };
|
||||||
result._isJSONSchemaObject = true;
|
result._isJSONSchemaObject = true;
|
||||||
return result;
|
return result;
|
||||||
})
|
}),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -261,26 +261,26 @@ describe('transformMultiColumnToSingleColumn', () => {
|
|||||||
name: 'grid1',
|
name: 'grid1',
|
||||||
'x-component': 'Grid',
|
'x-component': 'Grid',
|
||||||
properties: {
|
properties: {
|
||||||
row1: {
|
row1: {
|
||||||
'x-component': 'Grid.Row',
|
'x-component': 'Grid.Row',
|
||||||
properties: {
|
properties: {
|
||||||
col1: { 'x-component': 'Input' },
|
col1: { 'x-component': 'Input' },
|
||||||
col2: { 'x-component': 'Select' },
|
col2: { 'x-component': 'Select' },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
parent: {
|
parent: {
|
||||||
properties: {
|
properties: {
|
||||||
grid1: {} // Will be replaced by result
|
grid1: {}, // Will be replaced by result
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
toJSON: vi.fn().mockImplementation(function() {
|
toJSON: vi.fn().mockImplementation(function () {
|
||||||
return {
|
return {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
'x-component': this['x-component'],
|
'x-component': this['x-component'],
|
||||||
properties: this.properties
|
properties: this.properties,
|
||||||
};
|
};
|
||||||
})
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = transformMultiColumnToSingleColumn(mockSchema);
|
const result = transformMultiColumnToSingleColumn(mockSchema);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "权限控制",
|
"displayName.zh-CN": "权限控制",
|
||||||
"description": "Based on roles, resources, and actions, access control can precisely manage interface configuration permissions, data operation permissions, menu access permissions, and plugin permissions.",
|
"description": "Based on roles, resources, and actions, access control can precisely manage interface configuration permissions, data operation permissions, menu access permissions, and plugin permissions.",
|
||||||
"description.zh-CN": "基于角色、资源和操作的权限控制,可以精确控制界面配置权限、数据操作权限、菜单访问权限、插件权限。",
|
"description.zh-CN": "基于角色、资源和操作的权限控制,可以精确控制界面配置权限、数据操作权限、菜单访问权限、插件权限。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/acl",
|
"homepage": "https://docs.nocobase.com/handbook/acl",
|
||||||
|
@ -276,41 +276,43 @@ export const MenuPermissions: React.FC<{
|
|||||||
expandable={{
|
expandable={{
|
||||||
defaultExpandAllRows: false,
|
defaultExpandAllRows: false,
|
||||||
}}
|
}}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: 'title',
|
{
|
||||||
title: t('Route name'),
|
dataIndex: 'title',
|
||||||
},
|
title: t('Route name'),
|
||||||
{
|
|
||||||
dataIndex: 'accessible',
|
|
||||||
title: (
|
|
||||||
<>
|
|
||||||
<Checkbox
|
|
||||||
checked={allChecked}
|
|
||||||
onChange={async (value) => {
|
|
||||||
if (allChecked) {
|
|
||||||
await resource.set({
|
|
||||||
values: [],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await resource.set({
|
|
||||||
values: allIDList,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
refresh();
|
|
||||||
refreshDesktopRoutes();
|
|
||||||
message.success(t('Saved successfully'));
|
|
||||||
}}
|
|
||||||
/>{' '}
|
|
||||||
{t('Accessible')}
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
render: (_, schema) => {
|
|
||||||
const checked = IDList.includes(schema.id);
|
|
||||||
return <Checkbox checked={checked} onChange={() => handleChange(checked, schema)} />;
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
] as TableProps['columns']}
|
dataIndex: 'accessible',
|
||||||
|
title: (
|
||||||
|
<>
|
||||||
|
<Checkbox
|
||||||
|
checked={allChecked}
|
||||||
|
onChange={async (value) => {
|
||||||
|
if (allChecked) {
|
||||||
|
await resource.set({
|
||||||
|
values: [],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await resource.set({
|
||||||
|
values: allIDList,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
refreshDesktopRoutes();
|
||||||
|
message.success(t('Saved successfully'));
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
|
{t('Accessible')}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
render: (_, schema) => {
|
||||||
|
const checked = IDList.includes(schema.id);
|
||||||
|
return <Checkbox checked={checked} onChange={() => handleChange(checked, schema)} />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
] as TableProps['columns']
|
||||||
|
}
|
||||||
dataSource={translateTitle(items, t, compile)}
|
dataSource={translateTitle(items, t, compile)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -113,44 +113,46 @@ export const PluginPermissions: React.FC<{
|
|||||||
expandable={{
|
expandable={{
|
||||||
defaultExpandAllRows: true,
|
defaultExpandAllRows: true,
|
||||||
}}
|
}}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: 'title',
|
{
|
||||||
title: t('Plugin name'),
|
dataIndex: 'title',
|
||||||
render: (value) => {
|
title: t('Plugin name'),
|
||||||
return compile(value);
|
render: (value) => {
|
||||||
|
return compile(value);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
dataIndex: 'accessible',
|
||||||
dataIndex: 'accessible',
|
title: (
|
||||||
title: (
|
<>
|
||||||
<>
|
<Checkbox
|
||||||
<Checkbox
|
checked={allChecked}
|
||||||
checked={allChecked}
|
onChange={async () => {
|
||||||
onChange={async () => {
|
const values = allAclSnippets.map((v) => '!' + v);
|
||||||
const values = allAclSnippets.map((v) => '!' + v);
|
if (!allChecked) {
|
||||||
if (!allChecked) {
|
await resource.remove({
|
||||||
await resource.remove({
|
values,
|
||||||
values,
|
});
|
||||||
});
|
} else {
|
||||||
} else {
|
await resource.add({
|
||||||
await resource.add({
|
values,
|
||||||
values,
|
});
|
||||||
});
|
}
|
||||||
}
|
refresh();
|
||||||
refresh();
|
message.success(t('Saved successfully'));
|
||||||
message.success(t('Saved successfully'));
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
{t('Accessible')}
|
||||||
{t('Accessible')}
|
</>
|
||||||
</>
|
),
|
||||||
),
|
render: (_, record) => {
|
||||||
render: (_, record) => {
|
const checked = !snippets.includes('!' + record.aclSnippet);
|
||||||
const checked = !snippets.includes('!' + record.aclSnippet);
|
return <Checkbox checked={checked} onChange={() => handleChange(checked, record)} />;
|
||||||
return <Checkbox checked={checked} onChange={() => handleChange(checked, record)} />;
|
},
|
||||||
},
|
},
|
||||||
},
|
] as TableProps['columns']
|
||||||
] as TableProps['columns']}
|
}
|
||||||
dataSource={settings
|
dataSource={settings
|
||||||
.filter((v) => {
|
.filter((v) => {
|
||||||
return v.isTopLevel !== false;
|
return v.isTopLevel !== false;
|
||||||
|
@ -106,48 +106,50 @@ export const RolesResourcesActions = connect((props) => {
|
|||||||
className={styles}
|
className={styles}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: 'displayName',
|
{
|
||||||
title: t('Action display name'),
|
dataIndex: 'displayName',
|
||||||
render: (value) => compile(value),
|
title: t('Action display name'),
|
||||||
},
|
render: (value) => compile(value),
|
||||||
{
|
},
|
||||||
dataIndex: 'onNewRecord',
|
{
|
||||||
title: t('Action type'),
|
dataIndex: 'onNewRecord',
|
||||||
render: (onNewRecord) =>
|
title: t('Action type'),
|
||||||
onNewRecord ? (
|
render: (onNewRecord) =>
|
||||||
<Tag color={'green'}>{t('Action on new records')}</Tag>
|
onNewRecord ? (
|
||||||
) : (
|
<Tag color={'green'}>{t('Action on new records')}</Tag>
|
||||||
<Tag color={'geekblue'}>{t('Action on existing records')}</Tag>
|
) : (
|
||||||
),
|
<Tag color={'geekblue'}>{t('Action on existing records')}</Tag>
|
||||||
},
|
),
|
||||||
{
|
},
|
||||||
dataIndex: 'enabled',
|
{
|
||||||
title: t('Allow'),
|
dataIndex: 'enabled',
|
||||||
render: (enabled, action) => (
|
title: t('Allow'),
|
||||||
<Checkbox
|
render: (enabled, action) => (
|
||||||
checked={enabled}
|
<Checkbox
|
||||||
onChange={() => {
|
checked={enabled}
|
||||||
toggleAction(action.name);
|
onChange={() => {
|
||||||
}}
|
toggleAction(action.name);
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataIndex: 'scope',
|
|
||||||
title: t('Data scope'),
|
|
||||||
render: (value, action) =>
|
|
||||||
!action.onNewRecord && (
|
|
||||||
<ScopeSelect
|
|
||||||
value={value}
|
|
||||||
onChange={(scope) => {
|
|
||||||
setScope(action.name, scope);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
] as TableProps['columns']}
|
{
|
||||||
|
dataIndex: 'scope',
|
||||||
|
title: t('Data scope'),
|
||||||
|
render: (value, action) =>
|
||||||
|
!action.onNewRecord && (
|
||||||
|
<ScopeSelect
|
||||||
|
value={value}
|
||||||
|
onChange={(scope) => {
|
||||||
|
setScope(action.name, scope);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
] as TableProps['columns']
|
||||||
|
}
|
||||||
dataSource={availableActions?.map((item) => {
|
dataSource={availableActions?.map((item) => {
|
||||||
let enabled = false;
|
let enabled = false;
|
||||||
let scope = null;
|
let scope = null;
|
||||||
@ -170,60 +172,62 @@ export const RolesResourcesActions = connect((props) => {
|
|||||||
className={styles}
|
className={styles}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
dataSource={fieldPermissions}
|
dataSource={fieldPermissions}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: ['uiSchema', 'title'],
|
{
|
||||||
title: t('Field display name'),
|
dataIndex: ['uiSchema', 'title'],
|
||||||
render: (value) => compile(value),
|
title: t('Field display name'),
|
||||||
},
|
render: (value) => compile(value),
|
||||||
...availableActionsWithFields.map((action) => {
|
},
|
||||||
const checked = allChecked?.[action.name];
|
...availableActionsWithFields.map((action) => {
|
||||||
return {
|
const checked = allChecked?.[action.name];
|
||||||
dataIndex: action.name,
|
return {
|
||||||
title: (
|
dataIndex: action.name,
|
||||||
<>
|
title: (
|
||||||
|
<>
|
||||||
|
<Checkbox
|
||||||
|
checked={checked}
|
||||||
|
onChange={() => {
|
||||||
|
const item = actionMap[action.name] || {
|
||||||
|
name: action.name,
|
||||||
|
};
|
||||||
|
if (checked) {
|
||||||
|
item.fields = [];
|
||||||
|
} else {
|
||||||
|
item.fields = collectionFields?.map?.((item) => item.name);
|
||||||
|
}
|
||||||
|
actionMap[action.name] = item;
|
||||||
|
onChange(Object.values(actionMap));
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
|
{compile(action.displayName)}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
render: (checked, field) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={checked}
|
checked={checked}
|
||||||
|
aria-label={`${action.name}_checkbox`}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
const item = actionMap[action.name] || {
|
const item = actionMap[action.name] || {
|
||||||
name: action.name,
|
name: action.name,
|
||||||
};
|
};
|
||||||
|
const fields: string[] = item.fields || [];
|
||||||
if (checked) {
|
if (checked) {
|
||||||
item.fields = [];
|
const index = fields.indexOf(field.name);
|
||||||
|
fields.splice(index, 1);
|
||||||
} else {
|
} else {
|
||||||
item.fields = collectionFields?.map?.((item) => item.name);
|
fields.push(field.name);
|
||||||
}
|
}
|
||||||
|
item.fields = fields;
|
||||||
actionMap[action.name] = item;
|
actionMap[action.name] = item;
|
||||||
onChange(Object.values(actionMap));
|
onChange(Object.values(actionMap));
|
||||||
}}
|
}}
|
||||||
/>{' '}
|
/>
|
||||||
{compile(action.displayName)}
|
),
|
||||||
</>
|
};
|
||||||
),
|
}),
|
||||||
render: (checked, field) => (
|
] as TableProps['columns']
|
||||||
<Checkbox
|
}
|
||||||
checked={checked}
|
|
||||||
aria-label={`${action.name}_checkbox`}
|
|
||||||
onChange={() => {
|
|
||||||
const item = actionMap[action.name] || {
|
|
||||||
name: action.name,
|
|
||||||
};
|
|
||||||
const fields: string[] = item.fields || [];
|
|
||||||
if (checked) {
|
|
||||||
const index = fields.indexOf(field.name);
|
|
||||||
fields.splice(index, 1);
|
|
||||||
} else {
|
|
||||||
fields.push(field.name);
|
|
||||||
}
|
|
||||||
item.fields = fields;
|
|
||||||
actionMap[action.name] = item;
|
|
||||||
onChange(Object.values(actionMap));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
] as TableProps['columns']}
|
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</FormLayout>
|
</FormLayout>
|
||||||
|
@ -55,62 +55,64 @@ export const StrategyActions = connect((props) => {
|
|||||||
rowKey={'name'}
|
rowKey={'name'}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: 'displayName',
|
{
|
||||||
title: t('Action display name'),
|
dataIndex: 'displayName',
|
||||||
render: (value) => compile(value),
|
title: t('Action display name'),
|
||||||
},
|
render: (value) => compile(value),
|
||||||
{
|
},
|
||||||
dataIndex: 'onNewRecord',
|
{
|
||||||
title: t('Action type'),
|
dataIndex: 'onNewRecord',
|
||||||
render: (onNewRecord) =>
|
title: t('Action type'),
|
||||||
onNewRecord ? (
|
render: (onNewRecord) =>
|
||||||
<Tag color={'green'}>{t('Action on new records')}</Tag>
|
onNewRecord ? (
|
||||||
) : (
|
<Tag color={'green'}>{t('Action on new records')}</Tag>
|
||||||
<Tag color={'geekblue'}>{t('Action on existing records')}</Tag>
|
) : (
|
||||||
),
|
<Tag color={'geekblue'}>{t('Action on existing records')}</Tag>
|
||||||
},
|
),
|
||||||
{
|
},
|
||||||
dataIndex: 'enabled',
|
{
|
||||||
title: t('Allow'),
|
dataIndex: 'enabled',
|
||||||
render: (enabled, action) => (
|
title: t('Allow'),
|
||||||
<Checkbox
|
render: (enabled, action) => (
|
||||||
checked={enabled}
|
<Checkbox
|
||||||
aria-label={`${action.name}_checkbox`}
|
checked={enabled}
|
||||||
onChange={(e) => {
|
aria-label={`${action.name}_checkbox`}
|
||||||
if (enabled) {
|
onChange={(e) => {
|
||||||
delete scopes[action.name];
|
if (enabled) {
|
||||||
} else {
|
delete scopes[action.name];
|
||||||
scopes[action.name] = 'all';
|
} else {
|
||||||
}
|
scopes[action.name] = 'all';
|
||||||
onChange(toFieldValue(scopes));
|
}
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataIndex: 'scope',
|
|
||||||
title: t('Data scope'),
|
|
||||||
render: (scope, action) =>
|
|
||||||
!action.onNewRecord && (
|
|
||||||
<Select
|
|
||||||
data-testid="select-data-scope"
|
|
||||||
popupMatchSelectWidth={false}
|
|
||||||
size={'small'}
|
|
||||||
value={scope}
|
|
||||||
options={[
|
|
||||||
{ label: t('All records'), value: 'all' },
|
|
||||||
{ label: t('Own records'), value: 'own' },
|
|
||||||
]}
|
|
||||||
onChange={(value) => {
|
|
||||||
scopes[action.name] = value;
|
|
||||||
onChange(toFieldValue(scopes));
|
onChange(toFieldValue(scopes));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
] as TableProps['columns']}
|
{
|
||||||
|
dataIndex: 'scope',
|
||||||
|
title: t('Data scope'),
|
||||||
|
render: (scope, action) =>
|
||||||
|
!action.onNewRecord && (
|
||||||
|
<Select
|
||||||
|
data-testid="select-data-scope"
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
size={'small'}
|
||||||
|
value={scope}
|
||||||
|
options={[
|
||||||
|
{ label: t('All records'), value: 'all' },
|
||||||
|
{ label: t('Own records'), value: 'own' },
|
||||||
|
]}
|
||||||
|
onChange={(value) => {
|
||||||
|
scopes[action.name] = value;
|
||||||
|
onChange(toFieldValue(scopes));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
] as TableProps['columns']
|
||||||
|
}
|
||||||
dataSource={availableActions?.map((item) => {
|
dataSource={availableActions?.map((item) => {
|
||||||
let scope = 'all';
|
let scope = 'all';
|
||||||
let enabled = false;
|
let enabled = false;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-action-bulk-edit",
|
"name": "@nocobase/plugin-action-bulk-edit",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/action-bulk-edit",
|
"homepage": "https://docs.nocobase.com/handbook/action-bulk-edit",
|
||||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-edit",
|
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-edit",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-action-bulk-update",
|
"name": "@nocobase/plugin-action-bulk-update",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/action-bulk-update",
|
"homepage": "https://docs.nocobase.com/handbook/action-bulk-update",
|
||||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-update",
|
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-update",
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ISchema, useFieldSchema } from '@formily/react';
|
import { ISchema, useFieldSchema } from '@formily/react';
|
||||||
import { isValid } from '@formily/shared';
|
|
||||||
import {
|
import {
|
||||||
ActionDesigner,
|
ActionDesigner,
|
||||||
SchemaSettings,
|
SchemaSettings,
|
||||||
@ -19,6 +18,8 @@ import {
|
|||||||
useDesignable,
|
useDesignable,
|
||||||
useSchemaToolbar,
|
useSchemaToolbar,
|
||||||
RefreshDataBlockRequest,
|
RefreshDataBlockRequest,
|
||||||
|
useAfterSuccessOptions,
|
||||||
|
useGlobalVariable,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -49,11 +50,22 @@ function UpdateMode() {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const fieldNames = {
|
||||||
|
value: 'value',
|
||||||
|
label: 'label',
|
||||||
|
};
|
||||||
|
const useVariableProps = (environmentVariables) => {
|
||||||
|
const scope = useAfterSuccessOptions();
|
||||||
|
return {
|
||||||
|
scope: [environmentVariables, ...scope].filter(Boolean),
|
||||||
|
fieldNames,
|
||||||
|
};
|
||||||
|
};
|
||||||
function AfterSuccess() {
|
function AfterSuccess() {
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
|
const environmentVariables = useGlobalVariable('$env');
|
||||||
return (
|
return (
|
||||||
<SchemaSettingsModalItem
|
<SchemaSettingsModalItem
|
||||||
title={t('After successful submission')}
|
title={t('After successful submission')}
|
||||||
@ -100,8 +112,9 @@ function AfterSuccess() {
|
|||||||
redirectTo: {
|
redirectTo: {
|
||||||
title: t('Link'),
|
title: t('Link'),
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Input',
|
'x-component': 'Variable.TextArea',
|
||||||
'x-component-props': {},
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
'x-use-component-props': () => useVariableProps(environmentVariables),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as ISchema
|
} as ISchema
|
||||||
|
@ -68,7 +68,7 @@ export const useCustomizeBulkUpdateActionProps = () => {
|
|||||||
if (result) {
|
if (result) {
|
||||||
assignedValues[key] = transformVariableValue(result, { targetCollectionField: collectionField });
|
assignedValues[key] = transformVariableValue(result, { targetCollectionField: collectionField });
|
||||||
}
|
}
|
||||||
} else if (value != null && value !== '') {
|
} else if (value !== '') {
|
||||||
assignedValues[key] = value;
|
assignedValues[key] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-action-custom-request",
|
"name": "@nocobase/plugin-action-custom-request",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/action-custom-request",
|
"homepage": "https://docs.nocobase.com/handbook/action-custom-request",
|
||||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-custom-request",
|
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-custom-request",
|
||||||
|
@ -68,10 +68,13 @@ export const useCustomizeRequestActionProps = () => {
|
|||||||
responseType: fieldSchema['x-response-type'] === 'stream' ? 'blob' : 'json',
|
responseType: fieldSchema['x-response-type'] === 'stream' ? 'blob' : 'json',
|
||||||
});
|
});
|
||||||
if (res.headers['content-disposition']) {
|
if (res.headers['content-disposition']) {
|
||||||
const regex = /attachment;\s*filename="([^"]+)"/;
|
const contentDisposition = res.headers['content-disposition'];
|
||||||
const match = res.headers['content-disposition'].match(regex);
|
const utf8Match = contentDisposition.match(/filename\*=utf-8''([^;]+)/i);
|
||||||
if (match?.[1]) {
|
const asciiMatch = contentDisposition.match(/filename="([^"]+)"/i);
|
||||||
saveAs(res.data, match[1]);
|
if (utf8Match) {
|
||||||
|
saveAs(res.data, decodeURIComponent(utf8Match[1]));
|
||||||
|
} else if (asciiMatch) {
|
||||||
|
saveAs(res.data, asciiMatch[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
actionField.data.loading = false;
|
actionField.data.loading = false;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-action-duplicate",
|
"name": "@nocobase/plugin-action-duplicate",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/action-duplicate",
|
"homepage": "https://docs.nocobase.com/handbook/action-duplicate",
|
||||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-duplicate",
|
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-duplicate",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "操作:导出记录",
|
"displayName.zh-CN": "操作:导出记录",
|
||||||
"description": "Export filtered records to excel, you can configure which fields to export.",
|
"description": "Export filtered records to excel, you can configure which fields to export.",
|
||||||
"description.zh-CN": "导出筛选后的记录到 Excel 中,可以配置导出哪些字段。",
|
"description.zh-CN": "导出筛选后的记录到 Excel 中,可以配置导出哪些字段。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/action-export",
|
"homepage": "https://docs.nocobase.com/handbook/action-export",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "操作:导入记录",
|
"displayName.zh-CN": "操作:导入记录",
|
||||||
"description": "Import records using excel templates. You can configure which fields to import and templates will be generated automatically.",
|
"description": "Import records using excel templates. You can configure which fields to import and templates will be generated automatically.",
|
||||||
"description.zh-CN": "使用 Excel 模板导入数据,可以配置导入哪些字段,自动生成模板。",
|
"description.zh-CN": "使用 Excel 模板导入数据,可以配置导入哪些字段,自动生成模板。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/action-import",
|
"homepage": "https://docs.nocobase.com/handbook/action-import",
|
||||||
|
@ -12,6 +12,7 @@ import { ISchema, useFieldSchema } from '@formily/react';
|
|||||||
import { Action, ActionContextProvider, PopupSettingsProvider, SchemaComponent, useCompile } from '@nocobase/client';
|
import { Action, ActionContextProvider, PopupSettingsProvider, SchemaComponent, useCompile } from '@nocobase/client';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { NAMESPACE } from './constants';
|
import { NAMESPACE } from './constants';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { UploadOutlined } from '@ant-design/icons';
|
import { UploadOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
const importFormSchema: ISchema = {
|
const importFormSchema: ISchema = {
|
||||||
@ -128,7 +129,7 @@ export const ImportAction = (props) => {
|
|||||||
return (
|
return (
|
||||||
<ActionContextProvider value={{ visible, setVisible, fieldSchema }}>
|
<ActionContextProvider value={{ visible, setVisible, fieldSchema }}>
|
||||||
<Action
|
<Action
|
||||||
icon={props.icon || <UploadOutlined />}
|
icon={props.icon || 'uploadoutlined'}
|
||||||
title={compile(fieldSchema?.title || "t('Import')")}
|
title={compile(fieldSchema?.title || "t('Import')")}
|
||||||
{...props}
|
{...props}
|
||||||
onClick={() => setVisible(true)}
|
onClick={() => setVisible(true)}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-action-print",
|
"name": "@nocobase/plugin-action-print",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/action-print",
|
"homepage": "https://docs.nocobase.com/handbook/action-print",
|
||||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-print",
|
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-print",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "AI 集成",
|
"displayName.zh-CN": "AI 集成",
|
||||||
"description": "Support integration with AI services, providing AI-related workflow nodes to enhance business processing capabilities.",
|
"description": "Support integration with AI services, providing AI-related workflow nodes to enhance business processing capabilities.",
|
||||||
"description.zh-CN": "支持接入 AI 服务,提供 AI 相关的工作流节点,增强业务处理能力。",
|
"description.zh-CN": "支持接入 AI 服务,提供 AI 相关的工作流节点,增强业务处理能力。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@nocobase/client": "1.x",
|
"@nocobase/client": "1.x",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-api-doc",
|
"name": "@nocobase/plugin-api-doc",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"displayName": "API documentation",
|
"displayName": "API documentation",
|
||||||
"displayName.zh-CN": "API 文档",
|
"displayName.zh-CN": "API 文档",
|
||||||
"description": "An OpenAPI documentation generator for NocoBase HTTP API.",
|
"description": "An OpenAPI documentation generator for NocoBase HTTP API.",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "认证:API 密钥",
|
"displayName.zh-CN": "认证:API 密钥",
|
||||||
"description": "Allows users to use API key to access application's HTTP API",
|
"description": "Allows users to use API key to access application's HTTP API",
|
||||||
"description.zh-CN": "允许用户使用 API 密钥访问应用的 HTTP API",
|
"description.zh-CN": "允许用户使用 API 密钥访问应用的 HTTP API",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/api-keys",
|
"homepage": "https://docs.nocobase.com/handbook/api-keys",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "异步任务管理器",
|
"displayName.zh-CN": "异步任务管理器",
|
||||||
"description": "Manage and monitor asynchronous tasks such as data import/export. Support task progress tracking and notification.",
|
"description": "Manage and monitor asynchronous tasks such as data import/export. Support task progress tracking and notification.",
|
||||||
"description.zh-CN": "管理和监控数据导入导出等异步任务。支持任务进度跟踪和通知。",
|
"description.zh-CN": "管理和监控数据导入导出等异步任务。支持任务进度跟踪和通知。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@nocobase/client": "1.x",
|
"@nocobase/client": "1.x",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-audit-logs",
|
"name": "@nocobase/plugin-audit-logs",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"displayName": "Audit logs (deprecated)",
|
"displayName": "Audit logs (deprecated)",
|
||||||
"displayName.zh-CN": "审计日志(废弃)",
|
"displayName.zh-CN": "审计日志(废弃)",
|
||||||
"description": "This plugin is deprecated. There will be a new audit log plugin in the future.",
|
"description": "This plugin is deprecated. There will be a new audit log plugin in the future.",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "认证:短信",
|
"displayName.zh-CN": "认证:短信",
|
||||||
"description": "SMS authentication.",
|
"description": "SMS authentication.",
|
||||||
"description.zh-CN": "通过短信验证码认证身份。",
|
"description.zh-CN": "通过短信验证码认证身份。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/auth-sms",
|
"homepage": "https://docs.nocobase.com/handbook/auth-sms",
|
||||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth-sms",
|
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth-sms",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-auth",
|
"name": "@nocobase/plugin-auth",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/auth",
|
"homepage": "https://docs.nocobase.com/handbook/auth",
|
||||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth",
|
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "应用的备份与还原(废弃)",
|
"displayName.zh-CN": "应用的备份与还原(废弃)",
|
||||||
"description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.",
|
"description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.",
|
||||||
"description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
|
"description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/backup-restore",
|
"homepage": "https://docs.nocobase.com/handbook/backup-restore",
|
||||||
|
@ -111,11 +111,11 @@ const LearnMore: any = (props: { collectionsData?: any; isBackup?: boolean }) =>
|
|||||||
render: (_, data) => {
|
render: (_, data) => {
|
||||||
const title = compile(data.title);
|
const title = compile(data.title);
|
||||||
const name = data.name;
|
const name = data.name;
|
||||||
return name === title ? title : (
|
return name === title ? (
|
||||||
|
title
|
||||||
|
) : (
|
||||||
<div>
|
<div>
|
||||||
{data.name}
|
{data.name} <span style={{ color: 'rgba(0, 0, 0, 0.3)', fontSize: '0.9em' }}>({compile(data.title)})</span>
|
||||||
{' '}
|
|
||||||
<span style={{ color: 'rgba(0, 0, 0, 0.3)', fontSize: '0.9em' }}>({compile(data.title)})</span>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -418,73 +418,75 @@ export const BackupAndRestoreList = () => {
|
|||||||
<Table
|
<Table
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
title: t('Backup file'),
|
{
|
||||||
dataIndex: 'name',
|
title: t('Backup file'),
|
||||||
width: 400,
|
dataIndex: 'name',
|
||||||
onCell: (data) => {
|
width: 400,
|
||||||
return data.inProgress
|
onCell: (data) => {
|
||||||
? {
|
return data.inProgress
|
||||||
colSpan: 4,
|
? {
|
||||||
}
|
colSpan: 4,
|
||||||
: {};
|
}
|
||||||
|
: {};
|
||||||
|
},
|
||||||
|
render: (name, data) =>
|
||||||
|
data.inProgress ? (
|
||||||
|
<div style={{ color: 'rgba(0, 0, 0, 0.88)' }}>
|
||||||
|
{name}({t('Backing up')}...)
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>{name}</div>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
render: (name, data) =>
|
{
|
||||||
data.inProgress ? (
|
title: t('File size'),
|
||||||
<div style={{ color: 'rgba(0, 0, 0, 0.88)' }}>
|
dataIndex: 'fileSize',
|
||||||
{name}({t('Backing up')}...)
|
onCell: (data) => {
|
||||||
</div>
|
return data.inProgress
|
||||||
) : (
|
? {
|
||||||
<div>{name}</div>
|
colSpan: 0,
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Created at', { ns: 'client' }),
|
||||||
|
dataIndex: 'createdAt',
|
||||||
|
onCell: (data) => {
|
||||||
|
return data.inProgress
|
||||||
|
? {
|
||||||
|
colSpan: 0,
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
},
|
||||||
|
render: (value) => {
|
||||||
|
return <DatePicker.ReadPretty value={value} showTime />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('Actions', { ns: 'client' }),
|
||||||
|
dataIndex: 'actions',
|
||||||
|
onCell: (data) => {
|
||||||
|
return data.inProgress
|
||||||
|
? {
|
||||||
|
colSpan: 0,
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
},
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space split={<Divider type="vertical" />}>
|
||||||
|
<Restore ButtonComponent={'a'} title={t('Restore')} fileData={record} />
|
||||||
|
<a type="link" onClick={() => handleDownload(record)}>
|
||||||
|
{t('Download')}
|
||||||
|
</a>
|
||||||
|
<a onClick={() => handleDestory(record)}>{t('Delete')}</a>
|
||||||
|
</Space>
|
||||||
),
|
),
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('File size'),
|
|
||||||
dataIndex: 'fileSize',
|
|
||||||
onCell: (data) => {
|
|
||||||
return data.inProgress
|
|
||||||
? {
|
|
||||||
colSpan: 0,
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
},
|
},
|
||||||
},
|
] as TableProps['columns']
|
||||||
{
|
}
|
||||||
title: t('Created at', { ns: 'client' }),
|
|
||||||
dataIndex: 'createdAt',
|
|
||||||
onCell: (data) => {
|
|
||||||
return data.inProgress
|
|
||||||
? {
|
|
||||||
colSpan: 0,
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
},
|
|
||||||
render: (value) => {
|
|
||||||
return <DatePicker.ReadPretty value={value} showTime />;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('Actions', { ns: 'client' }),
|
|
||||||
dataIndex: 'actions',
|
|
||||||
onCell: (data) => {
|
|
||||||
return data.inProgress
|
|
||||||
? {
|
|
||||||
colSpan: 0,
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
},
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space split={<Divider type="vertical" />}>
|
|
||||||
<Restore ButtonComponent={'a'} title={t('Restore')} fileData={record} />
|
|
||||||
<a type="link" onClick={() => handleDownload(record)}>
|
|
||||||
{t('Download')}
|
|
||||||
</a>
|
|
||||||
<a onClick={() => handleDestory(record)}>{t('Delete')}</a>
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
] as TableProps['columns']}
|
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "区块:iframe",
|
"displayName.zh-CN": "区块:iframe",
|
||||||
"description": "Create an iframe block on the page to embed and display external web pages or content.",
|
"description": "Create an iframe block on the page to embed and display external web pages or content.",
|
||||||
"description.zh-CN": "在页面上创建和管理iframe,用于嵌入和展示外部网页或内容。",
|
"description.zh-CN": "在页面上创建和管理iframe,用于嵌入和展示外部网页或内容。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/block-iframe",
|
"homepage": "https://docs.nocobase.com/handbook/block-iframe",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "区块:模板",
|
"displayName.zh-CN": "区块:模板",
|
||||||
"description": "Create and manage block templates for reuse on pages.",
|
"description": "Create and manage block templates for reuse on pages.",
|
||||||
"description.zh-CN": "创建和管理区块模板,用于在页面中重复使用。",
|
"description.zh-CN": "创建和管理区块模板,用于在页面中重复使用。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/block-template",
|
"homepage": "https://docs.nocobase.com/handbook/block-template",
|
||||||
|
@ -23,7 +23,7 @@ import { useLocation } from 'react-router-dom';
|
|||||||
|
|
||||||
const blockDecoratorMenuMaps = {
|
const blockDecoratorMenuMaps = {
|
||||||
TableBlockProvider: ['Table', 'table'],
|
TableBlockProvider: ['Table', 'table'],
|
||||||
FormBlockProvider: ['Form', 'form'],
|
FormBlockProvider: ['FormItem', 'form'],
|
||||||
DetailsBlockProvider: ['Details', 'details'],
|
DetailsBlockProvider: ['Details', 'details'],
|
||||||
'List.Decorator': ['List', 'list'],
|
'List.Decorator': ['List', 'list'],
|
||||||
'GridCard.Decorator': ['GridCard', 'gridCard'],
|
'GridCard.Decorator': ['GridCard', 'gridCard'],
|
||||||
@ -281,6 +281,7 @@ function getTemplateSchemaFromPage(schema: ISchema) {
|
|||||||
if (s['x-template-root-uid']) {
|
if (s['x-template-root-uid']) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
t = t || {};
|
||||||
_.merge(t, _.omit(s, ['x-uid', 'properties']));
|
_.merge(t, _.omit(s, ['x-uid', 'properties']));
|
||||||
t['x-uid'] = uid();
|
t['x-uid'] = uid();
|
||||||
if (s.properties) {
|
if (s.properties) {
|
||||||
@ -288,7 +289,7 @@ function getTemplateSchemaFromPage(schema: ISchema) {
|
|||||||
if (s.properties[key]['x-template-root-uid']) {
|
if (s.properties[key]['x-template-root-uid']) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_.set(t, `properties.${key}`, {});
|
_.set(t, `properties.['${key}']`, {});
|
||||||
traverseSchema(s.properties[key], t.properties[key]);
|
traverseSchema(s.properties[key], t.properties[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,6 +169,9 @@ export class PluginBlockTemplateClient extends Plugin {
|
|||||||
'blockSettings:createForm',
|
'blockSettings:createForm',
|
||||||
'blockSettings:details',
|
'blockSettings:details',
|
||||||
'blockSettings:detailsWithPagination',
|
'blockSettings:detailsWithPagination',
|
||||||
|
'blockSettings:multiDataDetails',
|
||||||
|
'blockSettings:singleDataDetails',
|
||||||
|
'blockSettings:stepsForm',
|
||||||
'blockSettings:filterCollapse',
|
'blockSettings:filterCollapse',
|
||||||
'blockSettings:filterForm',
|
'blockSettings:filterForm',
|
||||||
'blockSettings:gantt',
|
'blockSettings:gantt',
|
||||||
@ -176,6 +179,13 @@ export class PluginBlockTemplateClient extends Plugin {
|
|||||||
'blockSettings:kanban',
|
'blockSettings:kanban',
|
||||||
'blockSettings:list',
|
'blockSettings:list',
|
||||||
'blockSettings:table',
|
'blockSettings:table',
|
||||||
|
'blockSettings:tree',
|
||||||
|
'ReadPrettyFormSettings',
|
||||||
|
'GanttBlockSettings',
|
||||||
|
'FormV1Settings',
|
||||||
|
'FormSettings',
|
||||||
|
'FormItemSettings',
|
||||||
|
'FormDetailsSettings',
|
||||||
];
|
];
|
||||||
if (blockSettings.includes(key)) {
|
if (blockSettings.includes(key)) {
|
||||||
// schemaSetting.add('template-saveAsTemplateItem', saveAsTemplateSetting);
|
// schemaSetting.add('template-saveAsTemplateItem', saveAsTemplateSetting);
|
||||||
|
@ -43,6 +43,10 @@ export function convertTplBlock(
|
|||||||
if (newSchema['x-decorator'] === 'TemplateGridDecorator') {
|
if (newSchema['x-decorator'] === 'TemplateGridDecorator') {
|
||||||
delete newSchema['x-decorator'];
|
delete newSchema['x-decorator'];
|
||||||
}
|
}
|
||||||
|
if (newSchema['x-linkage-rules']) {
|
||||||
|
// linkage rules 有可能保存在Grid组件中
|
||||||
|
delete newSchema['x-linkage-rules'];
|
||||||
|
}
|
||||||
for (const key in tpl.properties) {
|
for (const key in tpl.properties) {
|
||||||
const t = convertTplBlock(tpl.properties[key], virtual, isRoot, newRootId, templateKey, options);
|
const t = convertTplBlock(tpl.properties[key], virtual, isRoot, newRootId, templateKey, options);
|
||||||
if (isRoot) {
|
if (isRoot) {
|
||||||
@ -154,8 +158,12 @@ export function formSchemaPatch(currentSchema: ISchema, options?: any) {
|
|||||||
return key !== 'grid';
|
return key !== 'grid';
|
||||||
});
|
});
|
||||||
if (actionKey) {
|
if (actionKey) {
|
||||||
_.set(currentSchema, `properties.${comKey}.x-use-component-props`, 'useEditFormBlockProps');
|
_.set(currentSchema, `properties.['${comKey}'].x-use-component-props`, 'useEditFormBlockProps');
|
||||||
_.set(currentSchema, `properties.${comKey}.properties.${actionKey}.x-initializer`, 'editForm:configureActions');
|
_.set(
|
||||||
|
currentSchema,
|
||||||
|
`properties.['${comKey}'].properties.['${actionKey}'].x-initializer`,
|
||||||
|
'editForm:configureActions',
|
||||||
|
);
|
||||||
|
|
||||||
const actionBarSchema = _.get(currentSchema, `properties.${comKey}.properties.${actionKey}.properties`, {});
|
const actionBarSchema = _.get(currentSchema, `properties.${comKey}.properties.${actionKey}.properties`, {});
|
||||||
for (const key in actionBarSchema) {
|
for (const key in actionBarSchema) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-block-workbench",
|
"name": "@nocobase/plugin-block-workbench",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"displayName": "Block: Action panel",
|
"displayName": "Block: Action panel",
|
||||||
"displayName.zh-CN": "区块:操作面板",
|
"displayName.zh-CN": "区块:操作面板",
|
||||||
"description": "Centrally manages and displays various actions, allowing users to efficiently perform tasks. It supports extensibility, with current action types including pop-ups, links, scanning, and custom requests.",
|
"description": "Centrally manages and displays various actions, allowing users to efficiently perform tasks. It supports extensibility, with current action types including pop-ups, links, scanning, and custom requests.",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-calendar",
|
"name": "@nocobase/plugin-calendar",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"displayName": "Calendar",
|
"displayName": "Calendar",
|
||||||
"displayName.zh-CN": "日历",
|
"displayName.zh-CN": "日历",
|
||||||
"description": "Provides callendar collection template and block for managing date data, typically for date/time related information such as events, appointments, tasks, and so on.",
|
"description": "Provides callendar collection template and block for managing date data, typically for date/time related information such as events, appointments, tasks, and so on.",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "图表(废弃)",
|
"displayName.zh-CN": "图表(废弃)",
|
||||||
"description": "The plugin has been deprecated, please use the data visualization plugin instead.",
|
"description": "The plugin has been deprecated, please use the data visualization plugin instead.",
|
||||||
"description.zh-CN": "已废弃插件,请使用数据可视化插件代替。",
|
"description.zh-CN": "已废弃插件,请使用数据可视化插件代替。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "WEB 客户端",
|
"displayName.zh-CN": "WEB 客户端",
|
||||||
"description": "Provides a client interface for the NocoBase server",
|
"description": "Provides a client interface for the NocoBase server",
|
||||||
"description.zh-CN": "为 NocoBase 服务端提供客户端界面",
|
"description.zh-CN": "为 NocoBase 服务端提供客户端界面",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "数据表: SQL",
|
"displayName.zh-CN": "数据表: SQL",
|
||||||
"description": "Provides SQL collection template",
|
"description": "Provides SQL collection template",
|
||||||
"description.zh-CN": "提供 SQL 数据表模板",
|
"description.zh-CN": "提供 SQL 数据表模板",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"homepage": "https://docs-cn.nocobase.com/handbook/collection-sql",
|
"homepage": "https://docs-cn.nocobase.com/handbook/collection-sql",
|
||||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/collection-sql",
|
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/collection-sql",
|
||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-collection-tree",
|
"name": "@nocobase/plugin-collection-tree",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"displayName": "Collection: Tree",
|
"displayName": "Collection: Tree",
|
||||||
"displayName.zh-CN": "数据表:树",
|
"displayName.zh-CN": "数据表:树",
|
||||||
"description": "Provides tree collection template",
|
"description": "Provides tree collection template",
|
||||||
|
@ -31,6 +31,8 @@ export default class extends Migration {
|
|||||||
await this.db.sequelize.transaction(async (transaction) => {
|
await this.db.sequelize.transaction(async (transaction) => {
|
||||||
const treeCollections = await this.getTreeCollections({ transaction });
|
const treeCollections = await this.getTreeCollections({ transaction });
|
||||||
for (const treeCollection of treeCollections) {
|
for (const treeCollection of treeCollections) {
|
||||||
|
await treeCollection.load({ transaction });
|
||||||
|
|
||||||
const name = `main_${treeCollection.name}_path`;
|
const name = `main_${treeCollection.name}_path`;
|
||||||
const collectionOptions = {
|
const collectionOptions = {
|
||||||
name,
|
name,
|
||||||
@ -47,35 +49,16 @@ export default class extends Migration {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const collectionInstance = this.db.getCollection(treeCollection.name);
|
const collectionInstance = this.db.getCollection(treeCollection.name);
|
||||||
const treeCollectionSchema = collectionInstance.collectionSchema();
|
const treeCollectionSchema = collectionInstance.collectionSchema();
|
||||||
|
|
||||||
if (this.app.db.inDialect('postgres') && treeCollectionSchema != this.app.db.options.schema) {
|
if (this.app.db.inDialect('postgres') && treeCollectionSchema != this.app.db.options.schema) {
|
||||||
collectionOptions['schema'] = treeCollectionSchema;
|
collectionOptions['schema'] = treeCollectionSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.app.db.collection(collectionOptions);
|
this.app.db.collection(collectionOptions);
|
||||||
|
|
||||||
const treeExistsInDb = await this.app.db.getCollection(name).existsInDb({ transaction });
|
const treeExistsInDb = await this.app.db.getCollection(name).existsInDb({ transaction });
|
||||||
|
|
||||||
if (!treeExistsInDb) {
|
if (!treeExistsInDb) {
|
||||||
await this.app.db.getCollection(name).sync({ transaction } as SyncOptions);
|
await this.app.db.getCollection(name).sync({ transaction } as SyncOptions);
|
||||||
const opts = {
|
|
||||||
name: treeCollection.name,
|
|
||||||
autoGenId: false,
|
|
||||||
timestamps: false,
|
|
||||||
fields: [
|
|
||||||
{ type: 'integer', name: 'id' },
|
|
||||||
{ type: 'integer', name: 'parentId' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
if (treeCollectionSchema != this.app.db.options.schema) {
|
|
||||||
opts['schema'] = treeCollectionSchema;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.app.db.collection(opts);
|
|
||||||
const chunkSize = 1000;
|
const chunkSize = 1000;
|
||||||
await this.app.db.getRepository(treeCollection.name).chunk({
|
await this.app.db.getRepository(treeCollection.name).chunk({
|
||||||
chunkSize: chunkSize,
|
chunkSize: chunkSize,
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"displayName.zh-CN": "数据源:主数据库",
|
"displayName.zh-CN": "数据源:主数据库",
|
||||||
"description": "NocoBase main database, supports relational databases such as PostgreSQL, MySQL, MariaDB and so on.",
|
"description": "NocoBase main database, supports relational databases such as PostgreSQL, MySQL, MariaDB and so on.",
|
||||||
"description.zh-CN": "NocoBase 主数据库,支持 PostgreSQL、MySQL、MariaDB 等关系型数据库。",
|
"description.zh-CN": "NocoBase 主数据库,支持 PostgreSQL、MySQL、MariaDB 等关系型数据库。",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "./dist/server/index.js",
|
"main": "./dist/server/index.js",
|
||||||
"homepage": "https://docs.nocobase.com/handbook/data-source-main",
|
"homepage": "https://docs.nocobase.com/handbook/data-source-main",
|
||||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/data-source-main",
|
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/data-source-main",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@nocobase/plugin-data-source-manager",
|
"name": "@nocobase/plugin-data-source-manager",
|
||||||
"version": "1.7.0-alpha.4",
|
"version": "1.7.0-beta.9",
|
||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
"displayName": "Data source manager",
|
"displayName": "Data source manager",
|
||||||
"displayName.zh-CN": "数据源管理",
|
"displayName.zh-CN": "数据源管理",
|
||||||
|
@ -101,48 +101,50 @@ export const RolesResourcesActions = connect((props) => {
|
|||||||
className={styles}
|
className={styles}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: 'displayName',
|
{
|
||||||
title: t('Action display name'),
|
dataIndex: 'displayName',
|
||||||
render: (value) => compile(value),
|
title: t('Action display name'),
|
||||||
},
|
render: (value) => compile(value),
|
||||||
{
|
},
|
||||||
dataIndex: 'onNewRecord',
|
{
|
||||||
title: t('Action type'),
|
dataIndex: 'onNewRecord',
|
||||||
render: (onNewRecord) =>
|
title: t('Action type'),
|
||||||
onNewRecord ? (
|
render: (onNewRecord) =>
|
||||||
<Tag color={'green'}>{t('Action on new records')}</Tag>
|
onNewRecord ? (
|
||||||
) : (
|
<Tag color={'green'}>{t('Action on new records')}</Tag>
|
||||||
<Tag color={'geekblue'}>{t('Action on existing records')}</Tag>
|
) : (
|
||||||
),
|
<Tag color={'geekblue'}>{t('Action on existing records')}</Tag>
|
||||||
},
|
),
|
||||||
{
|
},
|
||||||
dataIndex: 'enabled',
|
{
|
||||||
title: t('Allow'),
|
dataIndex: 'enabled',
|
||||||
render: (enabled, action) => (
|
title: t('Allow'),
|
||||||
<Checkbox
|
render: (enabled, action) => (
|
||||||
checked={enabled}
|
<Checkbox
|
||||||
onChange={() => {
|
checked={enabled}
|
||||||
toggleAction(action.name);
|
onChange={() => {
|
||||||
}}
|
toggleAction(action.name);
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataIndex: 'scope',
|
|
||||||
title: t('Data scope'),
|
|
||||||
render: (value, action) =>
|
|
||||||
!action.onNewRecord && (
|
|
||||||
<ScopeSelect
|
|
||||||
value={value}
|
|
||||||
onChange={(scope) => {
|
|
||||||
setScope(action.name, scope);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
] as TableProps['columns']}
|
{
|
||||||
|
dataIndex: 'scope',
|
||||||
|
title: t('Data scope'),
|
||||||
|
render: (value, action) =>
|
||||||
|
!action.onNewRecord && (
|
||||||
|
<ScopeSelect
|
||||||
|
value={value}
|
||||||
|
onChange={(scope) => {
|
||||||
|
setScope(action.name, scope);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
] as TableProps['columns']
|
||||||
|
}
|
||||||
dataSource={availableActions?.map((item) => {
|
dataSource={availableActions?.map((item) => {
|
||||||
let enabled = false;
|
let enabled = false;
|
||||||
let scope = null;
|
let scope = null;
|
||||||
@ -165,59 +167,61 @@ export const RolesResourcesActions = connect((props) => {
|
|||||||
className={styles}
|
className={styles}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
dataSource={fieldPermissions}
|
dataSource={fieldPermissions}
|
||||||
columns={[
|
columns={
|
||||||
{
|
[
|
||||||
dataIndex: ['uiSchema', 'title'],
|
{
|
||||||
title: t('Field display name'),
|
dataIndex: ['uiSchema', 'title'],
|
||||||
render: (value, record) => compile(value) || record.name,
|
title: t('Field display name'),
|
||||||
},
|
render: (value, record) => compile(value) || record.name,
|
||||||
...availableActionsWithFields.map((action) => {
|
},
|
||||||
const checked = allChecked?.[action.name];
|
...availableActionsWithFields.map((action) => {
|
||||||
return {
|
const checked = allChecked?.[action.name];
|
||||||
dataIndex: action.name,
|
return {
|
||||||
title: (
|
dataIndex: action.name,
|
||||||
<>
|
title: (
|
||||||
|
<>
|
||||||
|
<Checkbox
|
||||||
|
checked={checked}
|
||||||
|
onChange={() => {
|
||||||
|
const item = actionMap[action.name] || {
|
||||||
|
name: action.name,
|
||||||
|
};
|
||||||
|
if (checked) {
|
||||||
|
item.fields = [];
|
||||||
|
} else {
|
||||||
|
item.fields = collectionFields?.map?.((item) => item.name);
|
||||||
|
}
|
||||||
|
actionMap[action.name] = item;
|
||||||
|
onChange(Object.values(actionMap));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{compile(action.displayName)}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
render: (checked, field) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={checked}
|
checked={checked}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
const item = actionMap[action.name] || {
|
const item = actionMap[action.name] || {
|
||||||
name: action.name,
|
name: action.name,
|
||||||
};
|
};
|
||||||
|
const fields: string[] = item.fields || [];
|
||||||
if (checked) {
|
if (checked) {
|
||||||
item.fields = [];
|
const index = fields.indexOf(field.name);
|
||||||
|
fields.splice(index, 1);
|
||||||
} else {
|
} else {
|
||||||
item.fields = collectionFields?.map?.((item) => item.name);
|
fields.push(field.name);
|
||||||
}
|
}
|
||||||
|
item.fields = fields;
|
||||||
actionMap[action.name] = item;
|
actionMap[action.name] = item;
|
||||||
onChange(Object.values(actionMap));
|
onChange(Object.values(actionMap));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{compile(action.displayName)}
|
),
|
||||||
</>
|
};
|
||||||
),
|
}),
|
||||||
render: (checked, field) => (
|
] as TableProps['columns']
|
||||||
<Checkbox
|
}
|
||||||
checked={checked}
|
|
||||||
onChange={() => {
|
|
||||||
const item = actionMap[action.name] || {
|
|
||||||
name: action.name,
|
|
||||||
};
|
|
||||||
const fields: string[] = item.fields || [];
|
|
||||||
if (checked) {
|
|
||||||
const index = fields.indexOf(field.name);
|
|
||||||
fields.splice(index, 1);
|
|
||||||
} else {
|
|
||||||
fields.push(field.name);
|
|
||||||
}
|
|
||||||
item.fields = fields;
|
|
||||||
actionMap[action.name] = item;
|
|
||||||
onChange(Object.values(actionMap));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
] as TableProps['columns']}
|
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</FormLayout>
|
</FormLayout>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user