mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-01 18:52:20 +08:00
Compare commits
36 Commits
v1.8.0-bet
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
3387366f1e | ||
|
88cb9884f6 | ||
|
22cd39552f | ||
|
026baab241 | ||
|
d1ff280d9f | ||
|
88591454ec | ||
|
3c555e9fc0 | ||
|
6afcbffdec | ||
|
8d91e1fded | ||
|
940002a876 | ||
|
a4eb026ea4 | ||
|
74f3fd8132 | ||
|
4dcf934b15 | ||
|
17195c788d | ||
|
d538cd7db7 | ||
|
a9bd6f7844 | ||
|
e527e4d6ba | ||
|
4606bdd7fd | ||
|
dcfed325de | ||
|
a0181b58b1 | ||
|
bd900e9a92 | ||
|
4959e6a78e | ||
|
e808da6f52 | ||
|
784bedbc08 | ||
|
2c8934bd9a | ||
|
aa1070ad0f | ||
|
0cbcd03390 | ||
|
aa0699c4a8 | ||
|
d318138700 | ||
|
3623b33f5f | ||
|
46553df6ec | ||
|
94e40c5c7b | ||
|
544f561b26 | ||
|
cca6b0faaf | ||
|
d70eb68651 | ||
|
a67302a468 |
@ -48,6 +48,14 @@ DB_PASSWORD=nocobase
|
||||
# DB_LOGGING=on
|
||||
# DB_UNDERSCORED=false
|
||||
|
||||
# @see https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-constructor-constructor
|
||||
# DB_POOL_MAX=5
|
||||
# DB_POOL_MIN=0
|
||||
# DB_POOL_IDLE=10000
|
||||
# DB_POOL_ACQUIRE=60000
|
||||
# DB_POOL_EVICT=1000
|
||||
# DB_POOL_MAX_USES=0
|
||||
|
||||
# sqlite only
|
||||
# DB_STORAGE=storage/db/nocobase.sqlite
|
||||
|
||||
|
2
.github/workflows/build-docker.yml
vendored
2
.github/workflows/build-docker.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: ./docker/nocobase
|
||||
file: ./docker/nocobase/Dockerfile-cn
|
||||
file: ./docker/nocobase/Dockerfile-full
|
||||
build-args: |
|
||||
CNA_VERSION=${{ inputs.tag_name }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
240
.github/workflows/e2e.yml
vendored
240
.github/workflows/e2e.yml
vendored
@ -274,7 +274,7 @@ jobs:
|
||||
|
||||
- run: npx playwright install chromium --with-deps
|
||||
- name: Test with postgres
|
||||
run: yarn e2e p-test --match 'packages/**/{plugin-workflow,plugin-workflow-*}/**/__e2e__/**/*.test.ts' --ignore 'packages/**/plugin-workflow-approval/**/__e2e__/**/*.test.ts'
|
||||
run: yarn e2e p-test --match 'packages/**/{plugin-workflow,plugin-workflow-*}/**/__e2e__/**/*.test.ts' --ignore 'packages/**/plugin-workflow-approval/**/__e2e__/**/*.test.ts' --ignore 'packages/**/plugin-workflow-manual/**/__e2e__/**/*.test.ts'
|
||||
env:
|
||||
__E2E__: true
|
||||
APP_ENV: production
|
||||
@ -297,131 +297,131 @@ jobs:
|
||||
|
||||
timeout-minutes: 60
|
||||
|
||||
plugin-workflow-approval:
|
||||
name: plugin-workflow-approval
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
container: node:20
|
||||
services:
|
||||
# Label used to access the service container
|
||||
postgres:
|
||||
# Docker Hub image
|
||||
image: postgres:11
|
||||
# Provide the password for postgres
|
||||
env:
|
||||
POSTGRES_USER: nocobase
|
||||
POSTGRES_PASSWORD: password
|
||||
# Set health checks to wait until postgres has started
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.NOCOBASE_APP_ID }}
|
||||
private-key: ${{ secrets.NOCOBASE_APP_PRIVATE_KEY }}
|
||||
repositories: nocobase,pro-plugins,plugin-workflow-approval
|
||||
skip-token-revoke: true
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout pro-plugins
|
||||
continue-on-error: true # 外部开发者提交 PR 的时候因为没有权限这里会报错,为了能够继续执行后续步骤,所以这里设置为 continue-on-error: true
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: nocobase/pro-plugins
|
||||
ref: main
|
||||
path: packages/pro-plugins
|
||||
fetch-depth: 0
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
- name: Checkout plugin-workflow-approval
|
||||
continue-on-error: true # 外部开发者提交 PR 的时候因为没有权限这里会报错,为了能够继续执行后续步骤,所以这里设置为 continue-on-error: true
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: nocobase/plugin-workflow-approval
|
||||
ref: main
|
||||
path: packages/pro-plugins/@nocobase/plugin-workflow-approval
|
||||
fetch-depth: 0
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
- run: |
|
||||
cd packages/pro-plugins &&
|
||||
if git show-ref --quiet refs/remotes/origin/${{ github.head_ref || github.ref_name }}; then
|
||||
git checkout ${{ github.head_ref || github.ref_name }}
|
||||
else
|
||||
if git show-ref --quiet refs/remotes/origin/${{ github.event.pull_request.base.ref }}; then
|
||||
git checkout ${{ github.event.pull_request.base.ref }}
|
||||
else
|
||||
git checkout main
|
||||
fi
|
||||
fi
|
||||
cd ../../
|
||||
cd packages/pro-plugins/@nocobase/plugin-workflow-approval &&
|
||||
if git show-ref --quiet refs/remotes/origin/${{ github.head_ref || github.ref_name }}; then
|
||||
git checkout ${{ github.head_ref || github.ref_name }}
|
||||
else
|
||||
if git show-ref --quiet refs/remotes/origin/${{ github.event.pull_request.base.ref }}; then
|
||||
git checkout ${{ github.event.pull_request.base.ref }}
|
||||
else
|
||||
git checkout main
|
||||
fi
|
||||
fi
|
||||
cd ../../../../
|
||||
continue-on-error: true # 外部开发者提交 PR 的时候因为没有权限这里会报错,为了能够继续执行后续步骤,所以这里设置为 continue-on-error: true
|
||||
- name: Git logs
|
||||
run: |
|
||||
cd packages/pro-plugins/@nocobase/plugin-workflow-approval && git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit -n 10
|
||||
continue-on-error: true # 外部开发者提交 PR 的时候因为没有权限这里会报错,为了能够继续执行后续步骤,所以这里设置为 continue-on-error: true
|
||||
- name: Set variables
|
||||
continue-on-error: true # 外部开发者提交 PR 的时候因为没有权限这里会报错,为了能够继续执行后续步骤,所以这里设置为 continue-on-error: true
|
||||
run: |
|
||||
APPEND_PRESET_LOCAL_PLUGINS=$(find ./packages/pro-plugins/@nocobase -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sed 's/^plugin-//' | tr '\n' ',' | sed 's/,$//')
|
||||
echo "var2=$APPEND_PRESET_LOCAL_PLUGINS" >> $GITHUB_OUTPUT
|
||||
id: vars
|
||||
# plugin-workflow-approval:
|
||||
# name: plugin-workflow-approval
|
||||
# needs: build
|
||||
# runs-on: ubuntu-latest
|
||||
# container: node:20
|
||||
# services:
|
||||
# # Label used to access the service container
|
||||
# postgres:
|
||||
# # Docker Hub image
|
||||
# image: postgres:11
|
||||
# # Provide the password for postgres
|
||||
# env:
|
||||
# POSTGRES_USER: nocobase
|
||||
# POSTGRES_PASSWORD: password
|
||||
# # Set health checks to wait until postgres has started
|
||||
# options: >-
|
||||
# --health-cmd pg_isready
|
||||
# --health-interval 10s
|
||||
# --health-timeout 5s
|
||||
# --health-retries 5
|
||||
# steps:
|
||||
# - uses: actions/create-github-app-token@v1
|
||||
# id: app-token
|
||||
# with:
|
||||
# app-id: ${{ vars.NOCOBASE_APP_ID }}
|
||||
# private-key: ${{ secrets.NOCOBASE_APP_PRIVATE_KEY }}
|
||||
# repositories: nocobase,pro-plugins,plugin-workflow-approval
|
||||
# skip-token-revoke: true
|
||||
# - uses: actions/checkout@v4
|
||||
# - name: Checkout pro-plugins
|
||||
# continue-on-error: true # 外部开发者提交 PR 的时候因为没有权限这里会报错,为了能够继续执行后续步骤,所以这里设置为 continue-on-error: true
|
||||
# uses: actions/checkout@v4
|
||||
# with:
|
||||
# repository: nocobase/pro-plugins
|
||||
# ref: main
|
||||
# path: packages/pro-plugins
|
||||
# fetch-depth: 0
|
||||
# token: ${{ steps.app-token.outputs.token }}
|
||||
# - name: Checkout plugin-workflow-approval
|
||||
# continue-on-error: true # 外部开发者提交 PR 的时候因为没有权限这里会报错,为了能够继续执行后续步骤,所以这里设置为 continue-on-error: true
|
||||
# uses: actions/checkout@v4
|
||||
# with:
|
||||
# repository: nocobase/plugin-workflow-approval
|
||||
# ref: main
|
||||
# path: packages/pro-plugins/@nocobase/plugin-workflow-approval
|
||||
# fetch-depth: 0
|
||||
# token: ${{ steps.app-token.outputs.token }}
|
||||
# - run: |
|
||||
# cd packages/pro-plugins &&
|
||||
# if git show-ref --quiet refs/remotes/origin/${{ github.head_ref || github.ref_name }}; then
|
||||
# git checkout ${{ github.head_ref || github.ref_name }}
|
||||
# else
|
||||
# if git show-ref --quiet refs/remotes/origin/${{ github.event.pull_request.base.ref }}; then
|
||||
# git checkout ${{ github.event.pull_request.base.ref }}
|
||||
# else
|
||||
# git checkout main
|
||||
# fi
|
||||
# fi
|
||||
# cd ../../
|
||||
# cd packages/pro-plugins/@nocobase/plugin-workflow-approval &&
|
||||
# if git show-ref --quiet refs/remotes/origin/${{ github.head_ref || github.ref_name }}; then
|
||||
# git checkout ${{ github.head_ref || github.ref_name }}
|
||||
# else
|
||||
# if git show-ref --quiet refs/remotes/origin/${{ github.event.pull_request.base.ref }}; then
|
||||
# git checkout ${{ github.event.pull_request.base.ref }}
|
||||
# else
|
||||
# git checkout main
|
||||
# fi
|
||||
# fi
|
||||
# cd ../../../../
|
||||
# continue-on-error: true # 外部开发者提交 PR 的时候因为没有权限这里会报错,为了能够继续执行后续步骤,所以这里设置为 continue-on-error: true
|
||||
# - name: Git logs
|
||||
# run: |
|
||||
# cd packages/pro-plugins/@nocobase/plugin-workflow-approval && git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit -n 10
|
||||
# continue-on-error: true # 外部开发者提交 PR 的时候因为没有权限这里会报错,为了能够继续执行后续步骤,所以这里设置为 continue-on-error: true
|
||||
# - name: Set variables
|
||||
# continue-on-error: true # 外部开发者提交 PR 的时候因为没有权限这里会报错,为了能够继续执行后续步骤,所以这里设置为 continue-on-error: true
|
||||
# run: |
|
||||
# APPEND_PRESET_LOCAL_PLUGINS=$(find ./packages/pro-plugins/@nocobase -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sed 's/^plugin-//' | tr '\n' ',' | sed 's/,$//')
|
||||
# echo "var2=$APPEND_PRESET_LOCAL_PLUGINS" >> $GITHUB_OUTPUT
|
||||
# id: vars
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
- uses: actions/cache@v4
|
||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
# - name: Get yarn cache directory path
|
||||
# id: yarn-cache-dir-path
|
||||
# run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
# - uses: actions/cache@v4
|
||||
# id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||
# with:
|
||||
# path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
# key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
# restore-keys: |
|
||||
# ${{ runner.os }}-yarn-
|
||||
|
||||
- run: yarn
|
||||
# - run: yarn
|
||||
|
||||
- name: Download build artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: build-artifact
|
||||
path: packages
|
||||
# - name: Download build artifact
|
||||
# uses: actions/download-artifact@v4
|
||||
# with:
|
||||
# name: build-artifact
|
||||
# path: packages
|
||||
|
||||
- run: npx playwright install chromium --with-deps
|
||||
- name: Test with postgres
|
||||
run: yarn e2e p-test --match 'packages/**/plugin-workflow-approval/**/__e2e__/**/*.test.ts'
|
||||
env:
|
||||
__E2E__: true
|
||||
APP_ENV: production
|
||||
LOGGER_LEVEL: error
|
||||
DB_DIALECT: postgres
|
||||
DB_HOST: postgres
|
||||
DB_PORT: 5432
|
||||
DB_USER: nocobase
|
||||
DB_PASSWORD: password
|
||||
DB_DATABASE: nocobase
|
||||
APPEND_PRESET_LOCAL_PLUGINS: ${{ steps.vars.outputs.var2 }}
|
||||
ENCRYPTION_FIELD_KEY: 1%&glK;<UA}aIxJVc53-4G(rTi0vg@J]
|
||||
# - run: npx playwright install chromium --with-deps
|
||||
# - name: Test with postgres
|
||||
# run: yarn e2e p-test --match 'packages/**/plugin-workflow-approval/**/__e2e__/**/*.test.ts'
|
||||
# env:
|
||||
# __E2E__: true
|
||||
# APP_ENV: production
|
||||
# LOGGER_LEVEL: error
|
||||
# DB_DIALECT: postgres
|
||||
# DB_HOST: postgres
|
||||
# DB_PORT: 5432
|
||||
# DB_USER: nocobase
|
||||
# DB_PASSWORD: password
|
||||
# DB_DATABASE: nocobase
|
||||
# APPEND_PRESET_LOCAL_PLUGINS: ${{ steps.vars.outputs.var2 }}
|
||||
# ENCRYPTION_FIELD_KEY: 1%&glK;<UA}aIxJVc53-4G(rTi0vg@J]
|
||||
|
||||
- name: Upload e2e-report
|
||||
if: ${{ !cancelled() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: e2e-report-${{ github.job }} # 为了防止在多个任务中存在冲突
|
||||
path: ./storage/playwright/tests-report-blob/blob-*/*
|
||||
# - name: Upload e2e-report
|
||||
# if: ${{ !cancelled() }}
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: e2e-report-${{ github.job }} # 为了防止在多个任务中存在冲突
|
||||
# path: ./storage/playwright/tests-report-blob/blob-*/*
|
||||
|
||||
timeout-minutes: 180
|
||||
# timeout-minutes: 180
|
||||
|
||||
plugin-data-source-main:
|
||||
name: plugin-data-source-main
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -216,7 +216,7 @@ jobs:
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: ./docker/nocobase
|
||||
file: ./docker/nocobase/Dockerfile-cn
|
||||
file: ./docker/nocobase/Dockerfile-full
|
||||
build-args: |
|
||||
CNA_VERSION=${{ steps.get-info.outputs.defaultTag }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
64
CHANGELOG.md
64
CHANGELOG.md
@ -5,6 +5,70 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [v1.7.18](https://github.com/nocobase/nocobase/compare/v1.7.17...v1.7.18) - 2025-06-26
|
||||
|
||||
### 🚀 Improvements
|
||||
|
||||
- **[Workflow]** Optimize mobile style ([#7040](https://github.com/nocobase/nocobase/pull/7040)) by @mytharcher
|
||||
|
||||
- **[Public forms]** Optimize the performance of date components in public forms ([#7117](https://github.com/nocobase/nocobase/pull/7117)) by @zhangzhonghe
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **[Workflow]** Fix params of loading record in tasks ([#7123](https://github.com/nocobase/nocobase/pull/7123)) by @mytharcher
|
||||
|
||||
- **[WEB client]** Fix issue where blocks under pages were not displayed after setting role menu permissions ([#7112](https://github.com/nocobase/nocobase/pull/7112)) by @aaaaaajie
|
||||
|
||||
- **[Workflow: Approval]**
|
||||
- Fix applicant variable name in trigger by @mytharcher
|
||||
|
||||
- Fix mobile styles by @mytharcher
|
||||
|
||||
- Fix error thrown when approval related collection deleted by @mytharcher
|
||||
|
||||
## [v1.7.17](https://github.com/nocobase/nocobase/compare/v1.7.16...v1.7.17) - 2025-06-23
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **[client]**
|
||||
- incorrect range limitation on date fields with time ([#7107](https://github.com/nocobase/nocobase/pull/7107)) by @katherinehhh
|
||||
|
||||
- When URL query parameter variables are empty, the data scope conditions are not removed ([#7104](https://github.com/nocobase/nocobase/pull/7104)) by @zhangzhonghe
|
||||
|
||||
- **[Mobile]** Fix mobile popup z-index issue ([#7110](https://github.com/nocobase/nocobase/pull/7110)) by @zhangzhonghe
|
||||
|
||||
- **[Calendar]** date field issue in quick create form of calendar block ([#7106](https://github.com/nocobase/nocobase/pull/7106)) by @katherinehhh
|
||||
|
||||
## [v1.7.16](https://github.com/nocobase/nocobase/compare/v1.7.15...v1.7.16) - 2025-06-19
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **[Workflow]**
|
||||
- Fix incorrectly executed checking on big integer number ([#7099](https://github.com/nocobase/nocobase/pull/7099)) by @mytharcher
|
||||
|
||||
- Fix stats cascade deleted by non-current workflow version ([#7103](https://github.com/nocobase/nocobase/pull/7103)) by @mytharcher
|
||||
|
||||
- **[Action: Import records]** Resolve login failure issue after batch import of usernames and passwords ([#7076](https://github.com/nocobase/nocobase/pull/7076)) by @aaaaaajie
|
||||
|
||||
- **[Workflow: Approval]** Only participants can view (get) detail of approval by @mytharcher
|
||||
|
||||
## [v1.7.15](https://github.com/nocobase/nocobase/compare/v1.7.14...v1.7.15) - 2025-06-18
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **[client]**
|
||||
- Use independent variable scope for each field ([#7012](https://github.com/nocobase/nocobase/pull/7012)) by @mytharcher
|
||||
|
||||
- Assign field values: Unable to clear data for relation fields ([#7086](https://github.com/nocobase/nocobase/pull/7086)) by @zhangzhonghe
|
||||
|
||||
- Table column text alignment function is not working ([#7094](https://github.com/nocobase/nocobase/pull/7094)) by @zhangzhonghe
|
||||
|
||||
- **[Workflow]** Fix incorrectly executed checking on big integer number ([#7091](https://github.com/nocobase/nocobase/pull/7091)) by @mytharcher
|
||||
|
||||
- **[File manager]** Fix attachments field can not be updated in approval process ([#7093](https://github.com/nocobase/nocobase/pull/7093)) by @mytharcher
|
||||
|
||||
- **[Workflow: Approval]** Use comparison instead of implicit logic to avoid type issues by @mytharcher
|
||||
|
||||
## [v1.7.14](https://github.com/nocobase/nocobase/compare/v1.7.13...v1.7.14) - 2025-06-17
|
||||
|
||||
### 🚀 Improvements
|
||||
|
@ -5,6 +5,70 @@
|
||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
||||
并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。
|
||||
|
||||
## [v1.7.18](https://github.com/nocobase/nocobase/compare/v1.7.17...v1.7.18) - 2025-06-26
|
||||
|
||||
### 🚀 优化
|
||||
|
||||
- **[工作流]** 优化移动端样式 ([#7040](https://github.com/nocobase/nocobase/pull/7040)) by @mytharcher
|
||||
|
||||
- **[公开表单]** 优化公开表单中日期组件的性能 ([#7117](https://github.com/nocobase/nocobase/pull/7117)) by @zhangzhonghe
|
||||
|
||||
### 🐛 修复
|
||||
|
||||
- **[工作流]** 修复待办中心加载记录的参数 ([#7123](https://github.com/nocobase/nocobase/pull/7123)) by @mytharcher
|
||||
|
||||
- **[WEB 客户端]** 修复设置角色菜单权限后页面下区块不显示的问题 ([#7112](https://github.com/nocobase/nocobase/pull/7112)) by @aaaaaajie
|
||||
|
||||
- **[工作流:审批]**
|
||||
- 修复审批触发器中申请人变量名的问题 by @mytharcher
|
||||
|
||||
- 修复移动端样式 by @mytharcher
|
||||
|
||||
- 修复审批关联表被删除后的报错 by @mytharcher
|
||||
|
||||
## [v1.7.17](https://github.com/nocobase/nocobase/compare/v1.7.16...v1.7.17) - 2025-06-23
|
||||
|
||||
### 🐛 修复
|
||||
|
||||
- **[client]**
|
||||
- 修复日期字段在含时间格式下的范围约束错误 ([#7107](https://github.com/nocobase/nocobase/pull/7107)) by @katherinehhh
|
||||
|
||||
- URL 查询参数变量为空时,数据范围的条件没有被移除 ([#7104](https://github.com/nocobase/nocobase/pull/7104)) by @zhangzhonghe
|
||||
|
||||
- **[移动端]** 修复移动端弹窗的层级问题 ([#7110](https://github.com/nocobase/nocobase/pull/7110)) by @zhangzhonghe
|
||||
|
||||
- **[日历]** 修复日历区块快速创建事项时,表单日期字段异常问题 ([#7106](https://github.com/nocobase/nocobase/pull/7106)) by @katherinehhh
|
||||
|
||||
## [v1.7.16](https://github.com/nocobase/nocobase/compare/v1.7.15...v1.7.16) - 2025-06-19
|
||||
|
||||
### 🐛 修复
|
||||
|
||||
- **[工作流]**
|
||||
- 修复已执行数在大整型数时检查错误的问题 ([#7099](https://github.com/nocobase/nocobase/pull/7099)) by @mytharcher
|
||||
|
||||
- 修复统计数据被不是主版本的工作流级联删除的问题 ([#7103](https://github.com/nocobase/nocobase/pull/7103)) by @mytharcher
|
||||
|
||||
- **[操作:导入记录]** 修复批量导入用户名和密码后无法登录的问题 ([#7076](https://github.com/nocobase/nocobase/pull/7076)) by @aaaaaajie
|
||||
|
||||
- **[工作流:审批]** 限制只有参与者可以查看审批详情 by @mytharcher
|
||||
|
||||
## [v1.7.15](https://github.com/nocobase/nocobase/compare/v1.7.14...v1.7.15) - 2025-06-18
|
||||
|
||||
### 🐛 修复
|
||||
|
||||
- **[client]**
|
||||
- 对每个字段使用独立的变量范围 ([#7012](https://github.com/nocobase/nocobase/pull/7012)) by @mytharcher
|
||||
|
||||
- 字段赋值:关系字段无法被清空数据 ([#7086](https://github.com/nocobase/nocobase/pull/7086)) by @zhangzhonghe
|
||||
|
||||
- 表格列的文本对齐功能无效 ([#7094](https://github.com/nocobase/nocobase/pull/7094)) by @zhangzhonghe
|
||||
|
||||
- **[工作流]** 修复已执行数在大整型数时检查错误的问题 ([#7091](https://github.com/nocobase/nocobase/pull/7091)) by @mytharcher
|
||||
|
||||
- **[文件管理器]** 修复审批处理中附件字段无法被更新的问题 ([#7093](https://github.com/nocobase/nocobase/pull/7093)) by @mytharcher
|
||||
|
||||
- **[工作流:审批]** 使用比较代替隐式逻辑以避免类型问题 by @mytharcher
|
||||
|
||||
## [v1.7.14](https://github.com/nocobase/nocobase/compare/v1.7.13...v1.7.14) - 2025-06-17
|
||||
|
||||
### 🚀 优化
|
||||
|
@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
nginx
|
||||
echo 'nginx started';
|
||||
|
||||
cd /app/nocobase && yarn nocobase db:auth --retry=30
|
||||
cd /app/nocobase && yarn nocobase install -s
|
||||
cd /app/nocobase && yarn nocobase upgrade -S
|
||||
cd /app/nocobase && yarn start
|
||||
|
||||
# Run command with node if the first argument contains a "-" or is not a system command. The last
|
||||
# part inside the "{}" is a workaround for the following bug in ash/dash:
|
||||
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
|
||||
if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then
|
||||
set -- node "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
@ -1,43 +0,0 @@
|
||||
log_format apm '"$time_local" client=$remote_addr '
|
||||
'method=$request_method request="$request" '
|
||||
'request_length=$request_length '
|
||||
'status=$status bytes_sent=$bytes_sent '
|
||||
'body_bytes_sent=$body_bytes_sent '
|
||||
'referer=$http_referer '
|
||||
'user_agent="$http_user_agent" '
|
||||
'upstream_addr=$upstream_addr '
|
||||
'upstream_status=$upstream_status '
|
||||
'request_time=$request_time '
|
||||
'upstream_response_time=$upstream_response_time '
|
||||
'upstream_connect_time=$upstream_connect_time '
|
||||
'upstream_header_time=$upstream_header_time';
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /app/nocobase/packages/app/client/dist;
|
||||
index index.html;
|
||||
client_max_body_size 0;
|
||||
|
||||
access_log /var/log/nginx/nocobase.log apm;
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /app/nocobase/storage/uploads/;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /app/nocobase/packages/app/client/dist;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location ^~ /api/ {
|
||||
proxy_pass http://127.0.0.1:13000/api/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"npmClientArgs": ["--ignore-engines"],
|
||||
|
@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@nocobase/acl",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"dependencies": {
|
||||
"@nocobase/resourcer": "1.7.14",
|
||||
"@nocobase/utils": "1.7.14",
|
||||
"@nocobase/resourcer": "1.7.18",
|
||||
"@nocobase/utils": "1.7.18",
|
||||
"minimatch": "^5.1.1"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -1,14 +1,14 @@
|
||||
{
|
||||
"name": "@nocobase/actions",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"dependencies": {
|
||||
"@nocobase/cache": "1.7.14",
|
||||
"@nocobase/database": "1.7.14",
|
||||
"@nocobase/resourcer": "1.7.14"
|
||||
"@nocobase/cache": "1.7.18",
|
||||
"@nocobase/database": "1.7.18",
|
||||
"@nocobase/resourcer": "1.7.18"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@nocobase/app",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"dependencies": {
|
||||
"@nocobase/database": "1.7.14",
|
||||
"@nocobase/preset-nocobase": "1.7.14",
|
||||
"@nocobase/server": "1.7.14"
|
||||
"@nocobase/database": "1.7.18",
|
||||
"@nocobase/preset-nocobase": "1.7.18",
|
||||
"@nocobase/server": "1.7.18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nocobase/client": "1.7.14"
|
||||
"@nocobase/client": "1.7.18"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "@nocobase/auth",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"dependencies": {
|
||||
"@nocobase/actions": "1.7.14",
|
||||
"@nocobase/cache": "1.7.14",
|
||||
"@nocobase/database": "1.7.14",
|
||||
"@nocobase/resourcer": "1.7.14",
|
||||
"@nocobase/utils": "1.7.14",
|
||||
"@nocobase/actions": "1.7.18",
|
||||
"@nocobase/cache": "1.7.18",
|
||||
"@nocobase/database": "1.7.18",
|
||||
"@nocobase/resourcer": "1.7.18",
|
||||
"@nocobase/utils": "1.7.18",
|
||||
"@types/jsonwebtoken": "^9.0.9",
|
||||
"jsonwebtoken": "^9.0.2"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/build",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "Library build tool based on rollup.",
|
||||
"main": "lib/index.js",
|
||||
"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",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"dependencies": {
|
||||
"@nocobase/lock-manager": "1.7.14",
|
||||
"@nocobase/lock-manager": "1.7.18",
|
||||
"bloom-filters": "^3.0.1",
|
||||
"cache-manager": "^5.2.4",
|
||||
"cache-manager-redis-yet": "^4.1.2"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/cli",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./src/index.js",
|
||||
@ -8,7 +8,7 @@
|
||||
"nocobase": "./bin/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nocobase/app": "1.7.14",
|
||||
"@nocobase/app": "1.7.18",
|
||||
"@types/fs-extra": "^11.0.1",
|
||||
"@umijs/utils": "3.5.20",
|
||||
"chalk": "^4.1.1",
|
||||
@ -26,7 +26,7 @@
|
||||
"tsx": "^4.19.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nocobase/devtools": "1.7.14"
|
||||
"@nocobase/devtools": "1.7.18"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -114,7 +114,7 @@ exports.postCheck = async (opts) => {
|
||||
const port = opts.port || process.env.APP_PORT;
|
||||
const result = await exports.isPortReachable(port);
|
||||
if (result) {
|
||||
console.error(chalk.red(`post already in use ${port}`));
|
||||
console.error(chalk.red(`Port ${port} already in use`));
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/client",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.mjs",
|
||||
@ -26,9 +26,9 @@
|
||||
"@formily/reactive-react": "^2.2.27",
|
||||
"@formily/shared": "^2.2.27",
|
||||
"@formily/validator": "^2.2.27",
|
||||
"@nocobase/evaluators": "1.7.14",
|
||||
"@nocobase/sdk": "1.7.14",
|
||||
"@nocobase/utils": "1.7.14",
|
||||
"@nocobase/evaluators": "1.7.18",
|
||||
"@nocobase/sdk": "1.7.18",
|
||||
"@nocobase/utils": "1.7.18",
|
||||
"ahooks": "^3.7.2",
|
||||
"antd": "5.24.2",
|
||||
"antd-style": "3.7.1",
|
||||
|
@ -197,9 +197,7 @@ export function useCollectValuesToSubmit() {
|
||||
|
||||
if (isVariable(value)) {
|
||||
const { value: parsedValue } = (await variables?.parseVariable(value, localVariables)) || {};
|
||||
if (parsedValue !== null && parsedValue !== undefined) {
|
||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||
}
|
||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||
} else if (value !== '') {
|
||||
assignedValues[key] = value;
|
||||
}
|
||||
@ -385,9 +383,7 @@ export const useAssociationCreateActionProps = () => {
|
||||
|
||||
if (isVariable(value)) {
|
||||
const { value: parsedValue } = (await variables?.parseVariable(value, localVariables)) || {};
|
||||
if (parsedValue) {
|
||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||
}
|
||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||
} else if (value !== '') {
|
||||
assignedValues[key] = value;
|
||||
}
|
||||
@ -658,9 +654,7 @@ export const useCustomizeUpdateActionProps = () => {
|
||||
|
||||
if (isVariable(value)) {
|
||||
const { value: parsedValue } = (await variables?.parseVariable(value, localVariables)) || {};
|
||||
if (parsedValue) {
|
||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||
}
|
||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||
} else if (value !== '') {
|
||||
assignedValues[key] = value;
|
||||
}
|
||||
@ -771,9 +765,7 @@ export const useCustomizeBulkUpdateActionProps = () => {
|
||||
|
||||
if (isVariable(value)) {
|
||||
const { value: parsedValue } = (await variables?.parseVariable(value, localVariables)) || {};
|
||||
if (parsedValue) {
|
||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||
}
|
||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||
} else if (value !== '') {
|
||||
assignedValues[key] = value;
|
||||
}
|
||||
@ -999,9 +991,7 @@ export const useUpdateActionProps = () => {
|
||||
|
||||
if (isVariable(value)) {
|
||||
const { value: parsedValue } = (await variables?.parseVariable(value, localVariables)) || {};
|
||||
if (parsedValue) {
|
||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||
}
|
||||
assignedValues[key] = transformVariableValue(parsedValue, { targetCollectionField: collectionField });
|
||||
} else if (value !== '') {
|
||||
assignedValues[key] = value;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ export class DateFieldInterface extends CollectionFieldInterface {
|
||||
'x-component': 'DatePicker',
|
||||
'x-component-props': {
|
||||
dateOnly: true,
|
||||
showTime: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
import { useField, useForm } from '@formily/react';
|
||||
import { Cascader, Input, Select, Spin, Table, Tag } from 'antd';
|
||||
import { last, omit } from 'lodash';
|
||||
import _, { last, omit } from 'lodash';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ResourceActionContext, useCompile } from '../../../';
|
||||
@ -120,9 +120,10 @@ const PreviewCom = (props) => {
|
||||
}, [databaseView]);
|
||||
|
||||
const handleFieldChange = (record, index) => {
|
||||
dataSource.splice(index, 1, record);
|
||||
setDataSource(dataSource);
|
||||
field.value = dataSource.map((v) => {
|
||||
const newDataSource = _.cloneDeep(dataSource);
|
||||
newDataSource[index] = record;
|
||||
setDataSource(newDataSource);
|
||||
field.value = newDataSource.map((v) => {
|
||||
const source = typeof v.source === 'string' ? v.source : v.source?.filter?.(Boolean)?.join('.');
|
||||
return {
|
||||
...v,
|
||||
@ -198,8 +199,7 @@ const PreviewCom = (props) => {
|
||||
style={{ width: '100%' }}
|
||||
popupMatchSelectWidth={false}
|
||||
onChange={(value) => {
|
||||
const interfaceConfig = getInterface(value);
|
||||
handleFieldChange({ ...item, interface: value, uiSchema: interfaceConfig?.default?.uiSchema }, index);
|
||||
handleFieldChange({ ...item, interface: value }, index);
|
||||
}}
|
||||
>
|
||||
{data.map((group) => (
|
||||
|
@ -66,7 +66,7 @@ export const createFormBlockSettings = new SchemaSettings({
|
||||
useVisible() {
|
||||
const { action } = useFormBlockContext();
|
||||
const schema = useFieldSchema();
|
||||
return !action && schema?.['x-acl-action'].includes('create');
|
||||
return !action && schema?.['x-acl-action']?.includes('create');
|
||||
},
|
||||
useComponentProps() {
|
||||
const { name } = useCollection_deprecated();
|
||||
|
@ -19,6 +19,7 @@ import { useKeepAlive } from '../../../route-switch/antd/admin-layout/KeepAlive'
|
||||
import { useSchemaComponentContext } from '../../hooks';
|
||||
import { AssociationFieldContext } from './context';
|
||||
import { FormItem, useSchemaOptionsContext } from '../../../schema-component';
|
||||
import { useCollectionRecord } from '../../../data-source';
|
||||
|
||||
export const AssociationFieldProvider = observer(
|
||||
(props) => {
|
||||
@ -28,6 +29,7 @@ export const AssociationFieldProvider = observer(
|
||||
const api = useAPIClient();
|
||||
const option = useSchemaOptionsContext();
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
const record = useCollectionRecord();
|
||||
|
||||
// 这里有点奇怪,在 Table 切换显示的组件时,这个组件并不会触发重新渲染,所以增加这个 Hooks 让其重新渲染
|
||||
useSchemaComponentContext();
|
||||
@ -71,7 +73,9 @@ export const AssociationFieldProvider = observer(
|
||||
if (_.isUndefined(ids) || _.isNil(ids) || _.isNaN(ids)) {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
if (record && !record.isNew) {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
return api.request({
|
||||
resource: collectionField.target,
|
||||
action: Array.isArray(ids) ? 'list' : 'get',
|
||||
|
@ -58,90 +58,98 @@ export const DatePicker = (props: any) => {
|
||||
}, [props._maxDate, props._minDate, localVariables, parseVariable]);
|
||||
|
||||
const limitDate = async () => {
|
||||
//dayjs()如果传入undefined可能会被解析成当前时间
|
||||
let minDateTimePromise = props._minDate ? Promise.resolve(dayjs(props._minDate)) : Promise.resolve(null);
|
||||
// 直接将 UTC 时间字符串转换成 dayjs 对象(注意不转成本地时间)
|
||||
let minDateTimePromise = props._minDate
|
||||
? Promise.resolve(dayjs(props._minDate)) // 保持 UTC 时间
|
||||
: Promise.resolve(null);
|
||||
let maxDateTimePromise = props._maxDate ? Promise.resolve(dayjs(props._maxDate)) : Promise.resolve(null);
|
||||
|
||||
if (isVariable(props._maxDate)) {
|
||||
maxDateTimePromise = parseVariable(props._maxDate, localVariables).then((result) => {
|
||||
console.log(dayjs(Array.isArray(result.value) ? last(result.value) : result.value));
|
||||
return dayjs(Array.isArray(result.value) ? last(result.value) : result.value);
|
||||
});
|
||||
}
|
||||
if (isVariable(props._minDate)) {
|
||||
minDateTimePromise = parseVariable(props._minDate, localVariables).then((result) => {
|
||||
return dayjs(Array.isArray(result.value) ? first(result.value) : result.value);
|
||||
});
|
||||
minDateTimePromise = parseVariable(props._minDate, localVariables).then((result) =>
|
||||
dayjs(Array.isArray(result.value) ? first(result.value) : result.value),
|
||||
);
|
||||
}
|
||||
|
||||
const [minDateTime, maxDateTime] = await Promise.all([minDateTimePromise, maxDateTimePromise]);
|
||||
|
||||
const fullTimeArr = Array.from({ length: 60 }, (_, i) => i);
|
||||
|
||||
// 根据最小日期和最大日期限定日期时间
|
||||
// disabledDate 只禁用日期,不要管时间部分
|
||||
const disabledDate = (current) => {
|
||||
if (!dayjs.isDayjs(current)) return false;
|
||||
|
||||
const currentDate = dayjs(current);
|
||||
const min = minDateTime ? dayjs(minDateTime) : null;
|
||||
const max = maxDateTime ? dayjs(maxDateTime).endOf('day') : null; // 设为 23:59:59
|
||||
// 把 current 转成本地时间(不加 .utc(),因为 current 就是本地时间)
|
||||
// 然后和 maxDateTime(同为本地时间)做比较
|
||||
const min = minDateTime ? minDateTime.startOf('day') : null;
|
||||
const max = maxDateTime ? maxDateTime.endOf('day') : null;
|
||||
|
||||
return (min && currentDate.isBefore(min, 'minute')) || (max && currentDate.isAfter(max, 'minute'));
|
||||
return (min && current.isBefore(min, 'day')) || (max && current.isAfter(max, 'day'));
|
||||
};
|
||||
|
||||
// 禁用时分秒
|
||||
const disabledTime = (current) => {
|
||||
if (!current || (!minDateTime && !maxDateTime)) {
|
||||
return { disabledHours: () => [], disabledMinutes: () => [], disabledSeconds: () => [] };
|
||||
}
|
||||
|
||||
const currentDate = dayjs(current);
|
||||
const isCurrentMinDay = currentDate.isSame(minDateTime, 'day');
|
||||
const isCurrentMaxDay = currentDate.isSame(maxDateTime, 'day');
|
||||
// current 是本地时间,转成 UTC 时间
|
||||
const currentUtc = current.utc();
|
||||
|
||||
// 判断是不是 minDate 和 maxDate 的同一天(UTC)
|
||||
const isCurrentMinDay = minDateTime && currentUtc.isSame(minDateTime, 'day');
|
||||
const isCurrentMaxDay = maxDateTime && currentUtc.isSame(maxDateTime, 'day');
|
||||
|
||||
const disabledHours = () => {
|
||||
const hours = [];
|
||||
if (isCurrentMinDay) {
|
||||
hours.push(...Array.from({ length: minDateTime.hour() }, (_, i) => i));
|
||||
for (let h = 0; h < minDateTime.hour(); h++) {
|
||||
hours.push(h);
|
||||
}
|
||||
}
|
||||
if (isCurrentMaxDay) {
|
||||
hours.push(...Array.from({ length: 24 - maxDateTime.hour() }, (_, i) => i + maxDateTime.hour() + 1));
|
||||
for (let h = maxDateTime.hour() + 1; h < 24; h++) {
|
||||
hours.push(h);
|
||||
}
|
||||
}
|
||||
return hours;
|
||||
};
|
||||
|
||||
const getDisabledMinutes = (selectedHour: number) => {
|
||||
const disabledMinutes = (selectedHour) => {
|
||||
if (isCurrentMinDay && selectedHour === minDateTime.hour()) {
|
||||
return fullTimeArr.filter((i) => i < minDateTime.minute());
|
||||
return fullTimeArr.filter((m) => m < minDateTime.minute());
|
||||
}
|
||||
if (isCurrentMaxDay && selectedHour === maxDateTime.hour()) {
|
||||
return fullTimeArr.filter((i) => i > maxDateTime.minute());
|
||||
return fullTimeArr.filter((m) => m > maxDateTime.minute());
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
const getDisabledSeconds = (selectedHour: number, selectedMinute: number) => {
|
||||
const disabledSeconds = (selectedHour, selectedMinute) => {
|
||||
if (isCurrentMinDay && selectedHour === minDateTime.hour() && selectedMinute === minDateTime.minute()) {
|
||||
return fullTimeArr.filter((i) => i < minDateTime.second());
|
||||
return fullTimeArr.filter((s) => s < minDateTime.second());
|
||||
}
|
||||
if (isCurrentMaxDay && selectedHour === maxDateTime.hour() && selectedMinute === maxDateTime.minute()) {
|
||||
return fullTimeArr.filter((i) => i > maxDateTime.second());
|
||||
return fullTimeArr.filter((s) => s > maxDateTime.second());
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
return {
|
||||
disabledHours,
|
||||
disabledMinutes: getDisabledMinutes,
|
||||
disabledSeconds: getDisabledSeconds,
|
||||
disabledMinutes,
|
||||
disabledSeconds,
|
||||
};
|
||||
};
|
||||
setDisabledDate(() => {
|
||||
return disabledDate;
|
||||
});
|
||||
setDisabledTime(() => {
|
||||
return disabledTime;
|
||||
});
|
||||
|
||||
setDisabledDate(() => disabledDate);
|
||||
setDisabledTime(() => disabledTime);
|
||||
};
|
||||
|
||||
const newProps = {
|
||||
utc,
|
||||
...props,
|
||||
|
@ -10,6 +10,7 @@
|
||||
import { getDefaultFormat, str2moment, toGmt, toLocal, getPickerFormat } from '@nocobase/utils/client';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import dayjs from 'dayjs';
|
||||
import { dayjsable, formatDayjsValue } from '@formily/antd-v5/esm/__builtins__';
|
||||
|
||||
const toStringByPicker = (value, picker = 'date', timezone: 'gmt' | 'local') => {
|
||||
if (!dayjs.isDayjs(value)) return value;
|
||||
@ -89,7 +90,7 @@ export const handleDateChangeOnForm = (value, dateOnly, utc, picker, showTime, g
|
||||
return value;
|
||||
}
|
||||
if (dateOnly) {
|
||||
return dayjs(value).startOf(picker).format('YYYY-MM-DD');
|
||||
return formatDayjsValue(value, 'YYYY-MM-DD');
|
||||
}
|
||||
if (utc) {
|
||||
if (gmt) {
|
||||
@ -114,6 +115,7 @@ export const mapDatePicker = function () {
|
||||
const { dateOnly, showTime, picker = 'date', utc, gmt, underFilter } = props;
|
||||
const format = getDefaultFormat(props);
|
||||
const onChange = props.onChange;
|
||||
|
||||
return {
|
||||
...props,
|
||||
inputReadOnly: isMobileMedia,
|
||||
|
@ -56,12 +56,13 @@ ReadPretty.Input = (props: InputReadPrettyProps) => {
|
||||
return props.value && typeof props.value === 'object' ? JSON.stringify(props.value) : compile(props.value);
|
||||
}, [props.value]);
|
||||
|
||||
const flexStyle = props.ellipsis ? { display: 'flex', alignItems: 'center' } : {};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cls(prefixCls, props.className)}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
...flexStyle,
|
||||
overflowWrap: 'break-word',
|
||||
whiteSpace: 'normal',
|
||||
...props.style,
|
||||
|
@ -48,11 +48,11 @@ const useStyles = genStyleHook('nb-list', (token) => {
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
'&:not(:first-child)': {
|
||||
paddingTop: token.paddingContentVertical,
|
||||
marginTop: token.paddingContentVertical,
|
||||
},
|
||||
|
||||
'&:not(:last-child)': {
|
||||
paddingBottom: token.paddingContentVertical,
|
||||
marginBottom: token.paddingContentVertical,
|
||||
borderBottom: `1px solid ${token.colorBorderSecondary}`,
|
||||
},
|
||||
},
|
||||
|
@ -244,7 +244,7 @@ function FinallyButton({
|
||||
inheritsCollections,
|
||||
linkageFromForm,
|
||||
allowAddToCurrent,
|
||||
props,
|
||||
props: { onlyIcon, ...props },
|
||||
componentType,
|
||||
menu,
|
||||
onClick,
|
||||
@ -362,7 +362,7 @@ function FinallyButton({
|
||||
...buttonStyle,
|
||||
}}
|
||||
>
|
||||
{props.onlyIcon ? props?.children?.[1] : props?.children}
|
||||
{onlyIcon ? props?.children?.[1] : props?.children}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
@ -10,8 +10,9 @@
|
||||
import { Field } from '@formily/core';
|
||||
import { useField, useFieldSchema } from '@formily/react';
|
||||
import { merge } from '@formily/shared';
|
||||
import _, { cloneDeep } from 'lodash';
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import _, { cloneDeepWith } from 'lodash';
|
||||
import React, { isValidElement, useCallback, useEffect, useMemo } from 'react';
|
||||
import { useBlockContext } from '../../../block-provider';
|
||||
import { useFormBlockContext } from '../../../block-provider/FormBlockProvider';
|
||||
import {
|
||||
useCollectionField_deprecated,
|
||||
@ -20,14 +21,13 @@ import {
|
||||
useCollection_deprecated,
|
||||
} from '../../../collection-manager';
|
||||
import { CollectionFieldProvider } from '../../../data-source';
|
||||
import { FlagProvider } from '../../../flag-provider';
|
||||
import { useRecord } from '../../../record-provider';
|
||||
import { useCompile, useComponent } from '../../../schema-component';
|
||||
import { VariableInput, getShouldChange } from '../../../schema-settings/VariableInput/VariableInput';
|
||||
import { Option } from '../../../schema-settings/VariableInput/type';
|
||||
import { formatVariableScop } from '../../../schema-settings/VariableInput/utils/formatVariableScop';
|
||||
import { useLocalVariables, useVariables } from '../../../variables';
|
||||
import { useBlockContext } from '../../../block-provider';
|
||||
import { FlagProvider } from '../../../flag-provider';
|
||||
interface AssignedFieldProps {
|
||||
value: any;
|
||||
onChange: (value: any) => void;
|
||||
@ -126,7 +126,14 @@ export const AssignedFieldInner = (props: AssignedFieldProps) => {
|
||||
currentForm.children = formatVariableScop(currentFormFields);
|
||||
}
|
||||
|
||||
return cloneDeep(scope);
|
||||
return cloneDeepWith(scope, (value) => {
|
||||
// 不对 `ReactElement` 进行深拷贝,因为会报错
|
||||
if (isValidElement(value)) {
|
||||
return value;
|
||||
}
|
||||
// 对于其他类型的对象,继续正常的深拷贝
|
||||
return undefined;
|
||||
});
|
||||
},
|
||||
[currentFormFields, name],
|
||||
);
|
||||
|
@ -64,7 +64,7 @@ export const SchemaSettingsDefaultValue = function DefaultValueConfigure(props:
|
||||
const localVariables = useLocalVariables();
|
||||
const collection = useCollection_deprecated();
|
||||
const record = useRecord();
|
||||
const { form } = useFormBlockContext();
|
||||
const { form, type } = useFormBlockContext();
|
||||
const { getFields } = useCollectionFilterOptionsV2(collection);
|
||||
const { isInSubForm, isInSubTable } = useFlag() || {};
|
||||
|
||||
@ -219,7 +219,6 @@ export const SchemaSettingsDefaultValue = function DefaultValueConfigure(props:
|
||||
targetField,
|
||||
variables,
|
||||
]);
|
||||
|
||||
const handleSubmit: (values: any) => void = useCallback(
|
||||
(v) => {
|
||||
const schema: ISchema = {
|
||||
@ -227,7 +226,7 @@ export const SchemaSettingsDefaultValue = function DefaultValueConfigure(props:
|
||||
};
|
||||
fieldSchema.default = v.default ?? null;
|
||||
if (!isVariable(v.default)) {
|
||||
field.setInitialValue?.(v.default);
|
||||
(record.__isNewRecord__ || type === 'create') && field.setInitialValue?.(v.default);
|
||||
}
|
||||
schema.default = v.default ?? null;
|
||||
dn.emit('patch', {
|
||||
|
@ -13,7 +13,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useBlockContext } from '../../../block-provider';
|
||||
import { useFormBlockContext } from '../../../block-provider/FormBlockProvider';
|
||||
import { CollectionFieldOptions_deprecated } from '../../../collection-manager';
|
||||
import { useDataBlockRequestData, useDataSource } from '../../../data-source';
|
||||
import { useCollection, useDataSource } from '../../../data-source';
|
||||
import { useFlag } from '../../../flag-provider/hooks/useFlag';
|
||||
import { useBaseVariable } from './useBaseVariable';
|
||||
|
||||
@ -100,6 +100,7 @@ export const useCurrentFormVariable = ({
|
||||
const { currentFormCtx, shouldDisplayCurrentForm } = useCurrentFormContext({ form: _form });
|
||||
const { t } = useTranslation();
|
||||
const { collectionName } = useFormBlockContext();
|
||||
const collection = useCollection();
|
||||
const dataSource = useDataSource();
|
||||
const currentFormSettings = useBaseVariable({
|
||||
collectionField,
|
||||
@ -108,7 +109,7 @@ export const useCurrentFormVariable = ({
|
||||
maxDepth: 4,
|
||||
name: '$nForm',
|
||||
title: t('Current form'),
|
||||
collectionName: collectionName,
|
||||
collectionName: collectionName || collection?.name,
|
||||
noDisabled,
|
||||
dataSource: dataSource?.key,
|
||||
returnFields: (fields, option) => {
|
||||
|
@ -53,7 +53,11 @@ const useLocalVariables = (props?: Props) => {
|
||||
dataSource: parentPopupDataSource,
|
||||
defaultValue: defaultValueOfParentPopupRecord,
|
||||
} = useParentPopupVariableContext();
|
||||
const { urlSearchParamsCtx, shouldDisplay: shouldDisplayURLSearchParams } = useURLSearchParamsVariable();
|
||||
const {
|
||||
urlSearchParamsCtx,
|
||||
shouldDisplay: shouldDisplayURLSearchParams,
|
||||
defaultValue: defaultValueOfURLSearchParams,
|
||||
} = useURLSearchParamsVariable();
|
||||
const { datetimeCtx } = useDatetimeVariableContext();
|
||||
const { currentFormCtx } = useCurrentFormContext({ form: props?.currentForm });
|
||||
const { name: currentCollectionName } = useCollection_deprecated();
|
||||
@ -151,6 +155,7 @@ const useLocalVariables = (props?: Props) => {
|
||||
shouldDisplayURLSearchParams && {
|
||||
name: '$nURLSearchParams',
|
||||
ctx: urlSearchParamsCtx,
|
||||
defaultValue: defaultValueOfURLSearchParams,
|
||||
},
|
||||
] as VariableOption[]
|
||||
).filter(Boolean);
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-nocobase-app",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "src/index.js",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
|
@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "@nocobase/data-source-manager",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"dependencies": {
|
||||
"@nocobase/actions": "1.7.14",
|
||||
"@nocobase/cache": "1.7.14",
|
||||
"@nocobase/database": "1.7.14",
|
||||
"@nocobase/resourcer": "1.7.14",
|
||||
"@nocobase/utils": "1.7.14",
|
||||
"@nocobase/actions": "1.7.18",
|
||||
"@nocobase/cache": "1.7.18",
|
||||
"@nocobase/database": "1.7.18",
|
||||
"@nocobase/resourcer": "1.7.18",
|
||||
"@nocobase/utils": "1.7.18",
|
||||
"@types/jsonwebtoken": "^8.5.8",
|
||||
"jsonwebtoken": "^9.0.2"
|
||||
},
|
||||
|
@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@nocobase/database",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@nocobase/logger": "1.7.14",
|
||||
"@nocobase/utils": "1.7.14",
|
||||
"@nocobase/logger": "1.7.18",
|
||||
"@nocobase/utils": "1.7.18",
|
||||
"async-mutex": "^0.3.2",
|
||||
"chalk": "^4.1.1",
|
||||
"cron-parser": "4.4.0",
|
||||
|
@ -40,4 +40,25 @@ describe('password field', () => {
|
||||
user = await User.model.findOne();
|
||||
expect(await pwd.verify('654321', user.password)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should be encrypted when adding password fields in batches', async () => {
|
||||
const User = db.collection({
|
||||
name: 'users',
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
{ type: 'password', name: 'password' },
|
||||
],
|
||||
});
|
||||
await db.sync();
|
||||
const instances = await User.model.bulkCreate([
|
||||
{
|
||||
password: '123456',
|
||||
name: 'zhangsan',
|
||||
},
|
||||
]);
|
||||
const pwd = User.getField<PasswordField>('password');
|
||||
expect(await pwd.verify('123456', instances[0].password)).toBeTruthy();
|
||||
const user = await User.model.findOne({ where: { name: 'zhangsan' } });
|
||||
expect(await pwd.verify('123456', user.password)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
40
packages/core/database/src/__tests__/helpers.test.ts
Normal file
40
packages/core/database/src/__tests__/helpers.test.ts
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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 { parseDatabaseOptionsFromEnv } from '@nocobase/database';
|
||||
|
||||
describe('database helpers', () => {
|
||||
describe('parseDatabaseOptionsFromEnv()', () => {
|
||||
it('undefined pool options', async () => {
|
||||
const options1 = await parseDatabaseOptionsFromEnv();
|
||||
expect(options1).toMatchObject({
|
||||
pool: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('custom pool options', async () => {
|
||||
process.env.DB_POOL_MAX = '10';
|
||||
process.env.DB_POOL_MIN = '1';
|
||||
process.env.DB_POOL_IDLE = '5000';
|
||||
process.env.DB_POOL_ACQUIRE = '30000';
|
||||
process.env.DB_POOL_EVICT = '2000';
|
||||
process.env.DB_POOL_MAX_USES = '0'; // Set to 0 to test default behavior
|
||||
|
||||
const options2 = await parseDatabaseOptionsFromEnv();
|
||||
expect(options2.pool).toMatchObject({
|
||||
max: 10,
|
||||
min: 1,
|
||||
idle: 5000,
|
||||
acquire: 30000,
|
||||
evict: 2000,
|
||||
maxUses: Number.POSITIVE_INFINITY, // Default value
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -56,16 +56,19 @@ export class PasswordField extends Field {
|
||||
|
||||
init() {
|
||||
const { name } = this.options;
|
||||
this.listener = async (model: Model) => {
|
||||
if (!model.changed(name as any)) {
|
||||
return;
|
||||
}
|
||||
const value = model.get(name) as string;
|
||||
if (value) {
|
||||
const hash = await this.hash(value);
|
||||
model.set(name, hash);
|
||||
} else {
|
||||
model.set(name, model.previous(name));
|
||||
this.listener = async (instances: Model[]) => {
|
||||
instances = Array.isArray(instances) ? instances : [instances];
|
||||
for (const instance of instances) {
|
||||
if (!instance.changed(name as any)) {
|
||||
continue;
|
||||
}
|
||||
const value = instance.get(name) as string;
|
||||
if (value) {
|
||||
const hash = await this.hash(value);
|
||||
instance.set(name, hash);
|
||||
} else {
|
||||
instance.set(name, instance.previous(name));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -73,12 +76,14 @@ export class PasswordField extends Field {
|
||||
bind() {
|
||||
super.bind();
|
||||
this.on('beforeCreate', this.listener);
|
||||
this.on('beforeBulkCreate', this.listener);
|
||||
this.on('beforeUpdate', this.listener);
|
||||
}
|
||||
|
||||
unbind() {
|
||||
super.unbind();
|
||||
this.off('beforeCreate', this.listener);
|
||||
this.off('beforeBulkCreate', this.listener);
|
||||
this.off('beforeUpdate', this.listener);
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import { MysqlDialect } from './dialects/mysql-dialect';
|
||||
import { SqliteDialect } from './dialects/sqlite-dialect';
|
||||
import { MariadbDialect } from './dialects/mariadb-dialect';
|
||||
import { PostgresDialect } from './dialects/postgres-dialect';
|
||||
import { PoolOptions } from 'sequelize';
|
||||
|
||||
function getEnvValue(key, defaultValue?) {
|
||||
return process.env[key] || defaultValue;
|
||||
@ -73,6 +74,29 @@ function extractSSLOptionsFromEnv() {
|
||||
});
|
||||
}
|
||||
|
||||
function getPoolOptions(): PoolOptions {
|
||||
const options: PoolOptions = {};
|
||||
if (process.env.DB_POOL_MAX) {
|
||||
options.max = Number.parseInt(process.env.DB_POOL_MAX, 10);
|
||||
}
|
||||
if (process.env.DB_POOL_MIN) {
|
||||
options.min = Number.parseInt(process.env.DB_POOL_MIN, 10);
|
||||
}
|
||||
if (process.env.DB_POOL_IDLE) {
|
||||
options.idle = Number.parseInt(process.env.DB_POOL_IDLE, 10);
|
||||
}
|
||||
if (process.env.DB_POOL_ACQUIRE) {
|
||||
options.acquire = Number.parseInt(process.env.DB_POOL_ACQUIRE, 10);
|
||||
}
|
||||
if (process.env.DB_POOL_EVICT) {
|
||||
options.evict = Number.parseInt(process.env.DB_POOL_EVICT, 10);
|
||||
}
|
||||
if (process.env.DB_POOL_MAX_USES) {
|
||||
options.maxUses = Number.parseInt(process.env.DB_POOL_MAX_USES, 10) || Number.POSITIVE_INFINITY;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
export async function parseDatabaseOptionsFromEnv(): Promise<IDatabaseOptions> {
|
||||
const databaseOptions: IDatabaseOptions = {
|
||||
logging: process.env.DB_LOGGING == 'on' ? customLogger : false,
|
||||
@ -87,6 +111,7 @@ export async function parseDatabaseOptionsFromEnv(): Promise<IDatabaseOptions> {
|
||||
tablePrefix: process.env.DB_TABLE_PREFIX,
|
||||
schema: process.env.DB_SCHEMA,
|
||||
underscored: process.env.DB_UNDERSCORED === 'true',
|
||||
pool: getPoolOptions(),
|
||||
};
|
||||
|
||||
const sslOptions = await extractSSLOptionsFromEnv();
|
||||
|
@ -33,7 +33,7 @@ const toDate = (date, options: any = {}) => {
|
||||
}
|
||||
|
||||
if (field.constructor.name === 'DateOnlyField') {
|
||||
val = moment(val).format('YYYY-MM-DD HH:mm:ss');
|
||||
val = moment.utc(val).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
|
||||
const eventObj = {
|
||||
@ -69,7 +69,6 @@ export default {
|
||||
const r = parseDate(value, {
|
||||
timezone: parseDateTimezone(ctx),
|
||||
});
|
||||
|
||||
if (typeof r === 'string') {
|
||||
return {
|
||||
[Op.eq]: toDate(r, { ctx }),
|
||||
@ -77,6 +76,9 @@ export default {
|
||||
}
|
||||
|
||||
if (Array.isArray(r)) {
|
||||
console.log(11111111, {
|
||||
[Op.and]: [{ [Op.gte]: toDate(r[0], { ctx }) }, { [Op.lt]: toDate(r[1], { ctx }) }],
|
||||
});
|
||||
return {
|
||||
[Op.and]: [{ [Op.gte]: toDate(r[0], { ctx }) }, { [Op.lt]: toDate(r[1], { ctx }) }],
|
||||
};
|
||||
|
@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@nocobase/devtools",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./src/index.js",
|
||||
"dependencies": {
|
||||
"@nocobase/build": "1.7.14",
|
||||
"@nocobase/client": "1.7.14",
|
||||
"@nocobase/test": "1.7.14",
|
||||
"@nocobase/build": "1.7.18",
|
||||
"@nocobase/client": "1.7.18",
|
||||
"@nocobase/test": "1.7.18",
|
||||
"@types/koa": "^2.15.0",
|
||||
"@types/koa-bodyparser": "^4.3.4",
|
||||
"@types/lodash": "^4.14.177",
|
||||
|
@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@nocobase/evaluators",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@formulajs/formulajs": "4.4.9",
|
||||
"@nocobase/utils": "1.7.14",
|
||||
"@nocobase/utils": "1.7.18",
|
||||
"mathjs": "^10.6.0"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "@nocobase/lock-manager",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "lib/index.js",
|
||||
"license": "AGPL-3.0",
|
||||
"devDependencies": {
|
||||
"@nocobase/utils": "1.7.14",
|
||||
"@nocobase/utils": "1.7.18",
|
||||
"async-mutex": "^0.5.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/logger",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "nocobase logging library",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./lib/index.js",
|
||||
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@nocobase/resourcer",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@nocobase/utils": "1.7.14",
|
||||
"@nocobase/utils": "1.7.18",
|
||||
"deepmerge": "^4.2.2",
|
||||
"koa-compose": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/sdk",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/server",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"license": "AGPL-3.0",
|
||||
@ -10,19 +10,19 @@
|
||||
"@koa/cors": "^5.0.0",
|
||||
"@koa/multer": "^3.1.0",
|
||||
"@koa/router": "^13.1.0",
|
||||
"@nocobase/acl": "1.7.14",
|
||||
"@nocobase/actions": "1.7.14",
|
||||
"@nocobase/auth": "1.7.14",
|
||||
"@nocobase/cache": "1.7.14",
|
||||
"@nocobase/data-source-manager": "1.7.14",
|
||||
"@nocobase/database": "1.7.14",
|
||||
"@nocobase/evaluators": "1.7.14",
|
||||
"@nocobase/lock-manager": "1.7.14",
|
||||
"@nocobase/logger": "1.7.14",
|
||||
"@nocobase/resourcer": "1.7.14",
|
||||
"@nocobase/sdk": "1.7.14",
|
||||
"@nocobase/telemetry": "1.7.14",
|
||||
"@nocobase/utils": "1.7.14",
|
||||
"@nocobase/acl": "1.7.18",
|
||||
"@nocobase/actions": "1.7.18",
|
||||
"@nocobase/auth": "1.7.18",
|
||||
"@nocobase/cache": "1.7.18",
|
||||
"@nocobase/data-source-manager": "1.7.18",
|
||||
"@nocobase/database": "1.7.18",
|
||||
"@nocobase/evaluators": "1.7.18",
|
||||
"@nocobase/lock-manager": "1.7.18",
|
||||
"@nocobase/logger": "1.7.18",
|
||||
"@nocobase/resourcer": "1.7.18",
|
||||
"@nocobase/sdk": "1.7.18",
|
||||
"@nocobase/telemetry": "1.7.18",
|
||||
"@nocobase/utils": "1.7.18",
|
||||
"@types/decompress": "4.2.7",
|
||||
"@types/ini": "^1.3.31",
|
||||
"@types/koa-send": "^4.1.3",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/telemetry",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"description": "nocobase telemetry library",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./lib/index.js",
|
||||
@ -11,7 +11,7 @@
|
||||
"directory": "packages/telemetry"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nocobase/utils": "1.7.14",
|
||||
"@nocobase/utils": "1.7.18",
|
||||
"@opentelemetry/api": "^1.7.0",
|
||||
"@opentelemetry/instrumentation": "^0.46.0",
|
||||
"@opentelemetry/resources": "^1.19.0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/test",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "lib/index.js",
|
||||
"module": "./src/index.ts",
|
||||
"types": "./lib/index.d.ts",
|
||||
@ -51,7 +51,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@faker-js/faker": "8.1.0",
|
||||
"@nocobase/server": "1.7.14",
|
||||
"@nocobase/server": "1.7.18",
|
||||
"@playwright/test": "^1.45.3",
|
||||
"@testing-library/jest-dom": "^6.4.2",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/utils",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"license": "AGPL-3.0",
|
||||
|
@ -15,6 +15,7 @@ export interface Str2momentOptions {
|
||||
picker?: 'year' | 'month' | 'week' | 'quarter';
|
||||
utcOffset?: number;
|
||||
utc?: boolean;
|
||||
dateOnly?: boolean;
|
||||
}
|
||||
|
||||
export type Str2momentValue = string | string[] | dayjs.Dayjs | dayjs.Dayjs[];
|
||||
@ -83,10 +84,14 @@ const toMoment = (val: any, options?: Str2momentOptions) => {
|
||||
return;
|
||||
}
|
||||
const offset = options.utcOffset;
|
||||
const { gmt, picker, utc = true } = options;
|
||||
const { gmt, picker, utc = true, dateOnly } = options;
|
||||
|
||||
if (dayjs(val).isValid()) {
|
||||
if (dateOnly) {
|
||||
return dayjs.utc(val, 'YYYY-MM-DD');
|
||||
}
|
||||
if (!utc) {
|
||||
return dayjs(val);
|
||||
return dayjs.utc(val);
|
||||
}
|
||||
|
||||
if (dayjs.isDayjs(val)) {
|
||||
|
@ -188,9 +188,11 @@ export const parseFilter = async (filter: any, opts: ParseFilterOptions = {}) =>
|
||||
const field = getField?.(path);
|
||||
|
||||
if (field?.constructor.name === 'DateOnlyField' || field?.constructor.name === 'DatetimeNoTzField') {
|
||||
if (value.type) {
|
||||
return getDayRangeByParams({ ...value, timezone: field?.timezone || timezone });
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
return dateValueWrapper(value, field?.timezone || timezone);
|
||||
}
|
||||
return value;
|
||||
|
@ -4,7 +4,7 @@
|
||||
"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.zh-CN": "基于角色、资源和操作的权限控制,可以精确控制界面配置权限、数据操作权限、菜单访问权限、插件权限。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/acl",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-action-bulk-edit",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"homepage": "https://docs.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",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/action-bulk-update",
|
||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-bulk-update",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-action-custom-request",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/action-custom-request",
|
||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-custom-request",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-action-duplicate",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/action-duplicate",
|
||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-duplicate",
|
||||
|
@ -84,8 +84,8 @@ export const actionDesignerCss = css`
|
||||
`;
|
||||
|
||||
export const DuplicateAction = observer(
|
||||
(props: any) => {
|
||||
const { children, onlyIcon, icon, title, ...others } = props;
|
||||
({ onlyIcon, ...props }: any) => {
|
||||
const { children, icon, title, ...others } = props;
|
||||
const { message } = App.useApp();
|
||||
const field = useField();
|
||||
const fieldSchema = useFieldSchema();
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "操作:导出记录",
|
||||
"description": "Export filtered records to excel, you can configure which fields to export.",
|
||||
"description.zh-CN": "导出筛选后的记录到 Excel 中,可以配置导出哪些字段。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/action-export",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "操作:导入记录",
|
||||
"description": "Import records using excel templates. You can configure which fields to import and templates will be generated automatically.",
|
||||
"description.zh-CN": "使用 Excel 模板导入数据,可以配置导入哪些字段,自动生成模板。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/action-import",
|
||||
|
@ -13,6 +13,7 @@ import { XlsxImporter } from '../services/xlsx-importer';
|
||||
import XLSX from 'xlsx';
|
||||
import * as process from 'node:process';
|
||||
import moment from 'moment';
|
||||
import { PasswordField } from '@nocobase/database';
|
||||
|
||||
describe('xlsx importer', () => {
|
||||
let app: MockServer;
|
||||
@ -2322,4 +2323,57 @@ describe('xlsx importer', () => {
|
||||
|
||||
expect(importer.run()).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('should import password field, insert data is encrypt', async () => {
|
||||
const User = app.db.collection({
|
||||
name: 'users',
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
{ type: 'password', name: 'password' },
|
||||
],
|
||||
});
|
||||
await app.db.sync();
|
||||
const templateCreator = new TemplateCreator({
|
||||
collection: User,
|
||||
columns: [
|
||||
{
|
||||
dataIndex: ['name'],
|
||||
defaultTitle: '姓名',
|
||||
},
|
||||
{
|
||||
dataIndex: ['password'],
|
||||
defaultTitle: '密码',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const template = (await templateCreator.run({ returnXLSXWorkbook: true })) as XLSX.WorkBook;
|
||||
const worksheet = template.Sheets[template.SheetNames[0]];
|
||||
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [['zhangsan', '123456']], {
|
||||
origin: 'A2',
|
||||
});
|
||||
|
||||
const importer = new XlsxImporter({
|
||||
collectionManager: app.mainDataSource.collectionManager,
|
||||
collection: User,
|
||||
columns: [
|
||||
{
|
||||
dataIndex: ['name'],
|
||||
defaultTitle: '姓名',
|
||||
},
|
||||
{
|
||||
dataIndex: ['password'],
|
||||
defaultTitle: '密码',
|
||||
},
|
||||
],
|
||||
workbook: template,
|
||||
});
|
||||
|
||||
await importer.run();
|
||||
|
||||
const pwd = User.getField<PasswordField>('password');
|
||||
const user = await User.model.findOne({ where: { name: 'zhangsan' } });
|
||||
expect(await pwd.verify('123456', user.password)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-action-print",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/action-print",
|
||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-print",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "AI 集成",
|
||||
"description": "Support integration with AI services, providing AI-related workflow nodes to enhance business processing capabilities.",
|
||||
"description.zh-CN": "支持接入 AI 服务,提供 AI 相关的工作流节点,增强业务处理能力。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"peerDependencies": {
|
||||
"@nocobase/client": "1.x",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-api-doc",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"displayName": "API documentation",
|
||||
"displayName.zh-CN": "API 文档",
|
||||
"description": "An OpenAPI documentation generator for NocoBase HTTP API.",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "认证:API 密钥",
|
||||
"description": "Allows users to use API key to access application's HTTP API",
|
||||
"description.zh-CN": "允许用户使用 API 密钥访问应用的 HTTP API",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/api-keys",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "异步任务管理器",
|
||||
"description": "Manage and monitor asynchronous tasks such as data import/export. Support task progress tracking and notification.",
|
||||
"description.zh-CN": "管理和监控数据导入导出等异步任务。支持任务进度跟踪和通知。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"peerDependencies": {
|
||||
"@nocobase/client": "1.x",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-audit-logs",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"displayName": "Audit logs (deprecated)",
|
||||
"displayName.zh-CN": "审计日志(废弃)",
|
||||
"description": "This plugin is deprecated. There will be a new audit log plugin in the future.",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "认证:短信",
|
||||
"description": "SMS authentication.",
|
||||
"description.zh-CN": "通过短信验证码认证身份。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/auth-sms",
|
||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth-sms",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-auth",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/auth",
|
||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "应用的备份与还原(废弃)",
|
||||
"description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.",
|
||||
"description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/backup-restore",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "区块:iframe",
|
||||
"description": "Create an iframe block on the page to embed and display external web pages or content.",
|
||||
"description.zh-CN": "在页面上创建和管理iframe,用于嵌入和展示外部网页或内容。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/block-iframe",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "区块:模板",
|
||||
"description": "Create and manage block templates for reuse on pages.",
|
||||
"description.zh-CN": "创建和管理区块模板,用于在页面中重复使用。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/block-template",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-block-workbench",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"displayName": "Block: Action panel",
|
||||
"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.",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-calendar",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"displayName": "Calendar",
|
||||
"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.",
|
||||
|
@ -47,8 +47,9 @@ import useStyle from './style';
|
||||
import type { ToolbarProps } from './types';
|
||||
import { formatDate } from './utils';
|
||||
import updateLocale from 'dayjs/plugin/updateLocale';
|
||||
|
||||
dayjs.extend(updateLocale);
|
||||
import { dateFnsLocalizer } from 'react-big-calendar';
|
||||
import { format, parse, startOfWeek, getDay } from 'date-fns';
|
||||
import enUS from 'date-fns/locale/en-US';
|
||||
|
||||
interface Event {
|
||||
id: string;
|
||||
@ -268,12 +269,16 @@ export const Calendar: any = withDynamicSchemaProps(
|
||||
);
|
||||
|
||||
const localizer = useMemo(() => {
|
||||
dayjs.updateLocale('en', {
|
||||
weekStart: props.weekStart ?? '1',
|
||||
return dateFnsLocalizer({
|
||||
format,
|
||||
parse,
|
||||
startOfWeek: (date) => {
|
||||
return startOfWeek(date, { locale: { options: { weekStartsOn: props.weekStart } } });
|
||||
},
|
||||
getDay,
|
||||
locales: { 'en-US': enUS },
|
||||
});
|
||||
return reactBigCalendar.dayjsLocalizer(dayjs);
|
||||
}, [reactBigCalendar]);
|
||||
|
||||
}, [props.weekStart]);
|
||||
// 新版 UISchema(1.0 之后)中已经废弃了 useProps,这里之所以继续保留是为了兼容旧版的 UISchema
|
||||
const { dataSource, fieldNames, showLunar, getFontColor, getBackgroundColor, enableQuickCreateEvent } =
|
||||
useProps(props);
|
||||
@ -455,14 +460,14 @@ export const Calendar: any = withDynamicSchemaProps(
|
||||
});
|
||||
}}
|
||||
formats={{
|
||||
monthHeaderFormat: 'YYYY-M',
|
||||
agendaDateFormat: 'M-DD',
|
||||
dayHeaderFormat: 'YYYY-M-DD',
|
||||
monthHeaderFormat: 'yyyy-M',
|
||||
agendaDateFormat: 'M-dd',
|
||||
dayHeaderFormat: 'yyyy-M-dd',
|
||||
dayRangeHeaderFormat: ({ start, end }, culture, local) => {
|
||||
if (eq(start, end, 'month')) {
|
||||
return local.format(start, 'YYYY-M', culture);
|
||||
return local.format(start, 'yyyy-M', culture);
|
||||
}
|
||||
return `${local.format(start, 'YYYY-M', culture)} - ${local.format(end, 'YYYY-M', culture)}`;
|
||||
return `${local.format(start, 'yyyy-M', culture)} - ${local.format(end, 'yyyy-M', culture)}`;
|
||||
},
|
||||
}}
|
||||
components={components}
|
||||
|
@ -277,11 +277,11 @@ export const calendarBlockSettings = new SchemaSettings({
|
||||
const { name } = useCollection();
|
||||
const app = useApp();
|
||||
const plugin = app.pm.get('calendar') as any;
|
||||
const { dateTimeFields } = plugin;
|
||||
const { dateTimeFieldInterfaces } = plugin;
|
||||
return {
|
||||
title: t('Start date field'),
|
||||
value: fieldNames.start,
|
||||
options: getCollectionFieldsOptions(name, null, dateTimeFields, {
|
||||
options: getCollectionFieldsOptions(name, null, dateTimeFieldInterfaces, {
|
||||
association: ['o2o', 'obo', 'oho', 'm2o'],
|
||||
}),
|
||||
onChange: (start) => {
|
||||
@ -315,11 +315,11 @@ export const calendarBlockSettings = new SchemaSettings({
|
||||
const fieldNames = fieldSchema?.['x-decorator-props']?.['fieldNames'] || {};
|
||||
const app = useApp();
|
||||
const plugin = app.pm.get('calendar') as any;
|
||||
const { dateTimeFields } = plugin;
|
||||
const { dateTimeFieldInterfaces } = plugin;
|
||||
return {
|
||||
title: t('End date field'),
|
||||
value: fieldNames.end,
|
||||
options: getCollectionFieldsOptions(name, null, dateTimeFields, {
|
||||
options: getCollectionFieldsOptions(name, null, dateTimeFieldInterfaces, {
|
||||
association: ['o2o', 'obo', 'oho', 'm2o'],
|
||||
}),
|
||||
onChange: (end) => {
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "图表(废弃)",
|
||||
"description": "The plugin has been deprecated, please use the data visualization plugin instead.",
|
||||
"description.zh-CN": "已废弃插件,请使用数据可视化插件代替。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "./dist/server/index.js",
|
||||
"license": "AGPL-3.0",
|
||||
"devDependencies": {
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "WEB 客户端",
|
||||
"description": "Provides a client interface for the NocoBase server",
|
||||
"description.zh-CN": "为 NocoBase 服务端提供客户端界面",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "./dist/server/index.js",
|
||||
"license": "AGPL-3.0",
|
||||
"devDependencies": {
|
||||
|
@ -7,7 +7,7 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { Model, Transaction } from '@nocobase/database';
|
||||
import { Model, MultipleRelationRepository, Transaction } from '@nocobase/database';
|
||||
import PluginLocalizationServer from '@nocobase/plugin-localization';
|
||||
import { Plugin } from '@nocobase/server';
|
||||
import { tval } from '@nocobase/utils';
|
||||
@ -34,7 +34,7 @@ async function getLang(ctx) {
|
||||
}
|
||||
|
||||
export class PluginClientServer extends Plugin {
|
||||
async beforeLoad() {}
|
||||
async beforeLoad() { }
|
||||
|
||||
async install() {
|
||||
const uiSchemas = this.db.getRepository<any>('uiSchemas');
|
||||
@ -216,7 +216,7 @@ export class PluginClientServer extends Plugin {
|
||||
const tabIds = tabs.map((x) => x.get('id'));
|
||||
const where = { desktopRouteId: tabIds, roleName };
|
||||
if (action === 'create') {
|
||||
const exists = await repository.find({ where });
|
||||
const exists = await repository.find({ where, transaction });
|
||||
const modelsByRouteId = _.keyBy(exists, (x) => x.get('desktopRouteId'));
|
||||
const createModels = tabs
|
||||
.map((x) => !modelsByRouteId[x.get('id')] && { desktopRouteId: x.get('id'), roleName })
|
||||
@ -282,6 +282,27 @@ export class PluginClientServer extends Plugin {
|
||||
|
||||
await next();
|
||||
});
|
||||
|
||||
this.app.resourceManager.registerActionHandler('roles.desktopRoutes:set', async (ctx, next) => {
|
||||
let { values } = ctx.action.params;
|
||||
if (values.length) {
|
||||
const instances = await this.app.db.getRepository('desktopRoutes').find({
|
||||
filter: {
|
||||
$or: [
|
||||
{ id: { $in: values } },
|
||||
{ parentId: { $in: values } }
|
||||
]
|
||||
}
|
||||
});
|
||||
values = instances.map((instance) => instance.get('id'));
|
||||
};
|
||||
const { resourceName, sourceId } = ctx.action;
|
||||
const repository = this.app.db.getRepository<MultipleRelationRepository>(resourceName, sourceId)
|
||||
await repository['set'](values);
|
||||
|
||||
ctx.status = 200;
|
||||
await next();
|
||||
});
|
||||
}
|
||||
|
||||
registerLocalizationSource() {
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "数据表: SQL",
|
||||
"description": "Provides SQL collection template",
|
||||
"description.zh-CN": "提供 SQL 数据表模板",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"homepage": "https://docs-cn.nocobase.com/handbook/collection-sql",
|
||||
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/collection-sql",
|
||||
"main": "dist/server/index.js",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-collection-tree",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"displayName": "Collection: Tree",
|
||||
"displayName.zh-CN": "数据表:树",
|
||||
"description": "Provides tree collection template",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "数据源:主数据库",
|
||||
"description": "NocoBase main database, supports relational databases such as PostgreSQL, MySQL, MariaDB and so on.",
|
||||
"description.zh-CN": "NocoBase 主数据库,支持 PostgreSQL、MySQL、MariaDB 等关系型数据库。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.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",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"displayName": "Data source manager",
|
||||
"displayName.zh-CN": "数据源管理",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-data-visualization",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"displayName": "Data visualization",
|
||||
"displayName.zh-CN": "数据可视化",
|
||||
"description": "Provides data visualization feature, including chart block and chart filter block, support line charts, area charts, bar charts and more than a dozen kinds of charts, you can also extend more chart types.",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "部门",
|
||||
"description": "Organize users by departments, set hierarchical relationships, link roles to control permissions, and use departments as variables in workflows and expressions.",
|
||||
"description.zh-CN": "以部门来组织用户,设定上下级关系,绑定角色控制权限,并支持作为变量用于工作流和表达式。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"peerDependencies": {
|
||||
"@nocobase/actions": "1.x",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-disable-pm-add",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "./dist/server/index.js",
|
||||
"peerDependencies": {
|
||||
"@nocobase/client": "1.x",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-environment-variables",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"peerDependencies": {
|
||||
"@nocobase/client": "1.x",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "错误处理器",
|
||||
"description": "Handling application errors and exceptions.",
|
||||
"description.zh-CN": "处理应用程序中的错误和异常。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
"devDependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-field-attachment-url",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"displayName": "Collection field: Attachment(URL)",
|
||||
"displayName.zh-CN": "数据表字段:附件(URL)",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-field-china-region",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"displayName": "Collection field: administrative divisions of China",
|
||||
"displayName.zh-CN": "数据表字段:中国行政区划",
|
||||
"description": "Provides data and field type for administrative divisions of China.",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "数据表字段:公式",
|
||||
"description": "Configure and store the results of calculations between multiple field values in the same record, supporting both Math.js and Excel formula functions.",
|
||||
"description.zh-CN": "可以配置并存储同一条记录的多字段值之间的计算结果,支持 Math.js 和 Excel formula functions 两种引擎",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/field-formula",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "数据表字段:多对多 (数组)",
|
||||
"description": "Allows to create many to many relationships between two models by storing an array of unique keys of the target model.",
|
||||
"description.zh-CN": "支持通过在数组中存储目标表唯一键的方式建立多对多关系。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"main": "dist/server/index.js",
|
||||
"peerDependencies": {
|
||||
"@nocobase/client": "1.x",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "数据表字段:Markdown(Vditor)",
|
||||
"description": "Used to store Markdown and render it using Vditor editor, supports common Markdown syntax such as list, code, quote, etc., and supports uploading images, recordings, etc.It also allows for instant rendering, where what you see is what you get.",
|
||||
"description.zh-CN": "用于存储 Markdown,并使用 Vditor 编辑器渲染,支持常见 Markdown 语法,如列表,代码,引用等,并支持上传图片,录音等。同时可以做到即时渲染,所见即所得。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/field-markdown-vditor",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "数据表字段:自动编码",
|
||||
"description": "Automatically generate codes based on configured rules, supporting combinations of dates, numbers, and text.",
|
||||
"description.zh-CN": "根据配置的规则自动生成编码,支持日期、数字、文本的组合。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/field-sequence",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-field-sort",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"displayName": "Collection field: Sort",
|
||||
"displayName.zh-CN": "数据表字段:排序",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-file-manager",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"displayName": "File manager",
|
||||
"displayName.zh-CN": "文件管理器",
|
||||
"description": "Provides files storage services with files collection template and attachment field.",
|
||||
|
@ -18,6 +18,7 @@ export default {
|
||||
createdBy: true,
|
||||
updatedBy: true,
|
||||
template: 'file',
|
||||
filterTargetKey: 'id',
|
||||
fields: [
|
||||
{
|
||||
comment: '用户文件名(不含扩展名)',
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-gantt",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"displayName": "Block: Gantt",
|
||||
"displayName.zh-CN": "区块:甘特图",
|
||||
"description": "Provides Gantt block.",
|
||||
|
@ -4,7 +4,7 @@
|
||||
"displayName.zh-CN": "可视化数据表管理",
|
||||
"description": "An ER diagram-like tool. Currently only the Master database is supported.",
|
||||
"description.zh-CN": "类似 ER 图的工具,目前只支持主数据库。",
|
||||
"version": "1.7.14",
|
||||
"version": "1.7.18",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
"homepage": "https://docs.nocobase.com/handbook/graph-collection-manager",
|
||||
|
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