diff --git a/CHANGELOG.md b/CHANGELOG.md index efd999fd2..e0c468f98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +## [v0.20.0-alpha.12](https://github.com/nocobase/nocobase/compare/v0.20.0-alpha.11...v0.20.0-alpha.12) - 2024-03-16 + +### Merged + +- fix: compatibility of @ant-design/plots 2.x [`#3734`](https://github.com/nocobase/nocobase/pull/3734) + +### Commits + +- chore(versions): 😊 publish v0.20.0-alpha.12 [`c1be864`](https://github.com/nocobase/nocobase/commit/c1be86412440c617771d079ded95f64aca3fa155) +- fix: yarn dev error [`c191f14`](https://github.com/nocobase/nocobase/commit/c191f149f96def2672fc50d4d042ca976c863ebc) +- chore: update changelog [`8278262`](https://github.com/nocobase/nocobase/commit/8278262728387fbd3963a0286ed09b2219eb7739) + +## [v0.20.0-alpha.11](https://github.com/nocobase/nocobase/compare/v0.20.0-alpha.10...v0.20.0-alpha.11) - 2024-03-16 + +### Merged + +- feat: supports subdirectory deployment [`#3731`](https://github.com/nocobase/nocobase/pull/3731) +- fix(variables): fix varaibles for table selector [`#3725`](https://github.com/nocobase/nocobase/pull/3725) +- fixing timezone header when it is negative value [`#3732`](https://github.com/nocobase/nocobase/pull/3732) +- fix(data-source): foreignkey [`#3707`](https://github.com/nocobase/nocobase/pull/3707) +- feat: add data source filter [`#3724`](https://github.com/nocobase/nocobase/pull/3724) +- fix(Table): fix disappearing content after selecting a row [`#3726`](https://github.com/nocobase/nocobase/pull/3726) +- refactor: view collection set name as default title when title is missing [`#3719`](https://github.com/nocobase/nocobase/pull/3719) +- refactor: add blocks in a unified way [`#3668`](https://github.com/nocobase/nocobase/pull/3668) +- feat: support to set data loading mode [`#3712`](https://github.com/nocobase/nocobase/pull/3712) +- fix: block template [`#3714`](https://github.com/nocobase/nocobase/pull/3714) +- refactor(SchemaInitializers): unify naming style [`#3604`](https://github.com/nocobase/nocobase/pull/3604) +- fix: remove env in colletion delete button [`#3682`](https://github.com/nocobase/nocobase/pull/3682) +- fix(data-vi): update antv version [`#3710`](https://github.com/nocobase/nocobase/pull/3710) + +### Commits + +- chore(versions): 😊 publish v0.20.0-alpha.11 [`15ef818`](https://github.com/nocobase/nocobase/commit/15ef81854e4f900ed53e5229d66d1c016d71b8e7) +- chore: update registry in yarn.lock [`e877e3b`](https://github.com/nocobase/nocobase/commit/e877e3b5d9c1543c74a55b41eb57f69f15ff9847) +- chore: update changelog [`42448ec`](https://github.com/nocobase/nocobase/commit/42448ecddb1afe455cced9c4a8b6ca78586a060f) + ## [v0.20.0-alpha.10](https://github.com/nocobase/nocobase/compare/v0.20.0-alpha.9...v0.20.0-alpha.10) - 2024-03-13 ### Merged diff --git a/docker/nocobase/Dockerfile b/docker/nocobase/Dockerfile index 2728e7486..db96d07fa 100644 --- a/docker/nocobase/Dockerfile +++ b/docker/nocobase/Dockerfile @@ -30,7 +30,6 @@ RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \ && apt-get update && apt-get install -y nginx RUN rm -rf /etc/nginx/sites-enabled/default -COPY ./nocobase.conf /etc/nginx/sites-enabled/nocobase.conf COPY --from=builder /app/nocobase.tar.gz /app/nocobase.tar.gz WORKDIR /app/nocobase diff --git a/docker/nocobase/docker-entrypoint.sh b/docker/nocobase/docker-entrypoint.sh index 4480dbcbc..83c0a4acf 100755 --- a/docker/nocobase/docker-entrypoint.sh +++ b/docker/nocobase/docker-entrypoint.sh @@ -1,9 +1,6 @@ #!/bin/sh set -e -nginx -echo 'nginx started'; - if [ ! -d "/app/nocobase" ]; then mkdir nocobase fi @@ -14,10 +11,16 @@ if [ ! -f "/app/nocobase/package.json" ]; then touch /app/nocobase/node_modules/@nocobase/app/dist/client/index.html fi +cd /app/nocobase && yarn nocobase create-nginx-conf +rm -rf /etc/nginx/sites-enabled/nocobase.conf +ln -s /app/nocobase/storage/nocobase.conf /etc/nginx/sites-enabled/nocobase.conf + +nginx +echo 'nginx started'; + if [ -z "$PM2_INSTANCE_NUM" ]; then PM2_INSTANCE_NUM=1 fi - cd /app/nocobase && yarn start --quickstart -i $PM2_INSTANCE_NUM # Run command with node if the first argument contains a "-" or is not a system command. The last diff --git a/lerna.json b/lerna.json index e9e38c08f..22efc4d0d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "npmClient": "yarn", "useWorkspaces": true, "npmClientArgs": ["--ignore-engines"], diff --git a/packages/core/acl/package.json b/packages/core/acl/package.json index 0cb0276fb..d85cf13ee 100644 --- a/packages/core/acl/package.json +++ b/packages/core/acl/package.json @@ -1,13 +1,13 @@ { "name": "@nocobase/acl", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "license": "Apache-2.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "dependencies": { - "@nocobase/resourcer": "0.20.0-alpha.10", - "@nocobase/utils": "0.20.0-alpha.10", + "@nocobase/resourcer": "0.20.0-alpha.12", + "@nocobase/utils": "0.20.0-alpha.12", "minimatch": "^5.1.1" }, "repository": { diff --git a/packages/core/actions/package.json b/packages/core/actions/package.json index 2b671c2a4..1d399e62d 100644 --- a/packages/core/actions/package.json +++ b/packages/core/actions/package.json @@ -1,14 +1,14 @@ { "name": "@nocobase/actions", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "license": "Apache-2.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "dependencies": { - "@nocobase/cache": "0.20.0-alpha.10", - "@nocobase/database": "0.20.0-alpha.10", - "@nocobase/resourcer": "0.20.0-alpha.10" + "@nocobase/cache": "0.20.0-alpha.12", + "@nocobase/database": "0.20.0-alpha.12", + "@nocobase/resourcer": "0.20.0-alpha.12" }, "repository": { "type": "git", diff --git a/packages/core/app/client/.umirc.ts b/packages/core/app/client/.umirc.ts index 95761bad1..6e11d7175 100644 --- a/packages/core/app/client/.umirc.ts +++ b/packages/core/app/client/.umirc.ts @@ -16,19 +16,35 @@ const outputPluginPath = path.join(__dirname, 'src', '.plugins'); const indexGenerator = new IndexGenerator(outputPluginPath, pluginDirs); indexGenerator.generate(); +const isDevCmd = !!process.env.IS_DEV_CMD; +const appPublicPath = isDevCmd ? '/' : '{{env.APP_PUBLIC_PATH}}'; + export default defineConfig({ title: 'Loading...', devtool: process.env.NODE_ENV === 'development' ? 'source-map' : false, - favicons: ['/favicon/favicon.ico'], + favicons: [`${appPublicPath}favicon/favicon.ico`], metas: [{ name: 'viewport', content: 'initial-scale=0.1' }], links: [ - { rel: 'apple-touch-icon', size: '180x180', ref: '/favicon/apple-touch-icon.png' }, - { rel: 'icon', type: 'image/png', size: '32x32', ref: '/favicon/favicon-32x32.png' }, - { rel: 'icon', type: 'image/png', size: '16x16', ref: '/favicon/favicon-16x16.png' }, - { rel: 'manifest', href: '/favicon/site.webmanifest' }, - { rel: 'stylesheet', href: '/global.css' }, + { rel: 'apple-touch-icon', size: '180x180', ref: `${appPublicPath}favicon/apple-touch-icon.png` }, + { rel: 'icon', type: 'image/png', size: '32x32', ref: `${appPublicPath}favicon/favicon-32x32.png` }, + { rel: 'icon', type: 'image/png', size: '16x16', ref: `${appPublicPath}favicon/favicon-16x16.png` }, + { rel: 'manifest', href: `${appPublicPath}favicon/site.webmanifest` }, + { rel: 'stylesheet', href: `${appPublicPath}global.css` }, + ], + headScripts: [ + { + src: `${appPublicPath}browser-checker.js`, + }, + { + content: isDevCmd ? '' : ` + window['__webpack_public_path__'] = '{{env.APP_PUBLIC_PATH}}'; + window['__nocobase_public_path__'] = '{{env.APP_PUBLIC_PATH}}'; + window['__nocobase_api_base_url__'] = '{{env.API_BASE_URL}}'; + window['__nocobase_ws_url__'] = '{{env.WS_URL}}'; + window['__nocobase_ws_path__'] = '{{env.WS_PATH}}'; + `, + }, ], - headScripts: ['/browser-checker.js'], outputPath: path.resolve(__dirname, '../dist/client'), hash: true, alias: { @@ -41,6 +57,7 @@ export default defineConfig({ proxy: { ...umiConfig.proxy, }, + publicPath: 'auto', fastRefresh: false, // 热更新会导致 Context 丢失,不开启 mfsu: false, esbuildMinifyIIFE: true, diff --git a/packages/core/app/client/src/pages/index.tsx b/packages/core/app/client/src/pages/index.tsx index 82c94739e..9952ec354 100644 --- a/packages/core/app/client/src/pages/index.tsx +++ b/packages/core/app/client/src/pages/index.tsx @@ -4,10 +4,18 @@ import devDynamicImport from '../.plugins/index'; export const app = new Application({ apiClient: { - baseURL: process.env.API_BASE_URL, + // @ts-ignore + baseURL: window['__nocobase_api_base_url__'] || process.env.API_BASE_URL || '/api/', }, + // @ts-ignore + publicPath: window['__nocobase_public_path__'] || process.env.APP_PUBLIC_PATH || '/', plugins: [NocoBaseClientPresetPlugin], - ws: true, + ws: { + // @ts-ignore + url: window['__nocobase_ws_url__'] || process.env.WEBSOCKET_URL || '', + // @ts-ignore + basename: window['__nocobase_ws_path__'] || process.env.WS_PATH || '/ws', + }, loadRemotePlugins: true, devDynamicImport, }); diff --git a/packages/core/app/package.json b/packages/core/app/package.json index a8abd359c..b49102fa9 100644 --- a/packages/core/app/package.json +++ b/packages/core/app/package.json @@ -1,17 +1,17 @@ { "name": "@nocobase/app", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "license": "AGPL-3.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "dependencies": { - "@nocobase/database": "0.20.0-alpha.10", - "@nocobase/preset-nocobase": "0.20.0-alpha.10", - "@nocobase/server": "0.20.0-alpha.10" + "@nocobase/database": "0.20.0-alpha.12", + "@nocobase/preset-nocobase": "0.20.0-alpha.12", + "@nocobase/server": "0.20.0-alpha.12" }, "devDependencies": { - "@nocobase/client": "0.20.0-alpha.10" + "@nocobase/client": "0.20.0-alpha.12" }, "repository": { "type": "git", diff --git a/packages/core/auth/package.json b/packages/core/auth/package.json index a5613924a..fd1614733 100644 --- a/packages/core/auth/package.json +++ b/packages/core/auth/package.json @@ -1,16 +1,16 @@ { "name": "@nocobase/auth", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "license": "Apache-2.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "dependencies": { - "@nocobase/actions": "0.20.0-alpha.10", - "@nocobase/cache": "0.20.0-alpha.10", - "@nocobase/database": "0.20.0-alpha.10", - "@nocobase/resourcer": "0.20.0-alpha.10", - "@nocobase/utils": "0.20.0-alpha.10", + "@nocobase/actions": "0.20.0-alpha.12", + "@nocobase/cache": "0.20.0-alpha.12", + "@nocobase/database": "0.20.0-alpha.12", + "@nocobase/resourcer": "0.20.0-alpha.12", + "@nocobase/utils": "0.20.0-alpha.12", "@types/jsonwebtoken": "^8.5.8", "jsonwebtoken": "^8.5.1" }, diff --git a/packages/core/build/package.json b/packages/core/build/package.json index c81042f07..1d2e1d7f2 100755 --- a/packages/core/build/package.json +++ b/packages/core/build/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/build", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "Library build tool based on rollup.", "main": "lib/index.js", "types": "./lib/index.d.ts", diff --git a/packages/core/cache/package.json b/packages/core/cache/package.json index bd4d1115c..965f5b143 100644 --- a/packages/core/cache/package.json +++ b/packages/core/cache/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/cache", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "license": "Apache-2.0", "main": "./lib/index.js", diff --git a/packages/core/cli/nocobase.conf.tpl b/packages/core/cli/nocobase.conf.tpl new file mode 100644 index 000000000..b1a7dcdfd --- /dev/null +++ b/packages/core/cli/nocobase.conf.tpl @@ -0,0 +1,89 @@ +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 {{cwd}}/node_modules/@nocobase/app/dist/client; + index index.html; + client_max_body_size 1000M; + access_log /var/log/nginx/nocobase.log apm; + + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + # 不缓存 HTML 文件 + # location ~ \.html$ { + # if_modified_since off; + # expires off; + # etag off; + # } + + # # 缓存 JavaScript 和 CSS 文件 + # location ~* \.(js|css)$ { + # expires 365d; + # add_header Cache-Control "public"; + # } + + location {{publicPath}}storage/uploads/ { + alias {{cwd}}/storage/uploads/; + add_header Cache-Control "public"; + access_log off; + autoindex off; + } + + location {{publicPath}} { + alias {{cwd}}/node_modules/@nocobase/app/dist/client/; + try_files $uri $uri/ /index.html; + add_header Last-Modified $date_gmt; + add_header Cache-Control 'no-store, no-cache'; + if_modified_since off; + expires off; + etag off; + } + + location ^~ {{publicPath}}api/ { + proxy_pass http://127.0.0.1:{{apiPort}}{{publicPath}}api/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + } + + location ^~ {{publicPath}}static/plugins/ { + proxy_pass http://127.0.0.1:{{apiPort}}{{publicPath}}static/plugins/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + } + + location {{publicPath}}ws { + proxy_pass http://127.0.0.1:{{apiPort}}{{publicPath}}ws; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + } +} diff --git a/packages/core/cli/package.json b/packages/core/cli/package.json index dace07c0a..75409c233 100644 --- a/packages/core/cli/package.json +++ b/packages/core/cli/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/cli", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "license": "Apache-2.0", "main": "./src/index.js", @@ -8,12 +8,12 @@ "nocobase": "./bin/index.js" }, "dependencies": { - "@nocobase/app": "0.20.0-alpha.10", + "@nocobase/app": "0.20.0-alpha.12", "@types/fs-extra": "^11.0.1", "@umijs/utils": "3.5.20", "chalk": "^4.1.1", "commander": "^9.2.0", - "dotenv": "^10.0.0", + "dotenv": "^16.0.0", "execa": "^5.1.1", "fast-glob": "^3.3.1", "fs-extra": "^11.1.1", @@ -25,7 +25,7 @@ "tsx": "^4.6.2" }, "devDependencies": { - "@nocobase/devtools": "0.20.0-alpha.10" + "@nocobase/devtools": "0.20.0-alpha.12" }, "repository": { "type": "git", diff --git a/packages/core/cli/src/commands/build.js b/packages/core/cli/src/commands/build.js index 39adbab65..d08bd5d7c 100644 --- a/packages/core/cli/src/commands/build.js +++ b/packages/core/cli/src/commands/build.js @@ -1,6 +1,6 @@ const { resolve } = require('path'); const { Command } = require('commander'); -const { run, nodeCheck, isPackageValid } = require('../util'); +const { run, nodeCheck, isPackageValid, buildIndexHtml } = require('../util'); /** * @@ -31,5 +31,6 @@ module.exports = (cli) => { !options.dts ? '--no-dts' : '', options.sourcemap ? '--sourcemap' : '', ]); + buildIndexHtml(true); }); }; diff --git a/packages/core/cli/src/commands/create-nginx-conf.js b/packages/core/cli/src/commands/create-nginx-conf.js new file mode 100644 index 000000000..ffacb5f92 --- /dev/null +++ b/packages/core/cli/src/commands/create-nginx-conf.js @@ -0,0 +1,21 @@ +const { resolve } = require('path'); +const { Command } = require('commander'); +const { readFileSync, writeFileSync } = require('fs'); + +/** + * + * @param {Command} cli + */ +module.exports = (cli) => { + cli.command('create-nginx-conf').action(async (name, options) => { + const file = resolve(__dirname, '../../nocobase.conf.tpl'); + const data = readFileSync(file, 'utf-8'); + const replaced = data + .replace(/\{\{cwd\}\}/g, '/app/nocobase') + .replace(/\{\{publicPath\}\}/g, process.env.APP_PUBLIC_PATH) + .replace(/\{\{apiPort\}\}/g, process.env.APP_PORT); + + const targetFile = resolve(process.cwd(), 'storage', 'nocobase.conf'); + writeFileSync(targetFile, replaced); + }); +}; diff --git a/packages/core/cli/src/commands/index.js b/packages/core/cli/src/commands/index.js index 2555675cc..48bfd57ee 100644 --- a/packages/core/cli/src/commands/index.js +++ b/packages/core/cli/src/commands/index.js @@ -8,6 +8,7 @@ const { isPackageValid, generateAppDir } = require('../util'); module.exports = (cli) => { generateAppDir(); require('./global')(cli); + require('./create-nginx-conf')(cli); require('./build')(cli); require('./tar')(cli); require('./dev')(cli); diff --git a/packages/core/cli/src/util.js b/packages/core/cli/src/util.js index eeac30871..93dbbd02c 100644 --- a/packages/core/cli/src/util.js +++ b/packages/core/cli/src/util.js @@ -180,6 +180,7 @@ exports.generateAppDir = function generateAppDir() { } else { process.env.APP_PACKAGE_ROOT = appPkgPath; } + buildIndexHtml(); }; exports.genTsConfigPaths = function genTsConfigPaths() { @@ -257,6 +258,30 @@ function parseEnv(name) { } } +function buildIndexHtml(force = false) { + const file = `${process.env.APP_PACKAGE_ROOT}/dist/client/index.html`; + if (!fs.existsSync(file)) { + return; + } + const tpl = `${process.env.APP_PACKAGE_ROOT}/dist/client/index.html.tpl`; + if (force && fs.existsSync(tpl)) { + fs.rmSync(tpl); + } + if (!fs.existsSync(tpl)) { + fs.copyFileSync(file, tpl); + } + const data = fs.readFileSync(tpl, 'utf-8'); + const replacedData = data + .replace(/\{\{env.APP_PUBLIC_PATH\}\}/g, process.env.APP_PUBLIC_PATH) + .replace(/\{\{env.API_BASE_URL\}\}/g, process.env.API_BASE_URL || process.env.API_BASE_PATH) + .replace(/\{\{env.WS_URL\}\}/g, process.env.WEBSOCKET_URL || '') + .replace(/\{\{env.WS_PATH\}\}/g, process.env.WS_PATH) + .replace('src="/umi.', `src="${process.env.APP_PUBLIC_PATH}umi.`); + fs.writeFileSync(file, replacedData, 'utf-8'); +} + +exports.buildIndexHtml = buildIndexHtml; + exports.initEnv = function initEnv() { const env = { APP_ENV: 'development', @@ -280,7 +305,10 @@ exports.initEnv = function initEnv() { PLAYWRIGHT_AUTH_FILE: resolve(process.cwd(), 'storage/playwright/.auth/admin.json'), CACHE_DEFAULT_STORE: 'memory', CACHE_MEMORY_MAX: 2000, + PLUGIN_STATICS_PATH: '/static/plugins/', LOGGER_BASE_PATH: 'storage/logs', + APP_SERVER_BASE_URL: '', + APP_PUBLIC_PATH: '/', }; if ( @@ -319,4 +347,16 @@ exports.initEnv = function initEnv() { process.env[key] = env[key]; } } + + if (process.env.APP_PUBLIC_PATH) { + const publicPath = process.env.APP_PUBLIC_PATH.replace(/\/$/g, ''); + const keys = ['API_BASE_PATH', 'WS_PATH', 'PLUGIN_STATICS_PATH']; + for (const key of keys) { + process.env[key] = publicPath + process.env[key]; + } + } + + if (process.env.APP_SERVER_BASE_URL && !process.env.API_BASE_URL) { + process.env.API_BASE_URL = process.env.APP_SERVER_BASE_URL + process.env.API_BASE_PATH; + } }; diff --git a/packages/core/client/package.json b/packages/core/client/package.json index f153b3c94..4ec8f20ce 100644 --- a/packages/core/client/package.json +++ b/packages/core/client/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/client", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "Apache-2.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": "0.20.0-alpha.10", - "@nocobase/sdk": "0.20.0-alpha.10", - "@nocobase/utils": "0.20.0-alpha.10", + "@nocobase/evaluators": "0.20.0-alpha.12", + "@nocobase/sdk": "0.20.0-alpha.12", + "@nocobase/utils": "0.20.0-alpha.12", "ahooks": "^3.7.2", "antd": "^5.12.8", "antd-style": "3.4.5", diff --git a/packages/core/client/src/api-client/APIClient.ts b/packages/core/client/src/api-client/APIClient.ts index 26385c14b..9c8ff70cd 100644 --- a/packages/core/client/src/api-client/APIClient.ts +++ b/packages/core/client/src/api-client/APIClient.ts @@ -1,4 +1,4 @@ -import { APIClient as APIClientSDK } from '@nocobase/sdk'; +import { APIClient as APIClientSDK, getSubAppName } from '@nocobase/sdk'; import { Result } from 'ahooks/es/useRequest/src/types'; import { notification } from 'antd'; import React from 'react'; @@ -39,9 +39,9 @@ export class APIClient extends APIClientSDK { interceptors() { this.axios.interceptors.request.use((config) => { config.headers['X-With-ACL-Meta'] = true; - const match = location.pathname.match(/^\/apps\/([^/]*)\//); - if (match) { - config.headers['X-App'] = match[1]; + const appName = this.app ? getSubAppName(this.app.getPublicPath()) : null; + if (appName) { + config.headers['X-App'] = appName; } return config; }); diff --git a/packages/core/client/src/application/Application.tsx b/packages/core/client/src/application/Application.tsx index 2629d334f..938745e13 100644 --- a/packages/core/client/src/application/Application.tsx +++ b/packages/core/client/src/application/Application.tsx @@ -9,14 +9,14 @@ import { createRoot } from 'react-dom/client'; import { I18nextProvider } from 'react-i18next'; import { Link, NavLink, Navigate } from 'react-router-dom'; +import { APIClient, APIClientProvider } from '../api-client'; import { CSSVariableProvider } from '../css-variable'; import { AntdAppProvider, GlobalThemeProvider } from '../global-theme'; +import { i18n } from '../i18n'; import { PluginManager, PluginType } from './PluginManager'; import { PluginSettingOptions, PluginSettingsManager } from './PluginSettingsManager'; import { ComponentTypeAndString, RouterManager, RouterOptions } from './RouterManager'; import { WebSocketClient, WebSocketClientOptions } from './WebSocketClient'; -import { APIClient, APIClientProvider } from '../api-client'; -import { i18n } from '../i18n'; import { AppComponent, BlankComponent, defaultAppComponents } from './components'; import { SchemaInitializer, SchemaInitializerManager } from './schema-initializer'; import * as schemaInitializerComponents from './schema-initializer/components'; @@ -25,10 +25,10 @@ import { compose, normalizeContainer } from './utils'; import { defineGlobalDeps } from './utils/globalDeps'; import { getRequireJs } from './utils/requirejs'; -import { type DataSourceManagerOptions, DataSourceManager } from '../data-source/data-source/DataSourceManager'; -import { DataSourceApplicationProvider } from '../data-source/components/DataSourceApplicationProvider'; import { CollectionField } from '../data-source/collection-field/CollectionField'; +import { DataSourceApplicationProvider } from '../data-source/components/DataSourceApplicationProvider'; import { DataBlockProvider } from '../data-source/data-block/DataBlockProvider'; +import { DataSourceManager, type DataSourceManagerOptions } from '../data-source/data-source/DataSourceManager'; import { AppSchemaComponentProvider } from './AppSchemaComponentProvider'; import type { Plugin } from './Plugin'; @@ -44,6 +44,7 @@ export type DevDynamicImport = (packageName: string) => Promise<{ default: typeo export type ComponentAndProps = [ComponentType, T]; export interface ApplicationOptions { name?: string; + publicPath?: string; apiClient?: APIClientOptions | APIClient; ws?: WebSocketClientOptions | boolean; i18n?: i18next; @@ -116,9 +117,10 @@ export class Application { this.addReactRouterComponents(); this.addProviders(options.providers || []); this.ws = new WebSocketClient(options.ws); + this.ws.app = this; this.pluginSettingsManager = new PluginSettingsManager(options.pluginSettings, this); this.addRoutes(); - this.name = this.options.name || getSubAppName() || 'main'; + this.name = this.options.name || getSubAppName(options.publicPath) || 'main'; } private initRequireJs() { @@ -157,6 +159,18 @@ export class Application { }); } + getOptions() { + return this.options; + } + + getPublicPath() { + return this.options.publicPath || '/'; + } + + getRouteUrl(pathname: string) { + return this.options.publicPath.replace(/\/$/g, '') + pathname; + } + getCollectionManager(dataSource?: string) { return this.dataSourceManager.getDataSource(dataSource)?.collectionManager; } diff --git a/packages/core/client/src/application/RouterManager.tsx b/packages/core/client/src/application/RouterManager.tsx index 588f60c4c..5784463b2 100644 --- a/packages/core/client/src/application/RouterManager.tsx +++ b/packages/core/client/src/application/RouterManager.tsx @@ -1,4 +1,4 @@ -import { set, get } from 'lodash'; +import { get, set } from 'lodash'; import React, { ComponentType } from 'react'; import { BrowserRouter, @@ -10,8 +10,8 @@ import { RouteObject, useRoutes, } from 'react-router-dom'; -import { BlankComponent, RouterContextCleaner } from './components'; import { Application } from './Application'; +import { BlankComponent, RouterContextCleaner } from './components'; export interface BrowserRouterOptions extends Omit { type?: 'browser'; @@ -98,6 +98,10 @@ export class RouterManager { this.options.type = type; } + getBasename() { + return this.options.basename; + } + setBasename(basename: string) { this.options.basename = basename; } diff --git a/packages/core/client/src/application/WebSocketClient.ts b/packages/core/client/src/application/WebSocketClient.ts index af662402a..cdadcd6fd 100644 --- a/packages/core/client/src/application/WebSocketClient.ts +++ b/packages/core/client/src/application/WebSocketClient.ts @@ -1,34 +1,13 @@ import { define, observable } from '@formily/reactive'; import { getSubAppName } from '@nocobase/sdk'; - -export const getWebSocketURL = () => { - if (!process.env.API_BASE_URL) { - return; - } - const subApp = getSubAppName(); - const queryString = subApp ? `?__appName=${subApp}` : ''; - const wsPath = process.env.WS_PATH || '/ws'; - if (process.env.WEBSOCKET_URL) { - const url = new URL(process.env.WEBSOCKET_URL); - if (url.hostname === 'localhost') { - const protocol = location.protocol === 'https:' ? 'wss' : 'ws'; - return `${protocol}://${location.hostname}:${url.port}${wsPath}${queryString}`; - } - return `${process.env.WEBSOCKET_URL}${queryString}`; - } - try { - const url = new URL(process.env.API_BASE_URL); - return `${url.protocol === 'https:' ? 'wss' : 'ws'}://${url.host}${wsPath}${queryString}`; - } catch (error) { - return `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}${wsPath}${queryString}`; - } -}; +import { Application } from './Application'; export type WebSocketClientOptions = { reconnectInterval?: number; reconnectAttempts?: number; pingInterval?: number; url?: string; + basename?: string; protocols?: string | string[]; onServerDown?: any; }; @@ -38,6 +17,7 @@ export class WebSocketClient { protected _reconnectTimes = 0; protected events = []; protected options: WebSocketClientOptions; + app: Application; enabled: boolean; connected = false; serverDown = false; @@ -57,6 +37,34 @@ export class WebSocketClient { }); } + getURL() { + if (!this.app) { + return; + } + const options = this.app.getOptions(); + const apiBaseURL = options?.apiClient?.['baseURL']; + if (!apiBaseURL) { + return; + } + const subApp = getSubAppName(this.app.getPublicPath()); + const queryString = subApp ? `?__appName=${subApp}` : ''; + const wsPath = this.options.basename || '/ws'; + if (this.options.url) { + const url = new URL(this.options.url); + if (url.hostname === 'localhost') { + const protocol = location.protocol === 'https:' ? 'wss' : 'ws'; + return `${protocol}://${location.hostname}:${url.port}${wsPath}${queryString}`; + } + return `${this.options.url}${queryString}`; + } + try { + const url = new URL(apiBaseURL); + return `${url.protocol === 'https:' ? 'wss' : 'ws'}://${url.host}${wsPath}${queryString}`; + } catch (error) { + return `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}${wsPath}${queryString}`; + } + } + get reconnectAttempts() { return this.options?.reconnectAttempts || 30; } @@ -90,7 +98,7 @@ export class WebSocketClient { return; } this._reconnectTimes++; - const ws = new WebSocket(this.options.url || getWebSocketURL(), this.options.protocols); + const ws = new WebSocket(this.getURL(), this.options.protocols); let pingIntervalTimer: any; ws.onopen = () => { console.log('[nocobase-ws]: connected.'); diff --git a/packages/core/client/src/block-provider/FormBlockProvider.tsx b/packages/core/client/src/block-provider/FormBlockProvider.tsx index 9c101c144..7ac794662 100644 --- a/packages/core/client/src/block-provider/FormBlockProvider.tsx +++ b/packages/core/client/src/block-provider/FormBlockProvider.tsx @@ -3,7 +3,7 @@ import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react import { Spin } from 'antd'; import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react'; import { useCollection_deprecated } from '../collection-manager'; -import { useCollectionParentRecordData, useCollectionRecord } from '../data-source'; +import { CollectionRecord, useCollectionParentRecordData, useCollectionRecord } from '../data-source'; import { RecordProvider, useRecord } from '../record-provider'; import { useActionContext, useDesignable } from '../schema-component'; import { Templates as DataTemplateSelect } from '../schema-component/antd/form-v2/Templates'; @@ -11,7 +11,20 @@ import { BlockProvider, useBlockRequestContext } from './BlockProvider'; import { TemplateBlockProvider } from './TemplateBlockProvider'; import { FormActiveFieldsProvider } from './hooks/useFormActiveFields'; -export const FormBlockContext = createContext({}); +export const FormBlockContext = createContext<{ + form?: any; + type?: 'update' | 'create'; + action?: string; + field?: any; + service?: any; + resource?: any; + updateAssociationValues?: any; + formBlockRef?: any; + collectionName?: string; + params?: any; + formRecord?: CollectionRecord; + [key: string]: any; +}>({}); FormBlockContext.displayName = 'FormBlockContext'; const InternalFormBlockProvider = (props) => { @@ -28,7 +41,7 @@ const InternalFormBlockProvider = (props) => { const { resource, service, updateAssociationValues } = useBlockRequestContext(); const formBlockRef = useRef(); const record = useCollectionRecord(); - const formBlockValue = useMemo(() => { + const formBlockValue: any = useMemo(() => { return { ...ctx, params, @@ -42,8 +55,9 @@ const InternalFormBlockProvider = (props) => { updateAssociationValues, formBlockRef, collectionName: collection, + formRecord: record, }; - }, [action, field, form, params, resource, service, updateAssociationValues]); + }, [action, collection, ctx, field, form, params, record, resource, service, updateAssociationValues]); if (service.loading && Object.keys(form?.initialValues)?.length === 0 && action) { return ; diff --git a/packages/core/client/src/modules/blocks/data-blocks/table-selector/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/blocks/data-blocks/table-selector/__e2e__/schemaSettings.test.ts index 140f6c45f..b43b71dcb 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/table-selector/__e2e__/schemaSettings.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/table-selector/__e2e__/schemaSettings.test.ts @@ -1,5 +1,6 @@ -import { expectSettingsMenu, test } from '@nocobase/test/e2e'; +import { expectSettingsMenu, test, expect } from '@nocobase/test/e2e'; import { createTable } from './utils'; +import { tableSelectorDataScopeVariable } from './templatesOfBug'; test.describe('table data selector schema settings', () => { test('supported options', async ({ page, mockPage }) => { @@ -11,6 +12,126 @@ test.describe('table data selector schema settings', () => { supportedOptions: ['Set the data scope', 'Set default sorting rules', 'Records per page', 'Delete'], }); }); + + test('should have a current form variable', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(tableSelectorDataScopeVariable).waitForInit(); + const record = await mockRecord('table-selector-data-scope-variable'); + await nocoPage.goto(); + + await page.getByLabel('action-Action.Link-View-view-table-selector-data-scope-variable-table-0').click(); + await page.getByTestId('select-data-picker').click(); + await page + .getByTestId('drawer-AssociationField.Selector-table-selector-data-scope-variable-Select record') + .getByLabel('block-item-CardItem-table-') + .hover(); + await page.getByLabel('designer-schema-settings-CardItem-blockSettings:tableSelector-table-selector-').hover(); + await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); + + // 使用 `当前表单` 设置数据范围 + await page.getByText('Add condition', { exact: true }).click(); + await page.getByTestId('select-filter-field').click(); + await page.getByRole('menuitemcheckbox', { name: 'singleLineText' }).click(); + await page.getByTestId('select-filter-operator').click(); + await page.getByRole('option', { name: 'is', exact: true }).click(); + await page.getByLabel('variable-button').click(); + await page.getByRole('menuitemcheckbox', { name: 'Current form right' }).click(); + await page.getByRole('menuitemcheckbox', { name: 'singleLineText' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 保存数据范围之后,表格选择器中应该只显示一条数据,且该数据与页面表格的第一行数据相同 + await expect( + page + .getByTestId('drawer-AssociationField.Selector-table-selector-data-scope-variable-Select record') + .getByLabel('block-item-CardItem-table-') + .getByRole('row'), + ).toHaveCount(2); // 这里之所以是 2,是因为表头也是一个 row + await expect( + page + .getByTestId('drawer-AssociationField.Selector-table-selector-data-scope-variable-Select record') + .getByLabel('block-item-CardItem-table-') + .getByText(record['singleLineText']), + ).toBeVisible(); + }); + + test('should have a current object variable', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(tableSelectorDataScopeVariable).waitForInit(); + const record = await mockRecord('table-selector-data-scope-variable'); + await nocoPage.goto(); + + await page.getByLabel('action-Action.Link-View-view-table-selector-data-scope-variable-table-0').click(); + + // 1. 将一个关系字段的 Select 组件改为子表单 + await page + .getByLabel( + 'block-item-CollectionField-table-selector-data-scope-variable-form-table-selector-data-scope-variable.manyToMany-manyToMany', + { exact: true }, + ) + .hover(); + await page + .getByLabel( + 'designer-schema-settings-CollectionField-fieldSettings:FormItem-table-selector-data-scope-variable-table-selector-data-scope-variable.manyToMany', + { exact: true }, + ) + .hover(); + await page.getByText('Field componentRecord picker').click(); + await page.getByRole('option', { name: 'Sub-form', exact: true }).click(); + // 使菜单消失 + await page.getByRole('menuitem', { name: 'Delete' }).hover(); + await page.mouse.move(-300, 0); + + // 2. 在子表单中创建一个关系字段,并切换成数据选择器组件 + await page.getByLabel('schema-initializer-Grid-form:').first().hover(); + await page.getByRole('menuitem', { name: 'manyToMany' }).click(); + await page.getByRole('menuitem', { name: 'singleLineText' }).click(); + await page.getByLabel('block-item-CollectionField-').nth(1).hover(); + await page + .getByLabel('designer-schema-settings-CollectionField-fieldSettings:FormItem-table-selector-') + .nth(1) + .hover(); + await page.getByRole('menuitem', { name: 'Field component Select' }).click(); + await page.getByRole('option', { name: 'Record picker' }).click(); + // 使菜单消失 + await page.getByRole('menuitem', { name: 'Delete' }).hover(); + await page.mouse.move(-300, 0); + + await page.getByLabel('block-item-CollectionField-').nth(1).click(); + + // 3. 创建 Table 区块 + await page.getByLabel('schema-initializer-Grid-popup').hover(); + await page.getByRole('menuitem', { name: 'form Table' }).click(); + + // 4. 设置数据范围 + await page.getByLabel('block-item-CardItem-table-selector-data-scope-variable-table-selector').hover(); + await page.getByLabel('designer-schema-settings-CardItem-blockSettings:tableSelector-table-selector-').hover(); + await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); + + // 使用 `当前对象` 设置数据范围 + await page.getByText('Add condition', { exact: true }).click(); + await page.getByTestId('select-filter-field').click(); + await page.getByRole('menuitemcheckbox', { name: 'singleLineText' }).click(); + await page.getByTestId('select-filter-operator').click(); + await page.getByRole('option', { name: 'is', exact: true }).click(); + await page.getByLabel('variable-button').click(); + await page.getByRole('menuitemcheckbox', { name: 'Current object right' }).click(); + await page.getByRole('menuitemcheckbox', { name: 'singleLineText' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // Table 中显示 singleLineText 字段 + await page.getByLabel('schema-initializer-TableV2.').hover(); + await page.getByRole('menuitem', { name: 'singleLineText' }).click(); + await page.mouse.move(300, 0); + + // 保存数据范围之后,表格选择器中应该只显示一条数据,且该数据与页面表格的第一行数据相同 + await expect( + page.getByLabel('block-item-CardItem-table-selector-data-scope-variable-table-selector').getByRole('row'), + ).toHaveCount(2); // 这里之所以是 2,是因为表头也是一个 row + await expect( + page + .getByLabel('block-item-CardItem-table-selector-data-scope-variable-table-selector') + .getByRole('row') + .getByText(record['manyToMany'][0]['singleLineText']), + ).toBeVisible(); + }); }); async function showSettingsMenu(page) { diff --git a/packages/core/client/src/modules/blocks/data-blocks/table-selector/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/blocks/data-blocks/table-selector/__e2e__/templatesOfBug.ts index e69de29bb..c649e89e5 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/table-selector/__e2e__/templatesOfBug.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/table-selector/__e2e__/templatesOfBug.ts @@ -0,0 +1,851 @@ +import { PageConfig } from '@nocobase/test/e2e'; + +const commonCollections = [ + { + name: 'table-selector-data-scope-variable', + fields: [ + { + name: 'manyToMany', + interface: 'm2m', + target: 'table-selector-data-scope-variable', + }, + { + name: 'singleLineText', + interface: 'input', + }, + ], + }, +]; + +export const tableSelectorDataScopeVariable: PageConfig = { + collections: commonCollections, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + ij2wf9hi0si: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + jdz50aeuduh: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + ij66b8u5o5m: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + '5j0kimft2lz': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'table-selector-data-scope-variable:list', + 'x-decorator-props': { + collection: 'table-selector-data-scope-variable', + dataSource: 'main', + resource: 'table-selector-data-scope-variable', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:table', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-uid': 'vdvzzbfp53e', + 'x-async': false, + 'x-index': 1, + }, + ttcsp9slh2z: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + f1gruzhfm8r: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + properties: { + esrrc38rvqe: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View") }}', + 'x-action': 'view', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:view', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: { + zhykdvqpa7k: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + luhz7fq6529: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + gecihd85864: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: false, + }, + 'x-acl-action': + 'table-selector-data-scope-variable:update', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + useSourceId: '{{ useSourceIdFromParentRecord }}', + useParams: '{{ useParamsFromRecord }}', + action: 'get', + dataSource: 'main', + resource: 'table-selector-data-scope-variable', + collection: 'table-selector-data-scope-variable', + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:editForm', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + '3h121b8k9ey': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + t4tin6z9nq1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + xb7fdug52ex: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + manyToMany: { + 'x-uid': 'p0km7m8dnj4', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': + 'FormItemSchemaToolbar', + 'x-settings': + 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'table-selector-data-scope-variable.manyToMany', + 'x-component-props': { + fieldNames: { + label: 'id', + value: 'id', + }, + mode: 'Picker', + }, + properties: { + guunasm2a3h: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': + 'AssociationField.Selector', + title: + '{{ t("Select record") }}', + 'x-component-props': { + className: + 'nb-record-picker-selector', + }, + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'TableSelectorInitializers', + properties: { + '0uui41pxdye': { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: { + '476w75depv3': { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: { + alibfkv2g0v: { + 'x-uid': + 'y8f4lswt52q', + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-acl-action': + 'table-selector-data-scope-variable:list', + 'x-decorator': + 'TableSelectorProvider', + 'x-decorator-props': + { + collection: + 'table-selector-data-scope-variable', + resource: + 'table-selector-data-scope-variable', + dataSource: + 'main', + action: + 'list', + params: { + pageSize: 20, + filter: + {}, + }, + rowKey: + 'id', + }, + 'x-toolbar': + 'BlockSchemaToolbar', + 'x-settings': + 'blockSettings:tableSelector', + 'x-component': + 'CardItem', + properties: { + rblwp47r7fz: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-initializer': + 'TableActionInitializers', + 'x-component': + 'ActionBar', + 'x-component-props': + { + style: { + marginBottom: + 'var(--nb-spacing)', + }, + }, + 'x-uid': + 'ubog2cks3ay', + 'x-async': + false, + 'x-index': 1, + }, + value: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'array', + 'x-initializer': + 'TableColumnInitializers', + 'x-component': + 'TableV2.Selector', + 'x-component-props': + { + rowSelection: + { + type: 'checkbox', + }, + useProps: + '{{ useTableSelectorProps }}', + }, + properties: + { + jryz1oqazsj: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + title: + '{{ t("Actions") }}', + 'x-decorator': + 'TableV2.Column.ActionBar', + 'x-component': + 'TableV2.Column', + 'x-designer': + 'TableV2.ActionColumnDesigner', + 'x-initializer': + 'TableActionColumnInitializers', + 'x-action-column': + 'actions', + properties: + { + pkzvqfi6lr5: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-decorator': + 'DndContext', + 'x-component': + 'Space', + 'x-component-props': + { + split: + '|', + }, + properties: + { + xffx2jx6u7q: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + title: + '{{ t("View") }}', + 'x-action': + 'view', + 'x-toolbar': + 'ActionSchemaToolbar', + 'x-settings': + 'actionSettings:view', + 'x-component': + 'Action.Link', + 'x-component-props': + { + openMode: + 'drawer', + }, + 'x-decorator': + 'ACLActionProvider', + 'x-designer-props': + { + linkageAction: + true, + }, + properties: + { + drawer: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + title: + '{{ t("View record") }}', + 'x-component': + 'Action.Container', + 'x-component-props': + { + className: + 'nb-action-popup', + }, + properties: + { + tabs: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Tabs', + 'x-component-props': + {}, + 'x-initializer': + 'TabPaneInitializers', + properties: + { + tab1: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + title: + '{{t("Details")}}', + 'x-component': + 'Tabs.TabPane', + 'x-designer': + 'Tabs.Designer', + 'x-component-props': + {}, + properties: + { + grid: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid', + 'x-initializer': + 'RecordBlockInitializers', + 'x-uid': + 'wkqrpvcqiih', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + '2lzui9z88st', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'ee4zj3qx2ip', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'l5ew3g2ka6s', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + '0m2i5xxfw1k', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'zm42p4adruu', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + '4ybzswir3zr', + 'x-async': + false, + 'x-index': 2, + }, + d51klxxphw4: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-decorator': + 'TableV2.Column.Decorator', + 'x-toolbar': + 'TableColumnSchemaToolbar', + 'x-settings': + 'fieldSettings:TableColumn', + 'x-component': + 'TableV2.Column', + properties: + { + singleLineText: + { + _isJSONSchemaObject: + true, + version: + '2.0', + 'x-collection-field': + 'table-selector-data-scope-variable.singleLineText', + 'x-component': + 'CollectionField', + 'x-component-props': + { + ellipsis: + true, + }, + 'x-read-pretty': + true, + 'x-decorator': + null, + 'x-decorator-props': + { + labelStyle: + { + display: + 'none', + }, + }, + 'x-uid': + 'n069twt8nsc', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + '51p2r7zlo9k', + 'x-async': + false, + 'x-index': 3, + }, + }, + 'x-uid': + 'gkbturli19t', + 'x-async': + false, + 'x-index': 2, + }, + }, + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 't45on50ncwe', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9hzvnye1ntr', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'k2bdu4w8zz2', + 'x-async': false, + 'x-index': 1, + }, + footer: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-component': + 'Action.Container.Footer', + 'x-component-props': {}, + properties: { + actions: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'ActionBar', + 'x-component-props': {}, + properties: { + submit: { + _isJSONSchemaObject: + true, + version: '2.0', + title: + '{{ t("Submit") }}', + 'x-action': + 'submit', + 'x-component': + 'Action', + 'x-toolbar': + 'ActionSchemaToolbar', + 'x-settings': + 'actionSettings:updateSubmit', + 'x-component-props': + { + type: 'primary', + htmlType: + 'submit', + useProps: + '{{ usePickActionProps }}', + }, + 'x-uid': + 'n6qpnb48sbd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '92iud7xsva7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3c8prk8jgoh', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '41hvryuv2jy', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qbnfti92f1t', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4dx0hfhj9mj', + 'x-async': false, + 'x-index': 1, + }, + '23d5tg85dmy': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + wwivbgmqgly: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + singleLineText: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': + 'FormItemSchemaToolbar', + 'x-settings': + 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'table-selector-data-scope-variable.singleLineText', + 'x-component-props': {}, + 'x-uid': 'sj6aet9kqxc', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9cj7a3ivw6b', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5w0lqwa932g', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'gmbrw8r2h2s', + 'x-async': false, + 'x-index': 1, + }, + gi40rgo7rbw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'UpdateFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': 'go3p2x3eo9j', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '5wir035vnz7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'r82q143nugf', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'rqwpj88fpss', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4yfu43yq0ff', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1xvy1k1xpig', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ip9pwu9kuf0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'h9iowhtt6mu', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'so8ptulb3b0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lcy4ohio47t', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'oh16739fgf8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ut6738nt9in', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4e89got7e7b', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '5yt30cpknsy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0s3jvo8y7y3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'irunx7mpta6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8es0fh04717', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hwlep783jqy', + 'x-async': true, + 'x-index': 1, + }, +}; diff --git a/packages/core/client/src/nocobase-buildin-plugin/index.tsx b/packages/core/client/src/nocobase-buildin-plugin/index.tsx index 61b3e39fe..38f533561 100644 --- a/packages/core/client/src/nocobase-buildin-plugin/index.tsx +++ b/packages/core/client/src/nocobase-buildin-plugin/index.tsx @@ -10,6 +10,7 @@ import { useAPIClient } from '../api-client'; import { Application } from '../application'; import { Plugin } from '../application/Plugin'; import { BlockSchemaComponentPlugin } from '../block-provider'; +import { CollectionPlugin } from '../collection-manager'; import { RemoteDocumentTitlePlugin } from '../document-title'; import { PinnedListPlugin } from '../plugin-manager'; import { PMPlugin } from '../pm'; @@ -22,7 +23,6 @@ import { BlockTemplateDetails, BlockTemplatePage } from '../schema-templates'; import { SystemSettingsPlugin } from '../system-settings'; import { CurrentUserProvider, CurrentUserSettingsMenuProvider } from '../user'; import { LocalePlugin } from './plugins/LocalePlugin'; -import { CollectionPlugin } from '../collection-manager'; const AppSpin = () => { return ( @@ -36,7 +36,7 @@ const useErrorProps = (app: Application, error: any) => { return {}; } const err = error?.response?.data?.errors?.[0] || error; - const subApp = getSubAppName(); + const subApp = getSubAppName(app.getPublicPath()); switch (err.code) { case 'USER_HAS_NO_ROLES_ERR': return { diff --git a/packages/core/client/src/schema-component/antd/association-field/Nester.tsx b/packages/core/client/src/schema-component/antd/association-field/Nester.tsx index af8fc1287..960c069d3 100644 --- a/packages/core/client/src/schema-component/antd/association-field/Nester.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/Nester.tsx @@ -25,6 +25,7 @@ import { import { AssociationFieldContext } from './context'; import { SubFormProvider, useAssociationFieldContext } from './hooks'; import { isNewRecord, markRecordAsNew } from '../../../data-source/collection-record/isNewRecord'; +import { useCollection } from '../../../data-source'; export const Nester = (props) => { const { options } = useContext(AssociationFieldContext); @@ -48,6 +49,7 @@ export const Nester = (props) => { const ToOneNester = (props) => { const { field } = useAssociationFieldContext(); const recordV2 = useCollectionRecord(); + const collection = useCollection(); const isAllowToSetDefaultValue = useCallback( ({ form, fieldSchema, collectionField, getInterface, formBlockType }: IsAllowToSetDefaultValueParams) => { @@ -84,7 +86,7 @@ const ToOneNester = (props) => { return ( - + {props.children} @@ -101,6 +103,7 @@ const ToManyNester = observer( const { options, field, allowMultiple, allowDissociate } = useAssociationFieldContext(); const { t } = useTranslation(); const recordData = useCollectionRecordData(); + const collection = useCollection(); if (!Array.isArray(field.value)) { field.value = []; @@ -193,7 +196,7 @@ const ToManyNester = observer( )} - + diff --git a/packages/core/client/src/schema-component/antd/association-field/hooks.ts b/packages/core/client/src/schema-component/antd/association-field/hooks.ts index 0dda6bbec..cd15de8c7 100644 --- a/packages/core/client/src/schema-component/antd/association-field/hooks.ts +++ b/packages/core/client/src/schema-component/antd/association-field/hooks.ts @@ -16,6 +16,7 @@ import { getVariableName } from '../../../variables/utils/getVariableName'; import { isVariable } from '../../../variables/utils/isVariable'; import { useDesignable } from '../../hooks'; import { AssociationFieldContext } from './context'; +import { Collection } from '../../../data-source'; export const useInsertSchema = (component) => { const fieldSchema = useFieldSchema(); @@ -178,7 +179,10 @@ export const useFieldNames = (props) => { return { label: 'label', value: 'value', ...fieldNames }; }; -const SubFormContext = createContext>(null); +const SubFormContext = createContext<{ + value: any; + collection: Collection; +}>(null); SubFormContext.displayName = 'SubFormContext'; export const SubFormProvider = SubFormContext.Provider; @@ -192,8 +196,9 @@ export const SubFormProvider = SubFormContext.Provider; * @returns */ export const useSubFormValue = () => { - const context = useContext(SubFormContext); + const { value, collection } = useContext(SubFormContext) || {}; return { - formValue: context, + formValue: value, + collection, }; }; diff --git a/packages/core/client/src/schema-component/antd/table-v2/Table.tsx b/packages/core/client/src/schema-component/antd/table-v2/Table.tsx index ada49213f..39c7f87de 100644 --- a/packages/core/client/src/schema-component/antd/table-v2/Table.tsx +++ b/packages/core/client/src/schema-component/antd/table-v2/Table.tsx @@ -18,6 +18,7 @@ import { DndContext, useDesignable, useTableSize } from '../..'; import { RecordIndexProvider, RecordProvider, + useCollection, useCollection_deprecated, useCollectionParentRecordData, useSchemaInitializerRender, @@ -44,6 +45,8 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) => const { designable } = useDesignable(); const { exists, render } = useSchemaInitializerRender(schema['x-initializer'], schema['x-initializer-props']); const parentRecordData = useCollectionParentRecordData(); + const collection = useCollection(); + const dataSource = field?.value?.slice?.()?.filter?.(Boolean) || []; const columns = schema .reduceProperties((buf, s) => { @@ -69,7 +72,7 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) => render: (v, record) => { const index = field.value?.indexOf(record); return ( - + diff --git a/packages/core/client/src/schema-initializer/utils.ts b/packages/core/client/src/schema-initializer/utils.ts index 4812c8cfe..08e4353d4 100644 --- a/packages/core/client/src/schema-initializer/utils.ts +++ b/packages/core/client/src/schema-initializer/utils.ts @@ -734,7 +734,7 @@ const recursiveParent = (schema: Schema) => { export const useCurrentSchema = (action: string, key: string, find = findSchema, rm = removeSchema) => { const { removeActiveFieldName } = useFormActiveFields() || {}; - const { form }: { form: Form } = useFormBlockContext(); + const { form }: { form?: Form } = useFormBlockContext(); let fieldSchema = useFieldSchema(); if (!fieldSchema?.['x-initializer'] && fieldSchema?.['x-decorator'] === 'FormItem') { const recursiveInitializerSchema = recursiveParent(fieldSchema); diff --git a/packages/core/client/src/schema-settings/EnableChildCollections/DynamicComponent.tsx b/packages/core/client/src/schema-settings/EnableChildCollections/DynamicComponent.tsx index 1f280b034..c1825e9d0 100644 --- a/packages/core/client/src/schema-settings/EnableChildCollections/DynamicComponent.tsx +++ b/packages/core/client/src/schema-settings/EnableChildCollections/DynamicComponent.tsx @@ -15,7 +15,6 @@ export const ChildDynamicComponent = observer( collectionField, }); const { currentObjectSettings } = useCurrentObjectVariable({ - currentCollection: collectionField?.collectionName, schema: collectionField?.uiSchema, collectionField, }); diff --git a/packages/core/client/src/schema-settings/LinkageRules/index.tsx b/packages/core/client/src/schema-settings/LinkageRules/index.tsx index 8ebf4f373..a44fbad76 100644 --- a/packages/core/client/src/schema-settings/LinkageRules/index.tsx +++ b/packages/core/client/src/schema-settings/LinkageRules/index.tsx @@ -167,7 +167,7 @@ export const FormLinkageRules = observer( ); return ( - + diff --git a/packages/core/client/src/schema-settings/SchemaSettings.tsx b/packages/core/client/src/schema-settings/SchemaSettings.tsx index 223007b7a..cbea0aee2 100644 --- a/packages/core/client/src/schema-settings/SchemaSettings.tsx +++ b/packages/core/client/src/schema-settings/SchemaSettings.tsx @@ -70,6 +70,7 @@ import { } from '..'; import { BlockRequestContext_deprecated, + FormBlockContext, useFormBlockContext, useFormBlockType, useTableBlockContext, @@ -968,9 +969,10 @@ export const SchemaSettingsModalItem: FC = (props) const dataSourceKey = useDataSourceKey(); const record = useCollectionRecord(); const { association } = useDataBlockProps() || {}; + const formCtx = useFormBlockContext(); // 解决变量`当前对象`值在弹窗中丢失的问题 - const { formValue: subFormValue } = useSubFormValue(); + const { formValue: subFormValue, collection: subFormCollection } = useSubFormValue(); if (hidden) { return null; @@ -987,44 +989,49 @@ export const SchemaSettingsModalItem: FC = (props) () => { return ( - - - - - - - - 576px - @media (min-width: 576px) { - min-width: 520px; - } + + + + + + + + + 576px + @media (min-width: 576px) { + min-width: 520px; + } - // screen <= 576px - @media (max-width: 576px) { - min-width: 320px; - } - `} - > - - - - - - - - - - - - - + // screen <= 576px + @media (max-width: 576px) { + min-width: 320px; + } + `} + > + + + + + + + + + + + + + + ); }, diff --git a/packages/core/client/src/schema-settings/VariableInput/VariableInput.tsx b/packages/core/client/src/schema-settings/VariableInput/VariableInput.tsx index 10020e01a..647eb1655 100644 --- a/packages/core/client/src/schema-settings/VariableInput/VariableInput.tsx +++ b/packages/core/client/src/schema-settings/VariableInput/VariableInput.tsx @@ -41,10 +41,6 @@ type Props = { style?: React.CSSProperties; collectionField: CollectionFieldOptions_deprecated; contextCollectionName?: string; - /**指定当前表单数据表 */ - currentFormCollectionName?: string; - /**指定当前对象数据表 */ - currentIterationCollectionName?: string; /** * 根据 `onChange` 的第一个参数,判断是否需要触发 `onChange` * @param value `onChange` 的第一个参数 @@ -86,8 +82,6 @@ export const VariableInput = (props: Props) => { record, returnScope = _.identity, targetFieldSchema, - currentFormCollectionName, - currentIterationCollectionName, } = props; const { name: blockCollectionName } = useBlockCollection(); const scope = useVariableScope(); @@ -100,8 +94,6 @@ export const VariableInput = (props: Props) => { operator, uiSchema, targetFieldSchema, - currentFormCollectionName, - currentIterationCollectionName, }); const contextVariable = useContextAssociationFields({ schema, maxDepth: 2, contextCollectionName, collectionField }); const { compatOldVariables } = useCompatOldVariables({ @@ -245,7 +237,6 @@ export function useCompatOldVariables(props: { }); const { currentRecordSettings } = useCurrentRecordVariable({ schema: uiSchema, - collectionName: blockCollectionName, collectionField, noDisabled, targetFieldSchema, diff --git a/packages/core/client/src/schema-settings/VariableInput/hooks/useFormVariable.ts b/packages/core/client/src/schema-settings/VariableInput/hooks/useFormVariable.ts index aeabcaa45..a053d6208 100644 --- a/packages/core/client/src/schema-settings/VariableInput/hooks/useFormVariable.ts +++ b/packages/core/client/src/schema-settings/VariableInput/hooks/useFormVariable.ts @@ -57,7 +57,6 @@ export const useFormVariable = ({ collectionName, collectionField, schema, noDis * @returns */ export const useCurrentFormVariable = ({ - collectionName, collectionField, schema, noDisabled, @@ -66,7 +65,7 @@ export const useCurrentFormVariable = ({ }: Props = {}) => { // const { getActiveFieldsName } = useFormActiveFields() || {}; const { t } = useTranslation(); - const { form } = useFormBlockContext(); + const { form, collectionName } = useFormBlockContext(); const currentFormSettings = useBaseVariable({ collectionField, uiSchema: schema, @@ -97,6 +96,6 @@ export const useCurrentFormVariable = ({ /** 变量值 */ currentFormCtx: formInstance?.values, /** 用来判断是否可以显示`当前表单`变量 */ - shouldDisplayCurrentForm: !!formInstance && !formInstance.readPretty, + shouldDisplayCurrentForm: formInstance && !formInstance.readPretty, }; }; diff --git a/packages/core/client/src/schema-settings/VariableInput/hooks/useIterationVariable.ts b/packages/core/client/src/schema-settings/VariableInput/hooks/useIterationVariable.ts index 8834af4cf..2808c97b8 100644 --- a/packages/core/client/src/schema-settings/VariableInput/hooks/useIterationVariable.ts +++ b/packages/core/client/src/schema-settings/VariableInput/hooks/useIterationVariable.ts @@ -5,6 +5,7 @@ import { CollectionFieldOptions } from '../../../data-source/collection/Collecti import { useFlag } from '../../../flag-provider'; import { useSubFormValue } from '../../../schema-component/antd/association-field/hooks'; import { useBaseVariable } from './useBaseVariable'; +import { useCollection } from '../../../data-source'; /** * @deprecated @@ -61,13 +62,11 @@ export const useIterationVariable = ({ * @returns */ export const useCurrentObjectVariable = ({ - currentCollection, collectionField, schema, noDisabled, targetFieldSchema, }: { - currentCollection?: string; collectionField?: CollectionFieldOptions; schema?: any; noDisabled?: boolean; @@ -75,7 +74,8 @@ export const useCurrentObjectVariable = ({ targetFieldSchema?: Schema; } = {}) => { // const { getActiveFieldsName } = useFormActiveFields() || {}; - const { formValue: currentObjectCtx } = useSubFormValue(); + const collection = useCollection(); + const { formValue: currentObjectCtx, collection: collectionOfCurrentObject } = useSubFormValue(); const { isInSubForm, isInSubTable } = useFlag() || {}; const { t } = useTranslation(); const currentObjectSettings = useBaseVariable({ @@ -85,7 +85,7 @@ export const useCurrentObjectVariable = ({ maxDepth: 4, name: '$iteration', title: t('Current object'), - collectionName: currentCollection, + collectionName: collectionOfCurrentObject?.name || collection?.name, noDisabled, returnFields: (fields, option) => { // fix https://nocobase.height.app/T-2277 diff --git a/packages/core/client/src/schema-settings/VariableInput/hooks/useRecordVariable.ts b/packages/core/client/src/schema-settings/VariableInput/hooks/useRecordVariable.ts index dfa733c2d..5078217f7 100644 --- a/packages/core/client/src/schema-settings/VariableInput/hooks/useRecordVariable.ts +++ b/packages/core/client/src/schema-settings/VariableInput/hooks/useRecordVariable.ts @@ -2,10 +2,8 @@ import { Schema } from '@formily/json-schema'; import _ from 'lodash'; import { useTranslation } from 'react-i18next'; import { CollectionFieldOptions_deprecated } from '../../../collection-manager'; -import { useCollection } from '../../../data-source/collection/CollectionProvider'; -import { useCollectionRecord } from '../../../data-source/collection-record/CollectionRecordProvider'; -import { useFlag } from '../../../flag-provider/hooks/useFlag'; import { useBaseVariable } from './useBaseVariable'; +import { useFormBlockContext } from '../../../block-provider/FormBlockProvider'; interface Props { collectionField?: CollectionFieldOptions_deprecated; @@ -47,16 +45,13 @@ export const useRecordVariable = (props: Props) => { */ export const useCurrentRecordVariable = (props: Props = {}) => { const { t } = useTranslation(); - const { isInSubForm, isInSubTable } = useFlag() || {}; - const record = useCollectionRecord(); - const recordData = isInSubForm || isInSubTable ? record?.parentRecord?.data : record?.data; - const { name: collectionName } = useCollection() || {}; + const { formRecord, collectionName } = useFormBlockContext(); const currentRecordSettings = useBaseVariable({ collectionField: props.collectionField, uiSchema: props.schema, name: '$nRecord', title: t('Current record'), - collectionName: props.collectionName || collectionName, + collectionName: collectionName, noDisabled: props.noDisabled, targetFieldSchema: props.targetFieldSchema, }); @@ -65,9 +60,9 @@ export const useCurrentRecordVariable = (props: Props = {}) => { /** 变量配置 */ currentRecordSettings, /** 变量值 */ - currentRecordCtx: recordData, + currentRecordCtx: formRecord?.data, /** 用于判断是否需要显示配置项 */ - shouldDisplayCurrentRecord: !_.isEmpty(recordData), + shouldDisplayCurrentRecord: !formRecord?.isNew && !_.isEmpty(formRecord?.data), /** 当前记录对应的 collection name */ collectionName, }; diff --git a/packages/core/client/src/schema-settings/VariableInput/hooks/useVariableOptions.ts b/packages/core/client/src/schema-settings/VariableInput/hooks/useVariableOptions.ts index c7c5a182d..d2aaa1ae0 100644 --- a/packages/core/client/src/schema-settings/VariableInput/hooks/useVariableOptions.ts +++ b/packages/core/client/src/schema-settings/VariableInput/hooks/useVariableOptions.ts @@ -35,10 +35,6 @@ interface Props { noDisabled?: boolean; /** 消费变量值的字段 */ targetFieldSchema?: Schema; - /**指定当前表单数据表 */ - currentFormCollectionName?: string; - /**指定当前对象数据表 */ - currentIterationCollectionName?: string; } export const useVariableOptions = ({ @@ -49,11 +45,8 @@ export const useVariableOptions = ({ noDisabled, targetFieldSchema, record, - currentFormCollectionName, - currentIterationCollectionName, }: Props) => { const { name: blockCollectionName = record?.__collectionName } = useBlockCollection(); - const { name } = useCollection_deprecated(); const blockParentCollectionName = record?.__parent?.__collectionName; const { currentUserSettings } = useCurrentUserVariable({ maxDepth: 3, @@ -71,14 +64,12 @@ export const useVariableOptions = ({ const { datetimeSettings } = useDatetimeVariable({ operator, schema: uiSchema, noDisabled }); const { currentFormSettings, shouldDisplayCurrentForm } = useCurrentFormVariable({ schema: uiSchema, - collectionName: currentFormCollectionName || blockCollectionName, collectionField, noDisabled, targetFieldSchema, form, }); const { currentObjectSettings, shouldDisplayCurrentObject } = useCurrentObjectVariable({ - currentCollection: currentIterationCollectionName || name, collectionField, schema: uiSchema, noDisabled, @@ -86,7 +77,6 @@ export const useVariableOptions = ({ }); const { currentRecordSettings, shouldDisplayCurrentRecord } = useCurrentRecordVariable({ schema: uiSchema, - collectionName: blockCollectionName, collectionField, noDisabled, targetFieldSchema, diff --git a/packages/core/create-nocobase-app/package.json b/packages/core/create-nocobase-app/package.json index eabddc9f3..0b11f25a6 100755 --- a/packages/core/create-nocobase-app/package.json +++ b/packages/core/create-nocobase-app/package.json @@ -1,6 +1,6 @@ { "name": "create-nocobase-app", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "src/index.js", "license": "Apache-2.0", "dependencies": { diff --git a/packages/core/data-source-manager/package.json b/packages/core/data-source-manager/package.json index 9a82b720b..49141aff9 100644 --- a/packages/core/data-source-manager/package.json +++ b/packages/core/data-source-manager/package.json @@ -1,16 +1,16 @@ { "name": "@nocobase/data-source-manager", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "license": "Apache-2.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "dependencies": { - "@nocobase/actions": "0.20.0-alpha.10", - "@nocobase/cache": "0.20.0-alpha.10", - "@nocobase/database": "0.20.0-alpha.10", - "@nocobase/resourcer": "0.20.0-alpha.10", - "@nocobase/utils": "0.20.0-alpha.10", + "@nocobase/actions": "0.20.0-alpha.12", + "@nocobase/cache": "0.20.0-alpha.12", + "@nocobase/database": "0.20.0-alpha.12", + "@nocobase/resourcer": "0.20.0-alpha.12", + "@nocobase/utils": "0.20.0-alpha.12", "@types/jsonwebtoken": "^8.5.8", "jsonwebtoken": "^8.5.1" }, diff --git a/packages/core/database/package.json b/packages/core/database/package.json index fecbde3d4..e9218bee2 100644 --- a/packages/core/database/package.json +++ b/packages/core/database/package.json @@ -1,13 +1,13 @@ { "name": "@nocobase/database", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "main": "./lib/index.js", "types": "./lib/index.d.ts", "license": "Apache-2.0", "dependencies": { - "@nocobase/logger": "0.20.0-alpha.10", - "@nocobase/utils": "0.20.0-alpha.10", + "@nocobase/logger": "0.20.0-alpha.12", + "@nocobase/utils": "0.20.0-alpha.12", "async-mutex": "^0.3.2", "chalk": "^4.1.1", "cron-parser": "4.4.0", diff --git a/packages/core/devtools/package.json b/packages/core/devtools/package.json index 75f1c3218..d8233e44f 100644 --- a/packages/core/devtools/package.json +++ b/packages/core/devtools/package.json @@ -1,13 +1,13 @@ { "name": "@nocobase/devtools", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "license": "Apache-2.0", "main": "./src/index.js", "dependencies": { - "@nocobase/build": "0.20.0-alpha.10", - "@nocobase/client": "0.20.0-alpha.10", - "@nocobase/test": "0.20.0-alpha.10", + "@nocobase/build": "0.20.0-alpha.12", + "@nocobase/client": "0.20.0-alpha.12", + "@nocobase/test": "0.20.0-alpha.12", "@types/koa": "^2.13.4", "@types/koa-bodyparser": "^4.3.4", "@types/lodash": "^4.14.177", diff --git a/packages/core/devtools/umiConfig.js b/packages/core/devtools/umiConfig.js index 0f08b7f03..06eee2281 100644 --- a/packages/core/devtools/umiConfig.js +++ b/packages/core/devtools/umiConfig.js @@ -8,11 +8,11 @@ const path = require('path'); console.log('VERSION: ', packageJson.version); function getUmiConfig() { - const { APP_PORT, API_BASE_URL } = process.env; + const { APP_PORT, API_BASE_URL, APP_PUBLIC_PATH } = process.env; const API_BASE_PATH = process.env.API_BASE_PATH || '/api/'; const PROXY_TARGET_URL = process.env.PROXY_TARGET_URL || `http://127.0.0.1:${APP_PORT}`; - const LOCAL_STORAGE_BASE_URL = '/storage/uploads/'; - const STATIC_PATH = '/static/'; + const LOCAL_STORAGE_BASE_URL = 'storage/uploads/'; + const STATIC_PATH = 'static/'; function getLocalStorageProxy() { if (LOCAL_STORAGE_BASE_URL.startsWith('http')) { @@ -20,11 +20,11 @@ function getUmiConfig() { } return { - [LOCAL_STORAGE_BASE_URL]: { + [APP_PUBLIC_PATH + LOCAL_STORAGE_BASE_URL]: { target: PROXY_TARGET_URL, changeOrigin: true, }, - [STATIC_PATH]: { + [APP_PUBLIC_PATH + STATIC_PATH]: { target: PROXY_TARGET_URL, changeOrigin: true, }, @@ -37,6 +37,7 @@ function getUmiConfig() { return memo; }, {}), define: { + 'process.env.APP_PUBLIC_PATH': process.env.APP_PUBLIC_PATH, 'process.env.WS_PATH': process.env.WS_PATH, 'process.env.API_BASE_URL': API_BASE_URL || API_BASE_PATH, 'process.env.APP_ENV': process.env.APP_ENV, @@ -221,9 +222,10 @@ export default function devDynamicImport(packageName: string): Promise { const pluginPackageJson = require(pluginPackageJsonPath); const pluginPathArr = pluginPackageJsonPath.replaceAll(path.sep, '/').split('/'); const hasNamespace = pluginPathArr[pluginPathArr.length - 3].startsWith('@'); - const pluginFileName = (hasNamespace - ? `${pluginPathArr[pluginPathArr.length - 3].replace('@', '')}_${pluginPathArr[pluginPathArr.length - 2]}` - : pluginPathArr[pluginPathArr.length - 2] + const pluginFileName = ( + hasNamespace + ? `${pluginPathArr[pluginPathArr.length - 3].replace('@', '')}_${pluginPathArr[pluginPathArr.length - 2]}` + : pluginPathArr[pluginPathArr.length - 2] ).replaceAll('-', '_'); let exportStatement = ''; diff --git a/packages/core/evaluators/package.json b/packages/core/evaluators/package.json index 3d5708527..d5d9e111c 100644 --- a/packages/core/evaluators/package.json +++ b/packages/core/evaluators/package.json @@ -1,13 +1,13 @@ { "name": "@nocobase/evaluators", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "main": "./lib/index.js", "types": "./lib/index.d.ts", "license": "Apache-2.0", "dependencies": { "@formulajs/formulajs": "4.2.0", - "@nocobase/utils": "0.20.0-alpha.10", + "@nocobase/utils": "0.20.0-alpha.12", "mathjs": "^10.6.0" }, "repository": { diff --git a/packages/core/logger/package.json b/packages/core/logger/package.json index 466d925b3..8862e750a 100644 --- a/packages/core/logger/package.json +++ b/packages/core/logger/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/logger", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "nocobase logging library", "license": "Apache-2.0", "main": "./lib/index.js", diff --git a/packages/core/resourcer/package.json b/packages/core/resourcer/package.json index 2af63bac9..22514787f 100644 --- a/packages/core/resourcer/package.json +++ b/packages/core/resourcer/package.json @@ -1,12 +1,12 @@ { "name": "@nocobase/resourcer", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "main": "./lib/index.js", "types": "./lib/index.d.ts", "license": "Apache-2.0", "dependencies": { - "@nocobase/utils": "0.20.0-alpha.10", + "@nocobase/utils": "0.20.0-alpha.12", "deepmerge": "^4.2.2", "koa-compose": "^4.1.0", "lodash": "^4.17.21", diff --git a/packages/core/sdk/package.json b/packages/core/sdk/package.json index bef489bbc..2f7e60ac6 100644 --- a/packages/core/sdk/package.json +++ b/packages/core/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/sdk", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "Apache-2.0", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/packages/core/sdk/src/APIClient.ts b/packages/core/sdk/src/APIClient.ts index 300644aae..297ed29d7 100644 --- a/packages/core/sdk/src/APIClient.ts +++ b/packages/core/sdk/src/APIClient.ts @@ -48,7 +48,7 @@ export class Auth { if (typeof window === 'undefined') { return; } - const appName = getSubAppName(); + const appName = getSubAppName(this.api['app'] ? this.api['app'].getPublicPath() : '/'); if (!appName) { return; } diff --git a/packages/core/sdk/src/getSubAppName.ts b/packages/core/sdk/src/getSubAppName.ts index ec79fe7b8..c56d84e40 100644 --- a/packages/core/sdk/src/getSubAppName.ts +++ b/packages/core/sdk/src/getSubAppName.ts @@ -1,9 +1,11 @@ -const getSubAppName = () => { - const match = window.location.pathname.match(/^\/apps\/([^/]*)\/?/); - if (!match) { - return ''; +const getSubAppName = (publicPath = '/') => { + const prefix = `${publicPath}apps/`; + if (!window.location.pathname.startsWith(prefix)) { + return; } - return match[1]; + const pathname = window.location.pathname.substring(prefix.length); + const args = pathname.split('/', 1); + return args[0] || ''; }; export default getSubAppName; diff --git a/packages/core/sdk/src/index.ts b/packages/core/sdk/src/index.ts index 22ae2b1eb..907a148cb 100644 --- a/packages/core/sdk/src/index.ts +++ b/packages/core/sdk/src/index.ts @@ -1,3 +1,3 @@ export * from './APIClient'; -export { default as getSubAppName } from './getSubAppName'; +export { default as getSubAppName } from './getSubAppName'; diff --git a/packages/core/server/package.json b/packages/core/server/package.json index 9edcd8e06..d324031f3 100644 --- a/packages/core/server/package.json +++ b/packages/core/server/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/server", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "lib/index.js", "types": "./lib/index.d.ts", "license": "Apache-2.0", @@ -10,18 +10,18 @@ "@koa/cors": "^3.1.0", "@koa/multer": "^3.0.2", "@koa/router": "^9.4.0", - "@nocobase/acl": "0.20.0-alpha.10", - "@nocobase/actions": "0.20.0-alpha.10", - "@nocobase/auth": "0.20.0-alpha.10", - "@nocobase/cache": "0.20.0-alpha.10", - "@nocobase/data-source-manager": "0.20.0-alpha.10", - "@nocobase/database": "0.20.0-alpha.10", - "@nocobase/evaluators": "0.20.0-alpha.10", - "@nocobase/logger": "0.20.0-alpha.10", - "@nocobase/resourcer": "0.20.0-alpha.10", - "@nocobase/sdk": "0.20.0-alpha.10", - "@nocobase/telemetry": "0.20.0-alpha.10", - "@nocobase/utils": "0.20.0-alpha.10", + "@nocobase/acl": "0.20.0-alpha.12", + "@nocobase/actions": "0.20.0-alpha.12", + "@nocobase/auth": "0.20.0-alpha.12", + "@nocobase/cache": "0.20.0-alpha.12", + "@nocobase/data-source-manager": "0.20.0-alpha.12", + "@nocobase/database": "0.20.0-alpha.12", + "@nocobase/evaluators": "0.20.0-alpha.12", + "@nocobase/logger": "0.20.0-alpha.12", + "@nocobase/resourcer": "0.20.0-alpha.12", + "@nocobase/sdk": "0.20.0-alpha.12", + "@nocobase/telemetry": "0.20.0-alpha.12", + "@nocobase/utils": "0.20.0-alpha.12", "@types/decompress": "4.2.4", "@types/ini": "^1.3.31", "@types/koa-send": "^4.1.3", diff --git a/packages/core/server/src/gateway/index.ts b/packages/core/server/src/gateway/index.ts index a8ce1613c..71ff9dd21 100644 --- a/packages/core/server/src/gateway/index.ts +++ b/packages/core/server/src/gateway/index.ts @@ -15,7 +15,7 @@ import handler from 'serve-handler'; import { parse } from 'url'; import { AppSupervisor } from '../app-supervisor'; import { ApplicationOptions } from '../application'; -import { PLUGIN_STATICS_PATH, getPackageDirByExposeUrl, getPackageNameByExposeUrl } from '../plugin-manager'; +import { getPackageDirByExposeUrl, getPackageNameByExposeUrl } from '../plugin-manager'; import { applyErrorWithArgs, getErrorWithCode } from './errors'; import { IPCSocketClient } from './ipc-socket-client'; import { IPCSocketServer } from './ipc-socket-server'; @@ -168,14 +168,16 @@ export class Gateway extends EventEmitter { async requestHandler(req: IncomingMessage, res: ServerResponse) { const { pathname } = parse(req.url); + const { PLUGIN_STATICS_PATH, APP_PUBLIC_PATH } = process.env; - if (pathname === '/__umi/api/bundle-status') { + if (pathname.endsWith('/__umi/api/bundle-status')) { res.statusCode = 200; res.end('ok'); return; } - if (pathname.startsWith('/storage/uploads/')) { + if (pathname.startsWith(APP_PUBLIC_PATH + 'storage/uploads/')) { + req.url = req.url.substring(APP_PUBLIC_PATH.length - 1); await compress(req, res); return handler(req, res, { public: resolve(process.cwd()), @@ -203,7 +205,8 @@ export class Gateway extends EventEmitter { }); } - if (!pathname.startsWith('/api')) { + if (!pathname.startsWith(process.env.API_BASE_PATH)) { + req.url = req.url.substring(APP_PUBLIC_PATH.length - 1); await compress(req, res); return handler(req, res, { public: `${process.env.APP_PACKAGE_ROOT}/dist/client`, diff --git a/packages/core/server/src/plugin-manager/clientStaticUtils.ts b/packages/core/server/src/plugin-manager/clientStaticUtils.ts index e7e6b6087..bb8c17ad1 100644 --- a/packages/core/server/src/plugin-manager/clientStaticUtils.ts +++ b/packages/core/server/src/plugin-manager/clientStaticUtils.ts @@ -36,7 +36,7 @@ export function getPackageFilePathWithExistCheck(packageName: string, filePath: } export function getExposeUrl(packageName: string, filePath: string) { - return `${PLUGIN_STATICS_PATH}${packageName}/${filePath}`; + return `${process.env.PLUGIN_STATICS_PATH}${packageName}/${filePath}`; } export function getExposeReadmeUrl(packageName: string, lang: string) { @@ -63,7 +63,7 @@ export function getExposeChangelogUrl(packageName: string) { * getPluginNameByClientStaticUrl('/static/plugins/@nocobase/foo/README.md') => '@nocobase/foo' */ export function getPackageNameByExposeUrl(pathname: string) { - pathname = pathname.replace(PLUGIN_STATICS_PATH, ''); + pathname = pathname.replace(process.env.PLUGIN_STATICS_PATH, ''); const pathArr = pathname.split('/'); if (pathname.startsWith('@')) { return pathArr.slice(0, 2).join('/'); diff --git a/packages/core/server/src/plugin-manager/options/resource.ts b/packages/core/server/src/plugin-manager/options/resource.ts index a82895dd6..8bd130868 100644 --- a/packages/core/server/src/plugin-manager/options/resource.ts +++ b/packages/core/server/src/plugin-manager/options/resource.ts @@ -5,7 +5,6 @@ import Application from '../../application'; import { getExposeUrl } from '../clientStaticUtils'; import PluginManager from '../plugin-manager'; //@ts-ignore -import { version } from '../../../package.json'; export default { name: 'pm', @@ -131,7 +130,10 @@ export default { try { return { ...item.toJSON(), - url: `${getExposeUrl(item.packageName, PLUGIN_CLIENT_ENTRY_FILE)}?version=${item.version}`, + url: `${process.env.APP_SERVER_BASE_URL}${getExposeUrl( + item.packageName, + PLUGIN_CLIENT_ENTRY_FILE, + )}?version=${item.version}`, }; } catch { return false; diff --git a/packages/core/telemetry/package.json b/packages/core/telemetry/package.json index 75aeb5c98..f7c484477 100644 --- a/packages/core/telemetry/package.json +++ b/packages/core/telemetry/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/telemetry", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "nocobase telemetry library", "license": "Apache-2.0", "main": "./lib/index.js", @@ -11,7 +11,7 @@ "directory": "packages/telemetry" }, "dependencies": { - "@nocobase/utils": "0.20.0-alpha.10", + "@nocobase/utils": "0.20.0-alpha.12", "@opentelemetry/api": "^1.7.0", "@opentelemetry/instrumentation": "^0.46.0", "@opentelemetry/resources": "^1.19.0", diff --git a/packages/core/test/package.json b/packages/core/test/package.json index 5b2d1e34d..755879a39 100644 --- a/packages/core/test/package.json +++ b/packages/core/test/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/test", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "lib/index.js", "module": "./src/index.ts", "types": "./lib/index.d.ts", @@ -40,7 +40,7 @@ }, "dependencies": { "@faker-js/faker": "8.1.0", - "@nocobase/server": "0.20.0-alpha.10", + "@nocobase/server": "0.20.0-alpha.12", "@playwright/test": "^1.42.1", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", diff --git a/packages/core/utils/package.json b/packages/core/utils/package.json index 74e79ddf8..541f53cc0 100644 --- a/packages/core/utils/package.json +++ b/packages/core/utils/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/utils", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "lib/index.js", "types": "./lib/index.d.ts", "license": "Apache-2.0", diff --git a/packages/plugins/@nocobase/plugin-acl/package.json b/packages/plugins/@nocobase/plugin-acl/package.json index a83bf4318..ac869ef14 100644 --- a/packages/plugins/@nocobase/plugin-acl/package.json +++ b/packages/plugins/@nocobase/plugin-acl/package.json @@ -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": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/acl", diff --git a/packages/plugins/@nocobase/plugin-action-bulk-edit/package.json b/packages/plugins/@nocobase/plugin-action-bulk-edit/package.json index 541015ea5..471354d6e 100644 --- a/packages/plugins/@nocobase/plugin-action-bulk-edit/package.json +++ b/packages/plugins/@nocobase/plugin-action-bulk-edit/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-action-bulk-edit", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "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", diff --git a/packages/plugins/@nocobase/plugin-action-bulk-update/package.json b/packages/plugins/@nocobase/plugin-action-bulk-update/package.json index e1aec50a3..7096076df 100644 --- a/packages/plugins/@nocobase/plugin-action-bulk-update/package.json +++ b/packages/plugins/@nocobase/plugin-action-bulk-update/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-action-bulk-update", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "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", diff --git a/packages/plugins/@nocobase/plugin-action-duplicate/package.json b/packages/plugins/@nocobase/plugin-action-duplicate/package.json index a1e5d902c..7ecbebfcd 100644 --- a/packages/plugins/@nocobase/plugin-action-duplicate/package.json +++ b/packages/plugins/@nocobase/plugin-action-duplicate/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-action-duplicate", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-duplicate", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-duplicate", diff --git a/packages/plugins/@nocobase/plugin-action-print/package.json b/packages/plugins/@nocobase/plugin-action-print/package.json index f7f3a5261..169ad56fe 100644 --- a/packages/plugins/@nocobase/plugin-action-print/package.json +++ b/packages/plugins/@nocobase/plugin-action-print/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-action-print", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-print", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-print", diff --git a/packages/plugins/@nocobase/plugin-api-doc/package.json b/packages/plugins/@nocobase/plugin-api-doc/package.json index 8bf3d1d05..2ee252cd4 100644 --- a/packages/plugins/@nocobase/plugin-api-doc/package.json +++ b/packages/plugins/@nocobase/plugin-api-doc/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-api-doc", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "displayName": "API documentation", "displayName.zh-CN": "API 文档", "description": "An OpenAPI documentation generator for NocoBase HTTP API.", diff --git a/packages/plugins/@nocobase/plugin-api-doc/src/client/Document.tsx b/packages/plugins/@nocobase/plugin-api-doc/src/client/Document.tsx index b515fcdfb..2110468d4 100644 --- a/packages/plugins/@nocobase/plugin-api-doc/src/client/Document.tsx +++ b/packages/plugins/@nocobase/plugin-api-doc/src/client/Document.tsx @@ -1,4 +1,5 @@ -import { css, useAPIClient, useRequest } from '@nocobase/client'; +import { css, useAPIClient, useApp, useRequest } from '@nocobase/client'; +import { getSubAppName } from '@nocobase/sdk'; import { Select, Space, Spin, Typography } from 'antd'; import React, { useEffect, useRef, useState } from 'react'; import SwaggerUIBundle from 'swagger-ui-dist/swagger-ui-bundle'; @@ -13,11 +14,12 @@ const Documentation = () => { const { t } = useTranslation(); const swaggerUIRef = useRef(); const { data: urls } = useRequest<{ data: { name: string; url: string }[] }>({ url: 'swagger:getUrls' }); + const app = useApp(); const requestInterceptor = (req) => { if (!req.headers['Authorization']) { - const match = location.pathname.match(/^\/apps\/([^/]*)\//); - if (match?.[1]) { - req.headers['X-App'] = match?.[1]; + const appName = getSubAppName(app.getPublicPath()); + if (appName) { + req.headers['X-App'] = appName; } req.headers['Authorization'] = `Bearer ${apiClient.auth.getToken()}`; } diff --git a/packages/plugins/@nocobase/plugin-api-doc/src/server/swagger/index.ts b/packages/plugins/@nocobase/plugin-api-doc/src/server/swagger/index.ts index d4f55f22a..3f56f4daf 100644 --- a/packages/plugins/@nocobase/plugin-api-doc/src/server/swagger/index.ts +++ b/packages/plugins/@nocobase/plugin-api-doc/src/server/swagger/index.ts @@ -1,10 +1,10 @@ import APIDocPlugin from '../server'; import baseSwagger from './base-swagger'; +import collectionToSwaggerObject from './collections'; import { SchemaTypeMapping } from './constants'; import { createDefaultActionSwagger, getInterfaceCollection } from './helpers'; import { getPluginsSwagger, getSwaggerDocument, loadSwagger } from './loader'; import { merge } from './merge'; -import collectionToSwaggerObject from './collections'; export class SwaggerManager { private plugin: APIDocPlugin; @@ -81,6 +81,10 @@ export class SwaggerManager { return merge(await this.getBaseSwagger(), await loadSwagger('@nocobase/server')); } + getURL(pathname: string) { + return process.env.API_BASE_PATH + pathname; + } + async getUrls() { const plugins = await getPluginsSwagger(this.db) .then((res) => { @@ -88,7 +92,7 @@ export class SwaggerManager { const schema = res[name]; return { name: schema.info?.title || name, - url: `/api/swagger:get?ns=${encodeURIComponent(`plugins/${name}`)}`, + url: this.getURL(`swagger:get?ns=${encodeURIComponent(`plugins/${name}`)}`), }; }); }) @@ -102,25 +106,25 @@ export class SwaggerManager { return [ { name: 'NocoBase API', - url: '/api/swagger:get', + url: this.getURL('swagger:get'), }, { name: 'NocoBase API - Core', - url: '/api/swagger:get?ns=core', + url: this.getURL('swagger:get?ns=core'), }, { name: 'NocoBase API - All plugins', - url: '/api/swagger:get?ns=plugins', + url: this.getURL('swagger:get?ns=plugins'), }, { name: 'NocoBase API - Custom collections', - url: '/api/swagger:get?ns=collections', + url: this.getURL('swagger:get?ns=collections'), }, ...plugins, ...collections.map((collection) => { return { name: `Collection API - ${collection.title}`, - url: `/api/swagger:get?ns=${encodeURIComponent('collections/' + collection.name)}`, + url: this.getURL(`swagger:get?ns=${encodeURIComponent('collections/' + collection.name)}`), }; }), ]; diff --git a/packages/plugins/@nocobase/plugin-api-keys/package.json b/packages/plugins/@nocobase/plugin-api-keys/package.json index b78a9252d..c580db25c 100644 --- a/packages/plugins/@nocobase/plugin-api-keys/package.json +++ b/packages/plugins/@nocobase/plugin-api-keys/package.json @@ -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": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/api-keys", diff --git a/packages/plugins/@nocobase/plugin-audit-logs/package.json b/packages/plugins/@nocobase/plugin-audit-logs/package.json index 290bdfbbb..78afa5d97 100644 --- a/packages/plugins/@nocobase/plugin-audit-logs/package.json +++ b/packages/plugins/@nocobase/plugin-audit-logs/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-audit-logs", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "displayName": "Audit logs (deprecated)", "displayName.zh-CN": "审计日志(废弃)", "description": "This plugin is deprecated. There will be a new audit log plugin in the future.", diff --git a/packages/plugins/@nocobase/plugin-auth/package.json b/packages/plugins/@nocobase/plugin-auth/package.json index 0d474060a..d4c5cd988 100644 --- a/packages/plugins/@nocobase/plugin-auth/package.json +++ b/packages/plugins/@nocobase/plugin-auth/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-auth", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/auth", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth", diff --git a/packages/plugins/@nocobase/plugin-backup-restore/package.json b/packages/plugins/@nocobase/plugin-backup-restore/package.json index fcf48888f..f0c88adb8 100644 --- a/packages/plugins/@nocobase/plugin-backup-restore/package.json +++ b/packages/plugins/@nocobase/plugin-backup-restore/package.json @@ -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": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/backup-restore", diff --git a/packages/plugins/@nocobase/plugin-calendar/package.json b/packages/plugins/@nocobase/plugin-calendar/package.json index 10db22f9f..81ff77e9f 100644 --- a/packages/plugins/@nocobase/plugin-calendar/package.json +++ b/packages/plugins/@nocobase/plugin-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-calendar", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "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.", diff --git a/packages/plugins/@nocobase/plugin-cas/package.json b/packages/plugins/@nocobase/plugin-cas/package.json index cf17c7519..9bd573a5b 100644 --- a/packages/plugins/@nocobase/plugin-cas/package.json +++ b/packages/plugins/@nocobase/plugin-cas/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "认证:CAS", "description": "CAS authentication.", "description.zh-CN": "通过 CAS 协议认证身份。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/auth-cas", diff --git a/packages/plugins/@nocobase/plugin-cas/src/client/SigninPage.tsx b/packages/plugins/@nocobase/plugin-cas/src/client/SigninPage.tsx index 0918d46b0..d38aae335 100644 --- a/packages/plugins/@nocobase/plugin-cas/src/client/SigninPage.tsx +++ b/packages/plugins/@nocobase/plugin-cas/src/client/SigninPage.tsx @@ -1,19 +1,23 @@ -import React, { useEffect } from 'react'; import { LoginOutlined } from '@ant-design/icons'; -import { Button, Space, message } from 'antd'; -import { useLocation } from 'react-router-dom'; -import { getSubAppName } from '@nocobase/sdk'; +import { useApp } from '@nocobase/client'; import { Authenticator } from '@nocobase/plugin-auth/client'; +import { getSubAppName } from '@nocobase/sdk'; +import { Button, Space, message } from 'antd'; +import React, { useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; export const SigninPage = (props: { authenticator: Authenticator }) => { const authenticator = props.authenticator; const location = useLocation(); const params = new URLSearchParams(location.search); const redirect = params.get('redirect'); + const app = useApp(); - const app = getSubAppName() || 'main'; + const appName = getSubAppName(app.getPublicPath()) || 'main'; const login = async () => { - window.location.replace(`/api/cas:login?authenticator=${authenticator.name}&__appName=${app}&redirect=${redirect}`); + window.location.replace( + `/api/cas:login?authenticator=${authenticator.name}&__appName=${appName}&redirect=${redirect}`, + ); }; useEffect(() => { diff --git a/packages/plugins/@nocobase/plugin-cas/src/server/actions/service.ts b/packages/plugins/@nocobase/plugin-cas/src/server/actions/service.ts index 132faf50c..28db05de4 100644 --- a/packages/plugins/@nocobase/plugin-cas/src/server/actions/service.ts +++ b/packages/plugins/@nocobase/plugin-cas/src/server/actions/service.ts @@ -9,7 +9,7 @@ export const service = async (ctx: Context, next: Next) => { if (appName && appName !== 'main') { const appSupervisor = AppSupervisor.getInstance(); if (appSupervisor?.runningMode !== 'single') { - prefix = `/apps/${appName}`; + prefix = process.env.APP_PUBLIC_PATH + `apps/${appName}`; } } diff --git a/packages/plugins/@nocobase/plugin-cas/src/server/auth.ts b/packages/plugins/@nocobase/plugin-cas/src/server/auth.ts index 3a07dc947..69c7a0e8c 100644 --- a/packages/plugins/@nocobase/plugin-cas/src/server/auth.ts +++ b/packages/plugins/@nocobase/plugin-cas/src/server/auth.ts @@ -19,7 +19,7 @@ export class CASAuth extends BaseAuth { const opts = this.options || {}; return { ...opts, - serviceUrl: `${opts.serviceDomain}/api/cas:service`, + serviceUrl: `${opts.serviceDomain}${process.env.API_BASE_PATH}cas:service`, }; } diff --git a/packages/plugins/@nocobase/plugin-charts/package.json b/packages/plugins/@nocobase/plugin-charts/package.json index 81b84351f..791d71f23 100644 --- a/packages/plugins/@nocobase/plugin-charts/package.json +++ b/packages/plugins/@nocobase/plugin-charts/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "图表(废弃)", "description": "The plugin has been deprecated, please use the data visualization plugin instead.", "description.zh-CN": "已废弃插件,请使用数据可视化插件代替。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "./dist/server/index.js", "license": "AGPL-3.0", "devDependencies": { diff --git a/packages/plugins/@nocobase/plugin-china-region/package.json b/packages/plugins/@nocobase/plugin-china-region/package.json index 983e4c3dd..bb95475f4 100644 --- a/packages/plugins/@nocobase/plugin-china-region/package.json +++ b/packages/plugins/@nocobase/plugin-china-region/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-china-region", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "displayName": "Administrative divisions of China", "displayName.zh-CN": "中国行政区划", "description": "Provides data and field type for administrative divisions of China.", diff --git a/packages/plugins/@nocobase/plugin-client/package.json b/packages/plugins/@nocobase/plugin-client/package.json index 6d88e5283..112b4f2da 100644 --- a/packages/plugins/@nocobase/plugin-client/package.json +++ b/packages/plugins/@nocobase/plugin-client/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "WEB 客户端", "description": "Provides a client interface for the NocoBase server", "description.zh-CN": "为 NocoBase 服务端提供客户端界面", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "./dist/server/index.js", "license": "AGPL-3.0", "devDependencies": { diff --git a/packages/plugins/@nocobase/plugin-collection-manager/package.json b/packages/plugins/@nocobase/plugin-collection-manager/package.json index 1e5aaa26b..6c2f689f9 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/package.json +++ b/packages/plugins/@nocobase/plugin-collection-manager/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "数据源:主数据库", "description": "NocoBase main database, supports relational databases such as MySQL, PostgreSQL, SQLite and so on.", "description.zh-CN": "NocoBase 主数据库,支持 MySQL、PostgreSQL、SQLite 等关系型数据库。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "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", diff --git a/packages/plugins/@nocobase/plugin-custom-request/package.json b/packages/plugins/@nocobase/plugin-custom-request/package.json index 64baf480a..168686f62 100644 --- a/packages/plugins/@nocobase/plugin-custom-request/package.json +++ b/packages/plugins/@nocobase/plugin-custom-request/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-custom-request", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "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", diff --git a/packages/plugins/@nocobase/plugin-data-source-manager/package.json b/packages/plugins/@nocobase/plugin-data-source-manager/package.json index 70f0fc105..f3fb5c949 100644 --- a/packages/plugins/@nocobase/plugin-data-source-manager/package.json +++ b/packages/plugins/@nocobase/plugin-data-source-manager/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-data-source-manager", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "dist/server/index.js", "displayName": "Data source manager", "displayName.zh-CN": "数据源管理", diff --git a/packages/plugins/@nocobase/plugin-data-visualization/package.json b/packages/plugins/@nocobase/plugin-data-visualization/package.json index 8c8d1c94e..ed2e66964 100644 --- a/packages/plugins/@nocobase/plugin-data-visualization/package.json +++ b/packages/plugins/@nocobase/plugin-data-visualization/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-data-visualization", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "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.", diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/chart.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/chart.ts index c7ae80215..26d6d6539 100644 --- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/chart.ts +++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/chart.ts @@ -122,6 +122,7 @@ export class Chart implements ChartType { let xField: FieldOption; let yField: FieldOption; let seriesField: FieldOption; + let colorField: FieldOption; let yFields: FieldOption[]; const getField = (fields: FieldOption[], selected: { field: string | string[]; alias?: string }) => { if (selected.alias) { @@ -147,17 +148,19 @@ export class Chart implements ChartType { xIndex = i; } }); - if (xIndex) { - // If there is a time field, the other field is used as the series field by default. - const index = xIndex === 0 ? 1 : 0; - seriesField = getField(fields, dimensions[index]); - } else { - xField = getField(fields, dimensions[0]); - seriesField = getField(fields, dimensions[1]); + xIndex = xIndex || 0; + xField = xField || getField(fields, dimensions[xIndex]); + const restFields = dimensions.filter((_, i) => i !== xIndex).map((i) => getField(fields, i)); + if (restFields.length === 1) { + seriesField = restFields[0]; + colorField = restFields[0]; + } else if (restFields.length > 1) { + colorField = restFields[0]; + seriesField = restFields[1]; } } } - return { xField, yField, seriesField, yFields }; + return { xField, yField, seriesField, colorField, yFields }; } /** diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/configs.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/configs.ts index b943a91e5..f41f44fe1 100644 --- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/configs.ts +++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/configs.ts @@ -49,4 +49,5 @@ export default { xField: (props: FieldConfigProps) => selectField({ name: 'xField', title: 'xField', required: true, ...props }), yField: (props: FieldConfigProps) => selectField({ name: 'yField', title: 'yField', required: true, ...props }), seriesField: (props: FieldConfigProps) => selectField({ name: 'seriesField', title: 'seriesField', ...props }), + colorField: (props: FieldConfigProps) => selectField({ name: 'colorField', title: 'colorField', ...props }), }; diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/dualAxes.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/dualAxes.ts index ca63adf8c..1403520bf 100644 --- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/dualAxes.ts +++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/dualAxes.ts @@ -2,6 +2,7 @@ import { G2PlotChart } from './g2plot'; import { ChartType, RenderProps } from '../chart'; import React, { useContext } from 'react'; import { DualAxes as G2DualAxes } from '@ant-design/plots'; +import lodash from 'lodash'; import { ChartRendererContext } from '../../renderer'; export class DualAxes extends G2PlotChart { @@ -60,18 +61,38 @@ export class DualAxes extends G2PlotChart { return { general: { xField: xField?.value, - yField: yFields?.map((f) => f.value).slice(0, 2) || [], + yField: yFields?.map((f) => f.value) || [], }, }; }; - render({ data, general, advanced, fieldProps, ctx }: RenderProps) { - const props = this.getProps({ data, general, advanced, fieldProps, ctx }); - const { data: _data } = props; - return () => - React.createElement(this.component, { - ...props, - data: [_data, _data], - }); + getProps({ data, general, advanced, fieldProps, ctx }: RenderProps) { + const props = super.getProps({ data, general, advanced, fieldProps, ctx }); + return { + ...lodash.omit(props, ['legend', 'tooltip']), + children: + props.yField?.map((yField: string, index: number) => { + return { + type: 'line', + yField, + colorField: () => { + const props = fieldProps[yField]; + const transformer = props?.transformer; + return props?.label || (transformer ? transformer(yField) : yField); + }, + axis: { + y: { + title: fieldProps[yField]?.label || yField, + position: index === 0 ? 'left' : 'right', + labelFormatter: (datnum) => { + const props = fieldProps[yField]; + const transformer = props?.transformer; + return transformer ? transformer(datnum) : datnum; + }, + }, + }, + }; + }) || [], + }; } } diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/g2plot.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/g2plot.ts index 9277ee836..fd73f177e 100644 --- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/g2plot.ts +++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/g2plot.ts @@ -1,6 +1,5 @@ +import { transform } from 'lodash'; import { Chart, ChartProps, ChartType, RenderProps } from '../chart'; -import { FieldOption } from '../../hooks'; -import { QueryProps } from '../../renderer'; import configs from './configs'; export class G2PlotChart extends Chart { @@ -29,15 +28,6 @@ export class G2PlotChart extends Chart { const meta = {}; // Some charts render wrong when the field name contains a dot in G2Plot const replace = (key: string) => key.replace(/\./g, '_'); - Object.entries(fieldProps).forEach(([key, props]) => { - if (key.includes('.')) { - key = replace(key); - } - meta[key] = { - formatter: props.transformer, - alias: props.label, - }; - }); general = Object.entries(general).reduce((obj, [key, value]) => { obj[key] = value; if (key.includes('Field')) { @@ -49,7 +39,40 @@ export class G2PlotChart extends Chart { } return obj; }, {}); - return { + const config = { + legend: { + color: { + itemLabelText: (datnum) => { + const props = fieldProps[datnum.label]; + const transformer = props?.transformer; + return props?.label || (transformer ? transformer(datnum.label) : datnum.label); + }, + }, + }, + tooltip: (d, index, data, column) => { + const field = column.y.field; + const props = fieldProps[field]; + const name = props?.label || field; + const transformer = props?.transformer; + const value = column.y.value[index]; + return { name, value: transformer ? transformer(value) : value }; + }, + axis: { + x: { + labelFormatter: (datnum) => { + const props = fieldProps[general.xField]; + const transformer = props?.transformer; + return transformer ? transformer(datnum) : datnum; + }, + }, + y: { + labelFormatter: (datnum) => { + const props = fieldProps[general.yField]; + const transformer = props?.transformer; + return transformer ? transformer(datnum) : datnum; + }, + }, + }, data: data.map((item) => { const obj = {}; Object.entries(item).forEach(([key, value]) => { @@ -60,11 +83,27 @@ export class G2PlotChart extends Chart { }); return obj; }), - meta, - animation: false, + theme: 'classic', + animate: { + enter: { + type: false, + }, + update: { + type: false, + }, + exit: { + type: false, + }, + }, + colorField: general.seriesField, + stack: general.isStack, + percent: general.isPercent ? true : undefined, + ...(general.smooth ? { shapeField: 'smooth' } : {}), ...general, + seriesField: general.isGroup ? general.seriesField : undefined, ...advanced, }; + return config; } getReference() { diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/index.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/index.ts index 112583bbd..d19deda50 100644 --- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/index.ts +++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/chart/g2plot/index.ts @@ -1,5 +1,4 @@ -import { Area, Column, Line, Scatter } from '@ant-design/plots'; -import { Bar } from './bar'; +import { Area, Column, Line, Scatter, Bar } from '@ant-design/plots'; import { Pie } from './pie'; import { DualAxes } from './dualAxes'; import { G2PlotChart } from './g2plot'; @@ -30,7 +29,12 @@ export default [ component: Column, config: ['isGroup', 'isStack', 'isPercent'], }), - new Bar(), + new G2PlotChart({ + name: 'bar', + title: 'Bar Chart', + component: Bar, + config: ['isGroup', 'isStack', 'isPercent'], + }), new Pie(), new DualAxes(), new G2PlotChart({ name: 'scatter', title: 'Scatter Chart', component: Scatter }), diff --git a/packages/plugins/@nocobase/plugin-disable-pm-add/package.json b/packages/plugins/@nocobase/plugin-disable-pm-add/package.json index f5082b226..2499f42d9 100644 --- a/packages/plugins/@nocobase/plugin-disable-pm-add/package.json +++ b/packages/plugins/@nocobase/plugin-disable-pm-add/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-disable-pm-add", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "./dist/server/index.js", "peerDependencies": { "@nocobase/client": "0.x", diff --git a/packages/plugins/@nocobase/plugin-error-handler/package.json b/packages/plugins/@nocobase/plugin-error-handler/package.json index cb908cd18..f6ce6c633 100644 --- a/packages/plugins/@nocobase/plugin-error-handler/package.json +++ b/packages/plugins/@nocobase/plugin-error-handler/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "错误处理器", "description": "Handling application errors and exceptions.", "description.zh-CN": "处理应用程序中的错误和异常。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "devDependencies": { diff --git a/packages/plugins/@nocobase/plugin-excel-formula-field/package.json b/packages/plugins/@nocobase/plugin-excel-formula-field/package.json index e05ffd36a..3f179b758 100644 --- a/packages/plugins/@nocobase/plugin-excel-formula-field/package.json +++ b/packages/plugins/@nocobase/plugin-excel-formula-field/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-excel-formula-field", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "license": "AGPL-3.0", "main": "./dist/server/index.js", diff --git a/packages/plugins/@nocobase/plugin-export/package.json b/packages/plugins/@nocobase/plugin-export/package.json index c0dc94477..fa15d35bd 100644 --- a/packages/plugins/@nocobase/plugin-export/package.json +++ b/packages/plugins/@nocobase/plugin-export/package.json @@ -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": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-export", diff --git a/packages/plugins/@nocobase/plugin-file-manager/package.json b/packages/plugins/@nocobase/plugin-file-manager/package.json index 3c3af3c0e..be95308e1 100644 --- a/packages/plugins/@nocobase/plugin-file-manager/package.json +++ b/packages/plugins/@nocobase/plugin-file-manager/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-file-manager", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "displayName": "File manager", "displayName.zh-CN": "文件管理器", "description": "Provides files storage services with files collection template and attachment field.", diff --git a/packages/plugins/@nocobase/plugin-file-manager/src/server/FileModel.ts b/packages/plugins/@nocobase/plugin-file-manager/src/server/FileModel.ts index 748a41b32..c73090bdb 100644 --- a/packages/plugins/@nocobase/plugin-file-manager/src/server/FileModel.ts +++ b/packages/plugins/@nocobase/plugin-file-manager/src/server/FileModel.ts @@ -10,6 +10,9 @@ export class FileModel extends Model { if (!json['thumbnailRule'] && storage?.type === 'ali-oss') { json['thumbnailRule'] = '?x-oss-process=image/auto-orient,1/resize,m_fill,w_94,h_94/quality,q_90'; } + if (storage?.type === 'local' && process.env.APP_PUBLIC_PATH) { + json['url'] = process.env.APP_PUBLIC_PATH.replace(/\/$/g, '') + json.url; + } } return json; } diff --git a/packages/plugins/@nocobase/plugin-formula-field/package.json b/packages/plugins/@nocobase/plugin-formula-field/package.json index 10a80f85c..3123fa785 100644 --- a/packages/plugins/@nocobase/plugin-formula-field/package.json +++ b/packages/plugins/@nocobase/plugin-formula-field/package.json @@ -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": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/field-formula", diff --git a/packages/plugins/@nocobase/plugin-gantt/package.json b/packages/plugins/@nocobase/plugin-gantt/package.json index c7714b92a..33844b761 100644 --- a/packages/plugins/@nocobase/plugin-gantt/package.json +++ b/packages/plugins/@nocobase/plugin-gantt/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-gantt", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "displayName": "Block: Gantt", "displayName.zh-CN": "区块:甘特图", "description": "Provides Gantt block.", diff --git a/packages/plugins/@nocobase/plugin-graph-collection-manager/package.json b/packages/plugins/@nocobase/plugin-graph-collection-manager/package.json index 040fda488..52fff5680 100644 --- a/packages/plugins/@nocobase/plugin-graph-collection-manager/package.json +++ b/packages/plugins/@nocobase/plugin-graph-collection-manager/package.json @@ -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": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/graph-collection-manager", diff --git a/packages/plugins/@nocobase/plugin-iframe-block/package.json b/packages/plugins/@nocobase/plugin-iframe-block/package.json index 88212dac4..1a95223b2 100644 --- a/packages/plugins/@nocobase/plugin-iframe-block/package.json +++ b/packages/plugins/@nocobase/plugin-iframe-block/package.json @@ -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": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/block-iframe", diff --git a/packages/plugins/@nocobase/plugin-iframe-block/src/client/Iframe.tsx b/packages/plugins/@nocobase/plugin-iframe-block/src/client/Iframe.tsx index e60f489fc..36bcb257d 100644 --- a/packages/plugins/@nocobase/plugin-iframe-block/src/client/Iframe.tsx +++ b/packages/plugins/@nocobase/plugin-iframe-block/src/client/Iframe.tsx @@ -1,5 +1,5 @@ import { observer, useField } from '@formily/react'; -import { useAPIClient } from '@nocobase/client'; +import { useAPIClient, useApp } from '@nocobase/client'; import { Card } from 'antd'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -22,13 +22,16 @@ export const Iframe: any = observer( const { t } = useTranslation(); const api = useAPIClient(); const field = useField(); + const app = useApp(); const src = React.useMemo(() => { if (mode === 'html') { - return `/api/iframeHtml:getHtml/${htmlId}?token=${api.auth.getToken()}&v=${field.data?.v || ''}`; + const options = app.getOptions(); + const apiBaseURL: string = options?.apiClient?.['baseURL']; + return `${apiBaseURL}iframeHtml:getHtml/${htmlId}?token=${api.auth.getToken()}&v=${field.data?.v || ''}`; } return url; - }, [url, mode, htmlId, field.data?.v]); + }, [app, url, mode, htmlId, field.data?.v]); if ((mode === 'url' && !url) || (mode === 'html' && !htmlId)) { return {t('Please fill in the iframe URL')}; diff --git a/packages/plugins/@nocobase/plugin-import/package.json b/packages/plugins/@nocobase/plugin-import/package.json index 388ab919a..e4b9e2abf 100644 --- a/packages/plugins/@nocobase/plugin-import/package.json +++ b/packages/plugins/@nocobase/plugin-import/package.json @@ -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": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/action-import", diff --git a/packages/plugins/@nocobase/plugin-kanban/package.json b/packages/plugins/@nocobase/plugin-kanban/package.json index c30c776ab..b8b34e0a8 100644 --- a/packages/plugins/@nocobase/plugin-kanban/package.json +++ b/packages/plugins/@nocobase/plugin-kanban/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-kanban", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/block-kanban", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/block-kanban", diff --git a/packages/plugins/@nocobase/plugin-localization-management/package.json b/packages/plugins/@nocobase/plugin-localization-management/package.json index b30647ce1..614a8ae74 100644 --- a/packages/plugins/@nocobase/plugin-localization-management/package.json +++ b/packages/plugins/@nocobase/plugin-localization-management/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-localization-management", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/localization-management", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/localization-management", diff --git a/packages/plugins/@nocobase/plugin-logger/package.json b/packages/plugins/@nocobase/plugin-logger/package.json index 741da708e..7cfde440c 100644 --- a/packages/plugins/@nocobase/plugin-logger/package.json +++ b/packages/plugins/@nocobase/plugin-logger/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "日志", "description": "Server-side logs, mainly including API request logs and system runtime logs, and allows to package and download log files.", "description.zh-CN": "服务端日志,主要包括接口请求日志和系统运行日志,并支持打包和下载日志文件。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/logger", diff --git a/packages/plugins/@nocobase/plugin-map/package.json b/packages/plugins/@nocobase/plugin-map/package.json index c397e904d..2647fa684 100644 --- a/packages/plugins/@nocobase/plugin-map/package.json +++ b/packages/plugins/@nocobase/plugin-map/package.json @@ -2,7 +2,7 @@ "name": "@nocobase/plugin-map", "displayName": "Block: Map", "displayName.zh-CN": "区块:地图", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "Map block, support Gaode map and Google map, you can also extend more map types.", "description.zh-CN": "地图区块,支持高德地图和 Google 地图,你也可以扩展更多地图类型。", "license": "AGPL-3.0", diff --git a/packages/plugins/@nocobase/plugin-math-formula-field/package.json b/packages/plugins/@nocobase/plugin-math-formula-field/package.json index c57ad4426..89bf23c6d 100644 --- a/packages/plugins/@nocobase/plugin-math-formula-field/package.json +++ b/packages/plugins/@nocobase/plugin-math-formula-field/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "数学公式字段", "description": "A powerful mathematical formula field plugin designed to provide flexible mathematical and formula calculation capabilities for databases or data management systems. It seamlessly integrates with various database systems such as MySQL, PostgreSQL, and offers an intuitive user interface for defining and executing mathematical formula fields.", "description.zh-CN": "一个功能强大的数学公式字段插件,旨在为数据库或数据管理系统提供灵活的数学计算和公式计算功能。它可以与各种数据库系统(如MySQL、PostgreSQL)无缝集成,并提供直观的用户界面来定义和执行数学公式字段。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "devDependencies": { diff --git a/packages/plugins/@nocobase/plugin-mobile-client/package.json b/packages/plugins/@nocobase/plugin-mobile-client/package.json index a80b47eb9..98befc8b1 100644 --- a/packages/plugins/@nocobase/plugin-mobile-client/package.json +++ b/packages/plugins/@nocobase/plugin-mobile-client/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-mobile-client", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/mobile-client", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/mobile-client", diff --git a/packages/plugins/@nocobase/plugin-mobile-client/src/client/configuration/App.tsx b/packages/plugins/@nocobase/plugin-mobile-client/src/client/configuration/App.tsx index 7d8e82916..2e1b576e8 100644 --- a/packages/plugins/@nocobase/plugin-mobile-client/src/client/configuration/App.tsx +++ b/packages/plugins/@nocobase/plugin-mobile-client/src/client/configuration/App.tsx @@ -1,18 +1,14 @@ +import { useApp } from '@nocobase/client'; import { Card, Form, Input } from 'antd'; import React, { useMemo } from 'react'; import { useTranslation } from '../locale'; -import { useLocation } from 'react-router-dom'; export const AppConfiguration = () => { + const app = useApp(); const { t } = useTranslation(); - const location = useLocation(); const targetUrl = useMemo(() => { - let baseUrl = '/mobile'; - if (location.pathname.startsWith('/apps')) { - baseUrl = location.pathname.split('/').slice(0, 3).join('/'); - } - return baseUrl; - }, [location.pathname]); + return app.getRouteUrl('/mobile'); + }, [app]); return ( { - const location = useLocation(); const { t } = useTranslation(); + const app = useApp(); const onOpenInNewTab = () => { - let baseUrl = window.origin; - if (window.location.pathname.startsWith('/apps')) { - baseUrl = window.origin + window.location.pathname.split('/').slice(0, 3).join('/'); - } - window.open(`${baseUrl}${location.pathname}${location.search}`); + window.open(app.getRouteUrl('/mobile')); }; return ( diff --git a/packages/plugins/@nocobase/plugin-mock-collections/package.json b/packages/plugins/@nocobase/plugin-mock-collections/package.json index 01833333e..19482d5f6 100644 --- a/packages/plugins/@nocobase/plugin-mock-collections/package.json +++ b/packages/plugins/@nocobase/plugin-mock-collections/package.json @@ -2,7 +2,7 @@ "name": "@nocobase/plugin-mock-collections", "displayName": "mock-collections", "description": "mock-collections", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "./dist/server/index.js", "license": "AGPL-3.0", "peerDependencies": { diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/package.json b/packages/plugins/@nocobase/plugin-multi-app-manager/package.json index ee47737bc..8d8aa7524 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/package.json +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "多应用管理器", "description": "Dynamically create multiple apps without separate deployments.", "description.zh-CN": "无需单独部署即可动态创建多个应用。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/multi-app-manager", diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppManager.tsx b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppManager.tsx index bd66cf223..be7ae97ed 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppManager.tsx +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppManager.tsx @@ -1,4 +1,4 @@ -import { SchemaComponent, useRecord } from '@nocobase/client'; +import { SchemaComponent, useApp, useRecord } from '@nocobase/client'; import { Card } from 'antd'; import React from 'react'; import { schema } from './settings/schemas/applications'; @@ -6,10 +6,11 @@ import { usePluginUtils } from './utils'; const useLink = () => { const record = useRecord(); + const app = useApp(); if (record.options?.standaloneDeployment && record.cname) { return `//${record.cname}`; } - return `/apps/${record.name}/admin/`; + return app.getRouteUrl(`/apps/${record.name}/admin/`); }; const AppVisitor = () => { diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppNameInput.tsx b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppNameInput.tsx index 3cd216ca6..a51026720 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppNameInput.tsx +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/AppNameInput.tsx @@ -1,10 +1,12 @@ import { connect, mapReadPretty } from '@formily/react'; +import { useApp } from '@nocobase/client'; import { Input as AntdInput } from 'antd'; import React from 'react'; const ReadPretty = (props) => { + const app = useApp(); const content = props.value && ( - + {props.value} ); diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/MultiAppManagerProvider.tsx b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/MultiAppManagerProvider.tsx index f4a56fb2a..d04707df4 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/MultiAppManagerProvider.tsx +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/client/MultiAppManagerProvider.tsx @@ -20,10 +20,10 @@ const MultiAppManager = () => { }, ); const { t } = usePluginUtils(); - const app = useApp(); + const instance = useApp(); const items = [ ...(data?.data || []).map((app) => { - let link = `/apps/${app.name}/admin/`; + let link = instance.getRouteUrl(`/apps/${app.name}/admin/`); if (app.options?.standaloneDeployment && app.cname) { link = `//${app.cname}`; } @@ -38,7 +38,9 @@ const MultiAppManager = () => { }), { key: '.manager', - label: {t('Manage applications')}, + label: ( + {t('Manage applications')} + ), }, ]; return ( diff --git a/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts b/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts index 16b9a4067..cd1c5675e 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts +++ b/packages/plugins/@nocobase/plugin-multi-app-manager/src/server/server.ts @@ -115,7 +115,7 @@ const defaultAppOptionsFactory = (appName: string, mainApp: Application) => { }, plugins: ['nocobase'], resourcer: { - prefix: '/api', + prefix: process.env.API_BASE_PATH, }, }; }; diff --git a/packages/plugins/@nocobase/plugin-multi-app-share-collection/package.json b/packages/plugins/@nocobase/plugin-multi-app-share-collection/package.json index 830cab66d..36b029e52 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-share-collection/package.json +++ b/packages/plugins/@nocobase/plugin-multi-app-share-collection/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "多应用数据表共享", "description": "", "description.zh-CN": "", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "./dist/server/index.js", "devDependencies": { "@formily/react": "2.x", diff --git a/packages/plugins/@nocobase/plugin-multi-app-share-collection/src/server/plugin.ts b/packages/plugins/@nocobase/plugin-multi-app-share-collection/src/server/plugin.ts index 6ff0b353f..af5121e17 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-share-collection/src/server/plugin.ts +++ b/packages/plugins/@nocobase/plugin-multi-app-share-collection/src/server/plugin.ts @@ -274,7 +274,7 @@ export class MultiAppShareCollectionPlugin extends Plugin { }), plugins: plugins.includes('nocobase') ? ['nocobase'] : plugins, resourcer: { - prefix: '/api', + prefix: process.env.API_BASE_PATH, }, logger: { ...mainApp.options.logger, diff --git a/packages/plugins/@nocobase/plugin-notifications/package.json b/packages/plugins/@nocobase/plugin-notifications/package.json index 635a614e5..510116f01 100644 --- a/packages/plugins/@nocobase/plugin-notifications/package.json +++ b/packages/plugins/@nocobase/plugin-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-notifications", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "description": "", "license": "AGPL-3.0", "main": "./dist/server/index.js", diff --git a/packages/plugins/@nocobase/plugin-oidc/package.json b/packages/plugins/@nocobase/plugin-oidc/package.json index 088f46fdc..500c11c5f 100644 --- a/packages/plugins/@nocobase/plugin-oidc/package.json +++ b/packages/plugins/@nocobase/plugin-oidc/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "认证:OIDC", "description": "OIDC (OpenID Connect) authentication.", "description.zh-CN": "通过 OIDC (OpenID Connect) 协议认证身份。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/auth-oidc", diff --git a/packages/plugins/@nocobase/plugin-oidc/src/client/Options.tsx b/packages/plugins/@nocobase/plugin-oidc/src/client/Options.tsx index a84b16979..9dc2325d2 100644 --- a/packages/plugins/@nocobase/plugin-oidc/src/client/Options.tsx +++ b/packages/plugins/@nocobase/plugin-oidc/src/client/Options.tsx @@ -1,9 +1,9 @@ import { CopyOutlined } from '@ant-design/icons'; import { ArrayItems, FormTab } from '@formily/antd-v5'; import { observer } from '@formily/react'; -import { FormItem, Input, SchemaComponent } from '@nocobase/client'; +import { FormItem, Input, SchemaComponent, useApp } from '@nocobase/client'; import { Card, Space, message } from 'antd'; -import React from 'react'; +import React, { useMemo } from 'react'; import { lang, useOidcTranslation } from './locale'; const schema = { @@ -327,9 +327,16 @@ const schema = { const Usage = observer( () => { const { t } = useOidcTranslation(); + const app = useApp(); - const { protocol, host } = window.location; - const url = `${protocol}//${host}/api/oidc:redirect`; + const url = useMemo(() => { + const options = app.getOptions(); + const apiBaseURL: string = options?.apiClient?.['baseURL']; + const { protocol, host } = window.location; + return apiBaseURL.startsWith('http') + ? `${apiBaseURL}oidc:redirect` + : `${protocol}//${host}${apiBaseURL}oidc:redirect`; + }, [app]); const copy = (text: string) => { navigator.clipboard.writeText(text); diff --git a/packages/plugins/@nocobase/plugin-oidc/src/server/actions/redirect.ts b/packages/plugins/@nocobase/plugin-oidc/src/server/actions/redirect.ts index 42d6b04f0..7cdadd839 100644 --- a/packages/plugins/@nocobase/plugin-oidc/src/server/actions/redirect.ts +++ b/packages/plugins/@nocobase/plugin-oidc/src/server/actions/redirect.ts @@ -1,6 +1,6 @@ import { Context, Next } from '@nocobase/actions'; -import { OIDCAuth } from '../oidc-auth'; import { AppSupervisor } from '@nocobase/server'; +import { OIDCAuth } from '../oidc-auth'; export const redirect = async (ctx: Context, next: Next) => { const { @@ -14,7 +14,7 @@ export const redirect = async (ctx: Context, next: Next) => { if (appName && appName !== 'main') { const appSupervisor = AppSupervisor.getInstance(); if (appSupervisor?.runningMode !== 'single') { - prefix = `/apps/${appName}`; + prefix = process.env.APP_PUBLIC_PATH + `apps/${appName}`; } } const auth = (await ctx.app.authManager.get(authenticator, ctx)) as OIDCAuth; diff --git a/packages/plugins/@nocobase/plugin-oidc/src/server/oidc-auth.ts b/packages/plugins/@nocobase/plugin-oidc/src/server/oidc-auth.ts index 5227717bf..021e5a591 100644 --- a/packages/plugins/@nocobase/plugin-oidc/src/server/oidc-auth.ts +++ b/packages/plugins/@nocobase/plugin-oidc/src/server/oidc-auth.ts @@ -1,7 +1,7 @@ import { AuthConfig, BaseAuth } from '@nocobase/auth'; +import { AuthModel } from '@nocobase/plugin-auth'; import { Issuer } from 'openid-client'; import { cookieName } from '../constants'; -import { AuthModel } from '@nocobase/plugin-auth'; export class OIDCAuth extends BaseAuth { constructor(config: AuthConfig) { @@ -17,7 +17,7 @@ export class OIDCAuth extends BaseAuth { const { http, port } = this.getOptions(); const protocol = http ? 'http' : 'https'; const host = port ? `${ctx.hostname}${port ? `:${port}` : ''}` : ctx.host; - return `${protocol}://${host}/api/oidc:redirect`; + return `${protocol}://${host}${process.env.API_BASE_PATH}oidc:redirect`; } getOptions() { diff --git a/packages/plugins/@nocobase/plugin-saml/package.json b/packages/plugins/@nocobase/plugin-saml/package.json index 3373bf0f2..54aea1ca4 100644 --- a/packages/plugins/@nocobase/plugin-saml/package.json +++ b/packages/plugins/@nocobase/plugin-saml/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "认证:SAML 2.0", "description": "SAML 2.0 authentication.", "description.zh-CN": "通过 SAML 2.0 协议认证身份。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/auth-saml", diff --git a/packages/plugins/@nocobase/plugin-saml/src/client/Options.tsx b/packages/plugins/@nocobase/plugin-saml/src/client/Options.tsx index 5a938c574..061a69daf 100644 --- a/packages/plugins/@nocobase/plugin-saml/src/client/Options.tsx +++ b/packages/plugins/@nocobase/plugin-saml/src/client/Options.tsx @@ -1,11 +1,10 @@ -import React from 'react'; -import { SchemaComponent } from '@nocobase/client'; -import { Card, message } from 'antd'; import { CopyOutlined } from '@ant-design/icons'; import { observer, useForm } from '@formily/react'; -import { useRecord, FormItem, Input } from '@nocobase/client'; -import { lang, useSamlTranslation } from './locale'; +import { FormItem, Input, SchemaComponent, useApp, useRecord } from '@nocobase/client'; import { getSubAppName } from '@nocobase/sdk'; +import { Card, message } from 'antd'; +import React, { useMemo } from 'react'; +import { lang, useSamlTranslation } from './locale'; const schema = { type: 'object', @@ -74,10 +73,19 @@ const Usage = observer( const record = useRecord(); const { t } = useSamlTranslation(); - const app = getSubAppName() || 'main'; + const app = useApp(); const name = form.values.name ?? record.name; - const { protocol, host } = window.location; - const url = `${protocol}//${host}/api/saml:redirect?authenticator=${name}&__appName=${app}`; + + const url = useMemo(() => { + const options = app.getOptions(); + const apiBaseURL: string = options?.apiClient?.['baseURL']; + const { protocol, host } = window.location; + const appName = getSubAppName(app.getPublicPath()) || 'main'; + + return apiBaseURL.startsWith('http') + ? `${apiBaseURL}saml:redirect?authenticator=${name}&__appName=${appName}` + : `${protocol}//${host}${apiBaseURL}saml:redirect?authenticator=${name}&__appName=${appName}`; + }, [app, name]); const copy = (text: string) => { navigator.clipboard.writeText(text); diff --git a/packages/plugins/@nocobase/plugin-saml/src/server/actions/redirect.ts b/packages/plugins/@nocobase/plugin-saml/src/server/actions/redirect.ts index 0acddaf53..21f225947 100644 --- a/packages/plugins/@nocobase/plugin-saml/src/server/actions/redirect.ts +++ b/packages/plugins/@nocobase/plugin-saml/src/server/actions/redirect.ts @@ -1,6 +1,6 @@ import { Context, Next } from '@nocobase/actions'; -import { SAMLAuth } from '../saml-auth'; import { AppSupervisor } from '@nocobase/server'; +import { SAMLAuth } from '../saml-auth'; export const redirect = async (ctx: Context, next: Next) => { const { authenticator, __appName: appName } = ctx.action.params || {}; @@ -9,7 +9,7 @@ export const redirect = async (ctx: Context, next: Next) => { if (appName && appName !== 'main') { const appSupervisor = AppSupervisor.getInstance(); if (appSupervisor?.runningMode !== 'single') { - prefix = `/apps/${appName}`; + prefix = process.env.APP_PUBLIC_PATH + `apps/${appName}`; } } const auth = (await ctx.app.authManager.get(authenticator, ctx)) as SAMLAuth; diff --git a/packages/plugins/@nocobase/plugin-saml/src/server/saml-auth.ts b/packages/plugins/@nocobase/plugin-saml/src/server/saml-auth.ts index 10ffee08c..51fd19eb4 100644 --- a/packages/plugins/@nocobase/plugin-saml/src/server/saml-auth.ts +++ b/packages/plugins/@nocobase/plugin-saml/src/server/saml-auth.ts @@ -24,7 +24,7 @@ export class SAMLAuth extends BaseAuth { const name = this.authenticator.get('name'); const protocol = http ? 'http' : 'https'; return { - callbackUrl: `${protocol}://${ctx.host}/api/saml:redirect?authenticator=${name}&__appName=${ctx.app.name}`, + callbackUrl: `${protocol}://${ctx.host}${process.env.API_BASE_PATH}saml:redirect?authenticator=${name}&__appName=${ctx.app.name}`, entryPoint: ssoUrl, issuer: name, cert: certificate, diff --git a/packages/plugins/@nocobase/plugin-sample-hello/package.json b/packages/plugins/@nocobase/plugin-sample-hello/package.json index 558459776..d88917930 100644 --- a/packages/plugins/@nocobase/plugin-sample-hello/package.json +++ b/packages/plugins/@nocobase/plugin-sample-hello/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-sample-hello", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "./dist/server/index.js", "displayName": "Hello", "displayName.zh-CN": "Hello", diff --git a/packages/plugins/@nocobase/plugin-sequence-field/package.json b/packages/plugins/@nocobase/plugin-sequence-field/package.json index 75701ac49..f26440933 100644 --- a/packages/plugins/@nocobase/plugin-sequence-field/package.json +++ b/packages/plugins/@nocobase/plugin-sequence-field/package.json @@ -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": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/field-sequence", diff --git a/packages/plugins/@nocobase/plugin-sms-auth/package.json b/packages/plugins/@nocobase/plugin-sms-auth/package.json index 09e12c77d..7a3c6f5c3 100644 --- a/packages/plugins/@nocobase/plugin-sms-auth/package.json +++ b/packages/plugins/@nocobase/plugin-sms-auth/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "认证:短信", "description": "SMS authentication.", "description.zh-CN": "通过短信验证码认证身份。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/auth-sms", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth-sms", diff --git a/packages/plugins/@nocobase/plugin-snapshot-field/package.json b/packages/plugins/@nocobase/plugin-snapshot-field/package.json index 6603c768c..044b97547 100644 --- a/packages/plugins/@nocobase/plugin-snapshot-field/package.json +++ b/packages/plugins/@nocobase/plugin-snapshot-field/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "数据表字段:关系快照", "description": "When adding a new record, create a snapshot for its relational record and save in the new record. The snapshot will not be updated when the relational record is updated.", "description.zh-CN": "在添加数据时,为它的关系数据创建快照,并保存在当前的数据中。关系数据更新时,快照不会更新。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/field-snapshot", diff --git a/packages/plugins/@nocobase/plugin-system-settings/package.json b/packages/plugins/@nocobase/plugin-system-settings/package.json index c042e0faa..ae0e74b01 100644 --- a/packages/plugins/@nocobase/plugin-system-settings/package.json +++ b/packages/plugins/@nocobase/plugin-system-settings/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "系统设置", "description": "Used to adjust the system title, logo, language, etc.", "description.zh-CN": "用于调整系统的标题、LOGO、语言等。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/system-settings", diff --git a/packages/plugins/@nocobase/plugin-theme-editor/package.json b/packages/plugins/@nocobase/plugin-theme-editor/package.json index 19e5999d0..2367838fb 100644 --- a/packages/plugins/@nocobase/plugin-theme-editor/package.json +++ b/packages/plugins/@nocobase/plugin-theme-editor/package.json @@ -1,6 +1,6 @@ { "name": "@nocobase/plugin-theme-editor", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "main": "dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/theme-editor", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/theme-editor", diff --git a/packages/plugins/@nocobase/plugin-ui-routes-storage/package.json b/packages/plugins/@nocobase/plugin-ui-routes-storage/package.json index 1e5278ed2..6315ac5d8 100644 --- a/packages/plugins/@nocobase/plugin-ui-routes-storage/package.json +++ b/packages/plugins/@nocobase/plugin-ui-routes-storage/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "路由管理", "description": "manage the routes of nocobase", "description.zh-CN": "管理页面路由。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "devDependencies": { diff --git a/packages/plugins/@nocobase/plugin-ui-schema-storage/package.json b/packages/plugins/@nocobase/plugin-ui-schema-storage/package.json index 67234b106..039d0f099 100644 --- a/packages/plugins/@nocobase/plugin-ui-schema-storage/package.json +++ b/packages/plugins/@nocobase/plugin-ui-schema-storage/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "UI schema 存储服务", "description": "Provides centralized UI schema storage service.", "description.zh-CN": "提供中心化的 UI schema 存储服务。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/ui-schema-storage", diff --git a/packages/plugins/@nocobase/plugin-users/package.json b/packages/plugins/@nocobase/plugin-users/package.json index b80078539..0fc6c483d 100644 --- a/packages/plugins/@nocobase/plugin-users/package.json +++ b/packages/plugins/@nocobase/plugin-users/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "用户", "description": "Provides basic user model, as well as created by and updated by fields.", "description.zh-CN": "提供了基础的用户模型,以及创建人和最后更新人字段。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/users", diff --git a/packages/plugins/@nocobase/plugin-verification/package.json b/packages/plugins/@nocobase/plugin-verification/package.json index 52614a7f6..dcf371fd8 100644 --- a/packages/plugins/@nocobase/plugin-verification/package.json +++ b/packages/plugins/@nocobase/plugin-verification/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "验证码", "description": "verification setting.", "description.zh-CN": "验证码配置。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/verification", diff --git a/packages/plugins/@nocobase/plugin-workflow-action-trigger/package.json b/packages/plugins/@nocobase/plugin-workflow-action-trigger/package.json index 87544fd71..34382c145 100644 --- a/packages/plugins/@nocobase/plugin-workflow-action-trigger/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-action-trigger/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:数据操作触发器", "description": "Bind action buttons to trigger workflow events when clicked.", "description.zh-CN": "可对数据操作按钮绑定,在点击后触发对应的工作流事件。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/plugins/workflow-action-trigger", diff --git a/packages/plugins/@nocobase/plugin-workflow-aggregate/package.json b/packages/plugins/@nocobase/plugin-workflow-aggregate/package.json index 5246841d2..7d45c34ac 100644 --- a/packages/plugins/@nocobase/plugin-workflow-aggregate/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-aggregate/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:聚合查询节点", "description": "Used to aggregate data against the database in workflow, such as: statistics, sum, average, etc.", "description.zh-CN": "可用于在工作流中对数据库进行聚合查询,如:统计数量、求和、平均值等。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-aggregate", diff --git a/packages/plugins/@nocobase/plugin-workflow-delay/package.json b/packages/plugins/@nocobase/plugin-workflow-delay/package.json index 757cb8aba..7681cac67 100644 --- a/packages/plugins/@nocobase/plugin-workflow-delay/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-delay/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:延时节点", "description": "Could be used in workflow parallel branch for waiting other branches.", "description.zh-CN": "可用于工作流并行分支中等待其他分支执行完成。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-delay", diff --git a/packages/plugins/@nocobase/plugin-workflow-dynamic-calculation/package.json b/packages/plugins/@nocobase/plugin-workflow-dynamic-calculation/package.json index 5bdcc5337..bb41e8f01 100644 --- a/packages/plugins/@nocobase/plugin-workflow-dynamic-calculation/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-dynamic-calculation/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:动态表达式计算节点", "description": "Useful plugin for doing dynamic calculation based on expression collection records in workflow.", "description.zh-CN": "用于在工作流中进行基于数据行的动态表达式计算。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-dynamic-calculation", diff --git a/packages/plugins/@nocobase/plugin-workflow-loop/package.json b/packages/plugins/@nocobase/plugin-workflow-loop/package.json index 929387b05..857ecbd3f 100644 --- a/packages/plugins/@nocobase/plugin-workflow-loop/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-loop/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:循环节点", "description": "Used to repeat the sub-process processing of each value in an array, and can also be used for fixed times of sub-process processing.", "description.zh-CN": "用于对一个数组中的每个值进行重复的子流程处理,也可用于固定次数的重复子流程处理。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-loop", diff --git a/packages/plugins/@nocobase/plugin-workflow-manual/package.json b/packages/plugins/@nocobase/plugin-workflow-manual/package.json index 14b9cf530..9cad7b4da 100644 --- a/packages/plugins/@nocobase/plugin-workflow-manual/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-manual/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:人工处理节点", "description": "Could be used for workflows which some of decisions are made by users.", "description.zh-CN": "用于人工控制部分决策的流程。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-manual", diff --git a/packages/plugins/@nocobase/plugin-workflow-parallel/package.json b/packages/plugins/@nocobase/plugin-workflow-parallel/package.json index 1c38a7631..077f0d06e 100644 --- a/packages/plugins/@nocobase/plugin-workflow-parallel/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-parallel/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:并行分支节点", "description": "Could be used for parallel execution of branch processes in the workflow.", "description.zh-CN": "用于在工作流中需要并行执行的分支流程。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-parallel", diff --git a/packages/plugins/@nocobase/plugin-workflow-request/package.json b/packages/plugins/@nocobase/plugin-workflow-request/package.json index f2fcd1ce9..12183feed 100644 --- a/packages/plugins/@nocobase/plugin-workflow-request/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-request/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:HTTP 请求节点", "description": "Send HTTP requests to any HTTP service for data interaction in workflow.", "description.zh-CN": "可用于在工作流中向任意 HTTP 服务发送请求,进行数据交互。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-request", diff --git a/packages/plugins/@nocobase/plugin-workflow-sql/package.json b/packages/plugins/@nocobase/plugin-workflow-sql/package.json index 3ebe59232..cbf9f5d28 100644 --- a/packages/plugins/@nocobase/plugin-workflow-sql/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-sql/package.json @@ -4,7 +4,7 @@ "displayName.zh-CN": "工作流:SQL 节点", "description": "Execute SQL statements in workflow.", "description.zh-CN": "可用于在工作流中对数据库执行任意 SQL 语句。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow-sql", diff --git a/packages/plugins/@nocobase/plugin-workflow-test/package.json b/packages/plugins/@nocobase/plugin-workflow-test/package.json index ab4ecd319..9d590f0b6 100644 --- a/packages/plugins/@nocobase/plugin-workflow-test/package.json +++ b/packages/plugins/@nocobase/plugin-workflow-test/package.json @@ -2,7 +2,7 @@ "name": "@nocobase/plugin-workflow-test", "displayName": "Workflow: test kit", "displayName.zh-CN": "工作流:测试工具包", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "dist/server/index.js", "types": "./dist/server/index.d.ts", diff --git a/packages/plugins/@nocobase/plugin-workflow/package.json b/packages/plugins/@nocobase/plugin-workflow/package.json index 5bb7fa020..d431fbe14 100644 --- a/packages/plugins/@nocobase/plugin-workflow/package.json +++ b/packages/plugins/@nocobase/plugin-workflow/package.json @@ -4,13 +4,13 @@ "displayName.zh-CN": "工作流", "description": "A powerful BPM tool that provides foundational support for business automation, with the capability to extend unlimited triggers and nodes.", "description.zh-CN": "一个强大的 BPM 工具,为业务自动化提供基础支持,并且可任意扩展更多的触发器和节点。", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./dist/server/index.js", "homepage": "https://docs.nocobase.com/handbook/workflow", "homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/workflow", "dependencies": { - "@nocobase/plugin-workflow-test": "0.20.0-alpha.10" + "@nocobase/plugin-workflow-test": "0.20.0-alpha.12" }, "devDependencies": { "@ant-design/icons": "5.x", diff --git a/packages/presets/nocobase/package.json b/packages/presets/nocobase/package.json index 00eab188a..9ba782c4a 100644 --- a/packages/presets/nocobase/package.json +++ b/packages/presets/nocobase/package.json @@ -1,66 +1,66 @@ { "name": "@nocobase/preset-nocobase", - "version": "0.20.0-alpha.10", + "version": "0.20.0-alpha.12", "license": "AGPL-3.0", "main": "./lib/server/index.js", "dependencies": { "@formily/json-schema": "2.x", - "@nocobase/plugin-acl": "0.20.0-alpha.10", - "@nocobase/plugin-action-bulk-edit": "0.20.0-alpha.10", - "@nocobase/plugin-action-bulk-update": "0.20.0-alpha.10", - "@nocobase/plugin-action-duplicate": "0.20.0-alpha.10", - "@nocobase/plugin-action-print": "0.20.0-alpha.10", - "@nocobase/plugin-api-doc": "0.20.0-alpha.10", - "@nocobase/plugin-api-keys": "0.20.0-alpha.10", - "@nocobase/plugin-audit-logs": "0.20.0-alpha.10", - "@nocobase/plugin-auth": "0.20.0-alpha.10", - "@nocobase/plugin-backup-restore": "0.20.0-alpha.10", - "@nocobase/plugin-calendar": "0.20.0-alpha.10", - "@nocobase/plugin-cas": "0.20.0-alpha.10", - "@nocobase/plugin-charts": "0.20.0-alpha.10", - "@nocobase/plugin-china-region": "0.20.0-alpha.10", - "@nocobase/plugin-client": "0.20.0-alpha.10", - "@nocobase/plugin-collection-manager": "0.20.0-alpha.10", - "@nocobase/plugin-custom-request": "0.20.0-alpha.10", - "@nocobase/plugin-data-source-manager": "0.20.0-alpha.10", - "@nocobase/plugin-data-visualization": "0.20.0-alpha.10", - "@nocobase/plugin-error-handler": "0.20.0-alpha.10", - "@nocobase/plugin-export": "0.20.0-alpha.10", - "@nocobase/plugin-file-manager": "0.20.0-alpha.10", - "@nocobase/plugin-formula-field": "0.20.0-alpha.10", - "@nocobase/plugin-gantt": "0.20.0-alpha.10", - "@nocobase/plugin-graph-collection-manager": "0.20.0-alpha.10", - "@nocobase/plugin-iframe-block": "0.20.0-alpha.10", - "@nocobase/plugin-import": "0.20.0-alpha.10", - "@nocobase/plugin-kanban": "0.20.0-alpha.10", - "@nocobase/plugin-localization-management": "0.20.0-alpha.10", - "@nocobase/plugin-logger": "0.20.0-alpha.10", - "@nocobase/plugin-map": "0.20.0-alpha.10", - "@nocobase/plugin-mobile-client": "0.20.0-alpha.10", - "@nocobase/plugin-mock-collections": "0.20.0-alpha.10", - "@nocobase/plugin-multi-app-manager": "0.20.0-alpha.10", - "@nocobase/plugin-multi-app-share-collection": "0.20.0-alpha.10", - "@nocobase/plugin-oidc": "0.20.0-alpha.10", - "@nocobase/plugin-saml": "0.20.0-alpha.10", - "@nocobase/plugin-sequence-field": "0.20.0-alpha.10", - "@nocobase/plugin-sms-auth": "0.20.0-alpha.10", - "@nocobase/plugin-snapshot-field": "0.20.0-alpha.10", - "@nocobase/plugin-system-settings": "0.20.0-alpha.10", - "@nocobase/plugin-theme-editor": "0.20.0-alpha.10", - "@nocobase/plugin-ui-schema-storage": "0.20.0-alpha.10", - "@nocobase/plugin-users": "0.20.0-alpha.10", - "@nocobase/plugin-verification": "0.20.0-alpha.10", - "@nocobase/plugin-workflow": "0.20.0-alpha.10", - "@nocobase/plugin-workflow-action-trigger": "0.20.0-alpha.10", - "@nocobase/plugin-workflow-aggregate": "0.20.0-alpha.10", - "@nocobase/plugin-workflow-delay": "0.20.0-alpha.10", - "@nocobase/plugin-workflow-dynamic-calculation": "0.20.0-alpha.10", - "@nocobase/plugin-workflow-loop": "0.20.0-alpha.10", - "@nocobase/plugin-workflow-manual": "0.20.0-alpha.10", - "@nocobase/plugin-workflow-parallel": "0.20.0-alpha.10", - "@nocobase/plugin-workflow-request": "0.20.0-alpha.10", - "@nocobase/plugin-workflow-sql": "0.20.0-alpha.10", - "@nocobase/server": "0.20.0-alpha.10", + "@nocobase/plugin-acl": "0.20.0-alpha.12", + "@nocobase/plugin-action-bulk-edit": "0.20.0-alpha.12", + "@nocobase/plugin-action-bulk-update": "0.20.0-alpha.12", + "@nocobase/plugin-action-duplicate": "0.20.0-alpha.12", + "@nocobase/plugin-action-print": "0.20.0-alpha.12", + "@nocobase/plugin-api-doc": "0.20.0-alpha.12", + "@nocobase/plugin-api-keys": "0.20.0-alpha.12", + "@nocobase/plugin-audit-logs": "0.20.0-alpha.12", + "@nocobase/plugin-auth": "0.20.0-alpha.12", + "@nocobase/plugin-backup-restore": "0.20.0-alpha.12", + "@nocobase/plugin-calendar": "0.20.0-alpha.12", + "@nocobase/plugin-cas": "0.20.0-alpha.12", + "@nocobase/plugin-charts": "0.20.0-alpha.12", + "@nocobase/plugin-china-region": "0.20.0-alpha.12", + "@nocobase/plugin-client": "0.20.0-alpha.12", + "@nocobase/plugin-collection-manager": "0.20.0-alpha.12", + "@nocobase/plugin-custom-request": "0.20.0-alpha.12", + "@nocobase/plugin-data-source-manager": "0.20.0-alpha.12", + "@nocobase/plugin-data-visualization": "0.20.0-alpha.12", + "@nocobase/plugin-error-handler": "0.20.0-alpha.12", + "@nocobase/plugin-export": "0.20.0-alpha.12", + "@nocobase/plugin-file-manager": "0.20.0-alpha.12", + "@nocobase/plugin-formula-field": "0.20.0-alpha.12", + "@nocobase/plugin-gantt": "0.20.0-alpha.12", + "@nocobase/plugin-graph-collection-manager": "0.20.0-alpha.12", + "@nocobase/plugin-iframe-block": "0.20.0-alpha.12", + "@nocobase/plugin-import": "0.20.0-alpha.12", + "@nocobase/plugin-kanban": "0.20.0-alpha.12", + "@nocobase/plugin-localization-management": "0.20.0-alpha.12", + "@nocobase/plugin-logger": "0.20.0-alpha.12", + "@nocobase/plugin-map": "0.20.0-alpha.12", + "@nocobase/plugin-mobile-client": "0.20.0-alpha.12", + "@nocobase/plugin-mock-collections": "0.20.0-alpha.12", + "@nocobase/plugin-multi-app-manager": "0.20.0-alpha.12", + "@nocobase/plugin-multi-app-share-collection": "0.20.0-alpha.12", + "@nocobase/plugin-oidc": "0.20.0-alpha.12", + "@nocobase/plugin-saml": "0.20.0-alpha.12", + "@nocobase/plugin-sequence-field": "0.20.0-alpha.12", + "@nocobase/plugin-sms-auth": "0.20.0-alpha.12", + "@nocobase/plugin-snapshot-field": "0.20.0-alpha.12", + "@nocobase/plugin-system-settings": "0.20.0-alpha.12", + "@nocobase/plugin-theme-editor": "0.20.0-alpha.12", + "@nocobase/plugin-ui-schema-storage": "0.20.0-alpha.12", + "@nocobase/plugin-users": "0.20.0-alpha.12", + "@nocobase/plugin-verification": "0.20.0-alpha.12", + "@nocobase/plugin-workflow": "0.20.0-alpha.12", + "@nocobase/plugin-workflow-action-trigger": "0.20.0-alpha.12", + "@nocobase/plugin-workflow-aggregate": "0.20.0-alpha.12", + "@nocobase/plugin-workflow-delay": "0.20.0-alpha.12", + "@nocobase/plugin-workflow-dynamic-calculation": "0.20.0-alpha.12", + "@nocobase/plugin-workflow-loop": "0.20.0-alpha.12", + "@nocobase/plugin-workflow-manual": "0.20.0-alpha.12", + "@nocobase/plugin-workflow-parallel": "0.20.0-alpha.12", + "@nocobase/plugin-workflow-request": "0.20.0-alpha.12", + "@nocobase/plugin-workflow-sql": "0.20.0-alpha.12", + "@nocobase/server": "0.20.0-alpha.12", "cronstrue": "^2.11.0" }, "repository": { diff --git a/packages/presets/nocobase/src/client/index.ts b/packages/presets/nocobase/src/client/index.ts index 894bc6448..657f2a8a5 100644 --- a/packages/presets/nocobase/src/client/index.ts +++ b/packages/presets/nocobase/src/client/index.ts @@ -1,20 +1,22 @@ -import { NocoBaseBuildInPlugin, Plugin } from '@nocobase/client'; +import { Application, NocoBaseBuildInPlugin, Plugin } from '@nocobase/client'; const getCurrentTimezone = () => { const timezoneOffset = new Date().getTimezoneOffset() / -60; - const timezone = String(timezoneOffset).padStart(2, '0') + ':00'; + const timezone = String(Math.abs(timezoneOffset)).padStart(2, '0') + ':00'; return (timezoneOffset > 0 ? '+' : '-') + timezone; }; -function getBasename() { - const match = location.pathname.match(/^\/apps\/([^/]*)\//); - return match ? match[0] : '/'; +function getBasename(app: Application) { + const publicPath = app.getPublicPath(); + const pattern = `^${publicPath}apps/([^/]*)/`; + const match = location.pathname.match(new RegExp(pattern)); + return match ? match[0] : publicPath; } export class NocoBaseClientPresetPlugin extends Plugin { async afterAdd() { this.router.setType('browser'); - this.router.setBasename(getBasename()); + this.router.setBasename(getBasename(this.app)); this.app.apiClient.axios.interceptors.request.use((config) => { config.headers['X-Hostname'] = window?.location?.hostname; config.headers['X-Timezone'] = getCurrentTimezone(); diff --git a/storage/.gitignore b/storage/.gitignore index 3f29fa2b2..39489c602 100644 --- a/storage/.gitignore +++ b/storage/.gitignore @@ -1,4 +1,5 @@ .pm2 tmp app.watch.ts -/e2e \ No newline at end of file +/e2e +nocobase.conf diff --git a/yarn.lock b/yarn.lock index 535044d55..d2480f1a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12291,10 +12291,10 @@ dot-prop@^6.0.1: dependencies: is-obj "^2.0.0" -dotenv@^10.0.0: - version "10.0.0" - resolved "https://registry.npmmirror.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" - integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== +dotenv@^16.0.0: + version "16.4.5" + resolved "https://registry.npmmirror.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== dotignore@~0.1.2: version "0.1.2"