Merge branch 'develop' of github.com:nocobase/nocobase into feat-main-datasource-mssql

This commit is contained in:
aaaaaajie 2025-03-27 23:35:31 +08:00
commit 5ed00e912c
267 changed files with 3314 additions and 1536 deletions

View File

@ -5,6 +5,49 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v1.6.12](https://github.com/nocobase/nocobase/compare/v1.6.11...v1.6.12) - 2025-03-27
### 🐛 Bug Fixes
- **[Block: Multi-step form]**
- the submit button has the same color in its default and highlighted by @jiannx
- fixed the bug that form reset is invalid when the field is associated with other field by @jiannx
- **[Workflow: Approval]** Fix approval form values to submit by @mytharcher
## [v1.6.11](https://github.com/nocobase/nocobase/compare/v1.6.10...v1.6.11) - 2025-03-27
### 🚀 Improvements
- **[client]**
- Optimize 502 error message ([#6547](https://github.com/nocobase/nocobase/pull/6547)) by @chenos
- Only support plain text file to preview ([#6563](https://github.com/nocobase/nocobase/pull/6563)) by @mytharcher
- **[Collection field: Sequence]** support setting sequence as the title field for calendar block ([#6562](https://github.com/nocobase/nocobase/pull/6562)) by @katherinehhh
- **[Workflow: Approval]** Support to skip validator in settings by @mytharcher
### 🐛 Bug Fixes
- **[client]**
- issue with date field display in data scope filtering ([#6564](https://github.com/nocobase/nocobase/pull/6564)) by @katherinehhh
- The 'Ellipsis overflow content' option requires a page refresh for the toggle state to take effect ([#6520](https://github.com/nocobase/nocobase/pull/6520)) by @zhangzhonghe
- Unable to open another modal within a modal ([#6535](https://github.com/nocobase/nocobase/pull/6535)) by @zhangzhonghe
- **[API documentation]** API document page cannot scroll ([#6566](https://github.com/nocobase/nocobase/pull/6566)) by @zhangzhonghe
- **[Workflow]** Make sure workflow key is generated before save ([#6567](https://github.com/nocobase/nocobase/pull/6567)) by @mytharcher
- **[Workflow: Post-action event]** Multiple records in bulk action should trigger multiple times ([#6559](https://github.com/nocobase/nocobase/pull/6559)) by @mytharcher
- **[Authentication]** Localization issue for fields of sign up page ([#6556](https://github.com/nocobase/nocobase/pull/6556)) by @2013xile
- **[Public forms]** issue with public form page title displaying 'Loading...' ([#6569](https://github.com/nocobase/nocobase/pull/6569)) by @katherinehhh
## [v1.6.10](https://github.com/nocobase/nocobase/compare/v1.6.9...v1.6.10) - 2025-03-25
### 🐛 Bug Fixes

View File

@ -5,6 +5,49 @@
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。
## [v1.6.12](https://github.com/nocobase/nocobase/compare/v1.6.11...v1.6.12) - 2025-03-27
### 🐛 修复
- **[区块:分步表单]**
- 提交按钮默认和高亮情况下颜色一样 by @jiannx
- 修复当字段与其他表单字段存在关联时,表单重置无效 by @jiannx
- **[工作流:审批]** 修复审批表单提交值的问题 by @mytharcher
## [v1.6.11](https://github.com/nocobase/nocobase/compare/v1.6.10...v1.6.11) - 2025-03-27
### 🚀 优化
- **[client]**
- 优化 502 错误提示 ([#6547](https://github.com/nocobase/nocobase/pull/6547)) by @chenos
- 仅支持纯文本文件预览 ([#6563](https://github.com/nocobase/nocobase/pull/6563)) by @mytharcher
- **[数据表字段:自动编码]** 支持使用 sequence 作为日历区块的标题字段 ([#6562](https://github.com/nocobase/nocobase/pull/6562)) by @katherinehhh
- **[工作流:审批]** 支持审批处理按钮跳过表单验证的设置 by @mytharcher
### 🐛 修复
- **[client]**
- 数据范围中筛选日期字段显示异常 ([#6564](https://github.com/nocobase/nocobase/pull/6564)) by @katherinehhh
- 选项“省略超出长度的内容”需要刷新页面,开关的状态才生效 ([#6520](https://github.com/nocobase/nocobase/pull/6520)) by @zhangzhonghe
- 在弹窗中无法再次打开弹窗 ([#6535](https://github.com/nocobase/nocobase/pull/6535)) by @zhangzhonghe
- **[API 文档]** API 文档页面不能滚动 ([#6566](https://github.com/nocobase/nocobase/pull/6566)) by @zhangzhonghe
- **[工作流]** 确保创建工作流之前 key 已生成 ([#6567](https://github.com/nocobase/nocobase/pull/6567)) by @mytharcher
- **[工作流:操作后事件]** 多行记录的批量操作需要触发多次 ([#6559](https://github.com/nocobase/nocobase/pull/6559)) by @mytharcher
- **[用户认证]** 注册页面字段的本地化问题 ([#6556](https://github.com/nocobase/nocobase/pull/6556)) by @2013xile
- **[公开表单]** 公开表单页面标题不应该显示 Loading... ([#6569](https://github.com/nocobase/nocobase/pull/6569)) by @katherinehhh
## [v1.6.10](https://github.com/nocobase/nocobase/compare/v1.6.9...v1.6.10) - 2025-03-25
### 🐛 修复

View File

@ -1,5 +1,5 @@
{
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"npmClient": "yarn",
"useWorkspaces": true,
"npmClientArgs": ["--ignore-engines"],

View File

@ -1,13 +1,13 @@
{
"name": "@nocobase/acl",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"license": "AGPL-3.0",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"dependencies": {
"@nocobase/resourcer": "1.7.0-beta.9",
"@nocobase/utils": "1.7.0-beta.9",
"@nocobase/resourcer": "1.7.0-alpha.10",
"@nocobase/utils": "1.7.0-alpha.10",
"minimatch": "^5.1.1"
},
"repository": {

View File

@ -1,14 +1,14 @@
{
"name": "@nocobase/actions",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"license": "AGPL-3.0",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"dependencies": {
"@nocobase/cache": "1.7.0-beta.9",
"@nocobase/database": "1.7.0-beta.9",
"@nocobase/resourcer": "1.7.0-beta.9"
"@nocobase/cache": "1.7.0-alpha.10",
"@nocobase/database": "1.7.0-alpha.10",
"@nocobase/resourcer": "1.7.0-alpha.10"
},
"repository": {
"type": "git",

View File

@ -1,17 +1,17 @@
{
"name": "@nocobase/app",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"license": "AGPL-3.0",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"dependencies": {
"@nocobase/database": "1.7.0-beta.9",
"@nocobase/preset-nocobase": "1.7.0-beta.9",
"@nocobase/server": "1.7.0-beta.9"
"@nocobase/database": "1.7.0-alpha.10",
"@nocobase/preset-nocobase": "1.7.0-alpha.10",
"@nocobase/server": "1.7.0-alpha.10"
},
"devDependencies": {
"@nocobase/client": "1.7.0-beta.9"
"@nocobase/client": "1.7.0-alpha.10"
},
"repository": {
"type": "git",

View File

@ -1,16 +1,16 @@
{
"name": "@nocobase/auth",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"license": "AGPL-3.0",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"dependencies": {
"@nocobase/actions": "1.7.0-beta.9",
"@nocobase/cache": "1.7.0-beta.9",
"@nocobase/database": "1.7.0-beta.9",
"@nocobase/resourcer": "1.7.0-beta.9",
"@nocobase/utils": "1.7.0-beta.9",
"@nocobase/actions": "1.7.0-alpha.10",
"@nocobase/cache": "1.7.0-alpha.10",
"@nocobase/database": "1.7.0-alpha.10",
"@nocobase/resourcer": "1.7.0-alpha.10",
"@nocobase/utils": "1.7.0-alpha.10",
"@types/jsonwebtoken": "^8.5.8",
"jsonwebtoken": "^8.5.1"
},

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/build",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "Library build tool based on rollup.",
"main": "lib/index.js",
"types": "./lib/index.d.ts",

View File

@ -1,12 +1,12 @@
{
"name": "@nocobase/cache",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"license": "AGPL-3.0",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"dependencies": {
"@nocobase/lock-manager": "1.7.0-beta.9",
"@nocobase/lock-manager": "1.7.0-alpha.10",
"bloom-filters": "^3.0.1",
"cache-manager": "^5.2.4",
"cache-manager-redis-yet": "^4.1.2"

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/cli",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"license": "AGPL-3.0",
"main": "./src/index.js",
@ -8,7 +8,7 @@
"nocobase": "./bin/index.js"
},
"dependencies": {
"@nocobase/app": "1.7.0-beta.9",
"@nocobase/app": "1.7.0-alpha.10",
"@types/fs-extra": "^11.0.1",
"@umijs/utils": "3.5.20",
"chalk": "^4.1.1",
@ -25,7 +25,7 @@
"tsx": "^4.19.0"
},
"devDependencies": {
"@nocobase/devtools": "1.7.0-beta.9"
"@nocobase/devtools": "1.7.0-alpha.10"
},
"repository": {
"type": "git",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/client",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "lib/index.js",
"module": "es/index.mjs",
@ -27,9 +27,9 @@
"@formily/reactive-react": "^2.2.27",
"@formily/shared": "^2.2.27",
"@formily/validator": "^2.2.27",
"@nocobase/evaluators": "1.7.0-beta.9",
"@nocobase/sdk": "1.7.0-beta.9",
"@nocobase/utils": "1.7.0-beta.9",
"@nocobase/evaluators": "1.7.0-alpha.10",
"@nocobase/sdk": "1.7.0-alpha.10",
"@nocobase/utils": "1.7.0-alpha.10",
"ahooks": "^3.7.2",
"antd": "5.24.2",
"antd-style": "3.7.1",

View File

@ -48,6 +48,7 @@ interface INocoBaseRecursionFieldProps extends IRecursionFieldProps {
* Whether to use Formily Field class - performance will be reduced but provides better compatibility with Formily
*/
isUseFormilyField?: boolean;
parentSchema?: Schema;
}
const CollectionFieldUISchemaContext = React.createContext<CollectionFieldOptions>({});
@ -266,6 +267,7 @@ export const NocoBaseRecursionField: ReactFC<INocoBaseRecursionFieldProps> = Rea
values,
isUseFormilyField = true,
uiSchema,
parentSchema,
} = props;
const basePath = useBasePath(props);
const newFieldSchemaRef = useRef(null);
@ -279,6 +281,14 @@ export const NocoBaseRecursionField: ReactFC<INocoBaseRecursionFieldProps> = Rea
const fieldSchema: Schema = newFieldSchemaRef.current || oldFieldSchema;
// Establish connection with the Schema tree
if (!fieldSchema.parent && parentSchema) {
fieldSchema.parent = parentSchema;
if (!fieldSchema.parent?.properties?.[fieldSchema.name] && fieldSchema.name) {
_.set(fieldSchema.parent, `properties.${fieldSchema.name}`, fieldSchema);
}
}
const refresh = useCallback(() => {
const parent = fieldSchema.parent;
newFieldSchemaRef.current = new Schema(fieldSchema.toJSON(), parent);

View File

@ -1,5 +1,7 @@
{
"Display <1><0>10</0><1>20</1><2>50</2><3>100</3></1> items per page": "Toon <1><0>10</0><1>20</1><2>50</2><3>100</3></1> items per pagina",
"Page number": "Paginanummer",
"Page size": "Paginagrootte",
"Meet <1><0>All</0><1>Any</1></1> conditions in the group": "Voldoe aan <1><0>Alle</0><1>Een</1></1> voorwaarde(n) in de groep",
"Open in<1><0>Modal</0><1>Drawer</1><2>Window</2></1>": "Open in<1><0>Modal</0><1>Drawer</1><2>Venster</2></1>",
"{{count}} filter items": "{{count}} filter items",
@ -38,15 +40,20 @@
"Unconnected": "Niet verbonden",
"System settings": "Systeeminstellingen",
"System title": "Systeemtitel",
"Setting" : "Instelling",
"Settings": "Instellingen",
"Enable": "Inschakelen",
"Disable": "Uitschakelen",
"On": "Aan",
"Off": "Uit",
"Logo": "Logo",
"Add menu item": "Menu-item toevoegen",
"Page": "Pagina",
"Tab": "Tab",
"Name": "Naam",
"Icon": "Icoon",
"Group": "Groep",
"Link": "Link",
"Tab": "Tab",
"Save conditions": "Voorwaarden opslaan",
"Edit menu item": "Menu-item bewerken",
"Move to": "Verplaats naar",
@ -82,9 +89,6 @@
"Disabled": "Uitgeschakeld",
"Enabled": "Ingeschakeld",
"Problematic": "Problematisch",
"Setting": "Instelling",
"On": "Aan",
"Off": "Uit",
"Empty": "Leeg",
"Linkage rule": "Koppelingregel",
"Linkage rules": "Koppelingregels",
@ -434,7 +438,7 @@
"Allow linking to multiple records": "Koppelen aan meerdere records toestaan",
"Allow uploading multiple files": "Meerdere bestanden uploaden toestaan",
"Configure calendar": "Kalender configureren",
"Title field": "Titelfeld",
"Title field": "Titelveld",
"Custom title": "Aangepaste titel",
"Daily": "Dagelijks",
"Weekly": "Wekelijks",
@ -884,5 +888,171 @@
"If selected, the page will display Tab pages.": "Indien geselecteerd, worden tabbladen op de pagina weergegeven.",
"If selected, the route will be displayed in the menu.": "Indien geselecteerd, wordt de route weergegeven in het menu.",
"Are you sure you want to hide this tab?": "Weet je zeker dat je dit tabblad wil verbergen?",
"After hiding, this tab will no longer appear in the tab bar. To show it again, you need to go to the route management page to set it.": "Na verbergen wordt dit tabblad niet meer weergegeven in de tabbalk. Om het opnieuw te tonen, moet je naar de routebeheerpagina gaan om het in te stellen."
}
"After hiding, this tab will no longer appear in the tab bar. To show it again, you need to go to the route management page to set it.": "Na verbergen wordt dit tabblad niet meer weergegeven in de tabbalk. Om het opnieuw te tonen, moet je naar de routebeheerpagina gaan om het in te stellen.",
"Calculation engine": "Berekeningsengine",
"Expression collection": "Expressiecollectie",
"Tree collection": "Boomcollectie",
"Parent ID": "Ouder-ID",
"Parent": "Ouder",
"Children": "Kinderen",
"Confirm": "Bevestigen",
"Block": "Blok",
"Unnamed": "Naamloos",
"SQL collection": "SQL-collectie",
"Configure field": "Veld configureren",
"Username": "Gebruikersnaam",
"Null": "Leeg",
"Boolean": "Boolean",
"String": "Tekst",
"Syntax references": "Syntax-referenties",
"Math.js comes with a large set of built-in functions and constants, and offers an integrated solution to work with different data types.": "Math.js wordt geleverd met een groot aantal ingebouwde functies en constanten en biedt een geïntegreerde oplossing om met verschillende gegevenstypen te werken.",
"Formula.js supports most Microsoft Excel formula functions.": "Formula.js ondersteunt de meeste Microsoft Excel-formulefuncties.",
"String template": "Tekstsjabloon",
"Simple string replacement, can be used to interpolate variables in a string.": "Eenvoudige tekstvervanging, kan worden gebruikt om variabelen in een tekst te interpoleren.",
"https://docs.nocobase.com/handbook/calculation-engines/formula": "https://docs.nocobase.com/handbook/calculation-engines/formula",
"https://docs.nocobase.com/handbook/calculation-engines/mathjs": "https://docs.nocobase.com/handbook/calculation-engines/mathjs",
"Display <icon></icon> when unchecked": "Toon <icon></icon> wanneer niet aangevinkt",
"Allow dissociate": "Loskoppelen toestaan",
"Edit block title & description": "Blok titel & beschrijving bewerken",
"Add Markdown": "Markdown toevoegen",
"Must be 1-50 characters in length (excluding @.<>\"'/)": "Moet 1-50 tekens lang zijn (exclusief @.<>\"'/)",
"Original title: ": "Originele titel: ",
"Original field title: ": "Originele veldtitel: ",
"Data source permissions": "Datatoegangsrechten",
"Now": "Nu",
"Access control": "Toegangscontrole",
"Remove": "Verwijderen",
"Docs": "Documentatie",
"Enable page header": "Paginahoofd inschakelen",
"Display page title": "Paginatitel weergeven",
"Edit page title": "Paginatitel bewerken",
"Enable page tabs": "Pagina-tabbladen inschakelen",
"Constant": "Constant",
"Select a variable": "Selecteer een variabele",
"Double click to choose entire object": "Dubbelklik om het hele object te kiezen",
"TRUE": "WAAR",
"FALSE": "ONWAAR",
"Prettify": "Opknappen",
"Theme": "Thema",
"Default theme": "Standaardthema",
"Compact theme": "Compact thema",
"Download": "Downloaden",
"File type is not supported for previewing, please download it to preview.": "Bestandstype wordt niet ondersteund voor voorbeeldweergave, download het om te bekijken.",
"Click or drag file to this area to upload": "Klik of sleep een bestand naar dit gebied om te uploaden.",
"Support for a single or bulk upload.": "Ondersteuning voor enkele of bulk-upload.",
"File size should not exceed {{size}}.": "Bestandsgrootte mag {{size}} niet overschrijden.",
"File size exceeds the limit": "Bestandsgrootte overschrijdt de limiet.",
"File type is not allowed": "Bestandstype is niet toegestaan.",
"Incomplete uploading files need to be resolved": "Onvolledig geüploade bestanden moeten worden opgelost.",
"Default title for each record": "Standaardtitel voor elk record.",
"If collection inherits, choose inherited collections as templates": "Als de collectie overerft, kies geërfde collecties als sjablonen.",
"Select an existing piece of data as the initialization data for the form": "Selecteer een bestaand gegeven als initiële data voor het formulier.",
"Only the selected fields will be used as the initialization data for the form": "Alleen de geselecteerde velden worden gebruikt als initiële data voor het formulier.",
"Template Data": "Sjabloongegevens",
"Data fields": "Gegevensvelden",
"Add template": "Sjabloon toevoegen",
"Enable form data template": "Formuliersjabloon inschakelen",
"Form data templates": "Formuliersjablonen",
"No configuration available.": "Geen configuratie beschikbaar.",
"Reload application": "Herlaad applicatie",
"The application is reloading, please do not close the page.": "De applicatie wordt opnieuw geladen, sluit de pagina niet.",
"Application reloading": "Applicatie wordt opnieuw geladen",
"Allows to clear cache, reboot application": "Sta toe om cache te wissen en applicatie te herstarten.",
"The will interrupt service, it may take a few seconds to restart. Are you sure to continue?": "Dit onderbreekt de service en kan enkele seconden duren. Weet je zeker dat je wilt doorgaan?",
"Clear cache": "Cache wissen",
"Are you sure you want to clear cache ?": "Weet je zeker dat je de cache wilt wissen?",
"Quick create": "Snel aanmaken",
"Dropdown": "Keuzelijst",
"Pop-up": "Pop-up",
"Direct duplicate": "Direct dupliceren",
"Copy into the form and continue to fill in": "Kopieer in het formulier en vul verder in.",
"Failed to load plugin": "Kan plug-in niet laden.",
"Date range limit": "Datumbereiklimiet",
"MinDate": "Minimale datum",
"MaxDate": "Maximale datum",
"Please select time or variable": "Selecteer een tijd of variabele.",
"Filter out a single piece or a group of records as a template": "Filter een enkel item of een groep records als sjabloon.",
"The title field is used to identify the template record": "Het titelveld wordt gebruikt om het sjabloonrecord te identificeren.",
"Template fields": "Sjabloonvelden",
"The selected fields will automatically populate the form": "De geselecteerde velden vullen automatisch het formulier in.",
"UnSelect all": "Alles deselecteren",
"Secondary confirmation": "Secundaire bevestiging",
"Perform the {{title}}": "Voer {{title}} uit.",
"Are you sure you want to perform the {{title}} action?": "Weet je zeker dat je de actie {{title}} wilt uitvoeren?",
"Permission denied": "Toestemming geweigerd.",
"Allow add new": "Sta toe om nieuw toe te voegen.",
"Data model": "Gegevensmodel",
"Security": "Beveiliging",
"Action": "Actie",
"System": "Systeem",
"Other": "Overige",
"Allow selection of existing records": "Sta selectie van bestaande records toe.",
"Data Model": "Gegevensmodel",
"Blocks": "Blokken",
"Users & permissions": "Gebruikers en machtigingen",
"System management": "Systeembeheer",
"System & security": "Systeem en beveiliging",
"Workflow": "Werkstroom",
"Third party services": "Diensten van derden",
"Data model tools": "Gegevensmodeltools",
"Data sources": "Gegevensbronnen",
"Collections": "Collecties",
"Collection fields": "Collectievelden",
"Authentication": "Authenticatie",
"Logging and monitoring": "Logging en monitoring",
"Main": "Hoofd",
"Index": "Index",
"Field values must be unique.": "Veldwaarden moeten uniek zijn.",
"Alphabet": "Alfabet",
"Accuracy": "Nauwkeurigheid",
"Millisecond": "Milliseconde",
"Second": "Seconde",
"Unix Timestamp": "Unix-tijdstempel",
"Field value do not meet the requirements": "Veldwaarde voldoet niet aan de vereisten.",
"Field value size is": "Veldwaardegrootte is",
"Unit conversion": "Eenheidsconversie",
"Separator": "Scheidingsteken",
"Prefix": "Voorvoegsel",
"Suffix": "Achtervoegsel",
"Record unique key": "Unieke recordsleutel",
"Filter target key": "Filterdoelsleutel",
"If a collection lacks a primary key, you must configure a unique record key to locate row records within a block, failure to configure this will prevent the creation of data blocks for the collection.": "Als een collectie geen primaire sleutel heeft, moet je een unieke recordsleutel configureren om rijen binnen een blok te lokaliseren. Anders kunnen er geen gegevensblokken worden aangemaakt.",
"Filter data based on the specific field, with the requirement that the field value must be unique.": "Filter gegevens op basis van een specifiek veld, waarbij de veldwaarde uniek moet zijn.",
"Multiply by": "Vermenigvuldigen met",
"Divide by": "Delen door",
"Scientifix notation": "Wetenschappelijke notatie",
"Normal": "Normaal",
"Automatically generate default values": "Automatisch standaardwaarden genereren.",
"Refresh data on close": "Ververs gegevens bij sluiten.",
"Refresh data on action": "Ververs gegevens bij actie.",
"Unknown field type": "Onbekend veldtype.",
"The following field types are not compatible and do not support output and display": "De volgende veldtypen zijn niet compatibel en ondersteunen geen uitvoer en weergave.",
"Not fixed": "Niet vastgezet",
"Left fixed": "Links vastgezet",
"Right fixed": "Rechts vastgezet",
"Fixed": "Vastgezet",
"Set block height": "Blokhoogte instellen",
"Specify height": "Hoogte specificeren",
"Full height": "Volledige hoogte",
"Please configure the URL": "Configureer de URL.",
"URL": "URL",
"Search parameters": "Zoekparameters",
"Do not concatenate search params in the URL": "Voeg zoekparameters niet samen in de URL.",
"Edit link": "Link bewerken",
"Add parameter": "Parameter toevoegen",
"Use simple pagination mode": "Gebruik eenvoudige paginering",
"Set Template Engine": "Sjabloonengine instellen",
"Template engine": "Sjabloonengine",
"Table size": "Tabelgrootte",
"No data": "Geen data",
"Show file name": "Toon bestandsnaam",
"Filled": "Gevuld",
"Enable index column": "Indexkolom inschakelen",
"Icon only": "Enkel icoon",
"Valid range: 100-900": "Geldige waarde: 100-900",
"Valid range: 10-40": "Geldige waarde: 10-40",
"Font Sizepx": "Lettergroottepx",
"Font Weight": "Letterdikte",
"Font Style": "Letterstijl",
"Italic": "Cursief"
}

View File

@ -8,6 +8,7 @@
*/
import { useField, useFieldSchema } from '@formily/react';
import _ from 'lodash';
import { useTranslation } from 'react-i18next';
import { useBlockContext, useOpenModeContext } from '../../../../';
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
@ -45,11 +46,12 @@ export const ellipsisSettingsItem: SchemaSettingsItemType = {
tableFieldInstanceList.forEach((fieldInstance) => {
fieldInstance.componentProps.ellipsis = checked;
});
schema['x-component-props']['ellipsis'] = checked;
} else {
formField.componentProps.ellipsis = checked;
}
_.set(schema, 'x-component-props.ellipsis', checked);
await dn.emit('patch', {
schema: {
'x-uid': schema['x-uid'],

View File

@ -88,7 +88,7 @@ const dividerTheme = {
},
};
export const PinnedPluginList = React.memo(() => {
export const PinnedPluginList = React.memo((props: { onClick?: () => void }) => {
const { allowAll, snippets } = useACLRoleContext();
const getSnippetsAllow = (aclKey) => {
return allowAll || aclKey === '*' || snippets?.includes(aclKey);
@ -98,6 +98,7 @@ export const PinnedPluginList = React.memo(() => {
return (
<div className={pinnedPluginListClassName}>
<div onClick={props.onClick}>
{Object.keys(ctx.items)
.sort((a, b) => ctx.items[a].order - ctx.items[b].order)
.filter((key) => getSnippetsAllow(ctx.items[key].snippet))
@ -105,6 +106,7 @@ export const PinnedPluginList = React.memo(() => {
const Action = get(components, ctx.items[key].component);
return Action ? <Action key={key} /> : null;
})}
</div>
<ConfigProvider theme={dividerTheme}>
<Divider type="vertical" />
</ConfigProvider>

View File

@ -12,6 +12,7 @@ import ProLayout, { RouteContext, RouteContextType } from '@ant-design/pro-layou
import { HeaderViewProps } from '@ant-design/pro-layout/es/components/Header';
import { css } from '@emotion/css';
import { theme as antdTheme, ConfigProvider, Popover, Tooltip } from 'antd';
import { createStyles } from 'antd-style';
import React, { createContext, FC, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import { Link, Navigate, Outlet, useLocation, useNavigate } from 'react-router-dom';
@ -52,7 +53,6 @@ import { KeepAlive } from './KeepAlive';
import { NocoBaseDesktopRoute, NocoBaseDesktopRouteType } from './convertRoutesToSchema';
import { MenuSchemaToolbar, ResetThemeTokenAndKeepAlgorithm } from './menuItemSettings';
import { userCenterSettings } from './userCenterSettings';
import { createGlobalStyle, createStyles } from 'antd-style';
export { KeepAlive, NocoBaseDesktopRouteType };
@ -155,10 +155,7 @@ const layoutContentClass = css`
display: flex;
flex-direction: column;
position: relative;
/* 基础高度(所有浏览器支持) */
height: calc(100vh - var(--nb-header-height));
/* 动态视口高度(现代浏览器支持) */
height: calc(100dvh - var(--nb-header-height));
> div {
position: relative;
}
@ -202,10 +199,29 @@ const pageContentStyle: React.CSSProperties = {
overflowY: 'auto',
};
// 移动端中需要使用 dvh 单位来计算高度,否则会出现滚动不到最底部的问题
const mobileHeight = {
height: `calc(100dvh - var(--nb-header-height))`,
};
function isDvhSupported() {
// 创建一个测试元素
const testEl = document.createElement('div');
// 尝试设置 dvh 单位
testEl.style.height = '1dvh';
// 如果浏览器支持 dvh则会解析这个值
// 如果不支持height 将保持为空字符串或被设置为无效值
return testEl.style.height === '1dvh';
}
export const LayoutContent = () => {
const style = useMemo(() => (isDvhSupported() ? mobileHeight : undefined), []);
/* Use the "nb-subpages-slot-without-header-and-side" class name to locate the position of the subpages */
return (
<div className={`${layoutContentClass} nb-subpages-slot-without-header-and-side`}>
<div className={`${layoutContentClass} nb-subpages-slot-without-header-and-side`} style={style}>
<div style={pageContentStyle}>
<Outlet />
</div>
@ -418,9 +434,22 @@ const popoverStyle = css`
const MobileActions: FC = (props) => {
const { token } = useToken();
const [open, setOpen] = useState(false);
// 点击时立即关闭 Popover避免影响用户操作
const handleContentClick = useCallback(() => {
setOpen(false);
}, []);
return (
<Popover rootClassName={popoverStyle} content={<PinnedPluginList />} color={token.colorBgHeader}>
<Popover
rootClassName={popoverStyle}
content={<PinnedPluginList onClick={handleContentClick} />}
color={token.colorBgHeader}
trigger="click"
open={open}
onOpenChange={setOpen}
>
<div style={{ padding: '0 16px', display: 'flex', alignItems: 'center', height: '100%', marginRight: -16 }}>
<EllipsisOutlined
style={{
@ -602,7 +631,7 @@ export const InternalAdminLayout = () => {
paddingPageVertical: 8, // Vertical page padding
marginBlock: 12, // Spacing between blocks
borderRadiusBlock: 8, // Block border radius
fontSize: 14, // Font size
fontSize: 16, // Font size
},
algorithm: isDarkTheme ? [antdTheme.compactAlgorithm, antdTheme.darkAlgorithm] : antdTheme.compactAlgorithm, // Set mobile mode to always use compact algorithm
};

View File

@ -69,6 +69,11 @@ export const filterAnalyses = (filters): any[] => {
return results;
};
function getFieldPath(str) {
const lastIndex = str.lastIndexOf('.');
return lastIndex === -1 ? str : str.slice(0, lastIndex);
}
const InternalAssociationSelect = observer(
(props: AssociationSelectProps) => {
const { objectValue = true, addMode: propsAddMode, ...rest } = props;
@ -100,11 +105,14 @@ const InternalAssociationSelect = observer(
//支持深层次子表单
onFieldInputValueChange('*', (fieldPath: any) => {
const linkageFields = filterAnalyses(field.componentProps?.service?.params?.filter) || [];
const linageFieldEntire = getFieldPath(fieldPath.address.entire);
const targetFieldEntire = getFieldPath(field.address.entire);
if (
linkageFields.includes(fieldPath?.props?.name) &&
field.value &&
isEqual(fieldPath?.indexes, field?.indexes) &&
fieldPath?.props?.name !== field.props.name
fieldPath?.props?.name !== field.props.name &&
(!field?.indexes?.length || isEqual(linageFieldEntire, targetFieldEntire))
) {
field.setValue(null);
setInnerValue(null);

View File

@ -273,7 +273,8 @@ const InternalPagePopups = (props: { paramsList?: PopupParams[] }) => {
);
});
const schemas = await Promise.all(waitList);
const clonedSchemas = schemas.map((schema, index) => {
const clonedSchemas = await Promise.all(
schemas.map(async (schema, index) => {
if (_.isEmpty(schema)) {
return get404Schema();
}
@ -284,6 +285,16 @@ const InternalPagePopups = (props: { paramsList?: PopupParams[] }) => {
const popupSchema = findSchemaByUid(params.puid, fieldSchema?.root);
if (popupSchema) {
savePopupSchemaToSchema(_.omit(popupSchema, 'parent'), schema);
} else {
// 当本地找不到 popupSchema 时,通过接口请求 puid 对应的 schema
try {
const remoteSchema = await requestSchema(params.puid);
if (remoteSchema) {
savePopupSchemaToSchema(remoteSchema, schema);
}
} catch (error) {
console.error('Failed to fetch schema for puid:', params.puid, error);
}
}
}
@ -297,7 +308,8 @@ const InternalPagePopups = (props: { paramsList?: PopupParams[] }) => {
result['x-read-pretty'] = true;
return result;
});
}),
);
popupPropsRef.current = clonedSchemas.map((schema, index, items) => {
const schemaContext = getPopupContextFromActionOrAssociationFieldSchema(schema);
let hidden = false;

View File

@ -89,7 +89,7 @@ attachmentFileTypes.add({
},
});
const iframePreviewSupportedTypes = ['application/pdf', 'audio/*', 'image/*', 'video/*', 'text/*'];
const iframePreviewSupportedTypes = ['application/pdf', 'audio/*', 'image/*', 'video/*', 'text/plain'];
function IframePreviewer({ index, list, onSwitchIndex }) {
const { t } = useTranslation();

View File

@ -8,7 +8,7 @@
*/
import { createForm } from '@formily/core';
import { Schema } from '@formily/react';
import { Schema, useFieldSchema } from '@formily/react';
import { Spin } from 'antd';
import React, { memo, useMemo } from 'react';
import { useRemoteCollectionManagerLoading } from '../../collection-manager/CollectionManagerProvider';
@ -62,6 +62,7 @@ const RequestSchemaComponent: React.FC<RemoteSchemaComponentProps> = (props) =>
});
const NotFoundComponent = useComponent(NotFoundPage);
const collectionManagerLoading = useRemoteCollectionManagerLoading();
const parentSchema = useFieldSchema();
if (collectionManagerLoading || loading || hidden) {
return <Spin style={{ width: '100%', marginTop: 20 }} delay={LOADING_DELAY} />;
@ -73,10 +74,20 @@ const RequestSchemaComponent: React.FC<RemoteSchemaComponentProps> = (props) =>
}
return noForm ? (
<SchemaComponent components={components} scope={scope} schema={schemaTransform(schema || {})} />
<SchemaComponent
components={components}
scope={scope}
schema={schemaTransform(schema || {})}
parentSchema={parentSchema}
/>
) : (
<FormProvider form={form}>
<SchemaComponent components={components} scope={scope} schema={schemaTransform(schema || {})} />
<SchemaComponent
components={components}
scope={scope}
schema={schemaTransform(schema || {})}
parentSchema={parentSchema}
/>
</FormProvider>
);
};

View File

@ -28,6 +28,7 @@ function toSchema(schema?: any) {
properties: {
[schema.name]: schema,
},
name: `p_${schema.name}`,
});
}
return new Schema(schema);
@ -52,8 +53,9 @@ interface DistributedProps {
*/
export const SchemaComponentOnChangeContext = createContext<SchemaComponentOnChange>({ onChange: _.noop });
const RecursionSchemaComponent = memo((props: ISchemaFieldProps & SchemaComponentOnChange & DistributedProps) => {
const { components, scope, schema: _schema, distributed, onChange: _onChange, ...others } = props;
const RecursionSchemaComponent = memo(
(props: ISchemaFieldProps & SchemaComponentOnChange & DistributedProps & { parentSchema?: Schema }) => {
const { components, scope, schema: _schema, distributed, onChange: _onChange, parentSchema, ...others } = props;
const ctx = useContext(SchemaComponentContext);
const schema = useMemo(() => toSchema(_schema), [_schema]);
const value = useMemo(
@ -84,26 +86,32 @@ const RecursionSchemaComponent = memo((props: ISchemaFieldProps & SchemaComponen
<SchemaComponentOnChangeContext.Provider value={onChangeValue}>
<SchemaComponentContext.Provider value={value}>
<SchemaComponentOptions inherit components={components} scope={scope}>
<NocoBaseRecursionField {...others} schema={schema} isUseFormilyField />
<NocoBaseRecursionField {...others} schema={schema} isUseFormilyField parentSchema={parentSchema} />
</SchemaComponentOptions>
</SchemaComponentContext.Provider>
</SchemaComponentOnChangeContext.Provider>
);
});
},
);
RecursionSchemaComponent.displayName = 'RecursionSchemaComponent';
const MemoizedSchemaComponent = memo((props: ISchemaFieldProps & SchemaComponentOnChange & DistributedProps) => {
const { schema, ...others } = props;
const MemoizedSchemaComponent = memo(
(props: ISchemaFieldProps & SchemaComponentOnChange & DistributedProps & { parentSchema?: Schema }) => {
const { schema, parentSchema, ...others } = props;
const s = useMemoizedSchema(schema);
return <RecursionSchemaComponent {...others} schema={s} />;
});
return <RecursionSchemaComponent {...others} schema={s} parentSchema={parentSchema} />;
},
);
MemoizedSchemaComponent.displayName = 'MemoizedSchemaComponent';
export const SchemaComponent = memo(
(
props: (ISchemaFieldProps | IRecursionFieldProps) & { memoized?: boolean } & SchemaComponentOnChange &
props: (ISchemaFieldProps | IRecursionFieldProps) & {
memoized?: boolean;
parentSchema?: Schema;
} & SchemaComponentOnChange &
DistributedProps,
) => {
const { memoized, ...others } = props;

View File

@ -1,6 +1,6 @@
{
"name": "create-nocobase-app",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "src/index.js",
"license": "AGPL-3.0",
"dependencies": {

View File

@ -1,16 +1,16 @@
{
"name": "@nocobase/data-source-manager",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"license": "AGPL-3.0",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"dependencies": {
"@nocobase/actions": "1.7.0-beta.9",
"@nocobase/cache": "1.7.0-beta.9",
"@nocobase/database": "1.7.0-beta.9",
"@nocobase/resourcer": "1.7.0-beta.9",
"@nocobase/utils": "1.7.0-beta.9",
"@nocobase/actions": "1.7.0-alpha.10",
"@nocobase/cache": "1.7.0-alpha.10",
"@nocobase/database": "1.7.0-alpha.10",
"@nocobase/resourcer": "1.7.0-alpha.10",
"@nocobase/utils": "1.7.0-alpha.10",
"@types/jsonwebtoken": "^8.5.8",
"jsonwebtoken": "^8.5.1"
},

View File

@ -1,13 +1,13 @@
{
"name": "@nocobase/database",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"license": "AGPL-3.0",
"dependencies": {
"@nocobase/logger": "1.7.0-beta.9",
"@nocobase/utils": "1.7.0-beta.9",
"@nocobase/logger": "1.7.0-alpha.10",
"@nocobase/utils": "1.7.0-alpha.10",
"async-mutex": "^0.3.2",
"chalk": "^4.1.1",
"cron-parser": "4.4.0",

View File

@ -1,13 +1,13 @@
{
"name": "@nocobase/devtools",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"license": "AGPL-3.0",
"main": "./src/index.js",
"dependencies": {
"@nocobase/build": "1.7.0-beta.9",
"@nocobase/client": "1.7.0-beta.9",
"@nocobase/test": "1.7.0-beta.9",
"@nocobase/build": "1.7.0-alpha.10",
"@nocobase/client": "1.7.0-alpha.10",
"@nocobase/test": "1.7.0-alpha.10",
"@types/koa": "^2.15.0",
"@types/koa-bodyparser": "^4.3.4",
"@types/lodash": "^4.14.177",

View File

@ -1,13 +1,13 @@
{
"name": "@nocobase/evaluators",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"license": "AGPL-3.0",
"dependencies": {
"@formulajs/formulajs": "4.4.9",
"@nocobase/utils": "1.7.0-beta.9",
"@nocobase/utils": "1.7.0-alpha.10",
"mathjs": "^10.6.0"
},
"repository": {

View File

@ -1,10 +1,10 @@
{
"name": "@nocobase/lock-manager",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "lib/index.js",
"license": "AGPL-3.0",
"devDependencies": {
"@nocobase/utils": "1.7.0-beta.9",
"@nocobase/utils": "1.7.0-alpha.10",
"async-mutex": "^0.5.0"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/logger",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "nocobase logging library",
"license": "AGPL-3.0",
"main": "./lib/index.js",

View File

@ -1,12 +1,12 @@
{
"name": "@nocobase/resourcer",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"license": "AGPL-3.0",
"dependencies": {
"@nocobase/utils": "1.7.0-beta.9",
"@nocobase/utils": "1.7.0-alpha.10",
"deepmerge": "^4.2.2",
"koa-compose": "^4.1.0",
"lodash": "^4.17.21",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/sdk",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "lib/index.js",
"types": "lib/index.d.ts",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/server",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "lib/index.js",
"types": "./lib/index.d.ts",
"license": "AGPL-3.0",
@ -10,19 +10,19 @@
"@koa/cors": "^5.0.0",
"@koa/multer": "^3.0.2",
"@koa/router": "^9.4.0",
"@nocobase/acl": "1.7.0-beta.9",
"@nocobase/actions": "1.7.0-beta.9",
"@nocobase/auth": "1.7.0-beta.9",
"@nocobase/cache": "1.7.0-beta.9",
"@nocobase/data-source-manager": "1.7.0-beta.9",
"@nocobase/database": "1.7.0-beta.9",
"@nocobase/evaluators": "1.7.0-beta.9",
"@nocobase/lock-manager": "1.7.0-beta.9",
"@nocobase/logger": "1.7.0-beta.9",
"@nocobase/resourcer": "1.7.0-beta.9",
"@nocobase/sdk": "1.7.0-beta.9",
"@nocobase/telemetry": "1.7.0-beta.9",
"@nocobase/utils": "1.7.0-beta.9",
"@nocobase/acl": "1.7.0-alpha.10",
"@nocobase/actions": "1.7.0-alpha.10",
"@nocobase/auth": "1.7.0-alpha.10",
"@nocobase/cache": "1.7.0-alpha.10",
"@nocobase/data-source-manager": "1.7.0-alpha.10",
"@nocobase/database": "1.7.0-alpha.10",
"@nocobase/evaluators": "1.7.0-alpha.10",
"@nocobase/lock-manager": "1.7.0-alpha.10",
"@nocobase/logger": "1.7.0-alpha.10",
"@nocobase/resourcer": "1.7.0-alpha.10",
"@nocobase/sdk": "1.7.0-alpha.10",
"@nocobase/telemetry": "1.7.0-alpha.10",
"@nocobase/utils": "1.7.0-alpha.10",
"@types/decompress": "4.2.7",
"@types/ini": "^1.3.31",
"@types/koa-send": "^4.1.3",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/telemetry",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"description": "nocobase telemetry library",
"license": "AGPL-3.0",
"main": "./lib/index.js",
@ -11,7 +11,7 @@
"directory": "packages/telemetry"
},
"dependencies": {
"@nocobase/utils": "1.7.0-beta.9",
"@nocobase/utils": "1.7.0-alpha.10",
"@opentelemetry/api": "^1.7.0",
"@opentelemetry/instrumentation": "^0.46.0",
"@opentelemetry/resources": "^1.19.0",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/test",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "lib/index.js",
"module": "./src/index.ts",
"types": "./lib/index.d.ts",
@ -51,7 +51,7 @@
},
"dependencies": {
"@faker-js/faker": "8.1.0",
"@nocobase/server": "1.7.0-beta.9",
"@nocobase/server": "1.7.0-alpha.10",
"@playwright/test": "^1.45.3",
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.0.0",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/utils",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "lib/index.js",
"types": "./lib/index.d.ts",
"license": "AGPL-3.0",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "权限控制",
"description": "Based on roles, resources, and actions, access control can precisely manage interface configuration permissions, data operation permissions, menu access permissions, and plugin permissions.",
"description.zh-CN": "基于角色、资源和操作的权限控制,可以精确控制界面配置权限、数据操作权限、菜单访问权限、插件权限。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/acl",

View File

@ -1,7 +1,11 @@
{
"The current user has no roles. Please try another account.": "De huidige gebruiker heeft geen rol. Probeer een andere gebruikersaccount.",
"The user role does not exist. Please try signing in again": "De gebruikersrol bestaat niet. Probeer opnieuw in te loggen.",
"Roles & Permissions": "Rollen & Permissies",
"General": "Algemeen",
"New role": "Nieuwe rol",
"Permissions": "Permissies",
"Desktop menu": "Desktop menu"
"Desktop menu": "Desktop menu",
"Plugin settings": "Plugin instellingen",
"Data sources": "Data bronnen"
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-action-bulk-edit",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"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",

View File

@ -1,4 +1,5 @@
{
"Bulk edit": "Bewerken in bulk",
"Data will be updated": "Gegevens worden bijgewerkt"
"Data will be updated": "Gegevens worden bijgewerkt",
"Entire collection": "Gehele collectie"
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-action-bulk-update",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"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",

View File

@ -1,5 +1,6 @@
{
"Bulk update": "Updaten in bulk",
"After successful bulk update": "Na succesvolle update in bulk",
"Please select the records to be updated": "Selecteer de records die moeten worden bijgewerkt"
"Please select the records to be updated": "Selecteer de records die moeten worden bijgewerkt",
"Entire collection": "Gehele collectie"
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-action-custom-request",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"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",

View File

@ -0,0 +1,27 @@
{
"Access control": "Toegangscontrole",
"Custom Request": "Aangepaste aanvraag",
"Request settings": "Aanvraaginstellingen",
"Roles": "Rollen",
"If not set, all roles can see this action": "Als niet ingesteld, kunnen alle rollen deze actie zien",
"Title": "Titel",
"HTTP method": "HTTP-methode",
"URL": "URL",
"Headers": "Kopteksten",
"Parameters": "Parameters",
"Add request header": "Voeg aanvraagkop toe",
"Add parameter": "Voeg parameter toe",
"Enter description info": "Voer beschrijvingsinformatie in",
"Body": "Inhoud",
"Use variable": "Gebruik variabele",
"Format": "Formaat",
"Insert": "Invoegen",
"Timeout config": "Time-outconfiguratie",
"ms": "ms",
"Input request data": "Voer aanvraaggegevens in",
"Only support standard JSON data": "Ondersteunt alleen standaard JSON-gegevens",
"\"Content-Type\" only support \"application/json\", and no need to specify": "\"Content-Type\" ondersteunt alleen \"application/json\", en hoeft niet te worden gespecificeerd",
"When the HTTP method is Post, Put or Patch, and this custom request inside the form, the request body will be automatically filled in with the form data": "Wanneer de HTTP-methode Post, Put of Patch is, en deze aangepaste aanvraag zich binnen het formulier bevindt, wordt de aanvraaginhoud automatisch ingevuld met de formuliergegevens",
"Please configure the request settings first": "Configureer eerst de aanvraaginstellingen"
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-action-duplicate",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-duplicate",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-duplicate",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "操作:导出记录",
"description": "Export filtered records to excel, you can configure which fields to export.",
"description.zh-CN": "导出筛选后的记录到 Excel 中,可以配置导出哪些字段。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-export",

View File

@ -1,6 +1,7 @@
{
"Export warning": "Je kunt maximaal {{limit}} rijen gegevens tegelijk exporteren, eventuele overschrijdingen worden genegeerd.",
"Start export": "Start exporteren",
"another export action is running, please try again later.": "Er is al een andere exportactie bezig, probeer het later opnieuw.",
"True": "Waar",
"False": "Onwaar"
}

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "操作:导入记录",
"description": "Import records using excel templates. You can configure which fields to import and templates will be generated automatically.",
"description.zh-CN": "使用 Excel 模板导入数据,可以配置导入哪些字段,自动生成模板。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-import",

View File

@ -1,42 +1,50 @@
{
"Only one file is allowed to be uploaded": "Only one file is allowed to be uploaded",
"File size cannot exceed 10M": "File size cannot exceed 10M",
"Please upload the file of Excel": "Please upload the file of Excel",
"Import Data": "Import Data",
"Start import": "Start import",
"Import explain": "Guide",
"Download template": "Download template",
"Step 1: Download template": "Step 1: Download template",
"Step 2: Upload Excel": "Step 2: Upload Excel",
"Step 3: Import options": "Step 3: Import options",
"Download tips": "- Download the template and fill in the data according to the format \r\n - Import only the first worksheet \r\n - Do not change the header of the template to prevent import failure",
"Import warnings": "You can import up to {{limit}} rows of data at a time, any excess will be ignored.",
"Upload placeholder": "Drag and drop the file here or click to upload, file size should not exceed 80M",
"Excel data importing": "Excel data importing",
"{{successCount}} records have been successfully imported": "{{successCount}} records have been successfully imported",
"To download the failure data": "To download the failure data",
"Add importable field": "Add importable field",
"Only one file is allowed to be uploaded": "Er kan slechts één bestand worden geüpload",
"File size cannot exceed 10M": "Bestandsgrootte mag niet groter zijn dan 10M",
"Please upload the file of Excel": "Upload het Excel-bestand",
"Import Data": "Importeer gegevens",
"Start import": "Start importeren",
"Import explain": "Uitleg",
"Download template": "Download sjabloon",
"Step 1: Download template": "Stap 1: Download sjabloon",
"Step 2: Upload Excel": "Stap 2: Upload Excel",
"Step 3: Import options": "Stap 3: Importeer opties",
"Download tips": "- Download het sjabloon en vul de gegevens in volgens het formaat\r\n - Importeer alleen het eerste werkblad\r\n - Wijzig de sjabloontitel niet om importfouten te voorkomen",
"Import warnings": "Maximaal {{limit}} rijen gegevens kunnen tegelijk worden geïmporteerd, eventuele overschrijdingen worden genegeerd.",
"Upload placeholder": "Sleep het bestand hierheen of klik om te uploaden, bestandsgrootte niet groter dan 80M",
"Excel data importing": "Gegevens importeren, sluit het venster niet",
"{{successCount}} records have been successfully imported": "{{successCount}} records zijn succesvol geïmporteerd",
"To download the failure data": "Download de gegevens die niet konden worden geïmporteerd",
"Add importable field": "Voeg een importeerbaar veld toe",
"Done": "Klaar",
"Yes": "Ja",
"No": "Nee",
"Field {{fieldName}} does not exist": "Field {{fieldName}} does not exist",
"can not find value": "can not find value",
"password is empty": "password is empty",
"Incorrect time format": "Incorrect time format",
"Incorrect date format": "Incorrect date format",
"Incorrect email format": "Incorrect email format",
"Illegal percentage format": "Illegal percentage format",
"Imported template does not match, please download again.": "Imported template does not match, please download again.",
"another import action is running, please try again later.": "another import action is running, please try again later.",
"Please select": "Please select",
"Field {{fieldName}} does not exist": "Veld {{fieldName}} bestaat niet",
"can not find value": "Kan de waarde niet vinden",
"password is empty": "Wachtwoord is leeg",
"Incorrect time format": "Onjuist tijdsformaat",
"Incorrect date format": "Onjuist datumformaat",
"Incorrect email format": "Onjuist e-mailformaat",
"Illegal percentage format": "Ongeldig percentageformaat",
"Imported template does not match, please download again.": "Het geïmporteerde sjabloon komt niet overeen, download het opnieuw.",
"another import action is running, please try again later.": "Er is al een andere importactie bezig, probeer het later opnieuw.",
"Please select": "Selecteer",
"Custom column title": "Aangepaste kolomtitel",
"Field description": "Field description",
"Field description placeholder": "Enter field description",
"Columns configuration is empty": "Columns configuration is empty",
"Field not found: {{field}}": "Field not found: {{field}}",
"Headers not found. Expected headers: {{headers}}": "Headers not found. Expected headers: {{headers}}",
"Header mismatch at column {{column}}: expected \"{{expected}}\", but got \"{{actual}}\"": "Header mismatch at column {{column}}: expected \"{{expected}}\", but got \"{{actual}}\"",
"No data to import": "No data to import",
"Failed to import row {{row}}, {{message}}, row data: {{data}}": "Failed to import row {{row}}, {{message}}, row data: {{data}}",
"import-error": "Failed to import row {{rowIndex}}, row data: {{rowData}}, cause: {{causeMessage}}"
"Field description": "Veldbeschrijving",
"Field description placeholder": "Voer de veldbeschrijving in",
"Columns configuration is empty": "Kolomconfiguratie is leeg",
"Field not found: {{field}}": "Veld niet gevonden: {{field}}",
"Headers not found. Expected headers: {{headers}}": "Kopteksten niet gevonden. Verwachte kopteksten: {{headers}}",
"Header mismatch at column {{column}}: expected \"{{expected}}\", but got \"{{actual}}\"": "Koptekst komt niet overeen in kolom {{column}}: verwachtte \"{{expected}}\", maar kreeg \"{{actual}}\"",
"No data to import": "Geen gegevens om te importeren",
"Failed to import row {{row}}, {{message}}, row data: {{data}}": "Fout bij importeren van rij {{row}}, {{message}}, rijgegevens: {{data}}",
"import-error": "Fout bij importeren van rij {{rowIndex}}, rijgegevens: {{rowData}}, reden: {{causeMessage}}",
"Import completed": "Importeren voltooid: {{success}} records zijn geïmporteerd, {{updated}} records zijn bijgewerkt, {{skipped}} records zijn overgeslagen, totaal {{total}} records",
"Successfully imported": "Succesvol geïmporteerd",
"Updated records": "Bijgewerkte records",
"Skipped records": "Overgeslagen records",
"Total records": "Totaal aantal records",
"View result": "Bekijk resultaat",
"ImportResult": "{{success}} records zijn geïmporteerd, {{updated}} records zijn bijgewerkt, {{skipped}} records zijn overgeslagen, totaal {{total}} records",
"Task result": "Taakresultaat"
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-action-print",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/action-print",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/action-print",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "AI 集成",
"description": "Support integration with AI services, providing AI-related workflow nodes to enhance business processing capabilities.",
"description.zh-CN": "支持接入 AI 服务,提供 AI 相关的工作流节点,增强业务处理能力。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "dist/server/index.js",
"peerDependencies": {
"@nocobase/client": "1.x",

View File

@ -0,0 +1,26 @@
{
"AI integration": "AI integratie",
"LLM services": "LLM diensten",
"LLM service": "LLM dienst",
"Model": "Model",
"Messages": "Berichten",
"Structured output": "Gestructureerde output",
"Message": "Bericht",
"Role": "Rol",
"UID": "UID",
"Add content": "Voeg inhoud toe",
"Add prompt": "Voeg prompt toe",
"Provider": "Provider",
"Text": "Tekst",
"Image": "Afbeelding",
"Timout (ms)": "Timout (ms)",
"Max retries": "Max herhalingen",
"Frequency penalty description": "Nummer tussen -2.0 en 2.0. Positieve waarden straffen nieuwe tokens op basis van hun bestaande frequentie in de tekst tot nu toe, waardoor de kans van het model om dezelfde regel letterlijk te herhalen afneemt.",
"Max completion tokens description": "Een bovengrens voor het aantal tokens dat kan worden gegenereerd voor een voltooiing, inclusief zichtbare outputtokens en redeneertokens.",
"Presence penalty description": "Nummer tussen -2.0 en 2.0. Positieve waarden straffen nieuwe tokens op basis van of ze tot nu toe in de tekst voorkomen, waardoor de kans van het model om over nieuwe onderwerpen te praten toeneemt.",
"Response format description": "Belangrijk: bij gebruik van de JSON-modus moet u het model ook zelf opdracht geven om JSON te produceren via een systeem- of gebruikersbericht.",
"Temperature description": "Welke bemonsteringstemperatuur te gebruiken, tussen 0 en 2. Hogere waarden zoals 0,8 maken de output willekeuriger, terwijl lagere waarden zoals 0,2 deze meer gefocust en deterministisch maken.",
"Top P description": "Een alternatief voor bemonstering met temperatuur, genaamd nucleusbemonstering, waarbij het model de resultaten van de tokens met top_p waarschijnlijkheidsmassa overweegt. Dus 0,1 betekent dat alleen de tokens die de top 10% waarschijnlijkheidsmassa vormen, worden overwogen.",
"Get models list failed, you can enter a model name manually.": "Het ophalen van de lijst met modellen is mislukt, u kunt een modelnaam handmatig invoeren."
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-api-doc",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"displayName": "API documentation",
"displayName.zh-CN": "API 文档",
"description": "An OpenAPI documentation generator for NocoBase HTTP API.",

View File

@ -67,6 +67,8 @@ const Documentation = () => {
direction="vertical"
style={{
width: '100%',
height: '100%',
overflowY: 'auto',
}}
>
<div

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "认证API 密钥",
"description": "Allows users to use API key to access application's HTTP API",
"description.zh-CN": "允许用户使用 API 密钥访问应用的 HTTP API",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/api-keys",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "异步任务管理器",
"description": "Manage and monitor asynchronous tasks such as data import/export. Support task progress tracking and notification.",
"description.zh-CN": "管理和监控数据导入导出等异步任务。支持任务进度跟踪和通知。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "dist/server/index.js",
"peerDependencies": {
"@nocobase/client": "1.x",

View File

@ -1,5 +1,46 @@
{
"Export {collection} attachments": "Exporteer {collection} bijlages",
"Export {collection} data": "Exporteer {collection} data",
"Import {collection} data": "Importeer {collection} data"
}
"Export": "Exporteer",
"Import": "Importeer",
"Data": "Data",
"Task": "Taak",
"Status": "Status",
"Actions": "Acties",
"Created at": "Aangemaakt op",
"Type": "Type",
"Waiting": "Wachten",
"Processing": "Verwerken",
"Completed": "Voltooid",
"Failed": "Mislukt",
"Cancelled": "Geannuleerd",
"Cancel": "Annuleren",
"Cancelling": "Annuleren",
"Download": "Downloaden",
"Error details": "Foutdetails",
"Confirm cancel": "Bevestig annuleren",
"Confirm cancel description": "Weet je zeker dat je deze taak wilt annuleren?",
"Confirm": "Bevestigen",
"Task cancelled": "Taak geannuleerd",
"Task completed": "Taak voltooid",
"Task failed": "Taak mislukt",
"Error Details": "Foutdetails",
"Close": "Sluiten",
"Error code": "Foutcode",
"Unknown error": "Onbekende fout",
"OK": "OK",
"Import result": "Importresultaat",
"Import completed": "Import voltooid: {{success}} records geïmporteerd, {{updated}} records bijgewerkt, {{skipped}} records overgeslagen, totaal {{total}} records",
"Import summary": "Importeer {{success}}/{{total}}",
"Import details": "{{success}} records zijn geïmporteerd, {{updated}} records zijn bijgewerkt, {{skipped}} records zijn overgeslagen, totaal {{total}} records",
"Imported": "{{count}}/{{total}}",
"Successfully imported": "Succesvol geïmporteerd",
"Updated records": "Bijgewerkte records",
"Skipped records": "Overgeslagen records",
"Total records": "Totaal aantal records",
"View result": "Toon",
"ImportResult": "{{success}} records zijn geïmporteerd, {{updated}} records zijn bijgewerkt, {{skipped}} records zijn overgeslagen, totaal {{total}} records",
"Task result": "Taakresultaat",
"Export {collection} attachments": "Exporteer {collection} bijlagen",
"Export {collection} data": "Exporteer {collection} gegevens",
"Import {collection} data": "Importeer {collection} gegevens"
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-audit-logs",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"displayName": "Audit logs (deprecated)",
"displayName.zh-CN": "审计日志(废弃)",
"description": "This plugin is deprecated. There will be a new audit log plugin in the future.",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "认证:短信",
"description": "SMS authentication.",
"description.zh-CN": "通过短信验证码认证身份。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/auth-sms",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth-sms",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-auth",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/auth",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/auth",

View File

@ -8,7 +8,7 @@
*/
import { SchemaComponent } from '@nocobase/client';
import { ISchema } from '@formily/react';
import { ISchema, Schema } from '@formily/react';
import React, { useMemo } from 'react';
import { uid } from '@formily/shared';
import { useAuthTranslation } from '../locale';
@ -122,6 +122,7 @@ const getSignupPageSchema = (fieldSchemas: any): ISchema => ({
export const SignUpForm = ({ authenticatorName: name }: { authenticatorName: string }) => {
const { t } = useAuthTranslation();
const { t: fieldT } = useTranslation('lm-collections');
const useBasicSignUp = () => {
return useSignUp({ authenticator: name });
};
@ -132,8 +133,12 @@ export const SignUpForm = ({ authenticatorName: name }: { authenticatorName: str
return signupForm
.filter((field: { show: boolean }) => field.show)
.reduce((prev: any, item: { field: string; required: boolean; uiSchema: any }) => {
prev[item.field] = {
const uiSchema = {
...item.uiSchema,
title: item.uiSchema.title ? fieldT(Schema.compile(item.uiSchema.title, { t })) : '',
};
prev[item.field] = {
...uiSchema,
required: item.required,
'x-decorator': 'FormItem',
};

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "应用的备份与还原(废弃)",
"description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.",
"description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/backup-restore",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "区块iframe",
"description": "Create an iframe block on the page to embed and display external web pages or content.",
"description.zh-CN": "在页面上创建和管理iframe用于嵌入和展示外部网页或内容。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/block-iframe",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "区块:模板",
"description": "Create and manage block templates for reuse on pages.",
"description.zh-CN": "创建和管理区块模板,用于在页面中重复使用。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/block-template",

View File

@ -169,8 +169,6 @@ export class PluginBlockTemplateClient extends Plugin {
'blockSettings:createForm',
'blockSettings:details',
'blockSettings:detailsWithPagination',
'blockSettings:multiDataDetails',
'blockSettings:singleDataDetails',
'blockSettings:stepsForm',
'blockSettings:filterCollapse',
'blockSettings:filterForm',

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-block-workbench",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"displayName": "Block: Action panel",
"displayName.zh-CN": "区块:操作面板",
"description": "Centrally manages and displays various actions, allowing users to efficiently perform tasks. It supports extensibility, with current action types including pop-ups, links, scanning, and custom requests.",

View File

@ -122,6 +122,7 @@ const useStyles = createStyles(({ token, css }) => ({
margin: -12px -32px;
width: calc(100% + 64px);
text-align: start;
justify-content: start !important;
color: ${token.colorText};
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-calendar",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"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.",

View File

@ -0,0 +1,56 @@
{
"Configure calendar": "Kalender configureren",
"Title field": "Titelveld",
"Custom title": "Aangepaste titel",
"Show lunar": "Maankalender weergeven",
"Start date field": "Startdatumveld",
"End date field": "Einddatumveld",
"Work week": "Werkweek",
"Today": "Vandaag",
"Day": "Dag",
"Agenda": "Agenda",
"Date": "Datum",
"Time": "Tijd",
"Event": "Gebeurtenis",
"None": "Geen",
"Calendar": "Kalender",
"Delete events": "Gebeurtenissen verwijderen",
"This event": "Dit evenement",
"This and following events": "Dit en volgende evenementen",
"All events": "Alle evenementen",
"Delete this event?": "Dit evenement verwijderen?",
"Delete Event": "Evenement verwijderen",
"Calendar collection": "Kalendercollectie",
"Create calendar block": "Kalenderblok maken",
"Filter": "Filter",
"Configure actions": "Acties configureren",
"Enable actions": "Acties inschakelen",
"Turn pages": "Bladeren",
"Select view": "Weergave selecteren",
"Add new": "Nieuw toevoegen",
"View record": "Record bekijken",
"Details": "Details",
"Customize": "Aanpassen",
"Update record": "Record bijwerken",
"Popup": "Popup",
"Updated successfully": "Succesvol bijgewerkt",
"Custom request": "Aangepast verzoek",
"Edit": "Bewerken",
"Delete": "Verwijderen",
"Print": "Afdrukken",
"Daily": "Dagelijks",
"Weekly": "Wekelijks",
"Monthly": "Maandelijks",
"Yearly": "Jaarlijks",
"Repeats": "Herhaalt",
"Title": "Titel",
"Month": "Maand",
"Week": "Week",
"{{count}} more items": "{{count}} meer items",
"Color field": "Kleurveld",
"Not selected": "Niet geselecteerd",
"Default view": "Standaardweergave",
"Event open mode": "Gebeurtenis openen modus",
"Quick create event": "Snel evenement maken"
}

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "图表(废弃)",
"description": "The plugin has been deprecated, please use the data visualization plugin instead.",
"description.zh-CN": "已废弃插件,请使用数据可视化插件代替。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "./dist/server/index.js",
"license": "AGPL-3.0",
"devDependencies": {

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "WEB 客户端",
"description": "Provides a client interface for the NocoBase server",
"description.zh-CN": "为 NocoBase 服务端提供客户端界面",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "./dist/server/index.js",
"license": "AGPL-3.0",
"devDependencies": {

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据表: SQL",
"description": "Provides SQL collection template",
"description.zh-CN": "提供 SQL 数据表模板",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"homepage": "https://docs-cn.nocobase.com/handbook/collection-sql",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/collection-sql",
"main": "dist/server/index.js",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-collection-tree",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"displayName": "Collection: Tree",
"displayName.zh-CN": "数据表:树",
"description": "Provides tree collection template",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据源:主数据库",
"description": "NocoBase main database, supports relational databases such as PostgreSQL, MySQL, MariaDB and so on.",
"description.zh-CN": "NocoBase 主数据库,支持 PostgreSQL、MySQL、MariaDB 等关系型数据库。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"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",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-data-source-manager",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "dist/server/index.js",
"displayName": "Data source manager",
"displayName.zh-CN": "数据源管理",

View File

@ -0,0 +1,41 @@
{
"Data source name": "Databron naam",
"Data source display name": "Databron weergavenaam",
"Host": "Host",
"Port": "Poort",
"Database": "Database",
"Data source manager": "Databron manager",
"Data sources": "Databronnen",
"No external data source plugin installed": "Geen externe databron plugin geïnstalleerd",
"View documentation": "Bekijk documentatie",
"Test Connection": "Test verbinding",
"Connection successful": "Verbinding succesvol",
"Display name": "Weergavenaam",
"Username": "Gebruikersnaam",
"Password": "Wachtwoord",
"Type": "Type",
"Description": "Beschrijving",
"Storage": "Opslag",
"Collections": "Collecties",
"Permissions": "Rechten",
"Allow adding and modifying collection": "Toestaan toevoegen en wijzigen collectie",
"Unknown field type": "Onbekend veldtype",
"The following field types are not compatible and do not support output and display": "De volgende veldtypen zijn niet compatibel en ondersteunen geen uitvoer en weergave",
"Field database type": "Veld database type",
"Field interface": "Veld interface",
"Status": "Status",
"Loading": "Laden",
"Failed": "Mislukt",
"Loaded": "Geladen",
"Reloading": "Herladen",
"Data source synchronization in progress": "Databron synchronisatie in uitvoering",
"Data source synchronization successful": "Databron synchronisatie succesvol",
"Filter target key":"Filter doel sleutel",
"Select field": "Selecteer veld",
"OK": "OK",
"Please select a field.": "Selecteer een veld.",
"Are you sure you want to set the \"{{title}}\" field as a record unique key? This setting cannot be changed after it's been set.": "Weet je zeker dat je het veld \"{{title}}\" als een unieke sleutel wilt instellen? Deze instelling kan niet worden gewijzigd nadat deze is ingesteld.",
"If a collection lacks a primary key, you must configure a unique record key to locate row records within a block, failure to configure this will prevent the creation of data blocks for the collection.": "Als een collectie geen primaire sleutel heeft, moet je een unieke record sleutel configureren om rijrecords binnen een blok te lokaliseren, het niet configureren hiervan zal de creatie van datablokken voor de collectie voorkomen.",
"Filter data based on the specific field, with the requirement that the field value must be unique.": "Filter gegevens op basis van het specifieke veld, met de eis dat de veldwaarde uniek moet zijn."
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-data-visualization",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"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.",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-disable-pm-add",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "./dist/server/index.js",
"peerDependencies": {
"@nocobase/client": "1.x",

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-environment-variables",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "dist/server/index.js",
"peerDependencies": {
"@nocobase/client": "1.x",

View File

@ -10,9 +10,18 @@ import { DeleteOutlined, DownOutlined, PlusOutlined, ReloadOutlined } from '@ant
import { Checkbox, FormButtonGroup, FormItem, FormLayout, Input, Radio, Reset, Submit } from '@formily/antd-v5';
import { registerValidateRules } from '@formily/core';
import { createSchemaField, useField } from '@formily/react';
import { SchemaComponent, SchemaComponentOptions, useAPIClient, FormDrawer, useGlobalTheme } from '@nocobase/client';
import {
SchemaComponent,
SchemaComponentOptions,
useAPIClient,
FormDrawer,
useGlobalTheme,
removeNullCondition,
} from '@nocobase/client';
import { useLocation } from 'react-router-dom';
import { Alert, App, Button, Card, Dropdown, Flex, Space, Table, Tag } from 'antd';
import React, { useContext, useState } from 'react';
import React, { useContext, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { VAR_NAME_RE } from '../../re';
import { EnvAndSecretsContext } from '../EnvironmentVariablesAndSecretsProvider';
import { useT } from '../locale';
@ -258,6 +267,13 @@ export function EnvironmentTabs() {
const [selectRowKeys, setSelectRowKeys] = useState([]);
const resource = api.resource('environmentVariables');
const { theme } = useGlobalTheme();
const location = useLocation();
useEffect(() => {
const { run, params } = variablesRequest;
if (params?.length) {
run();
}
}, [location.key]);
const handleBulkImport = async (importData) => {
const arr = Object.entries(importData).map(([type, dataString]) => {
return parseKeyValuePairs(dataString, type).filter(Boolean);
@ -359,13 +375,20 @@ export function EnvironmentTabs() {
const useFilterActionProps = () => {
const field = useField<any>();
const { run } = variablesRequest;
const { t } = useTranslation();
return {
options: filterOptions,
onSubmit: async (values) => {
run(values);
field.setValue(values);
const filter = removeNullCondition(values?.filter);
const items = filter?.$and || filter?.$or;
if (items?.length) {
field.title = t('{{count}} filter items', { count: items?.length || 0 });
} else {
field.title = t('Filter');
}
},
onReset: (values) => {
field.setValue(values);
@ -407,7 +430,7 @@ export function EnvironmentTabs() {
$and: [{ name: { $includes: '' } }],
},
'x-component': 'Filter.Action',
'x-component-props': { icon: 'FilterOutlined' },
enum: filterOptions,
'x-use-component-props': useFilterActionProps,
}}

View File

@ -0,0 +1,17 @@
{
"Environment": "Omgeving",
"Variables and secrets": "Variabelen en geheimen",
"Variables": "Variabelen",
"Secrets": "Geheimen",
"Add variable": "Variabele toevoegen",
"Bulk import": "Bulk importeren",
"Name": "Naam",
"Value": "Waarde",
"Type": "Type",
"Plain text": "Tekst",
"Encrypted": "Versleuteld",
"Delete variable": "Variabele verwijderen",
"Restart now": "Nu herstarten",
"Variables and secrets have been updated. A restart is required for the changes to take effect.": "Variabelen en geheimen zijn bijgewerkt. Een herstart is vereist voor de wijzigingen om van kracht te worden."
}

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "错误处理器",
"description": "Handling application errors and exceptions.",
"description.zh-CN": "处理应用程序中的错误和异常。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "./dist/server/index.js",
"devDependencies": {

View File

@ -1,6 +1,5 @@
{
"unique violation": "{{field}} bestaat al",
"notNull violation": "{{field}} mag niet leeg zijn",
"Validation error": "{{field}} validatiefout",
"notNull Violation": "{{field}} mag niet leeg zijn"
"Validation error": "{{field}} validatiefout"
}

View File

@ -1,6 +1,6 @@
{
"name": "@nocobase/plugin-field-china-region",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"displayName": "Collection field: administrative divisions of China",
"displayName.zh-CN": "数据表字段:中国行政区划",
"description": "Provides data and field type for administrative divisions of China.",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据表字段:公式",
"description": "Configure and store the results of calculations between multiple field values in the same record, supporting both Math.js and Excel formula functions.",
"description.zh-CN": "可以配置并存储同一条记录的多字段值之间的计算结果,支持 Math.js 和 Excel formula functions 两种引擎",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/field-formula",

View File

@ -4,5 +4,6 @@
"Expression": "Expressie",
"Expression syntax error": "Fout in expressiesyntax",
"Syntax references": "Syntaxverwijzingen",
"Compute a value based on the other fields": "Bereken een waarde op basis van de andere velden"
"Compute a value based on the other fields": "Bereken een waarde op basis van de andere velden",
"Configure and store the results of calculations between multiple field values in the same record, supporting both Math.js and Excel formula functions.": "Configureer en sla de resultaten op van berekeningen tussen meerdere veldwaarden in hetzelfde record, met ondersteuning voor zowel Math.js als Excel-formulefuncties."
}

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据表字段:多对多 (数组)",
"description": "Allows to create many to many relationships between two models by storing an array of unique keys of the target model.",
"description.zh-CN": "支持通过在数组中存储目标表唯一键的方式建立多对多关系。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"main": "dist/server/index.js",
"peerDependencies": {
"@nocobase/client": "1.x",

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据表字段Markdown(Vditor)",
"description": "Used to store Markdown and render it using Vditor editor, supports common Markdown syntax such as list, code, quote, etc., and supports uploading images, recordings, etc.It also allows for instant rendering, where what you see is what you get.",
"description.zh-CN": "用于存储 Markdown并使用 Vditor 编辑器渲染,支持常见 Markdown 语法,如列表,代码,引用等,并支持上传图片,录音等。同时可以做到即时渲染,所见即所得。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/field-markdown-vditor",

View File

@ -7,10 +7,12 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { useAPIClient, useApp, withDynamicSchemaProps } from '@nocobase/client';
import { useAPIClient, useCompile, usePlugin, withDynamicSchemaProps } from '@nocobase/client';
import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Vditor from 'vditor';
import { defaultToolbar } from '../interfaces/markdown-vditor';
import { NAMESPACE } from '../locale';
import { useCDN } from './const';
import useStyle from './style';
@ -24,11 +26,15 @@ export const Edit = withDynamicSchemaProps((props) => {
const vdFullscreen = useRef(false);
const containerRef = useRef<HTMLDivElement>(null);
const containerParentRef = useRef<HTMLDivElement>(null);
const app = useApp();
const apiClient = useAPIClient();
const cdn = useCDN();
const { wrapSSR, hashId, componentCls: containerClassName } = useStyle();
const locale = apiClient.auth.locale || 'en-US';
const fileManagerPlugin: any = usePlugin('@nocobase/plugin-file-manager');
const compile = useCompile();
const compileRef = useRef(compile);
compileRef.current = compile;
const { t } = useTranslation();
const lang: any = useMemo(() => {
const currentLang = locale.replace(/-/g, '_');
@ -41,7 +47,6 @@ export const Edit = withDynamicSchemaProps((props) => {
useEffect(() => {
if (!containerRef.current) return;
const uploadFileCollection = fileCollection || 'attachments';
const toolbarConfig = toolbar ?? defaultToolbar;
const vditor = new Vditor(containerRef.current, {
@ -68,24 +73,63 @@ export const Edit = withDynamicSchemaProps((props) => {
onChange(value);
},
upload: {
url: app.getApiUrl(`${uploadFileCollection}:create`),
headers: apiClient.getHeaders(),
multiple: false,
fieldName: 'file',
max: 1024 * 1024 * 1024, // 1G
format(files, responseText) {
const response = JSON.parse(responseText);
const formatResponse = {
msg: '',
code: 0,
data: {
errFiles: [],
succMap: {
[response.data.filename]: response.data.url,
},
},
};
return JSON.stringify(formatResponse);
async handler(files: File[]) {
const file = files[0];
// Need to ensure focus is in the current input box before uploading
vditor.focus();
const { data: checkData } = await apiClient.resource('vditor').check({
fileCollectionName: fileCollection,
});
if (!checkData?.data?.isSupportToUploadFiles) {
vditor.tip(
t('vditor.uploadError.message', { ns: NAMESPACE, storageTitle: checkData.data.storage?.title }),
0,
);
return;
}
vditor.tip(t('uploading'), 0);
const { data, errorMessage } = await fileManagerPlugin.uploadFile({
file,
fileCollectionName: fileCollection,
storageId: checkData?.data?.storage?.id,
storageType: checkData?.data?.storage?.type,
storageRules: checkData?.data?.storage?.rules,
});
if (errorMessage) {
vditor.tip(compileRef.current(errorMessage), 3000);
return;
}
if (!data) {
vditor.tip(t('Response data is empty', { ns: NAMESPACE }), 3000);
return;
}
const fileName = data.filename;
const fileUrl = data.url;
// Check if the uploaded file is an image
const isImage = file.type.startsWith('image/');
if (isImage) {
// Insert as an image - will be displayed in the editor
vditor.insertValue(`![${fileName}](${fileUrl})`);
} else {
// For non-image files, insert as a download link
vditor.insertValue(`[${fileName}](${fileUrl})`);
}
// hide the tip
vditor.tip(t(''), 10);
return null;
},
},
});
@ -94,7 +138,8 @@ export const Edit = withDynamicSchemaProps((props) => {
vdRef.current?.destroy();
vdRef.current = undefined;
};
}, [fileCollection, toolbar?.join(',')]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [toolbar?.join(',')]);
useEffect(() => {
if (editorReady && vdRef.current) {
@ -155,7 +200,7 @@ export const Edit = withDynamicSchemaProps((props) => {
return wrapSSR(
<div ref={containerParentRef} className={`${hashId} ${containerClassName}`}>
<div id={hashId} ref={containerRef}></div>
<div ref={containerRef}></div>
</div>,
);
});

View File

@ -7,9 +7,9 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ISchema } from '@formily/react';
import { CollectionFieldInterface, interfacesProperties } from '@nocobase/client';
import { generateNTemplate } from '../locale';
import { ISchema } from '@formily/react';
const { defaultProps, operators } = interfacesProperties;
@ -58,7 +58,9 @@ export class MarkdownVditorFieldInterface extends CollectionFieldInterface {
'x-reactions': {
fulfill: {
schema: {
description: generateNTemplate('Used to store files uploaded in the Markdown editor'),
description: generateNTemplate(
'Used to store files uploaded in the Markdown editor (default: attachments)',
),
},
},
},

View File

@ -9,7 +9,7 @@
import { tval } from '@nocobase/utils/client';
const NAMESPACE = 'field-markdown-vditor';
export const NAMESPACE = 'field-markdown-vditor';
export function generateNTemplate(key: string) {
return tval(key, { ns: NAMESPACE })

View File

@ -1,7 +1,7 @@
{
"Vditor": "Markdown(Vditor)",
"File collection": "Dateisammlung",
"Used to store files uploaded in the Markdown editor": "Wird verwendet, um Dateien zu speichern, die im Markdown-Editor hochgeladen wurden",
"Used to store files uploaded in the Markdown editor (default: attachments)": "Dateisammlung, die in den Markdown-Editor hochgeladen wurde (Standard: attachments)",
"Toolbar": "Editor-Symbolleistenkonfiguration",
"Emoji": "Emoji",
"Headings": "Überschriften",
@ -29,5 +29,10 @@
"Both": "Editor & Vorschau",
"Preview": "Vorschau",
"Fullscreen": "Vollbild umschalten",
"Outline": "Gliederung"
"Outline": "Gliederung",
"uploading": "Hochladen...",
"upload failed": "Hochladen fehlgeschlagen",
"vditor.uploadError.message": "Dateien können nicht in den aktuellen Speicher hochgeladen werden. Sie versuchen, Dateien in den Markdown-Editor hochzuladen, aber die aktuelle Speicher-Konfiguration unterstützt diese Operation nicht. Um die Upload-Funktionalität zu aktivieren, schließen Sie bitte die folgenden Einstellungen ab: 1. Gehen Sie zu \"Dateimanager\". 2. Wählen Sie den aktuell verwendeten Speicher ({{storageTitle}}) aus. 3. Legen Sie die \"Basis-URL\" fest und aktivieren Sie die Option \"Öffentlicher Zugriff\".",
"Storage configuration not found. Please configure a storage provider first.": "Speicherkonfiguration nicht gefunden. Bitte konfigurieren Sie zuerst einen Speicheranbieter.",
"Response data is empty": "Antwortdaten sind leer"
}

View File

@ -1,7 +1,7 @@
{
"Vditor": "Markdown(Vditor)",
"File collection": "File collection",
"Used to store files uploaded in the Markdown editor": "Used to store files uploaded in the Markdown editor",
"Used to store files uploaded in the Markdown editor (default: attachments)": "Used to store files uploaded in the Markdown editor (default: attachments)",
"Toolbar": "Editor toolbar configuration",
"Emoji": "Emoji",
"Headings": "Headings",
@ -29,5 +29,10 @@
"Both": "Editor & Preview",
"Preview": "Preview",
"Fullscreen": "Toggle Fullscreen",
"Outline": "Outline"
"Outline": "Outline",
"uploading": "Uploading...",
"upload failed": "upload failed",
"vditor.uploadError.message": "Unable to upload files to the current storage. You are trying to upload files to the Markdown editor, but the current storage configuration does not support this operation. To enable upload functionality, please complete the following settings: 1. Go to \"File Manager\". 2. Select the storage currently in use ({{storageTitle}}). 3. Set \"Base URL\" and enable the \"Public access\" option.",
"Storage configuration not found. Please configure a storage provider first.": "Storage configuration not found. Please configure a storage provider first.",
"Response data is empty": "Response data is empty"
}

View File

@ -1,7 +1,7 @@
{
{
"Vditor": "Markdown(Vditor)",
"File collection": "Raccolta file",
"Used to store files uploaded in the Markdown editor": "Utilizzato per archiviare i file caricati nell'editor Markdown",
"Used to store files uploaded in the Markdown editor (default: attachments)": "Utilizzato per archiviare i file caricati nell'editor Markdown (default: attachments)",
"Toolbar": "Configurazione barra degli strumenti dell'editor",
"Emoji": "Emoji",
"Headings": "Intestazioni",
@ -29,5 +29,10 @@
"Both": "Editor e Anteprima",
"Preview": "Anteprima",
"Fullscreen": "Attiva/disattiva schermo intero",
"Outline": "Struttura"
"Outline": "Struttura",
"uploading": "Uploading...",
"upload failed": "upload failed",
"vditor.uploadError.message": "Impossibile caricare file nello storage corrente. Stai tentando di caricare file nell'editor Markdown, ma la configurazione di archiviazione corrente non supporta questa operazione. Per abilitare la funzionalità di caricamento, completa le seguenti impostazioni: 1. Vai a \"Gestione file\". 2. Seleziona lo storage attualmente in uso ({{storageTitle}}). 3. Imposta \"URL di base\" e abilita l'opzione \"Accesso pubblico\".",
"Storage configuration not found. Please configure a storage provider first.": "Configurazione dello storage non trovata. Configura prima un provider di storage.",
"Response data is empty": "I dati di risposta sono vuoti"
}

View File

@ -1,7 +1,7 @@
{
"Vditor": "Markdown(Vditor)",
"File collection": "ファイルコレクション",
"Used to store files uploaded in the Markdown editor": "Markdownエディタでアップロードされたファイルを保存するために使用",
"Used to store files uploaded in the Markdown editor (default: attachments)": "Markdownエディタでアップロードされたファイルを保存するために使用 (デフォルト: attachments)",
"Toolbar": "ツールバー",
"Emoji": "絵文字",
"Headings": "見出し",
@ -29,5 +29,10 @@
"Both": "編集とプレビュー",
"Preview": "プレビュー",
"Fullscreen": "全画面表示の切り替え",
"Outline": "アウトライン"
"Outline": "アウトライン",
"uploading": "Uploading...",
"upload failed": "upload failed",
"vditor.uploadError.message": "現在のストレージにファイルをアップロードできません。Markdownエディタにファイルをアップロードしようとしていますが、現在のストレージ設定ではこの操作はサポートされていません。アップロード機能を有効にするには、次の設定を完了してください1.「ファイルマネージャー」に移動します。2.現在使用しているストレージ({{storageTitle}}を選択します。3.「ベースURL」を設定し、「パブリックアクセス」オプションを有効にします。",
"Storage configuration not found. Please configure a storage provider first.": "ストレージ構成が見つかりません。最初にストレージプロバイダーを構成してください。",
"Response data is empty": "応答データが空です"
}

View File

@ -1,7 +1,7 @@
{
"Vditor": "Markdown(Vditor)",
"File collection": "파일 데이터 테이블",
"Used to store files uploaded in the Markdown editor": "Markdown 편집기에 업로드된 파일을 저장하는 데 사용됩니다",
"Used to store files uploaded in the Markdown editor (default: attachments)": "Markdown 편집기에 업로드된 파일을 저장하는 데 사용됩니다 (default: attachments)",
"Toolbar": "편집기 도구 모음 구성",
"Emoji": "이모지",
"Headings": "제목크기",
@ -29,5 +29,10 @@
"Both": "에디터 & 미리보기",
"Preview": "미리보기",
"Fullscreen": "전체화면",
"Outline": "개요"
"Outline": "개요",
"uploading": "Uploading...",
"upload failed": "upload failed",
"vditor.uploadError.message": "현재 스토리지에 파일을 업로드할 수 없습니다. Markdown 편집기에 파일을 업로드하려고 하지만 현재 스토리지 구성에서는 이 작업을 지원하지 않습니다. 업로드 기능을 활성화하려면 다음 설정을 완료하십시오: 1. \"파일 관리\"로 이동합니다. 2. 현재 사용 중인 스토리지({{storageTitle}})를 선택합니다. 3. \"기본 URL\"을 설정하고 \"공개 액세스\" 옵션을 활성화합니다.",
"Storage configuration not found. Please configure a storage provider first.": "저장소 구성을 찾을 수 없습니다. 먼저 저장소 공급자를 구성하십시오.",
"Response data is empty": "응답 데이터가 비어 있습니다"
}

View File

@ -1,7 +1,7 @@
{
"Vditor": "Markdown(Vditor)",
"File collection": "文件数据表",
"Used to store files uploaded in the Markdown editor": "用于存储在Markdown编辑器中上传的文件",
"Used to store files uploaded in the Markdown editor (default: attachments)": "用于存储在Markdown编辑器中上传的文件 (默认: attachments)",
"Toolbar": "编辑器工具栏配置",
"Emoji": "表情",
"Headings": "标题",
@ -29,5 +29,10 @@
"Both": "编辑 & 预览",
"Preview": "预览",
"Fullscreen": "全屏切换",
"Outline": "大纲"
"Outline": "大纲",
"uploading": "上传中...",
"upload failed": "上传失败",
"vditor.uploadError.message": "无法上传文件到当前存储。您正在尝试上传文件到 Markdown 编辑器但当前的存储配置不支持此操作。要启用上传功能请完成以下设置1. 前往「文件管理器」。2. 选择当前正在使用的存储({{storageTitle}}。3. 设置「基础 URL」并启用「公开访问」选项。",
"Storage configuration not found. Please configure a storage provider first.": "存储配置未找到。请先配置存储提供程序。",
"Response data is empty": "接口返回的数据为空"
}

View File

@ -0,0 +1,282 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { mockServer } from '@nocobase/test';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
describe('vditor:check', () => {
let app;
let db;
let agent;
beforeEach(async () => {
app = mockServer({
cors: {
origin: '*',
},
plugins: ['field-sort', 'users', 'auth', 'file-manager', 'field-markdown-vditor'],
});
await app.load();
db = app.db;
agent = app.agent();
// 确保集合已同步
await db.sync();
// 清除数据并准备测试数据
await db.clean({ drop: true });
// 确保集合重新同步
await db.sync();
// 创建测试所需的存储和文件集合
await db.getRepository('storages').create({
values: {
name: 'default-storage',
type: 'local',
default: true,
},
});
await db.getRepository('storages').create({
values: {
name: 's3-storage',
type: 's3-compatible',
default: false,
},
});
await db.getRepository('storages').create({
values: {
name: 's3-storage-with-baseurl',
type: 's3-compatible',
default: false,
options: {
baseUrl: 'https://example.com',
public: true,
},
},
});
// 创建测试文件集合
await db.collection({
name: 'file-collection-default',
fields: [
{
type: 'string',
name: 'title',
},
],
});
await db.collection({
name: 'file-collection-s3',
fields: [
{
type: 'string',
name: 'title',
},
],
storage: 's3-storage',
});
await db.collection({
name: 'file-collection-s3-with-baseurl',
fields: [
{
type: 'string',
name: 'title',
},
],
storage: 's3-storage-with-baseurl',
});
await db.sync();
});
afterEach(async () => {
await app.destroy();
});
it('should return default storage when no fileCollectionName provided', async () => {
const response = await agent.resource('vditor').check();
expect(response.status).toBe(200);
expect(response.body.data.isSupportToUploadFiles).toBe(true);
expect(response.body.data.storage).toMatchInlineSnapshot(`
{
"id": 1,
"name": "default-storage",
"rules": {},
"title": null,
"type": "local",
}
`);
});
it('should return default storage when fileCollectionName without storage is provided', async () => {
const response = await agent.resource('vditor').check({
fileCollectionName: 'file-collection-default',
});
expect(response.status).toBe(200);
expect(response.body.data.isSupportToUploadFiles).toBe(true);
expect(response.body.data.storage).toMatchInlineSnapshot(`
{
"id": 1,
"name": "default-storage",
"rules": {},
"title": null,
"type": "local",
}
`);
});
it('should return s3 storage and not support upload when s3 collection without baseUrl is provided', async () => {
const response = await agent.resource('vditor').check({
fileCollectionName: 'file-collection-s3',
});
expect(response.status).toBe(200);
expect(response.body.data.isSupportToUploadFiles).toBe(false);
expect(response.body.data.storage).toMatchInlineSnapshot(`
{
"id": 2,
"name": "s3-storage",
"rules": {},
"title": null,
"type": "s3-compatible",
}
`);
});
it('should return s3 storage and support upload when s3 collection with baseUrl is provided', async () => {
const response = await agent.resource('vditor').check({
fileCollectionName: 'file-collection-s3-with-baseurl',
});
expect(response.status).toBe(200);
expect(response.body.data.isSupportToUploadFiles).toBe(true);
expect(response.body.data.storage).toMatchInlineSnapshot(`
{
"id": 3,
"name": "s3-storage-with-baseurl",
"rules": {},
"title": null,
"type": "s3-compatible",
}
`);
});
it('should handle non-existent fileCollectionName gracefully', async () => {
const response = await agent.resource('vditor').check({
fileCollectionName: 'non-existent-collection',
});
expect(response.status).toBe(200);
expect(response.body.data.isSupportToUploadFiles).toBe(true);
expect(response.body.data.storage).toMatchInlineSnapshot(`
{
"id": 1,
"name": "default-storage",
"rules": {},
"title": null,
"type": "local",
}
`);
});
it('should handle s3 storage with baseUrl but not public attribute', async () => {
// 创建测试所需的非公开 s3 存储
await db.getRepository('storages').create({
values: {
name: 's3-storage-with-baseurl-not-public',
type: 's3-compatible',
default: false,
options: {
baseUrl: 'https://example.com',
public: false,
},
},
});
// 创建关联的文件集合
await db.collection({
name: 'file-collection-s3-baseurl-not-public',
fields: [
{
type: 'string',
name: 'title',
},
],
storage: 's3-storage-with-baseurl-not-public',
});
await db.sync();
const response = await agent.resource('vditor').check({
fileCollectionName: 'file-collection-s3-baseurl-not-public',
});
expect(response.status).toBe(200);
expect(response.body.data.isSupportToUploadFiles).toBe(false);
expect(response.body.data.storage).toMatchInlineSnapshot(`
{
"id": 4,
"name": "s3-storage-with-baseurl-not-public",
"rules": {},
"title": null,
"type": "s3-compatible",
}
`);
});
it('should handle non-s3 storage types correctly', async () => {
// 创建一个非 s3 类型的存储
await db.getRepository('storages').create({
values: {
name: 'other-storage-type',
type: 'oss',
default: false,
},
});
// 创建关联的文件集合
await db.collection({
name: 'file-collection-oss',
fields: [
{
type: 'string',
name: 'title',
},
],
storage: 'other-storage-type',
});
await db.sync();
const response = await agent.resource('vditor').check({
fileCollectionName: 'file-collection-oss',
});
expect(response.status).toBe(200);
expect(response.body.data.isSupportToUploadFiles).toBe(true);
expect(response.body.data.storage).toMatchInlineSnapshot(`
{
"id": 4,
"name": "other-storage-type",
"rules": {},
"title": null,
"type": "oss",
}
`);
});
});

View File

@ -11,6 +11,11 @@ import { Plugin } from '@nocobase/server';
import fs from 'fs-extra';
import path from 'path';
// @ts-ignore
import pkg from '../../package.json';
const namespace = pkg.name;
export class PluginFieldMarkdownVditorServer extends Plugin {
async afterAdd() {}
@ -18,6 +23,63 @@ export class PluginFieldMarkdownVditorServer extends Plugin {
async load() {
await this.copyVditorDist();
this.setResource();
this.app.acl.allow('vditor', 'check', 'loggedIn');
}
setResource() {
this.app.resourceManager.define({
name: 'vditor',
actions: {
check: async (context, next) => {
const { fileCollectionName } = context.action.params;
let storage;
const fileCollection = this.db.getCollection(fileCollectionName || 'attachments');
const storageName = fileCollection?.options?.storage;
if (storageName) {
storage = await this.db.getRepository('storages').findOne({
where: {
name: storageName,
},
});
} else {
storage = await this.db.getRepository('storages').findOne({
where: {
default: true,
},
});
}
if (!storage) {
context.throw(
400,
context.t('Storage configuration not found. Please configure a storage provider first.', {
ns: namespace,
}),
);
}
const isSupportToUploadFiles =
storage.type !== 's3-compatible' || (storage.options?.baseUrl && storage.options?.public);
const storageInfo = {
id: storage.id,
title: storage.title,
name: storage.name,
type: storage.type,
rules: storage.rules,
};
context.body = {
isSupportToUploadFiles: !!isSupportToUploadFiles,
storage: storageInfo,
};
await next();
},
},
});
}
async copyVditorDist() {

View File

@ -4,7 +4,7 @@
"displayName.zh-CN": "数据表字段:自动编码",
"description": "Automatically generate codes based on configured rules, supporting combinations of dates, numbers, and text.",
"description.zh-CN": "根据配置的规则自动生成编码,支持日期、数字、文本的组合。",
"version": "1.7.0-beta.9",
"version": "1.7.0-alpha.10",
"license": "AGPL-3.0",
"main": "./dist/server/index.js",
"homepage": "https://docs.nocobase.com/handbook/field-sequence",

View File

@ -15,6 +15,9 @@ export class PluginFieldSequenceClient extends Plugin {
async load() {
this.app.use(SequenceFieldProvider);
this.app.dataSourceManager.addFieldInterfaces([SequenceFieldInterface]);
const calendarPlugin: any = this.app.pm.get('calendar');
// 注册标题字段
calendarPlugin.registerTitleFieldInterface('sequence');
}
}

View File

@ -1,5 +1,6 @@
{
"Sequence": "Reeks",
"Automatically generate codes based on configured rules, supporting combinations of dates, numbers, and text.": "Automatisch codes genereren op basis van geconfigureerde regels, met ondersteuning voor combinaties van datums, nummers en tekst.",
"Sequence rules": "Reeksregels",
"Add rule": "Voeg regel toe",
"Inputable": "Invoerbaar",
@ -8,6 +9,9 @@
"Autoincrement": "Automatisch verhogen",
"Fixed text": "Vaste tekst",
"Text content": "Tekstinhoud",
"Date": "Datum",
"Date format": "Datumformaat",
"Supports all formats of the Day.js library, such as \"YYYYMMDD\", \"YYYY-MM-DD\", etc.": "Ondersteunt alle formaten van de Day.js-bibliotheek, zoals \"YYYYMMDD\", \"YYYY-MM-DD\", enz.",
"Rule content": "Regelinhoud",
"{{value}} Digits": "{{value}} cijfers",
"Digits": "Cijfers",
@ -20,5 +24,14 @@
"Monthly": "Maandelijks",
"Yearly": "Jaarlijks",
"Operations": "Operaties",
"Customize": "Pas aan"
"Customize": "Pas aan",
"Random character": "Willekeurig karakter",
"Length": "Lengte",
"Will generate random characters with specified length.": "Genereert willekeurige tekens met de opgegeven lengte.",
"Character sets": "Karaktersets",
"Select character sets to generate random characters.": "Selecteer karaktersets om willekeurige tekens te genereren.",
"Number": "Nummer",
"Lowercase letters": "Kleine letters",
"Uppercase letters": "Hoofdletters",
"Symbols": "Symbolen"
}

Some files were not shown because too many files have changed in this diff Show More