diff --git a/README.md b/README.md index 971208858..83159f76e 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ yarn install yarn dev # or run en-US document yarn dev:en +# ou lancer fr-FR document +yarn dev:fr # または、日本語のドキュメントを実行する yarn dev:ja ``` diff --git a/docs/config/breaking.ts b/docs/config/breaking.ts index ae28fc79d..b22e26fef 100644 --- a/docs/config/breaking.ts +++ b/docs/config/breaking.ts @@ -1,6 +1,7 @@ export default [ { title: 'Breaking changes', + 'title.fr-FR': 'Modifications incompatibles', 'title.zh-CN': '不兼容变更', 'title.ja-JP': '互換性のない変更', type: 'group', diff --git a/docs/config/development.ts b/docs/config/development.ts index 0f9e02099..326032302 100644 --- a/docs/config/development.ts +++ b/docs/config/development.ts @@ -1,6 +1,7 @@ export default [ { title: 'Getting started', + 'title.fr-FR': 'Commencer', 'title.zh-CN': '快速开始', 'title.ja-JP': 'はじめに', type: 'group', @@ -15,6 +16,7 @@ export default [ }, { title: 'Server', + 'title.fr-FR': 'Serveur', 'title.zh-CN': '服务端', 'title.ja-JP': 'サーバー', type: 'group', @@ -22,6 +24,7 @@ export default [ '/development/server', { title: 'Collections & Fields', + 'title.fr-FR': 'Collections et champs', 'title.zh-CN': '数据表和字段', 'title.ja-JP': 'コレクションとフィールド', children: [ @@ -35,6 +38,7 @@ export default [ }, // { // title: 'Resources & Actions', + // 'title.fr-FR': 'Ressources et Actions', // 'title.zh-CN': '资源和操作', // 'title.ja-JP': 'リソースとアクション', // children: [ @@ -58,6 +62,7 @@ export default [ }, { title: 'Client', + 'title.fr-FR': 'Client', 'title.zh-CN': '客户端', 'title.ja-JP': 'クライアント', type: 'group', @@ -70,6 +75,7 @@ export default [ '/development/client/providers', { title: 'UI Schema', + 'title.fr-FR': 'Schéma UI', 'title.zh-CN': 'UI Schema', 'title.ja-JP': 'UIスキーマ', children: [ @@ -90,6 +96,7 @@ export default [ }, { title: 'Others', + 'title.fr-FR': 'Autres', 'title.zh-CN': '其他', 'title.ja-JP': 'その他', type: 'group', diff --git a/docs/config/handbook.ts b/docs/config/handbook.ts index bf40bbf07..eda94d350 100644 --- a/docs/config/handbook.ts +++ b/docs/config/handbook.ts @@ -1,35 +1,41 @@ export default [ { title: 'Guide', + 'title.fr-FR': 'Guide', 'title.zh-CN': '指南', 'title.ja-JP': 'ガイド', link: '/handbook', }, { title: 'Data modeling', + 'title.fr-FR': 'Modélisation des données', 'title.zh-CN': '数据建模', 'title.ja-JP': 'データモデリング', type: 'group', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/data-modeling', }, { title: 'Data sources', + 'title.zh-CN': 'Sources de données', 'title.zh-CN': '数据源', 'title.ja-JP': 'データソース', children: [ { title: 'Data source manager', + 'title.fr-FR': 'Gestionnaire de sources de données', 'title.zh-CN': '数据源管理', 'title.ja-JP': 'データソースマネージャー', link: '/handbook/data-source-manager', }, { title: 'Main database', + 'title.fr-FR': 'Base de données principale', 'title.zh-CN': '主数据库', 'title.ja-JP': 'メインデータベース', // subTitle: '@nocobase/plugin-collection-manager', @@ -37,17 +43,20 @@ export default [ }, { title: 'External database', + 'title.fr-FR': 'Base de données externe', 'title.zh-CN': '外部数据库', 'title.ja-JP': '外部データベース', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '介绍', 'title.ja-JP': '概要', link: '/handbook/data-source-manager/external-database', }, { title: 'External MySQL', + 'title.fr-FR': 'Source de données MySQL', 'title.zh-CN': '外部 MySQL', 'title.ja-JP': '外部 MySQL', // subTitle: '@nocobase/plugin-data-source-external-mysql', @@ -55,6 +64,7 @@ export default [ }, { title: 'External MariaDB', + 'title.fr-FR': 'Source de données MariaDB', 'title.zh-CN': '外部 MariaDB', 'title.ja-JP': '外部 MariaDB', // subTitle: '@nocobase/plugin-data-source-external-mariadb', @@ -62,6 +72,7 @@ export default [ }, { title: 'External PostgreSQL', + 'title.fr-FR': 'Source de données PostgreSQL', 'title.zh-CN': '外部 PostgreSQL', 'title.ja-JP': '外部 PostgreSQL', // subTitle: '@nocobase/plugin-data-source-external-postgres', @@ -69,6 +80,7 @@ export default [ }, { title: 'External MSSQL', + 'title.fr-FR': 'Source de données MSSQL', 'title.zh-CN': '外部 MSSQL', 'title.ja-JP': '外部 MSSQL', // subTitle: '@nocobase/plugin-data-source-external-mysql', @@ -76,6 +88,7 @@ export default [ }, { title: 'External Oracle', + 'title.fr-FR': 'Source de données Oracle', 'title.zh-CN': '外部 Oracle', 'title.ja-JP': '外部 Oracle', // subTitle: '@nocobase/plugin-data-source-external-mysql', @@ -85,6 +98,7 @@ export default [ }, { title: 'REST API data source', + 'title.fr-FR': 'Source de données API REST', 'title.zh-CN': 'REST API 数据源', 'title.ja-JP': 'REST API データソース', // subTitle: '@nocobase/plugin-data-source-external-postgres', @@ -92,12 +106,14 @@ export default [ }, { title: 'KingbaseES data source', + 'title.fr-FR': 'Source de données KingbaseES', 'title.zh-CN': '人大金仓(KingbaseES)数据源', 'title.ja-JP': '人大金仓(KingbaseES)データソース', link: '/handbook/data-source-kingbase', }, { title: 'ER diagram-like tool', + 'title.fr-FR': 'Outil de gestion des ER', 'title.zh-CN': '类 ER 工具', 'title.ja-JP': 'ER図のようなツール', // subTitle: '@nocobase/plugin-graph-collection-manager', @@ -159,65 +175,76 @@ export default [ // }, { title: 'Collections', + 'title.fr-FR': 'Collections', 'title.zh-CN': '数据表', 'title.ja-JP': 'コレクション', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/data-modeling/collection', }, { title: 'General collection', + 'title.fr-FR': 'Collection générale', 'title.zh-CN': '普通表', 'title.ja-JP': '一般コレクション', link: '/handbook/data-source-main/general-collection', }, { title: 'Inheritance collection', + 'title.fr-FR': 'Collection héritée', 'title.zh-CN': '继承表', 'title.ja-JP': '継承コレクション', link: '/handbook/data-source-main/inheritance-collection', }, { title: 'File collection', + 'title.fr-FR': 'Collection de fichiers', 'title.zh-CN': '文件表', 'title.ja-JP': 'ファイルコレクション', link: '/handbook/file-manager/file-collection', }, { title: 'Tree collection', + 'title.fr-FR': 'Arborescences', 'title.zh-CN': '树表', 'title.ja-JP': '木構造コレクション', link: '/handbook/collection-tree', }, { title: 'Calendar collection', + 'title.fr-FR': 'Collection de calendriers', 'title.zh-CN': '日历表', 'title.ja-JP': 'カレンダーコレクション', link: '/handbook/calendar/calendar-collection', }, { title: 'Expression collection', + 'title.fr-FR': 'Collection d\'expressions', 'title.zh-CN': '表达式表', 'title.ja-JP': '式コレクション', link: '/handbook/collection-expression/collection', }, { title: 'SQL collection', + 'title.fr-FR': 'Collection SQL', 'title.zh-CN': 'SQL 表', 'title.ja-JP': 'SQLコレクション', link: '/handbook/collection-sql', }, { title: 'View collection', + 'title.fr-FR': 'Collection de vues', 'title.zh-CN': '数据库视图', 'title.ja-JP': 'ビューコレクション', link: '/handbook/collection-view', }, { title: 'Foreign data collection(FDW)', + 'title.fr-FR': 'Collection de données étrangères(FDW)', 'title.zh-CN': '外部数据表', 'title.ja-JP': '外部データコレクション(FDW)', link: '/handbook/collection-fdw', @@ -226,11 +253,13 @@ export default [ }, { title: 'Collection fields', + 'title.fr-FR': 'Collection de champs', 'title.zh-CN': '数据表字段', 'title.ja-JP': 'コレクションフィールド', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', // subTitle: '@nocobase/plugin-data-source-external-mariadb', @@ -238,71 +267,83 @@ export default [ }, { title: 'Basic', + 'title.fr-FR': 'Basic', 'title.zh-CN': '基本类型', 'title.ja-JP': '基本タイプ', children: [ { title: 'Single text', + 'title.fr-FR': 'Texte simple', 'title.zh-CN': '单行文本', 'title.ja-JP': '単一行テキスト', link: '/handbook/data-modeling/collection-fields/basic/input', }, { title: 'Long text', + 'title.fr-FR': 'Texte long', 'title.zh-CN': '多行文本', 'title.ja-JP': '複数行テキスト', link: '/handbook/data-modeling/collection-fields/basic/textarea', }, { title: 'Phone', + 'title.fr-FR': 'Téléphone', 'title.zh-CN': '手机号码', 'title.ja-JP': '電話番号', link: '/handbook/data-modeling/collection-fields/basic/phone', }, { title: 'Email', + 'title.fr-FR': 'Email', 'title.zh-CN': '电子邮箱', 'title.ja-JP': '電子メール', link: '/handbook/data-modeling/collection-fields/basic/email', }, { title: 'URL', + 'title.fr-FR': URL', 'title.zh-CN': 'URL', 'title.ja-JP': 'URL', link: '/handbook/data-modeling/collection-fields/basic/url', }, { - title: 'Integer', + title: 'Integer', + 'title.fr-FR': 'Entier', 'title.zh-CN': '整数', 'title.ja-JP': '整数', link: '/handbook/data-modeling/collection-fields/basic/integer', }, { - title: 'Number', + title: 'Number', + 'title.fr-FR': 'Nombre', 'title.zh-CN': '数字', 'title.ja-JP': '数値', link: '/handbook/data-modeling/collection-fields/basic/number', }, { - title: 'Percent', + title: 'Percent', + 'title.fr-FR': 'Pourcentage', 'title.zh-CN': '百分比', 'title.ja-JP': 'パーセント', link: '/handbook/data-modeling/collection-fields/basic/percent', }, { - title: 'Password', + title: 'Password', + 'title.fr-FR': 'Mot de passe', 'title.zh-CN': '密码', 'title.ja-JP': 'パスワード', link: '/handbook/data-modeling/collection-fields/basic/password', }, { - title: 'Color', + title: 'Color', + 'title.fr-FR': 'Couleur', 'title.zh-CN': '颜色', 'title.ja-JP': '色', link: '/handbook/data-modeling/collection-fields/basic/color', }, { - title: 'Icon', + title: 'Icon', + 'title.fr-FR': 'Icône', 'title.zh-CN': '图标', 'title.ja-JP': 'アイコン', link: '/handbook/data-modeling/collection-fields/basic/icon', @@ -311,41 +352,48 @@ export default [ }, { title: 'Choices', + 'title.fr-FR': 'Selection', 'title.zh-CN': '选择类型', 'title.ja-JP': '選択タイプ', children: [ { - title: 'Checkbox', + title: 'Checkbox', + 'title.fr-FR': 'Checkbox', 'title.zh-CN': '勾选', 'title.ja-JP': 'チェックボックス', link: '/handbook/data-modeling/collection-fields/choices/checkbox', }, { - title: 'Single select', + title: 'Single select', + 'title.fr-FR': 'Selection simple', 'title.zh-CN': '下拉菜单(单选)', 'title.ja-JP': '単一選択', link: '/handbook/data-modeling/collection-fields/choices/select', }, { - title: 'Multiple select', + title: 'Multiple select', + 'title.fr-FR': 'Selection multiple', 'title.zh-CN': '下拉菜单(多选)', 'title.ja-JP': '複数選択', link: '/handbook/data-modeling/collection-fields/choices/multiple-select', }, { - title: 'Radio group', + title: 'Radio group', + 'title.fr-FR': 'Groupe Radio', 'title.zh-CN': '单选框', 'title.ja-JP': 'ラジオボタン', link: '/handbook/data-modeling/collection-fields/choices/radio-group', }, { - title: 'Checkbox group', + title: 'Checkbox group', + 'title.fr-FR': 'Groupe Checkbox', 'title.zh-CN': '复选框', 'title.ja-JP': 'チェックボックスグループ', link: '/handbook/data-modeling/collection-fields/choices/checkbox-group', }, { - title: 'China region', + title: 'China region', + 'title.fr-FR': 'China region', 'title.zh-CN': '中国行政区', 'title.ja-JP': '中国の行政区', link: '/handbook/field-china-region', @@ -354,35 +402,41 @@ export default [ }, { title: 'Media', + 'title.fr-FR': 'Média', 'title.zh-CN': '多媒体', 'title.ja-JP': 'メディア', children: [ { title: 'Markdown', + 'title.fr-FR': 'Markdown', 'title.zh-CN': 'Markdown', 'title.ja-JP': 'Markdown', link: '/handbook/data-modeling/collection-fields/media/markdown', }, { title: 'Markdown(Vditor)', + 'title.fr-FR': 'Markdown(Vditor)', 'title.zh-CN': 'Markdown(Vditor)', 'title.ja-JP': 'Markdown(Vditor)', link: '/handbook/field-markdown-vditor', }, { title: 'Rich text', + 'title.fr-FR': 'Rich text', 'title.zh-CN': '富文本', 'title.ja-JP': 'リッチテキスト', link: '/handbook/data-modeling/collection-fields/media/rich-text', }, { title: 'Attachment(Assocation)', + 'title.fr-FR': 'Attachment(Assocation)', 'title.zh-CN': '附件(关系)', 'title.ja-JP': '添付ファイル(Assocation)', link: '/handbook/file-manager/field-attachment', }, { title: 'Attachment(URL)', + 'title.fr-FR': 'Attachment(URL)', 'title.zh-CN': '附件(URL)', 'title.ja-JP': '添付ファイル(URL)', link: '/handbook/field-attachment-url', @@ -391,41 +445,48 @@ export default [ }, { title: 'Date & Time', + 'title.fr-FR': 'Date et heure', 'title.zh-CN': '日期 & 时间', 'title.ja-JP': '日付と時間', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/data-modeling/collection-fields/datetime', }, { title: 'Datetime(with time zone)', + 'title.fr-FR': 'Date et heure(avec time zone)', 'title.zh-CN': '日期时间(含时区)', 'title.ja-JP': '日付と時間(タイムゾーンあり)', link: '/handbook/data-modeling/collection-fields/datetime/datetime', }, { title: 'Datetime(without time zone)', + 'title.fr-FR': 'Date et heure(sans time zone)', 'title.zh-CN': '日期时间(不含时区)', 'title.ja-JP': '日付と時間(タイムゾーンなし)', link: '/handbook/data-modeling/collection-fields/datetime/datetime-without-tz', }, { title: 'Unix timestamp', + 'title.fr-FR': 'Timestamp Unix', 'title.zh-CN': 'Unix 时间戳', 'title.ja-JP': 'Unix タイムスタンプ', link: '/handbook/data-modeling/collection-fields/datetime/unix-timestamp', }, { title: 'Date(without time)', + 'title.fr-FR': 'Date(sans heure)', 'title.zh-CN': '日期(不含时间)', 'title.ja-JP': '日付(時間なし)', link: '/handbook/data-modeling/collection-fields/datetime/date', }, { title: 'Time', + 'title.fr-FR': 'Heure', 'title.zh-CN': '时间', 'title.ja-JP': '時間', link: '/handbook/data-modeling/collection-fields/datetime/time', @@ -434,29 +495,34 @@ export default [ }, { title: 'Geometric', + 'title.fr-FR': 'Géométrie', 'title.zh-CN': '几何图形', 'title.ja-JP': '幾何学', children: [ { title: 'Point', + 'title.fr-FR': 'Point', 'title.zh-CN': '点', 'title.ja-JP': '点', link: '/handbook/data-modeling/collection-fields/geometric/point', }, { title: 'Line', + 'title.fr-FR': 'Ligne', 'title.zh-CN': '线', 'title.ja-JP': '線', link: '/handbook/data-modeling/collection-fields/geometric/line', }, { title: 'Circle', + 'title.fr-FR': 'Cercle', 'title.zh-CN': '圆', 'title.ja-JP': '円', link: '/handbook/data-modeling/collection-fields/geometric/circle', }, { title: 'Polygon', + 'title.fr-FR': 'Polygone', 'title.zh-CN': '多边形', 'title.ja-JP': '多角形', link: '/handbook/data-modeling/collection-fields/geometric/polygon', @@ -465,53 +531,62 @@ export default [ }, { title: 'Advanced', + 'title.fr-FR': 'Avancé', 'title.zh-CN': '高级类型', 'title.ja-JP': '高度なタイプ', children: [ { title: 'UUID', + 'title.fr-FR': 'UUID', 'title.zh-CN': 'UUID', 'title.ja-JP': 'UUID', link: '/handbook/data-modeling/collection-fields/advanced/uuid', }, { title: 'Nano ID', + 'title.fr-FR': 'Nano ID', 'title.zh-CN': 'Nano ID', 'title.ja-JP': 'Nano ID', link: '/handbook/data-modeling/collection-fields/advanced/nano-id', }, { title: 'Sort', + 'title.fr-FR': 'Sort', 'title.zh-CN': '排序', 'title.ja-JP': 'ソート', link: '/handbook/field-sort', }, { title: 'Formula', + 'title.fr-FR': 'Formule', 'title.zh-CN': '计算公式', 'title.ja-JP': '計算式', link: '/handbook/field-formula', }, { title: 'Sequence', + 'title.fr-FR': 'Séquence', 'title.zh-CN': '自动编码', 'title.ja-JP': '自動エンコード', link: '/handbook/field-sequence', }, { title: 'JSON', + 'title.fr-FR': 'JSON', 'title.zh-CN': 'JSON', 'title.ja-JP': 'JSON', link: '/handbook/data-modeling/collection-fields/advanced/json', }, { - title: 'Collection select', + title: 'Collection select' + 'title.fr-FR': 'Collection select', 'title.zh-CN': '数据表选择器', 'title.ja-JP': 'コレクションセレクター', link: '/handbook/data-modeling/collection-fields/advanced/collection-select', }, { title: 'Encryption', + 'title.fr-FR': 'Chiffrement', 'title.zh-CN': '加密', 'title.ja-JP': '暗号化', link: '/handbook/field-encryption', @@ -520,35 +595,41 @@ export default [ }, { title: 'System info', + 'title.fr-FR': 'Système info', 'title.zh-CN': '系统信息', 'title.ja-JP': 'システム情報', children: [ { title: 'Created at', + 'title.fr-FR': 'Créé le', 'title.zh-CN': '创建日期', 'title.ja-JP': '作成日', link: '/handbook/data-modeling/collection-fields/system-info/created-at', }, { title: 'Last updated at', + 'title.fr-FR': 'Modifié le', 'title.zh-CN': '最后修改日期', 'title.ja-JP': '最終更新日', link: '/handbook/data-modeling/collection-fields/system-info/updated-at', }, { title: 'Created by', + 'title.fr-FR': 'Créé par', 'title.zh-CN': '创建人', 'title.ja-JP': '作成者', link: '/handbook/users/field-created-by', }, { title: 'Last updated by', + 'title.fr-FR': 'Modifié par', 'title.zh-CN': '最后修改人', 'title.ja-JP': '最終更新者', link: '/handbook/users/field-updated-by', }, { title: 'Table OID', + 'title.fr-FR': 'Table OID', 'title.zh-CN': 'Table OID', 'title.ja-JP': 'テーブルOID', link: '/handbook/data-modeling/collection-fields/system-info/table-oid', @@ -557,41 +638,48 @@ export default [ }, { title: 'Association', + 'title.fr-FR': 'Association', 'title.zh-CN': '关系类型', 'title.ja-JP': '関連タイプ', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/data-modeling/collection-fields/associations', }, { title: 'One-to-one', + 'title.fr-FR': 'Un à un', 'title.zh-CN': '一对一', 'title.ja-JP': '一対一', link: '/handbook/data-modeling/collection-fields/associations/o2o', }, { title: 'One-to-many', + 'title.fr-FR': 'Un à plusieurs', 'title.zh-CN': '一对多', 'title.ja-JP': '一対多', link: '/handbook/data-modeling/collection-fields/associations/o2m', }, { title: 'Many-to-one', + 'title.fr-FR': 'Plusieurs à un', 'title.zh-CN': '多对一', 'title.ja-JP': '多対一', link: '/handbook/data-modeling/collection-fields/associations/m2o', }, { title: 'Many-to-many', + 'title.fr-FR': 'Plusieurs à plusieurs', 'title.zh-CN': '多对多', 'title.ja-JP': '多対多', link: '/handbook/data-modeling/collection-fields/associations/m2m', }, { title: 'Many-to-many (array)', + 'title.fr-FR': 'Plusieurs à plusieurs (tableau)', 'title.zh-CN': '多对多(数组)', 'title.ja-JP': '多対多(配列)', link: '/handbook/field-m2m-array', @@ -604,112 +692,131 @@ export default [ }, { title: 'Edit UI', + 'title.fr-FR': 'Interface utilisateur(UI)', 'title.zh-CN': '配置界面', 'title.ja-JP': 'UI編集', type: 'group', children: [ { title: 'UI Editor mode', + 'title.fr-FR': 'Mode éditeur UI', 'title.zh-CN': '界面配置模式', 'title.ja-JP': 'UIエディタモード', link: '/handbook/ui/ui-editor', }, { title: 'Menu', + 'title.fr-FR': 'Menu', 'title.zh-CN': '菜单', 'title.ja-JP': 'メニュー', link: '/handbook/ui/menus', }, { title: 'Page', + 'title.fr-FR': 'Page', 'title.zh-CN': '页面', 'title.ja-JP': 'ページ', link: '/handbook/ui/pages', }, { title: 'Pop-up', + 'title.fr-FR': 'Pop-up', 'title.zh-CN': '弹窗', 'title.ja-JP': 'ポップアップ', link: '/handbook/ui/pop-up', }, { title: 'Blocks', + 'title.fr-FR': 'Blocks', 'title.zh-CN': '区块', 'title.ja-JP': 'ブロック', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/ui/blocks', }, { title: 'Data blocks', + 'title.fr-FR': 'Data blocks', 'title.zh-CN': '数据区块', 'title.ja-JP': 'データブロック', children: [ { title: 'Table', + 'title.fr-FR': 'Tableau', 'title.zh-CN': '表格', 'title.ja-JP': 'テーブル', link: '/handbook/ui/blocks/data-blocks/table', }, { title: 'Form', + 'title.fr-FR': 'Form', 'title.zh-CN': '表单', 'title.ja-JP': 'フォーム', link: '/handbook/ui/blocks/data-blocks/form', }, { title: 'Details', + 'title.fr-FR': 'Détails', 'title.zh-CN': '详情', 'title.ja-JP': '詳細', link: '/handbook/ui/blocks/data-blocks/details', }, { title: 'List', + 'title.fr-FR': 'Liste', 'title.zh-CN': '列表', 'title.ja-JP': 'リスト', link: '/handbook/ui/blocks/data-blocks/list', }, { title: 'Grid card', + 'title.fr-FR': 'Grille', 'title.zh-CN': '网格卡片', 'title.ja-JP': 'グリッドカード', link: '/handbook/ui/blocks/data-blocks/grid-card', }, { title: 'Calendar', + 'title.fr-FR': 'Calendar', 'title.zh-CN': '日历', 'title.ja-JP': 'カレンダー', link: '/handbook/calendar', }, { title: 'Gantt', + 'title.fr-FR': 'Gantt', 'title.zh-CN': '甘特图', 'title.ja-JP': 'ガントチャート', link: '/handbook/block-gantt', }, { title: 'Kanban', + 'title.fr-FR': 'Kanban', 'title.zh-CN': '看板', 'title.ja-JP': 'カンバン', link: '/handbook/block-kanban', }, { title: 'Map', + 'title.fr-FR': 'Carte', 'title.zh-CN': '地图', 'title.ja-JP': '地図', link: '/handbook/block-map', }, { title: 'Charts', + 'title.fr-FR': 'Graphiques', 'title.zh-CN': '图表', 'title.ja-JP': 'チャート', link: '/handbook/data-visualization/', }, { title: 'Multi-step form', + 'title.fr-FR': 'Formulaire multi-étapes', 'title.zh-CN': '分步表单', 'title.ja-JP': '多段階フォーム', link: '/handbook/block-multi-step-from', @@ -718,23 +825,27 @@ export default [ }, { title: 'Filter blocks', + 'title.fr-FR': 'Blocs filtre', 'title.zh-CN': '筛选区块', 'title.ja-JP': 'フィルターブロック', children: [ { title: 'Form', + 'title.fr-FR': 'Formulaire', 'title.zh-CN': '表单', 'title.ja-JP': 'フォーム', link: '/handbook/ui/blocks/filter-blocks/form', }, { title: 'Collapse', + 'title.fr-FR': 'Réduire', 'title.zh-CN': '折叠面板', 'title.ja-JP': '折りたたみパネル', link: '/handbook/ui/blocks/filter-blocks/collapse', }, { title: 'Tree', + 'title.fr-FR': 'Arborescence', 'title.zh-CN': '树', 'title.ja-JP': '木構造', link: '/handbook/block-tree', @@ -743,35 +854,41 @@ export default [ }, { title: 'Other blocks', + 'title.fr-FR': 'Autres blocs', 'title.zh-CN': '其他区块', 'title.ja-JP': 'その他のブロック', children: [ { title: 'Markdown', + 'title.fr-FR': 'Markdown', 'title.zh-CN': 'Markdown', 'title.ja-JP': 'Markdown', link: '/handbook/ui/blocks/other-blocks/markdown', }, { title: 'iframe', + 'title.fr-FR': 'iframe', 'title.zh-CN': 'iframe', 'title.ja-JP': 'iframe', link: '/handbook/block-iframe', }, { title: 'Action panel', + 'title.fr-FR': 'Action panel', 'title.zh-CN': '操作面板', 'title.ja-JP': 'アクションパネル', link: '/handbook/block-action-panel', }, { title: 'Workflow: Manual todos', + 'title.fr-FR': 'Workflow: manuel', 'title.zh-CN': '工作流:人工待办', 'title.ja-JP': 'ワークフロー:手動タスク', link: '/handbook/ui/blocks/other-blocks/workflow-manual-todos', }, { title: 'Workflow: Approval', + 'title.fr-FR': 'Workflow: Approbation', 'title.zh-CN': '工作流:审批', 'title.ja-JP': 'ワークフロー:承認', link: '/handbook/ui/blocks/other-blocks/workflow-approval', @@ -785,71 +902,83 @@ export default [ }, { title: 'Block templates', + 'title.fr-FR': 'Template de blocs', 'title.zh-CN': '区块模板', 'title.ja-JP': 'ブロックテンプレート', link: '/handbook/ui/blocks/block-templates', }, { title: 'Block settings', + 'title.fr-FR': 'Paramètre de blocs', 'title.zh-CN': '区块设置项', 'title.ja-JP': 'ブロック設定', children: [ { title: 'Set the data scope', + 'title.fr-FR': 'Data scope', 'title.zh-CN': '设置数据范围', 'title.ja-JP': 'データ範囲を設定', link: '/handbook/ui/blocks/block-settings/data-scope', }, { title: 'Set default sorting rules', + 'title.fr-FR': 'Règle de tri par défaut', 'title.zh-CN': '设置排序规则', 'title.ja-JP': 'デフォルトのソートルールを設定', link: '/handbook/ui/blocks/block-settings/sorting-rule', }, { title: 'Set data loading mode', + 'title.fr-FR': 'Mode de chargement des données', 'title.zh-CN': '设置数据加载方式', 'title.ja-JP': 'データ読み込みモードを設定', link: '/handbook/ui/blocks/block-settings/loading-mode', }, { title: 'Connect data blocks', + 'title.fr-FR': 'Connecter des blocs de données', 'title.zh-CN': '连接数据区块', 'title.ja-JP': 'データブロックを接続', link: '/handbook/ui/blocks/block-settings/connect-block', }, { title: 'Save as template', + 'title.fr-FR': 'Enregistrer une template', 'title.zh-CN': '保存为区块模板', 'title.ja-JP': 'テンプレートとして保存', link: '/handbook/ui/blocks/block-settings/block-template', }, { title: 'Linkage rules', + 'title.fr-FR': 'Règles de liaison', 'title.zh-CN': '联动规则', 'title.ja-JP': '連動ルール', link: '/handbook/ui/blocks/block-settings/linkage-rule', }, { title: 'Edit block title', + 'title.fr-FR': 'Titre de bloc', 'title.zh-CN': '编辑区块标题', 'title.ja-JP': 'ブロックタイトルを編集', link: '/handbook/ui/blocks/block-settings/block-title', }, { title: 'Set block height', + 'title.fr-FR': 'Hauteur', 'title.zh-CN': '设置区块高度', 'title.ja-JP': 'ブロックの高さを設定', link: '/handbook/ui/blocks/block-settings/block-height', }, { title: 'Layout', + 'title.fr-FR': 'Disposition', 'title.zh-CN': '布局', 'title.ja-JP': 'レイアウト', link: '/handbook/ui/blocks/block-settings/block-layout', }, { title: 'Delete', + 'title.fr-FR': 'Suppression', 'title.zh-CN': '删除区块', 'title.ja-JP': 'ブロックを削除', link: '/handbook/ui/blocks/block-settings/block-delete', @@ -860,52 +989,60 @@ export default [ }, { title: 'Fields', + 'title.fr-FR': 'Champs', 'title.zh-CN': '字段', 'title.ja-JP': 'フィールド', children: [ { - title: 'Overview', + title: 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/ui/fields', }, { - title: 'Common ettings', + title: 'Common settings', + 'title.fr-FR': 'Paramètres communs', 'title.zh-CN': '通用配置项', 'title.ja-JP': '一般設定', children: [ { title: 'Table column', + 'title.fr-FR': 'Colonne de tableau', 'title.zh-CN': '表格字段', 'title.ja-JP': 'テーブルカラム', link: '/handbook/ui/fields/generic/table-column', }, { title: 'Form', + 'title.fr-FR': 'Formulaire', 'title.zh-CN': '表单字段', 'title.ja-JP': 'フォームフィールド', link: '/handbook/ui/fields/generic/form-item', }, { title: 'Detail', + 'title.fr-FR': 'Détails', 'title.zh-CN': '详情字段', 'title.ja-JP': '詳細フィールド', link: '/handbook/ui/fields/generic/detail-form-item', }, { title: 'Bulk edit form', + 'title.fr-FR': 'Formulaire d\'édition en masse', 'title.zh-CN': '批量编辑表单', 'title.ja-JP': 'バルク編集フォーム', link: '/handbook/ui/fields/generic/bulk-edit-form-item', }, { title: 'Filter form', + 'title.fr-FR': 'Filtres', 'title.zh-CN': '筛选表单', 'title.ja-JP': 'フィルターフォーム', link: '/handbook/ui/fields/generic/filter-form-item', }, { title: 'Collapse', + 'title.fr-FR': 'Réduire', 'title.zh-CN': '折叠面板', 'title.ja-JP': '折りたたみパネル', link: '/handbook/ui/fields/generic/filter-collapse-item', @@ -914,77 +1051,90 @@ export default [ }, { title: 'Specific settings', + 'title.fr-FR': 'Paramètres spécifiques', 'title.zh-CN': '特有配置项', 'title.ja-JP': '特有設定', children: [ { title: 'Date picker', + 'title.fr-FR': 'Choix de date', 'title.zh-CN': '时间日期', 'title.ja-JP': '日付ピッカー', link: '/handbook/ui/fields/specific/date-picker', }, { title: 'Cascade select', + 'title.fr-FR': 'Choix en cascade', 'title.zh-CN': '级联选择', 'title.ja-JP': 'カスケードセレクト', link: '/handbook/ui/fields/specific/cascade-select', }, { title: 'Nester', + 'title.fr-FR': 'Imbrication', 'title.zh-CN': '子表单', 'title.ja-JP': 'ネスター', link: '/handbook/ui/fields/specific/nester', }, { title: 'Popover nester', + 'title.fr-FR': 'Imbrication popup', 'title.zh-CN': '子表单(弹窗)', 'title.ja-JP': 'ポップオーバーネスター', link: '/handbook/ui/fields/specific/popover-nester', }, { title: 'Select', + 'title.fr-FR': 'Selecteur', 'title.zh-CN': '选择器', 'title.ja-JP': 'セレクター', link: '/handbook/ui/fields/specific/select', }, { title: 'Record picker', + 'title.fr-FR': 'Selection d\'enregisrement', 'title.zh-CN': '数据选择器', 'title.ja-JP': 'レコードピッカー', link: '/handbook/ui/fields/specific/picker', }, { title: 'Sub table', + 'title.fr-FR': 'Sous table', 'title.zh-CN': '子表格', 'title.ja-JP': 'サブテーブル', link: '/handbook/ui/fields/specific/sub-table', }, { title: 'Sub detail', + 'title.fr-FR': 'Sous détails', 'title.zh-CN': '子详情', 'title.ja-JP': 'サブ詳細', link: '/handbook/ui/fields/specific/sub-detail', }, { title: 'Title', + 'title.fr-FR': 'Titre', 'title.zh-CN': '标题', 'title.ja-JP': 'タイトル', link: '/handbook/ui/fields/specific/title', }, { title: 'Tag', + 'title.fr-FR': 'Tag', 'title.zh-CN': '标签', 'title.ja-JP': 'タグ', link: '/handbook/ui/fields/specific/tag', }, { title: 'File manager', + 'title.fr-FR': 'Gestionnaire de fichier', 'title.zh-CN': '文件管理器', 'title.ja-JP': 'ファイルマネージャー', link: '/handbook/ui/fields/specific/file-manager', }, { title: 'Mask', + 'title.fr-FR': 'Masque', 'title.zh-CN': '掩码', 'title.ja-JP': '掩码', link: '/handbook/field-component-mask', @@ -993,83 +1143,97 @@ export default [ }, { title: 'Field Settings', + 'title.fr-FR': 'Paramètres de champs', 'title.zh-CN': '字段配置项', 'title.ja-JP': 'フィールド設定', children: [ { title: 'Required', + 'title.fr-FR': 'Requis', 'title.zh-CN': '必填', 'title.ja-JP': '必須', link: '/handbook/ui/fields/field-settings/required', }, { title: 'Default value', + 'title.fr-FR': 'Valeur par défaut', 'title.zh-CN': '默认值', 'title.ja-JP': 'デフォルト値', link: '/handbook/ui/fields/field-settings/default-value', }, { title: 'Validation rules', + 'title.fr-FR': 'Règle de validation', 'title.zh-CN': '验证规则', 'title.ja-JP': '検証ルール', link: '/handbook/ui/fields/field-settings/validation-rules', }, { title: 'Number format', + 'title.fr-FR': 'Format de nombre', 'title.zh-CN': '数值格式化', 'title.ja-JP': '数値フォーマット', link: '/handbook/ui/fields/field-settings/number-format', }, { title: 'Set the data scope', + 'title.fr-FR': 'Périmètre de données', 'title.zh-CN': '设置数据范围', 'title.ja-JP': 'データ範囲を設定', link: '/handbook/ui/fields/field-settings/data-scope', }, { title: 'Title field', + 'title.fr-FR': 'Titre', 'title.zh-CN': '标题字段', 'title.ja-JP': 'タイトルフィールド', link: '/handbook/ui/fields/field-settings/title-field', }, { title: 'Pattern', + 'title.fr-FR': 'Pattern', 'title.zh-CN': '显示模式', 'title.ja-JP': '表示パターン', link: '/handbook/ui/fields/field-settings/pattern', }, { title: 'Edit field title', + 'title.fr-FR': 'Modifier le titre', 'title.zh-CN': '编辑字段标题', 'title.ja-JP': 'フィールドタイトルを編集', link: '/handbook/ui/fields/field-settings/edit-title', }, { title: 'Display title', + 'title.fr-FR': 'Afficher le titre', 'title.zh-CN': '显示标题', 'title.ja-JP': '表示タイトル', link: '/handbook/ui/fields/field-settings/display-title', }, { title: 'Edit description', + 'title.fr-FR': 'Modifier la description', 'title.zh-CN': '编辑描述', 'title.ja-JP': '説明を編集', link: '/handbook/ui/fields/field-settings/edit-description', }, { title: 'Edit tooltip', + 'title.fr-FR': 'Modifier l\'infobulle', 'title.zh-CN': '编辑提示信息', 'title.ja-JP': 'ツールチップを編集', link: '/handbook/ui/fields/field-settings/edit-tooltip', }, { title: 'Field Component', + 'title.fr-FR': 'Composant du champ', 'title.zh-CN': '字段组件', 'title.ja-JP': 'フィールドコンポーネント', link: '/handbook/ui/fields/field-settings/field-component', }, { title: 'Style', + 'title.fr-FR': 'Style', 'title.zh-CN': '样式', 'title.ja-JP': 'スタイル', link: '/handbook/ui/fields/field-settings/style', @@ -1077,7 +1241,8 @@ export default [ ], }, { - title: 'Asscoation field component', + title: 'Association field component', + 'title.fr-FR': 'Composant de champ associé', 'title.zh-CN': '关系字段组件', 'title.ja-JP': '関連フィールドコンポーネント', link: '/handbook/ui/fields/association-field', @@ -1086,64 +1251,75 @@ export default [ }, { title: 'Actions', + 'title.fr-FR': 'Actions', 'title.zh-CN': '操作', 'title.ja-JP': 'アクション', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/ui/actions', }, { title: 'Common settings', + 'title.fr-FR': 'Parmètres communs', 'title.zh-CN': '通用配置项', 'title.ja-JP': '一般設定', children: [ { title: 'Linkage rule', + 'title.fr-FR': 'Règles de liaison', 'title.zh-CN': '联动规则', 'title.ja-JP': '連動ルール', link: '/handbook/ui/actions/action-settings/linkage-rule', }, { title: 'Open mode', + 'title.fr-FR': 'Mode d\'ouverture', 'title.zh-CN': '打开方式', 'title.ja-JP': 'オープンモード', link: '/handbook/ui/actions/action-settings/open-mode', }, { title: 'Popup size', + 'title.fr-FR': 'Taille de popup', 'title.zh-CN': '弹窗尺寸', 'title.ja-JP': 'ポップアップサイズ', link: '/handbook/ui/actions/action-settings/popup-size', }, { title: 'Secondary confirmation', + 'title.fr-FR': 'Confirmation secondaire', 'title.zh-CN': '二次确认', 'title.ja-JP': '二次確認', link: '/handbook/ui/actions/action-settings/double-check', }, { title: 'Bind workflows', + 'title.fr-FR': 'Liaison de workflows', 'title.zh-CN': '绑定工作流', 'title.ja-JP': 'ワークフローをバインド', link: '/handbook/ui/actions/action-settings/bind-workflow', }, { title: 'Assign field values', + 'title.fr-FR': 'Assignation de valeurs de champ', 'title.zh-CN': '字段赋值', 'title.ja-JP': 'フィールド値を割り当て', link: '/handbook/ui/actions/action-settings/assign-values', }, { title: 'Edit button', + 'title.fr-FR': 'Modification de boutons', 'title.zh-CN': '编辑按钮', 'title.ja-JP': 'ボタンを編集', link: '/handbook/ui/actions/action-settings/edit-button', }, { title: 'After successful submission', + 'title.fr-FR': 'Après soumission en succès', 'title.zh-CN': '提交成功后', 'title.ja-JP': '送信成功後', link: '/handbook/ui/actions/action-settings/affter-successful', @@ -1152,125 +1328,146 @@ export default [ }, { title: 'Action types', + 'title.fr-FR': 'Types d\'action', 'title.zh-CN': '操作类型', 'title.ja-JP': 'アクションタイプ', children: [ { title: 'View', + 'title.fr-FR': 'Vue', 'title.zh-CN': '查看', 'title.ja-JP': '表示', link: '/handbook/ui/actions/types/view', }, { title: 'Filter', + 'title.fr-FR': 'Filtre', 'title.zh-CN': '筛选', 'title.ja-JP': 'フィルター', link: '/handbook/ui/actions/types/filter', }, { title: 'Add new', + 'title.fr-FR': 'Ajouter un nouveau type', 'title.zh-CN': '添加', 'title.ja-JP': '追加', link: '/handbook/ui/actions/types/add-new', }, { title: 'Link', + 'title.fr-FR': 'Lien', 'title.zh-CN': '链接', 'title.ja-JP': 'リンク', link: '/handbook/ui/actions/types/link', }, { title: 'Edit', + 'title.fr-FR': 'Modifier', 'title.zh-CN': '编辑', 'title.ja-JP': '編集', link: '/handbook/ui/actions/types/edit', }, { title: 'Delete', + 'title.fr-FR': 'Supprimer', 'title.zh-CN': '删除', 'title.ja-JP': '削除', link: '/handbook/ui/actions/types/delete', }, { title: 'Refresh', + 'title.fr-FR': 'Rafraichir', 'title.zh-CN': '刷新', 'title.ja-JP': 'リフレッシュ', link: '/handbook/ui/actions/types/refresh', }, { title: 'Add record', + 'title.fr-FR': 'Ajouter', 'title.zh-CN': '添加记录', 'title.ja-JP': 'レコードを追加', link: '/handbook/ui/actions/types/add-record', }, { title: 'Custom pop-up', + 'title.fr-FR': 'Pop-up personalisée', 'title.zh-CN': '自定义弹窗', 'title.ja-JP': 'カスタムポップアップ', link: '/handbook/ui/actions/types/pop-up', }, { title: 'Update record', + 'title.fr-FR': 'Mettre à jour', 'title.zh-CN': '更新记录', 'title.ja-JP': 'レコードを更新', link: '/handbook/ui/actions/types/update-record', }, { title: 'Save record', + 'title.fr-FR': 'Enregistrer', 'title.zh-CN': '保存记录', 'title.ja-JP': 'レコードを保存', link: '/handbook/ui/actions/types/save-record', }, { title: 'Submit', + 'title.fr-FR': 'Soumettre', 'title.zh-CN': '提交', 'title.ja-JP': '送信', link: '/handbook/ui/actions/types/submit', }, { title: 'Trigger workflow', + 'title.fr-FR': 'Déclencher un workflow', 'title.zh-CN': '触发工作流', 'title.ja-JP': 'ワークフローをトリガー', link: '/handbook/ui/actions/types/trigger-workflow', }, { title: 'Bulk edit', + 'title.fr-FR': 'Modifier en masse', 'title.zh-CN': '批量编辑', 'title.ja-JP': 'バルク編集', link: '/handbook/action-bulk-edit', }, { title: 'Bulk update', + 'title.fr-FR': 'Mettre à jour en masse', 'title.zh-CN': '批量更新', 'title.ja-JP': 'バルク更新', link: '/handbook/action-bulk-update', }, { title: 'Custom request', + 'title.fr-FR': 'Requête personnalisée', 'title.zh-CN': '自定义请求', 'title.ja-JP': 'カスタムリクエスト', link: '/handbook/action-custom-request', }, { title: 'Duplicate', + 'title.fr-FR': 'Duppliquer', 'title.zh-CN': '复制', 'title.ja-JP': '複製', link: '/handbook/action-duplicate', }, { title: 'Print', + 'title.fr-FR': 'Imprimer', 'title.zh-CN': '打印', 'title.ja-JP': '印刷', link: '/handbook/action-print', }, { title: 'Template print', + 'title.fr-FR': 'Template d\'impression', 'title.zh-CN': '模板打印', link: '/handbook/action-template-print', }, { title: 'Import', + 'title.fr-FR': 'Importer', 'title.zh-CN': '导入', 'title.ja-JP': 'インポート', link: '/handbook/action-import', @@ -1282,6 +1479,7 @@ export default [ }, { title: 'Export', + 'title.fr-FR': 'Exporter', 'title.zh-CN': '导出', 'title.ja-JP': 'エクスポート', link: '/handbook/action-export', @@ -1293,6 +1491,7 @@ export default [ }, { title: 'Scan QR code', + 'title.fr-FR': 'Scanner un QR code', 'title.zh-CN': '扫二维码', 'title.ja-JP': 'QRコードをスキャン', link: '/handbook/action-qr-scan', @@ -1303,26 +1502,31 @@ export default [ }, { title: 'Variables', + 'title.fr-FR': 'Variables', 'title.zh-CN': '变量', 'title.ja-JP': '変数', link: '/handbook/ui/variables', }, { title: 'Template engines', + 'title.fr-FR': 'Moteur de template', 'title.zh-CN': '模板引擎', children: [ { title: 'JSON template', + 'title.fr-FR': 'Template JSON', 'title.zh-CN': 'JSON 模板', link: '/handbook/template-json', }, { title: 'String template', + 'title.fr-FR': 'Template String', 'title.zh-CN': '字符串模板', link: '/handbook/template-string', }, { title: 'Handlebars', + 'title.fr-FR': 'Template Handlebars', 'title.zh-CN': 'Handlebars', link: '/handbook/template-handlebars', }, @@ -1351,6 +1555,7 @@ export default [ }, { title: 'Mobile', + 'title.fr-FR': 'Mobile', 'title.zh-CN': '移动端', 'title.ja-JP': 'モバイル', link: '/handbook/mobile', @@ -1359,17 +1564,20 @@ export default [ }, { title: 'Core modules', + 'title.fr-FR': 'Core modules', 'title.zh-CN': '核心模块', 'title.ja-JP': 'コアモジュール', type: 'group', children: [ { title: 'Users & permissions', + 'title.fr-FR': 'Utilisateurs et droits', 'title.zh-CN': '用户和权限', 'title.ja-JP': 'ユーザーと権限', children: [ { title: 'Users', + 'title.fr-FR': 'Utilisateurs', 'title.zh-CN': '用户', 'title.ja-JP': 'ユーザー', // subTitle: '@nocobase/plugin-users', @@ -1377,23 +1585,27 @@ export default [ }, { title: 'Roles & permissions', + 'title.fr-FR': 'Rôles et droits', 'title.zh-CN': '角色和权限', 'title.ja-JP': '役割と権限', link: '/handbook/acl', }, { title: 'Departments', + 'title.fr-FR': 'Départements', 'title.zh-CN': '部门', 'title.ja-JP': '部門', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/departments', }, { title: 'User manual', + 'title.fr-FR': 'Gestion des départements', 'title.zh-CN': '使用手册', 'title.ja-JP': 'ユーザーマニュアル', link: '/handbook/departments/manual', @@ -1402,23 +1614,28 @@ export default [ }, { title: 'Synchronization', + 'title.fr-FR': 'Synchronisation', 'title.zh-CN': '同步', children: [ { title: 'Synchronization management', + 'title.fr-FR': 'Synchronisation des données utilisateurs', 'title.zh-CN': '同步管理', link: '/handbook/user-data-sync', }, { title: 'Data sources', + 'title.fr-FR': 'Sources de données', 'title.zh-CN': '数据源', children: [ { title: 'HTTP API', + 'title.fr-FR': 'HTTP API', link: '/handbook/user-data-sync/sources/api', }, { title: 'WeCom', + 'title.fr-FR': 'WeCom', 'title.zh-CN': '企业微信', link: '/handbook/wecom/user-data-sync', }, @@ -1426,6 +1643,7 @@ export default [ }, { title: 'Development', + 'title.fr-FR': 'Développement', 'title.zh-CN': '开发指南', children: [ { @@ -1448,29 +1666,34 @@ export default [ }, { title: 'Users authentication', + 'title.fr-FR': 'Authentification des utilisateurs', 'title.zh-CN': '用户认证', 'title.ja-JP': 'ユーザー認証', children: [ { title: 'Authentication', + 'title.fr-FR': 'Authentification', 'title.zh-CN': '用户认证', 'title.ja-JP': 'ユーザー認証', // subTitle: '@nocobase/plugin-auth', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/auth', }, { title: 'User manual', + 'title.fr-FR': 'Gestion de l\'authentification', 'title.zh-CN': '使用手册', 'title.ja-JP': 'ユーザーマニュアル', link: '/handbook/auth/user', }, { title: 'Development', + 'title.fr-FR': 'Développement', 'title.zh-CN': '开发指南', 'title.ja-JP': '開発ガイド', children: [ @@ -1492,6 +1715,7 @@ export default [ }, { title: 'Authentication - SMS', + 'title.fr-FR': 'Authentification - SMS', 'title.zh-CN': '用户认证 - 短信', 'title.ja-JP': 'ユーザー認証 - SMS', // subTitle: '@nocobase/plugin-sms-auth', @@ -1499,6 +1723,7 @@ export default [ }, { title: 'Authentication - CAS', + 'title.fr-FR': 'Authentification - CAS', 'title.zh-CN': '用户认证 - CAS', 'title.ja-JP': 'ユーザー認証 - CAS', // subTitle: '@nocobase/plugin-cas', @@ -1506,18 +1731,21 @@ export default [ }, { title: 'Authentication - OIDC', + 'title.fr-FR': 'Authentification - OIDC', 'title.zh-CN': '用户认证 - OIDC', 'title.ja-JP': 'ユーザー認証 - OIDC', // subTitle: '@nocobase/plugin-oidc', children: [ { title: 'User manual', + 'title.fr-FR': 'OIDC', 'title.zh-CN': '使用手册', 'title.ja-JP': 'ユーザーマニュアル', link: '/handbook/auth-oidc', }, { title: 'Example', + 'title.fr-FR': 'Exemple', 'title.zh-CN': '示例', 'title.ja-JP': '例', children: [ @@ -1539,18 +1767,21 @@ export default [ }, { title: 'Authentication - SAML', + 'title.fr-FR': 'Authentification - SAML', 'title.zh-CN': '用户认证 - SAML', 'title.ja-JP': 'ユーザー認証 - SAML', // subTitle: '@nocobase/plugin-saml', children: [ { title: 'User manual', + 'title.fr-FR': 'SAML', 'title.zh-CN': '使用手册', 'title.ja-JP': 'ユーザーマニュアル', link: '/handbook/auth-saml', }, { title: 'Example', + 'title.fr-FR': 'Exemple', 'title.zh-CN': '示例', 'title.ja-JP': '例', children: [ @@ -1566,12 +1797,14 @@ export default [ }, { title: 'Authentication - LDAP', + 'title.fr-FR': 'Authentification - LDAP', 'title.zh-CN': '用户认证 - LDAP', 'title.ja-JP': 'ユーザー認証 - LDAP', // subTitle: '@nocobase/plugin-saml', children: [ { title: 'User manual', + 'title.fr-FR': 'LDAP', 'title.zh-CN': '使用手册', 'title.ja-JP': 'ユーザーマニュアル', link: '/handbook/auth-ldap', @@ -1580,18 +1813,21 @@ export default [ }, { title: 'Authentication - DingTalk', + 'title.fr-FR': 'Authentification - DingTalk', 'title.zh-CN': '用户认证 - 钉钉', 'title.ja-JP': 'ユーザー認証 - DingTalk', link: '/handbook/auth-dingtalk', }, { title: 'Authentication - WeCom', + 'title.fr-FR': 'Authentification -WeCom', 'title.zh-CN': '用户认证 - 企业微信', 'title.ja-JP': 'ユーザー認証 - WeCom', link: '/handbook/wecom/auth', }, { title: 'Verification', + 'title.fr-FR': 'Vérification', 'title.zh-CN': '验证码', 'title.ja-JP': '検証', // subTitle: '@nocobase/plugin-verification', @@ -1599,6 +1835,7 @@ export default [ }, { title: 'API Keys', + 'title.fr-FR': 'Clés API', 'title.zh-CN': 'API 密钥', 'title.ja-JP': 'APIキー', // subTitle: '@nocobase/plugin-verification', @@ -1608,22 +1845,26 @@ export default [ }, { title: 'Notification', + 'title.fr-FR': 'Notifications', 'title.zh-CN': '通知', 'title.ja-JP': '通知', children: [ { title: 'Notification manager', + 'title.fr-FR': 'Gestionnaire de notifications', 'title.zh-CN': '通知管理', 'title.ja-JP': '通知管理', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/notification-manager', }, { title: 'Development', + 'title.fr-FR': 'Développement', 'title.zh-CN': '开发指南', children: [ { @@ -1642,18 +1883,21 @@ export default [ }, { title: 'Notification: In-app message', + 'title.fr-FR': 'Notification: message In-App', 'title.zh-CN': '通知:站内信', 'title.ja-JP': '通知:アプリ内メッセージ', link: '/handbook/notification-in-app-message', }, { title: 'Notification: Email', + 'title.fr-FR': 'Notification: Email', 'title.zh-CN': '通知:电子邮件', 'title.ja-JP': '通知:メール', link: '/handbook/notification-email', }, { title: 'Notification: WeCom', + 'title.fr-FR': 'Notification: WeCom', 'title.zh-CN': '通知:企业微信', link: '/handbook/wecom/notification', }, @@ -1661,29 +1905,34 @@ export default [ }, { title: 'File manager', + 'title.fr-FR': 'Gestionnaire de fichiers', 'title.zh-CN': '文件管理器', 'title.ja-JP': 'ファイルマネージャー', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/file-manager', }, { title: 'File collection', + 'title.fr-FR': 'Collection de fichiers', 'title.zh-CN': '文件表', 'title.ja-JP': 'ファイルコレクション', link: '/handbook/file-manager/file-collection', }, { title: 'Attachment field', + 'title.fr-FR': 'Champ de fichier', 'title.zh-CN': '附件字段', 'title.ja-JP': '添付フィールド', link: '/handbook/file-manager/field-attachment', }, { title: 'File storage', + 'title.fr-FR': 'Stockage des fichiers', 'title.zh-CN': '文件存储引擎', 'title.ja-JP': 'ファイルストレージエンジン', children: [ @@ -1695,24 +1944,28 @@ export default [ }, { title: 'File storage: Local', + 'title.fr-FR': 'Stockage local', 'title.zh-CN': '文件存储:本地', 'title.ja-JP': 'ファイルストレージ:ローカル', link: '/handbook/file-manager/storage/local', }, { title: 'File storage: OSS', + 'title.fr-FR': 'Stockage OSS', 'title.zh-CN': '文件存储:OSS', 'title.ja-JP': 'ファイルストレージ:OSS', link: '/handbook/file-manager/storage/aliyun-oss', }, { title: 'File storage: S3', + 'title.fr-FR': 'Stockage S3', 'title.zh-CN': '文件存储:S3', 'title.ja-JP': 'ファイルストレージ:S3', link: '/handbook/file-manager/storage/amazon-s3', }, { title: 'File storage: COS', + 'title.fr-FR': 'Stockage COS', 'title.zh-CN': '文件存储:COS', 'title.ja-JP': 'ファイルストレージ:COS', link: '/handbook/file-manager/storage/tencent-cos', @@ -1727,6 +1980,7 @@ export default [ }, { title: 'Development', + 'title.fr-FR': 'Développement', 'title.zh-CN': '扩展开发', link: '/handbook/file-manager/development', }, @@ -1734,11 +1988,13 @@ export default [ }, { title: 'Logging and monitoring', + 'title.fr-FR': 'Log et suppervision', 'title.zh-CN': '日志和监控', 'title.ja-JP': 'ログと監視', children: [ { title: 'Logger', + 'title.fr-FR': 'Log', 'title.zh-CN': '日志', 'title.ja-JP': 'ログ', // subTitle: '@nocobase/plugin-logger', @@ -1746,6 +2002,7 @@ export default [ }, { title: 'Telemetry - Prometheus', + 'title.fr-FR': 'Télémétrie - Prometheus', 'title.zh-CN': '遥测 - Prometheus', 'title.ja-JP': 'テレメトリ - Prometheus', // subTitle: '@nocobase/plugin-telemetry-prometheus', @@ -1753,6 +2010,7 @@ export default [ }, { title: 'Audit logs', + 'title.fr-FR': 'Log d\'audit', 'title.zh-CN': '审计日志', 'title.ja-JP': '監査ログ', // subTitle: '@nocobase/plugin-audit-logs', @@ -1762,40 +2020,47 @@ export default [ }, { title: 'Data visualization', + 'title.fr-FR': 'Visualisation des données', 'title.zh-CN': '数据可视化', 'title.ja-JP': 'データビジュアライゼーション', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/handbook/data-visualization', }, { title: 'User manual', + 'title.fr-FR': 'Documentation', 'title.zh-CN': '使用手册', 'title.ja-JP': 'ユーザーマニュアル', children: [ { title: 'Basic usage', + 'title.fr-FR': 'Utilisation de base', 'title.zh-CN': '基本使用', 'title.ja-JP': '基本的な使い方', type: 'group', children: [ { title: 'Chart block', + 'title.fr-FR': 'Graphiques', 'title.zh-CN': '图表区块', 'title.ja-JP': 'チャートブロック', link: '/handbook/data-visualization/user/chart-block', }, { title: 'Configure chart', + 'title.fr-FR': 'Configuration de graphique', 'title.zh-CN': '配置图表', 'title.ja-JP': 'チャートを設定', link: '/handbook/data-visualization/user/Configure', }, { title: 'Filter block', + 'title.fr-FR': 'Filtres', 'title.zh-CN': '筛选区块', 'title.ja-JP': 'フィルターブロック', link: '/handbook/data-visualization/user/filter', @@ -1804,6 +2069,7 @@ export default [ }, { title: 'Ant design charts', + 'title.fr-FR': 'Graphique Ant', type: 'group', children: [ { @@ -1852,6 +2118,7 @@ export default [ }, { title: 'Ant design', + 'title.fr-FR': 'Design Ant', type: 'group', children: [ { @@ -1956,17 +2223,20 @@ export default [ }, { title: 'Development', + 'title.fr-FR': 'Développement', 'title.zh-CN': '开发指南', 'title.ja-JP': '開発ガイド', children: [ { title: 'Extend chart types', + 'title.fr-FR': 'Extension de type de graphique', 'title.zh-CN': '扩展图表类型', 'title.ja-JP': 'チャートタイプを拡張', link: '/handbook/data-visualization/dev/', }, { title: 'Example of integrating ECharts', + 'title.fr-FR': 'Exemple d\'intégration ECharts', 'title.zh-CN': 'ECharts 集成示例', 'title.ja-JP': 'ECharts統合の例', link: '/handbook/data-visualization/step-by-step', @@ -1975,6 +2245,7 @@ export default [ }, { title: 'FAQ', + 'title.fr-FR': 'FAQ', 'title.zh-CN': '常见问题', 'title.ja-JP': 'よくある質問', link: '/handbook/data-visualization/faq', @@ -1983,6 +2254,7 @@ export default [ }, { title: 'Multi-app manager', + 'title.fr-FR': 'Gestionnaire multi-App', 'title.zh-CN': '多应用管理', 'title.ja-JP': 'マルチアプリ管理', // subTitle: '@nocobase/plugin-api-doc', @@ -2012,6 +2284,7 @@ export default [ }, { title: 'Workflow', + 'title.fr-FR': 'Workflow', 'title.zh-CN': '工作流', 'title.ja-JP': 'ワークフロー', type: 'group', @@ -2030,6 +2303,7 @@ export default [ }, { title: 'Advanced', + 'title.fr-FR': 'Avancé', 'title.zh-CN': '进阶理解', 'title.ja-JP': '高度な理解', children: [ @@ -2061,6 +2335,7 @@ export default [ }, { title: 'Triggers', + 'title.fr-FR': 'Déclencheurs', 'title.zh-CN': '触发器', 'title.ja-JP': 'トリガー', children: [ @@ -2116,6 +2391,7 @@ export default [ }, { title: 'Nodes', + 'title.fr-FR': 'Noeuds', 'title.zh-CN': '节点', 'title.ja-JP': 'ノード', children: [ @@ -2127,6 +2403,7 @@ export default [ }, { title: 'Control', + 'title.fr-FR': 'Contrôle du workflow', 'title.zh-CN': '流程控制类', 'title.ja-JP': 'フロー制御', type: 'group', @@ -2173,6 +2450,7 @@ export default [ }, { title: 'Calculation', + 'title.fr-FR': 'Calcul', 'title.zh-CN': '运算', 'title.ja-JP': '計算', type: 'group', @@ -2199,6 +2477,7 @@ export default [ }, { title: 'Collection Actions', + 'title.fr-FR': 'Collection Actions', 'title.zh-CN': '数据表操作', 'title.ja-JP': 'コレクションアクション', type: 'group', @@ -2243,6 +2522,7 @@ export default [ }, { title: 'Manual', + 'title.fr-FR': 'Manuel', 'title.zh-CN': '人工处理', 'title.ja-JP': '手動処理', type: 'group', @@ -2263,6 +2543,7 @@ export default [ }, { title: 'Extended', + 'title.fr-FR': 'Etendu', 'title.zh-CN': '扩展类型', 'title.ja-JP': '拡張タイプ', type: 'group', @@ -2309,6 +2590,7 @@ export default [ }, { title: 'Development', + 'title.fr-FR': 'Développement', 'title.zh-CN': '开发指南', 'title.ja-JP': '開発ガイド', children: [ @@ -2340,11 +2622,13 @@ export default [ }, { title: 'Related Plugins', + 'title.fr-FR': 'Plugins associés', 'title.zh-CN': '相关插件', 'title.ja-JP': '関連プラグイン', children: [ { title: 'Post-Action Trigger', + 'title.fr-FR': 'Post-Action Trigger', 'title.zh-CN': '操作后事件', 'title.ja-JP': 'アクション後トリガー', subTitle: '@nocobase/plugin-workflow-action-trigger', @@ -2383,6 +2667,7 @@ export default [ }, { title: 'Aggregate', + 'title.fr-FR': 'Aggregate', 'title.zh-CN': '聚合查询', 'title.ja-JP': '集約クエリ', subTitle: '@nocobase/plugin-workflow-aggregate', @@ -2390,6 +2675,7 @@ export default [ }, { title: 'Approval', + 'title.fr-FR': 'Approval', 'title.zh-CN': '审批', 'title.ja-JP': '承認', subTitle: '@nocobase/plugin-workflow-approval', @@ -2440,6 +2726,7 @@ export default [ }, { title: 'Custom Action Trigger', + 'title.fr-FR': 'Déclencheur d\'action personnalisé', 'title.zh-CN': '自定义操作事件', 'title.ja-JP': 'カスタムアクショントリガー', subTitle: '@nocobase/plugin-workflow-custom-action-trigger', @@ -2478,6 +2765,7 @@ export default [ }, { title: 'Date Calculation', + 'title.fr-FR': 'Calcul de date', 'title.zh-CN': '日期计算', 'title.ja-JP': '日付計算', subTitle: '@nocobase/plugin-workflow-date-calculation', @@ -2485,6 +2773,7 @@ export default [ }, { title: 'Delay', + 'title.fr-FR': 'Retard', 'title.zh-CN': '延时', 'title.ja-JP': '遅延', subTitle: '@nocobase/plugin-workflow-delay', @@ -2492,6 +2781,7 @@ export default [ }, { title: 'Dynamic Calculation', + 'title.fr-FR': 'Calcul dynamique', 'title.zh-CN': '动态表达式', 'title.ja-JP': '動的計算', subTitle: '@nocobase/plugin-workflow-dynamic-calculation', @@ -2518,6 +2808,7 @@ export default [ }, { title: 'JavaScript', + 'title.fr-FR': 'JavaScript', 'title.zh-CN': 'JavaScript 脚本', 'title.ja-JP': 'JavaScript スクリプト', subTitle: '@nocobase/plugin-workflow-javascript', @@ -2525,6 +2816,7 @@ export default [ }, { title: 'JSON Query', + 'title.fr-FR': 'Requête JSON', 'title.zh-CN': 'JSON 解析', 'title.ja-JP': 'JSONクエリ', subTitle: '@nocobase/plugin-workflow-json-query', @@ -2532,6 +2824,7 @@ export default [ }, { title: 'Loop', + 'title.fr-FR': 'Boucle', 'title.zh-CN': '循环', 'title.ja-JP': 'ループ', subTitle: '@nocobase/plugin-workflow-loop', @@ -2539,6 +2832,7 @@ export default [ }, { title: 'Manual Process', + 'title.fr-FR': 'Processus manuel', 'title.zh-CN': '人工处理', 'title.ja-JP': '手動処理', subTitle: '@nocobase/plugin-workflow-manual', @@ -2571,6 +2865,7 @@ export default [ }, { title: 'Parallel', + 'title.fr-FR': 'Parallèle', 'title.zh-CN': '并行分支', 'title.ja-JP': '並行分岐', subTitle: '@nocobase/plugin-workflow-parallel', @@ -2578,13 +2873,15 @@ export default [ }, { title: 'HTTP Request', + 'title.fr-FR': 'Requête HTTP', 'title.zh-CN': 'HTTP 请求', 'title.ja-JP': 'HTTPリクエスト', subTitle: '@nocobase/plugin-workflow-request', link: '/handbook/workflow-request', }, { - title: 'Pre-Action Trigger', + title: 'Pre-action Trigger', + 'title.fr-FR': 'Déclencheur avant action', 'title.zh-CN': '操作前事件', 'title.ja-JP': 'アクション前トリガー', subTitle: '@nocobase/plugin-workflow-request-interceptor', @@ -2630,6 +2927,7 @@ export default [ }, { title: 'Response Message', + 'title.fr-FR': 'Message de réponse', 'title.zh-CN': '响应消息', 'title.ja-JP': 'レスポンスメッセージ', subTitle: '@nocobase/plugin-workflow-response-message', @@ -2637,6 +2935,7 @@ export default [ }, { title: 'SQL Action', + 'title.fr-FR': 'Action SQL', 'title.zh-CN': 'SQL 操作', 'title.ja-JP': 'SQLアクション', subTitle: '@nocobase/plugin-workflow-sql', @@ -2651,6 +2950,7 @@ export default [ }, { title: 'Custom variable', + 'title.fr-FR': 'Variable personnalisée', 'title.zh-CN': '自定义变量', 'title.ja-JP': 'カスタム変数', subTitle: '@nocobase/plugin-workflow-variable', @@ -2658,6 +2958,7 @@ export default [ }, { title: 'Webhook Trigger', + 'title.fr-FR': 'Déclencheur Webhook', 'title.zh-CN': 'Webhook 触发器', 'title.ja-JP': 'Webhook トリガー', subTitle: '@nocobase/plugin-workflow-webhook', @@ -2669,18 +2970,21 @@ export default [ }, { title: 'System management', + 'title.fr-FR': 'Gestion du système', 'title.zh-CN': '系统管理', 'title.ja-JP': 'システム管理', type: 'group', children: [ { title: 'Plugin manager', + 'title.fr-FR': 'Gestionnaire de plugins', 'title.zh-CN': '插件管理', 'title.ja-JP': 'プラグイン管理', link: '/handbook/plugin-manager', }, { title: 'System settings', + 'title.fr-FR': 'Paramètrage système', 'title.zh-CN': '系统设置', 'title.ja-JP': 'システム設定', // subTitle: '@nocobase/plugin-system-settings', @@ -2688,6 +2992,7 @@ export default [ }, { title: 'Language settings', + 'title.fr-FR': 'Langues', 'title.zh-CN': '语言设置', 'title.ja-JP': '言語設定', // subTitle: '@nocobase/plugin-system-settings', @@ -2695,6 +3000,7 @@ export default [ }, { title: 'Theme editor', + 'title.fr-FR': 'Editeur de thèmes', 'title.zh-CN': '主题编辑器', 'title.ja-JP': 'テーマエディタ', // subTitle: '@nocobase/plugin-theme-editor', @@ -2702,6 +3008,7 @@ export default [ }, { title: 'Localization management', + 'title.fr-FR': 'Localisation', 'title.zh-CN': '本地化管理', 'title.ja-JP': 'ローカリゼーション管理', // subTitle: '@nocobase/plugin-localization-management', @@ -2709,6 +3016,7 @@ export default [ }, { title: 'Environment variables', + 'title.fr-FR': 'Variables d\'environnement', 'title.zh-CN': '环境变量', 'title.ja-JP': '环境变量', // subTitle: '@nocobase/plugin-backups', @@ -2716,7 +3024,8 @@ export default [ }, { title: 'Backup manager', - 'title.zh-CN': '备份管理', + 'title.fr-FR': 'Gestionnaire de sauvegardes', + 'title.zh-CN': '备份管理器', 'title.ja-JP': 'バックアップマネージャー', // subTitle: '@nocobase/plugin-backups', link: '/handbook/backups', @@ -2771,12 +3080,14 @@ export default [ }, { title: 'Others', + 'title.fr-FR': 'Autres', 'title.zh-CN': '其他', 'title.ja-JP': 'その他', type: 'group', children: [ { title: 'API doc', + 'title.fr-FR': 'Doc API', 'title.zh-CN': 'API 文档', 'title.ja-JP': 'APIドキュメント', // subTitle: '@nocobase/plugin-api-doc', @@ -2785,18 +3096,21 @@ export default [ }, { title: 'Embed', + 'title.fr-FR': 'Intégration', 'title.zh-CN': '嵌入', 'title.ja-JP': '埋め込み', link: '/handbook/embed', }, { title: 'Custom brand', + 'title.fr-FR': 'Personnaliser la marque', 'title.zh-CN': '自定义品牌', 'title.ja-JP': 'カスタムブランド', link: '/handbook/custom-brand', }, { title: 'Public forms', + 'title.fr-FR': 'Formulaire public', 'title.zh-CN': '公开表单', 'title.ja-JP': '公开表单', link: '/handbook/public-forms', diff --git a/docs/config/manual-bak.ts b/docs/config/manual-bak.ts index 89b4b5caa..29621ca37 100644 --- a/docs/config/manual-bak.ts +++ b/docs/config/manual-bak.ts @@ -1,3 +1,4 @@ +//seems not used yet or anymore export default [ { title: 'Quick Start', diff --git a/docs/config/manual.ts b/docs/config/manual.ts index 4b9e74e79..211c6dc76 100644 --- a/docs/config/manual.ts +++ b/docs/config/manual.ts @@ -1,3 +1,4 @@ +//seems not used yet or anuymore export default [ { title: 'Quick Start', diff --git a/docs/config/nav.ts b/docs/config/nav.ts index 6604c76bb..a7ca462ea 100644 --- a/docs/config/nav.ts +++ b/docs/config/nav.ts @@ -1,6 +1,7 @@ export default [ { title: 'Welcome', + 'title.fr-FR': 'Bienvenue', 'title.zh-CN': '欢迎', 'title.ja-JP': 'ようこそ', link: '/welcome/introduction', @@ -25,6 +26,7 @@ export default [ // }, { title: 'Handbook', + 'title.fr-FR': 'Manuel', 'title.zh-CN': '使用手册', 'title.ja-JP': 'ハンドブック', link: '/handbook', @@ -43,27 +45,32 @@ export default [ // }, { title: 'Plugin development', + 'title.fr-FR': 'Développement de plugin', 'title.zh-CN': '插件开发', 'title.ja-JP': 'プラグイン開発', link: '/development', }, { title: 'Plugin samples', + 'title.fr-FR': 'Exemples de plugin', 'title.zh-CN': '插件示例', 'title.ja-JP': 'プラグインサンプル', link: '/plugin-samples' }, { title: 'API reference', + 'title.fr-FR': 'Référence API', 'title.zh-CN': 'API 参考', 'title.ja-JP': 'API リファレンス', link: '/api', }, { title: 'NocoBase Home', + 'title.fr-FR': 'Accueil Nocobase', 'title.zh-CN': 'NocoBase 首页', 'title.ja-JP': 'NocoBase ホーム', link: 'https://www.nocobase.com', + 'link.fr-FR': 'https://www.nocobase.com/fr/', 'link.zh-CN': 'https://www.nocobase.com/cn/', 'link.ja-JP': 'https://www.nocobase.com/ja/', }, diff --git a/docs/config/pluginSamples.ts b/docs/config/pluginSamples.ts index 33bdc7668..cea7161d3 100644 --- a/docs/config/pluginSamples.ts +++ b/docs/config/pluginSamples.ts @@ -1,48 +1,56 @@ export default [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '总览', 'title.ja-JP': '概要', link: '/plugin-samples', }, { title: 'Router', + 'title.fr-FR': 'Routeur', 'title.zh-CN': '前端路由', 'title.ja-JP': 'ルーター', type: 'group', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/plugin-samples/router', }, { title: 'Add Page', + 'title.fr-FR': 'Ajouter une page', 'title.zh-CN': '新增页面', 'title.ja-JP': 'ページを追加', link: '/plugin-samples/router/add-page', }, { title: 'Replace Page', + 'title.fr-FR': 'Remplacer une page', 'title.zh-CN': '替换页面', 'title.ja-JP': 'ページを置き換える', link: '/plugin-samples/router/replace-page', }, { title: 'Add Plugin Setting Page (Single Route)', + 'title.fr-FR': 'Ajouter un page de paramètrage de plugin (Route simple)', 'title.zh-CN': '插件配置页面(单个路由)', 'title.ja-JP': 'プラグイン設定ページ(単一ルート)', link: '/plugin-samples/router/add-setting-page-single-route', }, { title: 'Add Plugin Setting Page (Tabs Routes)', + 'title.fr-FR': 'Ajouter un page de paramètrage de plugin (Route tabs)', 'title.zh-CN': '插件配置页面(Tabs 路由)', 'title.ja-JP': 'プラグイン設定ページ(タブルート)', link: '/plugin-samples/router/add-setting-page-tabs-routes', }, { title: 'Add Plugin Setting Page (different Routes)', + 'title.fr-FR': 'Ajouter un page de paramètrage de plugin (Route différente)', 'title.zh-CN': '插件配置页面(不同布局)', 'title.ja-JP': 'プラグイン設定ページ(異なるルート)', link: '/plugin-samples/router/add-setting-page-layout-routes', @@ -51,30 +59,35 @@ export default [ }, { title: 'Plugin Settings', + 'title.fr-FR': 'Paramètres de plugin', 'title.zh-CN': '插件配置', 'title.ja-JP': 'プラグイン設定', type: 'group', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/plugin-samples/plugin-settings', }, { title: 'Form Configuration Page', + 'title.fr-FR': 'Page de configuration de formulaire', 'title.zh-CN': '表单配置页面', 'title.ja-JP': 'フォーム設定ページ', link: '/plugin-samples/plugin-settings/form', }, { title: 'Table Configuration Page', + 'title.fr-FR': 'Page de configuration de tableau', 'title.zh-CN': '表格配置页面', 'title.ja-JP': 'テーブル設定ページ', link: '/plugin-samples/plugin-settings/table', }, { title: 'Table Configuration Page (Multiple Add Forms)', + 'title.fr-FR': 'Page de configuration de tableau (Fomulaire d\'ajout multiple)', 'title.zh-CN': '表格配置页面(多个新增表单)', 'title.ja-JP': 'テーブル設定ページ(複数の追加フォーム)', link: '/plugin-samples/plugin-settings/table-multiple-add-forms', @@ -83,24 +96,28 @@ export default [ }, { title: 'Provider', + 'title.fr-FR': 'Fournisseur', 'title.zh-CN': 'Provider', 'title.ja-JP': 'プロバイダー', type: 'group', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/plugin-samples/provider', }, { title: 'Global Content', + 'title.fr-FR': 'Contenu global', 'title.zh-CN': '全局内容', 'title.ja-JP': 'グローバルコンテンツ', link: '/plugin-samples/provider/content', }, { title: 'Global Context', + 'title.fr-FR': 'Context global', 'title.zh-CN': '全局上下文', 'title.ja-JP': 'グローバルコンテキスト', link: '/plugin-samples/provider/context', @@ -109,24 +126,28 @@ export default [ }, { title: 'Component and Scope', + 'title.fr-FR': 'Composants et périmètre', 'title.zh-CN': 'Component 和 Scope 注册和使用', 'title.ja-JP': 'コンポーネントとスコープの登録と使用', type: 'group', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/plugin-samples/component-and-scope', }, { title: 'Global Registration of Component and Scope', + 'title.fr-FR': 'Enregistrement global du composant et de la portée', 'title.zh-CN': '全局注册和使用', 'title.ja-JP': 'グローバル登録と使用', link: '/plugin-samples/component-and-scope/global', }, { title: 'Local Registration of Component and Scope', + 'title.fr-FR': 'Enregistrement local du composant et de la portée', 'title.zh-CN': '局部注册和使用', 'title.ja-JP': 'ローカル登録と使用', link: '/plugin-samples/component-and-scope/local', @@ -135,54 +156,63 @@ export default [ }, { title: 'SchemaInitializer', + 'title.fr-FR': 'SchemaInitializer', 'title.zh-CN': 'SchemaInitializer', 'title.ja-JP': 'スキーマ初期化', type: 'group', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/plugin-samples/schema-initializer', }, { title: 'Add Simple Block', + 'title.fr-FR': 'Ajout de bloc simple', 'title.zh-CN': '添加简单区块 Simple Block', 'title.ja-JP': 'シンプルブロックを追加', link: '/plugin-samples/schema-initializer/block-simple', }, { title: 'Add Data Block', + 'title.fr-FR': 'Ajout de bloc données', 'title.zh-CN': '添加数据区块 Data Block', 'title.ja-JP': 'データブロックを追加', link: '/plugin-samples/schema-initializer/block-data', }, { title: 'Add Data Block Modal', + 'title.fr-FR': 'Ajout de bloc données modal', 'title.zh-CN': '添加带弹窗的数据区块 Data Block Modal', 'title.ja-JP': 'モーダルデータブロックを追加', link: '/plugin-samples/schema-initializer/block-data-modal', }, { title: 'Add Simple Action', + 'title.fr-FR': 'Ajout d\'action simple', 'title.zh-CN': '添加简单 Action', 'title.ja-JP': 'シンプルアクションを追加', link: '/plugin-samples/schema-initializer/action-simple', }, { title: 'Add Modal Action', + 'title.fr-FR': 'Ajout d\'action modal', 'title.zh-CN': '添加弹窗 Action', 'title.ja-JP': 'モーダルアクションを追加', link: '/plugin-samples/schema-initializer/action-modal', }, { title: 'Configure Actions', + 'title.fr-FR': 'Configuration d\'action', 'title.zh-CN': '区块内嵌的 Initializer - 配置操作', 'title.ja-JP': 'ブロック内蔵の初期化 - アクションを設定', link: '/plugin-samples/schema-initializer/configure-actions', }, { title: 'Configure Fields', + 'title.fr-FR': 'Configuration de champs', 'title.zh-CN': '区块内嵌的 Initializer - 配置字段', 'title.ja-JP': 'ブロック内蔵の初期化 - フィールドを設定', link: '/plugin-samples/schema-initializer/configure-fields', @@ -197,24 +227,28 @@ export default [ }, { title: 'SchemaSettings', + 'title.fr-FR': 'SchemaSettings', 'title.zh-CN': 'SchemaSettings', 'title.ja-JP': 'スキーマ設定', type: 'group', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/plugin-samples/schema-settings', }, { title: 'Add Item to Existing SchemaSettings', + 'title.fr-FR': 'Ajout d\'item à un SchemaSettings existant', 'title.zh-CN': '添加子项到已有的 SchemaSettings', 'title.ja-JP': '既存のスキーマ設定にアイテムを追加', link: '/plugin-samples/schema-settings/add-item', }, { title: 'Add New SchemaSettings', + 'title.fr-FR': 'Ajout d\'un noouveau SchemaSettings', 'title.zh-CN': '新增 SchemaSettings', 'title.ja-JP': '新しいスキーマ設定を追加', link: '/plugin-samples/schema-settings/new', @@ -223,30 +257,35 @@ export default [ }, { title: 'Block', + 'title.fr-FR': 'Blocs', 'title.zh-CN': '区块', 'title.ja-JP': 'ブロック', type: 'group', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/plugin-samples/block', }, { title: 'Carousel Block', + 'title.fr-FR': 'Bloc caroussel', 'title.zh-CN': 'Carousel 区块', 'title.ja-JP': 'カルーセルブロック', link: '/plugin-samples/block/block-carousel', }, { title: 'Form Block', + 'title.fr-FR': 'Bloc formulaire', 'title.zh-CN': 'Form 区块', 'title.ja-JP': 'フォームブロック', link: '/plugin-samples/block/block-form', }, { title: 'Table Block', + 'title.fr-FR': 'Bloc tableau', 'title.zh-CN': 'Table 区块', 'title.ja-JP': 'テーブルブロック', link: '/plugin-samples/block/block-table', @@ -255,30 +294,35 @@ export default [ }, { title: 'Field', + 'title.fr-FR': 'Champs', 'title.zh-CN': ' 字段', 'title.ja-JP': 'フィールド', type: 'group', children: [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '概述', 'title.ja-JP': '概要', link: '/plugin-samples/field', }, { title: 'Without Value Field', + 'title.fr-FR': 'Champs sans valeur', 'title.zh-CN': '无值字段组件', 'title.ja-JP': '値なしフィールドコンポーネント', link: '/plugin-samples/field/without-value', }, { title: 'Value Field', + 'title.fr-FR': 'Champ valeur', 'title.zh-CN': '有值字段组件', 'title.ja-JP': '値ありフィールドコンポーネント', link: '/plugin-samples/field/value', }, { title: 'Interface', + 'title.fr-FR': 'Champ interface', 'title.zh-CN': 'Field interface', 'title.ja-JP': 'フィールドインターフェース', link: '/plugin-samples/field/interface', diff --git a/docs/config/plugins.ts b/docs/config/plugins.ts index a7371512c..8677f6d88 100644 --- a/docs/config/plugins.ts +++ b/docs/config/plugins.ts @@ -1,23 +1,28 @@ +//Seems not used yet or anymore export default [ { title: 'Overview', + 'title.fr-FR': 'Vue d\'ensemble', 'title.zh-CN': '插件总览', 'title.ja-JP': '概要', link: '/plugins', }, { title: 'Plugins', + 'title.fr-FR': 'Plugins', 'title.zh-CN': '插件列表', 'title.ja-JP': 'プラグイン', type: 'group', children: [ { title: 'Data modeling', + 'title.fr-FR': 'Modélisation de données', 'title.zh-CN': '数据建模', 'title.ja-JP': 'データモデリング', children: [ { title: 'Collection manager', + 'title.fr-FR': 'Gestionnaire de collections', 'title.zh-CN': '数据表管理', 'title.ja-JP': 'コレクションマネージャー', subTitle: '@nocobase/plugin-collection-manager', diff --git a/docs/config/welcome.ts b/docs/config/welcome.ts index 70535e334..c3f6f1c03 100644 --- a/docs/config/welcome.ts +++ b/docs/config/welcome.ts @@ -1,6 +1,7 @@ export default [ { title: 'Welcome', + 'title.fr-FR': 'Bienvenue', 'title.zh-CN': '欢迎', 'title.ja-JP': 'ようこそ', type: 'group', @@ -14,12 +15,14 @@ export default [ }, { title: 'Getting started', + 'title.fr-FR': 'Démarrer', 'title.zh-CN': '快速开始', 'title.ja-JP': '始めに', type: 'group', children: [ { title: 'Installation', + 'title.fr-FR': 'Installation', 'title.zh-CN': '安装', 'title.ja-JP': 'インストール', children: [ @@ -32,6 +35,7 @@ export default [ }, { title: 'Upgrading', + 'title.fr-FR': 'Upgrading', 'title.zh-CN': '升级', 'title.ja-JP': 'アップグレード', children: [ @@ -43,6 +47,7 @@ export default [ }, { title: 'Deployment', + 'title.fr-FR': 'Déploiement', 'title.zh-CN': '部署', 'title.ja-JP': 'デプロイ', children: [ @@ -110,6 +115,7 @@ export default [ // }, { title: 'Community', + 'title.fr-FR': 'Communauté', 'title.zh-CN': '社区', 'title.ja-JP': 'コミュニティ', type: 'group', diff --git a/docs/fr-FR/_partials/commercial-installation.md b/docs/fr-FR/_partials/commercial-installation.md new file mode 100644 index 000000000..7fc3f660f --- /dev/null +++ b/docs/fr-FR/_partials/commercial-installation.md @@ -0,0 +1,5 @@ +## Installation + +This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager: + +![](https://static-docs.nocobase.com/20240323162741.png) diff --git a/docs/fr-FR/api/acl/acl.md b/docs/fr-FR/api/acl/acl.md new file mode 100644 index 000000000..5129e000f --- /dev/null +++ b/docs/fr-FR/api/acl/acl.md @@ -0,0 +1,284 @@ +# ACL + +## Vue d'ensemble + +`ACL` est le moduel de gestion des permissions de NocoBase. Il est responsable de la gestion des rôles utilisateurs, de l'enregistrement des permissions et des autorisations. Il évalue aussi la politique de permission et le contrôle des accèss. + +### Concepts + +- **Resource**: Collections, ou ressources personnalisées enregistrées. Se reférer à [`@nocobase/resourcer`](../resourcer/resource-manager.md). +- **Action**: Une interface d'opération pour une ressource, comme la création, la lecture, la modification, la suppression ou d'autres actions personnalisées. Se reférer à [`@nocobase/actions`](../actions). +- **Strategy**: Configure des permission globales pour les rôles, comme des permissions pour une opération sur une ressource comme la création, la lecture, la modification, la suppression, l'importation, l'exportation, et les permission système comme configurer l'interface utilisateur. +- **Snippet**: Defines a collection of operations, enabling unified management of operation permissions. Snippet identifiers can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules. +- **Snippet**: Définit une collection d'opérations, permettant un gestion unifié de permission sur opération. Les identifiants de Snippet peuvent être associés en utilisant les règles [minimatch](https://github.com/isaacs/minimatch). + +## Méthode de classe + +### `define()` + +Défini un rôle. + +#### Signature + +- `define(options: DefineOptions): ACLRole` + +#### Définitions du type + +```typescript +export interface DefineOptions { + role: string; + strategy?: string | AvailableStrategyOptions; + actions?: ResourceActionsOptions; + snippets?: string[]; +} + +export interface AvailableStrategyOptions { + displayName?: string; + actions?: false | string | string[]; + allowConfigure?: boolean; + resource?: '*'; +} + +export interface ResourceActionsOptions { + [actionName: string]: RoleActionParams; +} + +export interface RoleActionParams { + fields?: string[]; + filter?: any; + own?: boolean; + whitelist?: string[]; + blacklist?: string[]; +} +``` + +#### Détails + +##### DefineOptions + +| Propriété | Type | Description | +| ---------- | ------------------------------------------------------------------- | ----------------------------------------------------------------- | +| `role` | `string` | Unique identifier for the role | +| `strategy` | `string` \| [`AvailableStrategyOptions`](#availablestrategyoptions) | Optional, global access strategy for the role | +| `actions` | [`{ [actionName: string]: RoleActionParams; }`](#roleactionparams) | Optional, permission configuration for actions | +| `snippets` | `string[]` | Optional, defines snippets that the role has permission to access | + +##### AvailableStrategyOptions + +| Propriété | Type | Description | +| ---------------- | --------------------------------- | --------------------------------------------------------- | +| `displayName` | `string` | Optional, display name for the strategy | +| `action` | `false` \| `string` \| `string[]` | Optional, operation interfaces | +| `allowConfigure` | `boolean` | Optional, whether to allow configuring the user interface | +| `resource` | `*` | Applies to all resources | + +##### RoleActionParams + +| Propriété | Type | Description | +| ----------- | ---------- | ------------------------------------------------------------------------------------------------------ | +| `fields` | `string[]` | Optional, fields of the data table to operate on | +| `filter` | `any` | Optional, filter parameters that must be met, only records that meet the conditions can be operated on | +| `own` | `boolean` | Optional, whether to operate only on records created by oneself | +| `whitelist` | `string[]` | Optional, whitelist of fields that can be accessed, only fields in the whitelist can be accessed | +| `blacklist` | `string[]` | Optional, blacklist of fields that cannot be accessed, fields in the blacklist cannot be accessed | + +### `can()` + +Determines the permission to execute an action and returns the final action parameters. Returns `null` if no permission. + +#### Signature + +- `can(options: CanArgs): CanResult | null` + +#### Type Definitions + +```typescript +interface CanArgs { + role: string; + resource: string; + action: string; + ctx?: any; +} + +interface CanResult { + role: string; + resource: string; + action: string; + params?: any; +} +``` + +#### Details + +##### CanArgs + +| Property | Type | Description | +| ---------- | -------- | ------------------------- | +| `role` | `string` | Role identifier | +| `resource` | `string` | Resource identifier | +| `action` | `string` | Action identifier | +| `ctx` | `any` | Optional, request context | + +##### CanResult + +| Property | Type | Description | +| ---------- | -------- | --------------------------- | +| `role` | `string` | Role identifier | +| `resource` | `string` | Resource identifier | +| `action` | `string` | Action identifier | +| `params` | `any` | Optional, action parameters | + +### `registerSnippet()` + +Registers a snippet. + +#### Signature + +- `registerSnippet(snippet: SnippetOptions)` + +#### Type Definitions + +```typescript +export type SnippetOptions = { + name: string; + actions: string[]; +}; +``` + +#### Details + +| Property | Type | Description | +| --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| `name` | `string` | Snippet identifier, can be matched using the [minimatch](https://github.com/isaacs/minimatch) rules. E.g., `auth.auth` matches `auth.*`. | +| `actions` | `string[]` | Resource operations included in the snippet, in the format `resource:action`. E.g., `users:list`. | + +### `setAvailableAction()` + +Sets allowed actions. + +#### Signature + +- `setAvailableAction(name: string, options: AvailableActionOptions = {})` + +```typescript +export interface AvailableActionOptions { + displayName?: string; + aliases?: string[] | string; + resource?: string; + // Perform operations on new data + onNewRecord?: boolean; + // Allow configuring fields + allowConfigureFields?: boolean; +} +``` + +#### Details + +| Property | Type | Description | +| ---------------------- | ---------------------- | ------------------------------------------------------------------------------------- | +| `displayName` | `string` | Optional, display name for the action | +| `aliases` | `string` \| `string[]` | Optional, action aliases. E.g., aliases for `get`, `list` operations are both `view`. | +| `resource` | `string` | Optional, resource | +| `onNewRecord` | `boolean` | Optional, whether the operation applies to new data, such as create operation | +| `allowConfigureFields` | `boolean` | Optional, whether to allow configuring fields | + +### `setAvailableStrategy()` + +Sets allowed strategies for actions. + +#### Signature + +- `setAvailableStrategy(name: string, options: AvailableStrategyOptions)` + +Refer to [AvailableStrategyOptions](#availablestrategyoptions). + +### `allow()` + +Defines the conditions under which operations are allowed. + +```typescript +acl.allow('plugins', '*', 'public'); +``` + +#### Signature + +- `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)` + +#### Type + +```typescript +export type ConditionFunc = (ctx: any) => Promise | boolean; +``` + +#### Details + +| Parameter | Type | Description | Default | +| -------------- | --------------------------- | --------------------------------------------------------------------------- | -------- | +| `resourceName` | `string` | Resource | - | +| `actionNames` | `string` \| `string[]` | Action | - | +| `condition` | `string` \| `ConditionFunc` | Optional, predefined condition identifier, or condition evaluation function | `public` | + +Predefined condition identifiers: + +- `public`: Public interface. +- `loggedIn`: Allowed when the user is logged in. +- `allowConfigure`: Allowed when the current user role has permission to configure the user interface. + +### `addFixedParams()` + +Adds fixed parameters to operations, merging them with current request parameters. + +```typescript +acl.addFixedParams('users', 'list', () => { + return { + filter: { + id: { + $eq: 1, + }, + }, + }; +}); +``` + +#### Signature + +- `addFixedParams(resource: string, action: string, merger: Merger)` + +#### Type Definitions + +```typescript +export type Merger = () => object; +``` + +#### Details + +| Parameter | Type | Description | +| ---------- | -------- | --------------------------------------------------------- | +| `resource` | `string` | Resource | +| `action` | `string` | Action | +| `merger` | `Merger` | Function returning the fixed parameter object to be added | + +### `use()` + +Adds the `ACL` middleware. + +```typescript +acl.use(async () => { + return async function (ctx, next) { + // ... + await next(); + }; +}); +``` + +#### Signature + +- `use(fn: any, options?: ToposortOptions)` + +#### Details + +Refer to [Middleware](../../development/server/middleware). + +### `middleware()` + +NocoBase access control middleware. diff --git a/docs/fr-FR/api/actions.md b/docs/fr-FR/api/actions.md new file mode 100644 index 000000000..f26bfdcd3 --- /dev/null +++ b/docs/fr-FR/api/actions.md @@ -0,0 +1,243 @@ +# @nocobase/actions + +## Overview + +The `@nocobase/actions` package encapsulates frequently used CRUD-related methods. By simply registering it with the [ResourceManager](./resourcer/resource-manager), CRUD operation interfaces can be globally added to system resources. + +### Basic Usage + +```typescript +import * as actions from `@nocobase/actions`; + +const resourceManager = new ResourceManager({ + // ...options +}); + +resourceManager.registerActionHandlers(actions); +``` + +## Action Methods + +### create + +Creates a resource. `POST /api/:create`. + +```shell +curl "http://localhost:13000/api/users:create" \ + -X POST \ + -H "Content-Type: application/json" \ + -d '{"username": "admin"}' +``` + +#### Request Body + +| Parameter Name | Type | Description | +| --------------- | ----- | ----------------------------------------------- | +| `[key: string]` | `any` | Key-value pairs representing resource fields | + +### list + +Retrieves a list of resources. `GET /api/:list`. + +```shell +curl -X GET http://localhost:13000/api/users:list +``` + +#### Parameters + +| Parameter | Type | Description | Default | +| ---------- | ---------- | ------------------------------------------------------------------ | ------- | +| `filter` | `Filter` | Filtering parameters, see [Filter Operators](./database/operators) | - | +| `fields` | `string[]` | Fields to retrieve | - | +| `except` | `string[]` | Fields to exclude | - | +| `appends` | `string[]` | Related fields to append | - | +| `sort` | `string[]` | Sorting parameters | - | +| `paginate` | `boolean` | Whether to use pagination | `true` | +| `page` | `number` | Current page number | `1` | +| `pageSize` | `number` | Number of items per page | `20` | + +### get + +Retrieves a specific resource. `GET /api/:get`. + +```shell +curl -X GET http://localhost:13000/api/users:get?filterByTk=1 +``` + +#### Parameters + +| Parameter | Type | Description | Default | +| ------------ | ------------------ | ------------------------------------------------------------------ | ------- | +| `filterByTk` | `number \| string` | Filter by primary key value | - | +| `filter` | `Filter` | Filtering parameters, see [Filter Operators](./database/operators) | - | +| `fields` | `string[]` | Fields to retrieve | - | +| `except` | `string[]` | Fields to exclude | - | +| `appends` | `string[]` | Related fields to append | - | + +### update + +Updates one or more resources. `PUT /api/:update`. + +```shell +curl "http://localhost:13000/api/users:update?filterByTk=1" \ + -X PUT \ + -H "Content-Type: application/json" \ + -d '{"username": "admin"}' +``` + +#### Parameters + +| Parameter | Type | Description | +| ------------ | ------------------ | ------------------------------------------------------------------ | +| `filter` | `Filter` | Filtering parameters, see [Filter Operators](./database/operators) | +| `filterByTk` | `number \| string` | Filter by primary key value | + +*Note: At least one of `filter` or `filterByTk` must be provided.* + +#### Request Body + +| Parameter Name | Type | Description | +| --------------- | ----- | ----------------------------------------------- | +| `[key: string]` | `any` | Key-value pairs representing resource fields | + +### destroy + +Deletes one or more resources. `DELETE /api/:destroy`. + +```shell +curl -X DELETE http://localhost:13000/api/users:destroy?filterByTk=1 +``` + +#### Parameters + +| Parameter | Type | Description | +| ------------ | ------------------ | ------------------------------------------------------------------ | +| `filter` | `Filter` | Filtering parameters, see [Filter Operators](./database/operators) | +| `filterByTk` | `number \| string` | Filter by primary key value | + +*Note: At least one of `filter` or `filterByTk` must be provided.* + +### firstOrCreate + +Retrieves or creates a resource. `POST /api/:firstOrCreate`. + +```shell +curl "http://localhost:13000/api/users:firstOrCreate?filterKeys[]=username" \ + -X POST \ + -H "Content-Type: application/json" \ + -d '{"username": "admin", "nickname": "Admin"}' +``` + +#### Parameters + +| Parameter | Type | Description | +| ------------ | ---------- | ---------------------------------------------------------- | +| `filterKeys` | `string[]` | Fields in the request body used to find existing resources | + +#### Request Body + +| Parameter Name | Type | Description | +| --------------- | ----- | ----------------------------------------------- | +| `[key: string]` | `any` | Key-value pairs representing resource fields | + +### updateOrCreate + +Updates or creates a resource. `POST /api/:updateOrCreate`. + +```shell +curl "http://localhost:13000/api/users:updateOrCreate?filterKeys[]=username" \ + -X POST \ + -H "Content-Type: application/json" \ + -d '{"username": "admin", "nickname": "Admin"}' +``` + +#### Parameters + +| Parameter | Type | Description | +| ------------ | ---------- | ---------------------------------------------------------- | +| `filterKeys` | `string[]` | Fields in the request body used to find existing resources | + +#### Request Body + +| Parameter Name | Type | Description | +| --------------- | ----- | ----------------------------------------------- | +| `[key: string]` | `any` | Key-value pairs representing resource fields | + +### move + +Moves resources, adjusting the order. Typically used for drag-and-drop sorting in pages. `POST /api/:move`. + +```shell +curl -X POST "http://localhost:13000/api/users:move?sourceId=1&targetId=2" +``` + +#### Parameters + +| Parameter | Type | Description | Default | +| ------------- | -------------------------- | ----------------------------------------------------------- | ------- | +| `sourceId` | `targetKey` | ID of the element to move | - | +| `targetId` | `targetKey` | ID of the element to swap positions with | - | +| `sortField` | `string` | Name of the field where sorting is stored | `sort` | +| `targetScope` | `string` | Sorting scope, a resource can be sorted by different scopes | - | +| `sticky` | `boolean` | Whether to stick the moved element | - | +| `method` | `insertAfter` \| `prepend` | Insertion method: whether to insert before | + +### set + +Sets associated objects for a resource. `POST /api///:set`. + +```shell +curl "http://localhost:13000/api/users/1/roles:set" \ + -X POST \ + -H "Content-Type: application/json" \ + -d '["admin", "member"]' +``` + +#### Request Body + +- `TargetKey | TargetKey[]` - Array of primary key values for associated objects. + +### add + +Adds associated objects to a resource. `POST /api///:add`. + +```shell +curl "http://localhost:13000/api/users/1/roles:add" \ + -X POST \ + -H "Content-Type: application/json" \ + -d '["admin"]' +``` + +#### Request Body + +- `TargetKey | TargetKey[]` - Array of primary key values for associated objects. + +### remove + +Removes associated objects from a resource. `POST /api///:remove`. + +```shell +curl "http://localhost:13000/api/users/1/roles:remove" \ + -X POST \ + -H "Content-Type: application/json" \ + -d '["admin"]' +``` + +#### Request Body + +- `TargetKey | TargetKey[]` - Array of primary key values for associated objects. + +### toggle + +Toggles associated objects for a resource, adding them if they don't exist, or removing them if they do. `POST /api///:toggle`. + +```shell +curl "http://localhost:13000/api/users/1/roles:toggle" \ + -X POST \ + -H "Content-Type: application/json" \ + -d '["admin", "member"]' +``` + +#### Request Body + +- `TargetKey | TargetKey[]` - Array of primary key values for associated objects. diff --git a/docs/fr-FR/api/auth/auth-manager.md b/docs/fr-FR/api/auth/auth-manager.md new file mode 100644 index 000000000..96126a97c --- /dev/null +++ b/docs/fr-FR/api/auth/auth-manager.md @@ -0,0 +1,175 @@ +# AuthManager + +## Overview + +`AuthManager` is the user authentication management module in NocoBase, used for registering different types of user authentication. + +### Basic Usage + +```ts +const authManager = new AuthManager({ + // Key to retrieve the current authenticator identifier from the request header + authKey: 'X-Authenticator', +}); + +// Set methods for storing and retrieving authenticators in AuthManager +authManager.setStorer({ + get: async (name: string) => { + return db.getRepository('authenticators').find({ filter: { name } }); + }, +}); + +// Register an authentication type +authManager.registerTypes('basic', { + auth: BasicAuth, + title: 'Password', +}); + +// Use authentication middleware +app.resourceManager.use(authManager.middleware()); +``` + +### Concepts + +- **Authentication type (`AuthType`)**: Different types of authentication, such as Password, SMS, OIDC, SAML, etc. +- **Authenticator**: An authenticator is a database-stored entity linked to a configuration record for a specific authentication type (`AuthType`). Multiple authenticators can exist for one authentication type, each offering diffrent authentications. +- **Authenticator name**: Unique identifier for an authenticator, used to determine the current authentication employed by the current request. + +## Class Methods + +### `constructor()` + +Constructor, creates an instance of `AuthManager`. + +#### Signature + +- `constructor(options: AuthManagerOptions)` + +#### Types + +```ts +export interface JwtOptions { + secret: string; + expiresIn?: string; +} + +export type AuthManagerOptions = { + authKey: string; + default?: string; + jwt?: JwtOptions; +}; +``` + +#### Details + +##### AuthManagerOptions + +| Attribute | Type | Description | Default | +| --------- | --------------------------- | ------------------------------------------------------------------------------- | ----------------- | +| `authKey` | `string` | Optional key to save the current authenticator identifier in the request header | `X-Authenticator` | +| `default` | `string` | Optional, default authenticator identifier | `basic` | +| `jwt` | [`JwtOptions`](#jwtoptions) | Optional, configure if using JWT for authentication | - | + +##### JwtOptions + +| Attribute | Type | Description | Default | +| ----------- | -------- | --------------------------------- | ----------------- | +| `secret` | `string` | Token secret key | `X-Authenticator` | +| `expiresIn` | `string` | Optional, token expiration period | `7d` | + +### `setStorer()` + +Set methods for storing and retrieving authenticator data. + +#### Signature + +- `setStorer(storer: Storer)` + +#### Types + +```ts +export interface Authenticator = { + authType: string; + options: Record; + [key: string]: any; +}; + +export interface Storer { + get: (name: string) => Promise; +} +``` + +#### Details + +##### Authenticator + +| Attribute | Type | Description | +| ---------- | --------------------- | ------------------------------------ | +| `authType` | `string` | Authentication type | +| `options` | `Record` | Authenticator-related configurations | + +##### Storer + +`Storer` is the interface for authenticator storage, containing one method. + +- `get(name: string): Promise` - Get authenticator by identifier. In NocoBase, the actual returned type is [AuthModel](../../handbook/auth/dev/api#authmodel). + +### `registerTypes()` + +Register authentication types. + +#### Signature + +- `registerTypes(authType: string, authConfig: AuthConfig)` + +#### Types + +```ts +export type AuthExtend = new (config: Config) => T; + +type AuthConfig = { + auth: AuthExtend; // The authentication class. + title?: string; // The display name of the authentication type. +}; +``` + +#### Details + +| Attribute | Type | Description | +| --------- | ------------------ | -------------------------------------------------------------------- | +| `auth` | `AuthExtend` | Authentication type implementation, refer to [Auth](./auth.md) | +| `title` | `string` | Optional. Title of the authentication type displayed on the frontend | + +### `listTypes()` + +Get a list of registered authentication types. + +#### Signature + +- `listTypes(): { name: string; title: string }[]` + +#### Details + +| Attribute | Type | Description | +| --------- | -------- | -------------------------------- | +| `name` | `string` | Authentication type identifier | +| `title` | `string` | Title of the authentication type | + +### `get()` + +Get authenticator. + +#### Signature + +- `get(name: string, ctx: Context)` + +#### Details + +| Attribute | Type | Description | +| --------- | --------- | ------------------------ | +| `name` | `string` | Authenticator identifier | +| `ctx` | `Context` | Request context | + +### `middleware()` + +Authentication middleware. Get the current authenticator and perform user authentication. diff --git a/docs/fr-FR/api/auth/auth.md b/docs/fr-FR/api/auth/auth.md new file mode 100644 index 000000000..3e07a9197 --- /dev/null +++ b/docs/fr-FR/api/auth/auth.md @@ -0,0 +1,103 @@ +# Auth + +## Overview + +`Auth` is an abstract class for user authentication types, defining the interfaces required to complete user authentication. To extend new user authentication types, you need to inherit from the `Auth` class and implement its methods. The basic implementation can be referred to as [BaseAuth](./base-auth.md). + +```ts +interface IAuth { + user: Model; + // Check the authentication status and return the current user. + check(): Promise; + signIn(): Promise; + signUp(): Promise; + signOut(): Promise; +} + +export abstract class Auth implements IAuth { + abstract user: Model; + abstract check(): Promise; + // ... +} + +class CustomAuth extends Auth { + // check: Authentication + async check() { + // ... + } +} +``` + +## Instance Properties + +### `user` + +Information of the authenticated user. + +#### Signature + +- `abstract user: Model` + +## Class Methods + +### `constructor()` + +Constructor, creates an instance of `Auth`. + +#### Signature + +- `constructor(config: AuthConfig)` + +#### Types + +```ts +export type AuthConfig = { + authenticator: Authenticator; + options: { + [key: string]: any; + }; + ctx: Context; +}; +``` + +#### Details + +##### AuthConfig + +| Attribute | Type | Description | +| --------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| `authenticator` | [`Authenticator`](./auth-manager#authenticator) | Authenticator data model, the actual type in NocoBase applications is [AuthModel](../../handbook/auth/dev/api.md#authmodel) | +| `options` | `Record` | Authenticator-related configurations | +| `ctx` | `Context` | Request context | + +### `check()` + +User authentication, returns user information. This is an abstract method that all authentication types must implement. + +#### Signature + +- `abstract check(): Promise` + +### `signIn()` + +User login. + +#### Signature + +- `signIn(): Promise` + +### `signUp()` + +User registration. + +#### Signature + +- `signUp(): Promise` + +### `signOut()` + +User logout. + +#### Signature + +- `signOut(): Promise` diff --git a/docs/fr-FR/api/auth/base-auth.md b/docs/fr-FR/api/auth/base-auth.md new file mode 100644 index 000000000..315a16561 --- /dev/null +++ b/docs/fr-FR/api/auth/base-auth.md @@ -0,0 +1,70 @@ +# BaseAuth + +## Overview + +`BaseAuth` inherits from the abstract class [Auth](./auth.md) and serves as the basic implementation for user authentication types, using JWT as the authentication method. In most cases, extending user authentication types can be achieved by inheriting from `BaseAuth` instead of directly inheriting from the `Auth` abstract class. + +```ts +class BasicAuth extends BaseAuth { + constructor(config: AuthConfig) { + // Set user collection + const userCollection = config.ctx.db.getCollection('users'); + super({ ...config, userCollection }); + } + + // User authentication logic, called by `auth.signIn` + // Returns user data + async validate() { + const ctx = this.ctx; + const { values } = ctx.action.params; + // ... + return user; + } +} +``` + +## Class Methods + +### `constructor()` + +Constructor, creates an instance of `BaseAuth`. + +#### Signature + +- `constructor(config: AuthConfig & { userCollection: Collection })` + +#### Details + +| Parameter | Type | Description | +| ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------ | +| `config` | `AuthConfig` | Refer to [Auth - AuthConfig](./auth.md#authconfig) | +| `userCollection` | `Collection` | User collection, e.g., `db.getCollection('users')`, refer to [DataBase - Collection](../database/collection) | + +### `user()` + +Accessor for setting and getting user information, defaulting to using the `ctx.state.currentUser` object. + +#### Signature + +- `set user()` +- `get user()` + +### `check()` + +Authenticates through the request token and returns user information. + +### `signIn()` + +User login, generates a token. + +### `signUp()` + +User registration. + +### `signOut()` + +User logout, token expiration. + +### `validate()` \* + +Core authentication logic, called by the `signIn` interface, to determine whether the user can successfully log in. diff --git a/docs/fr-FR/api/cache/cache-manager.md b/docs/fr-FR/api/cache/cache-manager.md new file mode 100644 index 000000000..ca0300ccc --- /dev/null +++ b/docs/fr-FR/api/cache/cache-manager.md @@ -0,0 +1,154 @@ +# CacheManager + +## Overview + +CacheManager is based on [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager) and provides caching module management for NocoBase. The built-in cache types are: + +- **memory**: Provided by the default lru-cache of node-cache-manager. +- **redis**: Supported by node-cache-manager-redis-yet for Redis caching. + +More types can be extended and registered through the API. + +### Concepts + +- **Store**: Defines a caching method, including a factory method for creating caches and other related configurations. Each caching method has a unique identifier provided during registration. The two built-in caching methods correspond to the unique identifiers `memory` and `redis`. + +- **Store Factory Method**: Provided by `node-cache-manager` and related extension packages, used to create caches. Examples include `memory` provided by `node-cache-manager` by default, and `redisStore` provided by `node-cache-manager-redis-yet`. In this context, the object to be provided corresponds to [`StoreOptions`](#storeoptions), which is the first parameter of the `caching` method in `node-cache-manager`. + +- **Cache**: A class encapsulated by NocoBase, providing methods related to cache usage. When actually using caching, operations are performed on instances of `Cache`. Each `Cache` instance has a unique identifier, which serves as a namespace for distinguishing different modules. + +## Class Methods + +### `constructor()` + +#### Signature + +- `constructor(options?: CacheManagerOptions)` + +#### Type + +```ts +export type CacheManagerOptions = Partial<{ + defaultStore: string; + stores: { + [storeType: string]: StoreOptions; + }; +}>; + +type StoreOptions = { + store?: 'memory' | FactoryStore; + close?: (store: Store) => Promise; + // global config + [key: string]: any; +}; +``` + +#### Details + +##### CacheManagerOptions + +| Property | Type | Description | +| -------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `defaultStore` | `string` | Unique identifier for the default cache type. | +| `stores` | `Record` | Registers cache types. The key is the unique identifier for the cache type, and the value is an object containing the registration method and global configurations. | + +##### StoreOptions + +| Property | Type | Description | +| --------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `store` | `memory` \| `FactoryStore` | The store factory method, corresponding to the first parameter of the `caching` method. | +| `close` | `(store: Store) => Promise` | Optional. For middleware that requires establishing a connection, such as Redis, provide a callback method for closing the connection. The parameter is the object returned by the store factory method. | +| `[key: string]` | `any` | Other global configurations for the store, corresponding to the second parameter of the `caching` method. | + +#### Default `options` + +```ts +import { redisStore, RedisStore } from 'cache-manager-redis-yet'; + +const defaultOptions: CacheManagerOptions = { + defaultStore: 'memory', + stores: { + memory: { + store: 'memory', + // global config + max: 2000, + }, + redis: { + store: redisStore, + close: async (redis: RedisStore) => { + await redis.client.quit(); + }, + }, + }, +}; +``` + +The `options` parameter will be merged with the default options. Existing default options can be omitted. For example: + +```ts +const cacheManager = new CacheManager({ + stores: { + defaultStore: 'redis', + redis: { + // redisStore is already provided in the default options, so only need to provide redisStore configuration. + url: 'redis://localhost:6379', + }, + }, +}); +``` + +### `registerStore()` + +Register a new caching method. Example: + +```ts +import { redisStore } from 'cache-manager-redis-yet'; + +cacheManager.registerStore({ + // Unique identifier for the store + name: 'redis', + // Factory method for creating the store + store: redisStore, + // Callback method for closing the store connection + close: async (redis: RedisStore) => { + await redis.client.quit(); + }, + // Global configurations + url: 'xxx', +}); +``` + +#### Signature + +- `registerStore(options: { name: string } & StoreOptions)` + +### `createCache()` + +Create a cache. Example: + +```ts +await cacheManager.createCache({ + name: 'default', // Unique identifier for the cache + store: 'memory', // Unique identifier for the store + prefix: 'mycache', // Automatically adds the 'mycache:' prefix to cache keys, optional + // Other store configurations, custom configurations that will be merged with global store configurations + max: 2000, +}); +``` + +#### Signature + +- `createCache(options: { name: string; prefix?: string; store?: string; [key: string]: any }): Promise` + +#### Details + +##### options + +| Property | Type | Description | +| --------------- | -------- | -------------------------------------------------- | +| `name` | `string` | Unique identifier for the cache | +| `store` | `string` | Unique identifier for the store | +| `prefix` | `string` | Optional. Prefix automatically added to cache keys | +| `[key: string]` | `any` | Other custom store configurations | + +When `store` is omitted, the `defaultStore` will be used. In this case, the caching diff --git a/docs/fr-FR/api/cache/cache.md b/docs/fr-FR/api/cache/cache.md new file mode 100644 index 000000000..c92aa9dda --- /dev/null +++ b/docs/fr-FR/api/cache/cache.md @@ -0,0 +1,60 @@ +# Cache + +## Basic Methods + +You can refer to the documentation of [node-cache-manager](https://github.com/node-cache-manager/node-cache-manager). + +- `get()` +- `set()` +- `del()` +- `reset()` +- `wrap()` +- `mset()` +- `mget()` +- `mdel()` +- `keys()` +- `ttl()` + +## Other Methods + +### `wrapWithCondition()` + +Similar to `wrap()`, but can decide whether to use caching based on conditions. + +```ts +async wrapWithCondition( + key: string, + fn: () => T | Promise, + options?: { + // External parameter to control whether to use cache results + useCache?: boolean; + // Determine whether to cache based on data results + isCacheable?: (val: unknown) => boolean | Promise; + ttl?: Milliseconds; + }, +): Promise { +``` + +### `setValueInObject()` + +When the cached content is an object, changes the value of a specific key. + +```ts +async setValueInObject(key: string, objectKey: string, value: unknown) +``` + +### `getValueInObject()` + +When the cached content is an object, retrieves the value of a specific key. + +```ts +async getValueInObject(key: string, objectKey: string) +``` + +### `delValueInObject()` + +When the cached content is an object, deletes a specific key. + +```ts +async delValueInObject(key: string, objectKey: string) +``` diff --git a/docs/fr-FR/api/cli.md b/docs/fr-FR/api/cli.md new file mode 100644 index 000000000..137f19774 --- /dev/null +++ b/docs/fr-FR/api/cli.md @@ -0,0 +1,351 @@ +# @nocobase/cli + +The NocoBase CLI is designed to help you develop, build, and deploy NocoBase applications. + + + +NocoBase CLI supports ts-node and node two operation modes. + +- ts-node mode (Default): Used for development environment, support real-time compilation, with relatively slow response +- node mode:Used for production environment, with quick response, but you need to execute `yarn nocobase build` to compile the entire source code first + + + +## Instructions For Use + +```bash +$ yarn nocobase -h + +Usage: nocobase [command] [options] + +Options: + -h, --help + +Commands: + console + db:auth Verify if the database is successfully connected + db:sync Generate relevant data tables and fields through the configuration of collections + install Install + start Start application in production environment + build Compile and package + clean Delete the compiled files + dev Start application for development environment with real-time compilation + doc Documentation development + test Testing + umi + upgrade Upgrade + migrator Data migration + pm Plugin manager + help +``` + +## Application in Scaffolding + +`scripts` in the application scaffolding `package.json` is as below: + +```json +{ + "scripts": { + "dev": "nocobase dev", + "start": "nocobase start", + "clean": "nocobase clean", + "build": "nocobase build", + "test": "nocobase test", + "pm": "nocobase pm", + "postinstall": "nocobase postinstall" + } +} +``` + +## Command Line Extensions + +NocoBase CLI is built based on [commander](https://github.com/tj/commander.js). You can write the extended commands freely in `app/server/index.ts`: + +```ts +const app = new Application(config); + +app.command('hello').action(() => {}); +``` + +or in the plugin: + +```ts +class MyPlugin extends Plugin { + beforeLoad() { + this.app.command('hello').action(() => {}); + } +} +``` + +Run in the terminal: + +```bash +$ yarn nocobase hello +``` + +## Built-in Commands + +Sorted by frequency of use. + +### `dev` + +Start application and compile code in real time in development environment. + + +NocoBase is installed automatically if it is not installed (Refer to the `install` command). + + +```bash +Usage: nocobase dev [options] + +Options: + -p, --port [port] + --client + --server + -h, --help +``` + +Example: + +```bash +# Launch application for development environment, with real-time compilation +yarn nocobase dev +# Start the server side only +yarn nocobase dev --server +# Start the client side only +yarn nocobase dev --client +``` + +### `start` + +Start application in production environment, the code needs yarn build. + + + +- NocoBase is installed automatically if it is not installed (Refer to the `install` command). +- The source code needs to be re-packaged if it has any modification (Refer to the `build` command). + + + +```bash +$ yarn nocobase start -h + +Usage: nocobase start [options] + +Options: + -p, --port + -s, --silent + -h, --help +``` + +Example: + +```bash +# Launch application for production environment +yarn nocobase start +``` + +### `install` + +Install. + +```bash +$ yarn nocobase install -h + +Usage: nocobase install [options] + +Options: + -f, --force + -c, --clean + -s, --silent + -l, --lang [lang] + -e, --root-email + -p, --root-password + -n, --root-nickname [rootNickname] + -h, --help +``` + +Example: + +```bash +# Initial installation +yarn nocobase install -l zh-CN -e admin@nocobase.com -p admin123 +# Delete all data tables from NocoBase and reinstall +yarn nocobase install -f -l zh-CN -e admin@nocobase.com -p admin123 +# Clear database and reinstall +yarn nocobase install -c -l zh-CN -e admin@nocobase.com -p admin123 +``` + + + +Difference between `-f/--force` and `-c/--clean`: + +- `-f/--force` Delete data tables of NocoBase +- `-c/--clean` Clear database, all data tables are deleted + + + +### `upgrade` + +Upgrade. + +```bash +yarn nocobase upgrade +``` + +### `test` + +jest test, which supports all [jest-cli](https://jestjs.io/docs/cli) options, also supports `-c, --db-clean`. + +```bash +$ yarn nocobase test -h + +Usage: nocobase test [options] + +Options: + -c, --db-clean Clear database before running all tests + -h, --help +``` + +Example: + +```bash +# Run all test files +yarn nocobase test +# Run all test files in the specified folder +yarn nocobase test packages/core/server +# Run all tests in the specified file +yarn nocobase test packages/core/database/src/__tests__/database.test.ts + +# Clear database before running all tests +yarn nocobase test -c +yarn nocobase test packages/core/server -c +``` + +### `build` + +The source code needs to be compiled and packaged before the code is deployed to the production environment; and you need to re-build the code if it has any modification. + +```bash +# All packages +yarn nocobase build +# Specified packages +yarn nocobase build app/server app/client +``` + +### `clean` + +Delete the compiled files. + +```bash +yarn clean +# Equivalent to +yarn rimraf -rf packages/*/*/{lib,esm,es,dist} +``` + +### `doc` + +Documentation development. + +```bash +# Start the documentation +yarn doc --lang=zh-CN # Equivalent to yarn doc dev +# Build the documentation, and output it to . /docs/dist/ directory by default +yarn doc build +# View the final result of the output documentation of dist +yarn doc serve --lang=zh-CN +``` + +### `db:auth` + +Verify if the database is successfully connected. + +```bash +$ yarn nocobase db:auth -h + +Usage: nocobase db:auth [options] + +Options: + -r, --retry [retry] Number of retries + -h, --help +``` + +### `db:sync` + +Generate relevant data tables and fields through the configuration of collections. + +```bash +$ yarn nocobase db:sync -h + +Usage: nocobase db:sync [options] + +Options: + -f, --force + -h, --help display help for command +``` + +### `migrator` + +Data migration. + +```bash +$ yarn nocobase migrator + +Positional arguments: + + up Applies pending migrations + down Revert migrations + pending Lists pending migrations + executed Lists executed migrations + create Create a migration file +``` + +### `pm` + +Plugin manager. + +```bash +# Create plugin +yarn pm create hello +# Register plugin +yarn pm add hello +# Enable plugin +yarn pm enable hello +# Disable plugin +yarn pm disable hello +# Remove plugin +yarn pm remove hello +``` + +Not achieved yet: + +```bash +# Upgrade plugin +yarn pm upgrade hello +# Publish plugin +yarn pm publish hello +``` + +### `umi` + +`app/client` is built based on [umi](https://umijs.org/), you can run other relevant commands through `nocobase umi`. + +```bash +# Generate the .umi cache needed for the development environment +yarn nocobase umi generate tmp +``` + +### `help` + +The help command, you can also use the option parameter, `-h` and `--help`. + +```bash +# View all cli +yarn nocobase help +# Use -h instead +yarn nocobase -h +# Or --help +yarn nocobase --help +# View options of command db:sync +yarn nocobase db:sync -h +``` diff --git a/docs/fr-FR/api/client/application.md b/docs/fr-FR/api/client/application.md new file mode 100644 index 000000000..0bdac33e6 --- /dev/null +++ b/docs/fr-FR/api/client/application.md @@ -0,0 +1,61 @@ +# Application + +## Constructor + +### `constructor()` + +Create an application instance. + +**Signature** + +- `constructor(options: ApplicationOptions)` + +**Example** + +```ts +const app = new Application({ + apiClient: { + baseURL: process.env.API_BASE_URL, + }, + dynamicImport: (name: string) => { + return import(`../plugins/${name}`); + }, +}); +``` + +## Methods + +### use() + +Add Providers, build-in Providers are: + +- APIClientProvider +- I18nextProvider +- AntdConfigProvider +- SystemSettingsProvider +- PluginManagerProvider +- SchemaComponentProvider +- SchemaInitializerProvider +- BlockSchemaComponentProvider +- AntdSchemaComponentProvider +- ACLProvider +- RemoteDocumentTitleProvider + +### render() + +Component to render the App. + +```ts +import { Application } from '@nocobase/client'; + +export const app = new Application({ + apiClient: { + baseURL: process.env.API_BASE_URL, + }, + dynamicImport: (name: string) => { + return import(`../plugins/${name}`); + }, +}); + +export default app.render(); +``` diff --git a/docs/fr-FR/api/client/extensions/acl.md b/docs/fr-FR/api/client/extensions/acl.md new file mode 100644 index 000000000..09d8e9a94 --- /dev/null +++ b/docs/fr-FR/api/client/extensions/acl.md @@ -0,0 +1,23 @@ +# ACL + +## Components + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` + +## Hooks + +### `useACLContext()` + +### `useACLRoleContext()` + +### `useRoleRecheck()` diff --git a/docs/fr-FR/api/client/extensions/block-provider.md b/docs/fr-FR/api/client/extensions/block-provider.md new file mode 100644 index 000000000..65baa50cd --- /dev/null +++ b/docs/fr-FR/api/client/extensions/block-provider.md @@ -0,0 +1,25 @@ +# BlockProvider + +## Kernel Methods + +### `` + +### `useBlockRequestContext()` + +## Build-in BlockProvider Components + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` diff --git a/docs/fr-FR/api/client/extensions/collection-manager.md b/docs/fr-FR/api/client/extensions/collection-manager.md new file mode 100644 index 000000000..50d8d8035 --- /dev/null +++ b/docs/fr-FR/api/client/extensions/collection-manager.md @@ -0,0 +1,273 @@ +# CollectionManager + +## Components + +### CollectionManagerProvider + +```jsx | pure + +``` + +### CollectionProvider + +```jsx | pure +const collection = { + name: 'tests', + fields: [ + { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input', + }, + }, + ], +}; +; +``` + +If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name. + +```jsx | pure +const collections = [ + { + name: 'tests', + fields: [ + { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input', + }, + }, + ], + }, +]; + + +; +``` + +### CollectionFieldProvider + +```jsx | pure +const field = { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input', + }, +}; +; +``` + +If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name. + +```jsx | pure +const collection = { + name: 'tests', + fields: [ + { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input', + }, + }, + ], +}; + + +; +``` + +### CollectionField + +Universal field component that needs to be used with ``, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located. + +```ts +{ + name: 'title', + 'x-decorator': 'FormItem', + 'x-decorator-props': {}, + 'x-component': 'CollectionField', + 'x-component-props': {}, + properties: {}, +} +``` + +## Hooks + +### useCollectionManager() + +Use with ``. + +```jsx | pure +const { collections, get } = useCollectionManager(); +``` + +### useCollection() + +Use with ``. + +```jsx | pure +const { name, fields, getField, findField, resource } = useCollection(); +``` + +### useCollectionField() + +Use with ``. + +```jsx | pure +const { name, uiSchema, resource } = useCollectionField(); +``` + +The resource needs to be used with `` to provide context of the record of the current data table row. + +# CollectionManager + +## Components + +### CollectionManagerProvider + +```jsx | pure + +``` + +### CollectionProvider + +```jsx | pure +const collection = { + name: 'tests', + fields: [ + { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input', + }, + }, + ], +}; +; +``` + +If there is no collection parameter passed in, get the collection from CollectionManagerProvider with the corresponding name. + +```jsx | pure +const collections = [ + { + name: 'tests', + fields: [ + { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input', + }, + }, + ], + }, +]; + + +; +``` + +### CollectionFieldProvider + +```jsx | pure +const field = { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input', + }, +}; +; +``` + +If there is no field parameter passed in, get the field from CollectionProvider with the corresponding name. + +```jsx | pure +const collection = { + name: 'tests', + fields: [ + { + type: 'string', + name: 'title', + interface: 'input', + uiSchema: { + type: 'string', + 'x-component': 'Input', + }, + }, + ], +}; + + +; +``` + +### CollectionField + +Universal field component that needs to be used with ``, but only in schema scenarios. Get the field schema from CollectionProvider with the corresponding name. Extend the configuration via the schema where the CollectionField is located. + +```ts +{ + name: 'title', + 'x-decorator': 'FormItem', + 'x-decorator-props': {}, + 'x-component': 'CollectionField', + 'x-component-props': {}, + properties: {}, +} +``` + +## Hooks + +### useCollectionManager() + +Use with ``. + +```jsx | pure +const { collections, get } = useCollectionManager(); +``` + +### useCollection() + +Use with ``. + +```jsx | pure +const { name, fields, getField, findField, resource } = useCollection(); +``` + +### useCollectionField() + +Use with ``. + +```jsx | pure +const { name, uiSchema, resource } = useCollectionField(); +``` + +The resource needs to be used with `` to provide context of the record of the current data table row. diff --git a/docs/fr-FR/api/client/extensions/schema-component.md b/docs/fr-FR/api/client/extensions/schema-component.md new file mode 100644 index 000000000..832818f75 --- /dev/null +++ b/docs/fr-FR/api/client/extensions/schema-component.md @@ -0,0 +1,14 @@ +# 适配的 Schema 组件 + +## Common + +- DndContext +- SortableItem + +## And Design + +- Action +- BlockItem +- Calendar +- CardItem +- Cascader diff --git a/docs/fr-FR/api/client/index.md b/docs/fr-FR/api/client/index.md new file mode 100644 index 000000000..3a2170da0 --- /dev/null +++ b/docs/fr-FR/api/client/index.md @@ -0,0 +1,3 @@ +# Overview + +test diff --git a/docs/fr-FR/api/client/router.md b/docs/fr-FR/api/client/router.md new file mode 100644 index 000000000..bfe211374 --- /dev/null +++ b/docs/fr-FR/api/client/router.md @@ -0,0 +1,185 @@ +# Router + +## API + +### Initial + +```tsx | pure +const app = new Application({ + router: { + type: 'browser', // type default value is `browser` + }, +}); + +// or +const app = new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, +}); +``` + +### add Route + +#### basic + +```tsx | pure +import { RouteObject } from 'react-router-dom'; +const app = new Application(); + +const Hello = () => { + return
Hello
; +}; + +// first argument is `name` of route, second argument is `RouteObject` +app.router.add('root', { + path: '/', + element: , +}); + +app.router.add('root', { + path: '/', + Component: Hello, +}); +``` + +#### Component is String + +```tsx | pure +app.addComponents({ + Hello, +}); +app.router.add('root', { + path: '/', + Component: 'Hello', +}); +``` + +#### nested + +```tsx | pure +import { Outlet } from 'react-router-dom'; + +const Layout = () => { + return ( +
+ Home + about + + +
+ ); +}; + +const Home = () => { + return
Home
; +}; + +const About = () => { + return
About
; +}; + +app.router.add('root', { + element: , +}); +app.router.add('root.home', { + path: '/home', + element: , +}); +app.router.add('root.about', { + path: '/about', + element: , +}); +``` + +It will generate the following routes: + +```tsx | pure +{ + element: , + children: [ + { + path: '/home', + element: + }, + { + path: '/about', + element: + } + ] +} +``` + +### remove Route + +```tsx | pure +// remove route by name +app.router.remove('root.home'); +app.router.remove('hello'); +``` + +#### Router in plugin + +```tsx | pure +class MyPlugin extends Plugin { + async load() { + // add route + this.app.router.add('hello', { + path: '/hello', + element:
hello
, + }); + + // remove route + this.app.router.remove('world'); + } +} +``` + +## Example + +```tsx +/** + * defaultShowCode: true + */ +import React from 'react'; +import { Link, Outlet } from 'react-router-dom'; +import { Application } from '@nocobase/client'; + +const Home = () =>

Home

; +const About = () =>

About

; + +const Layout = () => { + return ( +
+
+ Home, About +
+ +
+ ); +}; + +const app = new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, +}); + +app.router.add('root', { + element: , +}); + +app.router.add('root.home', { + path: '/', + element: , +}); + +app.router.add('root.about', { + path: '/about', + element: , +}); + +export default app.getRootComponent(); +``` diff --git a/docs/fr-FR/api/client/schema-designer/schema-component.md b/docs/fr-FR/api/client/schema-designer/schema-component.md new file mode 100644 index 000000000..2316523b8 --- /dev/null +++ b/docs/fr-FR/api/client/schema-designer/schema-component.md @@ -0,0 +1,17 @@ +# SchemaComponent + +## Core Components + +### `` + +### `` + +### `` + +## Core Methods + +### `createDesignable()` + +### `useDesignable()` + +### `useCompile()` diff --git a/docs/fr-FR/api/client/schema-designer/schema-initializer.md b/docs/fr-FR/api/client/schema-designer/schema-initializer.md new file mode 100644 index 000000000..a8673a125 --- /dev/null +++ b/docs/fr-FR/api/client/schema-designer/schema-initializer.md @@ -0,0 +1,27 @@ +# SchemaInitializer + +Used for the initialization of various schemas. Newly added schema can be inserted anywhere in an existing schema node, including: + +```ts +{ + properties: { + // beforeBegin - Insert in front of the current node + node1: { + properties: { + // afterBegin - Insert in front of the first child node of the current node + // ... + // beforeEnd - After the last child node of the current node + }, + }, + // afterEnd - After the current node + }, +} +``` + +The core of SchemaInitializer includes `` and `` the two components. `` is used to create the dropdown menu button of schema, and the options of the dropdown menu is ``. + +### `` + +### `` + +### `` diff --git a/docs/fr-FR/api/client/schema-designer/schema-settings.md b/docs/fr-FR/api/client/schema-designer/schema-settings.md new file mode 100644 index 000000000..b014e7435 --- /dev/null +++ b/docs/fr-FR/api/client/schema-designer/schema-settings.md @@ -0,0 +1,25 @@ +# SchemaSettings + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` + +### `` diff --git a/docs/fr-FR/api/data-source-manager/data-source.md b/docs/fr-FR/api/data-source-manager/data-source.md new file mode 100644 index 000000000..5f57d255a --- /dev/null +++ b/docs/fr-FR/api/data-source-manager/data-source.md @@ -0,0 +1,80 @@ +# DataSource (abstract) + +`DataSource` 抽象类,用于表示一种类型的数据源,可以是数据库、API等。 + +## 成员 + +### collectionManager + +数据源的 CollectionManager 实例,需实现 [`ICollectionManager`](/api/data-source-manager/i-collection-manager) 接口。 + +### resourceManager + +数据源的 resourceManager 实例,详见:[`resourceManager`](/api/resourcer/resource-manager) + +### acl + +数据源的 ACL 实例,详见: [`ACL`](/api/acl/acl) + +## API + +### constructor() + +构造函数,创建一个 `DataSource` 实例。 + +#### 签名 + +- `constructor(options: DataSourceOptions)` + +### init() + +初始化函数,在 `constructor` 之后既被调用。 + +#### 签名 + +- `init(options: DataSourceOptions)` + + +### name + +#### 签名 + +- `get name()` + +响应数据源的实例名称 + +### middleware() + +获得 DataSource 的中间件,用于挂载到 Server 中接收请求。 + +### testConnection() + +静态方法,在测试连接操作时调用,可用于参数校验,具体逻辑由子类实现。 + +#### 签名 + +- `static testConnection(options?: any): Promise` + +### load() + +#### 签名 + +- `async load(options: any = {})` + +数据源的加载操作,逻辑由子类实现。 + +### createCollectionManager() + +#### 签名 +- `abstract createCollectionManager(options?: any): ICollectionManager` + +创建数据源的 CollectionManager 实例,逻辑由子类实现。 + +### createResourceManager() + +创建数据源的 ResourceManager 实例,字类可覆盖实现,默认创建 `@nocobase/resourcer` 中的 `ResourceManager`。 + +### createACL() + +- 创建 DataSource 的 ACL 实例,字类可覆盖实现,默认创建 `@nocobase/acl` 中的 `ACL`。 + diff --git a/docs/fr-FR/api/data-source-manager/i-collection-manager.md b/docs/fr-FR/api/data-source-manager/i-collection-manager.md new file mode 100644 index 000000000..6b0911f27 --- /dev/null +++ b/docs/fr-FR/api/data-source-manager/i-collection-manager.md @@ -0,0 +1,112 @@ +# ICollectionManager + +`ICollectionManager` 接口,用于管理数据源的 `Collection` 实例。 + +## API + +### registerFieldTypes() + +注册 `Collection` 中的字段类型。 + +#### 签名 + +- `registerFieldTypes(types: Record): void` + +### registerFieldInterfaces() + +注册 `Collection` 的 `Interface` 。 + +#### 签名 + +- `registerFieldInterfaces(interfaces: Record): void` + +### registerCollectionTemplates() + +注册 `Collection Template`。 + +#### 签名 + +- `registerCollectionTemplates(templates: Record): void` + +### registerModels() + +注册 `Model`。 + +#### 签名 + +- `registerModels(models: Record): void` + +### registerRepositories() + +注册 `Repository`。 + +#### 签名 + +- `registerRepositories(repositories: Record): void` + +### getRegisteredRepository() + +获取已注册的仓库实例。 + +#### 签名 + +- `getRegisteredRepository(key: string): IRepository` + +### defineCollection() + +定义一个 `Collection`。 + +#### 签名 + +- `defineCollection(options: CollectionOptions): ICollection` + +### extendCollection() + +修改一个已存在的 `Collection` 属性。 + +#### 签名 + +- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ICollection` + +### hasCollection() + +判断 `Collection` 是否存在。 + +#### 签名 + + +- `hasCollection(name: string): boolean` + +### getCollection() + +获取 `Collection` 实例。 + +#### 签名 + +- `getCollection(name: string): ICollection` + +### getCollections() + +获取所有的 `Collection` 实例。 + +#### 签名 + +- `getCollections(): Array` + +### getRepository() + +获取 `Repository` 实例。 + +#### 签名 + +- `getRepository(name: string, sourceId?: string | number): IRepository` + +### sync() + +同步数据源,逻辑由子类实现。 + +#### 签名 + +- `sync(): Promise` + + diff --git a/docs/fr-FR/api/data-source-manager/i-collection.md b/docs/fr-FR/api/data-source-manager/i-collection.md new file mode 100644 index 000000000..2f8b05b1f --- /dev/null +++ b/docs/fr-FR/api/data-source-manager/i-collection.md @@ -0,0 +1,69 @@ +# ICollection + +`ICollection` 是数据模型的接口,其中包含了模型的名称、字段、关联等信息。 + +```typescript +export interface ICollection { + repository: IRepository; + + updateOptions(options: any): void; + + setField(name: string, options: any): IField; + + removeField(name: string): void; + + getFields(): Array; + + getField(name: string): IField; + + [key: string]: any; +} +``` + +## 成员 + +### repository + +`ICollection` 所属的 `Repository` 实例 + +## API + +### updateOptions() + +更新 `Collection` 的属性 + +#### 签名 + +- `updateOptions(options: any): void` + +### setField() + +设置 `Collection` 的字段 + +#### 签名 + +- `setField(name: string, options: any): IField` + +### removeField() + +移除 `Collection` 的字段 + +#### 签名 + +- `removeField(name: string): void` + +### getFields() + +获取 `Collection` 的所有字段 + +#### 签名 + +- `getFields(): Array` + +### getField() + +根据名称获取 `Collection` 的字段 + +#### 签名 + +- `getField(name: string): IField` diff --git a/docs/fr-FR/api/data-source-manager/i-field.md b/docs/fr-FR/api/data-source-manager/i-field.md new file mode 100644 index 000000000..c23936786 --- /dev/null +++ b/docs/fr-FR/api/data-source-manager/i-field.md @@ -0,0 +1,34 @@ +# IField + +`IField` 定义了字段需要实现的接口。 + +```typescript +export type FieldOptions = { + name: string; + field: string; + rawType: string; + type: string; + description?: string; + interface?: string; + uiSchema?: any; + possibleTypes?: string[]; + defaultValue?: any; + primaryKey: boolean; + unique: boolean; + allowNull?: boolean; + autoIncrement?: boolean; + [key: string]: any; +}; + +export interface IField { + options: FieldOptions; +} +``` + + +## 属性 + +### options + +- **类型**:`FieldOptions` + diff --git a/docs/fr-FR/api/data-source-manager/i-model.md b/docs/fr-FR/api/data-source-manager/i-model.md new file mode 100644 index 000000000..c6d0df97b --- /dev/null +++ b/docs/fr-FR/api/data-source-manager/i-model.md @@ -0,0 +1,15 @@ +# IModel + +`IModel` 接口定义了模型对象的基本属性和方法。 + +```typescript +export interface IModel { + toJSON: () => any; +} +``` + +## API + +### toJSON() + +将模型对象转换为 JSON 格式 diff --git a/docs/fr-FR/api/data-source-manager/i-repository.md b/docs/fr-FR/api/data-source-manager/i-repository.md new file mode 100644 index 000000000..069b49bff --- /dev/null +++ b/docs/fr-FR/api/data-source-manager/i-repository.md @@ -0,0 +1,62 @@ +# IRepository + +`Repository` 接口定义了一系列的模型操作方法,用于适配数据源的增删改查操作。 + +## API + +### find() + +根据查询参数,给出符合条件的模型列表 + +#### 签名 + +- `find(options?: any): Promise` + +### findOne() + +根据查询参数,给出符合条件的模型,如果有多个符合条件的模型,只返回第一个 + +#### 签名 + +- `findOne(options?: any): Promise` + + +### count() + +根据查询参数,给出符合条件的模型数量 + +#### 签名 + +- `count(options?: any): Promise` + +### findAndCount() + +根据查询参数,给出符合条件的模型列表和数量 + +#### 签名 + +- `findAndCount(options?: any): Promise<[IModel[], Number]>` + +### create() + +创建一个模型数据对象 + +#### 签名 + +- `create(options: any): void` + +### update() + +根据查询条件,更新模型数据对象 + +#### 签名 + +- `update(options: any): void` + +### destroy() + +根据查询条件,删除模型数据对象 + +#### 签名 + +- `destroy(options: any): void` diff --git a/docs/fr-FR/api/data-source-manager/index.md b/docs/fr-FR/api/data-source-manager/index.md new file mode 100644 index 000000000..2a147a39a --- /dev/null +++ b/docs/fr-FR/api/data-source-manager/index.md @@ -0,0 +1,56 @@ +# DataSourceManager + +`DataSourceManager` 是多 `dataSource` 实例的管理类。 + +## API + +### add() +添加一个 `dataSource` 实例。 + +#### 签名 + +- `add(dataSource: DataSource, options: any = {}): Promise` + +### use() + +给 `dataSource` 实例添加全局中间件。 + +### middleware() + +获取当前 `dataSourceManager` 实例的中间件,可用于响应 http 请求。 + +### afterAddDataSource() + +新增`dataSource` 添加后的钩子函数。 + +#### 签名 + +- `afterAddDataSource(hook: DataSourceHook)` + +```typescript +type DataSourceHook = (dataSource: DataSource) => void; +``` + +### registerDataSourceType() + +注册数据源类型及其类。 + +#### 签名 + +- `registerDataSourceType(type: string, dataSourceClass: typeof DataSource)` + +### getDataSourceType() + +获取数据源类。 + +#### 签名 + +- `getDataSourceType(type: string): typeof DataSource` + +### buildDataSourceByType() + +根据注册的数据源类型和实例参数,创建数据源实例。 + +#### 签名 + +- `buildDataSourceByType(type: string, options: any): DataSource` diff --git a/docs/fr-FR/api/database/collection.md b/docs/fr-FR/api/database/collection.md new file mode 100644 index 000000000..1c2da2726 --- /dev/null +++ b/docs/fr-FR/api/database/collection.md @@ -0,0 +1,513 @@ +# Collection + +## Overview + +`Collection` is used to define the data model in the system, such as model name, fields, indexes, associations, and other information. It is usually called through the `collection` method of the `Database` instance as a proxy entry. + +```javascript +const { Database } = require('@nocobase/database') + +// Create database instance +const db = new Database({...}); + +// Define data model +db.collection({ + name: 'users', + // Define model fields + fields: [ + // Scalar field + { + name: 'name', + type: 'string', + }, + + // Association field + { + name: 'profile', + type: 'hasOne' // 'hasMany', 'belongsTo', 'belongsToMany' + } + ], +}); +``` + +Refer to [Fields](/api/database/field.md) for more field types. + +## Constructor + +**Signature** + +- `constructor(options: CollectionOptions, context: CollectionContext)` + +**Parameter** + +| Name | Type | Default | Description | +| --------------------- | ----------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- | +| `options.name` | `string` | - | Identifier of the collection | +| `options.tableName?` | `string` | - | Database table name, the value of `options.name` is used if not set | +| `options.fields?` | `FieldOptions[]` | - | Definition of fields, refer to [Field](./field) for details | +| `options.model?` | `string \| ModelStatic` | - | Model type of Sequelize; in case `string` is used, this model name needs to be registered in the db before being called | +| `options.repository?` | `string \| RepositoryType` | - | Data repository type; in case `string` is used, this repository type needs to be registered in the db before being called | +| `options.sortable?` | `string \| boolean \| { name?: string; scopeKey?: string }` | - | Configure which fields are sortable; not sortable by default | +| `options.autoGenId?` | `boolean` | `true` | Whether to automatically generate unique primary key; `true` by default | +| `context.database` | `Database` | - | The context database in which it resides | + +**Example** + +Create a table posts: + +```ts +const posts = new Collection( + { + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + { + type: 'double', + name: 'price', + }, + ], + }, + { + // An existing database instance + database: db, + }, +); +``` + +## Instance Members + +### `options` + +Initial parameters for data table configuration, which are consistent with the `options` parameter of the constructor. + +### `context` + +The contextual environment to which the current data table belongs, currently mainly the database instance. + +### `name` + +Name of the data table. + +### `db` + +The database instance to which it belongs. + +### `filterTargetKey` + +Name of the field that is used as the primary key. + +### `isThrough` + +Whether it is an intermediate table. + +### `model` + +Match the Model type of Sequelize. + +### `repository` + +Data repository instance. + +## Field Configuration Methods + +### `getField()` + +Get a field object whose corresponding name has been defined in the data table. + +**Signature** + +- `getField(name: string): Field` + +**Parameter** + +| Name | Type | Default | Description | +| ------ | -------- | ------- | ----------------- | +| `name` | `string` | - | Name of the field | + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); + +const field = posts.getField('title'); +``` + +### `setField()` + +Set a field to the data table. + +**Signature** + +- `setField(name: string, options: FieldOptions): Field` + +**Parameter** + +| Name | Type | Default | Description | +| --------- | -------------- | ------- | ----------------------------------------------------------------- | +| `name` | `string` | - | Name of the field | +| `options` | `FieldOptions` | - | Configuration of the field, refer to [Field](./field) for details | + +**Example** + +```ts +const posts = db.collection({ name: 'posts' }); + +posts.setField('title', { type: 'string' }); +``` + +### `setFields()` + +Set multiple fields to the data table. + +**Signature** + +- `setFields(fields: FieldOptions[], resetFields = true): Field[]` + +**Parameter** + +| Name | Type | Default | Description | +| ------------- | ---------------- | ------- | ------------------------------------------------------------------ | +| `fields` | `FieldOptions[]` | - | Configuration of the fields, refer to [Field](./field) for details | +| `resetFields` | `boolean` | `true` | Whether to reset existing fields | + +**Example** + +```ts +const posts = db.collection({ name: 'posts' }); + +posts.setFields([ + { type: 'string', name: 'title' }, + { type: 'double', name: 'price' }, +]); +``` + +### `removeField()` + +Remove a field object whose corresponding name has been defined in the data table. + +**Signature** + +- `removeField(name: string): void | Field` + +**Parameter** + +| Name | Type | Default | Description | +| ------ | -------- | ------- | ----------------- | +| `name` | `string` | - | Name of the field | + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); + +posts.removeField('title'); +``` + +### `resetFields()` + +Reset (Empty) fields of the data table. + +**Signature** + +- `resetFields(): void` + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); + +posts.resetFields(); +``` + +### `hasField()` + +Check if the data table has defined a field object with the corresponding name. + +**Signature** + +- `hasField(name: string): boolean` + +**Parameter** + +| Name | Type | Default | Description | +| ------ | -------- | ------- | ----------------- | +| `name` | `string` | - | Name of the field | + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); + +posts.hasField('title'); // true +``` + +### `findField()` + +Find field objects in the data table that match the conditions. + +**Signature** + +- `findField(predicate: (field: Field) => boolean): Field | undefined` + +**Parameter** + +| Name | Type | Default | Description | +| ----------- | --------------------------- | ------- | ------------- | +| `predicate` | `(field: Field) => boolean` | - | The condition | + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); + +posts.findField((field) => field.name === 'title'); +``` + +### `forEachField()` + +Iterate over field objects in the data table. + +**Signature** + +- `forEachField(callback: (field: Field) => void): void` + +**Parameter** + +| Name | Type | Default | Description | +| ---------- | ------------------------ | ------- | ----------------- | +| `callback` | `(field: Field) => void` | - | Callback function | + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); + +posts.forEachField((field) => console.log(field.name)); +``` + +## Index Configuration Methods + +### `addIndex()` + +Add data table index. + +**Signature** + +- `addIndex(index: string | string[] | { fields: string[], unique?: boolean,[key: string]: any })` + +**Parameter** + +| Name | Type | Default | Description | +| ------- | ------------------------------------------------------------ | ------- | ----------------------------- | +| `index` | `string \| string[]` | - | Names of fields to be indexed | +| `index` | `{ fields: string[], unique?: boolean, [key: string]: any }` | - | Full configuration | + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); + +posts.addIndex({ + fields: ['title'], + unique: true, +}); +``` + +### `removeIndex()` + +Remove data table index. + +**Signature** + +- `removeIndex(fields: string[])` + +**Parameter** + +| Name | Type | Default | Description | +| -------- | ---------- | ------- | --------------------------------- | +| `fields` | `string[]` | - | Names of fields to remove indexes | + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], + indexes: [ + { + fields: ['title'], + unique: true, + }, + ], +}); + +posts.removeIndex(['title']); +``` + +## Table Configuration Methods + +### `remove()` + +Remove data table. + +**Signature** + +- `remove(): void` + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); + +posts.remove(); +``` + +## Database Operation Methods + +### `sync()` + +Synchronize the definitions in data table to the database. In addition to the default `Model.sync` logic in Sequelize, the data tables corresponding to the relational fields will also be handled together. + +**Signature** + +- `sync(): Promise` + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); + +await posts.sync(); +``` + +### `existsInDb()` + +Check whether the data table exists in the database. + +**Signature** + +- `existsInDb(options?: Transactionable): Promise` + +**Parameter** + +| Name | Type | Default | Description | +| ---------------------- | ------------- | ------- | -------------------- | +| `options?.transaction` | `Transaction` | - | Transaction instance | + +**Example** + +```ts +const posts = db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); + +const existed = await posts.existsInDb(); + +console.log(existed); // false +``` + +### `removeFromDb()` + +**Signature** + +- `removeFromDb(): Promise` + +**Example** + +```ts +const books = db.collection({ + name: 'books', +}); + +// Synchronize the table books to the database +await db.sync(); + +// Remove the table books from the database +await books.removeFromDb(); +``` diff --git a/docs/fr-FR/api/database/field.md b/docs/fr-FR/api/database/field.md new file mode 100644 index 000000000..ec2a31193 --- /dev/null +++ b/docs/fr-FR/api/database/field.md @@ -0,0 +1,558 @@ +# Field + +## Overview + +Data table field management class (abstract class). It is also the base class for all field types, and any other field types are implemented by inheriting from this class. + +Refer to [Extended Field Types](/development/guide/collections-fields#extended-field-types) to see how to customize fields. + +## Constructor + +It is usually not called directly by the developer, but mainly through the `db.collection({ fields: [] })` method as a proxy entry. + +Extended field is implemented mainly by inheriting the `Field` abstract class and registering it to a Database instance. + +**Signature** + +- `constructor(options: FieldOptions, context: FieldContext)` + +**Parameter** + +| Name | Type | Default | Description | +| -------------------- | -------------- | ------- | ---------------------------------------------------------------------------- | +| `options` | `FieldOptions` | - | Field configuration object | +| `options.name` | `string` | - | Field name | +| `options.type` | `string` | - | Field type, corresponding to the name of the field type registered in the db | +| `context` | `FieldContext` | - | Field context object | +| `context.database` | `Database` | - | Database instance | +| `context.collection` | `Collection` | - | Data table instance | + +## Instance Members + +### `name` + +Field name. + +### `type` + +Field type. + +### `dataType` + +Data type of the field. + +### `options` + +Configuration parameters to initialize the field. + +### `context` + +Field context object. + +## Configuration Methods + +### `on()` + +Quick definition method based on data table events. It is equivalent to `db.on(this.collection.name + '.' + eventName, listener)`. + +It is usually not necessary to override this method when inheriting. + +**Signature** + +- `on(eventName: string, listener: (...args: any[]) => void)` + +**Parameter** + +| Name | Type | Default | Description | +| ----------- | -------------------------- | ------- | -------------- | +| `eventName` | `string` | - | Event name | +| `listener` | `(...args: any[]) => void` | - | Event listener | + +### `off()` + +Quick removal method based on data table events. It is equivalent to `db.off(this.collection.name + '.' + eventName, listener)`. + +It is usually not necessary to override this method when inheriting. + +**Signature** + +- `off(eventName: string, listener: (...args: any[]) => void)` + +**Parameter** + +| Name | Type | Default | Description | +| ----------- | -------------------------- | ------- | -------------- | +| `eventName` | `string` | - | Event name | +| `listener` | `(...args: any[]) => void` | - | Event listener | + +### `bind()` + +The execution content that is triggered when a field is added to data table. Typically used to add data table event listeners and other processing. + +The corresponding `super.bind()` method needs to be called first when inheriting. + +**Signature** + +- `bind()` + +### `unbind()` + +The execution content that is triggered when a field is removed from data table. Typically used to remove data table event listeners and other processing. + +The corresponding `super.unbind()` method needs to be called first when inheriting. + +**Signature** + +- `unbind()` + +### `get()` + +Get the values of a configuration item of the field. + +**Signature** + +- `get(key: string): any` + +**Parameter** + +| Name | Type | Default | Description | +| ----- | -------- | ------- | ------------------------------ | +| `key` | `string` | - | Name of the configuration item | + +**Example** + +```ts +const field = db.collection('users').getField('name'); + +// Get and return the values of the configuration item 'name' +console.log(field.get('name')); +``` + +### `merge()` + +Merge the values of a configuration item of the field. + +**Signature** + +- `merge(options: { [key: string]: any }): void` + +**Parameter** + +| Name | Type | Default | Description | +| --------- | ------------------------ | ------- | ------------------------------- | +| `options` | `{ [key: string]: any }` | - | The configuration item to merge | + +**Example** + +```ts +const field = db.collection('users').getField('name'); + +field.merge({ + // Add an index configuration + index: true, +}); +``` + +### `remove()` + +Remove a field from data table (from memory only). + +**Example** + +```ts +const books = db.getCollections('books'); + +books.getField('isbn').remove(); + +// really remove from db +await books.sync(); +``` + +## Database Methods + +### `removeFromDb()` + +Remove a field from the database. + +**Signature** + +- `removeFromDb(options?: Transactionable): Promise` + +**Parameter** + +| Name | Type | Default | Description | +| ---------------------- | ------------- | ------- | -------------------- | +| `options.transaction?` | `Transaction` | - | Transaction instance | + +### `existsInDb()` + +Check if a field exists in the database. + +**Signature** + +- `existsInDb(options?: Transactionable): Promise` + +**Parameter** + +| Name | Type | Default | Description | +| ---------------------- | ------------- | ------- | -------------------- | +| `options.transaction?` | `Transaction` | - | Transaction instance | + +## Built-in Field Types + +NocoBase has some built-in common field types, the corresponding type name can be used directly to specify the type of field upon definition. Fields of different types are configured differently, please refer to the list below. + +The configuration items of all field types are passed through to Sequelize in addition to those described below. Therefore, all field configuration items supported by Sequelize can be used here (e.g. `allowNull`, `defaultValue`, etc.). + +Moreover, server-side field types are mainly used for solving the problems of database storage and some algorithms, they are barely relevant to the field display types and the use of components in front-end. The front-end field types can be found in the corresponding tutorials. + +### `'boolean'` + +Boolean type. + +**Example** + +```js +db.collection({ + name: 'books', + fields: [ + { + type: 'boolean', + name: 'published', + }, + ], +}); +``` + +### `'integer'` + +Integer type (32 bits). + +**Example** + +```ts +db.collection({ + name: 'books', + fields: [ + { + type: 'integer', + name: 'pages', + }, + ], +}); +``` + +### `'bigInt'` + +Long integer type (64 bits). + +**Example** + +```ts +db.collection({ + name: 'books', + fields: [ + { + type: 'bigInt', + name: 'words', + }, + ], +}); +``` + +### `'double'` + +Double-precision floating-point format (64 bits). + +**Example** + +```ts +db.collection({ + name: 'books', + fields: [ + { + type: 'double', + name: 'price', + }, + ], +}); +``` + +### `'real'` + +Real type (PG only). + +### `'decimal'` + +Decimal type. + +### `'string'` + +String type. Equivalent to the `VARCHAR` type for most databases. + +**Example** + +```ts +db.collection({ + name: 'books', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); +``` + +### `'text'` + +Text type. Equivalent to the `TEXT` type for most databases. + +**Example** + +```ts +db.collection({ + name: 'books', + fields: [ + { + type: 'text', + name: 'content', + }, + ], +}); +``` + +### `'password'` + +Password type (NocoBase extension). Password encryption based on the `scrypt` method of Node.js native crypto packages. + +**Example** + +```ts +db.collection({ + name: 'users', + fields: [ + { + type: 'password', + name: 'password', + length: 64, // Length, default is 64 + randomBytesSize: 8, // Length of random bytes, default is 8 + }, + ], +}); +``` + +**Parameter** + +| Name | Type | Default | Description | +| ----------------- | -------- | ------- | ---------------------- | +| `length` | `number` | 64 | Length of characters | +| `randomBytesSize` | `number` | 8 | Length of random bytes | + +### `'date'` + +Date type. + +### `'time'` + +Time type. + +### `'array'` + +Array type (PG only). + +### `'json'` + +JSON type. + +### `'jsonb'` + +JSONB type (PG only, others will be compatible with the `'json'` type). + +### `'uuid'` + +UUID type. + +### `'uid'` + +UID type (NocoBase extension). Short random string identifier type. + +### `'formula'` + +Formula type (NocoBase extension). Mathematical formula calculation can be configured based on [mathjs](https://www.npmjs.com/package/mathjs), and the formula can refer to the values of other columns in the same record to participate in the calculation. + +**Example** + +```ts +db.collection({ + name: 'orders', + fields: [ + { + type: 'double', + name: 'price', + }, + { + type: 'integer', + name: 'quantity', + }, + { + type: 'formula', + name: 'total', + expression: 'price * quantity', + }, + ], +}); +``` + +### `'radio'` + +Radio type (NocoBase extension). The field value is 'true' for at most one row of data for the full table, all others are 'false' or 'null'. + +**Example** + +There is only one user marked as root in the entire system, once the root value of any other user is changed to `true`, all other records with root of `true` will be changed to `false`: + +```ts +db.collection({ + name: 'users', + fields: [ + { + type: 'radio', + name: 'root', + }, + ], +}); +``` + +### `'sort'` + +Sorting type (NocoBase extension). Sorting based on integer numbers, automatically generating new serial numbers for new records, and rearranging serial numbers when moving data. + +If data table has the `sortable` option defined, the corresponding fields will be generated automatically. + +**Example** + +Posts are sortable based on the users they belong to. + +```ts +db.collection({ + name: 'posts', + fields: [ + { + type: 'belongsTo', + name: 'user', + }, + { + type: 'sort', + name: 'priority', + scopeKey: 'userId', // Sort data grouped by the values of userId + }, + ], +}); +``` + +### `'virtual'` + +Virtual type. No Data is actually stored, it is used only when special getter/setter is defined. + +### `'belongsTo'` + +Many-to-one association type. Foreign key is stored in its own table, as opposed to `'hasOne'`/`'hasMany'`. + +**Example** + +Any post belongs to an author: + +```ts +db.collection({ + name: 'posts', + fields: [ + { + type: 'belongsTo', + name: 'author', + target: 'users', // Default table name is the plural form of + foreignKey: 'authorId', // Default is ' + Id' + sourceKey: 'id', // Default is id of the table + }, + ], +}); +``` + +### `'hasOne'` + +One-to-one association type. Foreign key is stored in the association table, as opposed to `'belongsTo'`. + +**Example** + +Any user has a profile: + +```ts +db.collection({ + name: 'users', + fields: [ + { + type: 'hasOne', + name: 'profile', + target: 'profiles', // Can be omitted + }, + ], +}); +``` + +### `'hasMany'` + +One-to-many association type. The foreign key is stored in the association table, as opposed to `'belongsTo'`. + +**Example** + +Any user can have multiple posts: + +```ts +db.collection({ + name: 'users', + fields: [ + { + type: 'hasMany', + name: 'posts', + foreignKey: 'authorId', + sourceKey: 'id', + }, + ], +}); +``` + +### `'belongsToMany'` + +Many-to-many association type. Intermediate table is used to store both foreign keys. If no existing table is specified as intermediate table, it will be created automatically. + +**Example** + +Any post can have multiple tags added to it, and any tag can be added to multiple posts: + +```ts +db.collection({ + name: 'posts', + fields: [ + { + type: 'belongsToMany', + name: 'tags', + target: 'tags', // Can be omitted if name is the same + through: 'postsTags', // Intermediate table will be generated automatically if not specified + foreignKey: 'postId', // Foreign key in the intermediate table referring to the table itself + sourceKey: 'id', // Primary key of the table itself + otherKey: 'tagId', // Foreign key in the intermediate table referring to the association table + }, + ], +}); + +db.collection({ + name: 'tags', + fields: [ + { + type: 'belongsToMany', + name: 'posts', + through: 'postsTags', // Refer to the same intermediate table in the same set of relation + }, + ], +}); +``` diff --git a/docs/fr-FR/api/database/index.md b/docs/fr-FR/api/database/index.md new file mode 100644 index 000000000..747509f29 --- /dev/null +++ b/docs/fr-FR/api/database/index.md @@ -0,0 +1,1189 @@ +# Database + +## Overview + +Database is the database interaction tool provided by NocoBase, it provides very convenient database interaction features for no-code and low-code applications. The supported databases are: + +- SQLite 3.8.8+ +- MySQL 8.0.17+ +- PostgreSQL 10.0+ + +### Connect to Database + +In `Database` constructor, database connection can be configured by passing the `options` parameter. + +```javascript +const { Database } = require('@nocobase/database'); + +// SQLite database configuration parameters +const database = new Database({ + dialect: 'sqlite', + storage: 'path/to/database.sqlite' +}) + +// MySQL \ PostgreSQL database configuration parameters +const database = new Database({ + dialect: /* 'postgres' or 'mysql' */, + database: 'database', + username: 'username', + password: 'password', + host: 'localhost', + port: 'port' +}) + +``` + +Refer to [Constructor](#constructor) for detailed configurations. + +### Define Data Structure + +`Database` defines database structure through `Collection`, one `Collection` object represents one table in the database. + +```javascript +// Define Collection +const UserCollection = database.collection({ + name: 'users', + fields: [ + { + name: 'name', + type: 'string', + }, + { + name: 'age', + type: 'integer', + }, + ], +}); +``` + +After the database structure is defined, use `sync()` method to synchronize the database structure. + +```javascript +await database.sync(); +``` + +Refer to [Collection](/api/database/collection.md) for detailed usage of `Collection`. + +### CRUD Data + +`Database` operates data through `Repository`. + +```javascript +const UserRepository = UserCollection.repository(); + +// Create +await UserRepository.create({ + name: 'Mark', + age: 18, +}); + +// Query +const user = await UserRepository.findOne({ + filter: { + name: 'Mark', + }, +}); + +// Update +await UserRepository.update({ + values: { + age: 20, + }, +}); + +// Delete +await UserRepository.destroy(user.id); +``` + +Refer to [Repository](/api/database/repository.md) for details of data CRUD. + +## Constructor + +**Signature** + +- `constructor(options: DatabaseOptions)` + +Create a database instance. + +**Parameter** + +| Name | Type | Default | Description | +| ---------------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| `options.host` | `string` | `'localhost'` | Database host | +| `options.port` | `number` | - | Database service port, default port depends on the type of database used | +| `options.username` | `string` | - | Database username | +| `options.password` | `string` | - | Database password | +| `options.database` | `string` | - | Database name | +| `options.dialect` | `string` | `'mysql'` | Database type | +| `options.storage?` | `string` | `':memory:'` | Storage mode for SQLite | +| `options.logging?` | `boolean` | `false` | Whether to enable logging | +| `options.define?` | `Object` | `{}` | Default table definition parameters | +| `options.tablePrefix?` | `string` | `''` | NocoBase extension, table prefix | +| `options.migrator?` | `UmzugOptions` | `{}` | NocoBase extension, parameters for migrator, refer to [Umzug](https://github.com/sequelize/umzug/blob/main/src/types.ts#L15) for the implementation | + +## Migration Methods + +### `addMigration()` + +Add single migration file. + +**Signature** + +- `addMigration(options: MigrationItem)` + +**Parameter** + +| Name | Type | Default | Description | +| -------------------- | ------------------ | ------- | ----------------------------------- | +| `options.name` | `string` | - | Name of the migration file | +| `options.context?` | `string` | - | Context of the migration file | +| `options.migration?` | `typeof Migration` | - | Custom type of the migration file | +| `options.up` | `Function` | - | `up` method of the migration file | +| `options.down` | `Function` | - | `down` method of the migration file | + +**Example** + +```ts +db.addMigration({ + name: '20220916120411-test-1', + async up() { + const queryInterface = this.context.db.sequelize.getQueryInterface(); + await queryInterface.query(/* your migration sqls */); + }, +}); +``` + +### `addMigrations()` + +Add the migration files in the specified directory. + +**Signature** + +- `addMigrations(options: AddMigrationsOptions): void` + +**Parameter** + +| Name | Type | Default | Description | +| -------------------- | ---------- | -------------- | ----------------------------------------------- | +| `options.directory` | `string` | `''` | Directory where the migration files are located | +| `options.extensions` | `string[]` | `['js', 'ts']` | File extensions | +| `options.namespace?` | `string` | `''` | Namespace | +| `options.context?` | `Object` | `{ db }` | Context of the migration files | + +**Example** + +```ts +db.addMigrations({ + directory: path.resolve(__dirname, './migrations'), + namespace: 'test', +}); +``` + +## Tool Methods + +### `inDialect()` + +Check whether the current database type is the specified type. + +**Signature** + +- `inDialect(dialect: string[]): boolean` + +**Parameter** + +| Name | Type | Default | Description | +| --------- | ---------- | ------- | ----------------------------------------------------------- | +| `dialect` | `string[]` | - | Database type, options are `mysql`, `postgres` and `sqlite` | + +### `getTablePrefix()` + +Get the table name prefix in the configuration. + +**Signature** + +- `getTablePrefix(): string` + +## Data Table Configurations + +### `collection()` + +Define a data table. This is like the `define` method of Sequelize, which only creates table structure in memory. Call the `sync` method if needs to be persisted to the database. + +**Signature** + +- `collection(options: CollectionOptions): Collection` + +**Parameter** + +All configuration parameters of `options` is consistent with the constructor of the `Collection` class, refer to [Collection](/api/server/database/collection#Constructor). + +**Event** + +- `'beforeDefineCollection'`: Trigger before defining the table. +- `'afterDefineCollection'`: Trigger after defining the table. + +**Example** + +```ts +db.collection({ + name: 'books', + fields: [ + { + type: 'string', + name: 'title', + }, + { + type: 'float', + name: 'price', + }, + ], +}); + +// sync collection as table to db +await db.sync(); +``` + +### `getCollection()` + +Get a defined data table. + +**Signature** + +- `getCollection(name: string): Collection` + +**Parameter** + +| Name | Type | Default | Description | +| ------ | -------- | ------- | ----------- | +| `name` | `string` | - | Table name | + +**Example** + +```ts +const collection = db.getCollection('books'); +``` + +### `hasCollection()` + +Check whether a specified data table is defined. + +**Signature** + +- `hasCollection(name: string): boolean` + +**Parameter** + +| Name | Type | Default | Description | +| ------ | -------- | ------- | ----------- | +| `name` | `string` | - | Table name | + +**Example** + +```ts +db.collection({ name: 'books' }); + +db.hasCollection('books'); // true + +db.hasCollection('authors'); // false +``` + +### `removeCollection()` + +Remove a defined data table. It is to remove from memory only, call the `sync` method if needs to be persisted to the database. + +**Signature** + +- `removeCollection(name: string): void` + +**Parameter** + +| Name | Type | Default | Description | +| ------ | -------- | ------- | ----------- | +| `name` | `string` | - | Table name | + +**Event** + +- `'beforeRemoveCollection'`: Trigger before removing the table. +- `'afterRemoveCollection'`: Trigger after removing the table + +**Example** + +```ts +db.collection({ name: 'books' }); + +db.removeCollection('books'); +``` + +### `import()` + +Load all files in the import file directory into memory as the configuration of collection. + +**Signature** + +- `async import(options: { directory: string; extensions?: ImportFileExtension[] }): Promise>` + +**Parameter** + +| Name | Type | Default | Description | +| -------------------- | ---------- | -------------- | -------------------------------- | +| `options.directory` | `string` | - | Path of directory to be imported | +| `options.extensions` | `string[]` | `['ts', 'js']` | Scan for specific suffixes | + +**Example** + +The collection defined by file `./collections/books.ts` is as below: + +```ts +export default { + name: 'books', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}; +``` + +Import the relevant configurations when loading the plugin: + +```ts +class Plugin { + async load() { + await this.app.db.import({ + directory: path.resolve(__dirname, './collections'), + }); + } +} +``` + +## Extension Registrations and Acquisitions + +### `registerFieldTypes()` + +Register custom field type. + +**Signature** + +- `registerFieldTypes(fieldTypes: MapOf): void` + +**Parameter** + +`fieldTypes` is a key-value pair, where key is the field type name, and value is the field type class. + +**Example** + +```ts +import { Field } from '@nocobase/database'; + +class MyField extends Field { + // ... +} + +db.registerFieldTypes({ + myField: MyField, +}); +``` + +### `registerModels()` + +Register custom data model class. + +**Signature** + +- `registerModels(models: MapOf>): void` + +**Parameter** + +`models` is a key-value pair, where key is the data model name, and value is the data model class. + +**Example** + +```ts +import { Model } from '@nocobase/database'; + +class MyModel extends Model { + // ... +} + +db.registerModels({ + myModel: MyModel, +}); + +db.collection({ + name: 'myCollection', + model: 'myModel', +}); +``` + +### `registerRepositories()` + +Register custom data repository class. + +**Signature** + +- `registerRepositories(repositories: MapOf): void` + +**Parameter** + +`repositories` is a key-value pair, where key is the data repository name, and value is the data repository class. + +**Example** + +```ts +import { Repository } from '@nocobase/database'; + +class MyRepository extends Repository { + // ... +} + +db.registerRepositories({ + myRepository: MyRepository, +}); + +db.collection({ + name: 'myCollection', + repository: 'myRepository', +}); +``` + +### `registerOperators()` + +Register custom data query operator. + +**Signature** + +- `registerOperators(operators: MapOf)` + +**Parameter** + +`operators` is a key-value pair, where key is the operator name, and value is the generating function of the comparison operator statement. + +**Example** + +```ts +db.registerOperators({ + $dateOn(value) { + return { + [Op.and]: [ + { [Op.gte]: stringToDate(value) }, + { [Op.lt]: getNextDay(value) }, + ], + }; + }, +}); + +db.getRepository('books').count({ + filter: { + createdAt: { + // registered operator + $dateOn: '2020-01-01', + }, + }, +}); +``` + +### `getModel()` + +Get the defined data model class. If no custom model class has been registered before, the default model class of Sequelize will be returned. The default name is the same as the name defined by collection. + +**Signature** + +- `getModel(name: string): Model` + +**Parameter** + +| Name | Type | Default | Description | +| ------ | -------- | ------- | --------------------- | +| `name` | `string` | - | Registered model name | + +**Example** + +```ts +db.registerModels({ + books: class MyModel extends Model {}, +}); + +const ModelClass = db.getModel('books'); + +console.log(ModelClass.prototype instanceof MyModel); // true +``` + +Note: The model class retrieved from collection is not strictly equivalent to the model class at registration, but is inherited from the model class at registration. Since the properties of Sequelize's model class are modified during initialization, NocoBase automatically handles this inheritance relationship. All the definitions work fine except that the classes are not equal. + +### `getRepository()` + +Get the defined data repository class. If no custom data repository class has been registered before, the default data repository class of NocoBase will be returned. The default name is the same as the name defined by collection. + +Data repository class is mainly used for the CRUD operations based on data model, refer to [Repository](/api/server/database/repository). + +**Signature** + +- `getRepository(name: string): Repository` +- `getRepository(name: string, relationId?: string | number): Repository` + +**Parameter** + +| Name | Type | Default | Description | +| ------------ | -------------------- | ------- | ------------------------------------- | +| `name` | `string` | - | Registered data repository name | +| `relationId` | `string` \| `number` | - | Foreign key value for relational data | + +When the name contains relationship in the form of `'tables.relactions'`, the related data repository class is returned. If the second parameter is provided, the data repository will be used (query, modify, etc.) based on the foreign key values of the relational data. + +**Example** + +Suppose there are two data tables posts and authors, and there is a foreign key in the posts table points to the authors table: + +```ts +const AuthorsRepo = db.getRepository('authors'); +const author1 = AuthorsRepo.create({ name: 'author1' }); + +const PostsRepo = db.getRepository('authors.posts', author1.id); +const post1 = AuthorsRepo.create({ title: 'post1' }); +asset(post1.authorId === author1.id); // true +``` + +## Database Events + +### `on()` + +Listen for database events. + +**Signature** + +- `on(event: string, listener: (...args: any[]) => void | Promise): void` + +**Parameter** + +| Name | Type | Default | Description | +| -------- | -------- | ------- | -------------- | +| event | string | - | Event name | +| listener | Function | - | Event listener | + +Event name supports Model event of Sequelize by default. Global event is listened to by the name ``, single Model event is listened to by the name `. `. + +Refer to the [Built-in Events](#built-in-events) section for parameter descriptions and detailed examples of all built-in event types. + +### `off()` + +Remove the event listener function. + +**Signature** + +- `off(name: string, listener: Function)` + +**Parameter** + +| Name | Type | Default | Description | +| -------- | -------- | ------- | -------------- | +| name | string | - | Event name | +| listener | Function | - | Event listener | + +**Example** + +```ts +const listener = async (model, options) => { + console.log(model); +}; + +db.on('afterCreate', listener); + +db.off('afterCreate', listener); +``` + +## Database Operations + +### `auth()` + +Database connection verification. It can be used to ensure that the application has established connection to the data. + +**Signature** + +- `auth(options: QueryOptions & { retry?: number } = {}): Promise` + +**Parameter** + +| Name | Type | Default | Description | +| ---------------------- | --------------------- | ------- | ------------------------------------------------- | +| `options?` | `Object` | - | Verification option | +| `options.retry?` | `number` | `10` | Number of retries in case of verification failure | +| `options.transaction?` | `Transaction` | - | Transaction object | +| `options.logging?` | `boolean \| Function` | `false` | Whether to print the log | + +**Example** + +```ts +await db.auth(); +``` + +### `reconnect()` + +Reconnect to the database. + +**Example** + +```ts +await db.reconnect(); +``` + +### `closed()` + +Check whether database has closed the connection. + +**Signature** + +- `closed(): boolean` + +### `close()` + +Closes database connection. Equivalent to `sequelize.close()`. + +### `sync()` + +Synchronizes database table structure. Equivalent to `sequelize.sync()`, refer to [Sequelize documentation](https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-method-sync) for parameters. + +### `clean()` + +Empty the database, it will delete all data tables. + +**Signature** + +- `clean(options: CleanOptions): Promise` + +**Parameter** + +| Name | Type | Default | Description | +| --------------------- | ------------- | ------- | --------------------------------- | +| `options.drop` | `boolean` | `false` | Whether to remove all data tables | +| `options.skip` | `string[]` | - | Names of tables to skip | +| `options.transaction` | `Transaction` | - | Transaction object | + +**Example** + +Remove all tables except for the `users` table. + +```ts +await db.clean({ + drop: true, + skip: ['users'], +}); +``` + +## Package-Level Export + +### `defineCollection()` + +Create the configuration content of a data table. + +**Signature** + +- `defineCollection(name: string, config: CollectionOptions): CollectionOptions` + +**Parameter** + +| Name | Type | Default | Description | +| ------------------- | ------------------- | ------- | -------------------------------------------------- | +| `collectionOptions` | `CollectionOptions` | - | All parameters are the same with `db.collection()` | + +**Example** + +For the data table configuration file to be imported by `db.import()`: + +```ts +import { defineCollection } from '@nocobase/database'; + +export default defineCollection({ + name: 'users', + fields: [ + { + type: 'string', + name: 'name', + }, + ], +}); +``` + +### `extendCollection()` + +Extent the configuration content of a data table that is already in memory, mainly for the content of files imported by the `import()` method. This is the top-level package export method of `@nocobase/database`, and is not called through db instance. The `extend` alias can also be used. + +**Signature** + +- `extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ExtendedCollectionOptions` + +**Parameter** + +| Name | Type | Default | Description | +| ------------------- | ------------------- | ------- | ----------------------------------------------------------------------- | +| `collectionOptions` | `CollectionOptions` | - | All the same with `db.collection()` | +| `mergeOptions?` | `MergeOptions` | - | [deepmerge](https://npmjs.com/package/deepmerge) options of npm package | + +**Example** + +Original definition of the table books (books.ts): + +```ts +export default { + name: 'books', + fields: [{ name: 'title', type: 'string' }], +}; +``` + +Extend the definition of the table books (books.extend.ts): + +```ts +import { extend } from '@nocobase/database'; + +// Extend again +export default extend({ + name: 'books', + fields: [{ name: 'price', type: 'number' }], +}); +``` + +If the above two files are imported when calling `import()`, after being extended again by `extend()`, the table books will have `title` and `price` two fields. + +This method is especially useful when extending the table structure that is already defined by existing plugin. + +## Built-in Events + +The following events will be triggered in the corresponding lifecycle of database, subscribe by the `on()` method and perform specific processing to meet some business needs. + +### `'beforeSync'` / `'afterSync'` + +Events triggered before or after a new table structure configuration (fields, indexes, etc.) is synchronized to the database. This is usually triggered when executing `collection.sync()` (internal call) for the logical processing of the extension of some special fields. + +**Signature** + +```ts +on(eventName: `${string}.beforeSync` | 'beforeSync' | `${string}.afterSync` | 'afterSync', listener: SyncListener): this +``` + +**Type** + +```ts +import type { SyncOptions, HookReturn } from 'sequelize/types'; + +type SyncListener = (options?: SyncOptions) => HookReturn; +``` + +**Example** + +```ts +const users = db.collection({ + name: 'users', + fields: [{ type: 'string', name: 'username' }], +}); + +db.on('beforeSync', async (options) => { + // do something +}); + +db.on('users.afterSync', async (options) => { + // do something +}); + +await users.sync(); +``` + +### `'beforeValidate'` / `'afterValidate'` + +Before creating or updating data, there is a validation against the data based on the rules defined by the collection, and the corresponding events are triggered before and after the validation. This is triggered when `repository.create()` or `repository.update()` is called. + +**Signature** + +```ts +on(eventName: `${string}.beforeValidate` | 'beforeValidate' | `${string}.afterValidate` | 'afterValidate', listener: ValidateListener): this +``` + +**Type** + +```ts +import type { ValidationOptions } from 'sequelize/types/lib/instance-validator'; +import type { HookReturn } from 'sequelize/types'; +import type { Model } from '@nocobase/database'; + +type ValidateListener = ( + model: Model, + options?: ValidationOptions, +) => HookReturn; +``` + +**Example** + +```ts +db.collection({ + name: 'tests', + fields: [ + { + type: 'string', + name: 'email', + validate: { + isEmail: true, + }, + }, + ], +}); + +// all models +db.on('beforeValidate', async (model, options) => { + // do something +}); +// tests model +db.on('tests.beforeValidate', async (model, options) => { + // do something +}); + +// all models +db.on('afterValidate', async (model, options) => { + // do something +}); +// tests model +db.on('tests.afterValidate', async (model, options) => { + // do something +}); + +const repository = db.getRepository('tests'); +await repository.create({ + values: { + email: 'abc', // checks for email format + }, +}); +// or +await repository.update({ + filterByTk: 1, + values: { + email: 'abc', // checks for email format + }, +}); +``` + +### `'beforeCreate'` / `'afterCreate'` + +Events triggered before or after creating one piece of data. This is triggered when `repository.create()` is called. + +**Signature** + +```ts +on(eventName: `${string}.beforeCreate` | 'beforeCreate' | `${string}.afterCreate` | 'afterCreate', listener: CreateListener): this +``` + +**Type** + +```ts +import type { CreateOptions, HookReturn } from 'sequelize/types'; +import type { Model } from '@nocobase/database'; + +export type CreateListener = ( + model: Model, + options?: CreateOptions, +) => HookReturn; +``` + +**Example** + +```ts +db.on('beforeCreate', async (model, options) => { + // do something +}); + +db.on('books.afterCreate', async (model, options) => { + const { transaction } = options; + const result = await model.constructor.findByPk(model.id, { + transaction, + }); + console.log(result); +}); +``` + +### `'beforeUpdate'` / `'afterUpdate'` + +Events triggered before or after updating one piece of data. This is triggered when `repository.update()` is called. + +**Signature** + +```ts +on(eventName: `${string}.beforeUpdate` | 'beforeUpdate' | `${string}.afterUpdate` | 'afterUpdate', listener: UpdateListener): this +``` + +**Type** + +```ts +import type { UpdateOptions, HookReturn } from 'sequelize/types'; +import type { Model } from '@nocobase/database'; + +export type UpdateListener = ( + model: Model, + options?: UpdateOptions, +) => HookReturn; +``` + +**Example** + +```ts +db.on('beforeUpdate', async (model, options) => { + // do something +}); + +db.on('books.afterUpdate', async (model, options) => { + // do something +}); +``` + +### `'beforeSave'` / `'afterSave'` + +Events triggered before or after creating or updating one piece of data. This is triggered when `repository.create()` or `repository.update()` is called. + +**Signature** + +```ts +on(eventName: `${string}.beforeSave` | 'beforeSave' | `${string}.afterSave` | 'afterSave', listener: SaveListener): this +``` + +**Type** + +```ts +import type { SaveOptions, HookReturn } from 'sequelize/types'; +import type { Model } from '@nocobase/database'; + +export type SaveListener = (model: Model, options?: SaveOptions) => HookReturn; +``` + +**Example** + +```ts +db.on('beforeSave', async (model, options) => { + // do something +}); + +db.on('books.afterSave', async (model, options) => { + // do something +}); +``` + +### `'beforeDestroy'` / `'afterDestroy'` + +Events triggered before or after deleting one piece of data. This is triggered when `repository.destroy()` is called. + +**Signature** + +```ts +on(eventName: `${string}.beforeDestroy` | 'beforeDestroy' | `${string}.afterDestroy` | 'afterDestroy', listener: DestroyListener): this +``` + +**Type** + +```ts +import type { DestroyOptions, HookReturn } from 'sequelize/types'; +import type { Model } from '@nocobase/database'; + +export type DestroyListener = ( + model: Model, + options?: DestroyOptions, +) => HookReturn; +``` + +**Example** + +```ts +db.on('beforeDestroy', async (model, options) => { + // do something +}); + +db.on('books.afterDestroy', async (model, options) => { + // do something +}); +``` + +### `'afterCreateWithAssociations'` + +Events triggered after creating one piece of data that carries hierarchical data. This is triggered when `repository.create()` is called. + +**Signature** + +```ts +on(eventName: `${string}.afterCreateWithAssociations` | 'afterCreateWithAssociations', listener: CreateWithAssociationsListener): this +``` + +**Type** + +```ts +import type { CreateOptions, HookReturn } from 'sequelize/types'; +import type { Model } from '@nocobase/database'; + +export type CreateWithAssociationsListener = ( + model: Model, + options?: CreateOptions, +) => HookReturn; +``` + +**Example** + +```ts +db.on('afterCreateWithAssociations', async (model, options) => { + // do something +}); + +db.on('books.afterCreateWithAssociations', async (model, options) => { + // do something +}); +``` + +### `'afterUpdateWithAssociations'` + +Events triggered after updating one piece of data that carries hierarchical data. This is triggered when `repository.update()` is called. + +**Signature** + +```ts +on(eventName: `${string}.afterUpdateWithAssociations` | 'afterUpdateWithAssociations', listener: CreateWithAssociationsListener): this +``` + +**Type** + +```ts +import type { UpdateOptions, HookReturn } from 'sequelize/types'; +import type { Model } from '@nocobase/database'; + +export type UpdateWithAssociationsListener = ( + model: Model, + options?: UpdateOptions, +) => HookReturn; +``` + +**Example** + +```ts +db.on('afterUpdateWithAssociations', async (model, options) => { + // do something +}); + +db.on('books.afterUpdateWithAssociations', async (model, options) => { + // do something +}); +``` + +### `'afterSaveWithAssociations'` + +Events triggered after creating or updating one piece of data that carries hierarchical data. This is triggered when `repository.create()` or `repository.update()` is called. + +**Signature** + +```ts +on(eventName: `${string}.afterSaveWithAssociations` | 'afterSaveWithAssociations', listener: SaveWithAssociationsListener): this +``` + +**Type** + +```ts +import type { SaveOptions, HookReturn } from 'sequelize/types'; +import type { Model } from '@nocobase/database'; + +export type SaveWithAssociationsListener = ( + model: Model, + options?: SaveOptions, +) => HookReturn; +``` + +**Example** + +```ts +db.on('afterSaveWithAssociations', async (model, options) => { + // do something +}); + +db.on('books.afterSaveWithAssociations', async (model, options) => { + // do something +}); +``` + +### `'beforeDefineCollection'` + +Events triggered before defining a data table, such as when `db.collection()` is called. + +Note: This is a synchronous event. + +**Signature** + +```ts +on(eventName: 'beforeDefineCollection', listener: BeforeDefineCollectionListener): this +``` + +**Type** + +```ts +import type { CollectionOptions } from '@nocobase/database'; + +export type BeforeDefineCollectionListener = ( + options: CollectionOptions, +) => void; +``` + +**Example** + +```ts +db.on('beforeDefineCollection', (options) => { + // do something +}); +``` + +### `'afterDefineCollection'` + +Events triggered after defining a data table, such as when `db.collection()` is called. + +Note: This is a synchronous event. + +**Signature** + +```ts +on(eventName: 'afterDefineCollection', listener: AfterDefineCollectionListener): this +``` + +**Type** + +```ts +import type { Collection } from '@nocobase/database'; + +export type AfterDefineCollectionListener = (options: Collection) => void; +``` + +**Example** + +```ts +db.on('afterDefineCollection', (collection) => { + // do something +}); +``` + +### `'beforeRemoveCollection'` / `'afterRemoveCollection'` + +Events triggered before or after removing a data table from memory, such as when `db.removeCollection()` is called. + +Note: This is a synchronous event. + +**Signature** + +```ts +on(eventName: 'beforeRemoveCollection' | 'afterRemoveCollection', listener: RemoveCollectionListener): this +``` + +**Type** + +```ts +import type { Collection } from '@nocobase/database'; + +export type RemoveCollectionListener = (options: Collection) => void; +``` + +**Example** + +```ts +db.on('beforeRemoveCollection', (collection) => { + // do something +}); + +db.on('afterRemoveCollection', (collection) => { + // do something +}); +``` diff --git a/docs/fr-FR/api/database/interfaces/base-interface.md b/docs/fr-FR/api/database/interfaces/base-interface.md new file mode 100644 index 000000000..ea8cb0941 --- /dev/null +++ b/docs/fr-FR/api/database/interfaces/base-interface.md @@ -0,0 +1,29 @@ +# BaseInterface + +## 概览 + +BaseInterface 是所有 Interface 类型的基础类,用户可以自行继承此类实现自定义的 Interface 逻辑。 + +```typescript +class CustomInterface extends BaseInterface { + async toValue(value: string, ctx?: any): Promise { + // 自定义的 toValue 逻辑 + } + + toString(value: any, ctx?: any) { + // 自定义的 toString 逻辑 + } +} +// 注册 Interface +db.interfaceManager.registerInterfaceType('customInterface', CustomInterface) +``` + +## 接口 + +### toValue(value: string, ctx?: any): Promise + +将外部的字符串转换为 interface 的实际值,值可直接传递给 Repository 进行写入操作。 + +### toString(value: any, ctx?: any) + +将 interface 的实际值转换为 string 类型,string 类型可用作导出、展示时使用。 \ No newline at end of file diff --git a/docs/fr-FR/api/database/operators.md b/docs/fr-FR/api/database/operators.md new file mode 100644 index 000000000..093167e27 --- /dev/null +++ b/docs/fr-FR/api/database/operators.md @@ -0,0 +1,811 @@ +# Filter Operators + +Used in the filter parameters of the `find`, `findOne`, `findAndCount`, `count`, etc. APIs of repository: + +```ts +const repository = db.getRepository('books'); + +repository.find({ + filter: { + title: { + $eq: 'Spring and Autumn', + }, + }, +}); +``` + +To support JSON, NocoBase identifies query operators as a string prefixed with $. + +Moreover, NocoBase provides API to extend operators. Refer to [`db.registerOperators()`](../database#registeroperators). + +## General Operators + +### `$eq` + +Check if the field value is equal to the specified value. Equivalent to `=` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $eq: 'Spring and Autumn', + }, + }, +}); +``` + +Equal to `title: 'Spring and Autumn'` + +### `$ne` + +Check if the field value is not equal to the specified value. Equivalent to `!=` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $ne: 'Spring and Autumn', + }, + }, +}); +``` + +### `$is` + +Check if the field value is the specified value. Equivalent to `IS` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $is: null, + }, + }, +}); +``` + +### `$not` + +Check if the field value is not the specified value. Equivalent to `IS NOT` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $not: null, + }, + }, +}); +``` + +### `$col` + +Check if the field value is equal to the value of another field. Equivalent to `=` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $col: 'name', + }, + }, +}); +``` + +### `$in` + +Check if the field value is in the specified array. Equivalent to `IN` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $in: ['Spring and Autumn', 'Warring States'], + }, + }, +}); +``` + +### `$notIn` + +Check if the field value is not in the specified array. Equivalent to `NOT IN` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $notIn: ['Spring and Autumn', 'Warring States'], + }, + }, +}); +``` + +### `$empty` + +Check if the general field is empty. For string field, check if it is an empty string; for array field, check if it is an empty array. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $empty: true, + }, + }, +}); +``` + +### `$notEmpty` + +Check if the general field is not empty. For string field, check if it is not an empty string; for array field, check if it is not an empty array. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $notEmpty: true, + }, + }, +}); +``` + +## Logical Operators + +### `$and` + +Logical AND. Equivalent to `AND` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + $and: [{ title: 'Book of Songs' }, { isbn: '1234567890' }], + }, +}); +``` + +### `$or` + +Logical OR. Equivalent to `OR` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + $or: [ + { title: 'Book of Songs' }, + { publishedAt: { $lt: '0000-00-00T00:00:00Z' } }, + ], + }, +}); +``` + +## Boolean Field Operators + +For boolean fields: `type: 'boolean'` + +### `$isFalsy` + +Check if a Boolean field value is false. Boolean field values of `false`, `0` and `NULL` are all judged to be `$isFalsy: true`. + +**Example** + +```ts +repository.find({ + filter: { + isPublished: { + $isFalsy: true, + }, + }, +}); +``` + +### `$isTruly` + +Check if a Boolean field value is true. Boolean field values of `true` and `1` are all judged to be `$isTruly: true`. + +**Example** + +```ts +repository.find({ + filter: { + isPublished: { + $isTruly: true, + }, + }, +}); +``` + +## Numeric Type Field Operators + +For numeric type fields, including: + +- `type: 'integer'` +- `type: 'float'` +- `type: 'double'` +- `type: 'real'` +- `type: 'decimal'` + +### `$gt` + +Check if the field value is greater than the specified value. Equivalent to `>` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + price: { + $gt: 100, + }, + }, +}); +``` + +### `$gte` + +Check if the field value is equal to or greater than the specified value. Equivalent to `>=` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + price: { + $gte: 100, + }, + }, +}); +``` + +### `$lt` + +Check if the field value is less than the specified value. Equivalent to `<` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + price: { + $lt: 100, + }, + }, +}); +``` + +### `$lte` + +Check if the field value is equal to or less than the specified value. Equivalent to `<=` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + price: { + $lte: 100, + }, + }, +}); +``` + +### `$between` + +Check if the field value is between the specified two values. Equivalent to `BETWEEN` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + price: { + $between: [100, 200], + }, + }, +}); +``` + +### `$notBetween` + +Check if the field value is not between the specified two values. Equivalent to `NOT BETWEEN` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + price: { + $notBetween: [100, 200], + }, + }, +}); +``` + +## String Type Field Operators + +For string type fields, including `string`. + +### `$includes` + +Check if the string field contains the specified substring. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $includes: 'Three Character Classic', + }, + }, +}); +``` + +### `$notIncludes` + +Check if the string field does not contain the specified substring. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $notIncludes: 'Three Character Classic', + }, + }, +}); +``` + +### `$startsWith` + +Check if the string field starts with the specified substring. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $startsWith: 'Three Character Classic', + }, + }, +}); +``` + +### `$notStatsWith` + +Check if the string field does not start with the specified substring. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $notStatsWith: 'Three Character Classic', + }, + }, +}); +``` + +### `$endsWith` + +Check if the string field ends with the specified substring. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $endsWith: 'Three Character Classic', + }, + }, +}); +``` + +### `$notEndsWith` + +Check if the string field does not end with the specified substring. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $notEndsWith: 'Three Character Classic', + }, + }, +}); +``` + +### `$like` + +Check if the field value contains the specified string. Equivalent to `LIKE` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $like: 'Computer', + }, + }, +}); +``` + +### `$notLike` + +Check if the field value does not contain the specified string. Equivalent to `NOT LIKE` in SQL. + +**Example** + +```ts +repository.find({ + filter: { + title: { + $notLike: 'Computer', + }, + }, +}); +``` + +### `$iLike` + +Check if a field value contains the specified string, case ignored. Equivalent to `ILIKE` in SQL (PG only). + +**Example** + +```ts +repository.find({ + filter: { + title: { + $iLike: 'Computer', + }, + }, +}); +``` + +### `$notILike` + +Check if a field value does not contain the specified string, case ignored. Equivalent to `NOT ILIKE` in SQL (PG only). + +**Example** + +```ts +repository.find({ + filter: { + title: { + $notILike: 'Computer', + }, + }, +}); +``` + +### `$regexp` + +Check if the field value matches the specified regular expression. Equivalent to `REGEXP` in SQL (PG only). + +**Example** + +```ts +repository.find({ + filter: { + title: { + $regexp: '^Computer', + }, + }, +}); +``` + +### `$notRegexp` + +Check if the field value does not match the specified regular expression. Equivalent to `NOT REGEXP` in SQL (PG only). + +**Example** + +```ts +repository.find({ + filter: { + title: { + $notRegexp: '^Computer', + }, + }, +}); +``` + +### `$iRegexp` + +Check if the field value matches the specified regular expression, case ignored. Equivalent to `~*` in SQL (PG only). + +**Example** + +```ts +repository.find({ + filter: { + title: { + $iRegexp: '^COMPUTER', + }, + }, +}); +``` + +### `$notIRegexp` + +Check if the field value does not match the specified regular expression, case ignored. Equivalent to `!~*` in SQL (PG only). + +**Example** + +```ts +repository.find({ + filter: { + title: { + $notIRegexp: '^COMPUTER', + }, + }, +}); +``` + +## Date Type Field Operators + +For date type fields: `type: 'date'` + +### `$dateOn` + +Check if the date field value is within a certain day. + +**Example** + +```ts +repository.find({ + filter: { + createdAt: { + $dateOn: '2021-01-01', + }, + }, +}); +``` + +### `$dateNotOn` + +Check if the date field value is not within a certain day. + +**Example** + +```ts +repository.find({ + filter: { + createdAt: { + $dateNotOn: '2021-01-01', + }, + }, +}); +``` + +### `$dateBefore` + +Check if the date field value is before a certain value, i.e., less than the one passed in. + +**Example** + +```ts +repository.find({ + filter: { + createdAt: { + $dateBefore: '2021-01-01T00:00:00.000Z', + }, + }, +}); +``` + +### `$dateNotBefore` + +Check if the date field value is not before a certain value, i.e., equal to or greater than the one passed in. + +**Example** + +```ts +repository.find({ + filter: { + createdAt: { + $dateNotBefore: '2021-01-01T00:00:00.000Z', + }, + }, +}); +``` + +### `$dateAfter` + +Check if the date field value is after a certain value, i.e., greater than the one passed in. + +**Example** + +```ts +repository.find({ + filter: { + createdAt: { + $dateAfter: '2021-01-01T00:00:00.000Z', + }, + }, +}); +``` + +### `$dateNotAfter` + +Check if the date field value is not after a certain value, i.e., equal to or greater than the one passed in. + +**Example** + +```ts +repository.find({ + filter: { + createdAt: { + $dateNotAfter: '2021-01-01T00:00:00.000Z', + }, + }, +}); +``` + +## Array Type Field Operators + +For array type fields: `type: 'array'` + +### `$match` + +Check if the array field values match values of the specified array. + +**Example** + +```ts +repository.find({ + filter: { + tags: { + $match: ['literature', 'history'], + }, + }, +}); +``` + +### `$notMatch` + +Check if the array field values do not match values of the specified array. + +**Example** + +```ts +repository.find({ + filter: { + tags: { + $notMatch: ['literature', 'history'], + }, + }, +}); +``` + +### `$anyOf` + +Check if the array field values contain any of the values of the specified array. + +**Example** + +```ts +repository.find({ + filter: { + tags: { + $anyOf: ['literature', 'history'], + }, + }, +}); +``` + +### `$noneOf` + +Check if the array field values contain none of the values of the specified array. + +**Example** + +```ts +repository.find({ + filter: { + tags: { + $noneOf: ['literature', 'history'], + }, + }, +}); +``` + +### `$arrayEmpty` + +Check if the array field is empty. + +**Example** + +```ts +repository.find({ + filter: { + tags: { + $arrayEmpty: true, + }, + }, +}); +``` + +### `$arrayNotEmpty` + +Check if the array field is not empty. + +**Example** + +```ts +repository.find({ + filter: { + tags: { + $arrayNotEmpty: true, + }, + }, +}); +``` + +## Relational Field Type Operators + +For checking if a relationship exists, field types include: + +- `type: 'hasOne'` +- `type: 'hasMany'` +- `type: 'belongsTo'` +- `type: 'belongsToMany'` + +### `$exists` + +There is relational data existing. + +**Example** + +```ts +repository.find({ + filter: { + author: { + $exists: true, + }, + }, +}); +``` + +### `$notExists` + +There is no relational data existing. + +**Example** + +```ts +repository.find({ + filter: { + author: { + $notExists: true, + }, + }, +}); +``` diff --git a/docs/fr-FR/api/database/relation-repository/belongs-to-many-repository.md b/docs/fr-FR/api/database/relation-repository/belongs-to-many-repository.md new file mode 100644 index 000000000..72d611bf8 --- /dev/null +++ b/docs/fr-FR/api/database/relation-repository/belongs-to-many-repository.md @@ -0,0 +1,190 @@ +# BelongsToManyRepository + +`BelongsToManyRepository` is the `Relation Repository` for handling `BelongsToMany` relationships. + +Unlike other relationship types, the `BelongsToMany` type of relationship needs to be recorded through an intermediate table. The intermediate table can be created automatically or explicitly specified when defining association relationships in NocoBase. + +## Class Methods + +### `find()` + +Find associated objects. + +**Signature** + +- `async find(options?: FindOptions): Promise` + +**Detailed Information** + +Query parameters are the same as [`Repository.find()`](../repository.md#find). + +### `findOne()` + +Find associated objects, only to return one record. + +**Signature** + +- `async findOne(options?: FindOneOptions): Promise` + + + +### `count()` + +Return the number of records matching the query criteria. + +**Signature** + +- `async count(options?: CountOptions)` + +**Type** + +```typescript +interface CountOptions + extends Omit, + Transactionable { + filter?: Filter; +} +``` + +### `findAndCount()` + +Find datasets from the database with the specified filtering conditions and return the number of results. + +**Signature** + +- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>` + +**Type** + +```typescript +type FindAndCountOptions = CommonFindOptions; +``` + +### `create()` + +Create associated objects. + +**Signature** + +- `async create(options?: CreateOptions): Promise` + + + +### `update()` + +Update associated objects that match the conditions. + +**Signature** + +- `async update(options?: UpdateOptions): Promise` + + + +### `destroy()` + +Delete associated objects. + +**Signature** + +- `async destroy(options?: TargetKey | TargetKey[] | DestroyOptions): Promise` + + + +### `add()` + +Add new associated objects. + +**Signature** + +- `async add( +options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions +): Promise` + +**Type** + +```typescript +type PrimaryKeyWithThroughValues = [TargetKey, Values]; + +interface AssociatedOptions extends Transactionable { + tk?: + | TargetKey + | TargetKey[] + | PrimaryKeyWithThroughValues + | PrimaryKeyWithThroughValues[]; +} +``` + +**Detailed Information** + +Pass the `targetKey` of the associated object directly, or pass the `targetKey` along with the field values of the intermediate table. + +**Example** + +```typescript +const t1 = await Tag.repository.create({ + values: { name: 't1' }, +}); + +const t2 = await Tag.repository.create({ + values: { name: 't2' }, +}); + +const p1 = await Post.repository.create({ + values: { title: 'p1' }, +}); + +const PostTagRepository = new BelongsToManyRepository(Post, 'tags', p1.id); + +// Pass in the targetKey +PostTagRepository.add([t1.id, t2.id]); + +// Pass in intermediate table fields +PostTagRepository.add([ + [t1.id, { tagged_at: '123' }], + [t2.id, { tagged_at: '456' }], +]); +``` + +### `set()` + +Set the associated objects. + +**Signature** + +- async set( + options: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[] | AssociatedOptions, + ): Promise + +**Detailed Information** + +Parameters are the same as [add()](#add). + +### `remove()` + +Remove the association with the given objects. + +**Signature** + +- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)` + +**Type** + +```typescript +interface AssociatedOptions extends Transactionable { + tk?: TargetKey | TargetKey[]; +} +``` + +### `toggle()` + +Toggle the associated object. + +In some business scenarios, it is often needed to toggle the associated object. For example, user adds a product into collection, and the user cancels the collection and collect it again. Using the `toggle` method can quickly implement similar functions. + +**Signature** + +- `async toggle(options: TargetKey | { tk?: TargetKey; transaction?: Transaction }): Promise` + +**Detailed Information** + +The `toggle` method automatically checks whether the associated object already exists, and removes it if it does, or adds it if it does not. diff --git a/docs/fr-FR/api/database/relation-repository/belongs-to-repository.md b/docs/fr-FR/api/database/relation-repository/belongs-to-repository.md new file mode 100644 index 000000000..0a6b1df83 --- /dev/null +++ b/docs/fr-FR/api/database/relation-repository/belongs-to-repository.md @@ -0,0 +1,3 @@ +## BelongsToRepository + +The interface is the same as [HasOneRepository](./has-one-repository.md). `BelongsToRepository` is the `Repository` for handling `BelongsTo` relationships, and it provides some convenient methods to handle `BelongsTo` relationships. diff --git a/docs/fr-FR/api/database/relation-repository/has-many-repository.md b/docs/fr-FR/api/database/relation-repository/has-many-repository.md new file mode 100644 index 000000000..f7ae3e074 --- /dev/null +++ b/docs/fr-FR/api/database/relation-repository/has-many-repository.md @@ -0,0 +1,134 @@ +# HasManyRepository + +`HasManyRepository` is the `Relation Repository` for handling `HasMany` relationships. + +## Class Methods + +### `find()` + +Find associated objects. + +**Signature** + +- `async find(options?: FindOptions): Promise` + +**Detailed Information** + +Query parameters are the same as [`Repository.find()`](../repository.md#find). + +### `findOne()` + +Find associated objects, only to return one record. + +**Signature** + +- `async findOne(options?: FindOneOptions): Promise` + + + +### `count()` + +Return the number of records matching the query criteria. + +**Signature** + +- `async count(options?: CountOptions)` + +**Type** + +```typescript +interface CountOptions + extends Omit, + Transactionable { + filter?: Filter; +} +``` + +### `findAndCount()` + +Find datasets from the database with the specified filtering conditions and return the number of results. + +**Signature** + +- `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>` + +**Type** + +```typescript +type FindAndCountOptions = CommonFindOptions; +``` + +### `create()` + +Create associated objects. + +**Signature** + +- `async create(options?: CreateOptions): Promise` + + + +### `update()` + +Update associated objects that match the conditions. + +**Signature** + +- `async update(options?: UpdateOptions): Promise` + + + +### `destroy()` + +Delete associated objects. + +**Signature** + +- `async destroy(options?: TK | DestroyOptions): Promise` + + + +### `add()` + +Add association relationships between objects. + +**Signature** + +- `async add(options: TargetKey | TargetKey[] | AssociatedOptions)` + +**Type** + +```typescript +interface AssociatedOptions extends Transactionable { + tk?: TargetKey | TargetKey[]; +} +``` + +**Detailed Information** + +- `tk` - The targetKey value of the associated object, either as a single value or an array. + + +### `remove()` + +Remove the association with the given objects. + +**Signature** + +- `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)` + +**Detailed Information** + +Same parameters as the [`add()`](#add) method. + +### `set()` + +Set the associated object of the current relationship. + +**Signature** + +- `async set(options: TargetKey | TargetKey[] | AssociatedOptions)` + +**Detailed Information** + +Same parameters as the [`add()`](#add) method. diff --git a/docs/fr-FR/api/database/relation-repository/has-one-repository.md b/docs/fr-FR/api/database/relation-repository/has-one-repository.md new file mode 100644 index 000000000..12a814871 --- /dev/null +++ b/docs/fr-FR/api/database/relation-repository/has-one-repository.md @@ -0,0 +1,187 @@ +# HasOneRepository + +## Overview + +`HasOneRepository` is the associated repository of type `HasOne`. + +```typescript +const User = db.collection({ + name: 'users', + fields: [ + { type: 'hasOne', name: 'profile' }, + { type: 'string', name: 'name' }, + ], +}); + +const Profile = db.collection({ + name: 'profiles', + fields: [{ type: 'string', name: 'avatar' }], +}); + +const user = await User.repository.create({ + values: { name: 'u1' }, +}); + +// Get the associated repository +const userProfileRepository = User.repository + .relation('profile') + .of(user.get('id')); + +// Or to initialize directly +new HasOneRepository(User, 'profile', user.get('id')); +``` + +## Class Methods + +### `find()` + +Find associated objects. + +**Signature** + +- `async find(options?: SingleRelationFindOption): Promise | null>` + +**Type** + +```typescript +interface SingleRelationFindOption extends Transactionable { + fields?: Fields; + except?: Except; + appends?: Appends; + filter?: Filter; +} +``` + +**Detailed Information** + +Query parameters are the same as [`Repository.find()`](../repository.md#find). + +**Example** + +```typescript +const profile = await UserProfileRepository.find(); +// Return null if the associated object does not exist +``` + +### `create()` + +Create associated objects. + +**Signature** + +- `async create(options?: CreateOptions): Promise` + + + +**Example** + +```typescript +const profile = await UserProfileRepository.create({ + values: { avatar: 'avatar1' }, +}); + +console.log(profile.toJSON()); +/* +{ + id: 1, + avatar: 'avatar1', + userId: 1, + updatedAt: 2022-09-24T13:59:40.025Z, + createdAt: 2022-09-24T13:59:40.025Z +} +*/ +``` + +### `update()` + +Update associated objects. + +**Signature** + +- `async update(options: UpdateOptions): Promise` + + + +**Example** + +```typescript +const profile = await UserProfileRepository.update({ + values: { avatar: 'avatar2' }, +}); + +profile.get('avatar'); // 'avatar2' +``` + +### `remove()` + +Remove associated objects. Only to unassociate, not to delete the associated object. + +**Signature** + +- `async remove(options?: Transactionable): Promise` + +**Detailed Information** + +- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction. + +**Example** + +```typescript +await UserProfileRepository.remove(); +(await UserProfileRepository.find()) == null; // true + +(await Profile.repository.count()) === 1; // true +``` + +### `destroy()` + +Delete associated objects. + +**Signature** + +- `async destroy(options?: Transactionable): Promise` + +**Detailed Information** + +- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction. + +**Example** + +```typescript +await UserProfileRepository.destroy(); +(await UserProfileRepository.find()) == null; // true +(await Profile.repository.count()) === 0; // true +``` + +### `set()` + +Set associated objects. + +**Signature** + +- `async set(options: TargetKey | SetOption): Promise` + +**Type** + +```typescript +interface SetOption extends Transactionable { + tk?: TargetKey; +} +``` + +**Detailed Information** + +- tk: Set the targetKey of the associated object. +- transaction: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction. + +**Example** + +```typescript +const newProfile = await Profile.repository.create({ + values: { avatar: 'avatar2' }, +}); + +await UserProfileRepository.set(newProfile.get('id')); + +(await UserProfileRepository.find()).get('id') === newProfile.get('id'); // true +``` diff --git a/docs/fr-FR/api/database/relation-repository/index.md b/docs/fr-FR/api/database/relation-repository/index.md new file mode 100644 index 000000000..7a47f716c --- /dev/null +++ b/docs/fr-FR/api/database/relation-repository/index.md @@ -0,0 +1,48 @@ +# RelationRepository + +`RelationRepository` 是关系类型的 `Repository` 对象,`RelationRepository` 可以实现在不加载关联的情况下对关联数据进行操作。基于 `RelationRepository`,每种关联都派生出对应的实现,分别为 + +- [`HasOneRepository`](#has-one-repository) +- `HasManyRepository` +- `BelongsToRepository` +- `BelongsToManyRepository` + +## 构造函数 + +**签名** + +- `constructor(sourceCollection: Collection, association: string, sourceKeyValue: string | number)` + +**参数** + +| 参数名 | 类型 | 默认值 | 描述 | +| ------------------ | ------------------ | ------ | --------------------------------------------------------- | +| `sourceCollection` | `Collection` | - | 关联中的参照关系(referencing relation)对应的 Collection | +| `association` | `string` | - | 关联名称 | +| `sourceKeyValue` | `string \| number` | - | 参照关系中对应的 key 值 | + +## 基类属性 + +### `db: Database` + +数据库对象 + +### `sourceCollection` + +关联中的参照关系(referencing relation)对应的 Collection + +### `targetCollection` + +关联中被参照关系(referenced relation)对应的 Collection + +### `association` + +sequelize 中的与当前关联对应的 association 对象 + +### `associationField` + +collection 中的与当前关联对应的字段 + +### `sourceKeyValue` + +参照关系中对应的 key 值 diff --git a/docs/fr-FR/api/database/repository.md b/docs/fr-FR/api/database/repository.md new file mode 100644 index 000000000..c90203106 --- /dev/null +++ b/docs/fr-FR/api/database/repository.md @@ -0,0 +1,677 @@ +# Repository + +## Overview + +On a given `Collection` object, you can get its `Repository` object to perform read and write operations on the data table. + +```javascript +const { UserCollection } = require('./collections'); + +const UserRepository = UserCollection.repository; + +const user = await UserRepository.findOne({ + filter: { + id: 1, + }, +}); + +user.name = 'new name'; +await user.save(); +``` + +### Query + +#### Basic Query + +On the `Repository` object, call the `find*` methods to perform query. The `filter` parameter is supported by all query methods to filter the data. + +```javascript +// SELECT * FROM users WHERE id = 1 +userRepository.find({ + filter: { + id: 1, + }, +}); +``` + +#### Operator + +The `filter` parameter in the `Repository` also provides a variety of operators to perform more diverse queries. + +```javascript +// SELECT * FROM users WHERE age > 18 +userRepository.find({ + filter: { + age: { + $gt: 18, + }, + }, +}); + +// SELECT * FROM users WHERE age > 18 OR name LIKE '%张%' +userRepository.find({ + filter: { + $or: [{ age: { $gt: 18 } }, { name: { $like: '%张%' } }], + }, +}); +``` + +Refer to [Filter Operators](/api/database/operators) for more details on operators. + +#### Field Control + +Control the output fields by the `fields`, `except`, and `appends` parameters when performing query. + +- `fields`: Specify output fields +- `except`: Exclude output fields +- `appends`: Append output associated fields + +```javascript +// The result contains only the id and name fields +userRepository.find({ + fields: ['id', 'name'], +}); + +// The result does not contain only the password field +userRepository.find({ + except: ['password'], +}); + +// The result contains data associated with the posts object +userRepository.find({ + appends: ['posts'], +}); +``` + +#### Associated Field Query + +The `filter` parameter supports filtering by associated fields, for example: + +```javascript +// Find the user objects whose associated posts have title of "post title" +userRepository.find({ + filter: { + 'posts.title': 'post title', + }, +}); +``` + +Associated fields can also be nested: + +```javascript +// Find the user objects whose associated posts have comments containing "keywords" +await userRepository.find({ + filter: { + 'posts.comments.content': { + $like: '%keywords%', + }, + }, +}); +``` + +#### Sort + +Sort query results by the `sort` parameter. + +```javascript +// SELECT * FROM users ORDER BY age +await userRepository.find({ + sort: 'age', +}); + +// SELECT * FROM users ORDER BY age DESC +await userRepository.find({ + sort: '-age', +}); + +// SELECT * FROM users ORDER BY age DESC, name ASC +await userRepository.find({ + sort: ['-age', 'name'], +}); +``` + +Sort by the field of the associated object is also supported: + +```javascript +await userRepository.find({ + sort: 'profile.createdAt', +}); +``` + +### Create + +#### Basic Create + +Create new data objects via `Repository`. + +```javascript +await userRepository.create({ + name: 'Mark', + age: 18, +}); +// INSERT INTO users (name, age) VALUES ('Mark', 18) + +// Bulk creation +await userRepository.create([ + { + name: 'Mark', + age: 18, + }, + { + name: 'Alex', + age: 20, + }, +]); +``` + +#### Create Association + +Create associated objects at the same time of creating data. Like query, nested use of associated objects is also supported. For example: + +```javascript +await userRepository.create({ + name: 'Mark', + age: 18, + posts: [ + { + title: 'post title', + content: 'post content', + tags: [ + { + name: 'tag1', + }, + { + name: 'tag2', + }, + ], + }, + ], +}); +// When creating a user, create a post to associate with the user, and create tags to associate with the post +``` + +If the associated object is already in the database, you can pass its ID to create an association with it. + +```javascript +const tag1 = await tagRepository.findOne({ + filter: { + name: 'tag1', + }, +}); + +await userRepository.create({ + name: 'Mark', + age: 18, + posts: [ + { + title: 'post title', + content: 'post content', + tags: [ + { + id: tag1.id, // Create an association with an existing associated object + }, + { + name: 'tag2', + }, + ], + }, + ], +}); +``` + +### Update + +#### Basic Update + +After getting the data object, you can modify the properties directly on the data object (`Model`), and then call the `save` method to save the changes. + +```javascript +const user = await userRepository.findOne({ + filter: { + name: 'Mark', + }, +}); + +user.age = 20; +await user.save(); +``` + +The data object `Model` is inherited from Sequelize Model, refer to [Sequelize Model](https://sequelize.org/master/manual/model-basics.html) for the operations on `Model`. + +Or update data via `Repository`: + +```javascript +// Update the records that meet the filtering condition +await userRepository.update({ + filter: { + name: 'Mark', + }, + values: { + age: 20, + }, +}); +``` + +Control which fields to update by the `whitelist` and `blacklist` parameters, for example: + +```javascript +await userRepository.update({ + filter: { + name: 'Mark', + }, + values: { + age: 20, + name: 'Alex', + }, + whitelist: ['age'], // Only update the age field +}); +``` + +#### Update Associated Field + +Associated objects can be set while updating, for example: + +```javascript +const tag1 = tagRepository.findOne({ + filter: { + id: 1, + }, +}); + +await postRepository.update({ + filter: { + id: 1, + }, + values: { + title: 'new post title', + tags: [ + { + id: tag1.id, // Associate with tag1 + }, + { + name: 'tag2', // Create new tag and associate with it + }, + ], + }, +}); + +await postRepository.update({ + filter: { + id: 1, + }, + values: { + tags: null, // Disassociate post from tags + }, +}); +``` + +### Delete + +Call the `destroy()` method in `Repository` to perform the deletion operation. Filtering condition has to be specified to delete. + +```javascript +await userRepository.destroy({ + filter: { + status: 'blocked', + }, +}); +``` + +## Constructor + +It is usually not called directly by the developer, the instantiation is done mainly by specifying a corresponding repository type that is already registered in the parameter of `db.colletion()`. Repository type is registered through `db.registerRepositories()`. + +**Signature** + +- `constructor(collection: Collection)` + +**Example** + +```ts +import { Repository } from '@nocobase/database'; + +class MyRepository extends Repository { + async myQuery(sql) { + return this.database.sequelize.query(sql); + } +} + +db.registerRepositories({ + books: MyRepository, +}); + +db.collection({ + name: 'books', + // here link to the registered repository + repository: 'books', +}); + +await db.sync(); + +const books = db.getRepository('books') as MyRepository; +await books.myQuery('SELECT * FROM books;'); +``` + +## Instance Members + +### `database` + +The database management instance where the context is located. + +### `collection` + +The corresponding data table management instance. + +### `model` + +The corresponding data model class. + +## Instance Methods + +### `find()` + +Find datasets from the database with the specified filtering conditions and sorting, etc. + +**Signature** + +- `async find(options?: FindOptions): Promise` + +**Type** + +```typescript +type Filter = FilterWithOperator | FilterWithValue | FilterAnd | FilterOr; +type Appends = string[]; +type Except = string[]; +type Fields = string[]; +type Sort = string[] | string; + +interface SequelizeFindOptions { + limit?: number; + offset?: number; +} + +interface FilterByTk { + filterByTk?: TargetKey; +} + +interface CommonFindOptions extends Transactionable { + filter?: Filter; + fields?: Fields; + appends?: Appends; + except?: Except; + sort?: Sort; +} + +type FindOptions = SequelizeFindOptions & CommonFindOptions & FilterByTk; +``` + +**Detailed Information** + +#### `filter: Filter` + +Query conditions for filtering data results. In the query parameters that passed in, `key` is the name of the field, `value` is the corresponding value. Operators can be used in conjunction with other filtering conditions. + +```typescript +// Find records with name "foo" and age above 18 +repository.find({ + filter: { + name: 'foo', + age: { + $gt: 18, + }, + }, +}); +``` + +Refer to [Operators](./operators.md) for more information. + +#### `filterByTk: TargetKey` + +Query data by `TargetKey`, this is shortcut for the `filter` parameter. The field of `TargetKey` can be [configured](./collection.md#filtertargetkey) in `Collection`, the default is `primaryKey`. + +```typescript +// By default, find records with id 1 +repository.find({ + filterByTk: 1, +}); +``` + +#### `fields: string[]` + +Query columns. It is used to control which data fields to output. With this parameter, only the specified fields will be returned. + +#### `except: string[]` + +Exclude columns. It is used to control which data fields to output. With this parameter, the specified fields will not be returned. + +#### `appends: string[]` + +Append columns. It is used to load associated data. With this parameter, the specified associated fields will be returned together. + +#### `sort: string[] | string` + +Specify the sorting method of the query results. The input parameter is the name of the field, by default is to sort in the ascending order (`asc`); a `-` symbol needs to be added before the field name to sort in the descending order (`desc`). For example, `['-id', 'name']` means to sort by `id desc, name asc`. + +#### `limit: number` + +Limit the number of results, same as `limit` in `SQL`. + +#### `offset: number` + +The offset of the query, same as `offset` in `SQL`. + +**Example** + +```ts +const posts = db.getRepository('posts'); + +const results = await posts.find({ + filter: { + createdAt: { + $gt: '2022-01-01T00:00:00.000Z', + }, + }, + fields: ['title'], + appends: ['user'], +}); +``` + +### `findOne()` + +Find a single piece of data from the database for specific conditions. Equivalent to `Model.findOne()` in Sequelize. + +**Signature** + +- `async findOne(options?: FindOneOptions): Promise` + + + +**Example** + +```ts +const posts = db.getRepository('posts'); + +const result = await posts.findOne({ + filterByTk: 1, +}); +``` + +### `count()` + +Query a certain amount of data from the database for specific conditions. Equivalent to `Model.count()` in Sequelize. + +**Signature** + +- `count(options?: CountOptions): Promise` + +**Type** + +```typescript +interface CountOptions + extends Omit, + Transactionable { + filter?: Filter; +} +``` + +**Example** + +```ts +const books = db.getRepository('books'); + +const count = await books.count({ + filter: { + title: 'Three character classic', + }, +}); +``` + +### `findAndCount()` + +Find datasets from the database with the specified filtering conditions and return the number of results. Equivalent to `Model.findAndCountAll()` in Sequelize. + +**Signature** + +- `async findAndCount(options?: FindAndCountOptions): Promise<[Model[], number]>` + +**Type** + +```typescript +type FindAndCountOptions = Omit< + SequelizeAndCountOptions, + 'where' | 'include' | 'order' +> & + CommonFindOptions; +``` + +**Detailed Information** + +The query parameters are the same as `find()`. An array is returned with the first element of the query results, and the second element of the total number of results. + +### `create()` + +Inserts a newly created data into the data table. Equivalent to `Model.create()` in Sequelize. When the data object to be created carries any associated field, the corresponding associated data record is created or updated along with it. + +**Signature** + +- `async create(options: CreateOptions): Promise` + + + +**Example** + +```ts +const posts = db.getRepository('posts'); + +const result = await posts.create({ + values: { + title: 'NocoBase 1.0 Release Notes', + tags: [ + // Update data when there is a primary key and value of the associated table + { id: 1 }, + // Create data when there is no primary key and value + { name: 'NocoBase' }, + ], + }, +}); +``` + +### `createMany()` + +Inserts multiple newly created data into the data table. This is equivalent to calling the `create()` method multiple times. + +**Signature** + +- `createMany(options: CreateManyOptions): Promise` + +**Type** + +```typescript +interface CreateManyOptions extends BulkCreateOptions { + records: Values[]; +} +``` + +**Detailed Information** + +- `records`: An array of data objects to be created. +- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction. + +**Example** + +```ts +const posts = db.getRepository('posts'); + +const results = await posts.createMany({ + records: [ + { + title: 'NocoBase 1.0 Release Notes', + tags: [ + // Update data when there is a primary key and value of the associated table + { id: 1 }, + // Create data when there is no primary key and value + { name: 'NocoBase' }, + ], + }, + { + title: 'NocoBase 1.1 Release Notes', + tags: [{ id: 1 }], + }, + ], +}); +``` + +### `update()` + +Update data in the data table. Equivalent to `Model.update()` in Sequelize. When the data object to be updated carries any associated field, the corresponding associated data record is created or updated along with it. + +**Signature** + +- `async update(options: UpdateOptions): Promise` + + + +**Example** + +```ts +const posts = db.getRepository('posts'); + +const result = await posts.update({ + filterByTk: 1, + values: { + title: 'NocoBase 1.0 Release Notes', + tags: [ + // Update data when there is a primary key and value of the associated table + { id: 1 }, + // Create data when there is no primary key and value + { name: 'NocoBase' }, + ], + }, +}); +``` + +### `destroy()` + +Delete data from the data table. Equivalent to `Model.destroy()` in Sequelize. + +**Signature** + +- `async destroy(options?: TargetKey | TargetKey[] | DestoryOptions): Promise` + +**Type** + +```typescript +interface DestroyOptions extends SequelizeDestroyOptions { + filter?: Filter; + filterByTk?: TargetKey | TargetKey[]; + truncate?: boolean; + context?: any; +} +``` + +**Detailed Information** + +- `filter`:Specify the filtering conditions of the records to be deleted. Refer to the [`find()`](#find) method for the detailed usage of the filter. +- `filterByTk`:Specify the filtering conditions by TargetKey. +- `truncate`: Whether to empty the table data, this parameter is valid if no `filter` or `filterByTk` parameter is passed. +- `transaction`: Transaction object. If no transaction parameter is passed, the method will automatically create an internal transaction. diff --git a/docs/fr-FR/api/database/shared.md b/docs/fr-FR/api/database/shared.md new file mode 100644 index 000000000..ef98f128c --- /dev/null +++ b/docs/fr-FR/api/database/shared.md @@ -0,0 +1,8 @@ +**参数** + +| 参数名 | 类型 | 默认值 | 描述 | +| ---------------------- | ------------- | ------ | ----------------------------------------------- | +| `options.values` | `M` | `{}` | 插入的数据对象 | +| `options.whitelist?` | `string[]` | - | `values` 字段的白名单,只有名单内的字段会被存储 | +| `options.blacklist?` | `string[]` | - | `values` 字段的黑名单,名单内的字段不会被存储 | +| `options.transaction?` | `Transaction` | - | 事务 | diff --git a/docs/fr-FR/api/database/shared/create-options.md b/docs/fr-FR/api/database/shared/create-options.md new file mode 100644 index 000000000..7e7311fb3 --- /dev/null +++ b/docs/fr-FR/api/database/shared/create-options.md @@ -0,0 +1,22 @@ +**类型** + +```typescript +type WhiteList = string[]; +type BlackList = string[]; +type AssociationKeysToBeUpdate = string[]; + +interface CreateOptions extends SequelizeCreateOptions { + values?: Values; + whitelist?: WhiteList; + blacklist?: BlackList; + updateAssociationValues?: AssociationKeysToBeUpdate; + context?: any; +} +``` + +**详细信息** + +- `values`:要创建的记录的数据对象。 +- `whitelist`:指定要创建的记录的数据对象中,哪些字段**可以被写入**。若不传入此参数,则默认允许所有字段写入。 +- `blacklist`:指定要创建的记录的数据对象中,哪些字段**不允许被写入**。若不传入此参数,则默认允许所有字段写入。 +- `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 diff --git a/docs/fr-FR/api/database/shared/destroy-options.md b/docs/fr-FR/api/database/shared/destroy-options.md new file mode 100644 index 000000000..e28a277d9 --- /dev/null +++ b/docs/fr-FR/api/database/shared/destroy-options.md @@ -0,0 +1,17 @@ +**类型** + +```typescript +interface DestroyOptions extends SequelizeDestroyOptions { + filter?: Filter; + filterByTk?: TargetKey | TargetKey[]; + truncate?: boolean; + context?: any; +} +``` + +**详细信息** + +- `filter`:指定要删除的记录的过滤条件。Filter 详细用法可参考 [`find()`](#find) 方法。 +- `filterByTk`:按 TargetKey 指定要删除的记录的过滤条件。 +- `truncate`: 是否清空表数据,在没有传入 `filter` 或 `filterByTk` 参数时有效。 +- `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 diff --git a/docs/fr-FR/api/database/shared/find-one.md b/docs/fr-FR/api/database/shared/find-one.md new file mode 100644 index 000000000..e868598cc --- /dev/null +++ b/docs/fr-FR/api/database/shared/find-one.md @@ -0,0 +1,9 @@ +**类型** + +```typescript +type FindOneOptions = Omit; +``` + +**参数** + +大部分参数与 `find()` 相同,不同之处在于 `findOne()` 只返回单条数据,所以不需要 `limit` 参数,且查询时始终为 `1`。 diff --git a/docs/fr-FR/api/database/shared/find-options.md b/docs/fr-FR/api/database/shared/find-options.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/fr-FR/api/database/shared/transaction.md b/docs/fr-FR/api/database/shared/transaction.md new file mode 100644 index 000000000..dc8134210 --- /dev/null +++ b/docs/fr-FR/api/database/shared/transaction.md @@ -0,0 +1 @@ +- `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 diff --git a/docs/fr-FR/api/database/shared/update-options.md b/docs/fr-FR/api/database/shared/update-options.md new file mode 100644 index 000000000..5ba26af5b --- /dev/null +++ b/docs/fr-FR/api/database/shared/update-options.md @@ -0,0 +1,24 @@ +**类型** + +```typescript +interface UpdateOptions extends Omit { + values: Values; + filter?: Filter; + filterByTk?: TargetKey; + whitelist?: WhiteList; + blacklist?: BlackList; + updateAssociationValues?: AssociationKeysToBeUpdate; + context?: any; +} +``` + +**详细信息** + +- `values`:要更新的记录的数据对象。 +- `filter`:指定要更新的记录的过滤条件, Filter 详细用法可参考 [`find()`](#find) 方法。 +- `filterByTk`:按 TargetKey 指定要更新的记录的过滤条件。 +- `whitelist`: `values` 字段的白名单,只有名单内的字段会被写入。 +- `blacklist`: `values` 字段的黑名单,名单内的字段不会被写入。 +- `transaction`: 事务对象。如果没有传入事务参数,该方法会自动创建一个内部事务。 + +`filterByTk` 与 `filter` 至少要传其一。 diff --git a/docs/fr-FR/api/handlebars-helpers/array.md b/docs/fr-FR/api/handlebars-helpers/array.md new file mode 100644 index 000000000..412d0ee9e --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/array.md @@ -0,0 +1,545 @@ +# Array + +## {{after}} + +Returns all of the items in an array after the specified index. Opposite of [before](#before). + +**Params** + +* `array` **{Array}**: Collection +* `n` **{Number}**: Starting index (number of items to exclude) +* `returns` **{Array}**: Array exluding `n` items. + +**Example** + +```handlebars + +{{after array 1}} + +``` + +## {{arrayify}} + +Cast the given `value` to an array. + +**Params** + +* `value` **{any}** +* `returns` **{Array}** + +**Example** + +```handlebars +{{arrayify "foo"}} + +``` + +## {{before}} + +Return all of the items in the collection before the specified count. Opposite of [after](#after). + +**Params** + +* `array` **{Array}** +* `n` **{Number}** +* `returns` **{Array}**: Array excluding items after the given number. + +**Example** + +```handlebars + +{{before array 2}} + +``` + +## {{eachIndex}} + +**Params** + +* `array` **{Array}** +* `options` **{Object}** +* `returns` **{String}** + +**Example** + +```handlebars + +{{#eachIndex array}} + {{item}} is {{index}} +{{/eachIndex}} +``` + +## {{filter}} + +Block helper that filters the given array and renders the block for values that evaluate to `true`, otherwise the inverse block is returned. + +**Params** + +* `array` **{Array}** +* `value` **{any}** +* `options` **{Object}** +* `returns` **{String}** + +**Example** + +```handlebars + +{{#filter array "foo"}}AAA{{else}}BBB{{/filter}} + +``` + +## {{first}} + +Returns the first item, or first `n` items of an array. + +**Params** + +* `array` **{Array}** +* `n` **{Number}**: Number of items to return, starting at `0`. +* `returns` **{Array}** + +**Example** + +```handlebars +{{first "['a', 'b', 'c', 'd', 'e']" 2}} + +``` + +## {{forEach}} + +Iterates over each item in an array and exposes the current item in the array as context to the inner block. In addition to the current array item, the helper exposes the following variables to the inner block: + +* `index` +* `total` +* `isFirst` +* `isLast` +Also, `@index` is exposed as a private variable, and additional +private variables may be defined as hash arguments. + +**Params** + +* `array` **{Array}** +* `returns` **{String}** + +**Example** + +```handlebars + + +{{#forEach accounts}} + + {{ name }} + {{#unless isLast}}, {{/unless}} +{{/forEach}} +``` + +## {{inArray}} + +Block helper that renders the block if an array has the given `value`. Optionally specify an inverse block to render when the array does not have the given value. + +**Params** + +* `array` **{Array}** +* `value` **{any}** +* `options` **{Object}** +* `returns` **{String}** + +**Example** + +```handlebars + +{{#inArray array "d"}} + foo +{{else}} + bar +{{/inArray}} + +``` + +## {{isArray}} + +Returns true if `value` is an es5 array. + +**Params** + +* `value` **{any}**: The value to test. +* `returns` **{Boolean}** + +**Example** + +```handlebars +{{isArray "abc"}} + + + +{{isArray array}} + +``` + +## {{itemAt}} + +Returns the item from `array` at index `idx`. + +**Params** + +* `array` **{Array}** +* `idx` **{Number}** +* `returns` **{any}** `value` + +**Example** + +```handlebars + +{{itemAt array 1}} + +``` + +## {{join}} + +Join all elements of array into a string, optionally using a given separator. + +**Params** + +* `array` **{Array}** +* `separator` **{String}**: The separator to use. Defaults to `,`. +* `returns` **{String}** + +**Example** + +```handlebars + +{{join array}} + + +{{join array '-'}} + +``` + +## {{equalsLength}} + +Returns true if the the length of the given `value` is equal +to the given `length`. Can be used as a block or inline helper. + +**Params** + +* `value` **{Array|String}** +* `length` **{Number}** +* `options` **{Object}** +* `returns` **{String}** + +## {{last}} + +Returns the last item, or last `n` items of an array or string. Opposite of [first](#first). + +**Params** + +* `value` **{Array|String}**: Array or string. +* `n` **{Number}**: Number of items to return from the end of the array. +* `returns` **{Array}** + +**Example** + +```handlebars + + +{{last value}} + + +{{last value 2}} + + +{{last value 3}} + +``` + +## {{length}} + +Returns the length of the given string or array. + +**Params** + +* `value` **{Array|Object|String}** +* `returns` **{Number}**: The length of the value. + +**Example** + +```handlebars +{{length '["a", "b", "c"]'}} + + + +{{length myArray}} + + + +{{length myObject}} + +``` + +## {{lengthEqual}} + +Alias for [equalsLength](#equalsLength) + +## {{map}} + +Returns a new array, created by calling `function` on each element of the given `array`. For example, + +**Params** + +* `array` **{Array}** +* `fn` **{Function}** +* `returns` **{String}** + +**Example** + +```handlebars + +{{map array double}} + +``` + +## {{pluck}} + +Map over the given object or array or objects and create an array of values from the given `prop`. Dot-notation may be used (as a string) to get nested properties. + +**Params** + +* `collection` **{Array|Object}** +* `prop` **{Function}** +* `returns` **{String}** + +**Example** + +```handlebars +// {{pluck items "data.title"}} + +``` + +## {{reverse}} + +Reverse the elements in an array, or the characters in a string. + +**Params** + +* `value` **{Array|String}** +* `returns` **{Array|String}**: Returns the reversed string or array. + +**Example** + +```handlebars + +{{reverse value}} + + +{{reverse value}} + +``` + +## {{some}} + +Block helper that returns the block if the callback returns true for some value in the given array. + +**Params** + +* `array` **{Array}** +* `iter` **{Function}**: Iteratee +* **{Options}**: Handlebars provided options object +* `returns` **{String}** + +**Example** + +```handlebars + +{{#some array isString}} + Render me if the array has a string. +{{else}} + Render me if it doesn't. +{{/some}} + +``` + +## {{sort}} + +Sort the given `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument. + +**Params** + +* `array` **{Array}**: the array to sort. +* `key` **{String|Function}**: The object key to sort by, or sorting function. + +**Example** + +```handlebars + +{{sort array}} + +``` + +## {{sortBy}} + +Sort an `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument. + +**Params** + +* `array` **{Array}**: the array to sort. +* `props` **{String|Function}**: One or more properties to sort by, or sorting functions to use. + +**Example** + +```handlebars + +{{sortBy array "a"}} + +``` + +## {{withAfter}} + +Use the items in the array _after_ the specified index as context inside a block. Opposite of [withBefore](#withBefore). + +**Params** + +* `array` **{Array}** +* `idx` **{Number}** +* `options` **{Object}** +* `returns` **{Array}** + +**Example** + +```handlebars + +{{#withAfter array 3}} + {{this}} +{{/withAfter}} + +``` + +## {{withBefore}} + +Use the items in the array _before_ the specified index as context inside a block. Opposite of [withAfter](#withAfter). + +**Params** + +* `array` **{Array}** +* `idx` **{Number}** +* `options` **{Object}** +* `returns` **{Array}** + +**Example** + +```handlebars + +{{#withBefore array 3}} + {{this}} +{{/withBefore}} + +``` + +## {{withFirst}} + +Use the first item in a collection inside a handlebars block expression. Opposite of [withLast](#withLast). + +**Params** + +* `array` **{Array}** +* `idx` **{Number}** +* `options` **{Object}** +* `returns` **{String}** + +**Example** + +```handlebars + +{{#withFirst array}} + {{this}} +{{/withFirst}} + +``` + +## {{withGroup}} + +Block helper that groups array elements by given group `size`. + +**Params** + +* `array` **{Array}**: The array to iterate over +* `size` **{Number}**: The desired length of each array "group" +* `options` **{Object}**: Handlebars options +* `returns` **{String}** + +**Example** + +```handlebars + +{{#withGroup array 4}} + {{#each this}} + {{.}} + {{each}} +
+{{/withGroup}} + + + +``` + +## {{withLast}} + +Use the last item or `n` items in an array as context inside a block. Opposite of [withFirst](#withFirst). + +**Params** + +* `array` **{Array}** +* `idx` **{Number}**: The starting index. +* `options` **{Object}** +* `returns` **{String}** + +**Example** + +```handlebars + +{{#withLast array}} + {{this}} +{{/withLast}} + +``` + +## {{withSort}} + +Block helper that sorts a collection and exposes the sorted collection as context inside the block. + +**Params** + +* `array` **{Array}** +* `prop` **{String}** +* `options` **{Object}**: Specify `reverse="true"` to reverse the array. +* `returns` **{String}** + +**Example** + +```handlebars + +{{#withSort array}}{{this}}{{/withSort}} + +``` + +## {{unique}} + +Block helper that return an array with all duplicate values removed. Best used along with a [each](#each) helper. + +**Params** + +* `array` **{Array}** +* `options` **{Object}** +* `returns` **{Array}** + +**Example** + +```handlebars + +{{#each (unique array)}}{{.}}{{/each}} + +``` diff --git a/docs/fr-FR/api/handlebars-helpers/comparison.md b/docs/fr-FR/api/handlebars-helpers/comparison.md new file mode 100644 index 000000000..a5c61f8eb --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/comparison.md @@ -0,0 +1,379 @@ +# Comparison + +## {{and}} + +Helper that renders the block if **both** of the given values are truthy. If an inverse block is specified it will be rendered when falsy. Works as a block helper, inline helper or subexpression. + +**Params** + +* `a` **{any}** +* `b` **{any}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}** + +**Example** + +```handlebars + +{{#and great magnificent}}A{{else}}B{{/and}} + +``` + +## {{compare}} + +Render a block when a comparison of the first and third +arguments returns true. The second argument is +the [arithemetic operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators) to use. You may also +optionally specify an inverse block to render when falsy. + +**Params** + +* `a` **{}** +* `operator` **{}**: The operator to use. Operators must be enclosed in quotes: `">"`, `"="`, `"<="`, and so on. +* `b` **{}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or if specified the inverse block is rendered if falsey. + +## {{contains}} + +Block helper that renders the block if `collection` has the given `value`, using strict equality (`===`) for comparison, otherwise the inverse block is rendered (if specified). If a `startIndex` is specified and is negative, it is used as the offset from the end of the collection. + +**Params** + +* `collection` **{Array|Object|String}**: The collection to iterate over. +* `value` **{any}**: The value to check for. +* `[startIndex=0]` **{Number}**: Optionally define the starting index. +* `options` **{Object}**: Handlebars provided options object. + +**Example** + +```handlebars + +{{#contains array "d"}} + This will not be rendered. +{{else}} + This will be rendered. +{{/contains}} +``` + +## {{default}} + +Returns the first value that is not undefined, otherwise the "default" value is returned. + +**Params** + +* `value` **{any}** +* `defaultValue` **{any}** +* `returns` **{String}** + +## {{eq}} + +Block helper that renders a block if `a` is **equal to** `b`. +If an inverse block is specified it will be rendered when falsy. +You may optionally use the `compare=""` hash argument for the +second value. + +**Params** + +* `a` **{String}** +* `b` **{String}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +## {{gt}} + +Block helper that renders a block if `a` is **greater than** `b`. + +If an inverse block is specified it will be rendered when falsy. +You may optionally use the `compare=""` hash argument for the +second value. + +**Params** + +* `a` **{String}** +* `b` **{String}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +## {{gte}} + +Block helper that renders a block if `a` is **greater than or equal to** `b`. + +If an inverse block is specified it will be rendered when falsy. +You may optionally use the `compare=""` hash argument for the +second value. + +**Params** + +* `a` **{String}** +* `b` **{String}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +## {{has}} + +Block helper that renders a block if `value` has `pattern`. +If an inverse block is specified it will be rendered when falsy. + +**Params** + +* `val` **{any}**: The value to check. +* `pattern` **{any}**: The pattern to check for. +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}** + +## {{isEmpty}} + +Inline, subexpression, or block helper that returns true (or the block) if the given collection is empty, or false (or the inverse block, if supplied) if the colleciton is not empty. + +**Params** + +* `collection` **{Object}** +* `options` **{Object}** +* `returns` **{String}** + +**Example** + +```handlebars + +{{#isEmpty array}}AAA{{else}}BBB{{/isEmpty}} + + + +{{isEmpty array}} + +``` + +## {{isFalsey}} + +Returns true if the given `value` is falsey. Uses the [falsey](https://github.com/jonschlinkert/falsey) +library for comparisons. Please see that library for more information +or to report bugs with this helper. + +**Params** + +* `val` **{any}** +* `options` **{Options}** +* `returns` **{Boolean}** + +## {{isTruthy}} + +Returns true if the given `value` is truthy. Uses the [falsey](https://github.com/jonschlinkert/falsey) +library for comparisons. Please see that library for more information +or to report bugs with this helper. + +**Params** + +* `val` **{any}** +* `options` **{Options}** +* `returns` **{Boolean}** + +## {{ifEven}} + +Return true if the given value is an even number. + +**Params** + +* `number` **{Number}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +**Example** + +```handlebars +{{#ifEven value}} + render A +{{else}} + render B +{{/ifEven}} +``` + +## {{ifNth}} + +Conditionally renders a block if the remainder is zero when +`a` operand is divided by `b`. If an inverse block is specified +it will be rendered when the remainder is **not zero**. + +**Params** + +* **{}**: {Number} +* **{}**: {Number} +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +## {{ifOdd}} + +Block helper that renders a block if `value` is **an odd number**. If an inverse block is specified it will be rendered when falsy. + +**Params** + +* `value` **{Object}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +**Example** + +```handlebars +{{#ifOdd value}} + render A +{{else}} + render B +{{/ifOdd}} +``` + +## {{is}} + +Block helper that renders a block if `a` is **equal to** `b`. +If an inverse block is specified it will be rendered when falsy. +Similar to [eq](#eq) but does not do strict equality. + +**Params** + +* `a` **{any}** +* `b` **{any}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}** + +## {{isnt}} + +Block helper that renders a block if `a` is **not equal to** `b`. +If an inverse block is specified it will be rendered when falsy. +Similar to [unlessEq](#unlesseq) but does not use strict equality for +comparisons. + +**Params** + +* `a` **{String}** +* `b` **{String}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}** + +## {{lt}} + +Block helper that renders a block if `a` is **less than** `b`. + +If an inverse block is specified it will be rendered when falsy. +You may optionally use the `compare=""` hash argument for the +second value. + +**Params** + +* `context` **{Object}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +## {{lte}} + +Block helper that renders a block if `a` is **less than or equal to** `b`. + +If an inverse block is specified it will be rendered when falsy. +You may optionally use the `compare=""` hash argument for the +second value. + +**Params** + +* `a` **{Sring}** +* `b` **{Sring}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +## {{neither}} + +Block helper that renders a block if **neither of** the given values +are truthy. If an inverse block is specified it will be rendered +when falsy. + +**Params** + +* `a` **{any}** +* `b` **{any}** +* `options` **{}**: Handlebars options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +## {{not}} + +Returns true if `val` is falsey. Works as a block or inline helper. + +**Params** + +* `val` **{String}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}** + +## {{or}} + +Block helper that renders a block if **any of** the given values is truthy. If an inverse block is specified it will be rendered when falsy. + +**Params** + +* `arguments` **{...any}**: Variable number of arguments +* `options` **{Object}**: Handlebars options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +**Example** + +```handlebars +{{#or a b c}} + If any value is true this will be rendered. +{{/or}} +``` + +## {{unlessEq}} + +Block helper that always renders the inverse block **unless `a` is +is equal to `b`**. + +**Params** + +* `a` **{String}** +* `b` **{String}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Inverse block by default, or block if falsey. + +## {{unlessGt}} + +Block helper that always renders the inverse block **unless `a` is +is greater than `b`**. + +**Params** + +* `a` **{Object}**: The default value +* `b` **{Object}**: The value to compare +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Inverse block by default, or block if falsey. + +## {{unlessLt}} + +Block helper that always renders the inverse block **unless `a` is +is less than `b`**. + +**Params** + +* `a` **{Object}**: The default value +* `b` **{Object}**: The value to compare +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +## {{unlessGteq}} + +Block helper that always renders the inverse block **unless `a` is +is greater than or equal to `b`**. + +**Params** + +* `a` **{any}** +* `b` **{any}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. + +## {{unlessLteq}} + +Block helper that always renders the inverse block **unless `a` is +is less than or equal to `b`**. + +**Params** + +* `a` **{any}** +* `b` **{any}** +* `options` **{Object}**: Handlebars provided options object +* `returns` **{String}**: Block, or inverse block if specified and falsey. diff --git a/docs/fr-FR/api/handlebars-helpers/core.md b/docs/fr-FR/api/handlebars-helpers/core.md new file mode 100644 index 000000000..2f82a7c94 --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/core.md @@ -0,0 +1,96 @@ +# Built-in Helpers + +https://handlebarsjs.com/guide/builtin-helpers.html + +## {{if}} + +Renders a block if the given condition is truthy. + +**Params** + +- `condition` **{Any}**: The condition to evaluate. + +**Returns**: The content inside the block if the condition is truthy, otherwise returns nothing. + +**Example** + +```handlebars +{{#if condition}} + This will be displayed if the condition is true. +{{/if}} +``` + +## {{unless}} + +Renders a block if the given condition is falsy. This is the opposite of `if`. + +**Params** + +- `condition` **{Any}**: The condition to evaluate. + +**Returns**: The content inside the block if the condition is falsy, otherwise returns nothing. + +**Example** + +```handlebars +{{#unless condition}} + This will be displayed if the condition is false. +{{/unless}} +``` + +--- + +## {{each}} + +Iterates over an array or object and renders a block for each item. + +**Params** + +- `collection` **{Array|Object}**: The array or object to iterate over. + +**Returns**: Renders the block for each item in the collection. + +**Example** + +```handlebars +{{#each items}} +
  • {{this}}
  • +{{/each}} +``` + +## {{with}} + +Renders a block with a given context. It allows you to specify a context for the block, simplifying access to deeply nested properties. + +**Params** + +- `context` **{Any}**: The context to use within the block. + +**Returns**: Renders the block with the provided context. + +**Example** + +```handlebars +{{#with person}} +

    Name: {{name}}

    +

    Age: {{age}}

    +{{/with}} +``` + +## {{lookup}} + +Looks up the value of a specified key in an object. This helper is useful for accessing dynamic keys. + +**Params** + +- `context` **{Object}**: The object to look up the key from. +- `key` **{String|Number}**: The key to look up. + +**Returns**: The value of the specified key in the object. + +**Example** + +```handlebars +{{lookup person "name"}} + +``` diff --git a/docs/fr-FR/api/handlebars-helpers/date.md b/docs/fr-FR/api/handlebars-helpers/date.md new file mode 100644 index 000000000..11d00eacb --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/date.md @@ -0,0 +1,20 @@ +# Date + +## {{dateFormat}} + +The "dateFormat" helper in Handlebars is used to format a date using the day.js library. It takes two required arguments and an optional third argument for the timezone. + +**Params** + +* `datetime` **{String}** +* `format` **{String}** +* `timezone` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{dateFormat now "YYYY-MM-DD HH:mm:ss"}} +{{dateFormat now "YYYY-MM-DD HH:mm:ss" "Asia/Tokyo"}} +{{dateFormat now "YYYY-MM-DD HH:mm:ss" "UTC"}} +``` diff --git a/docs/fr-FR/api/handlebars-helpers/html.md b/docs/fr-FR/api/handlebars-helpers/html.md new file mode 100644 index 000000000..221c13438 --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/html.md @@ -0,0 +1,4 @@ +# HTML + +## {{qrcode}} + diff --git a/docs/fr-FR/api/handlebars-helpers/i18n.md b/docs/fr-FR/api/handlebars-helpers/i18n.md new file mode 100644 index 000000000..def146bbc --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/i18n.md @@ -0,0 +1,16 @@ +# I18n + +## {{t}} + +**Params** + +* `key` **{String}** +* `ns` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{t "Today"}} +{{t "Permissions" "@nocobase/plugin-acl"}} +``` diff --git a/docs/fr-FR/api/handlebars-helpers/index.md b/docs/fr-FR/api/handlebars-helpers/index.md new file mode 100644 index 000000000..2c1f165c8 --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/index.md @@ -0,0 +1,17 @@ +# Handlebars Helpers + +| Category | Description | +|-------------|-------------------------------------| +| [Core](./core.md) | Built-in helpers | +| [Array](./array.md) | Operations and methods related to arrays | +| [Comparison](./comparison.md) | Comparison operators and related methods | +| [Date](./date.md) | Operations and methods related to date and time handling | +| [HTML](./html.md) | Content related to HTML documents and elements | +| [I18n](./i18n.md) | Support for internationalization and multilingual handling | +| [Math](./math.md) | Mathematical functions and calculations | +| [Number](./number.md) | Content related to number handling and formatting | +| [Object](./object.md) | Methods related to object operations and properties | +| [Path](./path.md) | Path operations and content related to the file system | +| [Regex](./regex.md) | Regular expressions and their usage | +| [String](./string.md) | Methods related to string manipulation and operations | +| [URL](./url.md) | Content related to URL parsing and construction | diff --git a/docs/fr-FR/api/handlebars-helpers/math.md b/docs/fr-FR/api/handlebars-helpers/math.md new file mode 100644 index 000000000..7bfd21d03 --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/math.md @@ -0,0 +1,166 @@ + +# Math + +## {{abs}} + +Return the magnitude of `a`. + +**Params** + +* `a` **{Number}** +* `returns` **{Number}** + +## {{add}} + +Return the sum of `a` plus `b`. + +**Params** + +* `a` **{Number}** +* `b` **{Number}** +* `returns` **{Number}** + +## {{avg}} + +Returns the average of all numbers in the given array. + +**Params** + +* `array` **{Array}**: Array of numbers to add up. +* `returns` **{Number}** + +**Example** + +```handlebars +{{avg "[1, 2, 3, 4, 5]"}} + +``` + +## {{ceil}} + +Get the `Math.ceil()` of the given value. + +**Params** + +* `value` **{Number}** +* `returns` **{Number}** + +## {{divide}} + +Divide `a` by `b` + +**Params** + +* `a` **{Number}**: numerator +* `b` **{Number}**: denominator + +## {{floor}} + +Get the `Math.floor()` of the given value. + +**Params** + +* `value` **{Number}** +* `returns` **{Number}** + +## {{minus}} + +Return the difference of `a` minus `b`. + +**Params** + +* `a` **{Number}** +* `b` **{Number}** + +## {{modulo}} + +Get the remainder of a division operation. + +**Params** + +* `a` **{Number}** +* `b` **{Number}** +* `returns` **{Number}** + +## {{multiply}} + +Return the product of `a` times `b`. + +**Params** + +* `a` **{Number}**: factor +* `b` **{Number}**: multiplier +* `returns` **{Number}** + +## {{plus}} + +Add `a` by `b`. + +**Params** + +* `a` **{Number}**: factor +* `b` **{Number}**: multiplier + +## {{random}} + +Generate a random number between two values + +**Params** + +* `min` **{Number}** +* `max` **{Number}** +* `returns` **{String}** + +## {{remainder}} + +Get the remainder when `a` is divided by `b`. + +**Params** + +* `a` **{Number}**: a +* `b` **{Number}**: b + +## {{round}} + +Round the given number. + +**Params** + +* `number` **{Number}** +* `returns` **{Number}** + +## {{subtract}} + +Return the product of `a` minus `b`. + +**Params** + +* `a` **{Number}** +* `b` **{Number}** +* `returns` **{Number}** + +## {{sum}} + +Returns the sum of all numbers in the given array. + +**Params** + +* `array` **{Array}**: Array of numbers to add up. +* `returns` **{Number}** + +**Example** + +```handlebars +{{sum "[1, 2, 3, 4, 5]"}} + +``` + +## {{times}} + +Multiply number `a` by number `b`. + +**Params** + +* `a` **{Number}**: factor +* `b` **{Number}**: multiplier +* `returns` **{Number}** diff --git a/docs/fr-FR/api/handlebars-helpers/number.md b/docs/fr-FR/api/handlebars-helpers/number.md new file mode 100644 index 000000000..7cd4f08c9 --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/number.md @@ -0,0 +1,111 @@ + +# Number + +## {{bytes}} + +Format a number to it's equivalent in bytes. If a string is passed, it's length will be formatted and returned. + +**Examples:** + +* `'foo' => 3 B` +* `13661855 => 13.66 MB` +* `825399 => 825.39 kB` +* `1396 => 1.4 kB` + +**Params** + +* `number` **{Number|String}** +* `returns` **{String}** + +## {{addCommas}} + +Add commas to numbers + +**Params** + +* `num` **{Number}** +* `returns` **{Number}** + +## {{phoneNumber}} + +Convert a string or number to a formatted phone number. + +**Params** + +* `num` **{Number|String}**: The phone number to format, e.g. `8005551212` +* `returns` **{Number}**: Formatted phone number: `(800) 555-1212` + +## {{toAbbr}} + +Abbreviate numbers to the given number of `precision`. This is for +general numbers, not size in bytes. + +**Params** + +* `number` **{Number}** +* `precision` **{Number}** +* `returns` **{String}** + +## {{toExponential}} + +Returns a string representing the given number in exponential notation. + +**Params** + +* `number` **{Number}** +* `fractionDigits` **{Number}**: Optional. An integer specifying the number of digits to use after the decimal point. Defaults to as many digits as necessary to specify the number. +* `returns` **{Number}** + +**Example** + +```handlebars +{{toExponential number digits}}; +``` + +## {{toFixed}} + +Formats the given number using fixed-point notation. + +**Params** + +* `number` **{Number}** +* `digits` **{Number}**: (Optional) The number of digits to appear after the decimal point; this may be a value between 0 and 20. If this argument is omitted, it is treated as 0. +* `returns` **{String}**: A string representing the given number using fixed-point notation. + +**Example** + +```handlebars +{{toFixed "1.1234" 2}} +//=> '1.12' +``` + +## {{toFloat}} + +**Params** + +* `number` **{Number}** +* `returns` **{Number}** + +## {{toInt}} + +**Params** + +* `number` **{Number}** +* `returns` **{Number}** + +## {{toPrecision}} + +Returns a string representing the `Number` object to the specified precision. + +**Params** + +* `number` **{Number}** +* `precision` **{Number}**: (Optional) An integer specifying the number of significant digits. If precison is not between 1 and 100 (inclusive), it will be coerced to `0`. +* `returns` **{String}**: A string representing a Number object in fixed-point or exponential notation rounded to precision significant digits. + +**Example** + +```handlebars +{{toPrecision "1.1234" 2}} +//=> '1.1' +``` diff --git a/docs/fr-FR/api/handlebars-helpers/object.md b/docs/fr-FR/api/handlebars-helpers/object.md new file mode 100644 index 000000000..fa11031b1 --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/object.md @@ -0,0 +1,155 @@ +# Object + +## {{extend}} + +Extend the context with the properties of other objects. +A shallow merge is performed to avoid mutating the context. + +**Params** + +* `objects` **{Object}**: One or more objects to extend. +* `returns` **{Object}** + +## {{forIn}} + +Block helper that iterates over the properties of +an object, exposing each key and value on the context. + +**Params** + +* `context` **{Object}** +* `options` **{Object}** +* `returns` **{String}** + +## {{forOwn}} + +Block helper that iterates over the **own** properties of +an object, exposing each key and value on the context. + +**Params** + +* `obj` **{Object}**: The object to iterate over. +* `options` **{Object}** +* `returns` **{String}** + +## {{toPath}} + +Take arguments and, if they are string or number, convert them to a dot-delineated object property path. + +**Params** + +* `prop` **{String|Number}**: The property segments to assemble (can be multiple). +* `returns` **{String}** + +## {{get}} + +Use property paths (`a.b.c`) to get a value or nested value from +the context. Works as a regular helper or block helper. + +**Params** + +* `prop` **{String}**: The property to get, optionally using dot notation for nested properties. +* `context` **{Object}**: The context object +* `options` **{Object}**: The handlebars options object, if used as a block helper. +* `returns` **{String}** + +## {{getObject}} + +Use property paths (`a.b.c`) to get an object from +the context. Differs from the `get` helper in that this +helper will return the actual object, including the +given property key. Also, this helper does not work as a +block helper. + +**Params** + +* `prop` **{String}**: The property to get, optionally using dot notation for nested properties. +* `context` **{Object}**: The context object +* `returns` **{String}** + +## {{hasOwn}} + +Return true if `key` is an own, enumerable property of the given `context` object. + +**Params** + +* `key` **{String}** +* `context` **{Object}**: The context object. +* `returns` **{Boolean}** + +**Example** + +```handlebars +{{hasOwn context key}} +``` + +## {{isObject}} + +Return true if `value` is an object. + +**Params** + +* `value` **{String}** +* `returns` **{Boolean}** + +**Example** + +```handlebars +{{isObject "foo"}} +//=> false +``` + +## {{JSONparse}} + +Parses the given string using `JSON.parse`. + +**Params** + +* `string` **{String}**: The string to parse + +**Example** + +```handlebars + +{{JSONparse string}} + +``` + +## {{JSONstringify}} + +Stringify an object using `JSON.stringify`. + +**Params** + +* `obj` **{Object}**: Object to stringify +* `returns` **{String}** + +**Example** + +```handlebars + +{{JSONstringify object}} + +``` + +## {{merge}} + +Deeply merge the properties of the given `objects` with the +context object. + +**Params** + +* `object` **{Object}**: The target object. Pass an empty object to shallow clone. +* `objects` **{Object}** +* `returns` **{Object}** + +## {{pick}} + +Pick properties from the context object. + +**Params** + +* `properties` **{Array|String}**: One or more properties to pick. +* `context` **{Object}** +* `options` **{Object}**: Handlebars options object. +* `returns` **{Object}**: Returns an object with the picked values. If used as a block helper, the values are passed as context to the inner block. If no values are found, the context is passed to the inverse block. diff --git a/docs/fr-FR/api/handlebars-helpers/path.md b/docs/fr-FR/api/handlebars-helpers/path.md new file mode 100644 index 000000000..eb086adfd --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/path.md @@ -0,0 +1,136 @@ + +# Path + +## {{absolute}} + +Get the directory path segment from the given `filepath`. + +**Params** + +* `ext` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{absolute "docs/toc.md"}} + +``` + +## {{dirname}} + +Get the directory path segment from the given `filepath`. + +**Params** + +* `ext` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{dirname "docs/toc.md"}} + +``` + +## {{relative}} + +Get the relative filepath from `a` to `b`. + +**Params** + +* `a` **{String}** +* `b` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{relative a b}} +``` + +## {{basename}} + +Get the file extension from the given `filepath`. + +**Params** + +* `ext` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{basename "docs/toc.md"}} + +``` + +## {{stem}} + +Get the "stem" from the given `filepath`. + +**Params** + +* `filepath` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{stem "docs/toc.md"}} + +``` + +## {{extname}} + +Get the file extension from the given `filepath`. + +**Params** + +* `filepath` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{extname "docs/toc.md"}} + +``` + +## {{resolve}} + +Resolve an absolute path from the given `filepath`. + +**Params** + +* `filepath` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{resolve "docs/toc.md"}} + +``` + +## {{segments}} + +Get specific (joined) segments of a file path by passing a range of array indices. + +**Params** + +* `filepath` **{String}**: The file path to split into segments. +* `returns` **{String}**: Returns a single, joined file path. + +**Example** + +```handlebars +{{segments "a/b/c/d" "2" "3"}} + + +{{segments "a/b/c/d" "1" "3"}} + + +{{segments "a/b/c/d" "1" "2"}} + +``` diff --git a/docs/fr-FR/api/handlebars-helpers/regex.md b/docs/fr-FR/api/handlebars-helpers/regex.md new file mode 100644 index 000000000..3f7aa8dcc --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/regex.md @@ -0,0 +1,38 @@ + +# Regex + +## {{toRegex}} + +Convert the given string to a regular expression. + +**Params** + +* `str` **{String}** +* `returns` **{RegExp}** + +**Example** + +```handlebars +{{toRegex "foo"}} + +``` + +## {{test}} + +Returns true if the given `str` matches the given regex. A regex can be passed on the context, or using the [toRegex](#toregex) helper as a subexpression. + +**Params** + +* `str` **{String}** +* `returns` **{RegExp}** + +**Example** + +```handlebars +{{test "bar" (toRegex "foo")}} + +{{test "foobar" (toRegex "foo")}} + +{{test "foobar" (toRegex "^foo$")}} + +``` diff --git a/docs/fr-FR/api/handlebars-helpers/string.md b/docs/fr-FR/api/handlebars-helpers/string.md new file mode 100644 index 000000000..5adc2b755 --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/string.md @@ -0,0 +1,610 @@ + +# String + +## {{append}} + +Append the specified `suffix` to the given string. + +**Params** + +* `str` **{String}** +* `suffix` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars + +{{append item.stem ".html"}} + +``` + +## {{camelcase}} + +camelCase the characters in the given `string`. + +**Params** + +* `string` **{String}**: The string to camelcase. +* `returns` **{String}** + +**Example** + +```handlebars +{{camelcase "foo bar baz"}}; + +``` + +## {{capitalize}} + +Capitalize the first word in a sentence. + +**Params** + +* `str` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{capitalize "foo bar baz"}} + +``` + +## {{capitalizeAll}} + +Capitalize all words in a string. + +**Params** + +* `str` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{capitalizeAll "foo bar baz"}} + +``` + +## {{center}} + +Center a string using non-breaking spaces + +**Params** + +* `str` **{String}** +* `spaces` **{String}** +* `returns` **{String}** + +## {{chop}} + +Like trim, but removes both extraneous whitespace **and non-word characters** from the beginning and end of a string. + +**Params** + +* `string` **{String}**: The string to chop. +* `returns` **{String}** + +**Example** + +```handlebars +{{chop "_ABC_"}} + + +{{chop "-ABC-"}} + + +{{chop " ABC "}} + +``` + +## {{dashcase}} + +dash-case the characters in `string`. Replaces non-word characters and periods with hyphens. + +**Params** + +* `string` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{dashcase "a-b-c d_e"}} + +``` + +## {{dotcase}} + +dot.case the characters in `string`. + +**Params** + +* `string` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{dotcase "a-b-c d_e"}} + +``` + +## {{downcase}} + +Lowercase all of the characters in the given string. Alias for [lowercase](#lowercase). + +**Params** + +* `string` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{downcase "aBcDeF"}} + +``` + +## {{ellipsis}} + +Truncates a string to the specified `length`, and appends it with an elipsis, `…`. + +**Params** + +* `str` **{String}** +* `length` **{Number}**: The desired length of the returned string. +* `returns` **{String}**: The truncated string. + +**Example** + +```handlebars +{{ellipsis (sanitize "foo bar baz"), 7}} + +{{ellipsis "foo bar baz", 7}} + +``` + +## {{hyphenate}} + +Replace spaces in a string with hyphens. + +**Params** + +* `str` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{hyphenate "foo bar baz qux"}} + +``` + +## {{isString}} + +Return true if `value` is a string. + +**Params** + +* `value` **{String}** +* `returns` **{Boolean}** + +**Example** + +```handlebars +{{isString "foo"}} + +``` + +## {{lowercase}} + +Lowercase all characters in the given string. + +**Params** + +* `str` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{lowercase "Foo BAR baZ"}} + +``` + +## {{occurrences}} + +Return the number of occurrences of `substring` within the given `string`. + +**Params** + +* `str` **{String}** +* `substring` **{String}** +* `returns` **{Number}**: Number of occurrences + +**Example** + +```handlebars +{{occurrences "foo bar foo bar baz" "foo"}} + +``` + +## {{pascalcase}} + +PascalCase the characters in `string`. + +**Params** + +* `string` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{pascalcase "foo bar baz"}} + +``` + +## {{pathcase}} + +path/case the characters in `string`. + +**Params** + +* `string` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{pathcase "a-b-c d_e"}} + +``` + +## {{plusify}} + +Replace spaces in the given string with pluses. + +**Params** + +* `str` **{String}**: The input string +* `returns` **{String}**: Input string with spaces replaced by plus signs + +**Example** + +```handlebars +{{plusify "foo bar baz"}} + +``` + +## {{prepend}} + +Prepends the given `string` with the specified `prefix`. + +**Params** + +* `str` **{String}** +* `prefix` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars + +{{prepend val "foo-"}} + +``` + +## {{raw}} + +Render a block without processing mustache templates inside the block. + +**Params** + +* `options` **{Object}** +* `returns` **{String}** + +**Example** + +```handlebars +{{{{#raw}}}} +{{foo}} +{{{{/raw}}}} + +``` + +## {{remove}} + +Remove all occurrences of `substring` from the given `str`. + +**Params** + +* `str` **{String}** +* `substring` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{remove "a b a b a b" "a "}} + +``` + +## {{removeFirst}} + +Remove the first occurrence of `substring` from the given `str`. + +**Params** + +* `str` **{String}** +* `substring` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{remove "a b a b a b" "a"}} + +``` + +## {{replace}} + +Replace all occurrences of substring `a` with substring `b`. + +**Params** + +* `str` **{String}** +* `a` **{String}** +* `b` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{replace "a b a b a b" "a" "z"}} + +``` + +## {{replaceFirst}} + +Replace the first occurrence of substring `a` with substring `b`. + +**Params** + +* `str` **{String}** +* `a` **{String}** +* `b` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{replace "a b a b a b" "a" "z"}} + +``` + +## {{reverse}} + +Reverse a string. + +**Params** + +* `str` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{reverse "abcde"}} + +``` + +## {{sentence}} + +Sentence case the given string + +**Params** + +* `str` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{sentence "hello world. goodbye world."}} + +``` + +## {{snakecase}} + +snake_case the characters in the given `string`. + +**Params** + +* `string` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{snakecase "a-b-c d_e"}} + +``` + +## {{split}} + +Split `string` by the given `character`. + +**Params** + +* `string` **{String}**: The string to split. +* `returns` **{String}** `character`: Default is an empty string. + +**Example** + +```handlebars +{{split "a,b,c" ","}} + +``` + +## {{startsWith}} + +Tests whether a string begins with the given prefix. + +**Params** + +* `prefix` **{String}** +* `testString` **{String}** +* `options` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{#startsWith "Goodbye" "Hello, world!"}} + Whoops +{{else}} + Bro, do you even hello world? +{{/startsWith}} +``` + +## {{titleize}} + +Title case the given string. + +**Params** + +* `str` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{titleize "this is title case"}} + +``` + +## {{trim}} + +Removes extraneous whitespace from the beginning and end of a string. + +**Params** + +* `string` **{String}**: The string to trim. +* `returns` **{String}** + +**Example** + +```handlebars +{{trim " ABC "}} + +``` + +## {{trimLeft}} + +Removes extraneous whitespace from the beginning of a string. + +**Params** + +* `string` **{String}**: The string to trim. +* `returns` **{String}** + +**Example** + +```handlebars +{{trim " ABC "}} + +``` + +## {{trimRight}} + +Removes extraneous whitespace from the end of a string. + +**Params** + +* `string` **{String}**: The string to trim. +* `returns` **{String}** + +**Example** + +```handlebars +{{trimRight " ABC "}} + +``` + +## {{truncate}} + +Truncate a string to the specified `length`. Also see [ellipsis](#ellipsis). + +**Params** + +* `str` **{String}** +* `limit` **{Number}**: The desired length of the returned string. +* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated. Otherwise an ellipsis (`…`) will be used. +* `returns` **{String}**: The truncated string. + +**Example** + +```handlebars +truncate("foo bar baz", 7); + +truncate(sanitize("foo bar baz", 7)); + +``` + +## {{truncateWords}} + +Truncate a string to have the specified number of words. Also see [truncate](#truncate). + +**Params** + +* `str` **{String}** +* `limit` **{Number}**: The desired length of the returned string. +* `suffix` **{String}**: Optionally supply a string to use as a suffix to denote when the string has been truncated. +* `returns` **{String}**: The truncated string. + +**Example** + +```handlebars +truncateWords("foo bar baz", 1); + +truncateWords("foo bar baz", 2); + +truncateWords("foo bar baz", 3); + +``` + +## {{upcase}} + +Uppercase all of the characters in the given string. Alias for [uppercase](#uppercase). + +**Params** + +* `string` **{String}** +* `returns` **{String}** + +**Example** + +```handlebars +{{upcase "aBcDeF"}} + +``` + +## {{uppercase}} + +Uppercase all of the characters in the given string. If used as a block helper it will uppercase the entire block. This helper does not support inverse blocks. + +**Params** + +* `str` **{String}**: The string to uppercase +* `options` **{Object}**: Handlebars options object +* `returns` **{String}** + +**Example** + +```handlebars +{{uppercase "aBcDeF"}} + +``` diff --git a/docs/fr-FR/api/handlebars-helpers/url.md b/docs/fr-FR/api/handlebars-helpers/url.md new file mode 100644 index 000000000..6a6b1ac92 --- /dev/null +++ b/docs/fr-FR/api/handlebars-helpers/url.md @@ -0,0 +1,87 @@ + +# URL + +## {{encodeURI}} + +Encodes a Uniform Resource Identifier (URI) component +by replacing each instance of certain characters by +one, two, three, or four escape sequences representing +the UTF-8 encoding of the character. + +**Params** + +* `str` **{String}**: The un-encoded string +* `returns` **{String}**: The endcoded string + +## {{escape}} + +Escape the given string by replacing characters with escape sequences. +Useful for allowing the string to be used in a URL, etc. + +**Params** + +* `str` **{String}** +* `returns` **{String}**: Escaped string. + +## {{decodeURI}} + +Decode a Uniform Resource Identifier (URI) component. + +**Params** + +* `str` **{String}** +* `returns` **{String}** + +## {{url_encode}} + +Alias for [encodeURI](#encodeuri). + +## {{url_decode}} + +Alias for [decodeURI](#decodeuri). + +## {{urlResolve}} + +Take a base URL, and a href URL, and resolve them as a +browser would for an anchor tag. + +**Params** + +* `base` **{String}** +* `href` **{String}** +* `returns` **{String}** + +## {{urlParse}} + +Parses a `url` string into an object. + +**Params** + +* `str` **{String}**: URL string +* `returns` **{String}**: Returns stringified JSON + +## {{stripQuerystring}} + +Strip the query string from the given `url`. + +**Params** + +* `url` **{String}** +* `returns` **{String}**: the url without the queryString + +## {{stripProtocol}} + +Strip protocol from a `url`. Useful for displaying media that may have an 'http' protocol on secure connections. + +**Params** + +* `str` **{String}** +* `returns` **{String}**: the url with http protocol stripped + +**Example** + +```handlebars + +{{stripProtocol url}} + +``` diff --git a/docs/fr-FR/api/http/index.md b/docs/fr-FR/api/http/index.md new file mode 100644 index 000000000..6eddfdd12 --- /dev/null +++ b/docs/fr-FR/api/http/index.md @@ -0,0 +1,301 @@ +# Overview + +HTTP API of NocoBase is designed based on Resource & Action, a superset of REST API. The operation includes but not limited to create, read, update and delete. Resource Action can be extended arbitrarily in NocoBase. + +## Resource + +In NocoBase, resource has two expressions: + +- `` +- `.` + + + +- Collection is the set of all abstract data +- Association is the associated data of collection +- Resource includes both collection and collection.association + + + +### Example + +- `posts` Post +- `posts.user` Post user +- `posts.tags` Post tags + +## Action + +Action on resource is expressed by `:` + +- `:` +- `.:` + +Built-in global actions for collection or association: + +- `create` +- `get` +- `list` +- `update` +- `destroy` +- `move` + +Built-in association actions for association only: + +- `set` +- `add` +- `remove` +- `toggle` + +### Example + +- `posts:create` Create post +- `posts.user:get` Get post user +- `posts.tags:add` Add tags to post (associate existing tags with post) + +## Request URL + +```bash + /api/: + /api/:/ + /api///: + /api///:/ +``` + +### Example + +posts resource + +```bash +POST /api/posts:create +GET /api/posts:list +GET /api/posts:get/1 +POST /api/posts:update/1 +POST /api/posts:destroy/1 +``` + +posts.comments resource + +```bash +POST /api/posts/1/comments:create +GET /api/posts/1/comments:list +GET /api/posts/1/comments:get/1 +POST /api/posts/1/comments:update/1 +POST /api/posts/1/comments:destroy/1 +``` + +posts.tags resource + +```bash +POST /api/posts/1/tags:create +GET /api/posts/1/tags:get +GET /api/posts/1/tags:list +POST /api/posts/1/tags:update +POST /api/posts/1/tags:destroy +POST /api/posts/1/tags:add +GET /api/posts/1/tags:remove +``` + +## Locate Resource + +- Collection resource locates the data to be processed by `collectionIndex`, `collectionIndex` must be unique. +- Association resource locates the data to be processed by `collectionIndex` and `associationIndex` jointly, `associationIndex` may not be unique, but the joint index of `collectionIndex` and `associationIndex` must be unique. + +When viewing details of association resource, the requested URL needs to provide both `` and ``, `` is necessary as `` may not be unique. + +For example, `tables.fields` represents the fields of a data table: + +```bash +GET /api/tables/table1/fields/title +GET /api/tables/table2/fields/title +``` + +Both table1 and table2 have the title field, title is unique in one table, but other tables may also have fields of that name. + +## Request Parameters + +Request parameters can be placed in the headers, parameters (query string), and body (GET requests do not have a body) of the request. + +Some special request parameters: + +- `filter` Data filtering, used in actions related to query. +- `filterByTk` Filter by tk field, used in actions to specify details of data. +- `sort` Sorting, used in actions related to query. +- `fields` Date to output, used in actions related to query +- `appends` Fields of additional relationship, used in actions related to query. +- `except` Exclude some fields (not to output), used in actions related to query. +- `whitelist` Fields whitelist, used in actions related to data creation and update. +- `blacklist` Fields blacklist, used in actions related to data creation and update. + +### filter + +Data filtering. + +```bash +# simple +GET /api/posts?filter[status]=publish +# json string format is recommended, which requires encodeURIComponent encoding +GET /api/posts?filter={"status":"published"} + +# filter operators +GET /api/posts?filter[status.$eq]=publish +GET /api/posts?filter={"status.$eq":"published"} + +# $and +GET /api/posts?filter={"$and": [{"status.$eq":"published"}, {"title.$includes":"a"}]} +# $or +GET /api/posts?filter={"$or": [{"status.$eq":"pending"}, {"status.$eq":"draft"}]} + +# association field +GET /api/posts?filter[user.email.$includes]=gmail +GET /api/posts?filter={"user.email.$includes":"gmail"} +``` + +[Click here for more information about filter operators](http-api/filter-operators) + +### filterByTk + +Filter by tk field. In the default settings: + +- collection resource: tk is the primary key of the data table. +- association resource: tk is the targetKey field of the association. + +```bash +GET /api/posts:get?filterByTk=1&fields=name,title&appends=tags +``` + +### sort + +Sorting. To sort in the descending order, put `-` in front of the field. + +```bash +# Sort createAt field in the ascending order +GET /api/posts:get?sort=createdAt +# Sort createAt field in the descending order +GET /api/posts:get?sort=-createdAt +# Sort multiple fields jointly, createAt field descending, title A-Z ascending +GET /api/posts:get?sort=-createdAt,title +``` + +### fields + +Data to output. + +```bash +GET /api/posts:list?fields=name,title + +Response 200 (application/json) +{ + "data": [ + { + "name": "", + "title": "" + } + ], + "meta": {} +} +``` + +### appends + +Fields of additional relationship. + +### except + +Exclude some fields (not to output), used in actions related to query. + +### whitelist + +Whitelist. + +```bash +POST /api/posts:create?whitelist=title + +{ + "title": "My first post", + "date": "2022-05-19" # The date field will be filtered out and not be written to the database +} +``` + +### blacklist + +Blacklist. + +```bash +POST /api/posts:create?blacklist=date + +# The date field will be filtered out and not be written to the database +{ + "title": "My first post" +} +``` + +## Request Response + +Format of the response: + +```ts +type ResponseResult = { + data?: any; // Main data + meta?: any; // Additional Data + errors?: ResponseError[]; // Errors +}; + +type ResponseError = { + code?: string; + message: string; +}; +``` + +### Example + +View list: + +```bash +GET /api/posts:list + +Response 200 (application/json) + +{ + data: [ + { + id: 1 + } + ], + meta: { + count: 1 + page: 1, + pageSize: 1, + totalPage: 1 + }, +} +``` + +View details: + +```bash +GET /api/posts:get/1 + +Response 200 (application/json) + +{ + data: { + id: 1 + } +} +``` + +Error: + +```bash +POST /api/posts:create + +Response 400 (application/json) + +{ + errors: [ + { + message: 'name must be required', + }, + ], +} +``` diff --git a/docs/fr-FR/api/http/rest-api.md b/docs/fr-FR/api/http/rest-api.md new file mode 100644 index 000000000..cfe2a46d5 --- /dev/null +++ b/docs/fr-FR/api/http/rest-api.md @@ -0,0 +1,180 @@ +# REST API + +HTTP API of NocoBase is a superset of REST API, and the standard CRUD API also supports the RESTful style. + +## Collection Resources + +### Create Collection + +HTTP API + +```bash +POST /api/:create + +{} # JSON body +``` + +REST API + +```bash +POST /api/ + +{} # JSON body +``` + +### View Collection List + +HTTP API + +```bash +GET /api/:list +``` + +REST API + +```bash +GET /api/ +``` + +### View Collection Details + +HTTP API + +```bash +GET /api/:get?filterByTk= +GET /api/:get/ +``` + +REST API + +```bash +GET /api// +``` + +### Update Collection + +HTTP API + +```bash +POST /api/:update?filterByTk= + +{} # JSON body + +# Or +POST /api/:update/ + +{} # JSON body +``` + +REST API + +```bash +PUT /api// + +{} # JSON body +``` + +### Delete Collection + +HTTP API + +```bash +POST /api/:destroy?filterByTk= +# Or +POST /api/:destroy/ +``` + +REST API + +```bash +DELETE /api// +``` + +## Association Resources + +### Create Association + +HTTP API + +```bash +POST /api///:create + +{} # JSON body +``` + +REST API + +```bash +POST /api/// + +{} # JSON body +``` + +### View Association List + +HTTP API + +```bash +GET /api///:list +``` + +REST API + +```bash +GET /api/// +``` + +### View Association Details + +HTTP API + +```bash +GET /api///:get?filterByTk= +# Or +GET /api///:get/ +``` + +REST API + +```bash +GET /api///:get/ +``` + +### Update Association + +HTTP API + +```bash +POST /api///:update?filterByTk= + +{} # JSON body + +# Or +POST /api///:update/ + +{} # JSON body +``` + +REST API + +```bash +PUT /api///:update/ + +{} # JSON +``` + +### Delete Association + +HTTP API + +```bash +POST /api///:destroy?filterByTk= +# Or +POST /api///:destroy/ +``` + +REST API + +```bash +DELETE /api//// +``` diff --git a/docs/fr-FR/api/index.md b/docs/fr-FR/api/index.md new file mode 100644 index 000000000..b6539a798 --- /dev/null +++ b/docs/fr-FR/api/index.md @@ -0,0 +1,17 @@ +# Overview + +| Module | Package | Description | +| ----------------------------------------------------------------------------------------------------- | --------------------- | ---------------------------------| +| [Server](/api/server/application) | `@nocobase/server` | Application Serveur | +| [Database](/api/database) | `@nocobase/database` | Couche d'accès aux données | +| [Resourcer](/api/resourcer/resource-manager) | `@nocobase/resourcer` | Mapping des ressources / routes | +| [ACL](/api/acl/acl) | `@nocobase/acl` | Contrôle d'accès | +| [Auth](/api/auth/auth-manager) | `@nocobase/auth` | Authentification des utilisateurs| +| Client | `@nocobase/client` | Application Client | +| [Cache](/api/cache/cache-manager) | `@nocobase/cache` | Cache Serveur | +| [Logger](/api/logger) | `@nocobase/logger` | Log Serveur | +| [Telemetry](/api/telemetry/telemetry) | `@nocobase/telemetry` | Télémetrie Serveur | +| [CLI](/api/cli) | `@nocobase/cli` | NocoBase Command Line Interface | +| [SDK](/api/sdk) | `@nocobase/sdk` | NocoBase SDK | +| [Actions](/api/actions) | `@nocobase/actions` | Ressources d'opération incluses | +| [Test](/api/test/server) | `@nocobase/test` | Tests automatiques | diff --git a/docs/fr-FR/api/logger.md b/docs/fr-FR/api/logger.md new file mode 100644 index 000000000..dd4d17d2e --- /dev/null +++ b/docs/fr-FR/api/logger.md @@ -0,0 +1,131 @@ +# @nocobase/logger + +## Create Logger + +### createLogger() + +Creates a custom logger. + +#### Signature + +- `createLogger(options: LoggerOptions)` + +#### Type + +```ts +interface LoggerOptions + extends Omit { + dirname?: string; + filename?: string; + format?: 'logfmt' | 'json' | 'delimiter' | 'console' | winston.Logform.Format; + transports?: ('console' | 'file' | 'dailyRotateFile' | winston.transport)[]; +} +``` + +#### Details + +- `dirname`: Log directory +- `filename`: Log file name +- `format`: Log format +- `transports`: Log transports + +### createSystemLogger() + +Creates system runtime logs printed in a specified method. Refer to [Logger plugin - System log](../plugins/logger/index.md#system-log). + +#### Signature + +- `createSystemLogger(options: SystemLoggerOptions)` + +#### Type + +```ts +export interface SystemLoggerOptions extends LoggerOptions { + seperateError?: boolean; // print error seperately, default true +} +``` + +#### Details + +- `seperateError`: Whether to print `error` level logs separately + +### app.createLogger() + +#### Definition + +```ts +class Application { + createLogger(options: LoggerOptions) { + const { dirname } = options; + return createLogger({ + ...options, + dirname: getLoggerFilePath(this.name || 'main', dirname || ''), + }); + } +} +``` + +When `dirname` is a relative path, the log files will be output to the directory named after the current application. + +### plugin.createLogger() + +Usage is the same as `app.createLogger()`. + +#### Definition + +```ts +class Plugin { + createLogger(options: LoggerOptions) { + return this.app.createLogger(options); + } +} +``` + +## Configuration + +### getLoggerLevel() + +`getLoggerLevel(): 'debug' | 'info' | 'warn' | 'error'` + +Gets the log level currently configured in the system. + +### getLoggerFilePath() + +`getLoggerFilePath(...paths: string[]): string` + +Concatenates directory paths based on the log directory currently configured in the system. + +### getLoggerTransports() + +`getLoggerTransports(): ('console' | 'file' | 'dailyRotateFile')[]` + +Gets the log output methods currently configured in the system. + +### getLoggerFormat() + +`getLoggerFormat(): 'logfmt' | 'json' | 'delimiter' | 'console'` + +Gets the log format currently configured in the system. + +## Logger Transports + +### Transports + +Predefined output methods. + +- `Transports.console` +- `Transports.file` +- `Transports.dailyRotateFile` + +```ts +import { Transports } from '@nocobase/logger'; + +const transport = Transports.console({ + //... +}); +``` + +## References + +- [Development - Logger](../handbook/logger/index.md) +- [Logger Plugin](../plugins/logger/index.md) diff --git a/docs/fr-FR/api/resourcer/action.md b/docs/fr-FR/api/resourcer/action.md new file mode 100644 index 000000000..8e31d9dab --- /dev/null +++ b/docs/fr-FR/api/resourcer/action.md @@ -0,0 +1,173 @@ +# ctx.action + +## Overview + +After the resource operation request is parsed by [`resourceManager.middleware()`](./resource-manager#middleware), some important request parameters are stored in `ctx.action` for use by subsequent middleware. + +## API + +### resourceName + +`ctx.action.resourceName` + +The name of the resource. It can take two forms: + +- `a` - Operates on resource `a`. +- `a.b` - Operates on associated object `b` of resource `a`. + +### actionName + +`ctx.action.actionName` + +The name of the action. + +### sourceId + +`ctx.action.sourceId` + +When the operation object is an associated object of the resource, it represents the primary key value of the corresponding resource. For example: when `resourceName` is `a.b`, `sourceId` represents the primary key value of `a`. + +### params + +Request parameters. + +- URL parameters can be directly obtained from `ctx.action.params`. + +```ts +const { filterByTk } = ctx.action.params; +``` + +- Request body parameters can be obtained using `ctx.action.params.values`. + +### mergeParams() + +Combines parameter content with request parameters. + +```ts +ctx.action.mergeParams( + { + filter: { + name: 'foo', + }, + fields: ['id', 'name'], + except: ['name'], + sort: ['id'], + page: 1, + pageSize: 10, + values: { + name: 'foo', + }, + }, + { + filter: 'and', + fields: 'union', + except: 'union', + sort: 'overwrite', + page: 'overwrite', + pageSize: 'overwrite', + values: 'deepMerge', + }, +); + +ctx.action.mergeParams( + { + filter: {}, + }, + { + filter: (x, y) => { + // ... + }, + }, +); +``` + +#### Signature + +- `mergeParams(params: ActionParams, strategies: MergeStrategies = {})` + +#### Type + +```ts +export interface ActionParams { + filterByTk?: any; + fields?: string[]; + appends?: string[]; + except?: string[]; + whitelist?: string[]; + blacklist?: string[]; + filter?: FilterOptions; + sort?: string[]; + page?: number; + pageSize?: number; + values?: any; + [key: string]: any; +} + +type MergeStrategyType = + | 'merge' + | 'deepMerge' + | 'overwrite' + | 'andMerge' + | 'orMerge' + | 'intersect' + | 'union'; +type MergeStrategyFunc = (x: any, y: any) => any; +export type MergeStrategy = MergeStrategyType | MergeStrategyFunc; +export interface MergeStrategies { + [key: string]: MergeStrategy; +} +``` + +#### Details + +| Property | Type | Description | +| ------------ | -------------------------------------------------------- | ------------------------------------------------------------- | +| `params` | [`ActionParams`](#actionparams) | Request parameters | +| `strategies` | [`{ [key: string]: MergeStrategies }`](#mergestrategies) | Merge strategies for various fields in the request parameters | + +Default `strategies`: + +```ts +{ + filter: 'andMerge', + fields: 'intersect', + appends: 'union', + except: 'union', + whitelist: 'intersect', + blacklist: 'intersect', + sort: 'overwrite', +}; +``` + +##### ActionParams + +| Property | Type | Description | +| --------------- | ---------- | ----------------------------------------------------------------------- | +| `filterByTk` | `any` | The primary key value of the operated resource | +| `filter` | `Filter` | Filtering parameters, refer to [Filter Operators](./database/operators) | +| `fields` | `string[]` | Fields to retrieve | +| `except` | `string[]` | Fields to exclude | +| `appends` | `string[]` | Related fields to append | +| `whitelist` | `string[]` | Field whitelist | +| `blacklist` | `string[]` | Field blacklist | +| `sort` | `string[]` | Sorting parameters | +| `page` | `number` | Current page | +| `pageSize` | `number` | Number of data items per page | +| `values` | `any` | Request body | +| `[key: string]` | `any` | Other extended configurations | + +##### MergeStrategies + +Predefined merge strategies or custom merge functions. + +Predefined merge strategies: + +| Strategy Name | Description | +| ------------- | ------------------------------------------------- | +| `merge` | `Object.assign` | +| `deepMerge` | Deep traversal merge | +| `overwrite` | Overwrite | +| `andMerge` | Merge filter parameters using the `$and` operator | +| `orMerge` | Merge filter parameters using the `$or` operator | +| `intersect` | Intersection | +| `union` | Union | diff --git a/docs/fr-FR/api/resourcer/middleware.md b/docs/fr-FR/api/resourcer/middleware.md new file mode 100644 index 000000000..5a21a5d7d --- /dev/null +++ b/docs/fr-FR/api/resourcer/middleware.md @@ -0,0 +1,173 @@ +# Middleware + +It is similar to the middleware of Koa, but with more enhanced features for easy extensions. + +The defined middleware can be inserted for use in multiple places, such as the resourcer, and it is up to the developer for when to invoke it. + +## Constructor + +**Signature** + +- `constructor(options: Function)` +- `constructor(options: MiddlewareOptions)` + +**Parameter** + +| Name | Type | Default | Description | +| ----------------- | -------------------- | ------- | -------------------------------------- | +| `options` | `Function` | - | Handler function of middlware | +| `options` | `MiddlewareOptions ` | - | Configuration items of middlware | +| `options.only` | `string[]` | - | Only the specified actions are allowed | +| `options.except` | `string[]` | - | The specified actions are excluded | +| `options.handler` | `Function` | - | Handler function | + +**Example** + +Simple definition: + +```ts +const middleware = new Middleware((ctx, next) => { + await next(); +}); +``` + +Definition with relevant parameters: + +```ts +const middleware = new Middleware({ + only: ['create', 'update'], + async handler(ctx, next) { + await next(); + }, +}); +``` + +## Instance Methods + +### `getHandler()` + +Get the orchestrated handler functions. + +**Example** + +The following middleware will output `1` and then `2` when requested. + +```ts +const middleware = new Middleware((ctx, next) => { + console.log(1); + await next(); +}); + +middleware.use(async (ctx, next) => { + console.log(2); + await next(); +}); + +app.resourcer.use(middleware.getHandler()); +``` + +### `use()` + +Add a middleware function to the current middleware. Used to provide extension points for the middleware. See `getHandler()` for the examples. + +**Signature** + +- `use(middleware: Function)` + +**Parameter** + +| Name | Type | Default | Description | +| ------------ | ---------- | ------- | ---------------------------------- | +| `middleware` | `Function` | - | Handler function of the middleware | + +### `disuse()` + +Remove the middleware functions that have been added to the current middleware. + +**Signature** + +- `disuse(middleware: Function)` + +**Parameter** + +| Name | Type | Default | Description | +| ------------ | ---------- | ------- | ---------------------------------- | +| `middleware` | `Function` | - | Handler function of the middleware | + +**Example** + +The following example will only output `1` when requested, the output of `2` in fn1 will not be executed. + +```ts +const middleware = new Middleware((ctx, next) => { + console.log(1); + await next(); +}); + +async function fn1(ctx, next) { + console.log(2); + await next(); +} + +middleware.use(fn1); + +app.resourcer.use(middleware.getHandler()); + +middleware.disuse(fn1); +``` + +### `canAccess()` + +Check whether the current middleware is to be invoked for a specific action, it is usually handled by the resourcer internally. + +**Signature** + +- `canAccess(name: string): boolean` + +**Parameter** + +| Name | Type | Default | Description | +| ------ | -------- | ------- | ------------------ | +| `name` | `string` | - | Name of the action | + +## Other Exports + +### `branch()` + +Create a branch middleware for branching in the middleware. + +**Signature** + +- `branch(map: { [key: string]: Function }, reducer: Function, options): Function` + +**Parameter** + +| Name | Type | Default | Description | +| ------------------------ | ----------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- | +| `map` | `{ [key: string]: Function }` | - | Mapping table of the branch handler function, key names are given by subsequent calculation functions when called | +| `reducer` | `(ctx) => string` | - | Calculation function, it is used to calculate the key name of the branch based on the context | +| `options?` | `Object` | - | Configuration items of the branch | +| `options.keyNotFound?` | `Function` | `ctx.throw(404)` | Handler function when key name is not found | +| `options.handlerNotSet?` | `Function` | `ctx.throw(404)` | The function when no handler function is defined | + +**Example** + +When authenticating user, determine what to do next according to the value of the `authenticator` parameter in the query section of the request URL. + +```ts +app.resourcer.use( + branch( + { + password: async (ctx, next) => { + // ... + }, + sms: async (ctx, next) => { + // ... + }, + }, + (ctx) => { + return ctx.action.params.authenticator ?? 'password'; + }, + ), +); +``` diff --git a/docs/fr-FR/api/resourcer/resource-manager.md b/docs/fr-FR/api/resourcer/resource-manager.md new file mode 100644 index 000000000..3e335b240 --- /dev/null +++ b/docs/fr-FR/api/resourcer/resource-manager.md @@ -0,0 +1,258 @@ +# ResourceManager + +## Overview + +`ResourceManager` is the resource management module of NocoBase, used to define resources and register operation methods for resources. + +## Class Methods + +### `define()` + +Defines a resource. + +```ts +app.resourceManager.define({ + name: 'auth', + actions: { + check: async (ctx, next) => { + // ... + await next(); + }, + }, +}); +``` + +#### Signature + +- `define(options: ResourceOptions): Resource` + +#### Type + +```ts +export interface ResourceOptions { + name: string; + type?: ResourceType; + actions?: { + [key: string]: ActionType; + }; + only?: Array; + except?: Array; + middleware?: MiddlewareType; + middlewares?: MiddlewareType; +} + +export type ResourceType = + | 'single' + | 'hasOne' + | 'hasMany' + | 'belongsTo' + | 'belongsToMany'; + +export type ActionType = HandlerType | ActionOptions; +export type HandlerType = ( + ctx: ResourcerContext, + next: () => Promise, +) => any; +export interface ActionOptions { + values?: any; + fields?: string[]; + appends?: string[]; + except?: string[]; + whitelist?: string[]; + blacklist?: string[]; + filter?: FilterOptions; + sort?: string[]; + page?: number; + pageSize?: number; + maxPageSize?: number; + middleware?: MiddlewareType; + middlewares?: MiddlewareType; + handler?: HandlerType; + [key: string]: any; +} +``` + +#### Details + +##### ResourceOptions + +| Property | Type | Description | Default | +| ------------- | ---------------------------------------------- | ---------------------- | -------- | +| `name` | `string` | Resource name | - | +| `type` | `ResourceType` | Resource type | `single` | +| `actions` | [`{ [key: string]: ActionType }`](#actiontype) | Actions | - | +| `only` | `ActionName[]` | Whitelist of `actions` | - | +| `except` | `ActionName[]` | Blacklist of `actions` | - | +| `middleware` | `MiddlewareType` | Middleware | - | +| `middlewares` | `MiddlewareType` | Middlewares | - | + +##### ActionType + +There are two types of action methods: + +- `HandlerType` + +This type directly defines the operation method through middleware. Example: + +```ts +app.resourceManager.define({ + name: 'users', + actions: { + updateProfile: async (ctx, next) => { + // ... + await next(); + }, + }, +}); +``` + +- `ActionOptions` + +This type is mainly used to override the request parameters of a certain existing operation. Example: + +```ts +app.resourceManager.define({ + name: 'users', + actions: { + list: { + fields: [], + filter: {}, + // ... + }, + }, +}); +``` + +| Property | Type | Description | +| --------------- | ---------------- | --------------------------------------------------------------------------- | +| `values` | `any` | Default values for the action request | +| `filter` | `Filter` | Filtering parameters, refer to [Filter Operators](../database/operators.md) | +| `fields` | `string[]` | Fields to retrieve | +| `except` | `string[]` | Fields to exclude | +| `appends` | `string[]` | Related fields to append | +| `whitelist` | `string[]` | Field whitelist | +| `blacklist` | `string[]` | Field blacklist | +| `sort` | `string[]` | Sorting parameters | +| `page` | `number` | Current page | +| `pageSize` | `number` | Number of data items per page | +| `maxPageSize` | `number` | Maximum number of data items per page | +| `middleware` | `MiddlewareType` | Middleware | +| `middlewares` | `MiddlewareType` | Middlewares | +| `handler` | `HandlerType` | Method executed for the action | +| `[key: string]` | `any` | Other extended configurations | + +### `registerActionHandlers()` + +Registers action methods. + +#### Signature + +- `registerActionHandler(name: ActionName, handler: HandlerType)` + +#### Type + +```ts +export type DefaultActionType = + | 'list' + | 'create' + | 'get' + | 'update' + | 'destroy' + | 'set' + | 'add' + | 'remove'; +export type ActionName = DefaultActionType | Omit; + +export type HandlerType = ( + ctx: ResourcerContext, + next: () => Promise, +) => any; +``` + +#### Details + +| Property | Type | Description | +| --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `name` | `ActionName` | Action name.
    1. As a regular string, registers actions for all resources.
    2. In the form `:`, registers actions for specific resources | +| `handler` | `HandlerType` | Middleware for the action | + +### `isDefined()` + +Checks if a resource is defined. + +#### Signature + +- `isDefined(name: string)` + +#### Details + +| Property | Type | Description | +| -------- | -------- | ------------- | +| `name` | `string` | Resource name | + +### `import()` + +Loads resource configurations from a specified directory. + +```ts +// ./resources/demo.ts +export default { + name: 'demo', + actions: { + async list(ctx, next) { + // ... + await next(); + }, + }, +}; + +const resourceMangaer = new ResourceManager(); +await resourceManager.import({ + directory: path.resolve(__dirname, 'resources'), +}); +``` + +#### Signature + +- `import(options: ImportOptions): Promise>` + +#### Type + +```ts +export interface ImportOptions { + directory: string; + extensions?: string[]; +} +``` + +#### Details + +| Property | Type | Description | Default Value | +| ------------ | ---------- | ------------------------- | ---------------------- | +| `directory` | `string` | Directory path | - | +| `extensions` | `string[]` | Optional, file extensions | `['js', 'ts', 'json']` | + +### `use()` + +Adds `ResourceManager` middleware. + +```ts +resourceManager.use(async () => { + return async function (ctx, next) { + // ... + await next(); + }; +}); +``` + +#### Signature + +- `use(middlewares: HandlerType | HandlerType[], options: ToposortOptions = {})` + +#### Details + +Refer to [Middleware](../../development/server/middleware.md). + +### `middleware()` + +Middleware for `ResourceManager`, parses request parameters (refer to [ctx.action](./action.md)) and executes operation methods. diff --git a/docs/fr-FR/api/resourcer/resource.md b/docs/fr-FR/api/resourcer/resource.md new file mode 100644 index 000000000..e1374aef1 --- /dev/null +++ b/docs/fr-FR/api/resourcer/resource.md @@ -0,0 +1,114 @@ +# Resource + +Resource is used to define resource instance. Resource instances managed by resourcer can be accessed through HTTP requests. + +## Constructor + +To create resource instance. Normally it is not used directly, but replaced by the call of the `define()` interface of resourcer. + +**Signature** + +- `constructor(options: ResourceOptions, resourcer: Resourcer)` + +**Parameter** + +| Name | Type | Default | Description | +| --------------------- | ------------------------------------ | ---------- | --------------------------------------------------------------------------------------------------------------- | +| `options.name` | `string` | - | Name of the resource, corresponding to the resource address in the route of the URL | +| `options.type` | `string` | `'single'` | Type of the resource, options are `'single'`, `'hasOne'`, `'hasMany'`, `'belongsTo'`, `'belongsToMany'` | +| `options.actions` | `Object` | - | List of actions that can be taken on the resource, see the example for details | +| `options.middlewares` | `MiddlewareType \| MiddlewareType[]` | - | List of middlewares for any operational access to the resource that is defining,see the example for details | +| `options.only` | `ActionName[]` | `[]` | Whitelist for global actions, only actions contained in the array (if `length > 0`) can be accessed | +| `options.except` | `ActionName[]` | `[]` | Blacklist for global actions, all actions except those contained in the array (if `length > 0`) can be accessed | +| `resourcer` | `Resourcer` | - | The resourcer instance | + +**Example** + +```ts +app.resourcer.define({ + name: 'books', + actions: { + // Extended action + publish(ctx, next) { + ctx.body = 'ok'; + }, + }, + middleware: [ + // Extended middleware + async (ctx, next) => { + await next(); + }, + ], +}); +``` + +## Instance Members + +### `options` + +Configuration items for the current resource. + +### `resourcer` + +The resourcer instance to which the resource belongs. + +### `middlewares` + +The registered middlewares. + +### `actions` + +The registered mapping table of actions. + +### `except` + +Actions that are excluded. + +## Instance Methods + +### `getName()` + +Get the name of the current resource. + +**Signature** + +- `getName(): string` + +**Example** + +```ts +const resource = app.resourcer.define({ + name: 'books', +}); + +resource.getName(); // 'books' +``` + +### `getAction()` + +Get action with the corresponding name. + +**Signature** + +- `getAction(name: string): Action` + +**Parameter** + +| Name | Type | Default | Description | +| ------ | -------- | ------- | ------------------ | +| `name` | `string` | - | Name of the action | + +**Example** + +```ts +const resource = app.resourcer.define({ + name: 'books', + actions: { + publish(ctx, next) { + ctx.body = 'ok'; + }, + }, +}); + +resource.getAction('publish'); // [Function: publish] +``` diff --git a/docs/fr-FR/api/sdk/auth.md b/docs/fr-FR/api/sdk/auth.md new file mode 100644 index 000000000..c616510b4 --- /dev/null +++ b/docs/fr-FR/api/sdk/auth.md @@ -0,0 +1,70 @@ +# Auth + +## Overview + +The `Auth` class is primarily used for accessing user information on the client-side, as well as requesting user authentication-related APIs. + +## Instance Properties + +### `locale` + +The language used by the current user. + +### `role` + +The role used by the current user. + +### `token` + +The API interface token. + +### `authenticator` + +The authenticator used for current user authentication. Refer to [User Authentication](../../handbook/auth/user.md). + +## Class Methods + +### `signIn()` + +User login. + +#### Signature + +- `async signIn(values: any, authenticator?: string): Promise>` + +#### Details + +| Parameter | Type | Description | +| --------------- | -------- | --------------------------------------- | +| `values` | `any` | Login API request parameters | +| `authenticator` | `string` | Authenticator identifier used for login | + +### `signUp()` + +User registration. + +#### Signature + +- `async signUp(values: any, authenticator?: string): Promise>` + +#### Details + +| Parameter | Type | Description | +| --------------- | -------- | ---------------------------------------------- | +| `values` | `any` | Registration API request parameters | +| `authenticator` | `string` | Authenticator identifier used for registration | + +### `signOut()` + +Log out. + +#### Signature + +- `async signOut(values: any, authenticator?: string): Promise>` + +#### Details + +| Parameter | Type | Description | +| --------------- | -------- | ---------------------------------------- | +| `values` | `any` | Logout API request parameters | +| `authenticator` | `string` | Authenticator identifier used for logout | diff --git a/docs/fr-FR/api/sdk/index.md b/docs/fr-FR/api/sdk/index.md new file mode 100644 index 000000000..a9376279f --- /dev/null +++ b/docs/fr-FR/api/sdk/index.md @@ -0,0 +1,151 @@ +# APIClient + +## Overview + +`APIClient` is a wrapper based on `axios`, used for making HTTP requests to perform resource operations in NocoBase from the client-side. + +### Basic Usage + +```ts +class PluginSampleAPIClient extends Plugin { + async load() { + const res = await this.app.apiClient.request({ + // ... + }); + } +} +``` + +## Instance Properties + +### `axios` + +An `axios` instance that provides access to the `axios` API, such as `apiClient.axios.interceptors`. + +### `auth` + +A client-side authentication class, refer to [Auth](./auth.md). + +### `storage` + +A client-side storage class, refer to [Storage](./storage.md). + +## Class Methods + +### `constructor()` + +Constructor to create an `APIClient` instance. + +#### Signature + +- `constructor(instance?: APIClientOptions)` + +#### Type + +```ts +interface ExtendedOptions { + authClass?: any; + storageClass?: any; +} + +export type APIClientOptions = + | AxiosInstance + | (AxiosRequestConfig & ExtendedOptions); +``` + +### `request()` + +Makes an HTTP request. + +#### Signature + +- `request, D = any>(config: AxiosRequestConfig | ResourceActionOptions): Promise` + +#### Type + +```ts +type ResourceActionOptions

    = { + resource?: string; + resourceOf?: any; + action?: string; + params?: P; +}; +``` + +#### Details + +##### AxiosRequestConfig + +Common axios request parameters. Refer to Request Config. + +```ts +const res = await apiClient.request({ url: '' }); +``` + +##### ResourceActionOptions + +Parameters for NocoBase resource operations. + +```ts +const res = await apiClient.request({ + resource: 'users', + action: 'list', + params: { + pageSize: 10, + }, +}); +``` + +| Property | Type | Description | +| --------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `resource` | `string` | 1. Resource name, such as `a`
    2. Name of the associated object, such as `a.b` | +| `resourceOf` | `any` | Primary key value of the resource when `resource` is the name of an associated object. For example, for `a.b`, it represents the primary key value of `a`. | +| `action` | `string` | Action name | +| `params` | `any` | Request parameter object, mainly URL parameters, request body is put into `params.values` | +| `params.values` | `any` | Request body object | + +### `resource()` + +Gets the object containing NocoBase resource operation methods. + +```ts +const resource = apiClient.resource('users'); + +await resource.create({ + values: { + username: 'admin', + }, +}); + +const res = await resource.list({ + page: 2, + pageSize: 20, +}); +``` + +#### Signature + +- `resource(name: string, of?: any, headers?: AxiosRequestHeaders): IResource` + +#### Type + +```ts +export interface ActionParams { + filterByTk?: any; + [key: string]: any; +} + +type ResourceAction = (params?: ActionParams) => Promise; + +export type IResource = { + [key: string]: ResourceAction; +}; +``` + +#### Details + +| Parameter | Type | Description | +| --------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `name` | `string` | Resource name, such as `a`
    2. Name of the associated object, such as `a.b` | +| `of` | `any` | Primary key value of the resource when `resource` is the name of an associated object. For example, for `a.b`, it represents the primary key value of `a`. | +| `headers` | `AxiosRequestHeaders` | HTTP request headers to be sent with subsequent resource operation requests | diff --git a/docs/fr-FR/api/sdk/storage.md b/docs/fr-FR/api/sdk/storage.md new file mode 100644 index 000000000..d23042ce5 --- /dev/null +++ b/docs/fr-FR/api/sdk/storage.md @@ -0,0 +1,54 @@ +# Storage + +## Overview + +The `Storage` class is used for client-side information storage, defaulting to `localStorage`. + +### Basic Usage + +```ts +export abstract class Storage { + abstract clear(): void; + abstract getItem(key: string): string | null; + abstract removeItem(key: string): void; + abstract setItem(key: string, value: string): void; +} + +export class CustomStorage extends Storage { + // ... +} +``` + +## Class Methods + +### `setItem()` + +Store content. + +#### Signature + +- `setItem(key: string, value: string): void` + +### `getItem()` + +Retrieve content. + +#### Signature + +- `getItem(key: string): string | null` + +### `removeItem()` + +Delete content. + +#### Signature + +- `removeItem(key: string): void` + +### `clear()` + +Clear all content. + +#### Signature + +- `clear(): void` diff --git a/docs/fr-FR/api/server/application.md b/docs/fr-FR/api/server/application.md new file mode 100644 index 000000000..da3829dcf --- /dev/null +++ b/docs/fr-FR/api/server/application.md @@ -0,0 +1,370 @@ +# Application + +`Application` is the core module of the NocoBase server, based on [Koa](https://koajs.com) extensions. It's responsible for major application initialization logic and managing the application lifecycle. + +## Constructor + +### `constructor()` + +#### Signature + +- `constructor(public options: ApplicationOptions)` + +#### Types + +```typescript +export type PluginType = string | typeof Plugin; +export type PluginConfiguration = PluginType | [PluginType, any]; + +export interface ResourceManagerOptions { + prefix?: string; +} + +export interface AppLoggerOptions { + request: RequestLoggerOptions; + system: SystemLoggerOptions; +} + +export interface AppTelemetryOptions extends TelemetryOptions { + enabled?: boolean; +} + +export interface ApplicationOptions { + database?: IDatabaseOptions | Database; + cacheManager?: CacheManagerOptions; + resourceManager?: ResourceManagerOptions; + bodyParser?: any; + cors?: any; + dataWrapping?: boolean; + registerActions?: boolean; + i18n?: i18n | InitOptions; + plugins?: PluginConfiguration[]; + acl?: boolean; + logger?: AppLoggerOptions; + name?: string; + authManager?: AuthManagerOptions; + telemetry?: AppTelemetryOptions; +} +``` + +#### Details + +##### ApplicationOptions + +| Property | Type | Description | +| ----------------- | --------------------------------------- | --------------------------------------------------------------------- | +| `name` | `string` | Application identifier | +| `database` | `IDatabaseOptions` \| `DataBase` | Configuration for `DataBase` instance or the instance itself | +| `cacheManager` | `CacheManagerOptions` | Configuration for `CacheManager` instance | +| `resourceManager` | [`ResourcerOptions`](#resourceroptions) | Configuration for resource management | +| `authManager` | `AuthManagerOptions` | Configuration for user authentication management | +| `bodyParser` | `bodyParser.Options` | Parameters passed to the `@koa/bodyparser` middleware | +| `bodyParser` | `any` | Parameters passed to the `@koa/cors` middleware | +| `dataWrapping` | `boolean` | Whether to format response data | +| `registerActions` | `boolean` | Whether to register default CRUD operation interfaces for data tables | +| `i18n` | `i18n` \| `InitOptions` | `i18n` instance or initialization configuration | +| `plugins` | `PluginConfiguration[]` | Names of built-in installed plugins or an array of instances | +| `acl` | `boolean` | Whether to enable access control | +| `logger` | [`AppLoggerOptions`](#apploggeroptions) | Configuration for application logging | +| `telemetry` | `AppTelemetryOptions` | Configuration for telemetry module | + +##### ResourcerOptions + +| Property | Type | Description | +| -------- | -------- | ------------------------ | +| `prefix` | `string` | Prefix for resource APIs | + +##### AppLoggerOptions + +| Property | Type | Description | +| --------- | ---------------------- | ------------------------------------------------------------------------- | +| `request` | `RequestLoggerOptions` | Refer to [Logger - requestLogger()](../logger.md#requestlogger) | +| `system` | `SystemLoggerOptions` | Refer to [Logger - createSystemLogger()](../logger.md#createsystemlogger) | + +## Instance Properties + +### `name` + +Application identifier. Default is `main`. + +### `version` + +Application version management. Application version can be obtained using `version.get()`. + +### `mainDataSource` + +Main data source. + +### `db` + +Instance of `DataBase` for the main data source. Refer to [DataBase](../database/index.md). + +### `acl` + +Instance of `ACL`. Refer to [ACL](../acl/acl.md). + +### `log` + +System logs. Refer to [Logger](../logger.md). + +### `logger` + +Equivalent to `log`. + +### `cache` + +Application cache, instance of `Cache`. Refer to [Cache](../cache/cache.md). + +### `cli` + +Application command-line methods. + +### `i18n` + +Internationalization. Instance of `i18n`. + +### `telemetry` + +Instance of `Telemetry`. Refer to [Telemetry](../telemetry/telemetry.md). + +### `pm` + +Plugin management. Refer to [PluginManager](./plugin-manager). + +### `dataSourceManager` + +Data source management. Refer to [DataSourceManager](../data-source-manager/). + +### `resourceManager` + +Resource management. Refer to [ResourceManager](../resourcer/resource-manager.md). + +### `cacheManager` + +Cache management. Refer to [CacheManager](../cache/cache-manager.md). + + + +### `authManager` + +User authentication management. Refer to [AuthManager](../auth/auth-manager.md). + +### `cronJobManager` + +Application cron job management. + +### `localeManager` + +Application localization resource management. + +## Lifecycle Methods + +### `load()` + +Loads the application and performs application initialization. + +#### Signature + +- `load(options?: LoadOptions): Promise` + +#### Types + +```typescript +interface LoadOptions { + reload?: boolean; + hooks?: boolean; + sync?: boolean; + [key: string]: any; +} +``` + +#### Details + +| Property | Type | Description | Default | +| --------------- | --------- | ------------------------------------------------------- | ------- | +| `reload` | `boolean` | Indicates if it's a reload operation | `false` | +| `hooks` | `boolean` | Whether to trigger `beforeLoad` / `afterLoad` hooks | `true` | +| `sync` | `boolean` | Whether to synchronize data table configuration changes | `false` | +| `[key: string]` | `any` | Additional configuration, will be passed to hooks | - | + +### `reload()` + +Reloads the application, triggering a re-initialization. + +#### Signature + +- `reload(options?: LoadOptions): Promise` + +### `start()` + +Starts the application to accept requests. + +#### Signature + +- `start(options: StartOptions = {}): Promise` + +#### Types + +```typescript +interface StartOptions { + checkInstall?: boolean; +} +``` + +#### Details + +| Property | Type | Description | Default | +| -------------- | --------- | ---------------------------------------------------------- | ------- | +| `checkInstall` | `boolean` | Indicates whether to check if the application is installed | `false` | + +### `restart()` + +Restarts the application, executing `reload()` and `start()`. + +#### Signature + +- `restart(options: StartOptions = {}): Promise` + +### `install()` + +Installs the application, which involves application initialization, synchronization of data table configuration changes, plugin installation, and application restart if it's already started. + +#### Signature + +- `install(options: InstallOptions = {}): Promise` + +#### Details + +| Property | Type | Description | Default | +| -------- | --------- | ------------------------------------------------------------------------ | ------- | +| `force` | `boolean` | Indicates whether to reinstall the application if it's already installed | `false` | + +### `upgrade()` + +Upgrades the application by executing migration scripts for each plugin and restarting the application. + +#### Signature + +- `upgrade(): Promise` + +### ` + +stop()` + +Stops the application by closing database connections, cache middleware, and telemetry connections. + +#### Signature + +- `stop(): Promise` + +### `destroy()` + +Destroys the application, equivalent to calling `stop()`. + +#### Signature + +- `destroy(): Promise` + +### `isInstalled()` + +Checks if the application is installed. + +#### Signature + +- `isInstalled(): Promise` + +### `isStarted()` + +Checks if the application is started. + +#### Signature + +- `isStarted(): Promise` + +## Other Methods + +### `on()` + +Listens for application events. Refer to [emitter.on(eventName, listener)](https://nodejs.org/api/events.html#emitteroneventname-listener). + +#### Signature + +- `on(eventName: string | symbol, listener: (...args: any[]) => void): this` + +### `off()` + +Removes event listeners. Refer to [emitter.off(eventName, listener)](https://nodejs.org/api/events.html#emitteroffeventname-listener). + +#### Signature + +- `off(eventName: string | symbol, listener: (...args: any[]) => void): this` + +### `use()` + +Adds application middleware. Refer to [Koa - Application](https://koajs.com/#application). + +### `command()` + +Adds application command-line commands. + +#### Signature + +- `command(name: string, desc?: string, opts?: CommandOptions): AppCommand` + +#### Details + +| Property | Type | Description | +| -------- | ---------------- | ---------------------------------------------------------------------------------- | +| `name` | `string` | Command | +| `desc` | `string` | Command description | +| `opts` | `CommandOptions` | Command configuration, refer to [Commander.js](https://github.com/tj/commander.js) | + +### `runCommand()` + +Runs application commands. + +#### Signature + +- `runCommand(command: string, ...args: any[])` + +### `authenticate()` + +Performs DB connection check and version check. + +#### Signature + +- `authenticate(): Promise` + +## Events + +### `'beforeLoad'` / `'afterLoad'` + +Triggered before and after [`load()`](#load) and [`reload()`](#reload). + +### `'beforeReload'` / `'afterReload'` + +Triggered before and after [`reload()`](#reload). + +### `'beforeInstall'` / `'afterInstall'` + +Triggered before and after [`install()`](#install). + +### `'beforeUpgrade'` / `'afterUpgrade'` + +Triggered before and after [`upgrade()`](#upgrade). + +### `'beforeStart'` / `'afterStart'` + +Triggered before and after [`start()`](#start). + +### `'beforeStop'` / `'afterStop'` + +Triggered before and after [`stop()`](#stop) and [`destroy()`](#destroy). `'beforeStop'` is triggered before [`restart()`](#restart). + +### `'beforeDestroy'` / `'afterDestroy'` + +Triggered before and after [`destroy()`](#destroy). diff --git a/docs/fr-FR/api/server/migration.md b/docs/fr-FR/api/server/migration.md new file mode 100644 index 000000000..98452440e --- /dev/null +++ b/docs/fr-FR/api/server/migration.md @@ -0,0 +1,61 @@ +# Migration + +`Migration` is a class in NocoBase used for upgrade scripts, typically used to synchronize database-related changes. + +## Instance Properties + +### `appVersion` + +Current application version. The script will be executed only if it matches the version. + +```typescript +export default class extends Migration { + appVersion = '<=1.0.0-alpha.1'; + // ... +} +``` + +### `on` + +The trigger timing for the upgrade script execution, with a default value of `afterLoad`. Refer to [Application - Events](./application.md#events). + +```typescript +export default class extends Migration { + on = 'afterLoad'; + // ... +} +``` + +### `app` + +The `Application` instance of the current application. Refer to [Application](./application.md). + +### `pm` + +The `PluginManager` instance of the current application. Refer to [PluginManager](./plugin-manager.md). + +### `plugin` + +The `Plugin` instance of the current plugin. Refer to [Plugin](./plugin.md). + +### `db` + +The `DataBase` instance of the current application. Refer to [DataBase](../database/index.md). + +### `sequelize` + +The `Sequelize` instance. Refer to [Sequelize](https://sequelize.org/). + +### `queryInterface` + +Refer to [Sequelize - Query Interface](https://sequelize.org/docs/v6/other-topics/query-interface/). + +### Instance Methods + +### `up()` + +Method for upgrade execution. + +### `down()` + +Method for downgrade execution. diff --git a/docs/fr-FR/api/server/plugin-manager.md b/docs/fr-FR/api/server/plugin-manager.md new file mode 100644 index 000000000..22ba6a9b3 --- /dev/null +++ b/docs/fr-FR/api/server/plugin-manager.md @@ -0,0 +1,138 @@ +# PluginManager + +`PluginManager` is the plugin manager for NocoBase. + +## Instance Properties + +### `repository` + +The `Repository` instance for the plugin data table. API reference: [DataBase - Repository](../database/repository.md). + +## Instance Methods + +### `addPreset()` + +Adds a system built-in plugin. Built-in plugins are enabled by default and do not appear in the client plugin manager list. + +#### Signature + +- `addPreset(plugin: string | typeof Plugin, options: any = {})` + +#### Details + +| Parameter | Type | Description | +| --------- | --------------------------- | ----------------------- | +| `plugin` | `string` \| `typeof Plugin` | Plugin name or instance | +| `options` | `any` | Plugin options | + +### `getPlugins()` + +Gets all plugin instances of the current application. + +#### Signature + +- `getPlugins(): Map>` + +### `getAliases()` + +Gets all plugin names. + +#### Signature + +- `getAliases(): IterableIterator` + +### `get()` + +Gets a specific plugin. + +#### Signature + +- `get(name: string | typeof Plugin): Plugin` + +### `has()` + +Checks if a plugin exists. + +#### Signature + +- `has(name: string | typeof Plugin): boolean` + +### `create()` + +Creates a plugin and generates the plugin directory. + +#### Signature + +- `create(pluginName: string, options?: { forceRecreate?: boolean }): Promise` + +#### Details + +| Parameter | Type | Description | Default | +| ----------------------- | --------- | --------------------------------------------------------------- | ------- | +| `pluginName` | `string` | Plugin name | - | +| `options.forceRecreate` | `boolean` | Whether to remove the existing plugin directory and recreate it | `false` | + +### `add()` + +Adds or upgrades a plugin. + +#### Signature + +- `add(plugin?: any, options: any = {}, insert = false, isUpgrade = false): Promise` + +#### Details + +| Parameter | Type | Description | Default | +| ----------- | --------------------------- | ----------------------------------- | ------- | +| `plugin` | `string` \| `typeof Plugin` | Plugin name or instance | - | +| `options` | `any` | Plugin configuration | - | +| `insert` | `boolean` | Whether to add plugin table records | `false` | +| `isUpgrade` | `boolean` | Whether it's a plugin upgrade | `false` | + +### `load()` + +Loads all enabled plugins. + +#### Signature + +- `load(): Promise` + +### `install()` + +Installs all enabled plugins that are not yet installed. + +#### Signature + +- `install(): Promise` + +### `enable()` + +Enables one or more plugins that are not enabled. + +#### Signature + +- `enable(name: string | string[]): Promise` + +### `disable()` + +Disables one or more enabled plugins. + +#### Signature + +- `disable(name: string | string[]): Promise` + +### `remove()` + +Removes one or more plugins. + +#### Signature + +- `remove(name: string | string[], options?: { removeDir?: boolean; force?: boolean })` + +#### Details + +| Parameter | Type | Description | Default | +| ------------------- | ---------------------- | ------------------------------------------------------------------------------------------ | ------- | +| `name` | `string` \| `string[]` | Plugin name(s) | - | +| `options.removeDir` | `boolean` | Whether to remove the plugin directory | `false` | +| `options.force` | `boolean` | Whether to delete database records directly, skipping `beforeRemove` / `afterRemove` hooks | `false` | diff --git a/docs/fr-FR/api/server/plugin.md b/docs/fr-FR/api/server/plugin.md new file mode 100644 index 000000000..dcaa9ad87 --- /dev/null +++ b/docs/fr-FR/api/server/plugin.md @@ -0,0 +1,151 @@ +# Plugin + +## Overview + +`Plugin` is the plugin class for the NocoBase server, providing configuration properties and lifecycle methods related to server-side plugins. + +### Basic Usage + +```ts +import { Plugin } from '@nocobase/server'; + +export class PluginDemoServer extends Plugin {} + +export default PluginDemoServer; +``` + +## Instance Properties + +### `options` + +Configuration options for the plugin. + +### `name` + +`string` - The name of the plugin. + +### `enabled` + +`boolean` - Whether the plugin is enabled. + +### `installed` + +`boolean` - Whether the plugin is installed. + +### `log` + +System log instance, with the default `module` set to the plugin name. Refer to [Logger](../logger.md). + +### `app` + +The `Application` instance of the current application. Refer to [Application](./application.md). + +### `pm` + +The `PluginManager` instance of the current application. Refer to [PluginManager](./plugin-manager.md). + +### `db` + +The `DataBase` instance of the current application. Refer to [DataBase](../database/index.md). + +## Lifecycle Methods + +### `afterAdd()` + +Executed after the plugin is added, i.e., after [`pm.add()`](./plugin-manager.md#add). + +### `beforeLoad()` + +Executed during [`pm.load()`](./plugin-manager.md#load). Used to register events, initialize classes, or perform other preprocessing logic before plugin loading. At this stage, the core API can be accessed, but not other plugin APIs. + +### `load()` + +Loads the plugin and its related configurations. Executed during [`pm.load()`](./plugin-manager.md#load), after all [`beforeLoad()`](#beforeload) methods of plugins have finished execution. At this stage, other plugin APIs can be accessed. + +### `install()` + +Installation logic of the plugin, executed during application installation, upgrade, or when the plugin is first enabled. Typically used to perform tasks such as inserting preset data into tables. + +### `beforeEnable()` + +Executed before the plugin is enabled. + +### `afterEnable()` + +Executed after the plugin is enabled. + +### `beforeDisable()` + +Executed before the plugin is disabled. + +### `afterDisable()` + +Executed after the plugin is disabled. + +### `beforeRemove()` + +Executed before the plugin is removed. + +### `afterRemove()` + +Executed after the plugin is removed. + + +## Other Methods + +### `t()` + +Internationalization method. + +### `createLogger()` + +Creates a logger. Refer to [Logger](../logger.md). + +### `toJSON()` + +A method for internal use. Outputs plugin-related configuration information. + +### `sendSyncMessage()` + +Publish synchronization messages. The synchronization messages sent by this method will only be received by the same plugin on other nodes, and will not be related to other plugins. + +#### Signature + +```ts +sendSyncMessage(message: any): void | Promise +``` + +#### Arguments + +- `message`: Sync message data. + +#### Example + +```ts +this.sendSyncMessage({ + key: 'value' +}); +``` + +### `handleSyncMessage()` + +In a distributed environment, handle synchronization events published by the current plugin from other nodes. When the plugin uses memory state, it is necessary to override the event handling logic to ensure synchronization with the state of other nodes. + +#### Signature + +``` +handleSyncMessage(message: any): void | Promise +``` + +#### Arguments + +- `message`: Sync message data from other nodes. + +#### Example + +```ts +handleSyncMessage(message: SyncMessage) { + console.log('handleSyncMessage', message); + // this.reloadData(); +} +``` diff --git a/docs/fr-FR/api/server/sync-message-manager.md b/docs/fr-FR/api/server/sync-message-manager.md new file mode 100644 index 000000000..dfb0d1e19 --- /dev/null +++ b/docs/fr-FR/api/server/sync-message-manager.md @@ -0,0 +1,37 @@ +# SyncMessageManager + +Used to manage synchronization signals between multiple application nodes. In a distributed deployment, when the memory state changes, it is necessary to notify other nodes for synchronization. `SyncMessageManager` provides a common interface to be invoked, allowing it to be used in same way across different modules. + +The SyncMessageManager itself does not implement specific synchronization functionality, but provides a unified interface, and it will invoke the underlying `pubSubManager` to send and receive messages. + +## `SyncMessageManager` + +### Members + +#### `constructor()` + +Constructor, creates an instance of the SyncMessageManager. An instance is automatically created during application initialization and is accessible globally within the application (`app.syncMessageManager`), so there is no need to call it. + +#### `subscribe(channel: string, callback: SyncEventCallback)` + +Subscribes to sync events. + +- `channel`: Channel name to differentiate between different sync events. +- `callback`: Event callback function, called when a sync event occurs. + +#### `unsubscribe(channel: string, callback: SyncEventCallback)` + +Unsubscribes from sync events. + +#### `publish(channel: string, message: any)` + +Publishes a sync message. + +- `channel`: Channel name to differentiate between different sync events. +- `message`: Sync message data. + +### Related Types + +```ts +export type PubSubCallback = (message: any) => Promise; +``` diff --git a/docs/fr-FR/api/telemetry/metric.md b/docs/fr-FR/api/telemetry/metric.md new file mode 100644 index 000000000..6a0cf636f --- /dev/null +++ b/docs/fr-FR/api/telemetry/metric.md @@ -0,0 +1,105 @@ +# Metric + +## Class Methods + +### `constructor()` + +Constructor to create a `Metric` instance. + +#### Signature + +- `constructor(options?: MetricOptions)` + +#### Type + +```ts +export type MetricOptions = { + meterName?: string; + version?: string; + readerName?: string | string[]; +}; +``` + +#### Details + +| Property | Type | Description | Default Value | +| ------------ | ---------------------- | ------------------------------------------------- | --------------------------- | +| `meterName` | `string` | Meter identifier | `nocobase-meter` | +| `version` | `string` | | Current version of NocoBase | +| `readerName` | `string` \| `string[]` | Identifier(s) of registered `MetricReader` to use | - | + +### `init()` + +Initializes `MetricProvider`. + +#### Signature + +- `init(): void` + +### `registerReader()` + +Registers a `MetricReader`. + +#### Signature + +- `registerReader(name: string, reader: GetMetricReader)` + +#### Type + +```ts +import { MetricReader } from '@opentelemetry/sdk-metrics'; + +type GetMetricReader = () => MetricReader; +``` + +#### Details + +| Parameter | Type | Description | +| --------- | -------------------- | ------------------------------------ | +| `name` | `string` | Unique identifier for `MetricReader` | +| `reader` | `() => MetricReader` | Function to get `MetricReader` | + +### `addView()` + +Adds a `View`. Refer to [Configure Metric Views](https://opentelemetry.io/docs/instrumentation/js/manual/#configure-metric-views). + +#### Signature + +- `addView(...view: View[])` + +#### Type + +```ts +import { View } from '@opentelemetry/sdk-metrics'; +``` + +### `getMeter()` + +Gets the `Meter`. + +#### Signature + +- `getMeter(name?: string, version?: string)` + +#### Details + +| Parameter | Type | Description | Default Value | +| --------- | -------- | ---------------- | --------------------------- | +| `name` | `string` | Meter identifier | `nocobase-meter` | +| `version` | `string` | | Current version of NocoBase | + +### `start()` + +Starts the `MetricReader`. + +#### Signature + +- `start(): void` + +### `shutdown()` + +Stops the `MetricReader`. + +#### Signature + +- `shutdown(): Promise` diff --git a/docs/fr-FR/api/telemetry/telemetry.md b/docs/fr-FR/api/telemetry/telemetry.md new file mode 100644 index 000000000..58a4eeed4 --- /dev/null +++ b/docs/fr-FR/api/telemetry/telemetry.md @@ -0,0 +1,67 @@ +# Telemetry + +## Overview + +`Telemetry` is the telemetry module of NocoBase, encapsulating OpenTelemetry support for registering metrics and traces within the OpenTelemetry ecosystem. + +## Class Methods + +### `constructor()` + +Constructor to create a `Telemetry` instance. + +#### Signature + +- `constructor(options?: TelemetryOptions)` + +#### Type + +```ts +export interface TelemetryOptions { + serviceName?: string; + version?: string; + trace?: TraceOptions; + metric?: MetricOptions; +} +``` + +#### Details + +| Property | Type | Description | Default Value | +| ------------- | --------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------- | +| `serviceName` | `string` | Optional. Refer to [Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/resource/#service) | `nocobase` | +| `version` | `string` | Optional. Refer to [Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/resource/#service) | Optional, current NocoBase version | +| `trace` | `TraceOptions` | Optional. Refer to [Trace](./trace.md) | - | +| `metric` | `MetricOptions` | Optional. Refer to [Metric](./metric.md) | - | + +### `init()` + +Registers instrumentation and initializes `Trace` and `Metric`. + +#### Signature + +- `init(): void` + +### `start()` + +Starts the processing of `Trace` and `Metric` related data, such as exporting to Prometheus. + +#### Signature + +- `start(): void` + +### `shutdown()` + +Stops the processing of `Trace` and `Metric` related data. + +#### Signature + +- `shutdown(): Promise` + +### `addInstrumentation()` + +Adds instrumentation libraries. + +#### Signature + +- `addInstrumentation(...instrumentation: InstrumentationOption[])` diff --git a/docs/fr-FR/api/telemetry/trace.md b/docs/fr-FR/api/telemetry/trace.md new file mode 100644 index 000000000..519b645e1 --- /dev/null +++ b/docs/fr-FR/api/telemetry/trace.md @@ -0,0 +1,91 @@ +# Trace + +## Class Methods + +### `constructor()` + +Constructor to create a `Trace` instance. + +#### Signature + +- `constructor(options?: TraceOptions)` + +#### Type + +```ts +export type TraceOptions = { + tracerName?: string; + version?: string; + processorName?: string | string[]; +}; +``` + +#### Details + +| Property | Type | Description | Default Value | +| --------------- | ---------------------- | -------------------------------------------------- | --------------------------- | +| `tracerName` | `string` | Trace identifier | `nocobase-trace` | +| `version` | `string` | | Current version of NocoBase | +| `processorName` | `string` \| `string[]` | Identifier(s) of registered `SpanProcessor` to use | - | + +### `init()` + +Initializes `NodeTracerProvider`. + +#### Signature + +- `init(): void` + +### `registerProcessor()` + +Registers a `SpanProcessor`. + +#### Signature + +- `registerProcessor(name: string, processor: GetSpanProcessor)` + +#### Type + +```ts +import { SpanProcessor } from '@opentelemetry/sdk-trace-base'; + +type GetSpanProcessor = () => SpanProcessor; +``` + +#### Details + +| Parameter | Type | Description | +| ----------- | --------------------- | ------------------------------------- | +| `name` | `string` | Unique identifier for `SpanProcessor` | +| `processor` | `() => SpanProcessor` | Function to get `SpanProcessor` | + +### `getTracer()` + +Gets the `Tracer`. + +#### Signature + +- `getTracer(name?: string, version?: string)` + +#### Details + +| Parameter | Type | Description | Default Value | +| --------- | -------- | ---------------- | --------------------------- | +| `name` | `string` | Trace identifier | `nocobase-trace` | +| `version` | `string` | | Current version of NocoBase | + +### `start()` + +Starts the `SpanProcessor`. + +#### Signature + +- `start(): void` + +### `shutdown()` + +Stops the `SpanProcessor`. + +#### Signature + +- `shutdown(): Promise` diff --git a/docs/fr-FR/api/test/client.md b/docs/fr-FR/api/test/client.md new file mode 100644 index 000000000..2d1e0177c --- /dev/null +++ b/docs/fr-FR/api/test/client.md @@ -0,0 +1,49 @@ +# Client + +## Overview + +NocoBase utilizes [Vitest](https://vitest.dev/) for client-side testing. `@nocobase/test/client` provides convenient methods for writing client-side test cases. + +## API + +### `defineConfig()` + +Retrieve the Vitest configuration. + +```ts +import { defineConfig } from '@nocobase/test/vitest.mjs'; + +const config = defineConfig(); +``` + +### `sleep()` + +Delay execution for a specified period of time. + +```ts +sleep(5000); +``` + +#### Signature + +- `sleep: (timeout?: number) => Promise` + +#### Details + +| Parameter | Type | Description | +| --------- | -------- | ------------------ | +| `timeout` | `number` | Delay time (in ms) | + +### @testing-library/react + +Used for testing React components. Refer to [React Testing Library](https://testing-library.com/docs/react-testing-library/intro). + +### @testing-library/user-event + +Used for simulating user interactions. Refer to [User Interactions](https://testing-library.com/docs/user-event/intro/). + +```ts +import { userEvent } from '@nocobase/test/client'; + +await userEvent.click(); +``` diff --git a/docs/fr-FR/api/test/e2e.md b/docs/fr-FR/api/test/e2e.md new file mode 100644 index 000000000..6e26bcc91 --- /dev/null +++ b/docs/fr-FR/api/test/e2e.md @@ -0,0 +1,190 @@ +# End-to-End + +## Overview + +NocoBase uses [Playwright](https://playwright.dev/) for end-to-end (E2E) testing and provides some mock methods to simplify test writing. + +### mockPage + +Generates a NocoBase page based on the configuration. + +**Signature** + +- `mockPage(pageConfig?: PageConfig): NocoPage` + +**Parameters** + +| Parameter | Type | Default | Description | +| ------------------------ | ----------------------------- | --------- | ---------------------------------------- | +| `pageConfig.type` | `'group' \| 'page' \| 'link'` | 'page' | Type of page | +| `pageConfig.name` | `string` | - | Name of the page visible to users | +| `pageConfig.url` | `string` | - | URL to navigate when `type` is 'link' | +| `pageConfig.basePath` | `string` | '/admin/' | Base path of the page | +| `pageConfig.collections` | `CollectionSetting[]` | - | Configuration of collections on the page | +| `pageConfig.pageSchema` | - | - | Schema of the entire page | + +**Example** + +Create an empty page that will be automatically deleted after the current test case finishes running. + +```ts +import { test } from '@nocobase/test/e2e'; + +test('learn how to use mockPage', async ({ mockPage }) => { + const nocoPage = await mockPage(); + await nocoPage.goto(); +}); +``` + +### mockManualDestroyPage + +Generates a page instance that needs to be manually destroyed. + +**Signature** + +- `mockManualDestroyPage(pageConfig?: PageConfig): NocoPage` + +**Parameters** + +Same as `mockPage`. + +**Example** + +Create an empty page that needs to be manually destroyed. Use this method when multiple test cases share the same page to avoid creating identical pages repeatedly. + +```ts +import { test } from '@nocobase/test/e2e'; + +let nocoPage; + +test.beforeAll(async ({ mockManualDestroyPage }) => { + nocoPage = await mockManualDestroyPage(); +}); + +test.afterAll(async () => { + await nocoPage.destroy(); +}); + +test('learn how to use mockManualDestroyPage', async ({ page }) => { + // Use page.goto method to navigate + await page.goto(nocoPage.getUrl()); +}); +``` + +### mockCollections + +Generates multiple collections based on the configuration. + +**Signature** + +- `mockCollections(collectionSettings: CollectionSetting[]): Promise` + +**Parameters** + +Refer to the definition of [CollectionSetting](https://github.com/nocobase/nocobase/blob/323b527aeb46aee2bc23387fddc54f39a9504739/packages/core/test/src/e2e/e2eUtils.ts#L11-L90) type. + +**Example** + +Create a collection named `posts`. + +```ts +import { test } from '@nocobase/test/e2e'; + +test('learn how to use mockCollections', async ({ mockCollections }) => { + await mockCollections([ + { + name: 'posts', + }, + ]); +}); +``` + +### mockCollection + +Generates a collection based on the configuration. + +**Signature** + +- `mockCollection(collectionSetting: CollectionSetting): Promise` + +**Parameters** + +Refer to the definition of [CollectionSetting](https://github.com/nocobase/nocobase/blob/323b527aeb46aee2bc23387fddc54f39a9504739/packages/core/test/src/e2e/e2eUtils.ts#L11-L90) type. + +**Example** + +Create a collection named `posts`. + +```ts +import { test } from '@nocobase/test/e2e'; + +test('learn how to use mockCollection', async ({ mockCollection }) => { + await mockCollection({ + name: 'posts', + }); +}); +``` + +### mockRecords + +Generates data for multiple collections. + +**Signature** + +- `mockRecords(collectionName: string, count?: number): Promise` +- `mockRecords(collectionName: string, records?: T[]): Promise` + +**Parameters** + +Refer to the type definition [here](https://github.com/nocobase/nocobase/blob/323b527aeb46aee2bc23387fddc54f39a9504739/packages/core/test/src/e2e/e2eUtils.ts#L166-L177). + +**Example** + +Create 10 records for the `posts` collection. + +```ts +import { test } from '@nocobase/test/e2e'; + +test('learn how to use mockRecords', async ({ mockRecords }) => { + await mockRecords('posts', 10); +}); +``` + +Customize the value of a field. + +```ts +import { test } from '@nocobase/test/e2e'; + +test('learn how to use mockRecords', async ({ mockRecords }) => { + // Create a record with the title 'hello world' + await mockRecords('posts', [ + { + title: 'hello world', + }, + ]); +}); +``` + +### mockRecord + +Generates data for a single collection. + +**Signature** + +- `mockRecord(collectionName: string, data?: T): Promise` + +**Parameters** + +Refer to the type definition [here](https://github.com/nocobase/nocobase/blob/323b527aeb46aee2bc23387fddc54f39a9504739/packages/core/test/src/e2e/e2eUtils.ts#L156-L162). + +**Example** + +Create a record for the `posts` collection. + +```ts +import { test } from '@nocobase/test/e2e'; + +test('learn how to use mockRecord', async ({ mockRecord }) => { + await mockRecord('posts'); +}); +``` diff --git a/docs/fr-FR/api/test/server.md b/docs/fr-FR/api/test/server.md new file mode 100644 index 000000000..1fc7ff5fc --- /dev/null +++ b/docs/fr-FR/api/test/server.md @@ -0,0 +1,157 @@ +# Server + +## Overview + +NocoBase conducts server-side testing based on [Vitest](https://vitest.dev/). `@nocobase/test` provides convenient methods for server-side testing to mock services and databases. + +### Basic Usage + +```ts +describe('actions', () => { + let app: MockServer; + let db: Database; + let agent: any; + + beforeAll(async () => { + app = await createMockServer({ + plugins: ['acl', 'users', 'data-source-manager'], + }); + db = app.db; + agent = app.agent(); + }); + + afterAll(async () => { + await app.destroy(); + }); +}); +``` + +## API + +### `defineConfig()` + +Retrieve the Vitest configuration. + +```ts +import { defineConfig } from '@nocobase/test/vitest.mjs'; + +const config = defineConfig(); +``` + +### `mockDatabase()` + +Create a `MockDataBase` instance for testing. + +#### Signature + +- `mockDatabase(options: IDatabaseOptions = {}): MockDatabase` + +#### Details + +| Parameter | Type | Description | +| --------- | ------------------ | ----------------------------------------- | +| `options` | `IDatabaseOptions` | Refer to [DataBase](../database/index.md) | + +### `mockServer()` + +Create a `MockServer` instance. + +#### Signature + +- `mockServer(options?: ApplicationOptions): MockServer` + +#### Details + +| Parameter | Type | Description | +| --------- | -------------------- | ------------------------------------------------ | +| `options` | `ApplicationOptions` | Refer to [Application](../server/application.md) | + +### `createMockServer()` + +Create a `MockServer` instance, perform forced installation, and start it. + +#### Signature + +```ts +createMockServer(options?: ApplicationOptions & { + version?: string; + beforeInstall?: BeforeInstallFn; + skipInstall?: boolean; + skipStart?: boolean; +}): Promise +``` + +#### Details + +| Parameter | Type | Description | +| ----------------------- | -------------------- | ------------------------------------------------ | +| `options` | `ApplicationOptions` | Refer to [Application](../server/application.md) | +| `options.version` | `string` | Application version | +| `options.beforeInstall` | `BeforeInstallFn` | Function to execute before installation | +| `options.skipInstall` | `boolean` | Whether to skip forced installation | +| `options.skipStart` | `boolean` | Whether to skip application startup | + +### `MockServer` + +`MockServer` inherits from `Application` and is a class for server-side testing applications. + +#### Class Methods + +##### `loadAndInstall()` + +Load and install the application. + +##### `cleanDb()` + +Clear the database. + +##### `quickstart()` + +Execute `nocobase start --quickstart`. + +##### `destroy()` + +Destroy the application. + +##### `agent()` + +Initiate API requests in test cases. + +**Signature** + +- `agent(): ExtendedAgent` + +**Type** + +```ts +interface ExtendedAgent extends SuperAgentTest { + login: (user: any) => ExtendedAgent; + loginUsingId: (userId: number) => ExtendedAgent; + resource: (name: string, resourceOf?: any) => Resource; +} +``` + +**Details** + +- `SuperAgentTest` + +Refer to [superagent](https://github.com/ladjs/superagent). + +- `login()` + +Log in with a user model. + +- `loginUsingId()` + +Log in with a user ID. + +- `resource()` + +Retrieve a resource. + +| Parameter | Type | Description | +| ------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `name` | `string` | 1. Resource name, e.g., `a`
    2. Associated object name of the resource, e.g., `a.b` | +| `resourceOf` | `any` | Primary key value of the resource when `resource` is the associated object name of the resource. For example, when `a.b` is specified, it represents the primary key value of `a`. | + +### sleep diff --git a/docs/fr-FR/breaking-changes/index.md b/docs/fr-FR/breaking-changes/index.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/fr-FR/breaking-changes/static/2023-12-13-12-52-32.png b/docs/fr-FR/breaking-changes/static/2023-12-13-12-52-32.png new file mode 100644 index 000000000..413d8b8df Binary files /dev/null and b/docs/fr-FR/breaking-changes/static/2023-12-13-12-52-32.png differ diff --git a/docs/fr-FR/breaking-changes/v0-17-0-alpha-1.md b/docs/fr-FR/breaking-changes/v0-17-0-alpha-1.md new file mode 100644 index 000000000..875be91b5 --- /dev/null +++ b/docs/fr-FR/breaking-changes/v0-17-0-alpha-1.md @@ -0,0 +1,463 @@ +# 0.17.0-alpha.1 + +:::warning +This article only covers incompatibility changes related to plugin development. +::: + +## Changes to SchemaInitializer + +- Added `SchemaInitializerManager` for registering `SchemaInitializer` +- Added `useSchemaInitializerRender()` to replace the original `useSchemaInitializer()` `render()` +- Added `useSchemaInitializerItem()` for obtaining the context of the current initialization item +- Added `SchemaInitializerItemGroup` component as the default component for `type: 'itemGroup'` +- Added `SchemaInitializerSubMenu` component as the default component for `type: 'subMenu'` +- Added `SchemaInitializerDivider` component as the default component for `type: 'divider'` +- Added `SchemaInitializerChildren` component for custom rendering of multiple list items +- Added `SchemaInitializerChild` component for custom rendering of a single list item +- Changed the responsibilities of `SchemaInitializerContext` for storing the context of the current initializer +- Changed the responsibilities of `useSchemaInitializer()` for obtaining the context of the current initializer +- Changed `function SchemaInitializer` to `class SchemaInitializer` for defining initializer +- Changed parameters of `SchemaInitializer` + - Added `name` required parameter for the value of `x-initializer` + - Added `Component` parameter for custom rendering of the button. Default is `SchemaInitializerButton`. + - Added `componentProps`, `style` for configuring the properties and style of `Component` + - Added `ItemsComponent` parameter for custom rendering of the list. Default is `SchemaInitializerItems`. + - Added `itemsComponentProps`, `itemsComponentStyle` for configuring the properties and style of `ItemsComponent` + - Added `popover` parameter for configuring whether to display the `popover` effect + - Added `useInsert` parameter for when the `insert` function needs to use hooks + - Changed `dropdown` parameter to `popoverProps`, using `Popover` instead of `Dropdown` +- Changed parameters of `items` for `SchemaInitializer` + - Added `useChildren` function for dynamically controlling child items + - Added `componentProps` function for the properties of the component itself + - Added `useComponentProps` function for dynamically processing the props of the component + - Changed `key` parameter to `name` for the unique identification of list items + - Changed `visible` parameter to `useVisible` function for dynamically controlling whether to display + - Changed `component` parameter to `Component` for rendering list items +- Changed `SchemaInitializer.Button` to `SchemaInitializerButton`, the default value for the Component parameter of SchemaInitializer +- Changed `SchemaInitializer.Item` to `SchemaInitializerItem`, with unchanged parameters +- Changed `SchemaInitializer.ActionModal` to `SchemaInitializerActionModal`, with unchanged parameters +- Changed `SchemaInitializer.SwitchItem` to `SchemaInitializer.Switch`, with unchanged parameters +- Deleted `SchemaInitializerProvider`, replaced by `SchemaInitializerManager` +- Deleted `SchemaInitializer.itemWrap`, no longer need to wrap the `item` component + +For more information, refer to the following documentation: + +- [Plugin Development / Schema Initializer](/development/client/ui-schema/initializer) +- [API Documentation / SchemaInitializer](https://client.docs.nocobase.com/core/ui-schema/schema-component) + +### Adding items to an existing initializer + +In the past, we used to get all the `Initializers` through `SchemaInitializerContext` and then add, delete or change them. For example, the following code adds `Hello` to `media` in `BlockInitializers`: + +```tsx | pure +const items = useContext(SchemaInitializerContext); +const mediaItems = items.BlockInitializers.items.find( + (item) => item.key === 'media', +); + +if (process.env.NODE_ENV !== 'production' && !mediaItems) { + throw new Error('media block initializer not found'); +} + +const children = mediaItems.children; +if (!children.find((item) => item.key === 'hello')) { + children.push({ + key: 'hello', + type: 'item', + title: '{{t("Hello block")}}', + component: HelloBlockInitializer, + }); +} +``` + +The new way to add items is to use the `schemaInitializerManager.addItem()` method in the load method of the plugin. + +```tsx | pure +class MyPlugin extends Plugin { + async load() { + this.schemaInitializerManager.addItem( + 'BlockInitializers', + 'otherBlocks.hello', + { + title: '{{t("Hello block")}}', + Component: HelloBlockInitializer, + }, + ); + } +} +``` + +Detailed documentation reference + +- [Plugin Development / Schema Initializer / Adding items to an existing initializer](/development/client/ui-schema/initializer) +- [API Documentation / SchemaInitializer / Built-in components and types](https://client.docs.nocobase.com/core/ui-schema/schema-initializer) + +### Add the new initializer to the application + +Previously added via `SchemaInitializerProvider`, for example: + +```tsx | pure + +``` + +Now add it in the load of the plugin, for example: + +```tsx | pure +import { Plugin } from '@nocobase/client'; + +class MyPlugin extends Plugin { + async load() { + this.app.schemaInitializerManager.add(blockInitializers); + this.app.addComponents({ ManualActionDesigner }); + } +} +``` + +For detailed documentation refer to + +- [Plugin Development / Schema Initializer / Add New Initializer](/development/client/ui-schema/initializer) +- [API Documentation / SchemaInitializerManager / schemaInitializerManager.addItem()](https://client.docs.nocobase.com/core/ui-schema/schema-initializer-manager) + +### Add new initializer + +Before `SchemaInitializer` support JSON object and component writing, now only `new SchemaInitializer()`. + +Example 1: The old way of writing JSON is changed to `new SchemaInitializer()`. + +```diff +- export const BlockInitializers = { ++ export const blockInitializers = new SchemaInitializer({ ++ name: 'BlockInitializers', + 'data-testid': 'add-block-button-in-page', + title: '{{t("Add block")}}', + icon: 'PlusOutlined', + wrap: gridRowColWrap, + items: [ + { +- key: 'dataBlocks', ++ name: 'data-blocks', + type: 'itemGroup', + title: '{{t("Data blocks")}}', + children: [ + { +- key: 'table', ++ name: 'table', +- type: 'item', + title: '{{t("Table")}}', +- component: TableBlockInitializer, ++ Component: TableBlockInitializer, + }, + { + key: 'form', + type: 'item', + title: '{{t("Form")}}', + component: FormBlockInitializer, + } + ], + }, + ], +}); +``` + +Example 2: Modify the way the component is written to `new SchemaInitializer()`. + +Turns out it's the way components are defined: + +```tsx | pure +export const BulkEditFormItemInitializers = (props: any) => { + const { t } = useTranslation(); + const { insertPosition, component } = props; + const associationFields = useAssociatedFormItemInitializerFields({ + readPretty: true, + block: 'Form', + }); + return ( + + ); +}; +``` + +Now it needs to be changed to the `new SchemaInitializer()` approach: + +```tsx | pure +const bulkEditFormItemInitializers = new SchemaInitializer({ + name: 'BulkEditFormItemInitializers', + 'data-testid': 'configure-fields-button-of-bulk-edit-form-item', + wrap: gridRowColWrap, + icon: 'SettingOutlined', + // 原 insertPosition 和 component 是透传的,这里不用管,也是透传的 + items: [ + { + type: 'itemGroup', + title: t('Display fields'), + name: 'displayFields', // 记得加上 name + useChildren: useCustomBulkEditFormItemInitializerFields, // 使用到了 useChildren + }, + { + type: 'divider', + }, + { + title: t('Add text'), + name: 'addText', + Component: BlockItemInitializer, // component 替换为 Component + }, + ], +}); +``` + +For detailed documentation refer to + +- [Plugin Development / Schema Initializer / Add new initializer](/development/client/ui-schema/initializer) +- [API Documentation / SchemaInitializer / new SchemaInitializer(options)](https://client.docs.nocobase.com/core/ui-schema/schema-initializer) + +### Item definition and implementation + +Previously, when configuring an Item, the props of the components were placed in the item, but now it is recommended to use `componentProps` and `useComponentProps`. + +```diff +{ + name: 'BlockInitializers', + items: [ + { + name: 'xxx', + Component: XXXSchemaInitializerItem, + title: 'Title 1', + schema: {}, +- foo: 'bar', ++ useComponentProps: () => { ++ return { foo: 'bar' } ++ } + } + ] +} +``` + +In the Item component, Item configuration used to be passed directly by props, but now it is obtained by `useSchemaInitializerItem()`, and the related hooks are included: + +- `useSchemaInitializer()` to get the current initializer context. +- `useSchemaInitializerItem()` gets the context of the current item. + +```diff +const XXXSchemaInitializerItem = (props) => { +- const { insert, title, schema, foo } = props; ++ const { foo } = props; ++ const { insert } = useSchemaInitializer(); ++ const { title, schema } = useSchemaInitializerItem(); + // ... +} +``` + +Detailed Documentation Reference + +- [API Documentation / SchemaInitializer / Built-in Components and Types](https://client.docs.nocobase.com/core/ui-schema/schema-initializer) + +## Changes to SchemaSettings + +- Added `SchemaSettingsManager` for registering `SchemaSettings` +- Added `useSchemaSettingsItem()` +- Added `useSchemaSettingsRender()` +- Added `x-settings` parameter for configuring schema settings +- Added `x-toolbar` parameter for configuring schema toolbar +- Added `SchemaToolbar` component for customizing schema toolbar +- Added `useSchemaToolbarRender()` to replace the original `useDesigner()` +- Changed `function SchemaSettings` to `class SchemaSettings` for defining settings +- Changed the original `SchemaSettings` to `SchemaSettingsDropdown` +- Changed `SchemaSettings.Item` to `SchemaSettingsItem` +- Changed `SchemaSettings.ItemGroup` to `SchemaSettingsItemGroup` +- Changed `SchemaSettings.SubMenu` to `SchemaSettingsSubMenu` +- Changed `SchemaSettings.Divider` to `SchemaSettingsDivider` +- Changed `SchemaSettings.Remove` to `SchemaSettingsRemove` +- Changed `SchemaSettings.SelectItem` to `SchemaSettingsSelectItem` +- Changed `SchemaSettings.CascaderItem` to `SchemaSettingsCascaderItem` +- Changed `SchemaSettings.SwitchItem` to `SchemaSettingsSwitchItem` +- Changed `SchemaSettings.ModalItem` to `SchemaSettingsModalItem` +- Changed `SchemaSettings.ActionModalItem` to `SchemaSettingsActionModalItem` +- Deleted `x-designer` parameter, deprecated, will be removed in the future, use `x-toolbar` instead +- Deleted `useDesigner()`, deprecated, will be removed in the future, use `useSchemaToolbarRender()` instead + +Related Documentation + +- [Plugin Development / SchemaSettings Settings](/development/client/ui-schema/initializer) +- [Plugins / SchemaToolbar](/development/client/ui-schema/initializer) +- [API Documentation / SchemaSettings](https://client.docs.nocobase.com/core/ui-schema/schema-component) +- [API Documentation / SchemaSettingsManager](https://client.docs.nocobase.com/core/ui-schema/schema-component) +- [API Documentation / SchemaToolbar](https://client.docs.nocobase.com/core/ui-schema/schema-component) + +### Settings definition and implementation + +Previously SchemaSettings was implemented with GeneralSchemaDesigner and used in `x-designer`. + +```tsx | pure + + {}} + > + + + +``` + +Now split the two into `x-toolbar` and `x-settings`, with `x-toolbar` missing and SchemaSettings used in `x-settings`. + +```ts +const mySettings = new SchemaSettings({ + name: 'MySettings', + items: [ + { + name: 'enableHeader', + type: 'switch', + componentProps: { + title: 'Enable Header', + onClick: () => {}, + }, + }, + { + name: 'divider', + type: 'divider', + }, + { + name: 'xxx', + type: 'modal', + useComponentProps() { + // useSchemaDesigner() 会传入 props + const { onSubmit } = useSchemaDesigner(); + return { + title: 'xxx', + schema: {}, + onSubmit, + }; + }, + }, + ], +}); +``` + +Changes in the schema + +```diff +{ + type: 'void', +- 'x-designer': 'CustomButton.Designer' ++ 'x-toolbar': 'CustomButtonToolbar', // 非必须 ++ 'x-settings': 'CustomButtonSettings', + 'x-component': 'CustomButton', + 'x-content': 'Hello2', +} +``` + +### Implementation of Item for Settings + +The previous version of the Item component was very tedious to implement, but now we use useSchemaSettings() to get the Designable of the current Schema, and use the Designable to modify the current Schema. + +```diff +function EditBlockTitle(props) { +- const field = useField(); +- const fieldSchema = useFieldSchema(); +- const { dn } = useDesignable(); ++ const { dn } = useSchemaSettings(); + + return ( + { +- field.decoratorProps.title = title; +- fieldSchema['x-decorator-props'] = fieldSchema['x-decorator-props'] || {}; +- fieldSchema['x-decorator-props'].title = title; +- dn.emit('patch', { +- schema: { +- ['x-uid']: fieldSchema['x-uid'], +- 'x-decorator-props': { +- ...fieldSchema['x-decorator-props'], +- }, +- }, +- }); +- dn.refresh(); ++ dn.deepMerge({ ++ 'x-decorator-props': { ++ title, ++ }, ++ }); + }} + /> + ); +} +``` + +Related Documentation Reference + +- [Plugin Development / SchemaSettings Setter / How to implement Schema settings](/development/client/ui-schema/settings) +- [Plugin Development / Designable Designer](/development/client/ui-schema/designable) +- [API Reference / SchemaSettings / Built-in Components and Types](https://client.docs.nocobase.com/core/ui-schema/schema-settings) +- [API Reference / Designable](https://client.docs.nocobase.com/core/ui-schema/designable) + +## Other + +### app.addComponent method privatization + +The `app.addComponent` method is privatized and no longer exposed to the public, you need to register the component via the `app.addComponents` method. + +```diff +- app.addComponent(MyComponent, 'MyComponent') ++ app.addComponents({ MyComponent }) +``` + +### Delete the `PluginManagerContext`. + +```diff +const MyProvider = props => { +- const ctx = useContext(PluginManagerContext); +return

    +- + {/* ... */} +- +
    +} +``` diff --git a/docs/fr-FR/breaking-changes/v0-17-0-alpha-3.md b/docs/fr-FR/breaking-changes/v0-17-0-alpha-3.md new file mode 100644 index 000000000..78774a0fd --- /dev/null +++ b/docs/fr-FR/breaking-changes/v0-17-0-alpha-3.md @@ -0,0 +1,29 @@ +# 0.17.0-alpha.3 + +## Localization management + +### Background + +Refer to Update(localization-management):Organize text namespaces by modules + +### Translation texts are no longer deduplicated + +Duplicate texts across modules require separate translations. + +![](https://static-docs.nocobase.com/1c5fd02f1348787e1833bd3ece36c9aa.png) + +### Removed `fallbackNS` option from `i18n` instance + +The `i18n` instance of client no longer includes the option `fallbackNS: "client"`. + +For plugin developers, if language files in a plugin omit some texts already present in the core client, it's necessary to supplement them. If you still want to reuse content from `packages/core/client/src/locale`, pass the appropriate parameters when using it, for example: + +```ts +import { useTranslation } from 'react-i18next'; + +export const NAMESPACE = 'localization-management'; + +export const useLocalTranslation = () => { + return useTranslation([NAMESPACE, 'client'], { nsMode: 'fallback' }); +}; +``` \ No newline at end of file diff --git a/docs/fr-FR/breaking-changes/v0-17-0-alpha-5.md b/docs/fr-FR/breaking-changes/v0-17-0-alpha-5.md new file mode 100644 index 000000000..0947c476f --- /dev/null +++ b/docs/fr-FR/breaking-changes/v0-17-0-alpha-5.md @@ -0,0 +1,82 @@ +# 0.17.0-alpha.5 + +## Server `ctx.state.currentUser` + +### Background + +The new version introduces caching for the user information stored in `ctx.state.currentUser`. + +Previously, `ctx.state.currentUser` stored a Sequelize UserModel object: + +```json +{ + "dataValues": { + "username": "nocobase" + // Other user information + } + // Other Model properties +} +``` + +The actual user information is located in `dataValues`. You can access the corresponding properties through a `getter` accessor or use methods provided by Sequelize Model like `get`, `setDataValues`, `toJSON`, etc. + +With the addition of caching, if the user selects a caching method other than in-memory caching, retrieving results from the cache will yield a plain object. Consequently, Model-related methods used in the code will throw exceptions. + +### Changes + +`ctx.state.currentUser` now directly utilizes a plain object containing user information, specifically the contents of `dataValues` of the original Model. + +```json +{ + "username": "nocobase" + // Other user information +} +``` + +Model-related methods no longer apply to `ctx.state.currentUser`. + +#### Accessing User Attributes + +Previously + +```ts +ctx.state.currentUser.get('id'); +// or +ctx.state.currentUser.id; +``` + +Now + +```ts +// Only applicable method +ctx.state.currentUser.id; +``` + +#### Modifying User Attributes + +Previously + +```ts +ctx.state.currentUser.setDataValues('roles', roles); +// or +ctx.state.currentUser.roles = roles; +``` + +Now + +```ts +// Only applicable method +ctx.state.currentUser.roles = roles; +``` + +#### Retrieving User Information Object + +Previously + +```ts +ctx.state.currentUser.toJSON(); +``` + +Now + +Deprecated. `ctx.state.currentUser` itself represents the result of `toJSON` on the UserModel. diff --git a/docs/fr-FR/breaking-changes/v0-18-0-alpha-1.md b/docs/fr-FR/breaking-changes/v0-18-0-alpha-1.md new file mode 100644 index 000000000..2164ef786 --- /dev/null +++ b/docs/fr-FR/breaking-changes/v0-18-0-alpha-1.md @@ -0,0 +1,130 @@ +# 0.18.0-alpha.1 + +:::warning +This article only covers incompatibility changes related to plugin development. +::: + +## Test framework changed from jest to vitest + +- [Server - Testing](/development/server/test) +- [Client - Testing](/development/client/test) + +## Authentication Client API changes + +### Background + +Previously, when developing the client for a custom authentication method, it was based on React `Context`. +It utilized the `Provider` to extend custom sign-in, sign-up, and admin settings forms. For example: + +```html + + + + {props.children} + + + +``` + +It was required nested Providers, leading to less concise and intuitive code. + +### Changes + +Now the client for a custom authentication can be registered by utilizing the `registerType` method provided by the [authentication plugin `@nocobase/plugin-auth`](../plugins/auth/index.md). + +```ts +export type AuthOptions = { + components: Partial<{ + SignInForm: ComponentType<{ authenticator: AuthenticatorType }>; + SignInButton: ComponentType<{ authenticator: AuthenticatorType }>; + SignUpForm: ComponentType<{ authenticatorName: string }>; + AdminSettingsForm: ComponentType; + }>; +}; + +export class AuthPlugin extends Plugin { + registerType(authType: string, options: AuthOptions); +} +``` + +### Example + +#### Customize sign-in form + sign-up form + admin settings form + +```diff +- import { OptionsComponentProvider, SigninPageProvider, SignupPageProvider } from '@nocobase/client'; ++ import AuthPlugin from '@nocobase/plugin-auth/client'; + import React, { FC } from 'react'; + import { Options } from './basic/Options'; + import SignInForm from './basic/SignInForm'; + import SignUpForm from './basic/SignUpForm'; + +- export const BasicAuthPluginProvider: FC = (props) => { +- return ( +- +- +- +- {props.children} +- +- +- +- ); +- } + + export class BasicAuthPlugin extends Plugin { + async load() { +- this.app.use(BasicAuthPluginProvider); ++ const auth = this.app.pm.get(AuthPlugin); ++ auth.registerType("Email/Password", { ++ components: { ++ SignInForm: SignInForm, ++ SignUpForm: SignUpForm, ++ AdminSettingsForm: Options, ++ }, ++ }); + } + } +``` + +#### Customize sign-in (thirt-party) button + admin settings form + +```diff +- import { OptionsComponentProvider, SigninPageExtensionProvider } from '@nocobase/client'; ++ import AuthPlugin from '@nocobase/plugin-auth/client'; + import React, { FC } from 'react'; + import { OIDCButton } from './OIDCButton'; + import { Options } from './Options'; + +- export const OIDCProvider: FC = (props) => { +- return ( +- +- +- {props.children} +- +- +- ); +- }; + + export class OidcPlugin extends Plugin { + async load() { +- const auth = this.app.pm.get(AuthPlugin); ++ auth.registerType("OIDC", { ++ components: { ++ SignInButton: OIDCButton, ++ AdminSettingsForm: Options, ++ }, ++ }); + } + } +``` + +For more details, refer to the documentation: [Authentication - Development](../plugins/auth/dev/guide.md) + +### Removed + +The following `Provider` has been removed: + +- `SigninPageProvider` +- `SignupPageProvider` +- `OptionsComponentProvider` +- `SigninExtensionProvider` diff --git a/docs/fr-FR/breaking-changes/v0.19.0-alpha.1.md b/docs/fr-FR/breaking-changes/v0.19.0-alpha.1.md new file mode 100644 index 000000000..fe8c2b827 --- /dev/null +++ b/docs/fr-FR/breaking-changes/v0.19.0-alpha.1.md @@ -0,0 +1,101 @@ +# 0.19.0-alpha.1 + +:::warning +This article only covers incompatibility changes related to plugin development. +::: + +## Collections, commands, migrations configuration changes to convention-based directories + +Example 1: Collections loaded by importCollections, the code is deleted directly, and the collections configuration file must be placed in the `src/server/collections` directory. + +```diff +export class AuthPlugin extends Plugin { + async load() { +- await this.importCollections(resolve(__dirname, 'collections')); + } +} +``` + +Example 2: Collections loaded through this.db.import, the code is directly deleted, the collections configuration file must be placed in the `src/server/collections` directory + +```diff +export class AuthPlugin extends Plugin { + async load() { +- await this.db.import({ +- directory: resolve(__dirname, 'collections') +- }); + } +} +``` + +Example 3: A collection defined by db.collection() is recommended to be placed in the `src/server/collections` directory. + +```diff +export class AuthPlugin extends Plugin { + async load() { +- this.db.collection({ +- name: 'examples', +- }); + } +} +``` + +Add a new `src/server/collections/examples.ts` file with the following contents: + +```typescript +import { defineCollection } from '@nocobase/database'; + +export default defineCollection({ + name: 'examples', +}); +``` + +Example 4: Remove db.addMigrations() and place the migration file in the `src/server/migrations` directory. + +```diff +export class AuthPlugin extends Plugin { + async load() { +- this.db.addMigrations({ +- namespace: 'auth', +- directory: resolve(__dirname, 'migrations'), +- context: { +- plugin: this, +- }, +- }); + } +} +``` + +Example 5: Customizing the command line + +```diff +export class MyPlugin extends Plugin { + load() { +- this.app +- .command('echo') +- .option('-v, --version'); +- .action(async ([options]) => { +- console.log('Hello World!'); +- if (options.version) { +- console.log('Current version:', app.getVersion()); +- } +- }); +- } +} +``` + +Add a new `src/server/collections/echo.ts` file with the following contents: + +```typescript +export default function(app) { + app + .command('echo') + .option('-v, --version'); + .action(async ([options]) => { + console.log('Hello World!'); + if (options.version) { + console.log('Current version:', await app.version.get()); + } + }); +} +``` \ No newline at end of file diff --git a/docs/fr-FR/components.md b/docs/fr-FR/components.md new file mode 100644 index 000000000..0eac4eb52 --- /dev/null +++ b/docs/fr-FR/components.md @@ -0,0 +1 @@ +# Components diff --git a/docs/fr-FR/development/app-ds.md b/docs/fr-FR/development/app-ds.md new file mode 100644 index 000000000..bbf2cabaf --- /dev/null +++ b/docs/fr-FR/development/app-ds.md @@ -0,0 +1,76 @@ +# Directory Structure + +Whether it is a NocoBase application created via [Git source](/welcome/getting-started/installation/git-clone) or [create-nocobase-app](/welcome/getting-started/installation/create-nocobase-app), the directory structure is the same, as follows: + +```bash +├── my-nocobase-app + ├── packages # Packages under development + ├── plugins # Plugins under development + ├── storage # Used to store database files, attachments, cache, etc. + ├── backups # Backup files directory + ├── plugins # Plug-and-play plugins (already compiled) + ├── tar # Location for storing output of yarn build --tar + ├── uploads # Local storage directory + ├── .env # Environment variables + ├── .env.e2e # Environment variables for e2e tests yarn e2e test + ├── .env.test # Environment variables for unit tests yarn test + ├── lerna.json + ├── package.json + ├── playwright.config.ts + ├── tsconfig.json + ├── tsconfig.server.json + ├── vitest.config.mts +``` + +## Plugins Directory + +Plugins under development are stored in the `packages/plugins` directory, organized as npm packages, example as below: + +```bash +|- /packages/ + |- /plugins/ + |- /@nocobase/ + |- /plugin-hello1/ + |- /plugin-hello2/ + |- /my-nocobase-plugin-hello1/ + |- /my-nocobase-plugin-hello2/ +``` + +Plugins added via the interface are stored in the `storage/plugins` directory, organized as npm packages, example as below: + +```bash +|- /storage/ + |- /plugins/ + |- /@nocobase/ + |- /plugin-hello1/ + |- /plugin-hello2/ + |- /my-nocobase-plugin-hello1/ + |- /my-nocobase-plugin-hello2/ +``` + +Built-in plugins or plugins declared in the `dependencies` of `package.json` will all be in `node_modules`, example as below: + +```bash +|- /node_modules/ + |- /@nocobase/ + |- /plugin-acl/ + |- /plugin-auth/ +``` + +## Plugin Directory Structure + +You can quickly create an empty plugin with `yarn pm create @my-project/plugin-hello`. The directory structure is as follows: + +```bash +|- /packages/plugins/@my-project/plugin-hello + |- /dist # The produсt of build + |- /src + |- /client # Plugin client code + |- /server # Plugin server code + |- .npmignore # Which files or directories should be ignored when publishing the plugin package + |- client.d.ts + |- client.js + |- package.json # Plugin package information + |- server.d.ts + |- server.js +``` \ No newline at end of file diff --git a/docs/fr-FR/development/client/api-client.md b/docs/fr-FR/development/client/api-client.md new file mode 100644 index 000000000..fbd1fcf68 --- /dev/null +++ b/docs/fr-FR/development/client/api-client.md @@ -0,0 +1,121 @@ +# HTTP Request + +NocoBase provides an `APIClient` for making HTTP requests. Within the [plugin lifecycle](/development/client#插件的声明周期) of a client-side application, you can use `app.apiClient` to make client-side requests. Inside components, you can use `useAPIClient()` and `useRequest()`. + +## app.apiClient + +```ts +class PluginSampleAPIClient extends Plugin { + async load() { + const { data } = await this.app.apiClient.request({ url: 'test' }); + } +} +``` + +--- + +### apiClient.request() + +For standard requests, refer to axios's [request config](https://axios-http.com/docs/req_config) for more details on usage. + +```ts +class APIClient { + // Client-side requests, supporting AxiosRequestConfig and ResourceActionOptions + request, D = any>( + config: AxiosRequestConfig | ResourceActionOptions, + ): Promise; +} +``` + +Example: + +```ts +const response = await apiClient.request({ url }); +``` + +### apiClient.axios + +`AxiosInstance` instance + +It can be used to modify axios's [default configuration](https://axios-http.com/docs/config_defaults). + +```ts +axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; +axios.defaults.headers.post['Content-Type'] = + 'application/x-www-form-urlencoded'; +``` + +It can also be used to [intercept requests or responses](https://axios-http.com/docs/interceptors). + +```ts +// Add request interceptor: use qs to convert params +axios.interceptors.request.use((config) => { + config.paramsSerializer = (params) => { + return qs.stringify(params, { + strictNullHandling: true, + arrayFormat: 'brackets', + }); + }; + return config; +}); + +// Add request interceptor: customize request headers +axios.interceptors.request.use((config) => { + config.headers['Authorization'] = `Bearer token123`; + config.headers['X-Hostname'] = `localhost`; + config.headers['X-Timezone'] = `+08:00`; + config.headers['X-Locale'] = 'zh-CN'; + config.headers['X-Role'] = 'admin'; + config.headers['X-Authenticator'] = 'basic'; + config.headers['X-App'] = 'sub1'; + return config; +}); + +// Add response interceptor +axios.interceptors.response.use( + (response) => response, + (error) => { + // Notify the user about the error + notification.error({ + message: 'Request Response Error', + }); + }, +); +``` + +### Custom Request Headers in NocoBase Server + +- `X-App`: Specify the current app when using multiple apps. +- `X-Locale`: Current language. +- `X-Hostname`: Client hostname. +- `X-Timezone`: Client timezone. +- `X-Role`: Current role. +- `X-Authenticator`: Current user authentication method. + +## useAPIClient() + +Within a component, you can use `useAPIClient()` to get the APIClient instance of the current app, which is equivalent to `app.apiClient`. + +## useRequest() + +Asynchronous data management, which can either be data from client requests or a custom asynchronous function. For detailed usage, refer to ahooks's [useRequest()](https://ahooks.js.org/hooks/use-request/index). + +```ts +function useRequest

    ( + service: AxiosRequestConfig

    | ResourceActionOptions

    | FunctionService, + options?: Options, +); +``` + +Example: + +```ts +const { data, loading, refresh, run, params } = useRequest({ url: '/users' }); + +// Since useRequest accepts AxiosRequestConfig, the run function also accepts AxiosRequestConfig. +run({ + params: { + pageSize: 20, + }, +}); +``` diff --git a/docs/fr-FR/development/client/demos/demo1.tsx b/docs/fr-FR/development/client/demos/demo1.tsx new file mode 100644 index 000000000..93dd69471 --- /dev/null +++ b/docs/fr-FR/development/client/demos/demo1.tsx @@ -0,0 +1,20 @@ +import { Application, Plugin } from '@nocobase/client'; +import React from 'react'; + +class PluginHello extends Plugin { + async load() { + this.router.add('hello', { + path: '/', + Component: () =>

    Hello NocoBase
    , + }); + } +} + +const app = new Application({ + router: { + type: 'hash', + }, + plugins: [PluginHello], +}); + +export default app.getRootComponent(); \ No newline at end of file diff --git a/docs/fr-FR/development/client/demos/demo2.tsx b/docs/fr-FR/development/client/demos/demo2.tsx new file mode 100644 index 000000000..ecc31eb5a --- /dev/null +++ b/docs/fr-FR/development/client/demos/demo2.tsx @@ -0,0 +1,44 @@ +import { + Application, + Plugin, + SchemaComponent, + SchemaComponentProvider, +} from '@nocobase/client'; +import React from 'react'; + +const Hello = () =>

    Hello NocoBase

    ; + +const HelloPage = () => { + return ( + + ); +}; + +class PluginHello extends Plugin { + async load() { + this.app.addProvider(SchemaComponentProvider, { + components: this.app.components, + scopes: this.app.scopes, + }); + this.app.addComponents({ Hello }); + this.router.add('hello', { + path: '/', + Component: HelloPage, + }); + } +} + +const app = new Application({ + router: { + type: 'memory', + }, + plugins: [PluginHello], +}); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/demos/demo3.tsx b/docs/fr-FR/development/client/demos/demo3.tsx new file mode 100644 index 000000000..37b599d0c --- /dev/null +++ b/docs/fr-FR/development/client/demos/demo3.tsx @@ -0,0 +1,113 @@ +import { useFieldSchema } from '@formily/react'; +import { + Application, + CardItem, + Grid, + Plugin, + SchemaComponent, + SchemaInitializer, + SchemaInitializerItem, + SchemaSettings, + useSchemaComponentContext, + useSchemaInitializer, + useSchemaInitializerItem, +} from '@nocobase/client'; +import { Button } from 'antd'; +import React from 'react'; + +const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [ + { + name: 'remove', + type: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + }, + }, + ], +}); + +const myInitializer = new SchemaInitializer({ + name: 'MyInitializer', + // 按钮标题标题 + title: 'Button Text', + wrap: Grid.wrap, + // 调用 initializer.render() 时会渲染 items 列表 + items: [ + { + name: 'demo1', + title: 'Demo1', + Component: () => { + const itemConfig = useSchemaInitializerItem(); + // 调用插入功能 + const { insert } = useSchemaInitializer(); + const handleClick = () => { + insert({ + type: 'void', + 'x-settings': 'mySettings', + 'x-decorator': 'CardItem', + 'x-component': 'Hello', + }); + }; + return ; + }, + }, + ], +}); + +const Hello = () => { + const schema = useFieldSchema(); + return

    Hello, world! {schema.name}

    +}; + +const Btn = () => { + const { designable, setDesignable } = useSchemaComponentContext(); + return ( + + ); +}; + +const HelloPage = () => { + return ( +
    + + +
    + ); +}; + +class PluginHello extends Plugin { + async load() { + this.app.addComponents({ Grid, CardItem, Hello }); + this.app.schemaSettingsManager.add(mySettings); + this.app.schemaInitializerManager.add(myInitializer); + this.router.add('hello', { + path: '/', + Component: HelloPage, + }); + } +} + +const app = new Application({ + router: { + type: 'memory', + }, + plugins: [PluginHello], +}); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/i18n.md b/docs/fr-FR/development/client/i18n.md new file mode 100644 index 000000000..b76849682 --- /dev/null +++ b/docs/fr-FR/development/client/i18n.md @@ -0,0 +1,113 @@ +# Internationalization + +## Internationalization Files + +In the plugin, both front-end and back-end multilingual files are stored in the `src/locale` folder. You can view [all supported languages](#) in NocoBase by clicking here. + +```bash +|- /plugin-sample-i18n + |- /src + |- /locale # Multilingual files + |- en_US.ts # English language + |- zh_CN.ts # Chinese language +``` + +To add translation entries, simply update the corresponding multilingual file (`/src/locale/${lang}.ts`). If you're adding a new language file for the first time, you’ll need to restart the application for the changes to take effect. You can verify the successful addition of translation entries by checking the `app:getLang` interface. + +http://localhost:13000/api/app:getLang?locale=zh-CN + +## How to Support Internationalization + +### app.i18n Instance + +```ts +import { Plugin } from '@nocobase/client'; + +class PluginDemoClient extends Plugin { + async load() { + // i18n instance + this.app.i18n; + this.app.i18n.t('hello'); + await this.app.i18n.changeLanguage('zh-CN'); + } +} +``` + +The i18n implementation is based on i18next. For more detailed instructions, refer to the [I18next API Documentation](https://www.i18next.com/overview/api). + +### React Hook Method + +```ts +import { useApp } from '@nocobase/client'; +import { useTranslation } from 'react-i18next'; + +const { i18n } = useApp(); +const { t } = useTranslation('@nocobase/plugin-sample-i18n'); +t('hello'); +// Equivalent to +i18n.t('hello', { ns: '@nocobase/plugin-sample-i18n' }); +``` + +For detailed usage of `useTranslation()`, refer to the [react-i18next Documentation](https://react.i18next.com/). + +### Namespace + +Each plugin’s locale is distinguished by its namespace (ns), which corresponds to the plugin name, like this: + +```ts +app.i18n.t('Hello', { ns: '@nocobase/plugin-sample-i18n' }); +``` + +### tval Method + +When used in schema: + +```ts +const schema = { + type: 'string', + title: '{{t("I\'m fine", { ns: "@nocobase/plugin-sample-i18n" })}}', + 'x-component': 'FormItem', + 'x-component': 'Input', +}; +``` + +Writing `'{{t("I\'m fine", { ns: "@nocobase/plugin-sample-i18n" })}}'` directly can be prone to errors. Instead, you can use the more convenient tval function: + +```ts +import { tval } from '@nocobase/client'; + +const schema = { + type: 'string', + title: tval("I'm fine", { ns: '@nocobase/plugin-sample-i18n', ...others }), + 'x-component': 'FormItem', + 'x-component': 'Input', +}; +``` + +## Important Notes + +Avoid using the `i18n` instance exported from `@nocobase/client`, as it will be deprecated in the future. Instead, use `app.i18n`. + +```ts +// Incorrect +import { i18n } from '@nocobase/client'; + +i18n.t('hello'); + +// Correct +import { Plugin } from '@nocobase/client'; + +class PluginDemoClient extends Plugin { + async load() { + this.app.i18n.t('hello'); + } +} +``` + +**Why is it deprecated?** + +Each app instance operates independently, including its i18n. A global i18n instance can cause interference between multiple app instances, which violates design principles, making it an undesirable practice. + +## Complete Plugin Example + +- [@nocobase/plugin-sample-i18n](#) diff --git a/docs/fr-FR/development/client/image-1.png b/docs/fr-FR/development/client/image-1.png new file mode 100644 index 000000000..cb6bcf3c5 Binary files /dev/null and b/docs/fr-FR/development/client/image-1.png differ diff --git a/docs/fr-FR/development/client/image.png b/docs/fr-FR/development/client/image.png new file mode 100644 index 000000000..b850fddb5 Binary files /dev/null and b/docs/fr-FR/development/client/image.png differ diff --git a/docs/fr-FR/development/client/index.md b/docs/fr-FR/development/client/index.md new file mode 100644 index 000000000..aeaf408a7 --- /dev/null +++ b/docs/fr-FR/development/client/index.md @@ -0,0 +1,64 @@ +# Overview + +## Directory Structure + +Initialized empty plugin, the client directory structure is as follows: + +```bash +|- /plugin-sample-hello + |- /src + |- /client + |- index.tsx + |- client.d.ts + |- client.js +``` + +## Plugin Class + +The plugin class provides various methods for the plugin lifecycle. + +```ts +import { Plugin } from '@nocobase/client'; + +export class PluginSampleHelloClient extends Plugin { + async afterAdd() {} + + async beforeLoad() {} + + async load() {} +} + +export default PluginSampleHelloClient; +``` + +## Plugin Lifecycle + +Plugin Lifecycle + +- After the plugin is initialized, `afterAdd` is triggered. It's important to note that the addition of plugins is unordered, so do not attempt to obtain instances of other plugins in `afterAdd`. If you need to get instances of other plugins, you can do so in `beforeLoad` or `load`. +- In `beforeLoad`, all activated plugins have been instantiated, and by then, instances can be obtained through [app.pluginManager.get()](https://client.docs.nocobase.com/core/application/plugin-settings-manager). +- In `load`, the `beforeLoad` method of all plugins has been executed. + +## Common Properties and Methods in the Plugin Class + +| API | Tutorial | +| ---------------------------- | -------------------------------------------------------------------------- | +| app.i18n | [Internationalization](/development/client/i18n) | +| app.apiClient | [API Client](/development/client/api-client) | +| app.pluginManager | [Plugin Manager](https://client.docs.nocobase.com/core/application/plugin-manager) | +| app.router | [Routing Management](/development/client/router) | +| app.pluginSettingsManager | [Plugin Settings Page](/development/client/router#plugin-settings-page-extension) | +| app.schemaInitializerManager | [Schema Initializer Config](/development/client/ui-schema/initializer) | +| app.schemaSettingsManager | [Schema Settings Config](/development/client/ui-schema/settings) | +| app.addProviders | [Provider Components](/development/client/providers) | +| app.addComponents | [Schema Rendering](/development/client/ui-schema/rendering) | +| app.addScopes | [Schema Rendering](/development/client/ui-schema/rendering) | + +## Commonly Used React **hooks** in Components + +| API | Tutorial | +| -------------- | ------------------------------------------------------------------------------------------------- | +| useApp() | [useApp() API](https://client.docs.nocobase.com/core/application/application#useapp) | +| usePlugin() | [usePlugin() API](https://client.docs.nocobase.com/core/application/plugin-manager#useplugin) | +| useAPIClient() | [API Client](/development/client/api-client) | +| useRequest() | [API Client](/development/client/api-client) | diff --git a/docs/fr-FR/development/client/life-cycle.md b/docs/fr-FR/development/client/life-cycle.md new file mode 100644 index 000000000..876712807 --- /dev/null +++ b/docs/fr-FR/development/client/life-cycle.md @@ -0,0 +1,129 @@ +# 插件的生命周期 + +## 生命周期 + +以下是 `Plugin` 类的定义,我们看到它提供了三个生命周期方法 `afterAdd`、`beforeLoad`、`load`。 + +```typescript +export class Pluginany> { + constructor( + protected options: T, + protected app: Application, + ) {} + + async afterAdd() {} + + async beforeLoad() {} + + async load() {} +} +``` + +### `afterAdd` + +- 调用时机:插件被添加并实例化后立即调用 +- 作用:用于加载其他插件 + +```typescript +class Demo1Plugin extends Plugin {} +class Demo2Plugin extends Plugin {} + +class MyPlugin extends Plugin { + async afterrAdd() { + // 加载其他插件 + this.app.pluginManager.add(Demo1Plugin); + this.app.pluginManager.add(Demo2Plugin); + } +} + +export default MyPlugin; +``` + +### `beforeLoad` + +- 调用时机:在全部插件被添加后,但执行 load 前 +- 用于:用于处理在之前 `load` 之前的一些特殊逻辑 + +### `load` + +- 调用时机:全部插件执行完 `beforeLoad` 后 +- 作用:大多数对 app 实例的操作和方法的调用都应在此声明周期内 + +```typescript +class MyPlugin extends Plugin { + async load() { + // 添加路由 + this.app.router.add(); + + // 添加全局组件 + this.app.addComponents({}); + + // 添加插件配置页 + this.app.pluginSettingsManager({}); + + // ... + } +} + +export default MyPlugin; +``` + +整体执行流程为: + +`app.mount()/app.getRootComponent()` -> `pluginList.forEach(plugin.afterAdd)`-> `pluginList.forEach(plugin.beforeLoad)`-> `pluginList.forEach(plugin.load)` + +同一个类型的生命周期,插件列表的执行并无先后顺序。 + +## 插件管理器 + +- 作用:对插件进行增删改查 +- 场景:当插件有拆分和聚合需求时 +- 实例方法:app.pluginManager +- API 详细介绍:[插件管理](https://www.baidu.com) + +### 获取插件 + +我们可以通过 `app.pluginManager.get` 获取对应插件的实例,并修改插件实例属性或者调用实例上的方法。 + +```typescript +import { DemoPlugin } from 'my-demo-plugin'; + +class MyPlugin extends Plugin { + async load() { + // 通过 Class 类获取实例 + const demoPluginInstance = this.pm.get(DemoPlugin); + + // 如果 add 时传递了 name,则可以通过 name 字符串获取 + const demoPluginInstance = this.pm.get('DemoPlugin'); + + // 对实例进行处理 ... + } +} +``` + +如果需要在组件内获取,可以使用 `usePlugin()` 获取。 + +```typescript +import { usePlugin } from '@nocobase/client'; +const Demo = () => { + const myPlugin = usePlugin(MyPlugin); // 通过 Class 类获取实例 + + const myPlugin = usePlugin('MyPlugin'); // 通过 name 获取实例 +}; +``` + +### 添加插件 + +添加插件,我们可以直接添加,也可以传递第二个参数,`name` 方面其他插件获取。 + +大部分情况下是不需要了解这个能力的,除非要进行将一个插件拆成几个。 + +```typescript +class MyPlugin extends Plugin { + // 注意要在 afterrAdd 生命周期内 + async afterrAdd() { + this.app.pluginManager.add(DemoPlugin); + this.app.pluginManager.add(DemoPlugin, { name: 'DemoPlugin' }); + } +} +``` diff --git a/docs/fr-FR/development/client/providers.md b/docs/fr-FR/development/client/providers.md new file mode 100644 index 000000000..d9a7f8851 --- /dev/null +++ b/docs/fr-FR/development/client/providers.md @@ -0,0 +1,146 @@ +# **Provider component** + +In the NocoBase client application, the `Provider` component is defined in the outer layer, with the core structure as follows: + +```tsx | pure + + {' '} + {/* Context Provider for routes */} + + + {/* Custom Provider components - Opening tag */} + + {/* Custom Provider components - Closing tag */} + + + +``` + +Since it is defined at the outer layer, the `Provider` component serves the following purposes: + +- Provides globally shared context, rendering `props.children` when needed. +- Displays global content by rendering `props.children`. +- Acts as an interceptor, conditionally rendering `props.children`. + +## Providing a globally shared context + +Use `createContext` to define a context and `useContext` to retrieve the defined context: + +```tsx +import { Plugin, Application } from '@nocobase/client'; +import { createContext, useContext } from 'react'; + +const MyContext = createContext({ color: null }); + +const HomePage = () => { + // Access the context value + const { color } = useContext(MyContext); + return
    Color is: {color}
    ; +}; + +class PluginSampleProvider extends Plugin { + async load() { + this.app.addProvider(MyContext.Provider, { value: { color: 'blue' } }); + this.app.router.add('home', { + path: '/', + Component: HomePage, + }); + } +} + +const app = new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + plugins: [PluginSampleProvider], +}); + +export default app.getRootComponent(); +``` + +## Providing global content display + +```tsx +import { Plugin, Application } from '@nocobase/client'; + +// Create a component and ensure children are rendered +const MyProvider = (props) => { + const { children, name } = props; + return ( +
    +
    Global content display - {name}
    + {children} +
    + ); +}; + +class PluginSampleProvider extends Plugin { + async load() { + this.app.addProvider(MyProvider, { name: 'NocoBase' }); + + this.app.router.add('home', { + path: '/', + Component: () =>
    Home page
    , + }); + } +} + +const app = new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + plugins: [PluginSampleProvider], +}); + +export default app.getRootComponent(); +``` + +## Intercepting functionality + +```tsx +import { Plugin, Application } from '@nocobase/client'; +import { useLocation } from 'react-router'; +import { Link } from 'react-router-dom'; + +// Create a component and ensure children are rendered +const MyProvider = (props) => { + const { children, name } = props; + const location = useLocation(); + if (location.pathname === '/about') { + return ( +
    + Content intercepted. Return to Home +
    + ); + } + return ( +
    +
    Hello, {name}
    + Home, About + {children} +
    + ); +}; + +class PluginSampleProvider extends Plugin { + async load() { + this.app.addProvider(MyProvider); + this.app.router.add('home', { + path: '/', + Component: () =>
    Home page
    , + }); + } +} + +const app = new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + plugins: [PluginSampleProvider], +}); + +export default app.getRootComponent(); +``` diff --git a/docs/fr-FR/development/client/router.md b/docs/fr-FR/development/client/router.md new file mode 100644 index 000000000..058b7e37a --- /dev/null +++ b/docs/fr-FR/development/client/router.md @@ -0,0 +1,199 @@ +# Page Routing and Extensions + +## Introduction + +NocoBase client extends pages through [app.router.add()](https://client.docs.nocobase.com/core/application/router-manager) and [app.pluginSettingsManager.add()](https://client.docs.nocobase.com/core/application/plugin-settings-manager), for example: + +```tsx | pure +import { Application, Plugin } from '@nocobase/client'; +import React from 'react'; + +class PluginHello extends Plugin { + async load() { + this.router.add('hello', { + path: '/', + Component: () =>
    Hello NocoBase
    , + }); + + this.app.pluginSettingsManager.add('hello', { + title: 'Hello', + icon: 'ApiOutlined', + Component: () =>
    Hello Setting page
    , + }); + } +} +``` + +You can use the `app.router.getRoutes()` method to view all registered pages. + +```tsx | pure +import { Application, Plugin } from '@nocobase/client'; +import React from 'react'; + +class PluginHello extends Plugin { + async load() { + console.log(this.app.router.getRoutes()); + } +} +``` + +## Existing Page Routes + +The initially installed NocoBase has the following registered page routes: + +| Name | Path | Component | Description | +| -------------- | ------------------ | ------------------- |---------| +| admin | /admin/\* | AdminLayout | Admin page | +| admin.page | /admin/:name | AdminDynamicPage | Dynamic page | +| admin.settings | /admin/settings/\* | AdminSettingsLayout | Plugin configuration page | +| admin.pm.list | /admin/pm/list/\* | PluginManager | Plugin management page | + + +### AdminLayout + +```ts +router.add('admin', { + path: '/admin/*', + Component: AdminLayout, +}); +``` + +### AdminDynamicPage + +```ts +router.add('admin.page', { + path: '/admin/:name', + Component: AdminDynamicPage, +}); +``` + +Dynamic pages are managed through menu management, by adding menu items -> page addition. + +![](https://static-docs.nocobase.com/9204957c39f644cfbf23eef3cbdc7eca.png) + +### AdminSettingsLayout + +```typescript +router.add('admin.settings', { + path: '/admin/settings/*', + Component: AdminSettingsLayout, +}); +``` + +Plugin configuration pages. + +![](https://static-docs.nocobase.com/ea22826eba4fd38d68a5a52fd68e7719.png) + +The menu and tabs for plugin configuration pages are registered via `app.pluginSettingsManager`. + +## Page Extensions + +- Dynamic Schema pages are added through `Add Menu Item` -> `Page`. +- Regular pages are added through [app.router.add()](https://client.docs.nocobase.com/core/application/router-manager). +- Plugin settings pages are added through [app.pluginSettingsManager.add()](https://client.docs.nocobase.com/core/application/plugin-settings-manager). + +### Dynamic Schema Pages + +Added through `Add Menu Item` -> `Page`. + +### Regular Page Extensions + +Pages are extended through [app.router.add()](https://client.docs.nocobase.com/core/application/router-manager). + +```typescript +import React from 'react'; +import { Link, Outlet } from 'react-router-dom'; +import { Application, Plugin } from '@nocobase/client'; + +const Home = () =>

    Home

    ; +const About = () =>

    About

    ; + +const Layout = () => { + return ( +
    +
    + Home, About +
    + +
    + ); +}; + +class MyPlugin extends Plugin { + async load() { + this.app.router.add('root', { + element: , + }); + + this.app.router.add('root.home', { + path: '/', + element: , + }); + + this.app.router.add('root.about', { + path: '/about', + element: , + }); + } +} + +const app = new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + plugins: [MyPlugin] +}); + + +export default app.getRootComponent(); +``` + +### Plugin Settings Page Extensions + +Plugin settings pages are added through [app.pluginSettingsManager.add()](https://client.docs.nocobase.com/core/application/plugin-settings-manager). + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import React from 'react'; + +const HelloSettingPage = () =>
    Hello Setting page
    ; + +export class HelloPlugin extends Plugin { + async load() { + this.app.pluginSettingsManager.add('hello', { + title: 'Hello', // The title and menu name of the settings page + icon: 'ApiOutlined', // Menu icon for the settings page + Component: HelloSettingPage, + }); + } +} +``` + +Multi-level routing usage + +```tsx | pure +import { Outlet } from 'react-router-dom'; + +const pluginName = 'hello'; + +class HelloPlugin extends Plugin { + async load() { + this.app.pluginSettingsManager.add(pluginName, { + title: 'HelloWorld', + icon: '', + Component: Outlet, // No need to pass, default is `Outlet` component + }); + + this.app.pluginSettingsManager.add(`${pluginName}.demo1`, { + title: 'Demo1 Page', + Component: () =>
    Demo1 Page Content
    , + }); + + this.app.pluginSettingsManager.add(`${pluginName}.demo2`, { + title: 'Demo2 Page', + Component: () =>
    Demo2 Page Content
    , + }); + } +} +``` diff --git a/docs/fr-FR/development/client/static/D30xbFKV9oHJvXxN6HGcaBZlnph.png b/docs/fr-FR/development/client/static/D30xbFKV9oHJvXxN6HGcaBZlnph.png new file mode 100644 index 000000000..a9f59f9f6 Binary files /dev/null and b/docs/fr-FR/development/client/static/D30xbFKV9oHJvXxN6HGcaBZlnph.png differ diff --git a/docs/fr-FR/development/client/static/DifFbVdZkoLGS2xDx0ucPISnnag.png b/docs/fr-FR/development/client/static/DifFbVdZkoLGS2xDx0ucPISnnag.png new file mode 100644 index 000000000..81f85af0d Binary files /dev/null and b/docs/fr-FR/development/client/static/DifFbVdZkoLGS2xDx0ucPISnnag.png differ diff --git a/docs/fr-FR/development/client/static/DoNDbXU2XoEGkjx8u0YcqoU8nId.png b/docs/fr-FR/development/client/static/DoNDbXU2XoEGkjx8u0YcqoU8nId.png new file mode 100644 index 000000000..2fe5e2836 Binary files /dev/null and b/docs/fr-FR/development/client/static/DoNDbXU2XoEGkjx8u0YcqoU8nId.png differ diff --git a/docs/fr-FR/development/client/static/KItpbzcUQo9A2yx2i1tcOmlLnjI.png b/docs/fr-FR/development/client/static/KItpbzcUQo9A2yx2i1tcOmlLnjI.png new file mode 100644 index 000000000..319c371c7 Binary files /dev/null and b/docs/fr-FR/development/client/static/KItpbzcUQo9A2yx2i1tcOmlLnjI.png differ diff --git a/docs/fr-FR/development/client/static/KLf2bSErAocXnhxnOiycyd0jnUe.png b/docs/fr-FR/development/client/static/KLf2bSErAocXnhxnOiycyd0jnUe.png new file mode 100644 index 000000000..d151ba31a Binary files /dev/null and b/docs/fr-FR/development/client/static/KLf2bSErAocXnhxnOiycyd0jnUe.png differ diff --git a/docs/fr-FR/development/client/static/LOsWbeuJgocLsmxM1YZcGHGGn6f.png b/docs/fr-FR/development/client/static/LOsWbeuJgocLsmxM1YZcGHGGn6f.png new file mode 100644 index 000000000..b4a9a3702 Binary files /dev/null and b/docs/fr-FR/development/client/static/LOsWbeuJgocLsmxM1YZcGHGGn6f.png differ diff --git a/docs/fr-FR/development/client/static/LtfabsBExoQHtSxmkLwcgE6andf.png b/docs/fr-FR/development/client/static/LtfabsBExoQHtSxmkLwcgE6andf.png new file mode 100644 index 000000000..1f4ed5d85 Binary files /dev/null and b/docs/fr-FR/development/client/static/LtfabsBExoQHtSxmkLwcgE6andf.png differ diff --git a/docs/fr-FR/development/client/static/QFUPbE99LobwzCx5x8YcW1Txn7e.png b/docs/fr-FR/development/client/static/QFUPbE99LobwzCx5x8YcW1Txn7e.png new file mode 100644 index 000000000..1f64353a5 Binary files /dev/null and b/docs/fr-FR/development/client/static/QFUPbE99LobwzCx5x8YcW1Txn7e.png differ diff --git a/docs/fr-FR/development/client/static/ShlTbs6Rbo0RylxzTaPcmcjUnqg.png b/docs/fr-FR/development/client/static/ShlTbs6Rbo0RylxzTaPcmcjUnqg.png new file mode 100644 index 000000000..3c923380a Binary files /dev/null and b/docs/fr-FR/development/client/static/ShlTbs6Rbo0RylxzTaPcmcjUnqg.png differ diff --git a/docs/fr-FR/development/client/static/TcQ0b9vAAoX3gKx5uPYchs4tnEb.png b/docs/fr-FR/development/client/static/TcQ0b9vAAoX3gKx5uPYchs4tnEb.png new file mode 100644 index 000000000..5d778c46c Binary files /dev/null and b/docs/fr-FR/development/client/static/TcQ0b9vAAoX3gKx5uPYchs4tnEb.png differ diff --git a/docs/fr-FR/development/client/static/W1xyb05JAoC0i5xVlDNc4xUrn3e.gif b/docs/fr-FR/development/client/static/W1xyb05JAoC0i5xVlDNc4xUrn3e.gif new file mode 100644 index 000000000..918837d0e Binary files /dev/null and b/docs/fr-FR/development/client/static/W1xyb05JAoC0i5xVlDNc4xUrn3e.gif differ diff --git a/docs/fr-FR/development/client/static/WCBPbKackoxlV3xs2zxcXymTnQf.png b/docs/fr-FR/development/client/static/WCBPbKackoxlV3xs2zxcXymTnQf.png new file mode 100644 index 000000000..3aa7e5291 Binary files /dev/null and b/docs/fr-FR/development/client/static/WCBPbKackoxlV3xs2zxcXymTnQf.png differ diff --git a/docs/fr-FR/development/client/static/XIXObandIozuMyxpG4Vc3Mz7nDb.jpg b/docs/fr-FR/development/client/static/XIXObandIozuMyxpG4Vc3Mz7nDb.jpg new file mode 100644 index 000000000..a7769b0b5 Binary files /dev/null and b/docs/fr-FR/development/client/static/XIXObandIozuMyxpG4Vc3Mz7nDb.jpg differ diff --git a/docs/fr-FR/development/client/static/ZyL3b28aioYlhixPrjGcu0OjnZd.png b/docs/fr-FR/development/client/static/ZyL3b28aioYlhixPrjGcu0OjnZd.png new file mode 100644 index 000000000..e084b87bf Binary files /dev/null and b/docs/fr-FR/development/client/static/ZyL3b28aioYlhixPrjGcu0OjnZd.png differ diff --git a/docs/fr-FR/development/client/styles-and-themes.md b/docs/fr-FR/development/client/styles-and-themes.md new file mode 100644 index 000000000..067cef874 --- /dev/null +++ b/docs/fr-FR/development/client/styles-and-themes.md @@ -0,0 +1,276 @@ +# Styles & Themes + +To better accommodate NocoBase's dynamic theme capabilities, it is recommended to use [antd-style](https://ant-design.github.io/antd-style/zh-CN/guide) when writing styles in the plugin. By combining it with the existing [theme tokens](https://ant.design/docs/react/customize-theme-cn#seedtoken), you can efficiently manage the dynamic aspects of themes. Additionally, NocoBase provides a [theme editor plugin](#) that allows for easy style adjustments. + +## Writing Styles + +### Writing Styles with `createStyles` (Recommended) + +```tsx +import { createStyles } from 'antd-style'; + +const useStyles = createStyles(({ token, css }) => ({ + // Supports CSS object syntax + container: { + backgroundColor: token.colorBgLayout, + borderRadius: token.borderRadiusLG, + maxWidth: 400, + width: '100%', + height: 180, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + flexDirection: 'column', + marginLeft: 'auto', + marginRight: 'auto', + }, + // Also supports CSS string templates for a familiar CSS writing experience + card: css` + color: ${token.colorTextTertiary}; + box-shadow: ${token.boxShadow}; + &:hover { + color: ${token.colorTextSecondary}; + box-shadow: ${token.boxShadowSecondary}; + } + + padding: ${token.padding}px; + border-radius: ${token.borderRadius}px; + background: ${token.colorBgContainer}; + transition: all 100ms ${token.motionEaseInBack}; + + margin-bottom: 8px; + cursor: pointer; + `, +})); + +export default () => { + // The styles object is cached by default in the useStyles method, so re-rendering is not a concern + const { styles, cx, theme } = useStyles(); + + return ( + // Use cx to organize classNames +
    +
    createStyles Demo
    + {/* The theme object contains all tokens and theme-related information */} +
    Current theme mode: {theme.appearance}
    +
    + ); +}; +``` + +For detailed usage, refer to the [createStyles API](https://ant-design.github.io/antd-style/zh-CN/api/create-styles). + +### Creating Reusable Styles with `createStylish` + +```tsx +import { createStyles, createStylish, css } from 'antd-style'; + +const useStylish = createStylish(({ token, css }) => { + const containerBgHover = css` + cursor: pointer; + transition: 150ms background-color ease-in-out; + &:hover { + background: ${token.colorFillQuaternary}; + } + `; + + const defaultButtonBase = css` + color: ${token.colorTextSecondary}; + background: ${token.colorFillQuaternary}; + border-color: transparent; + `; + + return { + defaultButton: css` + ${defaultButtonBase}; + + &:hover { + color: ${token.colorText}; + background: ${token.colorFillSecondary}; + border-color: transparent; + } + &:focus { + ${defaultButtonBase}; + border-color: ${token.colorPrimary}; + } + `, + + containerBgHover: css` + cursor: pointer; + transition: 150ms background-color ease-in-out; + + &:hover { + background: ${token.colorFillQuaternary}; + } + `, + + containerBgL2: css` + ${containerBgHover}; + border-radius: 4px; + background: ${token.colorFillQuaternary}; + + &:hover { + background: ${token.colorFillTertiary}; + } + `, + }; +}); + +const useStyles = createStyles({ + // Supports CSS object syntax + container: { + backgroundColor: '#f5f5f5', + maxWidth: 400, + width: '100%', + height: 180, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + // Also supports CSS string templates for a familiar CSS writing experience + btn: css` + padding: 24px; + `, +}); + +export default () => { + const { styles, cx } = useStyles(); + const stylish = useStylish(); + + return ( +
    +
    + Stylish Button +
    +
    + ); +}; +``` + +For detailed usage, refer to the [createStylish API](https://ant-design.github.io/antd-style/zh-CN/api/create-stylish). + +### Injecting Global Styles with `createGlobalStyle` + +```tsx +import { createGlobalStyle } from 'antd-style'; + +const Global = createGlobalStyle` + .some-class { + color: hotpink; + } +`; + +export default () => { + return ( +
    + +
    Favorite color of macho men
    +
    + ); +}; +``` + +For detailed usage, refer to the [createGlobalStyle API](https://ant-design.github.io/antd-style/zh-CN/api/global-styles). + +## Customizing Themes + +### Using `antd`'s Theme Tokens + +#### `createStyles` Example + +```tsx +import { SmileOutlined } from '@ant-design/icons'; +import { Button, Space } from 'antd'; +import { createStyles } from 'antd-style'; + +const useStyles = createStyles(({ token, css }) => { + const commonCard = css` + border-radius: ${token.borderRadiusLG}px; + padding: ${token.paddingLG}px; + `; + + return { + container: css` + background-color: ${token.colorBgLayout}; + padding: 24px; + `, + + primaryCard: css` + ${commonCard}; + background: ${token.colorPrimary}; + color: ${token.colorTextLightSolid}; + `, + + defaultCard: css` + ${commonCard}; + background: ${token.colorBgContainer}; + color: ${token.colorText}; + `, + }; +}); + +const App = () => { + const { styles } = useStyles(); + + return ( +
    + + +
    + ); +}; + +export default App; +``` + +#### `createGlobalStyle` Example + +```tsx +import { createGlobalStyle, ThemeProvider } from 'antd-style'; + +const Global = createGlobalStyle` + .ant-custom-button { + color: ${(p) => p.theme.colorPrimary}; + background: ${(p) => p.theme.colorPrimaryBg}; + height: ${(p) => p.theme.controlHeight}px; + border-radius: ${(p) => p.theme.borderRadius}px; + padding: 0 ${(p) => p.theme.paddingContentHorizontal}px; + + :hover { + background: ${(p) => p.theme.colorPrimaryBgHover}; + color: ${(p) => p.theme.colorPrimaryTextActive}; + } + + :active { + background: ${(p) => p.theme.colorPrimaryBorder}; + color: ${(p) => p.theme.colorPrimaryText}; + } + + border: none; + cursor: pointer; + } +`; + +export default () => { + return ( + + + + + ); +}; +``` + +## Debugging Themes + +### Using the Theme Editor Plugin + +![Theme Editor](https://static-docs.nocobase.com/440f844d056a485f9f0dc64a8ca1b4f4.png) diff --git a/docs/fr-FR/development/client/test.md b/docs/fr-FR/development/client/test.md new file mode 100644 index 000000000..f00b526a9 --- /dev/null +++ b/docs/fr-FR/development/client/test.md @@ -0,0 +1 @@ +# Testing diff --git a/docs/fr-FR/development/client/ui-schema/SchemaInitializes.png b/docs/fr-FR/development/client/ui-schema/SchemaInitializes.png new file mode 100644 index 000000000..70291780a Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/SchemaInitializes.png differ diff --git a/docs/fr-FR/development/client/ui-schema/SchemaSettings.png b/docs/fr-FR/development/client/ui-schema/SchemaSettings.png new file mode 100644 index 000000000..52c1e1742 Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/SchemaSettings.png differ diff --git a/docs/fr-FR/development/client/ui-schema/components.md b/docs/fr-FR/development/client/ui-schema/components.md new file mode 100644 index 000000000..3cb0673b2 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/components.md @@ -0,0 +1,82 @@ +# Schema components + +## Wrapper Components + +- BlockItem +- FormItem +- CardItem + +## Layout + +- Page +- Grid +- Tabs +- Space + +## Field Components + +Field components are generally not used alone but are utilized within data display components. + +- CollectionField: Universal component +- Cascader +- Checkbox +- ColorSelect +- DatePicker +- Filter +- Formula +- IconPicker +- Input +- InputNumber +- Markdown +- Password +- Percent +- Radio +- RecordPicker +- RichText +- Select +- TimePicker +- TreeSelect +- Upload + +## Data Display Components + +These need to be used in conjunction with field components. + +- Calendar +- Form +- Kanban +- Table +- TableV2 + +## Actions (onClick Event Components) + +- Action +- Action.Drawer +- Action.Modal +- ActionBar: Used for action layout +- Menu + +## Others + +- G2plot +- Markdown.Void + +## Use Cases of `x-designer` and `x-initializer` + +`x-designer` is effective when `x-decorator` or `x-component` is one of the following components: + +- BlockItem +- CardItem +- FormItem +- Table.Column +- Tabs.TabPane + +`x-initializer` is effective when `x-decorator` or `x-component` is one of the following components: + +- ActionBar +- BlockItem +- CardItem +- FormItem +- Grid +- Table +- Tabs \ No newline at end of file diff --git a/docs/fr-FR/development/client/ui-schema/demos/demo1.tsx b/docs/fr-FR/development/client/ui-schema/demos/demo1.tsx new file mode 100644 index 000000000..d4b765fb0 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/demo1.tsx @@ -0,0 +1,35 @@ +import { Application, Plugin, SchemaComponent } from '@nocobase/client'; +import React from 'react'; + +const Hello = () =>

    Hello NocoBase

    ; + +const HelloPage = () => { + return ( + + ); +}; + +class PluginHello extends Plugin { + async load() { + this.app.addComponents({ Hello }); + this.router.add('hello', { + path: '/', + Component: HelloPage, + }); + } +} + +const app = new Application({ + router: { + type: 'memory', + }, + plugins: [PluginHello], +}); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/demo2.tsx b/docs/fr-FR/development/client/ui-schema/demos/demo2.tsx new file mode 100644 index 000000000..636529c90 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/demo2.tsx @@ -0,0 +1,76 @@ +import { + Application, + CardItem, + Grid, + Plugin, + SchemaComponent, + SchemaInitializer, + SchemaInitializerItem, + useSchemaInitializer, + useSchemaInitializerItem, +} from '@nocobase/client'; +import React from 'react'; + +const Hello = () =>

    Hello NocoBase

    ; + +const myInitializer = new SchemaInitializer({ + name: 'myInitializer', + // 按钮标题标题 + title: 'Add block', + wrap: Grid.wrap, + items: [ + { + name: 'demo1', + title: 'Hello block', + Component: () => { + const itemConfig = useSchemaInitializerItem(); + // 调用插入功能 + const { insert } = useSchemaInitializer(); + const handleClick = () => { + insert({ + type: 'void', + 'x-component': 'Hello', + }); + }; + return ; + }, + }, + ], +}); + +const HelloPage = () => { + return ( +
    + +
    + ); +}; + +class PluginHello extends Plugin { + async load() { + this.app.addComponents({ Grid, CardItem, Hello }); + this.router.add('hello', { + path: '/', + Component: HelloPage, + }); + this.app.schemaInitializerManager.add(myInitializer); + } +} + +const app = new Application({ + router: { + type: 'memory', + }, + // 为了更好的展示 demo,直接将 designable 设置为 true + designable: true, + plugins: [PluginHello], +}); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/demo3.tsx b/docs/fr-FR/development/client/ui-schema/demos/demo3.tsx new file mode 100644 index 000000000..a2d8f8664 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/demo3.tsx @@ -0,0 +1,107 @@ +import { useFieldSchema } from '@formily/react'; +import { + Application, + CardItem, + Grid, + Plugin, + SchemaComponent, + SchemaInitializer, + SchemaInitializerItem, + SchemaSettings, + useSchemaInitializer, + useSchemaInitializerItem, +} from '@nocobase/client'; +import React from 'react'; + +const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [ + { + name: 'remove', + type: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + }, + }, + ], +}); + +const myInitializer = new SchemaInitializer({ + name: 'MyInitializer', + // 按钮标题标题 + title: 'Button Text', + wrap: Grid.wrap, + // 调用 initializer.render() 时会渲染 items 列表 + items: [ + { + name: 'demo1', + title: 'Demo1', + Component: () => { + const itemConfig = useSchemaInitializerItem(); + // 调用插入功能 + const { insert } = useSchemaInitializer(); + const handleClick = () => { + insert({ + type: 'void', + 'x-settings': 'mySettings', + 'x-decorator': 'CardItem', + 'x-component': 'Hello', + }); + }; + return ; + }, + }, + ], +}); + +const Hello = () => { + const schema = useFieldSchema(); + return

    Hello, world! {schema.name}

    ; +}; + +const hello1 = Grid.wrap({ + type: 'void', + 'x-settings': 'mySettings', + 'x-decorator': 'CardItem', + 'x-component': 'Hello', +}); + +const HelloPage = () => { + return ( +
    + +
    + ); +}; + +class PluginHello extends Plugin { + async load() { + this.app.addComponents({ Grid, CardItem, Hello }); + this.app.schemaSettingsManager.add(mySettings); + this.app.schemaInitializerManager.add(myInitializer); + this.router.add('hello', { + path: '/', + Component: HelloPage, + }); + } +} + +const app = new Application({ + router: { + type: 'memory', + }, + designable: true, + plugins: [PluginHello], +}); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add-item/app.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add-item/app.tsx new file mode 100644 index 000000000..f1296db2e --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add-item/app.tsx @@ -0,0 +1,80 @@ +import { + Application, + CardItem, + Grid, + Plugin, + SchemaComponent, + SchemaInitializer, + useSchemaInitializer, +} from '@nocobase/client'; +import React from 'react'; + +const HelloPage = () => { + return ( +
    + +
    + ); +}; + +class PluginHello extends Plugin { + async load() { + const myInitializer = new SchemaInitializer({ + name: 'myInitializer', + title: 'Add block', + wrap: Grid.wrap, + items: [ + { + name: 'otherBlocks', + title: 'Other blocks', + type: 'itemGroup', + children: [ + { + name: 'helloBlock', + type: 'item', + useComponentProps() { + const { insert } = useSchemaInitializer(); + return { + title: 'Hello', + onClick: () => { + insert({ + type: 'void', + 'x-decorator': 'CardItem', + 'x-component': 'h1', + 'x-content': 'Hello, world!', + }); + }, + }; + }, + }, + ], + }, + ], + }); + this.schemaInitializerManager.add(myInitializer); + this.app.addComponents({ Grid, CardItem }); + this.router.add('hello', { + path: '/', + Component: HelloPage, + }); + } +} + +export function createApp(options: any = {}) { + const { plugins = [] } = options; + return new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + designable: true, + plugins: [PluginHello, ...plugins], + }); +} diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add-item/index.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add-item/index.tsx new file mode 100644 index 000000000..3d10f56a4 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add-item/index.tsx @@ -0,0 +1,36 @@ +import { Plugin, useSchemaInitializer } from '@nocobase/client'; +import { createApp } from './app'; + +class PluginDemoAddSchemaInitializerItem extends Plugin { + async load() { + const customItem = { + name: 'custom', + type: 'item', + useComponentProps() { + const { insert } = useSchemaInitializer(); + return { + title: 'Custom', + onClick: () => { + insert({ + type: 'void', + 'x-decorator': 'CardItem', + 'x-component': 'h1', + 'x-content': 'Custom block', + }); + }, + }; + }, + }; + + this.schemaInitializerManager.addItem( + 'myInitializer', // 示例,已存在的 schema initializer + 'otherBlocks.custom', // 向 otherBlocks 分组内添加 custom + customItem, + ); + } +} + +// 快捷模拟一个 App +const app = createApp({ plugins: [PluginDemoAddSchemaInitializerItem] }); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add/app.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add/app.tsx new file mode 100644 index 000000000..5f1ae25fc --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add/app.tsx @@ -0,0 +1,22 @@ +import { Application, Plugin } from '@nocobase/client'; + +class PluginHome extends Plugin { + async load() { + this.router.add('home', { + path: '/', + Component: 'HomePage', + }); + } +} + +export function createApp(options: any = {}) { + const { plugins = [] } = options; + return new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + designable: true, + plugins: [PluginHome, ...plugins], + }); +} diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add/index.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add/index.tsx new file mode 100644 index 000000000..c5a2bcfea --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-initializer-manager-add/index.tsx @@ -0,0 +1,60 @@ +import { + Grid, + Plugin, + SchemaComponent, + SchemaInitializer, + useSchemaInitializer, +} from '@nocobase/client'; +import React from 'react'; +import { createApp } from './app'; + +const HomePage = () => { + return ( + + ); +}; + +class PluginDemoAddSchemaInitializer extends Plugin { + async load() { + // 注册全局组件 + this.app.addComponents({ Grid, HomePage }); + const myInitializer = new SchemaInitializer({ + name: 'myInitializer', + title: 'Add block', + wrap: Grid.wrap, + items: [ + { + name: 'helloBlock', + type: 'item', + useComponentProps() { + const { insert } = useSchemaInitializer(); + return { + title: 'Hello', + onClick: () => { + insert({ + type: 'void', + 'x-decorator': 'CardItem', + 'x-component': 'h1', + 'x-content': 'Hello, world!', + }); + }, + }; + }, + }, + ], + }); + this.schemaInitializerManager.add(myInitializer); + } +} + +// 快捷模拟一个 App +const app = createApp({ plugins: [PluginDemoAddSchemaInitializer] }); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-settings-basic/app.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-basic/app.tsx new file mode 100644 index 000000000..b92bd0f52 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-basic/app.tsx @@ -0,0 +1,58 @@ +import { + Application, + CardItem, + FormItem, + Input, + Plugin, + SchemaComponent, + SchemaSettings, +} from '@nocobase/client'; +import React from 'react'; + +const HelloPage = () => { + return ( +
    + +
    + ); +}; + +class PluginHello extends Plugin { + async load() { + const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [], + }); + this.schemaSettingsManager.add(mySettings); + this.app.addComponents({ CardItem, Input, FormItem }); + this.router.add('hello', { + path: '/', + Component: HelloPage, + }); + } +} + +export function createApp(options: any = {}) { + const { plugins = [] } = options; + return new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + designable: true, + plugins: [PluginHello, ...plugins], + }); +} diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-settings-basic/index.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-basic/index.tsx new file mode 100644 index 000000000..bf75ceedc --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-basic/index.tsx @@ -0,0 +1,56 @@ +/** + * defaultShowCode: true + */ +import { ISchema } from '@formily/react'; +import { Plugin, SchemaSettingsModalItem, useSchemaSettings } from '@nocobase/client'; +import React from 'react'; +import { createApp } from './app'; + +export const SchemaSettingsBlockTitleItem: any = () => { + // 设计器的 Designable 实例 + const { dn } = useSchemaSettings(); + + return ( + { + // 参数覆盖 + dn.deepMerge({ + 'x-decorator-props': { + title, + }, + }); + }} + /> + ); +}; + +class PluginDemoAddSchemaInitializerItem extends Plugin { + async load() { + this.schemaSettingsManager.addItem('mySettings', 'blockTitle', { + Component: SchemaSettingsBlockTitleItem, + }); + } +} + +// 快捷模拟一个 App +const app = createApp({ plugins: [PluginDemoAddSchemaInitializerItem] }); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add-item/app.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add-item/app.tsx new file mode 100644 index 000000000..0f1a2a041 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add-item/app.tsx @@ -0,0 +1,70 @@ +import { + Application, + CardItem, + Plugin, + SchemaComponent, + SchemaSettings +} from '@nocobase/client'; +import React from 'react'; + +const HelloPage = () => { + return ( +
    + +
    + ); +}; + +class PluginHello extends Plugin { + async load() { + const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [ + { + type: 'item', + name: 'edit', + useComponentProps() { + // TODO: 补充相关设置逻辑 + return { + title: 'Edit', + onClick() { + // todo + }, + }; + }, + }, + ], + }); + this.schemaSettingsManager.add(mySettings); + this.app.addComponents({ CardItem }); + this.router.add('hello', { + path: '/', + Component: HelloPage, + }); + } +} + +export function createApp(options: any = {}) { + const { plugins = [] } = options; + return new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + designable: true, + plugins: [PluginHello, ...plugins], + }); +} diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add-item/index.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add-item/index.tsx new file mode 100644 index 000000000..8cf66d1b8 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add-item/index.tsx @@ -0,0 +1,30 @@ +import { Plugin } from '@nocobase/client'; +import { createApp } from './app'; + +class PluginDemoAddSchemaSettingsItem extends Plugin { + async load() { + const customItem = { + name: 'custom', + type: 'item', + useComponentProps() { + return { + title: 'Custom', + onClick: () => {}, + }; + }, + }; + + this.schemaSettingsManager.addItem( + 'mySettings', // 示例,已存在的 schema settings name + 'customItem', // 新增的 item name + customItem, + ); + } +} + +// 快捷模拟一个 App +const app = createApp({ + plugins: [PluginDemoAddSchemaSettingsItem], +}); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add/app.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add/app.tsx new file mode 100644 index 000000000..5f1ae25fc --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add/app.tsx @@ -0,0 +1,22 @@ +import { Application, Plugin } from '@nocobase/client'; + +class PluginHome extends Plugin { + async load() { + this.router.add('home', { + path: '/', + Component: 'HomePage', + }); + } +} + +export function createApp(options: any = {}) { + const { plugins = [] } = options; + return new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + designable: true, + plugins: [PluginHome, ...plugins], + }); +} diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add/index.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add/index.tsx new file mode 100644 index 000000000..3e1429901 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-settings-manager-add/index.tsx @@ -0,0 +1,58 @@ +import { + CardItem, + Plugin, + SchemaComponent, + SchemaSettings, +} from '@nocobase/client'; +import React from 'react'; +import { createApp } from './app'; + +const HomePage = () => { + return ( + + ); +}; + +class PluginDemoAddSchemaSettings extends Plugin { + async load() { + // 注册全局组件 + this.app.addComponents({ CardItem, HomePage }); + const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [ + { + type: 'item', + name: 'edit', + useComponentProps() { + // TODO: 补充相关设置逻辑 + return { + title: 'Edit', + onClick() { + // todo + }, + }; + }, + }, + ], + }); + this.schemaSettingsManager.add(mySettings); + } +} + +// 快捷模拟一个 App +const app = createApp({ plugins: [PluginDemoAddSchemaSettings] }); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/app.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/app.tsx new file mode 100644 index 000000000..26623fb55 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/app.tsx @@ -0,0 +1,23 @@ +import { Application, ApplicationOptions, Plugin } from '@nocobase/client'; + +class PluginHome extends Plugin { + async load() { + this.router.add('home', { + path: '/', + Component: 'HomePage', + }); + } +} + +export function createApp(options: ApplicationOptions = {}) { + const { plugins = [], ...others } = options; + return new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + designable: true, + ...others, + plugins: [PluginHome, ...plugins], + }); +} diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/button.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/button.tsx new file mode 100644 index 000000000..b9d14841e --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/button.tsx @@ -0,0 +1,76 @@ +import { useFieldSchema } from '@formily/react'; +import { + Plugin, + SchemaComponent, + SchemaSettings, + SchemaToolbar, + Space, + useSchemaToolbarRender, +} from '@nocobase/client'; +import { Space as AntdSpace, Button } from 'antd'; +import React from 'react'; +import { createApp } from './app'; + +const MyToolbar = (props) => { + return ; +}; + +const SchemaToolbarRenderer = (props) => { + const fieldSchema = useFieldSchema(); + const { render } = useSchemaToolbarRender(fieldSchema); + return render({ draggable: false }); +}; + +const CustomButton = (props) => { + return ( + + ); +}; + +const HomePage = () => { + return ( + + ); +}; + +class PluginDemoToolbar extends Plugin { + async load() { + this.app.addComponents({ HomePage, CustomButton, MyToolbar, Space }); + const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [], + }); + this.schemaSettingsManager.add(mySettings); + } +} + +const app = createApp({ plugins: [PluginDemoToolbar] }); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/custom.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/custom.tsx new file mode 100644 index 000000000..66f12dabb --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/custom.tsx @@ -0,0 +1,48 @@ +import { useFieldSchema } from '@formily/react'; +import { + CardItem, + Plugin, + SchemaComponent, + SchemaSettings, + SchemaToolbar +} from '@nocobase/client'; +import React from 'react'; +import { createApp } from './app'; + +const MyToolbar = (props) => { + const fieldSchema = useFieldSchema(); + return ( + + ); +}; + +const HomePage = () => { + return ( + + ); +}; + +class PluginDemoToolbar extends Plugin { + async load() { + this.app.addComponents({ HomePage, CardItem, MyToolbar }); + const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [], + }); + this.schemaSettingsManager.add(mySettings); + } +} + +const app = createApp({ plugins: [PluginDemoToolbar] }); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/grid.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/grid.tsx new file mode 100644 index 000000000..d03b4e78a --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/grid.tsx @@ -0,0 +1,98 @@ +import { useFieldSchema } from '@formily/react'; +import { + CardItem, + Grid, + Plugin, + SchemaComponent, + SchemaInitializer, + SchemaSettings, + SchemaToolbar, + useSchemaInitializer +} from '@nocobase/client'; +import React from 'react'; +import { createApp } from './app'; + +const MyToolbar = (props) => { + const fieldSchema = useFieldSchema(); + return ( + + ); +}; + +const HomePage = () => { + return ( + + ); +}; + +class PluginDemoToolbar extends Plugin { + async load() { + this.app.addComponents({ HomePage, CardItem, MyToolbar, Grid }); + const myInitializer = new SchemaInitializer({ + name: 'myInitializer', + title: 'AddBlock', + wrap: Grid.wrap, + items: [ + { + name: 'helloBlock', + type: 'item', + useComponentProps() { + const { insert } = useSchemaInitializer(); + return { + title: 'Hello', + onClick: () => { + insert({ + type: 'void', + 'x-decorator': 'CardItem', + 'x-settings': 'mySettings', + 'x-component': 'h1', + 'x-content': 'Hello, world!', + }); + }, + }; + }, + }, + ], + }); + const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [], + }); + this.schemaInitializerManager.add(myInitializer); + this.schemaSettingsManager.add(mySettings); + } +} + +const app = createApp({ plugins: [PluginDemoToolbar] }); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/index.tsx b/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/index.tsx new file mode 100644 index 000000000..5ad0f7293 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/schema-toolbar-basic/index.tsx @@ -0,0 +1,80 @@ +import { + Action, + BlockItem, + CardItem, + FormItem, + Input, + Plugin, + SchemaComponent, + SchemaSettings, +} from '@nocobase/client'; +import React from 'react'; +import { createApp } from './app'; + +const HomePage = () => { + return ( + + ); +}; + +class PluginDemoToolbar extends Plugin { + async load() { + this.app.addComponents({ + HomePage, + Action, + CardItem, + FormItem, + BlockItem, + Input, + }); + const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [], + }); + this.schemaSettingsManager.add(mySettings); + } +} + +const app = createApp({ plugins: [PluginDemoToolbar] }); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/use-schema-initializer-render/app.tsx b/docs/fr-FR/development/client/ui-schema/demos/use-schema-initializer-render/app.tsx new file mode 100644 index 000000000..78aa4e363 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/use-schema-initializer-render/app.tsx @@ -0,0 +1,47 @@ +import { Application, Plugin, SchemaInitializer, useSchemaInitializer } from '@nocobase/client'; + +class PluginHome extends Plugin { + async load() { + this.router.add('home', { + path: '/', + Component: 'HomePage', + }); + const myInitializer = new SchemaInitializer({ + name: 'myInitializer', + title: 'Add block', + items: [ + { + name: 'helloBlock', + type: 'item', + useComponentProps() { + const { insert } = useSchemaInitializer(); + return { + title: 'Hello', + onClick: () => { + insert({ + type: 'void', + 'x-decorator': 'CardItem', + 'x-component': 'h1', + 'x-content': 'Hello, world!', + }); + }, + }; + }, + }, + ], + }); + this.schemaInitializerManager.add(myInitializer); + } +} + +export function createApp(options: any = {}) { + const { plugins = [] } = options; + return new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + designable: true, + plugins: [PluginHome, ...plugins], + }); +} diff --git a/docs/fr-FR/development/client/ui-schema/demos/use-schema-initializer-render/index.tsx b/docs/fr-FR/development/client/ui-schema/demos/use-schema-initializer-render/index.tsx new file mode 100644 index 000000000..6c57328f2 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/use-schema-initializer-render/index.tsx @@ -0,0 +1,50 @@ +import { useFieldSchema } from '@formily/react'; +import { + Plugin, + SchemaComponent, + useSchemaInitializerRender +} from '@nocobase/client'; +import React from 'react'; +import { createApp } from './app'; + +// 自定义 Hello 组件 +const Hello = (props) => { + return ( +
    + {props.children} + +
    + ) +} + +// 通过 useSchemaInitializerRender 来支持 x-initializer 的渲染 +const HelloInitializer = () => { + const fieldSchema = useFieldSchema(); + const { render } = useSchemaInitializerRender(fieldSchema['x-initializer']); + return render(); +} + +const HomePage = () => { + return ( + + ); +}; + +class PluginDemoUseSchemaInitializerRender extends Plugin { + async load() { + // 注册全局组件 + this.app.addComponents({ Hello, HomePage }); + } +} + +// 快捷模拟一个 App +const app = createApp({ plugins: [PluginDemoUseSchemaInitializerRender] }); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/demos/use-schema-settings-render/app.tsx b/docs/fr-FR/development/client/ui-schema/demos/use-schema-settings-render/app.tsx new file mode 100644 index 000000000..bc1b4d395 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/use-schema-settings-render/app.tsx @@ -0,0 +1,41 @@ +import { Application, Plugin, SchemaSettings } from '@nocobase/client'; + +class PluginHome extends Plugin { + async load() { + this.router.add('home', { + path: '/', + Component: 'HomePage', + }); + const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [ + { + type: 'item', + name: 'edit', + useComponentProps() { + // TODO: 补充相关设置逻辑 + return { + title: 'Edit', + onClick() { + // todo + }, + }; + }, + }, + ], + }); + this.schemaSettingsManager.add(mySettings); + } +} + +export function createApp(options: any = {}) { + const { plugins = [] } = options; + return new Application({ + router: { + type: 'memory', + initialEntries: ['/'], + }, + designable: true, + plugins: [PluginHome, ...plugins], + }); +} diff --git a/docs/fr-FR/development/client/ui-schema/demos/use-schema-settings-render/index.tsx b/docs/fr-FR/development/client/ui-schema/demos/use-schema-settings-render/index.tsx new file mode 100644 index 000000000..ec45e6421 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/demos/use-schema-settings-render/index.tsx @@ -0,0 +1,57 @@ +import { useFieldSchema } from '@formily/react'; +import { + Plugin, + SchemaComponent, + useSchemaSettingsRender +} from '@nocobase/client'; +import { Space } from 'antd'; +import React from 'react'; +import { createApp } from './app'; + +// 自定义 Hello 组件 +const Hello = (props) => { + return ( + + {props.children} + + + ); +}; + +// 通过 useSchemaSettingsRender 来支持 x-settings 的渲染 +const HelloSettings = () => { + const fieldSchema = useFieldSchema(); + const { render } = useSchemaSettingsRender(fieldSchema['x-settings']); + return render(); +}; + +const HomePage = () => { + return ( + + ); +}; + +class PluginDemoUseSchemaInitializerRender extends Plugin { + async load() { + // 注册全局组件 + this.app.addComponents({ Hello, HomePage }); + } +} + +// 快捷模拟一个 App +const app = createApp({ plugins: [PluginDemoUseSchemaInitializerRender] }); + +export default app.getRootComponent(); diff --git a/docs/fr-FR/development/client/ui-schema/designable.md b/docs/fr-FR/development/client/ui-schema/designable.md new file mode 100644 index 000000000..b1c020dba --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/designable.md @@ -0,0 +1,603 @@ +# Designable + +NocoBase provides design capabilities for Schema through the `createDesignable()` method. + +```ts +import React from 'react'; +import { Schema } from '@formily/json-schema'; +import { createDesignable } from '@nocobase/client'; + +// Create a schema example +const current = new Schema({ + name: 'root', + type: 'void', + 'x-component': 'Page', +}); + +// Create a designable for the current schema +const dn = createDesignable({ + current, +}); + +// Add a hello node inside the schema node +dn.insertAfterBegin({ + name: 'hello', + type: 'void', + 'x-component': 'Hello', +}); + +console.log(current.toJSON()); +{ + "name": "root", + "type": "void", + "x-component": "Page", + "properties": { + "hello": { + "type": "void", + "name": "hello", + "x-component": "Hello", + "x-index": 0 + } + } +} +``` + +In the Schema component, `useDesignable()` can be directly used to handle the current Schema node. + +```javascript +import React from 'react'; +import { Button } from 'antd'; +import { + SchemaComponent, + SchemaComponentProvider, + useDesignable, +} from '@nocobase.client'; + +const Hello = () =>

    Hello, world!

    ; + +const Page = (props) => { + const dn = useDesignable(); + return ( +
    + + {props.children} +
    + ); +}; + +const schema = { + type: 'void', + name: 'page', + 'x-component': 'Page', +}; + +export default () => { + return ( + + + + ); +}; +``` + +## createDesignable vs useDesignable + +- `createDesignable` requires the `current` parameter, while `useDesignable` is used directly on the current node without needing `current`. +- `createDesignable` can be used in events, while `useDesignable` is a React hook method that must be executed first. +- `createDesignable`'s `current` can be any schema, while `useDesignable` can only be the current schema. + +Use cases: + +- If it's clear that the operation is on the current node, using `useDesignable` is more convenient. +- If the operation is not on the current node, `createDesignable` is more appropriate. +- If the operation is triggered by an event, such as drag and drop, `createDesignable` is more suitable. + +## Design capabilities of designable + +The design capabilities provided by designable for schema are reflected in: + +- Add: Insert at an adjacent position of the current node. +- Query: Find child nodes. +- Modify: Change schema parameters via patch. +- Delete: Delete the current node or a specific child node. +- Move: Move between nodes. + +### Add: Insert at an adjacent position of the current node + +Similar to the DOM's [insert adjacent](https://dom.spec.whatwg.org/#insert-adjacent) concept, Schema also provides the `insertAdjacent()` method for resolving adjacent position insertion issues. + +Four adjacent positions: + +```html + +
    + +

    + + ... + +

    + +
    +``` + +The Schema is written as follows: + +```ts +{ + type: 'void', + 'x-component': 'div', + properties: { + // beforeBegin Insert before the current node + node1: { + type: 'void', + 'x-component': 'p', + properties: { + // afterBegin Insert before the first child of the current node + // ... + // beforeEnd Insert after the last child of the current node + }, + }, + // afterEnd Insert after the current node + }, +} +``` + +Use `useDesignable()` to insert at an adjacent position of the current schema. + +```tsx +import React from 'react'; +import { + SchemaComponentProvider, + SchemaComponent, + useDesignable, +} from '@nocobase/client'; +import { observer, Schema, useFieldSchema } from '@formily/react'; +import { Button, Space } from 'antd'; +import { uid } from '@formily/shared'; + +const Hello = (props) => { + const { insertAdjacent } = useDesignable(); + const fieldSchema = useFieldSchema(); + return ( +
    +

    + {fieldSchema.title} - {fieldSchema.name} +

    + + + + + + +
    {props.children}
    +
    + ); +}; + +const Page = (props) => { + return
    {props.children}
    ; +}; + +export default () => { + return ( + + + + ); +}; +``` + +Use `createDesignable()` to insert at an adjacent position of a specified schema. + +```tsx +import React from 'react'; +import { + SchemaComponentProvider, + SchemaComponent, + createDesignable, + useSchemaComponentContext, +} from '@nocobase/client'; +import { observer, Schema, useFieldSchema } from '@formily/react'; +import { Button } from 'antd'; +import { uid } from '@formily/shared'; + +const Hello = (props) => { + const fieldSchema = useFieldSchema(); + return ( +

    + {fieldSchema.title} - {fieldSchema.name} +

    + ); +}; + +const Page = (props) => { + const fieldSchema = useFieldSchema(); + const { refresh } = useSchemaComponentContext(); + + return ( +
    + + {props.children} +
    + ); +}; + +export default () => { + return ( + + + + ); +}; +``` + +### Query: Find child nodes + +formily's json-schema provides `reduceProperties` for traversing and finding nodes, but it's too cumbersome to use. Therefore, Designable provides easier-to-use `findProperties` and `findProperty` methods to find child nodes. + +#### `findProperties` + +Find all child nodes that meet the conditions and return an array. + +```ts +interface FindOptions { + // Filter conditions + filter: any; + // Elements to skip during the search + skipOn?: (s: Schema) => boolean; + // Exit when finding a certain element + breakOn?: (s: Schema) => boolean; + // Recursive search + recursive?: boolean; +} + +class Designable { + findProperties(options: FindOptions): Schema[]; +} +``` + +Example to find all nodes that meet the conditions: + +```ts +const items = dn.findProperties({ + filter: { + 'x-component': 'Hello', + }, +}); +// [current.properties.hello1, current.properties.hello2] +console.log(items.map((s) => schema.toJSON())); +[ + { + name: 'hello1', + type: 'void', + 'x-component': 'Hello', + }, + { + name: 'hello2', + type: 'void', + 'x-component': 'Hello', + }, +]; +``` + +#### `findProperty` + +Find the first child node that meets the conditions. + +```ts +interface FindOptions { + // Filter conditions + filter: any; + // Elements to skip during the search + skipOn?: (s: Schema) => boolean; + // Exit when finding a certain element + breakOn?: (s: Schema) => boolean; + // Recursive search + recursive?: boolean; +} + +class Designable { + findProperty(options: FindOptions): Schema | null; +} +``` + +Example: + +```ts +const current = new Schema({ + name: 'root', + type: 'void', + 'x-component': 'Page', + properties: { + hello1: { + type: 'void', + 'x-component': 'Hello', + }, + hello2: { + type: 'void', + 'x-component': 'Hello', + } + } +}); + +const dn = createDesignable({ current }); + +const schema = dn.findProperty({ + filter: { + 'x-component': 'Hello', + }, +}); +// current.properties.hello1 +console.log(schema.toJSON()); +{ + name: 'hello1', + type: 'void', + 'x-component': 'Hello', +} +``` + +### Modify: Change schema parameters + +```ts +const current = new Schema({ + name: 'root', + type: 'void', + 'x-component': 'Page', +}); + +const dn = createDesignable({ + current, +}); + +dn.deepMerge({ + 'x-component-props': {}, +}); + +dn.shallowMerge({ + 'x-component-props': {}, +}); +``` + +### Delete: Delete the current node or a specific child node + +```ts +const current = new Schema({ + name: 'root', + type: 'void', + 'x-component': 'Page', +}); + +const dn = createDesignable({ + current, +}); + +dn.remove(); + +dn.remove({ + filter: (s) => boolean, + skipOn: (s) => boolean, + breakOn: (s) => boolean, + recursive: true, + removeParentsIfNoChildren: true, +}); +``` + +### Move: Move between nodes + +`insertAdjacent` and other methods can also be used for node drag and drop movement. + +```javascript +import React from 'react'; +import { uid } from '@formily/shared'; +import { observer, useField, useFieldSchema } from '@formily/react'; +import { + DndContext, + DragEndEvent, + useDraggable, + useDroppable, +} from '@dnd-kit/core'; +import { + SchemaComponent, + SchemaComponentProvider, + createDesignable, + useSchemaComponentContext, +} from '@nocobase/client'; + +const useDragEnd = () => { + const { refresh } = useSchemaComponentContext(); + + return ({ active, over }: DragEndEvent) => { + const activeSchema = active?.data?.current?.schema; + const overSchema = over?.data?.current?.schema; + + if (!activeSchema or !overSchema) { + return; + } + + if (activeSchema === overSchema) { + return; + } + + const dn = createDesignable({ + current: overSchema, + }); + + dn.on('insertAdjacent', refresh); + dn.insertBeforeBeginOrAfterEnd(activeSchema); + }; +}; + +const Page = observer((props) => { + return {props.children}; +}); + +function Draggable(props) { + const { attributes, listeners, setNodeRef, transform } = useDraggable({ + id: props.id, + data: props.data, + }); + const style = transform + ? { + transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, + } + : undefined; + + return ( + + ); +} + +function Droppable(props) { + const { isOver, setNodeRef } = useDroppable({ + id: props.id, + data: props.data, + }); + const style = { + color: isOver ? 'green' : undefined, + }; + + return ( +
    + {props.children} +
    + ); +} + +const Block = observer((props) => { + const field = useField(); + const fieldSchema = useFieldSchema(); + return ( + +
    + Block {fieldSchema.name}{' '} + + Drag + +
    +
    + ); +}); + +export default function App() { + return ( + + + + ); +} +``` \ No newline at end of file diff --git a/docs/fr-FR/development/client/ui-schema/extending.md b/docs/fr-FR/development/client/ui-schema/extending.md new file mode 100644 index 000000000..eac4d95c4 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/extending.md @@ -0,0 +1,557 @@ +# Extending Schema Components + +In addition to native HTML tags, developers can adapt more custom components to enrich the Schema component library. + +Common methods for extending components include: + +- [connect](https://react.formilyjs.org/api/shared/connect): Non-intrusive integration with third-party components, generally used for adapting field components, often used in conjunction with [mapProps](https://react.formilyjs.org/api/shared/map-props) and [mapReadPretty](https://react.formilyjs.org/api/shared/map-read-pretty). +- [observer](https://react.formilyjs.org/api/shared/observer): Used when the component uses observable objects internally, and you want the component to respond to changes in the observable objects. + +## Simple Extension + +Register an existing React component directly. + +```tsx +/** + * defaultShowCode: true + */ +import React from 'react'; +import { SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; + +const Hello = () =>

    Hello, world!

    ; + +const schema = { + type: 'void', + name: 'hello', + 'x-component': 'Hello', +}; + +export default () => { + return ( + + + + ); +}; +``` + +## Integrating Third-Party Components with Connect + +```tsx +/** + * defaultShowCode: true + */ +import React from 'react'; +import { Input } from 'antd'; +import { connect, mapProps, mapReadPretty } from '@formily/react'; +import { SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; + +const ReadPretty = (props) => { + return
    {props.value}
    ; +}; + +const SingleText = connect( + Input, + mapProps((props, field) => { + return { + ...props, + suffix: 'Suffix', + }; + }), + mapReadPretty(ReadPretty), +); + +const schema = { + type: 'object', + properties: { + t1: { + type: 'string', + default: 'hello t1', + 'x-component': 'SingleText', + }, + t2: { + type: 'string', + default: 'hello t2', + 'x-component': 'SingleText', + 'x-pattern': 'readPretty', + }, + }, +}; + +export default () => { + return ( + + + + ); +}; +``` + +## Using Observer to Respond to Data Changes + +```tsx +/** + * defaultShowCode: true + */ +import React from 'react'; +import { Input } from 'antd'; +import { connect, observer, useForm } from '@formily/react'; +import { SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; + +const SingleText = connect(Input); + +const UsedObserver = observer( + (props) => { + const form = useForm(); + return
    UsedObserver: {form.values.t1}
    ; + }, + { displayName: 'UsedObserver' }, +); + +const NotUsedObserver = (props) => { + const form = useForm(); + return
    NotUsedObserver: {form.values.t1}
    ; +}; + +const schema = { + type: 'object', + properties: { + t1: { + type: 'string', + 'x-component': 'SingleText', + }, + t2: { + type: 'string', + 'x-component': 'UsedObserver', + }, + t3: { + type: 'string', + 'x-component': 'NotUsedObserver', + }, + }, +}; + +const components = { + SingleText, + UsedObserver, + NotUsedObserver, +}; + +export default () => { + return ( + + + + ); +}; +``` + +## Nested Schema + +- `props.children` nesting is suitable for `void` and `object` type properties. For examples, see [Nesting void and object type schema](#nesting-void-and-object-type-schema) +- `` for custom nesting, suitable for all types. For examples, see [Nesting array type schema](#nesting-array-type-schema). + +Note: + +- Properties other than `void` and `object` types cannot be directly rendered through `props.children`, but you can use `` to solve the nesting problem. +- Only `void` and `object` type schemas can be used with `onlyRenderProperties`. + +```tsx | pure + +``` + +### Nesting void and object type schema + +Properties nodes can be adapted directly through `props.children`. + +```tsx +/** + * defaultShowCode: true + */ +import React from 'react'; +import { SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; + +// The Hello component adapted children, allowing nested properties. +const Hello = (props) =>

    Hello, {props.children}!

    ; +const World = () => world; + +const schema = { + type: 'object', + name: 'hello', + 'x-component': 'Hello', + properties: { + world: { + type: 'string', + 'x-component': 'World', + }, + }, +}; + +export default () => { + return ( + + + + ); +}; +``` + +Rendering results comparison of various property types: + +```tsx +import React from 'react'; +import { SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; + +const Hello = (props) =>

    Hello, {props.children}!

    ; +const World = () => world; + +const schema = { + type: 'object', + properties: { + title1: { + type: 'void', + 'x-content': 'Void schema, rendering properties', + }, + void: { + type: 'void', + name: 'hello', + 'x-component': 'Hello', + properties: { + world: { + type: 'void', + 'x-component': 'World', + }, + }, + }, + title2: { + type: 'void', + 'x-content': 'Object schema, rendering properties', + }, + object: { + type: 'object', + name: 'hello', + 'x-component': 'Hello', + properties: { + world: { + type: 'string', + 'x-component': 'World', + }, + }, + }, + title3: { + type: 'void', + 'x-content': 'Array schema, not rendering properties', + }, + array: { + type: 'array', + name: 'hello', + 'x-component': 'Hello', + properties: { + world: { + type: 'string', + 'x-component': 'World', + }, + }, + }, + title4: { + type: 'void', + 'x-content': 'String schema, not rendering properties', + }, + string: { + type: 'string', + name: 'hello', + 'x-component': 'Hello', + properties: { + world: { + type: 'string', + 'x-component': 'World', + }, + }, + }, + }, +}; + +export default () => { + return ( + + + + ); +}; +``` + +### Nesting array type schema + +You can use `` to solve custom nesting issues. + +#### When array elements are string or number + +```tsx +import React from 'react'; +import { + useFieldSchema, + Schema, + RecursionField, + useField, + observer, + connect, +} from '@formily/react'; +import { SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; + +const useValueSchema = () => { + const schema = useFieldSchema(); + return schema.reduceProperties((buf, s) => { + if (s['x-component'] === 'Value') { + return s; + } + return buf; + }); +}; + +const ArrayList = observer( + (props) => { + const field = useField(); + const schema = useValueSchema(); + return ( + <> + String Array +
      + {field.value?.map((item, index) => { + // Only one element + return ; + })} +
    + + ); + }, + { displayName: 'ArrayList' }, +); + +const Value = connect((props) => { + return
  • value: {props.value}
  • ; +}); + +const schema = { + type: 'object', + properties: { + strArr: { + type: 'array', + default: [1, 2, 3], + 'x-component': 'ArrayList', + properties: { + value: { + type: 'number', + 'x-component': 'Value', + }, + }, + }, + }, +}; + +export default () => { + return ( + + + + ); +}; +``` + +#### When array elements are objects + +```tsx +import React from 'react'; +import { + useFieldSchema, + Schema, + RecursionField, + useField, + observer, + connect, +} from '@formily/react'; +import { SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; + +const ArrayList = observer( + (props) => { + const field = useField(); + const schema = useFieldSchema(); + // Convert array schema to object schema as array type schema cannot onlyRenderProperties + const objSchema = new Schema({ + type: 'object', + properties: schema.properties, + }); + return ( +
      + {field.value?.map((item, index) => { + // Array element is object + return ( + + ); + })} +
    + ); + }, + { displayName: 'ArrayList' }, +); + +const Value = connect((props) => { + return
  • value: {props.value}
  • ; +}); + +const schema = { + type: 'object', + properties: { + objArr: { + type: 'array', + default: [{ value: 't1' }, { value: 't2' }, { value: 't3' }], + 'x-component': 'ArrayList', + properties: { + value: { + type: 'number', + 'x-component': 'Value', + }, + }, + }, + }, +}; + +export default () => { + return ( + + + + ); +}; +``` + +#### Tree Structure Data + +```tsx +import { ArrayField } from '@formily/core'; +import { + connect, + ISchema, + observer, + RecursionField, + useField, + useFieldSchema, +} from '@formily/react'; +import { SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; +import { Table, TableColumnType } from 'antd'; +import React from 'react'; + +const ArrayTable = observer( + (props: any) => { + const { rowKey } = props; + const field = useField(); + const schema = useFieldSchema(); + const columnSchemas = schema.reduceProperties((buf, s) => { + if (s['x-component'] === 'ArrayTable.Column') { + buf.push(s); + } + return buf; + }, []); + + const columns = columnSchemas.map((s) => { + return { + render: (value, record) => { + return ( + + ); + }, + } as TableColumnType; + }); + + return ; + }, + { displayName: 'ArrayTable' }, +); + +const Value = connect((props) => { + return
  • value: {props.value}
  • ; +}); + +const schema: ISchema = { + type: 'object', + properties: { + objArr: { + type: 'array', + default: [ + { __path: '0', id: 1, value: 't1' }, + { + __path: '1', + id: 2, + value: 't2', + children: [ + { + __path: '1.children.0', + id: 5, + value: 't5', + parentId: 2, + }, + ], + }, + { + __path: '2', + id: 3, + value: 't3', + children: [ + { + __path: '2.children.0', + id: 4, + value: 't4', + parentId: 3, + children: [ + { + __path: '2.children.0.children.0', + id: 6, + value: 't6', + parentId: 4, + }, + { + __path: '2.children.0.children.1', + id: 7, + value: 't7', + parentId: 4, + }, + ], + }, + ], + }, + ], + 'x-component': 'ArrayTable', + 'x-component-props': { + rowKey: 'id', + }, + properties: { + c1: { + type: 'void', + 'x-component': 'ArrayTable.Column', + properties: { + value: { + type: 'string', + 'x-component': 'Value', + }, + }, + }, + }, + }, + }, +}; + +export default () => { + return ( + + + + ); +}; +``` \ No newline at end of file diff --git a/docs/fr-FR/development/client/ui-schema/image-1.png b/docs/fr-FR/development/client/ui-schema/image-1.png new file mode 100644 index 000000000..aa9ed4093 Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/image-1.png differ diff --git a/docs/fr-FR/development/client/ui-schema/image-2.png b/docs/fr-FR/development/client/ui-schema/image-2.png new file mode 100644 index 000000000..9ebd5b305 Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/image-2.png differ diff --git a/docs/fr-FR/development/client/ui-schema/image-3.png b/docs/fr-FR/development/client/ui-schema/image-3.png new file mode 100644 index 000000000..0101b5e48 Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/image-3.png differ diff --git a/docs/fr-FR/development/client/ui-schema/image-4.png b/docs/fr-FR/development/client/ui-schema/image-4.png new file mode 100644 index 000000000..40df1c17c Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/image-4.png differ diff --git a/docs/fr-FR/development/client/ui-schema/image-5.png b/docs/fr-FR/development/client/ui-schema/image-5.png new file mode 100644 index 000000000..3e6003a3f Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/image-5.png differ diff --git a/docs/fr-FR/development/client/ui-schema/image.png b/docs/fr-FR/development/client/ui-schema/image.png new file mode 100644 index 000000000..0ff383b8a Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/image.png differ diff --git a/docs/fr-FR/development/client/ui-schema/initializer.md b/docs/fr-FR/development/client/ui-schema/initializer.md new file mode 100644 index 000000000..fbc7d9d4d --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/initializer.md @@ -0,0 +1,120 @@ +# Schema initializer + +After activating the UI configuration, the various visible orange buttons on the interface are Schema initializers, used for adding various blocks, fields, actions, etc., to the interface. + + + +## Built-in initializers + + + +## Adding items to existing initializers + +It is recommended to use the [`schemaInitializerManager.addItem()`](#) method to add items. For detailed item configurations, refer to [SchemaInitializer Item API](#). + +```ts +class PluginDemoAddSchemaInitializerItem extends Plugin { + async load() { + this.schemaInitializerManager.addItem( + 'myInitializer', // Example of an existing schema initializer + 'otherBlocks.custom', // Add custom to the otherBlocks group + { + type: 'item', + useComponentProps() {}, + }, + ); + } +} +``` + + + +## Adding new initializers + +For detailed parameters of SchemaInitializer, refer to [SchemaInitializerOptions API](https://client.docs-cn.nocobase.com/core/ui-schema/schema-initializer#new-schemainitializeroptions). + +```ts +const myInitializer = new SchemaInitializer({ + // Unique identifier for the initializer + name: 'myInitializer', + title: 'Add Block', + // Wrapper, for example, inserting into a Grid requires using Grid.wrap (adds row and column tags) + wrap: Grid.wrap, + // Insertion position, defaults to beforeEnd, supports 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' + insertPosition: 'beforeEnd', + // Dropdown menu items + items: [ + { + name: 'a', + type: 'item', + useComponentProps() {}, + }, + ], +}); +``` + +### Registering in the plugin's load method + +It is recommended to use `schemaInitializerManager.add()` to add the new initializer to the application. + +```ts +class PluginDemoAddSchemaInitializer extends Plugin { + async load() { + const myInitializer = new SchemaInitializer({ + name: 'myInitializer', + title: 'Add block', + wrap: Grid.wrap, + items: [ + { + name: 'helloBlock', + type: 'item', + useComponentProps() { + const { insert } = useSchemaInitializer(); + return { + title: 'Hello', + onClick: () => { + insert({ + type: 'void', + 'x-decorator': 'CardItem', + 'x-component': 'h1', + 'x-content': 'Hello, world!', + }); + }, + }; + }, + }, + ], + }); + this.schemaInitializerManager.add(myInitializer); + } +} +``` + +### How to use the newly added initializer + +SchemaInitializer is used in the Schema's `x-initializer` parameter. + +#### Schema components that support `x-initializer` + +General Schema components that support `x-initializer` include Grid, ActionBar, Tabs. For example: + +```ts +{ + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'myInitializer', +} +``` + + + +#### How to support `x-initializer` in custom components + +If Grid, ActionBar, Tabs, and similar components do not meet your needs, you can use [useSchemaInitializerRender()](https://client.docs-cn.nocobase.com/core/ui-schema/schema-initializer#useschemainitializerrender) to handle the rendering of `x-initializer` in custom components. + + + +## API Reference + +- [SchemaInitializerManager](https://client.docs-cn.nocobase.com/core/ui-schema/schema-initializer-manager) +- [SchemaInitializer](https://client.docs-cn.nocobase.com/core/ui-schema/schema-initializer) \ No newline at end of file diff --git a/docs/fr-FR/development/client/ui-schema/quick-start.md b/docs/fr-FR/development/client/ui-schema/quick-start.md new file mode 100644 index 000000000..5f9e1be71 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/quick-start.md @@ -0,0 +1,37 @@ +# Quick start + +## 1. Create Schema Component + +Render registered components by configuring `x-component`. + +Key Concepts: + +- [UI Schema Protocol](/development/client/ui-schema/what-is-ui-schema) +- [Schema Rendering](/development/client/ui-schema/rendering) +- [Extending Schema Components](/development/client/ui-schema/extending) + + + +## 2. Add Schema Component to the Page + +Insert new components adjacent to existing Schemas by configuring `x-initializer`. + +Key Concepts: + +- [Designable Designer](/development/client/ui-schema/designable) +- [UI Schema Protocol - x-initializer Parameter](/development/client/ui-schema/what-is-ui-schema#x-initializer) +- [SchemaInitializer](/development/client/ui-schema/initializer) + + + +## 3. Add Designer Toolbar to Schema + +Provide a parameter configurator for Schema components by configuring `x-settings`. The designer toolbar has drag-and-drop functionality enabled by default. + +Key Concepts: + +- [UI Schema Protocol - x-settings Parameter](/development/client/ui-schema/what-is-ui-schema#x-settings) +- [SchemaSettings](/development/client/ui-schema/settings) +- [Dragging and Moving Existing Schema Nodes](/development/client/ui-schema/designable#move-between-nodes) + + \ No newline at end of file diff --git a/docs/fr-FR/development/client/ui-schema/rendering.md b/docs/fr-FR/development/client/ui-schema/rendering.md new file mode 100644 index 000000000..60f862b40 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/rendering.md @@ -0,0 +1,166 @@ +# Schema Rendering + +## Core Components + +Schema rendering involves several core components: + +- `` provides the context needed for schema rendering. +- `` extends components and scopes, optional. +- `` renders the schema, must be used within ``. + +Basic usage is as follows: + +```tsx +import React from 'react'; +import { SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; + +const Hello = () =>

    Hello, world!

    ; + +const schema = { + type: 'void', + name: 'hello', + 'x-component': 'Hello', +}; + +export default () => { + return ( + + + + ); +}; +``` + +For specific API details, refer to [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component). + +## What is Scope? + +Scope refers to variables or functions available within the schema. For example, the function `t()` in the following example needs to be registered in the scope to render the title correctly. + +```tsx | pure + +``` + +## Registering Components and Scopes + +Components and scopes can be registered with SchemaComponentProvider, SchemaComponentOptions, and SchemaComponent. The differences are: + +- SchemaComponentProvider provides the top-level context. +- SchemaComponentOptions is used to replace and extend the local context. +- SchemaComponent provides the current schema's context. + +For example: + +```tsx | pure + + + + + + + + +``` + +- schema1 can use ComponentA and ComponentB +- schema2 can use ComponentA and ComponentC +- schema3 can use ComponentA, ComponentD, and ComponentE +- schema4 can use ComponentA, ComponentD, and ComponentF + +## Using in Application + +The Application in the NocoBase client has built-in SchemaComponentProvider components in its Providers. + +```ts +class Application { + // Default Providers + addDefaultProviders() { + this.addProvider(SchemaComponentProvider, { + scopes: this.scopes, + components: this.components, + }); + } +} +``` + +The final rendering component structure is as follows: + +```tsx | pure + + {/* Context Provider for routing */} + + {/* Custom Provider components - start tag */} + + {/* Custom Provider components - end tag */} + + +``` + +When using it within the application, you don't need to wrap it with SchemaComponentProvider; you can directly use SchemaComponent. + +```tsx +import { + Application, + Plugin, + SchemaComponent, + SchemaComponentProvider, +} from '@nocobase/client'; +import React from 'react'; + +const Hello = () =>

    Hello, world!

    ; + +const HelloPage = () => { + return ( + + ); +}; + +class PluginHello extends Plugin { + async load() { + this.app.addProvider(SchemaComponentProvider, { + components: this.app.components, + scopes: this.app.scopes, + }); + this.app.addComponents({ Hello }); + this.router.add('hello', { + path: '/', + Component: HelloPage, + }); + } +} + +const app = new Application({ + router: { + type: 'memory', + }, + plugins: [PluginHello], +}); + +export default app.getRootComponent(); +``` + +In the application's lifecycle methods, you can use `app.addComponents()` and `app.addScopes()` to extend global components and scopes. + +```ts +class PluginHello extends Plugin { + async load() { + this.app.addComponents({ + // Extended components + }); + this.app.addScopes({ + // Extended scope + }); + } +} +``` \ No newline at end of file diff --git a/docs/fr-FR/development/client/ui-schema/settings.md b/docs/fr-FR/development/client/ui-schema/settings.md new file mode 100644 index 000000000..af70db6f7 --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/settings.md @@ -0,0 +1,136 @@ +# Schema settings + +After activating the UI configuration, when the mouse moves over a specific block, field, or action, the corresponding Schema toolbar will be displayed. The settings button in the toolbar is the settings component for the current Schema. + +![Alt text](https://static-docs.nocobase.com/3f37519ddd9ba1a99f1fdbfe32b4a454.png) + +## Built-in settings + + + +## Adding settings items to existing settings + +It is recommended to use the `schemaSettingsManager.addItem()` method to add settings items. For detailed item configurations, refer to [SchemaSettings Item API](#). + +```ts +class PluginDemoAddSchemaSettingsItem extends Plugin { + async load() { + this.schemaSettingsManager.addItem( + 'mySettings', // Example of existing schema settings + 'customItem', + { + type: 'item', + useComponentProps() {}, + }, + ); + } +} +``` + + + +## Adding new settings + +For detailed parameters of SchemaSettings, refer to [SchemaSettingsOptions API](https://client.docs-cn.nocobase.com/core/ui-schema/schema-settings#new-schemasettingsoptions). + +```ts +const mySettings = new SchemaSettings({ + // Must be a unique identifier + name: 'mySettings', + // Dropdown menu items + items: [ + { + name: 'edit', + type: 'item', + useComponentProps() {}, + }, + ], +}); +``` + +### Adding in the plugin's load method + +It is recommended to use `schemaSettingsManager.add()` to add the new settings to the application. + +```ts +class PluginDemoAddSchemaSettings extends Plugin { + async load() { + // Register global components + this.app.addComponents({ CardItem, HomePage }); + const mySettings = new SchemaSettings({ + name: 'mySettings', + items: [ + { + type: 'item', + name: 'edit', + useComponentProps() { + // TODO: Add relevant settings logic + return { + title: 'Edit', + onClick() { + // todo + }, + }; + }, + }, + ], + }); + this.schemaSettingsManager.add(mySettings); + } +} +``` + +### How to use the newly added settings + +The added SchemaSettings can be used in the Schema's `x-settings` parameter. Not all components support `x-settings`; it is usually used in combination with wrapper components such as BlockItem, FormItem, CardItem. In custom components, you can also use `useSchemaSettingsRender()` to handle the rendering of `x-settings` independently. + +#### Schema components that currently support `x-settings` + +In most scenarios, `x-settings` need to be used in combination with wrapper components such as BlockItem, FormItem, CardItem. For example: + +```ts +{ + type: 'void', + 'x-settings': 'mySettings', + 'x-decorator': 'CardItem', + 'x-component': 'Hello', +} +``` + + + +#### How to support `x-settings` in custom components + +If the wrapper components like BlockItem, FormItem, CardItem do not meet your needs, you can use `useSchemaSettingsRender()` to handle the rendering of `x-settings`. + + + +In most scenarios, settings are placed on the SchemaToolbar, so supporting `x-toolbar` for custom components can also indirectly support `x-settings`. For more usage details, refer to [Schema toolbar](/development/client/ui-schema/toolbar). + + + +## How to implement Schema settings? + +Use `useSchemaSettings()` to get the current Schema's `Designable`, and operate the Schema through `Designable`. Common APIs include: + +- `dn.insertAdjacent()` +- `dn.getSchemaAttribute()` +- `dn.shallowMerge()` +- `dn.deepMerge()` +- `dn.findOne()` +- `dn.find()` +- `dn.remove()` +- `dn.remove()` + +For more details, refer to: + +- [Designable Designer](/development/client/ui-schema/designable) +- [Designable API](https://client.docs-cn.nocobase.com/core/ui-schema/designable) + + + +## API Reference + +- [SchemaSettingsManager](https://client.docs-cn.nocobase.com/core/ui-schema/schema-settings-manager) +- [SchemaSettings](https://client.docs-cn.nocobase.com/core/ui-schema/schema-settings) +- [Designable](https://client.docs-cn.nocobase.com/core/ui-schema/designable) \ No newline at end of file diff --git a/docs/fr-FR/development/client/ui-schema/static/DFYhbY9Tpo5hX6x4Y3EckLV7nqc.png b/docs/fr-FR/development/client/ui-schema/static/DFYhbY9Tpo5hX6x4Y3EckLV7nqc.png new file mode 100644 index 000000000..d497c1cd1 Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/static/DFYhbY9Tpo5hX6x4Y3EckLV7nqc.png differ diff --git a/docs/fr-FR/development/client/ui-schema/static/LUChb8kzqoh3zsxVC4FcEP3Snqd.png b/docs/fr-FR/development/client/ui-schema/static/LUChb8kzqoh3zsxVC4FcEP3Snqd.png new file mode 100644 index 000000000..4117520fd Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/static/LUChb8kzqoh3zsxVC4FcEP3Snqd.png differ diff --git a/docs/fr-FR/development/client/ui-schema/static/MLUnbpVfFotjr1x0ZMacUzG4nlb.png b/docs/fr-FR/development/client/ui-schema/static/MLUnbpVfFotjr1x0ZMacUzG4nlb.png new file mode 100644 index 000000000..a2fd3b440 Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/static/MLUnbpVfFotjr1x0ZMacUzG4nlb.png differ diff --git a/docs/fr-FR/development/client/ui-schema/static/RruTbxqYuoThnAxXUkZc6Uz9n8f.png b/docs/fr-FR/development/client/ui-schema/static/RruTbxqYuoThnAxXUkZc6Uz9n8f.png new file mode 100644 index 000000000..a2b9796d2 Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/static/RruTbxqYuoThnAxXUkZc6Uz9n8f.png differ diff --git a/docs/fr-FR/development/client/ui-schema/static/VclIboKU9oukbpx3mpucfY9unQJ.png b/docs/fr-FR/development/client/ui-schema/static/VclIboKU9oukbpx3mpucfY9unQJ.png new file mode 100644 index 000000000..2ecb12d7b Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/static/VclIboKU9oukbpx3mpucfY9unQJ.png differ diff --git a/docs/fr-FR/development/client/ui-schema/static/WKbEbtLkYoDKU8xBlDBcxgMSnyf.png b/docs/fr-FR/development/client/ui-schema/static/WKbEbtLkYoDKU8xBlDBcxgMSnyf.png new file mode 100644 index 000000000..d483c02eb Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/static/WKbEbtLkYoDKU8xBlDBcxgMSnyf.png differ diff --git a/docs/fr-FR/development/client/ui-schema/static/WYuQbeZVioqB84xumakctLMGnkg.png b/docs/fr-FR/development/client/ui-schema/static/WYuQbeZVioqB84xumakctLMGnkg.png new file mode 100644 index 000000000..fcca6f417 Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/static/WYuQbeZVioqB84xumakctLMGnkg.png differ diff --git a/docs/fr-FR/development/client/ui-schema/static/Zqm5bBLh9o2M5BxDrWtcowE1nzb.png b/docs/fr-FR/development/client/ui-schema/static/Zqm5bBLh9o2M5BxDrWtcowE1nzb.png new file mode 100644 index 000000000..88082d2a9 Binary files /dev/null and b/docs/fr-FR/development/client/ui-schema/static/Zqm5bBLh9o2M5BxDrWtcowE1nzb.png differ diff --git a/docs/fr-FR/development/client/ui-schema/toolbar.md b/docs/fr-FR/development/client/ui-schema/toolbar.md new file mode 100644 index 000000000..20622ee4d --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/toolbar.md @@ -0,0 +1,61 @@ +# Schema toolbar + +After activating the UI configuration, a toolbar corresponding to the Schema will appear when the mouse hovers over the specified block, field, or action. + +![Alt text](https://static-docs.nocobase.com/e6d327da8e85d6548529e1051d06c31a.png) + +The toolbar consists of: + +- Title, default is empty +- Drag control, providing drag capability, default is draggable +- Initializer, default is empty +- Settings, default is empty + +```tsx | pure + +``` + +## Usage + +The SchemaToolbar component is used in `x-toolbar`, for example: + +```ts +// Using the built-in SchemaToolbar +{ + 'x-toolbar': 'SchemaToolbar', + 'x-toolbar-props': {}, +} +// Custom SchemaToolbar +{ + 'x-toolbar': 'MySchemaToolbar', + 'x-toolbar-props': {}, +} +``` + +## Schema components that support `x-toolbar` include + +- `BlockItem` (wrapper component, generally used in `x-decorator`) +- `CardItem` (wrapper component, generally used in `x-decorator`) +- `FormItem` (wrapper component, generally used in `x-decorator`) +- `Action` (action button component, used in `x-component`) + +If the schema's `x-component` or `x-decorator` uses the above components and `x-settings` is configured, `x-toolbar` can be omitted, and the built-in `SchemaToolbar` will be used by default. + + + +You can also customize the toolbar component. + + + +When used in a Grid layout, schemas within the rows and columns will inherit the Grid's `x-initializer`. + + + +## Supporting `x-toolbar` for custom components + + \ No newline at end of file diff --git a/docs/fr-FR/development/client/ui-schema/what-is-ui-schema.md b/docs/fr-FR/development/client/ui-schema/what-is-ui-schema.md new file mode 100644 index 000000000..dcedc044b --- /dev/null +++ b/docs/fr-FR/development/client/ui-schema/what-is-ui-schema.md @@ -0,0 +1,570 @@ +# UI Schema + +A protocol for describing frontend components, based on Formily Schema 2.0, in a JSON Schema style. + +```ts +interface ISchema { + type: 'void' | 'string' | 'number' | 'object' | 'array'; + name?: string; + title?: any; + // Decorator component + ['x-decorator']?: string; + // Decorator component properties + ['x-decorator-props']?: any; + // Dynamic decorator component properties + ['x-use-decorator-props']?: any; + // Component + ['x-component']?: string; + // Component properties + ['x-component-props']?: any; + // Dynamic component properties + ['x-use-component-props']?: any; + // Display state, default is 'visible' + ['x-display']?: 'none' | 'hidden' | 'visible'; + // Component's child nodes, simple usage + ['x-content']?: any; + // children node schema + properties?: Record; + + // Below are only used for field components + + // Field reactions + ['x-reactions']?: SchemaReactions; + // Field UI interaction mode, default is 'editable' + ['x-pattern']?: 'editable' | 'disabled' | 'readPretty'; + // Field validation + ['x-validator']?: Validator; + // Default data + default?: any; + + // For designer related + + // Initializer, determines what can be inserted adjacent to the current schema + ['x-initializer']?: string; + ['x-initializer-props']?: any; + + // Block settings, determines what parameters can be configured for the current schema + ['x-settings']?: string; + ['x-settings-props']?: any; + + // Toolbar component + ['x-toolbar']?: string; + ['x-toolbar-props']?: any; +} +``` + +## Examples + +### Simplest Component + +All native HTML tags can be written as schemas. For example: + +```ts +{ + type: 'void', + 'x-component': 'h1', + 'x-content': 'Hello, world!', +} +``` + +JSX Example + +```tsx | pure +

    Hello, world!

    +``` + +### Child Components + +Children components are written in properties + +```tsx | pure +{ + type: 'void', + 'x-component': 'div', + 'x-component-props': { className: 'form-item' }, + properties: { + title: { + type: 'string', + 'x-component': 'input', + }, + }, +} +``` + +Equivalent JSX + +```tsx | pure +
    + +
    +``` + +## Parameter Descriptions + +### `type` + +Type of the node + +```ts +type SchemaTypes = + | 'string' + | 'object' + | 'array' + | 'number' + | 'boolean' + | 'void'; +interface ISchema { + type?: SchemaTypes; +} +``` + +### `name` + +Schema name + +```ts +type SchemaName = string; +interface ISchema { + name?: SchemaName; // Root node + properties?: { + [name: SchemaName]?: ISchema; // Child node + } +}; +``` + +All schemas have a name, and child node names are also the keys of properties + +```ts +{ + name: 'root', + properties: { + child1: { + // No need to write name here + }, + }, +} +``` + +### `title` + +Node title + +```ts +type SchemaTitle = string; +interface ISchema { + title?: SchemaTitle; +} +``` + +### `properties` + +Children components can be written in properties + +```ts +{ + type: 'void', + 'x-component': 'div', + 'x-component-props': { className: 'form-item' }, + properties: { + title: { + type: 'string', + 'x-component': 'input', + }, + }, +} +``` + +Equivalent JSX + +```tsx | pure +
    + +
    +``` + +### `x-component` + +Component + +```ts +type Component = any; +interface ISchema { + ['x-component']?: Component; +} +``` + +All native HTML tags can be written as schemas. For example: + +```ts +{ + type: 'void', + 'x-component': 'h1', + 'x-content': 'Hello, world!', +} +``` + +JSX Example + +```tsx | pure +

    Hello, world!

    +``` + +### `x-component-props` and `x-use-component-props` + +`x-component-props` are component properties. + +```ts +{ + type: 'void', + 'x-component': 'Table', + 'x-component-props': { + loading: true, + }, +} +``` + +In some cases, component properties are dynamic, so you can use `x-use-component-props`. + +```ts +{ + type: 'void', + 'x-component': 'MyTable', + 'x-use-component-props': 'useTableProps', +} +``` + +The `MyTable` component needs to be wrapped with a higher-order function `withDynamicSchemaProps`. For example: + +```ts +const MyTable = withDynamicSchemaProps(Table, { displayName: 'MyTable' }); +``` + +`useTableProps` is a custom hook for dynamically generating component properties. + +```ts +const useTableProps = () => { + const service = useRequest({xx}); + return { + loading: service.loading, + }; +}; +``` + +You also need to register it in the scope, refer to the documentation [Schema Rendering](/development/client/ui-schema/rendering). + +```tsx | pure + +``` + +### `x-decorator` + +Decorator component + +```ts +type Decorator = any; +interface ISchema { + ['x-decorator']?: Decorator; +} +``` + +The combination of x-decorator and x-component allows you to place two components in one schema node, reducing schema structure complexity and increasing component reusability. + +For example, in a form scenario, you can combine the FormItem component with any field component, where FormItem is the Decorator. + +```ts +{ + type: 'void', + ['x-component']: 'div', + properties: { + title: { + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'Input', + }, + content: { + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'Input.TextArea', + }, + }, +} +``` + +Equivalent JSX + +```tsx | pure +
    + + + + + + +
    +``` + +You can also provide a CardItem component to wrap all blocks, so all blocks are wrapped by Card. + +```ts +{ + type: 'void', + ['x-component']: 'div', + properties: { + table: { + type: 'array', + 'x-decorator': 'CardItem', + 'x-component': 'Table', + }, + kanban: { + type: 'array', + 'x-decorator': 'CardItem', + 'x-component': 'Kanban', + }, + }, +} +``` + +Equivalent JSX + +```tsx | pure +
    + +
    + + + + + +``` + +### `x-decorator-props` and `x-use-decorator-props` + +Use similarly to `x-component-props` and `x-use-component-props`. The `withDynamicSchemaProps()` higher-order function needs to be used for decorator components. + +### `x-display` + +Component display state + +- `'x-display': 'visible'`: Show component +- `'x-display': 'hidden'`: Hide component, data is not hidden +- `'x-display': 'none'`: Hide component, data is also hidden + +#### `'x-display': 'visible'` + +```ts +{ + type: 'void', + 'x-component': 'div', + 'x-component-props': { className: 'form-item' }, + properties: { + title: { + type: 'string', + 'x-component': 'input', + 'x-display': 'visible' + }, + }, +} +``` + +Equivalent JSX + +```tsx | pure +
    + +
    +``` + +#### `'x-display': 'hidden'` + +```ts +{ + type: 'void', + 'x-component': 'div', + 'x-component-props': { className: 'form-item' }, + properties: { + title: { + type: 'string', + 'x-component': 'input', + 'x-display': 'hidden' + }, + }, +} +``` + +Equivalent JSX + +```tsx | pure +
    + {/* No input component is output here, but the field model with name=title still exists */} +
    +``` + +#### `'x-display': 'none'` + +```ts +{ + type: 'void', + 'x-component': 'div', + 'x-component-props': { className: 'form-item' }, + properties: { + title: { + type: 'string', + 'x-component': 'input', + 'x-display': 'none' + }, + }, +} +``` + +Equivalent JSX + +```tsx | pure +
    + {/* No input component is output here, and the field model with name=title does not exist */} +
    +``` + +### `x-pattern` + +Component display mode + +Used for field components, there are three display modes: + +- `'x-pattern': 'editable'`: Editable +- `'x-pattern': 'disabled'`: Non-editable +- `'x-pattern': 'readPretty'`: Read-only + +For example, the single-line text `` component, editable and non-editable modes are ``, read-only mode is `
    `. + +#### `'x-pattern': 'editable'` + +```ts +const schema = { + name: 'test', + type: 'void', + 'x-component': 'div', + 'x-component-props': { className: 'form-item' }, + properties: { + title: { + type: 'string', + default: 'Hello', + 'x-component': 'SingleText', + 'x-pattern': 'editable', + }, + }, +}; +``` + +Equivalent JSX + +```tsx | pure +
    + +
    +``` + +#### `'x-pattern': 'disabled'` + +```ts +const schema = { + name: 'test', + type: 'void', + 'x-component': 'div', + 'x-component-props': { className: 'form-item' }, + properties: { + title: { + type: 'string', + default: 'Hello', + 'x-component': 'SingleText', + 'x-pattern': 'disabled', + }, + }, +}; +``` + +Equivalent JSX + +```tsx | pure +
    + +
    +``` + +#### `'x-pattern': 'readPretty'` + +```ts +const schema = { + name: 'test', + type: 'void', + 'x-component': 'div', + 'x-component-props': { className: 'form-item' }, + properties: { + title: { + type: 'string', + default: 'Hello', + 'x-component': 'SingleText', + 'x-pattern': 'readPretty', + }, + }, +}; +``` + +Equivalent JSX + +```tsx | pure +
    +
    Hello
    +
    +``` + +### `x-initializer` + +Not all components support `x-initializer`. Among existing common schema components, only Grid, ActionBar, and Tabs support the `x-initializer` parameter. + +```ts +{ + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'myInitializer', +} +``` + +Custom components can also use `useSchemaInitializerRender()` to handle `x-initializer` rendering. Refer to the [SchemaInitializer Initializer](/development/client/ui-schema/initializer) section for detailed usage. + +### `x-settings` + +Not all components support `x-settings`. Usually, it needs to be combined with wrapper components such as BlockItem, FormItem, CardItem. + +```ts +{ + type: 'void', + 'x-settings': 'mySettings', + 'x-decorator': 'CardItem', + 'x-component': 'Hello', +} +``` + +Custom components can also use `useSchemaSettingsRender()` to handle `x-settings` rendering. Refer to the [SchemaSettings Configurator](/development/client/ui-schema/settings) section for detailed usage. + +### `x-toolbar` + +Not all components support `x-toolbar`. Usually, it needs to be combined with wrapper components such as BlockItem, FormItem, CardItem. + +```ts +{ + type: 'void', + 'x-toolbar': 'HelloToolbar', + 'x-decorator': 'CardItem', + 'x-component': 'Hello', +} +``` + +Custom components can also use `useToolbarRender()` to handle `x-toolbar` rendering. Refer to the [SchemaToolbar Toolbar](/development/client/ui-schema/toolbar) section for detailed usage. \ No newline at end of file diff --git a/docs/fr-FR/development/http-api/action-api.md b/docs/fr-FR/development/http-api/action-api.md new file mode 100644 index 000000000..26fd5e1b8 --- /dev/null +++ b/docs/fr-FR/development/http-api/action-api.md @@ -0,0 +1,139 @@ +# Action API + +## Common + +--- + +Collection 和 Association 资源通用。 + +### `create` + +```bash +POST /api/users:create?whitelist=a,b&blacklist=c,d + +{} # Request Body +``` + +- Parameters + - whitelist 白名单 + - blacklist 黑名单 +- Request body: 待插入的 JSON 数据 +- Response body data: 已创建的数据 JSON + +#### 新增用户 + +```bash +POST /api/users:create + +Request Body +{ + "email": "demo@nocobase.com", + "name": "Admin" +} + +Response 200 (application/json) +{ + "data": {}, +} +``` + +#### 新增用户文章 + +```bash +POST /api/users/1/posts:create + +Request Body +{ + "title": "My first post" +} + +Response 200 (application/json) +{ + "data": {} +} +``` + +#### Request Body 里的 association + +```bash +POST /api/posts:create + +Request Body +{ + "title": "My first post", + "user": 1 +} + +Response 200 (application/json) +{ + "data": { + "id": 1, + "title": "My first post", + "userId": 1, + "user": { + "id": 1 + } + } +} +``` + +### `update` + +```bash +POST /api/users:create?filterByTk=1&whitelist=a,b&blacklist=c,d + +{} # Request Body +``` + +- Parameters + - whitelist 白名单 + - blacklist 黑名单 + - filterByTk 根据 tk 字段过滤,默认情况 tk 为数据表的主键 + - filter 过滤,支持 json string +- Request body: 待更新的 JSON 数据 + +#### Request Body 里的 association + +```bash +POST /api/posts:update/1 + +Request Body +{ + "title": "My first post 2", + "user": 2 +} + +Response 200 (application/json) +{ + "data": [ + { + "id": 1, + "title": "My first post 2", + "userId": 2, + "user": { + "id": 2 + } + } + ] +} +``` + +### `list` + +### `get` + +### `destroy` + +### `move` + +## Association + +--- + +### `add` + +### `set` + +### `remove` + +### `toggle` diff --git a/docs/fr-FR/development/http-api/filter-operators.md b/docs/fr-FR/development/http-api/filter-operators.md new file mode 100644 index 000000000..332f28a50 --- /dev/null +++ b/docs/fr-FR/development/http-api/filter-operators.md @@ -0,0 +1,59 @@ +# Filter operators + +## 通用 + +- $eq +- $ne +- $gte +- $gt +- $lte +- $lt +- $not +- $is +- $in +- $notIn +- $like +- $notLike +- $iLike +- $notILike +- $and +- $or +- $empty +- $notEmpty + +## array + +- $match +- $notMatch +- $anyOf +- $noneOf +- $arrayEmpty +- $arrayNotEmpty + +## association + +- $exists +- $notExists + +## boolean + +- $isTruly +- $isFalsy + +## date + +- $dateOn +- $dateNotOn +- $dateBefore +- $dateNotBefore +- $dateAfter +- $dateNotAfter + +## string + +- $includes +- $notIncludes +- $startsWith +- $notStartsWith +- $endWith +- $notEndWith diff --git a/docs/fr-FR/development/http-api/index.md b/docs/fr-FR/development/http-api/index.md new file mode 100644 index 000000000..8dc58486d --- /dev/null +++ b/docs/fr-FR/development/http-api/index.md @@ -0,0 +1,301 @@ +# 概述 + +NocoBase 的 HTTP API 基于 Resource & Action 设计,是 REST API 的超集,操作不局限于增删改查,在 NocoBase 里,Resource Action 可以任意的扩展。 + +## 资源 Resource + +在 NocoBase 里,资源(resource)有两种表达方式: + +- `` +- `.` + + + +- collection 是所有抽象数据的集合 +- association 为 collection 的关联数据 +- resource 包括 collection 和 collection.association 两类 + + + +### 示例 + +- `posts` 文章 +- `posts.user` 文章用户 +- `posts.tags` 文章标签 + +## 操作 Action + +以 `:` 的方式表示资源操作 + +- `:` +- `.:` + +内置的全局操作,可用于 collection 或 association + +- `create` +- `get` +- `list` +- `update` +- `destroy` +- `move` + +内置的关联操作,仅用于 association + +- `set` +- `add` +- `remove` +- `toggle` + +### 示例 + +- `posts:create` 创建文章 +- `posts.user:get` 查看文章用户 +- `posts.tags:add` 附加文章标签(将现有的标签与文章关联) + +## 请求 URL + +```bash + /api/: + /api/:/ + /api///: + /api///:/ +``` + +### 示例 + +posts 资源 + +```bash +POST /api/posts:create +GET /api/posts:list +GET /api/posts:get/1 +POST /api/posts:update/1 +POST /api/posts:destroy/1 +``` + +posts.comments 资源 + +```bash +POST /api/posts/1/comments:create +GET /api/posts/1/comments:list +GET /api/posts/1/comments:get/1 +POST /api/posts/1/comments:update/1 +POST /api/posts/1/comments:destroy/1 +``` + +posts.tags 资源 + +```bash +POST /api/posts/1/tags:create +GET /api/posts/1/tags:get +GET /api/posts/1/tags:list +POST /api/posts/1/tags:update +POST /api/posts/1/tags:destroy +POST /api/posts/1/tags:add +GET /api/posts/1/tags:remove +``` + +## 资源定位 + +- collection 资源,通过 `collectionIndex` 定位到待处理的数据,`collectionIndex` 必须唯一 +- association 资源,通过 `collectionIndex` 和 `associationIndex` 联合定位待处理的数据,`associationIndex` 可能不是唯一的,但是 `collectionIndex` 和 `associationIndex` 的联合索引必须唯一 + +查看 association 资源详情时,请求的 URL 需要同时提供 `` 和 ``,`` 并不多余,因为 `` 可能不是唯一的。 + +例如 `tables.fields` 表示数据表的字段 + +```bash +GET /api/tables/table1/fields/title +GET /api/tables/table2/fields/title +``` + +table1 和 table2 都有 title 字段,title 在 table1 里是唯一的,但是其他表也可能有 title 字段 + +## 请求参数 + +请求的参数可以放在 Request 的 headers、parameters(query string)、body(GET 请求没有 body) 里。 + +几个特殊的 Parameters 请求参数 + +- `filter` 数据过滤,用于查询相关操作里; +- `filterByTk` 根据 tk 字段字过滤,用于指定详情数据的操作里; +- `sort` 排序,用于查询相关操作里。 +- `fields` 输出哪些数据,用于查询相关操作里; +- `appends` 附加关系字段,用于查询相关操作里; +- `except` 排除哪些字段(不输出),用于查询相关操作里; +- `whitelist` 字段白名单,用于数据的创建和更新相关操作里; +- `blacklist` 字段黑名单,用于数据的创建和更新相关操作里; + +### filter + +数据过滤 + +```bash +# simple +GET /api/posts?filter[status]=publish +# 推荐使用 json string 的格式,需要 encodeURIComponent 编码 +GET /api/posts?filter={"status":"published"} + +# filter operators +GET /api/posts?filter[status.$eq]=publish +GET /api/posts?filter={"status.$eq":"published"} + +# $and +GET /api/posts?filter={"$and": [{"status.$eq":"published"}, {"title.$includes":"a"}]} +# $or +GET /api/posts?filter={"$or": [{"status.$eq":"pending"}, {"status.$eq":"draft"}]} + +# association field +GET /api/posts?filter[user.email.$includes]=gmail +GET /api/posts?filter={"user.email.$includes":"gmail"} +``` + +[点此查看更多关于 filter operators 的内容](http-api/filter-operators) + +### filterByTk + +根据 tk 字段过滤,默认情况: + +- collection 资源,tk 为数据表的主键; +- association 资源,tk 为 association 的 targetKey 字段。 + +```bash +GET /api/posts:get?filterByTk=1&fields=name,title&appends=tags +``` + +### sort + +排序。降序时,字段前面加上减号 `-`。 + +```bash +# createAt 字段升序 +GET /api/posts:get?sort=createdAt +# createAt 字段降序 +GET /api/posts:get?sort=-createdAt +# 多个字段联合排序,createAt 字段降序、title A-Z 升序 +GET /api/posts:get?sort=-createdAt,title +``` + +### fields + +输出哪些数据 + +```bash +GET /api/posts:list?fields=name,title + +Response 200 (application/json) +{ + "data": [ + { + "name": "", + "title": "" + } + ], + "meta": {} +} +``` + +### appends + +附加关系字段 + +### except + +排除哪些字段(不输出),用于查询相关操作里; + +### whitelist + +白名单 + +```bash +POST /api/posts:create?whitelist=title + +{ + "title": "My first post", + "date": "2022-05-19" # date 字段会被过滤掉,不会写入数据库 +} +``` + +### blacklist + +黑名单 + +```bash +POST /api/posts:create?blacklist=date + +{ + "title": "My first post", + "date": "2022-05-19" # date 字段会被过滤掉,不会写入数据库 +} +``` + +## 请求响应 + +响应的格式 + +```ts +type ResponseResult = { + data?: any; // 主体数据 + meta?: any; // 附加数据 + errors?: ResponseError[]; // 报错 +}; + +type ResponseError = { + code?: string; + message: string; +}; +``` + +### 示例 + +查看列表 + +```bash +GET /api/posts:list + +Response 200 (application/json) + +{ + data: [ + { + id: 1 + } + ], + meta: { + count: 1 + page: 1, + pageSize: 1, + totalPage: 1 + }, +} +``` + +查看详情 + +```bash +GET /api/posts:get/1 + +Response 200 (application/json) + +{ + data: { + id: 1 + }, +} +``` + +报错 + +```bash +POST /api/posts:create + +Response 400 (application/json) + +{ + errors: [ + { + message: 'name must be required', + }, + ], +} +``` diff --git a/docs/fr-FR/development/http-api/rest-api.md b/docs/fr-FR/development/http-api/rest-api.md new file mode 100644 index 000000000..2d7fd86d5 --- /dev/null +++ b/docs/fr-FR/development/http-api/rest-api.md @@ -0,0 +1,184 @@ +# REST API + +NocoBase 的 HTTP API 是 REST API 的超集,标准的 CRUD API 也支持 RESTful 风格。 + +## Collection 资源 + +--- + +### 创建 collection + +HTTP API + +```bash +POST /api/:create + +{} # JSON body +``` + +REST API + +```bash +POST /api/ + +{} # JSON body +``` + +### 查看 collection 列表 + +HTTP API + +```bash +GET /api/:list +``` + +REST API + +```bash +GET /api/ +``` + +### 查看 collection 详情 + +HTTP API + +```bash +GET /api/:get?filterByTk= +GET /api/:get/ +``` + +REST API + +```bash +GET /api// +``` + +### 更新 collection + +HTTP API + +```bash +POST /api/:update?filterByTk= + +{} # JSON body + +# 或者 +POST /api/:update/ + +{} # JSON body +``` + +REST API + +```bash +PUT /api// + +{} # JSON body +``` + +### 删除 collection + +HTTP API + +```bash +POST /api/:destroy?filterByTk= +# 或者 +POST /api/:destroy/ +``` + +REST API + +```bash +DELETE /api// +``` + +## Association 资源 + +--- + +### 创建 Association + +HTTP API + +```bash +POST /api///:create + +{} # JSON body +``` + +REST API + +```bash +POST /api/// + +{} # JSON body +``` + +### 查看 Association 列表 + +HTTP API + +```bash +GET /api///:list +``` + +REST API + +```bash +GET /api/// +``` + +### 查看 Association 详情 + +HTTP API + +```bash +GET /api///:get?filterByTk= +# 或者 +GET /api///:get/ +``` + +REST API + +```bash +GET /api///:get/ +``` + +### 更新 Association + +HTTP API + +```bash +POST /api///:update?filterByTk= + +{} # JSON body + +# 或者 +POST /api///:update/ + +{} # JSON body +``` + +REST API + +```bash +PUT /api///:update/ + +{} # JSON 数据 +``` + +### 删除 Association + +HTTP API + +```bash +POST /api///:destroy?filterByTk= +# 或者 +POST /api///:destroy/ +``` + +REST API + +```bash +DELETE /api//// +``` diff --git a/docs/fr-FR/development/image-1.png b/docs/fr-FR/development/image-1.png new file mode 100644 index 000000000..97e973eed Binary files /dev/null and b/docs/fr-FR/development/image-1.png differ diff --git a/docs/fr-FR/development/index.md b/docs/fr-FR/development/index.md new file mode 100644 index 000000000..6d7af06e5 --- /dev/null +++ b/docs/fr-FR/development/index.md @@ -0,0 +1,37 @@ +# Introduction + +NocoBase adopts a microkernel architecture, where various functionalities are extended in the form of plugins. The plugin-based design reduces the coupling between modules, increasing reusability. With the continuous expansion of the plugin library, common scenarios can be easily built by combining plugins. NocoBase's no-code platform is composed of various plugins. + +## Plugin Manager + +NocoBase provides a powerful plugin manager to handle plugin management. No-code users can manage the addition, activation, deactivation, and deletion of plugins through the interface. + +![Plugin Manager](https://static-docs.nocobase.com/f914d978dbfd8c45a650bd88ef867832.png) + +Developers can also manage plugins through the CLI. + +For more plugin examples, see [packages/samples](https://github.com/nocobase/nocobase/tree/main/packages/plugins/%40nocobase). + +## Extensibility + +Whether it's generic functionalities or personalized customization, they can be written in the form of plugins. NocoBase's extensibility is reflected in various aspects: + +- It can be visible user interface-related page modules, block types, operation types, field types, etc. +- It can also be used for enhancing or restricting HTTP API filters, validators, access restrictions, etc. +- It can also be more fundamental enhancements of features such as data tables, migrations, events, command-line, etc. + +Modules are distributed as follows: + +- Server-side + - Data tables and fields + - Resources and operations + - Middleware + - Events + - Custom command-line + - Internationalization +- Client-side + - Route management and plugin configuration pages + - Styles and themes + - Providers and contexts + - UI Schema + - Internationalization diff --git a/docs/fr-FR/development/index/app-flow.svg b/docs/fr-FR/development/index/app-flow.svg new file mode 100644 index 000000000..e167cda39 --- /dev/null +++ b/docs/fr-FR/development/index/app-flow.svg @@ -0,0 +1 @@ +
    beforeLoad
    loop: plugin.beforeLoad()
    load/reload
    loop: plugin.load()
    afterLoad
    Reinstall?
    beforeInstall
    install
    afterInstall
    beforeUpgrade
    upgrade
    afterUpgrade
    Restart?
    beforeStart
    start
    afterStart
    beforeStop
    stop
    afterStop
    beforeDestroy
    destroy
    afterDestroy
    \ No newline at end of file diff --git a/docs/fr-FR/development/index/pm-built-in.jpg b/docs/fr-FR/development/index/pm-built-in.jpg new file mode 100644 index 000000000..2fe60fdac Binary files /dev/null and b/docs/fr-FR/development/index/pm-built-in.jpg differ diff --git a/docs/fr-FR/development/index/pm-flow.svg b/docs/fr-FR/development/index/pm-flow.svg new file mode 100644 index 000000000..23a738cfc --- /dev/null +++ b/docs/fr-FR/development/index/pm-flow.svg @@ -0,0 +1 @@ +
    Local
    pm.create
    Marketplace
    pm.publish
    NPM registry
    Extracting client files
    pm.add
    plugin.afterAdd()
    app/client plugins
    pm.enable
    plugin.install()
    plugin.afterEnable()
    pm.disable
    plugin.afterDisable()
    pm.remove
    plugin.remove()
    pm.upgrade
    \ No newline at end of file diff --git a/docs/fr-FR/development/index/pm-ui.jpg b/docs/fr-FR/development/index/pm-ui.jpg new file mode 100644 index 000000000..4c8fdd3c1 Binary files /dev/null and b/docs/fr-FR/development/index/pm-ui.jpg differ diff --git a/docs/fr-FR/development/learning-guide.md b/docs/fr-FR/development/learning-guide.md new file mode 100644 index 000000000..115402259 --- /dev/null +++ b/docs/fr-FR/development/learning-guide.md @@ -0,0 +1,125 @@ +# 学习路线指南 + +## 1. 从安装运行 NocoBase 开始 + +**相关文档:快速开始** + +主要命令包括: + +下载 + +```bash +yarn create/git clone +yarn install +``` + +安装 + +```bash +yarn nocobase install +``` + +运行 + +```bash +# for development +yarn dev + +# for production +yarn build +yarn start +``` + +## 2. 了解 NocoBase 平台提供的核心功能 + +**相关文档:使用手册** + +主要的三部分包括: + +- UI 设计器:主要包括区块、字段和操作 +- 插件管理器:功能需求扩展 +- 配置中心:已激活插件提供的配置功能 + +## 3. 进一步了解插件管理器的使用 + +**相关文档:插件开发** + +NocoBase 提供了简易的插件管理器界面,但是在界面上只能处理本地插件的 enable、disable 和 remove,完整的操作需要通过 CLI + +```bash +# 创建插件 +yarn pm create hello +# 注册插件 +yarn pm add hello +# 激活插件 +yarn pm enable hello +# 禁用插件 +yarn pm disable hello +# 删除插件 +yarn pm remove hello +``` + +更多插件示例,查看 packages/samples,通过 samples 插件能够了解插件的基本用法,就可以进一步开发插件了。 + +## 4. 开发新插件,了解模块分布 + +**相关文档:扩展指南** + +[编写第一个插件](/development/your-fisrt-plugin) 章节,虽然简单的讲述了插件的主要开发流程,但是为了更快速的介入插件细节,你可能需要进一步了解 NocoBase 框架的模块分布: + +- Server + - Collections & Fields:主要用于系统表配置,业务表建议在「配置中心 - 数据表配置」里配置 + - Resources & Actions:主要用于扩展 Action API + - Middleware:中间件 + - Events:事件 + - I18n:服务端国际化 +- Client + - UI Schema Designer:页面设计器 + - UI Router:有自定义页面需求时 + - Plugin Settings Manager:为插件提供配置页面 + - I18n:客户端国际化 +- Devtools + - Commands:自定义命令行 + - Migrations:迁移脚本 + +## 5. 查阅各模块主要 API + +**相关文档:API 参考** + +查看各模块的 packages/samples,进一步了解模块主要 API 的用法 + +- Server + - Collections & Fields + - db.collection + - db.import + - Resources & Actions + - app.resourcer.define + - app.resourcer.registerActions + - Middleware + - app.use + - app.acl.use + - app.resourcer.use + - Events + - app.on + - app.db.on + - I18n + - app.i18n + - ctx.i18n +- Client + - UI Schema Designer + - SchemaComponent + - SchemaInitializer + - SchemaSettings + - UI Router + - RouteSwitchProvider + - RouteSwitch + - I18n + - app.i18n + - useTranslation +- Devtools + - Commands + - app.command + - app.findCommand + - Migrations + - app.db.addMigration + - app.db.addMigrations diff --git a/docs/fr-FR/development/life-cycle.md b/docs/fr-FR/development/life-cycle.md new file mode 100644 index 000000000..c3a1b612e --- /dev/null +++ b/docs/fr-FR/development/life-cycle.md @@ -0,0 +1,35 @@ +# Lifecycle + +## Lifecycle of the server-side application + +Lifecycle of the server-side application + +Triggered by `app.on()`, see [Server-side - Events](/development/server/events) for details. + +```ts +class PluginSampleHelloServer extends Plugin { + async beforeLoad() { + this.app.on('beforeInstall', async () => { + // coding... + }); + } +} +``` + +## Lifecycle of the server-side plugin + +Lifecycle of the server-side plugin + +Written in the plugin class, see [Server - Overview](/development/server) for usage details. + +```ts +class PluginSampleHelloServer extends Plugin { + async beforeLoad() {} +} +``` + +## Lifecycle of the client-side plugin + +Lifecycle of the client-side plugin + +Written in the plugin class, see [Client - Overview](/development/client) for usage details. diff --git a/docs/fr-FR/development/others/build.md b/docs/fr-FR/development/others/build.md new file mode 100644 index 000000000..70a3f9a61 --- /dev/null +++ b/docs/fr-FR/development/others/build.md @@ -0,0 +1,34 @@ +# Building + +## Custom Build Configuration + +If you want to customize the build configuration, you can create a `build.config.ts` file in the root directory of the plugin with the following content: + +```js +import { defineConfig } from '@nocobase/build'; + +export default defineConfig({ + modifyViteConfig: (config) => { + // Vite is used for packaging the `src/client` side code + + // Modify the Vite configuration. For details, refer to: https://vitejs.dev/guide/ + return config; + }, + modifyTsupConfig: (config) => { + // Tsup is used for packaging the `src/server` side code + + // Modify the Tsup configuration. For details, refer to: https://tsup.egoist.dev/#using-custom-configuration + return config; + }, + beforeBuild: (log) => { + // Callback function before the build starts. You can perform some actions before the build. + }, + afterBuild: (log: PkgLog) => { + // Callback function after the build is completed. You can perform some actions after the build. + }; +}); +``` + +## Plugin Example + +- [@nocobase/plugin-sample-custom-build](#) diff --git a/docs/fr-FR/development/others/deps.md b/docs/fr-FR/development/others/deps.md new file mode 100644 index 000000000..0ee526c2f --- /dev/null +++ b/docs/fr-FR/development/others/deps.md @@ -0,0 +1,94 @@ +# Dependencies + +The plugin's dependencies are categorized into local dependencies and global dependencies. Global dependencies are provided by `@nocobase/server` and `@nocobase/client`, and they are not included in the plugin's final bundle. However, local dependencies will be bundled with the plugin. + +Since the local dependencies will be bundled (including npm packages required by the server, which will also be included in `dist/node_modules`), when developing a plugin, all dependencies should be added to `devDependencies`. + + +When installing the following dependencies for the plugin, ensure that their **versions** are consistent with those of `@nocobase/server` and `@nocobase/client`. + + +## Global Dependencies + +```js +// nocobase +'@nocobase/acl', + '@nocobase/actions', + '@nocobase/auth', + '@nocobase/cache', + '@nocobase/client', + '@nocobase/database', + '@nocobase/evaluators', + '@nocobase/logger', + '@nocobase/resourcer', + '@nocobase/sdk', + '@nocobase/server', + '@nocobase/test', + '@nocobase/utils', + // @nocobase/auth + 'jsonwebtoken', + // @nocobase/cache + 'cache-manager', + 'cache-manager-fs-hash', + // @nocobase/database + 'sequelize', + 'umzug', + 'async-mutex', + // @nocobase/evaluators + '@formulajs/formulajs', + 'mathjs', + // @nocobase/logger + 'winston', + 'winston-daily-rotate-file', + // koa + 'koa', + '@koa/cors', + '@koa/router', + 'multer', + '@koa/multer', + 'koa-bodyparser', + 'koa-static', + 'koa-send', + // react + 'react', + 'react-dom', + 'react/jsx-runtime', + // react-router + 'react-router', + 'react-router-dom', + // antd + 'antd', + 'antd-style', + '@ant-design/icons', + '@ant-design/cssinjs', + // i18next + 'i18next', + 'react-i18next', + // dnd-kit + '@dnd-kit/accessibility', + '@dnd-kit/core', + '@dnd-kit/modifiers', + '@dnd-kit/sortable', + '@dnd-kit/utilities', + // formily + '@formily/antd-v5', + '@formily/core', + '@formily/react', + '@formily/json-schema', + '@formily/path', + '@formily/validator', + '@formily/shared', + '@formily/reactive', + '@formily/reactive-react', + // utils + 'dayjs', + 'mysql2', + 'pg', + 'pg-hstore', + 'sqlite3', + 'supertest', + 'axios', + '@emotion/css', + 'ahooks', + 'lodash'; +``` diff --git a/docs/fr-FR/development/others/languages.md b/docs/fr-FR/development/others/languages.md new file mode 100644 index 000000000..4d104ff5e --- /dev/null +++ b/docs/fr-FR/development/others/languages.md @@ -0,0 +1,73 @@ +# Languages + +```ts +{ + 'ar-EG': { label: 'العربية' }, + 'az-AZ': { label: 'Azərbaycan dili' }, + 'bg-BG': { label: 'Български' }, + 'bn-BD': { label: 'Bengali' }, + 'by-BY': { label: 'Беларускі' }, + 'ca-ES': { label: 'Сatalà/Espanya' }, + 'cs-CZ': { label: 'Česky' }, + 'da-DK': { label: 'Dansk' }, + 'de-DE': { label: 'Deutsch' }, + 'el-GR': { label: 'Ελληνικά' }, + 'en-GB': { label: 'English(GB)' }, + 'en-US': { label: 'English' }, + 'es-ES': { label: 'Español' }, + 'et-EE': { label: 'Estonian (Eesti)' }, + 'fa-IR': { label: 'فارسی' }, + 'fi-FI': { label: 'Suomi' }, + 'fr-BE': { label: 'Français(BE)' }, + 'fr-CA': { label: 'Français(CA)' }, + 'fr-FR': { label: 'Français' }, + 'ga-IE': { label: 'Gaeilge' }, + 'gl-ES': { label: 'Galego' }, + 'he-IL': { label: 'עברית' }, + 'hi-IN': { label: 'हिन्दी' }, + 'hr-HR': { label: 'Hrvatski jezik' }, + 'hu-HU': { label: 'Magyar' }, + 'hy-AM': { label: 'Հայերեն' }, + 'id-ID': { label: 'Bahasa Indonesia' }, + 'is-IS': { label: 'Íslenska' }, + 'it-IT': { label: 'Italiano' }, + 'ja-JP': { label: '日本語' }, + 'ka-GE': { label: 'ქართული' }, + 'kk-KZ': { label: 'Қазақ тілі' }, + 'km-KH': { label: 'ភាសាខ្មែរ' }, + // 'kmr-IQ': { label: 'kmr_IQ' }, + 'kn-IN': { label: 'ಕನ್ನಡ' }, + 'ko-KR': { label: '한국어' }, + 'ku-IQ': { label: 'کوردی' }, + 'lt-LT': { label: 'lietuvių' }, + 'lv-LV': { label: 'Latviešu valoda' }, + 'mk-MK': { label: 'македонски јазик' }, + 'ml-IN': { label: 'മലയാളം' }, + 'mn-MN': { label: 'Монгол хэл' }, + 'ms-MY': { label: 'بهاس ملايو' }, + 'nb-NO': { label: 'Norsk bokmål' }, + 'ne-NP': { label: 'नेपाली' }, + 'nl-BE': { label: 'Vlaams' }, + 'nl-NL': { label: 'Nederlands' }, + 'pl-PL': { label: 'Polski' }, + 'pt-BR': { label: 'Português brasileiro' }, + 'pt-PT': { label: 'Português' }, + 'ro-RO': { label: 'România' }, + 'ru-RU': { label: 'Русский' }, + 'si-LK': { label: 'සිංහල' }, + 'sk-SK': { label: 'Slovenčina' }, + 'sl-SI': { label: 'Slovenščina' }, + 'sr-RS': { label: 'српски језик' }, + 'sv-SE': { label: 'Svenska' }, + 'ta-IN': { label: 'Tamil' }, + 'th-TH': { label: 'ภาษาไทย' }, + 'tk-TK': { label: 'Turkmen' }, + 'tr-TR': { label: 'Türkçe' }, + 'uk-UA': { label: 'Українська' }, + 'ur-PK': { label: 'Oʻzbekcha' }, + 'vi-VN': { label: 'Tiếng Việt' }, + 'zh-CN': { label: '简体中文' }, + 'zh-HK': { label: '繁體中文(香港)' }, + 'zh-TW': { label: '繁體中文(台湾)' }, +} +``` diff --git a/docs/fr-FR/development/others/tech-stack.md b/docs/fr-FR/development/others/tech-stack.md new file mode 100644 index 000000000..ba28c53a0 --- /dev/null +++ b/docs/fr-FR/development/others/tech-stack.md @@ -0,0 +1,18 @@ +# 技术栈 + +| NPM 包和版本 | 作用 | +| -------------------------------------- | ------------ | +| react、react-dom(18.x) | 框架 | +| react-router(6.x) | 路由 | +| i18next(22.x)、react-i18next(11.x) | 国际化 | +| ant-design(5.x) | UI 组件库 | +| antd-style(3.x) | 动态主题 | +| axios(0.26.x)、useRequest(3.x) | API 请求 | +| Formily(2.x) | UI Schema | +| dayjs(1.11.x) | 日期格式化 | +| dnd-kit(5.x) | 拖拽 | +| umi(4.x) | 应用开发框架 | +| dumi(2.x) | 文档工具 | +| vite(4.x)、tsup(7.x) | 构建工具 | +| vitest(0.34.x) | 单测工具 | +| playwright(1.x) | E2E 测试工具 | diff --git a/docs/fr-FR/development/others/testing.md b/docs/fr-FR/development/others/testing.md new file mode 100644 index 000000000..01249d0bd --- /dev/null +++ b/docs/fr-FR/development/others/testing.md @@ -0,0 +1,163 @@ +# 单元测试 + +## 介绍 + +NocoBase 的测试基于 [Jest](https://jestjs.io/) 测试框架。同时,为了方便的编写测试,我们提供了两个工具类,在测试环境模拟正常的数据库和应用的服务端。 + +### MockDatabase + +模拟数据库类继承自 [`Database`](/api/database) 类,大部分内容没有区别,主要在构造函数默认内置了随机表前缀,在每个测试用例初始化数据库时相关数据表都通过前缀名称与其他用例进行隔离,在运行测试用例时互不影响。 + +```ts +import { MockDatabase } from '@nocobase/test'; + +describe('my suite', () => { + let db; + + beforeEach(async () => { + db = new MockDatabase(); + + db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], + }); + + await db.sync(); + }); + + test('my case', async () => { + const postRepository = db.getRepository('posts'); + const p1 = await postRepository.create({ + values: { + title: 'hello', + }, + }); + + expect(p1.get('title')).toEqual('hello'); + }); +}); +``` + +### MockServer + +模拟服务器也继承自 [Application](/api/server/application) 类,除了内置的数据库实例是通过模拟数据库类生成的以外,还提供了比较方便的生成基于 [superagent](https://www.npmjs.com/package/superagent) 请求代理功能,针对从发送请求到获取响应的写法也集成了 `.resource('posts').create()`,比较简化。 + +```ts +import { mockServer } from '@nocobase/test'; + +describe('my suite', () => { + let app; + let agent; + let db; + + beforeEach(async () => { + app = mockServer(); + agent = app.agent(); + + db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], + }); + + await db.sync(); + await app.load(); + }); + + test('my case', async () => { + const { body } = await agent.resource('posts').create({ + values: { + title: 'hello', + }, + }); + + expect(body.data.title).toEqual('hello'); + }); +}); +``` + +## 示例 + +我们以之前在 [资源与操作](development/guide/resources-actions) 章节的功能为例,来写一个插件的测试: + +```ts +import { mockServer } from '@nocobase/test'; +import Plugin from '../../src/server'; + +describe('shop actions', () => { + let app; + let agent; + let db; + + beforeEach(async () => { + app = mockServer(); + app.plugin(Plugin); + agent = app.agent(); + db = app.db; + + await app.load(); + await db.sync(); + }); + + afterEach(async () => { + await app.destroy(); + }); + + test('product order case', async () => { + const { body: product } = await agent.resource('products').create({ + values: { + title: 'iPhone 14 Pro', + price: 7999, + enabled: true, + inventory: 1, + }, + }); + expect(product.data.price).toEqual(7999); + + const { body: order } = await agent.resource('orders').create({ + values: { + productId: product.data.id, + }, + }); + expect(order.data.totalPrice).toEqual(7999); + expect(order.data.status).toEqual(0); + + const { body: deliveredOrder } = await agent.resource('orders').deliver({ + filterByTk: order.data.id, + values: { + provider: 'SF', + trackingNumber: '123456789', + }, + }); + expect(deliveredOrder.data.status).toBe(2); + expect(deliveredOrder.data.delivery.trackingNumber).toBe('123456789'); + }); +}); +``` + +编写完成后,在命令行中允许测试命令: + +```bash +yarn test packages/samples/shop-actions +``` + +该测试将验证: + +1. 商品可以创建成功; +2. 订单可以创建成功; +3. 订单可以发货成功; + +当然这只是个最基本的例子,从业务上来说并不完善,但作为示例已经可以说明整个测试的流程。 + +## 小结 + +本章涉及的示例代码整合在对应的包 [packages/samples/shop-actions](https://github.com/nocobase/nocobase/tree/main/packages/samples/shop-actions) 中,可以直接在本地运行,查看效果。 diff --git a/docs/fr-FR/development/plugin-ds.md b/docs/fr-FR/development/plugin-ds.md new file mode 100644 index 000000000..a91e82fc7 --- /dev/null +++ b/docs/fr-FR/development/plugin-ds.md @@ -0,0 +1,45 @@ +# 插件目录结构 + +可以通过 `yarn pm create my-plugin` 快速创建一个空插件,目录结构如下: + +```bash +|- /my-plugin + |- /src + |- /client # 插件客户端代码 + |- /server # 插件服务端代码 + |- client.d.ts + |- client.js + |- package.json # 插件包信息 + |- server.d.ts + |- server.js + |- build.config.ts # 或者 `build.config.js` ,用于修改打包配置,实现自定义逻辑 +``` + +`/src/server` 的教程参考 [服务端](./server) 章节,`/src/client` 的教程参考 [客户端](./client) 章节。 + +如果你想要自定义打包配置,可以在根目录下创建 `config.js` 文件,内容如下: + +```js +import { defineConfig } from '@nocobase/build'; + +export default defineConfig({ + modifyViteConfig: (config) => { + // vite 是用来打包 `src/client` 端代码的 + + // 修改 Vite 配置,具体可参考:https://vitejs.dev/guide/ + return config + }, + modifyTsupConfig: (config) => { + // tsup 是用来打包 `src/server` 端代码的 + + // 修改 tsup 配置,具体可参考:https://tsup.egoist.dev/#using-custom-configuration + return config + }, + beforeBuild: (log) => { + // 构建开始前的回调函数,可以在构建开始前做一些操作 + }, + afterBuild: (log: PkgLog) => { + // 构建完成后的回调函数,可以在构建完成后做一些操作 + }; +}); +``` diff --git a/docs/fr-FR/development/plugin.md b/docs/fr-FR/development/plugin.md new file mode 100644 index 000000000..d0c5b68bd --- /dev/null +++ b/docs/fr-FR/development/plugin.md @@ -0,0 +1,106 @@ +### Plugin Organization Methods + +NocoBase offers three distinct methods for organizing plugins, ensuring that all plugin packages are ultimately consolidated within the `node_modules` directory at the project's root: + +![20240428091419](https://static-docs.nocobase.com/20240428091419.png) + +#### storages/plugins + +This directory is reserved for storing pre-compiled plugins that require no additional dependencies. These plugins are designed for immediate use—simply plug and play. Plugins added via the interface are placed in this directory, and you can also add plugins using the `pm add` command. + +```bash +tar -xvzf /downloads/plugin-data-source-external-mysql-0.21.0-alpha.10.tgz -C /my-nocobase-app/storage/plugins/@nocobase/plugin-data-source-external-mysql --strip-components=1 +``` + +The directory structure is organized as follows: + +```bash +|- /storage/ + |- /plugins/ + |- /@nocobase/ + |- /plugin-data-source-external-mysql/ +``` + +#### packages/plugins + +For plugins that are still in development, maintenance is handled through Yarn workspaces. Running `yarn install` will ensure that all dependencies for these plugins are downloaded. The source code is accessible, but these plugins require compilation before they can be deployed in a production environment. The structure of these plugin packages mirrors that of npm packages, as illustrated below: + +```bash +|- /packages/ + |- /plugins/ + |- /@nocobase/ + |- /plugin-hello1/ + |- /plugin-hello2/ + |- /my-nocobase-plugin-hello1/ + |- /my-nocobase-plugin-hello2/ +``` + +#### package.json + dependencies + +An example of this method is the NocoBase preset plugin, which lists its plugins under the `dependencies` section in `package.json`. When you run `yarn install`, all specified plugins are automatically downloaded and ready for use. + +```js +{ + "name": "@nocobase/preset-nocobase", + "version": "0.21.0-alpha.15", + "license": "AGPL-3.0", + "main": "./lib/server/index.js", + "dependencies": { + "@nocobase/plugin-acl": "0.21.0-alpha.15", + "@nocobase/plugin-action-bulk-edit": "0.21.0-alpha.15", + "@nocobase/plugin-action-bulk-update": "0.21.0-alpha.15", + "@nocobase/plugin-action-duplicate": "0.21.0-alpha.15", + "@nocobase/plugin-action-print": "0.21.0-alpha.15", + "@nocobase/plugin-api-doc": "0.21.0-alpha.15", + "@nocobase/plugin-api-keys": "0.21.0-alpha.15", + "@nocobase/plugin-audit-logs": "0.21.0-alpha.15", + "@nocobase/plugin-auth": "0.21.0-alpha.15", + "@nocobase/plugin-backup-restore": "0.21.0-alpha.15", + "@nocobase/plugin-calendar": "0.21.0-alpha.15", + "@nocobase/plugin-cas": "0.21.0-alpha.15", + "@nocobase/plugin-charts": "0.21.0-alpha.15", + "@nocobase/plugin-china-region": "0.21.0-alpha.15", + "@nocobase/plugin-client": "0.21.0-alpha.15", + "@nocobase/plugin-collection-manager": "0.21.0-alpha.15", + "@nocobase/plugin-custom-request": "0.21.0-alpha.15", + "@nocobase/plugin-data-source-manager": "0.21.0-alpha.15", + "@nocobase/plugin-data-visualization": "0.21.0-alpha.15", + "@nocobase/plugin-error-handler": "0.21.0-alpha.15", + "@nocobase/plugin-export": "0.21.0-alpha.15", + "@nocobase/plugin-file-manager": "0.21.0-alpha.15", + "@nocobase/plugin-formula-field": "0.21.0-alpha.15", + "@nocobase/plugin-gantt": "0.21.0-alpha.15", + "@nocobase/plugin-graph-collection-manager": "0.21.0-alpha.15", + "@nocobase/plugin-iframe-block": "0.21.0-alpha.15", + "@nocobase/plugin-import": "0.21.0-alpha.15", + "@nocobase/plugin-kanban": "0.21.0-alpha.15", + "@nocobase/plugin-localization-management": "0.21.0-alpha.15", + "@nocobase/plugin-logger": "0.21.0-alpha.15", + "@nocobase/plugin-map": "0.21.0-alpha.15", + "@nocobase/plugin-mobile-client": "0.21.0-alpha.15", + "@nocobase/plugin-mock-collections": "0.21.0-alpha.15", + "@nocobase/plugin-multi-app-manager": "0.21.0-alpha.15", + "@nocobase/plugin-multi-app-share-collection": "0.21.0-alpha.15", + "@nocobase/plugin-oidc": "0.21.0-alpha.15", + "@nocobase/plugin-saml": "0.21.0-alpha.15", + "@nocobase/plugin-sequence-field": "0.21.0-alpha.15", + "@nocobase/plugin-sms-auth": "0.21.0-alpha.15", + "@nocobase/plugin-snapshot-field": "0.21.0-alpha.15", + "@nocobase/plugin-system-settings": "0.21.0-alpha.15", + "@nocobase/plugin-theme-editor": "0.21.0-alpha.15", + "@nocobase/plugin-ui-schema-storage": "0.21.0-alpha.15", + "@nocobase/plugin-users": "0.21.0-alpha.15", + "@nocobase/plugin-verification": "0.21.0-alpha.15", + "@nocobase/plugin-workflow": "0.21.0-alpha.15", + "@nocobase/plugin-workflow-action-trigger": "0.21.0-alpha.15", + "@nocobase/plugin-workflow-aggregate": "0.21.0-alpha.15", + "@nocobase/plugin-workflow-delay": "0.21.0-alpha.15", + "@nocobase/plugin-workflow-dynamic-calculation": "0.21.0-alpha.15", + "@nocobase/plugin-workflow-loop": "0.21.0-alpha.15", + "@nocobase/plugin-workflow-manual": "0.21.0-alpha.15", + "@nocobase/plugin-workflow-parallel": "0.21.0-alpha.15", + "@nocobase/plugin-workflow-request": "0.21.0-alpha.15", + "@nocobase/plugin-workflow-sql": "0.21.0-alpha.15" + } +} +``` diff --git a/docs/fr-FR/development/server/collections-fields.md b/docs/fr-FR/development/server/collections-fields.md new file mode 100644 index 000000000..b52947b65 --- /dev/null +++ b/docs/fr-FR/development/server/collections-fields.md @@ -0,0 +1,320 @@ +## Collections and Fields + +## Basic Concepts + +Data modeling is the lowest level foundation of an application. In NocoBase applications we model data through data tables (Collection) and fields (Field), and the modeling is also mapped to database tables for persistence. + +### Collection + +Collection is a collection of all similar data, which corresponds to the concept of database tables in NocoBase. Such as orders, products, users, comments, etc. can form a collection definition. Different collections are distinguished by name and contain fields defined by `fields`, such as + +```ts +db.collection({ + name: 'posts', + fields: [ + { name: 'title', type: 'string' } + { name: 'content', type: 'text' }, + // ... + ] +}); +``` + +The collection is only in memory after the definition, you need to call the [``db.sync()`'' (/api/database#sync) method to synchronize it to the database. + +### Field + +Corresponding to the concept of database table "fields", each data table (Collection) can have a number of Fields, for example. + +```ts +db.collection({ + name: 'users', + fields: [ + { type: 'string', name: 'name' } + { type: 'integer', name: 'age' } + // Other fields + ], +}); +``` + +The field name (`name`) and field type (`type`) are required, and different fields are distinguished by the field name (`name`). All field types and their configurations are described in the [List of built-in field types](/api/database/field#List of built-in field types) section of the API reference. + +## Example + +For developers, we usually build functional collections that are different from normal collections and solidify these collections as part of the plugin and combine them with other data processing processes to form a complete functionality. + +Let's take a simple online store plugin as an example to show how to model and manage the collections of the plugin. Assuming you have already learned about [Develop your first plugin](/development/your-first-plugin), we continue to build on the previous plugin code, except that the name of the plugin is changed from `hello` to `shop-modeling`. + +### Define and create collections in the plugin + +For a store, you first need to create a collection of products, named `products`. Instead of calling [`db.collection()`](/api/database#collection) directly, in the plugin we will use a more convenient method to import multiple files of defined data tables at once. So let's start by creating a file for the product collection definition named `collections/products.ts` and fill it with the following content. + +```ts +export default { + name: 'products', + fields: [ + { + type: 'string', + name: 'title', + }, + { + type: 'integer', + name: 'price', + }, + { + type: 'boolean', + name: 'enabled', + }, + { + type: 'integer', + name: 'inventory', + }, + ], +}; +``` + +As you can see, the collections structure definition can be used directly in standard JSON format, where `name` and `fields` are required representing the collection's name and the field definitions in the collection. Field definitions similar to Sequelize create system fields such as primary key (`id`), data creation time (`createdAt`) and data update time (`updatedAt`) by default, which can be overridden by a configuration with the same name if there is a special need. + +The data table defined in this file we can introduce and complete the definition in the `load()` cycle of the main plugin class using `db.import()`. This is shown below. + +```ts +import path from 'path'; +import { Plugin } from '@nocobase/server'; + +export default class ShopPlugin extends Plugin { + async load() { + await this.db.import({ + directory: path.resolve(__dirname, 'collections'), + }); + + this.app.acl.allow('products', '*'); + this.app.acl.allow('categories', '*'); + this.app.acl.allow('orders', '*'); + } +} +``` + +In the meantime, for testing purposes, we will temporarily allow all access permissions for the data in these collections, and later we will detail how to manage data permissions in [Permissions Management](/development/guide/acl). + +This way, when the plugin is loaded by the main application, the `products` collection we defined is also loaded into the memory of the database management instance. At the same time, the NocoBase constraint-based resource mapping of the collections automatically generates the corresponding CRUD HTTP API after the application's service is started. + +When the following URLs are requested from the client, the corresponding responses are obtained. + +- `GET /api/products:list`: Get a list of all product data +- `GET /api/products:get?filterByTk=`: Get the product data for the specified ID +- `POST /api/products`: Create a new product data +- `PUT /api/products:update?filterByTk=`: Update a product data +- `DELETE /api/products:destroy?filterByTk=`: Delete a product data + +### Defining associated collections and fields + +In the above example, we only defined a product collection, but in reality a product also needs to be associated to a category, a brand, a supplier, etc. For example, we can define a `categories` collection to store the categories, and then add a `category` field to the product collection to associate it with the category collection. + +Add a new file `collections/categories.ts` and fill in the content. + +```ts +export default { + name: 'categories', + fields: [ + { + type: 'string', + name: 'title', + }, + { + type: 'hasMany', + name: 'products', + }, + ], +}; +``` + +We have defined two fields for the `categories` collection, one for the title and another one-to-many field for all the products associated under that category, which will be described later. Since we have already used the `db.import()` method in the plugin's main class to import all the data table definitions under the `collections` directory, the new `categories` collection added here will also be automatically imported into the database management instance. + +Modify the file `collections/products.ts`` to add a `category`field to the`fields`. + +```ts +{ + name: 'products', + fields: [ + // ... + { + type: 'belongsTo', + name: 'category', + target: 'categories', + } + ] +} +``` + +As you can see, the `category` field we added to the `products` collection is a `belongsTo` type field, and its `target` property points to the `categories` collection, thus defining a many-to-one relationship between the `products` collection and the `categories` collection. Combined with the `hasMany` field defined in the `categories` collection, we can achieve a relationship where one product can be associated to multiple categories and multiple products under one category. Usually `belongsTo` and `hasMany` can appear in pairs, defined in two separate collections. + +Once the relationship between the two collections is defined, we can also request the associated data directly through the HTTP API + +- `GET /api/products:list?appends=category`: Get all products data, including the associated categories data +- `GET /api/products:get?filterByTk=&appends=category`: Get the product data for the specified ID, including the associated category data. +- `GET /api/categories//products:list`: Get all the products under the specified category +- `POST /api/categories//products`: Create a new product under the specified category + +Similar to the general ORM framework, NocoBase has four built-in relational field types, for more information you can refer to the section about API field types. + +- [`belongsTo` type](/api/database/field#belongsto) +- [`belongsToMany` type](/api/database/field#belongstomany) +- [`hasMany` type](/api/database/field#hasmany) +- [`hasOne` type](/api/database/field#hasone) + +### Extend an existing collection + +In the above example, we already have a product collection and a category collection, in order to provide the sales process we also need an order collection. We can add a new `orders.ts` file to the `collections` directory and define an `orders` collection as follows + +```ts +export default { + name: 'orders', + fields: [ + { + type: 'uuid', + name: 'id', + primaryKey: true, + }, + { + type: 'belongsTo', + name: 'product', + }, + { + type: 'integer', + name: 'quantity', + }, + { + type: 'integer', + name: 'totalPrice', + }, + { + type: 'integer', + name: 'status', + }, + { + type: 'string', + name: 'address', + }, + { + type: 'belongsTo', + name: 'user', + }, + ], +}; +``` + +For the sake of simplicity, the association between the order collection and the product collection we simply define as a many-to-one relationship, while in the actual business may be used in a complex modeling approach such as many-to-many or snapshot. As you can see, an order in addition to corresponding to a commodity, we also added a relationship definition corresponding to the users, which is a collection managed by the NocoBase built-in plugins (refer to [code for users plugin](https://github.com/nocobase/nocobase/tree/main/packages/) for details plugins/users)). If we want to extend the definition of the "multiple orders owned by a user" relationship for the existing users collection, we can continue to add a new collection file `collections/users.ts` inside the current shop-modeling plugin, which is different from exporting the JSON collection directly. Unlike the direct export of a JSON, the `@nocobase/database` package's `extend()` method is used here to extend the definition of an existing collection: ``ts + +```ts +import { extend } from '@nocobase/database'; + +export extend({ + name: 'users', + fields: [ + { + type: 'hasMany', + name: 'orders' + } + ] +}); +``` + +This way, the existing users table also has an `orders` associated field, and we can retrieve all the order data for a given user via `GET /api/users//orders:list`. + +This method is very useful when extending collections already defined by other plugins, so that other existing plugins do not depend on the new plugin in reverse, but only form one-way dependencies, facilitating a certain degree of decoupling at the extension level. + +### Extend field types + +We use `uuid` type for `id` field when we define order table, which is a built-in field type. Sometimes we may feel that UUID looks too long and waste space, and the query performance is not good, we want to use a more suitable field type, such as a complex numbering logic with date information, or Snowflake algorithm, we need to extend a custom field type. + +Suppose we need to apply the Snowflake ID generation algorithm directly to extend a `snowflake` field type, we can create a `fields/snowflake.ts` file. + +```ts +// Import the algorithm toolkit +import { Snowflake } from 'nodejs-snowflake'; +// Import field type base class +import { DataTypes, Field, BaseColumnFieldOptions } from '@nocobase/database'; + +export interface SnowflakeFieldOptions extends BaseColumnFieldOptions { + type: 'snowflake'; + epoch: number; + instanceId: number; +} + +export class SnowflakeField extends Field { + get dataType() { + return DataTypes.BIGINT; + } + + constructor(options: SnowflakeFieldOptions, context) { + super(options, context); + + const { + epoch: custom_epoch, + instanceId: instance_id = process.env.INSTANCE_ID + ? Number.parseInt(process.env.INSTANCE_ID) + : 0, + } = options; + this.generator = new Snowflake({ custom_epoch, instance_id }); + } + + setValue = (instance) => { + const { name } = this.options; + instance.set(name, this.generator.getUniqueID()); + }; + + bind() { + super.bind(); + this.on('beforeCreate', this.setValue); + } + + unbind() { + super.unbind(); + this.off('beforeCreate', this.setValue); + } +} + +export default SnowflakeField; +``` + +Afterwards, register the new field type into the collection in the main plugin file. + +```ts +import SnowflakeField from '. /fields/snowflake'; + +export default class ShopPlugin extends Plugin { + initialize() { + // ... + this.db.registerFieldTypes({ + snowflake: SnowflakeField, + }); + // ... + } +} +``` + +This allows us to use the `snowflake` field type in the order table: + +```ts +export default { + name: 'orders', + fields: [ + { + type: 'snowflake' + name: 'id', + primaryKey: true + }, + // ... . other fields + ] +} +``` + +## Summary + +With the above example, we basically understand how to model data in a plugin, including. + +- Defining collections and common fields +- Defining association collections and fields relationships +- Extending fields of an existing collections +- Extending new field types + +We have put the code covered in this chapter into a complete sample package [packages/samples/shop-modeling](https://github.com/nocobase/nocobase/tree/main/packages/samples/shop-modeling), which can be run directly locally to see the results. diff --git a/docs/fr-FR/development/server/collections/association-fields.md b/docs/fr-FR/development/server/collections/association-fields.md new file mode 100755 index 000000000..c6a873e07 --- /dev/null +++ b/docs/fr-FR/development/server/collections/association-fields.md @@ -0,0 +1,153 @@ +# Association Fields + +In a relational database, the standard way to build a table relationship is to add a foreign key field followed by a foreign key constraint. For example, Knex builds a table with the following example. + +```ts +knex.schema.table('posts', function (table) { + table.integer('userId').unsigned(); + table.foreign('userId').references('users.id'); +}); +``` + +This procedure creates a userId field in the posts table and sets the foreign key constraint posts.userId to refer to users.id. In NocoBase's Collection, such a relational constraint is created by configuring the relational field, e.g. + +```ts +{ + name: 'posts', + fields: [ + { + type: 'belongsTo', + name: 'user', + target: 'users', + foreignKey: 'userId', + }, + ], +} +``` + +## Relationship parameters + +### BelongsTo + +```ts +interface BelongsTo { + type: 'belongsTo'; + name: string; + // defaults to name's plural + target?: string; + // The default value is the primary key of the target model, usually 'id' + targetKey?: any; + // defaults to target + 'Id' + foreignKey?: any; +} + +// The authors table's primary key id is concatenated with the books table's foreign key authorId +{ + name: 'books', + fields: [ + { + type: 'belongsTo', + name: 'author', + target: 'authors', + targetKey: 'id', // authors table's primary key + foreignKey: 'authorId', // foreign key in books table + } + ], +} +``` + +### HasOne + +```ts +interface HasOne { + type: 'hasOne'; + name: string; + // defaults to name's plural + target?: string; + // The default value is the primary key of the source model, usually 'id' + sourceKey?: string; + // default value is the singular form of source collection name + 'Id' + foreignKey?: string; +foreignKey?} + +// The users table's primary key id is concatenated with the profiles' foreign key userId +{ + name: 'users', + fields: [ + { + type: 'hasOne', + name: 'profile', + target: 'profiles', + sourceKey: 'id', // users table's primary key + foreignKey: 'userId', // foreign key in profiles table + } + ], +} +``` + +### HasMany + +```ts +interface HasMany { + type: 'hasMany'; + name: string; + // defaults to name + target?: string; + // The default value is the primary key of the source model, usually 'id' + sourceKey?: string; + // the default value is the singular form of the source collection name + 'Id' + foreignKey?: string; +} + +// The posts table's primary key id is concatenated with the comments table's postId +{ + name: 'posts', + fields: [ + { + type: 'hasMany', + name: 'comments', + target: 'comments', + sourceKey: 'id', // posts table's primary key + foreignKey: 'postId', // foreign key in the comments table + } + ], +} +``` + +### BelongsToMany + +```ts +interface BelongsToMany { + type: 'belongsToMany'; + name: string; + // default value is name + target?: string; + // defaults to the source collection name and target in the natural order of the first letter of the string + through?: string; + // defaults to the singular form of source collection name + 'Id' + foreignKey?: string; + // The default value is the primary key of the source model, usually id + sourceKey?: string; + // the default value is the singular form of target + 'Id' + otherKey?: string; + // the default value is the primary key of the target model, usually id + targetKey?: string; +} + +// tags table's primary key, posts table's primary key and posts_tags two foreign keys are linked +{ + name: 'posts', + fields: [ + { + type: 'believesToMany', + name: 'tags', + target: 'tags', + through: 'posts_tags', // intermediate table + foreignKey: 'tagId', // foreign key 1, in posts_tags table + otherKey: 'postId', // foreignKey2, in posts_tags table + targetKey: 'id', // tags table's primary key + sourceKey: 'id', // posts table's primary key + } + ], +} +``` diff --git a/docs/fr-FR/development/server/collections/cm.svg b/docs/fr-FR/development/server/collections/cm.svg new file mode 100755 index 000000000..9be5cbf5f --- /dev/null +++ b/docs/fr-FR/development/server/collections/cm.svg @@ -0,0 +1 @@ +
    Collection Manager Plugin

    Provide rest api to manage collections
    REST API
    Plugin A
    db.collection()
    Collections
    UI: Collections & Fields
    UI: Graphical interface
    Plugin B
    db.collection()
    Third party
    \ No newline at end of file diff --git a/docs/fr-FR/development/server/collections/collection-field.svg b/docs/fr-FR/development/server/collections/collection-field.svg new file mode 100755 index 000000000..77c6d5f6f --- /dev/null +++ b/docs/fr-FR/development/server/collections/collection-field.svg @@ -0,0 +1 @@ +
    Field Type
    Field Component
    Field Interface
    Collection Field
    \ No newline at end of file diff --git a/docs/fr-FR/development/server/collections/collection-template.md b/docs/fr-FR/development/server/collections/collection-template.md new file mode 100755 index 000000000..6e2769977 --- /dev/null +++ b/docs/fr-FR/development/server/collections/collection-template.md @@ -0,0 +1,78 @@ +# Collection templates + + +📢 Collection templates are scheduled to be available in Q4 2022. + + +In real business scenarios, different collections may have their own initialization rules and business logic, and NocoBase addresses such issues by providing collection templates. + +## General collections + +```ts +db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], +}); +``` + +## Tree structure collections + +```ts +db.collection({ + name: 'categories', + tree: 'adjacency-list', + fields: [ + { + type: 'string', + name: 'name', + }, + { + type: 'string', + name: 'description', + }, + { + type: 'belongsTo', + name: 'parent', + target: 'categories', + foreignKey: 'parentId', + }, + { + type: 'hasMany', + name: 'children', + target: 'categories', + foreignKey: 'parentId', + }, + ], +}); +``` + +## Parent-child inheritance collections + +```ts +db.collection({ + name: 'a', + fields: [], +}); + +db.collection({ + name: 'b', + inherits: 'a', + fields: [], +}); +``` + +## More templates + +As in the case of calendar collections, each initialized collection needs to be initialized with special cron and exclude fields, and the definition of such fields is done by the template + +```ts +db.collection({ + name: 'events', + template: 'calendar', +}); +``` diff --git a/docs/fr-FR/development/server/collections/configure.md b/docs/fr-FR/development/server/collections/configure.md new file mode 100755 index 000000000..35cbc8092 --- /dev/null +++ b/docs/fr-FR/development/server/collections/configure.md @@ -0,0 +1,74 @@ +# How to configure collections? + +NocoBase has three ways to configure collections. + + + +## Configuring collections through the interface + +Business data is generally recommended to be configured using the interface, and the NocoBase platform provides two interfaces to configure collections. + +### Regular table interface + + + +### Graphical configuration interface + + + +## Defined in the plugin code + +In the plugin, custom collection must be placed in the `src/server/collections/*.ts` directory of the plugin, with the following content: + +```ts +import { defineCollection } from '@nocobase/database'; + +export default defineCollection({ + name: 'examples', +}); +``` + +Extend the options of an existing collection using `extendCollection()`. + +```ts +import { extendCollection } from '@nocobase/database'; + +export default extendCollection({ + name: 'examples', +}); +``` + +Related API Reference + +- [defineCollection()](/api/database#definecollection) +- [extendCollection()](/api/database#extendcollection) + +The collection configured in the plugin is automatically synchronized with the database when the plugin is activated, giving birth to the corresponding data tables and fields. + +:::info{title="INFO"} +The collection configured in the plugin is automatically synchronized with the database when the plugin is activated, generating the corresponding data tables and fields. If the plugin is already active, you need to handle the synchronization of the data tables with the upgrade command `yarn nocobase upgrade`. +::: + +## Managing data tables via REST API + +Third parties can also manage data tables via the HTTP interface (permissions required) + +### Collections + +```bash +GET /api/collections +POST /api/collections +GET /api/collections/ +PUT /api/collections/ +DELETE /api/collections/ +``` + +### Collection fields + +```bash +GET /api/collections//fields +POST /api/collections//fields +GET /api/collections//fields/ +PUT /api/collections//fields/ +DELETE /api/collections//fields/ +``` diff --git a/docs/fr-FR/development/server/collections/field-extension.md b/docs/fr-FR/development/server/collections/field-extension.md new file mode 100755 index 000000000..490da21c0 --- /dev/null +++ b/docs/fr-FR/development/server/collections/field-extension.md @@ -0,0 +1,39 @@ +# How to extend fields + +The composition of a Collection Field in NocoBase consists of + + + +## Extend Field Type + +For example, to extend the password type field ``type: 'password'` + +```ts +export class MyPlugin extends Plugin { + beforeLoad() { + this.db.registerFieldTypes({ + password: PasswordField, + }); + } +} + +export class PasswordField extends Field { + get dataType() { + return DataTypes.STRING; + } +} +``` + +- [More implementations of the built-in field types can be found here](https://github.com/nocobase/nocobase/tree/main/packages/core/database/src/fields) +- Also see the full samples plugin [packages/samples/shop-modeling](https://github.com/nocobase/nocobase/tree/main/packages/samples/shop-modeling) + +## Extend Field Component + +Related extension documentation can be found at + +- [Extending Schema Components](/development/client/ui-schema-designer/extending-schema-components) +- [Schema component library](/development/client/ui-schema-designer/component-library) + +## Extend Field Interface + +- [Built-in field interfaces view here](https://github.com/nocobase/nocobase/tree/main/packages/core/client/src/collection-manager/interfaces) diff --git a/docs/fr-FR/development/server/collections/graph.jpg b/docs/fr-FR/development/server/collections/graph.jpg new file mode 100755 index 000000000..16c2f95d1 Binary files /dev/null and b/docs/fr-FR/development/server/collections/graph.jpg differ diff --git a/docs/fr-FR/development/server/collections/index.md b/docs/fr-FR/development/server/collections/index.md new file mode 100755 index 000000000..27e7d7dd9 --- /dev/null +++ b/docs/fr-FR/development/server/collections/index.md @@ -0,0 +1,194 @@ +# Core concepts + +## Collection + +Collection is a collection of all kinds of data, such as orders, products, users, comments, etc. Different collections are distinguished by name, e.g. + +```ts +// Orders +{ + name: 'orders', +} +// Products +{ + name: 'products', +} +// Users +{ + name: 'users', +} +// Comments +{ + name: 'comments', +} +``` + +## Collection Field + +Each Collection has a number of Fields. + +```ts +// Collection configuration +{ + name: 'users', + fields: [ + { type: 'string', name: 'name' }, + { type: 'integer', name: 'age' }, + // Other fields + ], +} +// sample data +[ + { + name: 'Jason', + age: 20, + }, + { { + name: 'Li Si', + age: 18, + } +]; +``` + +The composition of a Collection Field in NocoBase consists of + + + +### Field Type + +Different fields are distinguished by name, and type indicates the data type of the field, which is divided into Attribute Type and Association Type, e.g. + +**Attribute - Attribute Type** + +- string +- text +- date +- boolean +- time +- float +- json +- location +- password +- virtual +- ... + +**Relationship - Association Type** + +- hasOne +- hasMany +- belongsTo +- belongsToMany +- ... + +### Field Component + +The field has a data type, the IO of the field value is fine, but it is not enough, if you need to display the field on the interface, you need another dimension of configuration -- `uiSchema`, e.g. + +```tsx | pure +// Email field, displayed with Input component, using email validation rules +{ + type: 'string', + name: 'email', + uiSchema: { + 'x-component': 'Input', + 'x-component-props': { size: 'large' }, + 'x-validator': 'email', + 'x-pattern': 'editable', // editable state, and readonly state, read-pretty state + }, +} + +// Example data +{ + email: 'admin@nocobase.com', +} + +// Component example + +``` + +The uiSchema is used to configure the components of the field to be displayed on the interface, each field component will correspond to a value and includes several maintained configurations: + +- The component of the field +- The parameters of the component +- The field's validation rules +- The mode of the field (editable, readonly, read-pretty) +- The default value of the field +- Other + +[see the UI Schema chapter for more information](/development/client/ui-schema-designer/what-is-ui-schema). + +The built-in field components of NocoBase are + +- Input +- InputNumber +- Select +- Radio +- Checkbox +- ... + +### Field Interface + +With Field Type and Field Component you can freely combine several fields, we call this combined template Field Interface, e.g. + +```ts +// email field, string + input, email validation rules +{ + type: 'string', + name: 'email', + uiSchema: { + 'x-component': 'Input', + 'x-component-props': {}, + 'x-validator': 'email', + }, +} + +// phone field, string + input, phone validation rules +{ + type: 'string', + name: 'phone', + uiSchema: { + 'x-component': 'Input', + 'x-component-props': {}, + 'x-validator': 'phone', + }, +} +``` + +The above email and phone require a full uiSchema to be configured each time which is very tedious. To simplify the configuration, another concept Field interface is introduced, which can template some parameters, e.g. + +```ts +// Template for the email field +interface email { + type: 'string'; + uiSchema: { + 'x-component': 'Input', + 'x-component-props': {}, + 'x-validator': 'email', + }; +} + +// Template for the phone field +interface phone { + type: 'string'; + uiSchema: { + 'x-component': 'Input', + 'x-component-props': {}, + 'x-validator': 'phone', + }; +} + +// Simplified field configuration +// email +{ + interface: 'email', + name: 'email', +} + +// phone +{ + interface: 'phone', + name: 'phone', +} +``` + +[More Field Interface here](https://github.com/nocobase/nocobase/tree/main/packages/core/client/src/collection-manager/interfaces) diff --git a/docs/fr-FR/development/server/collections/options.md b/docs/fr-FR/development/server/collections/options.md new file mode 100755 index 000000000..9b5974452 --- /dev/null +++ b/docs/fr-FR/development/server/collections/options.md @@ -0,0 +1,144 @@ +# Collection protocol + +Collection is the backbone of NocoBase, a protocol for describing data structures (collections and fields), very close to the concept of a relational database, but not limited to relational databases, but can also be a data source for NoSQL databases, HTTP APIs, etc. + + + +At this stage, the Collection protocol is based on the relational database interface (db.collections), and data sources such as NoSQL databases and HTTP APIs will be implemented gradually in the future. + +Collection protocol mainly includes two parts: CollectionOptions and FieldOptions. Because Field is extensible, the parameters of FieldOptions are very flexible. + +## CollectionOptions + +```ts +interface CollectionOptions { + name: string; + title?: string; + // Tree structure table, TreeRepository + tree?: + | 'adjacency-list' + | 'closure-table' + | 'materialized-path' + | 'nested-set'; + // parent-child inheritance + inherits?: string | string[]; + fields?: FieldOptions[]; + timestamps?: boolean; + paranoid?: boolean; + sortable?: CollectionSortable; + model?: string; + repository?: string; + [key: string]: any; +} + +type CollectionSortable = + | string + | boolean + | { name?: string; scopeKey?: string }; +``` + +## FieldOptions + +Generic field parameters + +```ts +interface FieldOptions { + name: string; + type: string; + hidden?: boolean; + index?: boolean; + interface?: string; + uiSchema?: ISchema; +``` + +[Introduction to UI Schema here](/development/client/ui-schema-designer/what-is-ui-schema) + +### Field Type + +Field Type includes Attribute Type and Association Type. + +**Attribute Type** + +- 'boolean' +- 'integer' +- 'bigInt' +- 'double' +- 'real' +- 'decimal' +- 'string' +- 'text' +- 'password' +- 'date' +- 'time' +- 'array' +- 'json' +- 'jsonb' +- 'uuid' +- 'uid' +- 'formula' +- 'radio' +- 'sort' +- 'virtual' + +**Association Type** + +- 'belongsTo' +- 'hasOne' +- 'hasMany' +- 'belongsToMany' + +### Field Interface + +**Basic** + +- input +- textarea +- phone +- email +- integer +- number +- percent +- password +- icon + +**Choices** + +- checkbox +- select +- multipleSelect +- radioGroup +- checkboxGroup +- chinaRegion + +**Media** + +- attachment +- markdown +- richText + +**Date & Time** + +- datetime +- time + +**Relation** + +- linkTo - `type: 'believesToMany'` +- oho - `type: 'hasOne'` +- obo - `type: 'believesTo'` +- o2m - `type: 'hasMany'` +- m2o - `type: 'believesTo'` +- m2m - `type: 'believesToMany'` + +**Advanced** + +- formula +- sequence + +**System info** + +- id +- createdAt +- createdBy +- updatedAt +- updatedBy diff --git a/docs/fr-FR/development/server/collections/schema.svg b/docs/fr-FR/development/server/collections/schema.svg new file mode 100755 index 000000000..230a9bbca --- /dev/null +++ b/docs/fr-FR/development/server/collections/schema.svg @@ -0,0 +1 @@ +
    Collection
    Field Type
    Field Component
    UI Schema
    Field Interface
    Collection Field
    Relational Database
    PostgreSQL
    NoSQL
    API
    SQLite
    MySQL
    Others
    Resource
    Client
    \ No newline at end of file diff --git a/docs/fr-FR/development/server/collections/table.jpg b/docs/fr-FR/development/server/collections/table.jpg new file mode 100755 index 000000000..55fe4c183 Binary files /dev/null and b/docs/fr-FR/development/server/collections/table.jpg differ diff --git a/docs/fr-FR/development/server/commands.md b/docs/fr-FR/development/server/commands.md new file mode 100644 index 000000000..23c943d36 --- /dev/null +++ b/docs/fr-FR/development/server/commands.md @@ -0,0 +1,37 @@ +# Commands + +In a plugin, custom commands must be located in the `src/server/commands/*.ts` directory of the plugin. The content should look like this: + +```ts +import { Application } from '@nocobase/server'; + +export default function(app: Application) { + app + .command('echo') + .option('-v, --version') + .action(async ([options]) => { + console.log('Hello World!'); + if (options.version) { + console.log('Current version:', await app.version.get()); + } + }); +} +``` + +:::warning +Custom commands in the plugin are only effective after the plugin is installed and activated. +::: + +Special Configurations for Commands: + +- `ipc()` When the app is running, the command-line sends instructions through ipc to operate on the running app instance. Without the `ipc()` configuration, a new application instance will be created to execute the command (this will not interfere with the running app instance). +- `auth()` Performs database verification. If the database configuration is incorrect, the command will not be executed. +- `preload()` Determines whether to pre-load the application configuration, i.e., execute `app.load()`. + +These configurations can be adjusted according to the actual use of the command, as shown in the examples below: + +```ts +app.command('a').ipc().action() +app.command('a').auth().action() +app.command('a').preload().action() +``` \ No newline at end of file diff --git a/docs/fr-FR/development/server/events.md b/docs/fr-FR/development/server/events.md new file mode 100644 index 000000000..95ed0bedf --- /dev/null +++ b/docs/fr-FR/development/server/events.md @@ -0,0 +1,171 @@ +# Events + +NocoBase provides a very large number of event listeners in the lifecycle of applications, plugins, and database, and these methods will only be executed when an event is triggered. + +## How to add event listeners? + +The registration of events is usually placed in afterAdd or beforeLoad + +```ts +export class MyPlugin extends Plugin { + // After the plugin is added, afterAdd() is executed with or without activation + afterAdd() { + this.app.on(); + this.db.on(); + } + + // beforeLoad() will only be executed after the plugin is activated + beforeLoad() { + this.app.on(); + this.db.on(); + } +} +``` + +### `db.on` + +Database related events are related to Collection configuration, CRUD of Repository, including: + +- 'beforeSync' / 'afterSync' +- 'beforeValidate' / 'afterValidate' +- 'beforeCreate' / 'afterCreate' +- 'beforeUpdate' / 'afterUpdate' +- 'beforeSave' / 'afterSave' +- 'beforeDestroy' / 'afterDestroy' +- 'afterCreateWithAssociations' +- 'afterUpdateWithAssociations' +- 'afterSaveWithAssociations' +- 'beforeDefineCollection' +- 'afterDefineCollection' +- 'beforeRemoveCollection' / 'afterRemoveCollection' + +See [Database API](/api/database) for more details. + +### `app.on()` + +The app's events are related to the application's lifecycle, and the relevant events are: + +- 'beforeLoad' / 'afterLoad' +- 'beforeInstall' / 'afterInstall' +- 'beforeUpgrade' / 'afterUpgrade' +- 'beforeStart' / 'afterStart' +- 'beforeStop' / 'afterStop' +- 'beforeDestroy' / 'afterDestroy' + +Refer to [Application API](/api/server/application#Events) for more details. + +## Example + +Let's continue with a simple online store as an example, the related collections modeling can be reviewed in the [Collections and Fields](/development/) section for examples. + +### Deducting product inventory after creating an order + +Usually we have different collections for products and orders. The problem of overselling can be solved by subtracting the inventory of the item after the customer has placed the order. At this point we can define the corresponding event for the action of Creating Order and solve the inventory modification problem at this time together with: + +```ts +class ShopPlugin extends Plugin { + beforeLoad() { + this.db.on('orders.afterCreate', async (order, options) => { + const product = await order.getProduct({ + transaction: options.transaction, + }); + + await product.update( + { + inventory: product.inventory - order.quantity, + }, + { + transaction: options.transaction, + }, + ); + }); + } +} +``` + +Since the default Sequelize event carries information about the transaction, we can use transaction directly to ensure that both data actions are performed in the same transaction. + +Similarly, you can change the order status to shipped after creating the shipping record: ```ts + +```ts +class ShopPlugin extends Plugin { + load() { + this.db.on('deliveries.afterCreate', async (delivery, options) => { + const orderRepo = this.db.getRepository('orders'); + await orderRepo.update({ + filterByTk: delivery.orderId, + value: { + status: 2 + } + transaction: options.transaction + }); + }); + } +} +``` + +### Timed tasks that exist alongside the application + +Without considering complex cases such as using workflow plugins, we can also implement a simple timed task mechanism via application-level events, and it can be bound to the application's process and stop when it exits. For example, if we want to scan all orders at regular intervals and automatically sign them after the sign-off time. + +```ts +class ShopPlugin extends Plugin { + timer = null; + orderReceiveExpires = 86400 * 7; + + checkOrder = async () => { + const expiredDate = new Date(Date.now() - this.orderReceiveExpires); + const deliveryRepo = this.db.getRepository('deliveries'); + const expiredDeliveries = await deliveryRepo.find({ + fields: ['id', 'orderId'], + filter: { + status: 0, + createdAt: { + $lt: expiredDate, + }, + }, + }); + await deliveryRepo.update({ + filter: { + id: expiredDeliveries.map((item) => item.get('id')), + }, + values: { + status: 1, + }, + }); + const orderRepo = this.db.getRepository('orders'); + const [updated] = await orderRepo.update({ + filter: { + status: 2, + id: expiredDeliveries.map((item) => item.get('orderId')), + }, + values: { + status: 3, + }, + }); + + console.log('%d orders expired', updated); + }; + + load() { + this.app.on('beforeStart', () => { + // execute every minute + this.timer = setInterval(this.checkOrder, 1000 * 60); + }); + + this.app.on('beforeStop', () => { + clearInterval(this.timer); + this.timer = null; + }); + } +} +``` + +## Summary + +The above example gives us a basic understanding of what events do and the ways they can be used to extend. + +- Database related events +- Application related events + +The sample code covered in this chapter is integrated in the corresponding package [packages/samples/shop-events](https://github.com/nocobase/nocobase/tree/main/packages/samples/shop-events), which can be run directly in run locally to see the results. diff --git a/docs/fr-FR/development/server/i18n.md b/docs/fr-FR/development/server/i18n.md new file mode 100644 index 000000000..d74660a0a --- /dev/null +++ b/docs/fr-FR/development/server/i18n.md @@ -0,0 +1,115 @@ +# Internalization + +## Internationalization Files + +In a plugin, both frontend and backend multilingual files are stored in the `src/locale` folder. Click here to see [all languages](/development/others/languages) supported by NocoBase. + +```bash +|- /plugin-sample-i18n + |- /src + |- /locale # Multilingual folder + |- en_US.ts # English language file + |- zh_CN.ts # Chinese language file +``` + +Just add translation entries in the corresponding multilingual files (`/src/locale/${lang}.ts`). If it's the first time adding a multilingual file, the application needs to be restarted to take effect. You can check the `app:getLang` API to verify whether the translation entries have been added successfully. + +http://localhost:13000/api/app:getLang?locale=zh-CN + +## How to Support Internationalization + +The server has two i18n instances: app.i18n and ctx.i18n. + +### app.i18n + +app.i18n is a global i18n instance, generally used in CLI. For example, it can be combined with inquirer to implement command-line interactions. + +```ts +import { select } from '@inquirer/select'; +import { input } from '@inquirer/input'; + +export class PluginSampleI18nServer extends Plugin { + load() { + this.app.command('test-i18n').action(async () => { + const answer1 = await select({ + message: 'Select a language', + choices: [ + { + name: '中文', + value: 'zh-CN', + }, + { + name: 'English', + value: 'en-US', + }, + ], + }); + await this.app.changeLanguage(answer1); + const answer2 = await input({ + message: this.app.i18n.t('Enter your name'), + }); + console.log(this.app.i18n.t(`Your name is {{name}}`, { name: answer2 })); + }); + } +} +``` + +### ctx.i18n + +It's a cloneInstance of the global app.i18n. Each request's ctx is completely independent, responding to multilingual information according to the client's language. + +Client request parameters can be placed in the query string + +```bash +GET /?locale=en-US HTTP/1.1 +Host: localhost:13000 +``` + +Or in the request headers (recommended) + +```bash +GET / HTTP/1.1 +Host: localhost:13000 +X-Locale: en-US +``` + +Example + +```ts +export class PluginSampleI18nServer extends Plugin { + load() { + this.app.use(async (ctx, next) => { + if (ctx.path === '/api/test-i18n') { + ctx.body = `${ctx.i18n.t('Hello')} ${ctx.i18n.t('World')}`; + } + await next(); + }); + } +} +``` + +Visit http://localhost:13000/api/test-i18n?locale=zh-CN + +## API + +NocoBase's i18n is implemented based on i18next. For detailed usage instructions, refer to the [I18next API documentation](https://www.i18next.com/overview/api). Below are some important examples listed. + +### i18n.t() + +Each plugin's locale is distinguished by the namespace (ns), which is the plugin name, such as: + +```ts +t('Hello', { ns: '@nocobase/plugin-sample-i18n' }); +``` + +### i18n.changeLanguage() + +To change the current language + +```ts +await i18n.changeLanguage('en-US'); +``` + +## Complete Plugin Example + +- [@nocobase/plugin-sample-i18n](#) \ No newline at end of file diff --git a/docs/fr-FR/development/server/image-1.png b/docs/fr-FR/development/server/image-1.png new file mode 100644 index 000000000..4adc3127c Binary files /dev/null and b/docs/fr-FR/development/server/image-1.png differ diff --git a/docs/fr-FR/development/server/image-2.png b/docs/fr-FR/development/server/image-2.png new file mode 100644 index 000000000..e279fb28f Binary files /dev/null and b/docs/fr-FR/development/server/image-2.png differ diff --git a/docs/fr-FR/development/server/image.png b/docs/fr-FR/development/server/image.png new file mode 100644 index 000000000..473358cb1 Binary files /dev/null and b/docs/fr-FR/development/server/image.png differ diff --git a/docs/fr-FR/development/server/index.md b/docs/fr-FR/development/server/index.md new file mode 100644 index 000000000..c77d20c5b --- /dev/null +++ b/docs/fr-FR/development/server/index.md @@ -0,0 +1,110 @@ +# Overview + +The directory structure related to the server side of an initialized empty plugin is as follows: + +```bash +|- /plugin-sample-hello + |- /src + |- /server # Plugin server-side code + |- plugin.ts # Plugin class + |- index.ts # Server-side entry point + |- server.d.ts + |- server.js +``` + +## Plugin + +`plugin.ts` facilitates the invocation of various methods across the plugin lifecycle. + +```ts +import { InstallOptions, Plugin } from '@nocobase/server'; + +export class PluginSampleHelloServer extends Plugin { + afterAdd() { + // After the plugin is registered with pm.add. Mainly used for placing listeners for the app beforeLoad event + this.app.on('beforeLoad'); + } + beforeLoad() { + // Customize classes or methods + this.db.registerFieldTypes(); + this.db.registerModels(); + this.db.registerRepositories(); + this.db.registerOperators(); + // Event listeners + this.app.on(); + this.db.on(); + } + async load() { + // Define collection + this.db.collection(); + // Import collection configurations + this.db.import(); + this.db.addMigrations(); + + // Define resource + this.resourcer.define(); + // Register resource actions + this.resourcer.registerActions(); + + // Register middleware + this.resourcer.use(); + this.acl.use(); + this.app.use(); + + this.app.i18n; + // Custom commands + this.app.command(); + } + async install(options?: InstallOptions) { + // Installation logic + } + async afterEnable() { + // After activation + } + async afterDisable() { + // After deactivation + } + async remove() { + // Deletion logic + } +} + +export default MyPlugin; +``` + +## Plugin Lifecycle + +Plugin Lifecycle + +- After the plugin is initialized, `afterAdd` is triggered. In `afterAdd`, not all other plugins might have been instantiated. +- In `beforeLoad`, all activated plugins have been instantiated, and their instances can be retrieved via `app.pluginManager.get()`. +- In `load`, the `beforeLoad` method of all plugins has been executed. + +## Common Properties and Methods in the Plugin Class + +| API | Tutorial | +| -------------------------------- | ----------------- | +| this.name | Plugin name | +| this.enabled | Activated | +| this.installed | Installed | +| this.app | Application instance | +| this.pm | Plugin manager instance | +| this.db | Database instance | +| this.resourcer | Resource manager | +| this.acl | Access control | +| this.log | Logging | +| this.app.i18n | Internationalization | +| this.db.registerFieldTypes() | Register field types | +| this.db.registerModels() | Register Models | +| this.db.registerRepositories() | Register Repositories | +| this.db.registerOperators() | Register custom operators | +| this.app.on() | Application events | +| this.db.on() | Database events | +| this.db.collection() | Configure data tables | +| this.db.import() | Import data table configurations | +| this.db.addMigrations() | Migrations | +| this.resourcer.registerActions() | Register resource actions | +| this.resourcer.use() | Middleware | +| this.acl.use() | Middleware | +| this.app.use() | Middleware | +| this.app.command() | Command line | \ No newline at end of file diff --git a/docs/fr-FR/development/server/logger.md b/docs/fr-FR/development/server/logger.md new file mode 100644 index 000000000..056544f14 --- /dev/null +++ b/docs/fr-FR/development/server/logger.md @@ -0,0 +1,111 @@ +# Logger + +NocoBase's logging is based on Winston. By default, NocoBase divides logs into API request logs, system operation logs, and SQL execution logs, where API request logs and SQL execution logs are printed internally by the application, and plugin developers typically only need to print plugin-related system operation logs. + +This document mainly introduces how to create and print logs when developing plugins. For more information about logs, refer to: [Logger Plugin](../../handbook/logger/index.md). + +## Default Print Method + +NocoBase provides a printing method for system operation logs, which are printed according to specified fields and output to a designated file. Refer to: [Logger Plugin - System Logs](../../handbook/logger/index.md#system-logs). + +```ts +// Default print method +app.log.info("message"); + +// Use in middleware +async function (ctx, next) { + ctx.log.info("message"); +} + +// Use in a plugin +class CustomPlugin extends Plugin { + async load() { + this.log.info("message"); + } +} +``` + +All the above methods follow the usage below: + +The first parameter is the log message, the second parameter is an optional metadata object, which can be any key-value pair, where `module`, `submodule`, `method` will be extracted as separate fields, and other fields will be placed in the `meta` field. + +```ts +app.log.info('message', { + module: 'module', + submodule: 'submodule', + method: 'method', + key1: 'value1', + key2: 'value2', +}); +// => level=info timestamp=2023-12-27 10:30:23 message=message module=module submodule=submodule method=method meta={"key1": "value1", "key2": "value2"} + +app.log.debug(); +app.log.warn(); +app.log.error(); +``` + +## Output to Other Files + +If you want to use the system's default printing method but do not want to output to the default file, you can use `createSystemLogger` to create a custom system log instance. + +```ts +import { createSystemLogger } from '@nocobase/logger'; + +const logger = createSystemLogger({ + dirname: '/pathto/', + filename: 'xxx', + separateError: true, // Whether to output error-level logs separately to 'xxx_error.log' +}); +``` + +## Custom Logs + +If you do not want to use the system-provided printing method and want to use Winston's native methods, you can create logs through the following method. + +### `createLogger` + +```ts +import { createLogger } from '@nocobase/logger'; + +const logger = createLogger({ + // options +}); +``` + +`options` has been extended based on the original `winston.LoggerOptions`. + +- `transports` - You can use `'console' | 'file' | 'dailyRotateFile'` to apply preset output methods. +- `format` - You can use `'logfmt' | 'json' | 'delimiter'` to apply preset printing formats. + +### `app.createLogger` + +In scenarios with multiple applications, sometimes we hope to customize the output directory and file, which can be output to the directory under the current application name. Refer to: [Logger Plugin - Log Directory](../../handbook/logger/index.md#log-directory). + +```ts +app.createLogger({ + dirname: '', + filename: 'custom', // Output to /storage/logs/main/custom.log +}); +``` + +### `plugin.createLogger` + +The usage scenario and method are the same as `app.createLogger`. + +```ts +class CustomPlugin extends Plugin { + async load() { + const logger = this.createLogger({ + // Output to /storage/logs/main/custom-plugin/YYYY-MM-DD.log + dirname: 'custom-plugin', + filename: '%DATE%.log', + transports: ['dailyRotateFile'], + }); + } +} +``` + +## Related Documents + +- [Logger Plugin](../../handbook/logger/index.md) +- [API Reference](../../api/logger.md) diff --git a/docs/fr-FR/development/server/middleware.md b/docs/fr-FR/development/server/middleware.md new file mode 100644 index 000000000..80f156b53 --- /dev/null +++ b/docs/fr-FR/development/server/middleware.md @@ -0,0 +1,160 @@ +# Middleware + +## How to register middleware? + +The registration method for middleware is usually written in the load method + +```ts +export class MyPlugin extends Plugin { + load() { + this.app.acl.use(); + this.app.resourcer.use(); + this.app.use(); + } +} +``` + +Notes. + +1. `app.acl.use()` Add a resource-permission-level middleware to be executed before permission determination +2. `app.resourcer.use()` Adds a resource-level middleware that is executed only when a defined resource is requested +3. `app.use()` Add an application-level middleware to be executed on every request + +## Onion Circle Model + +```ts +app.use(async (ctx, next) => { + ctx.body = ctx.body || []; + ctx.body.push(1); + await next(); + ctx.body.push(2); +}); + +app.use(async (ctx, next) => { + ctx.body = ctx.body || []; + ctx.body.push(3); + await next(); + ctx.body.push(4); +}); +``` + +Visit http://localhost:13000/api/hello to see that the browser responds with the following data + +```js +{"data": [1,3,4,2]} +``` + +## Built-in middlewares and execution order + +1. `cors` +2. `bodyParser` +3. `i18n` +4. `dataWrapping` +5. `db2resource` 6. +6. `restApi` 1. + 1. `parseToken` 2. + 2. `checkRole` + 3. `acl` 1. + 1. `acl.use()` Additional middleware added + 4. `resourcer.use()` Additional middleware added + 5. `action handler` +7. `app.use()` Additional middleware added + +You can also use `before` or `after` to insert the middleware into the location of one of the preceding `tag`, e.g. + +```ts +app.use(m1, { tag: 'restApi' }); +app.resourcer.use(m2, { tag: 'parseToken' }); +app.resourcer.use(m3, { tag: 'checkRole' }); +// m4 will come before m1 +app.use(m4, { before: 'restApi' }); +// m5 will be inserted between m2 and m3 +app.resourcer.use(m5, { after: 'parseToken', before: 'checkRole' }); +``` + +If no location is specifically specified, the order of execution of the added middlewares is + +1. middlewares added by `acl.use` will be executed first +2. then the ones added by `resourcer.use`, including the middleware handler and action handler +3. and finally the ones added by `app.use` + +```ts +app.use(async (ctx, next) => { + ctx.body = ctx.body || []; + ctx.body.push(1); + await next(); + ctx.body.push(2); +}); + +app.resourcer.use(async (ctx, next) => { + ctx.body = ctx.body || []; + ctx.body.push(3); + await next(); + ctx.body.push(4); +}); + +app.acl.use(async (ctx, next) => { + ctx.body = ctx.body || []; + ctx.body.push(5); + await next(); + ctx.body.push(6); +}); + +app.resourcer.define({ + name: 'test', + actions: { + async list(ctx, next) { + ctx.body = ctx.body || []; + ctx.body.push(7); + await next(); + ctx.body.push(8); + }, + }, +}); +``` + +Visit http://localhost:13000/api/hello to see that the browser responds with the data + +```js +{"data": [1,2]} +``` + +Visiting http://localhost:13000/api/test:list to see, the browser responds with the following data + +```js +{"data": [5,3,7,1,2,8,4,6]} +``` + +### Resource undefined, middlewares added by resourcer.use() will not be executed + +```ts +app.use(async (ctx, next) => { + ctx.body = ctx.body || []; + ctx.body.push(1); + await next(); + ctx.body.push(2); +}); + +app.resourcer.use(async (ctx, next) => { + ctx.body = ctx.body || []; + ctx.body.push(3); + await next(); + ctx.body.push(4); +}); +``` + +Visit http://localhost:13000/api/hello to see that the browser responds with the following data + +```js +{"data": [1,2]} +``` + +In the above example, the hello resource is not defined and will not enter the resourcer, so the middleware in the resourcer will not be executed + +## Middleware Usage + +TODO + +## Example + +- [samples/ratelimit](https://github.com/nocobase/nocobase/blob/main/packages/samples/ratelimit/) IP rate-limiting diff --git a/docs/fr-FR/development/server/migration.md b/docs/fr-FR/development/server/migration.md new file mode 100644 index 000000000..81fbbda5d --- /dev/null +++ b/docs/fr-FR/development/server/migration.md @@ -0,0 +1,91 @@ +# Migration + +During the update and iteration process of plugins, there might be some incompatible changes. These incompatible upgrades can be handled by writing migration files, which are triggered by the `nocobase upgrade` command. The relevant process is as follows: + + + +The migrations for upgrades are divided into beforeLoad, afterSync, and afterLoad: + +- beforeLoad: Executed before the loading of each module, divided into three phases: + - Before the loading of the core module + - Before the loading of preset plugins + - Before the loading of other plugins +- afterSync: After the synchronization of table configurations with the database, divided into three phases: + - After the synchronization of the core tables with the database + - After the synchronization of the preset plugins' tables with the database + - After the synchronization of other plugins' tables with the database +- afterLoad: Executed after all applications have been loaded + +## Creating migration files + +Create migration files through the create-migration command + +```bash +yarn nocobase create-migration -h + +Usage: nocobase create-migration [options] + +Options: + --pkg package name + --on [on] Options include beforeLoad, afterSync, and afterLoad + -h, --help display help for command +``` + +Example + +```bash +$ yarn nocobase create-migration update-ui --pkg=@nocobase/plugin-client + +2024-01-07 17:33:13 [info ] add app main into supervisor +2024-01-07 17:33:13 [info ] migration file in /nocobase/packages/plugins/@nocobase/plugin-client/src/server/migrations/20240107173313-update-ui.ts +✨ Done in 5.02s. +``` + +A migration file named 20240107173313-update-ui.ts will be generated in the src/server/migrations of the plugin package @nocobase/plugin-client, with the initial content as follows: + +```ts +import { Migration } from '@nocobase/server'; + +export default class extends Migration { + on = 'afterLoad'; // 'beforeLoad' | 'afterSync' | 'afterLoad' + appVersion = '<0.19.0-alpha.3'; + + async up() { + // coding + } +} +``` + +## Triggering migration + +Triggered by the `nocobase upgrade` command + +```bash +$ yarn nocobase upgrade +``` + +## Testing migration + +```ts +import { createMockServer, MockServer } from '@nocobase/test'; + +describe('test example', () => { + let app: MockServer; + + beforeEach(async () => { + app = await createMockServer({ + plugins: ['my-plugin'], // Plugins + version: '0.18.0-alpha.5', // Version before upgrade + }); + }); + + afterEach(async () => { + await app.destroy(); + }); + + test('case1', async () => { + await app.runCommand('upgrade'); + // coding... + }); +}); +``` \ No newline at end of file diff --git a/docs/fr-FR/development/server/resources-actions-v2/configuration.md b/docs/fr-FR/development/server/resources-actions-v2/configuration.md new file mode 100644 index 000000000..2b2f0b58e --- /dev/null +++ b/docs/fr-FR/development/server/resources-actions-v2/configuration.md @@ -0,0 +1,121 @@ +# 配置资源和操作 + +最简单的 resource actions +带默认参数的 Action +使用全局 Action +Action 参数的多来源合并 +内置 Actions 的用法 + +在 NocoBase 中,resource 是为 collection 服务的,已配置的 collections(包括 associations) 会自动转为相应的 resources。 + +## 自动转换 + +```ts +export class PluginSampleToResourcesServer extends Plugin { + async load() { + this.db.collection({ + name: 'posts', + fields: [ + { + type: 'hasMany', + name: 'comments', + target: 'comments', + }, + ], + }); + this.db.collection({ + name: 'comments', + }); + } +} +``` + +以上示例的 `posts` 和 `posts.comments` 的接口如下: + +posts 资源 + +```bash +POST /api/posts:create +GET /api/posts:list +GET /api/posts:get/1 +POST /api/posts:update/1 +POST /api/posts:destroy/1 +``` + +posts.comments 资源 + +```bash +POST /api/posts/1/comments:create +GET /api/posts/1/comments:list +GET /api/posts/1/comments:get/1 +POST /api/posts/1/comments:update/1 +POST /api/posts/1/comments:destroy/1 +``` + +NocoBase 的 HTTP API 是 REST API 的超集,标准的 CRUD API 也支持 RESTful 风格。 + +## 内置的操作 + +上面 collection 转为 resource 之后,之所以可以直接进行 CRUD 操作了,是因为内置了一些常用的操作 + +内置的全局操作,可用于 collection 或 association + +- create +- get +- list +- update +- destroy +- move + +内置的关联操作,仅用于 association + +- set +- add +- remove +- toggle + +内置 Actions 的用法参考 API 文档 + +## 自定义操作 + +### 全局操作 + +```ts +export class PluginSampleResourcerServer extends Plugin { + async load() { + this.resourcer.registerActions({ + import: async (ctx, next) => {}, + export: async (ctx, next) => {}, + }); + } +} +``` + +### 某资源的操作 + +```ts +export class PluginSampleResourcerServer extends Plugin { + async load() { + this.resourcer.registerActions({ + 'posts:listPublished': async (ctx, next) => {}, + }); + } +} +``` + +## 自定义资源 + +如果有特殊需求,也可以显式的定义资源及相关操作 + +```ts +app.resourcer.define({ + name: 'posts', + actions: { + create: {}, + get: {}, + list: {}, + update: {}, + destroy: {}, + }, +}); +``` diff --git a/docs/fr-FR/development/server/resources-actions-v2/index.md b/docs/fr-FR/development/server/resources-actions-v2/index.md new file mode 100644 index 000000000..899224e4c --- /dev/null +++ b/docs/fr-FR/development/server/resources-actions-v2/index.md @@ -0,0 +1,140 @@ +# 核心概念 + +## 资源 Resource + +在 NocoBase 里,资源(resource)有两种表达方式: + +- `` +- `.` + + + +- collection 是所有抽象数据的集合 +- association 为 collection 的关联数据 + + + +示例 + +- `posts` 文章 +- `posts.user` 文章用户 +- `posts.tags` 文章标签 + +配置 + +```js +// 文章 +{ + name: 'posts', +} +// 文章用户 +{ + name: 'posts.user', +} +// 文章标签 +{ + name: 'posts.tags', +} +``` + +## 操作 Action + +以 `:` 的方式表示资源操作 + +- `:` +- `.:` + +**示例** + +- `posts:create` 创建文章 +- `posts.user:get` 查看文章用户 +- `posts.tags:add` 附加文章标签(将现有的标签与文章关联) + +配置 + +```js +// 文章资源的增删改查配置 +{ + name: 'posts', + actions: { + create: async (ctx, next) => {}, + get: async (ctx, next) => {}, + list: async (ctx, next) => {}, + update: async (ctx, next) => {}, + destroy: async (ctx, next) => {}, + }, +} + +// 文章用户 +{ + name: 'posts.tags', + actions: { + create: async (ctx, next) => {}, + get: async (ctx, next) => {}, + list: async (ctx, next) => {}, + update: async (ctx, next) => {}, + destroy: async (ctx, next) => {}, + add: async (ctx, next) => {}, + remove: async (ctx, next) => {}, + }, +} +``` + +## 如何请求资源 + +```bash + /api/: + /api/:/ + /api///: + /api///:/ +``` + +**示例** + +posts 资源 + +```bash +POST /api/posts:create +GET /api/posts:list +GET /api/posts:get/1 +POST /api/posts:update/1 +POST /api/posts:destroy/1 +``` + +posts.comments 资源 + +```bash +POST /api/posts/1/comments:create +GET /api/posts/1/comments:list +GET /api/posts/1/comments:get/1 +POST /api/posts/1/comments:update/1 +POST /api/posts/1/comments:destroy/1 +``` + +posts.tags 资源 + +```bash +POST /api/posts/1/tags:create +GET /api/posts/1/tags:get +GET /api/posts/1/tags:list +POST /api/posts/1/tags:update +POST /api/posts/1/tags:destroy +POST /api/posts/1/tags:add +GET /api/posts/1/tags:remove +``` + +## 资源定位 + +所有资源都通过 `filterByTk` 定位 + +- collection 资源,`filterByTk` 必须是唯一的 +- association 资源,`filterByTk` 可能并不是唯一的,需要同时提供 `sourceId` 来定位。 + +例如 `tables.fields` 表示数据表的字段 + +```bash +GET /api/tables/table1/fields/title +GET /api/tables/table2/fields/title +``` + +table1 和 table2 都有 title 字段,title 在 table1 里是唯一的,但是其他表也可能有 title 字段 diff --git a/docs/fr-FR/development/server/resources-actions-v2/rest-api.md b/docs/fr-FR/development/server/resources-actions-v2/rest-api.md new file mode 100644 index 000000000..2d7fd86d5 --- /dev/null +++ b/docs/fr-FR/development/server/resources-actions-v2/rest-api.md @@ -0,0 +1,184 @@ +# REST API + +NocoBase 的 HTTP API 是 REST API 的超集,标准的 CRUD API 也支持 RESTful 风格。 + +## Collection 资源 + +--- + +### 创建 collection + +HTTP API + +```bash +POST /api/:create + +{} # JSON body +``` + +REST API + +```bash +POST /api/ + +{} # JSON body +``` + +### 查看 collection 列表 + +HTTP API + +```bash +GET /api/:list +``` + +REST API + +```bash +GET /api/ +``` + +### 查看 collection 详情 + +HTTP API + +```bash +GET /api/:get?filterByTk= +GET /api/:get/ +``` + +REST API + +```bash +GET /api// +``` + +### 更新 collection + +HTTP API + +```bash +POST /api/:update?filterByTk= + +{} # JSON body + +# 或者 +POST /api/:update/ + +{} # JSON body +``` + +REST API + +```bash +PUT /api// + +{} # JSON body +``` + +### 删除 collection + +HTTP API + +```bash +POST /api/:destroy?filterByTk= +# 或者 +POST /api/:destroy/ +``` + +REST API + +```bash +DELETE /api// +``` + +## Association 资源 + +--- + +### 创建 Association + +HTTP API + +```bash +POST /api///:create + +{} # JSON body +``` + +REST API + +```bash +POST /api/// + +{} # JSON body +``` + +### 查看 Association 列表 + +HTTP API + +```bash +GET /api///:list +``` + +REST API + +```bash +GET /api/// +``` + +### 查看 Association 详情 + +HTTP API + +```bash +GET /api///:get?filterByTk= +# 或者 +GET /api///:get/ +``` + +REST API + +```bash +GET /api///:get/ +``` + +### 更新 Association + +HTTP API + +```bash +POST /api///:update?filterByTk= + +{} # JSON body + +# 或者 +POST /api///:update/ + +{} # JSON body +``` + +REST API + +```bash +PUT /api///:update/ + +{} # JSON 数据 +``` + +### 删除 Association + +HTTP API + +```bash +POST /api///:destroy?filterByTk= +# 或者 +POST /api///:destroy/ +``` + +REST API + +```bash +DELETE /api//// +``` diff --git a/docs/fr-FR/development/server/resources-actions-v2/to-resource.md b/docs/fr-FR/development/server/resources-actions-v2/to-resource.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/fr-FR/development/server/resources-actions-v2/vs-router.md b/docs/fr-FR/development/server/resources-actions-v2/vs-router.md new file mode 100644 index 000000000..c0c1122f3 --- /dev/null +++ b/docs/fr-FR/development/server/resources-actions-v2/vs-router.md @@ -0,0 +1 @@ +# 与 Router 的区别 diff --git a/docs/fr-FR/development/server/resources-actions.md b/docs/fr-FR/development/server/resources-actions.md new file mode 100644 index 000000000..12c4327d6 --- /dev/null +++ b/docs/fr-FR/development/server/resources-actions.md @@ -0,0 +1,468 @@ +# Resources and Actions + +In the web development world, you may have heard of the concept of RESTful, and NocoBase borrows this concept of resources to map various entities in the system, such as data in a database, a file in a file system or a service. However, NocoBase does not fully follow the RESTful conventions based on practical considerations, but rather extends the specifications from the [Google Cloud API Design Guide](https://cloud.google.com/apis/design) to fit more scenarios. + +## Basic concepts + +The same concept as resources in RESTful, which are externally available objects in the system that can be manipulated, such as data tables, files, and other custom objects. + +Actions refer to reading and writing to resources, usually for accessing data, creating data, updating data, deleting data, etc. NocoBase implements access to resources by defining actions, the core of which is actually a Koa-compatible middleware function for handling requests. + +### Automatic mapping of collections to resources + +NocoBase automatically maps collections to resources by default, and also provides a server-side data interface. So by default, as long as a collection is defined using `db.collection()`, you can access the data resources of this collection via NocoBase HTTP API. The name of the automatically generated resource is the same as the collection name, for example, the collection defined by `db.collection({ name: 'users' })` has the corresponding resource name `users`. + +Also, there are built-in common CRUD actions for these data resources, and built-in actions methods for associative data for relational data resources. + +The default actions for a simple data resource: + +- [`list`](/api/actions#list): Query the list of data in the collection +- [`get`](/api/actions#get): Query a single record in the collection +- [`create`](/api/actions#create): Create a single record to the collection +- [`update`](/api/actions#update): Update a single record on the collection +- [`destroy`](/api/actions#destroy): Delete a single record from the collection + +In addition to simple CRUD actions, relational resources have default relational actions: + +- [`add`](/api/actions#add): Add a association to the data +- [`remove`](/api/actions#remove): Removes an association from the data +- [`set`](/api/actions#set): Set the association to the data +- [`toggle`](/api/actions#toggle): Add or remove associations to data + +For example, to define an article collection and synchronize it to the database. + +```ts +app.db.collection({ + name: 'posts', + fields: [{ type: 'string', name: 'title' }], +}); + +await app.db.sync(); +``` + +All CRUD methods for the `posts` data resource can then be called directly via the HTTP API: ```bash + +```bash +# create +curl -X POST -H "Content-Type: application/json" -d '{"title": "first"}' http://localhost:13000/api/posts:create +# list +curl http://localhost:13000/api/posts:list +# update +curl -X PUT -H "Content-Type: application/json" -d '{"title": "second"}' http://localhost:13000/api/posts:update +# destroy +curl -X DELETE http://localhost:13000/api/posts:destroy?filterByTk=1 +``` + +### Customize Actions + +It is also possible to extend specific resources with more actions when the default provided actions such as CRUD do not satisfy the business scenario. For example, additional processing of built-in actions, or the need to set default parameters. + +Custom actions for specific resources, such as overriding the `create` action in the article collection. + +```ts +// Equivalent to app.resourcer.registerActions() +// Register the create action method for article resources +app.actions({ + async ['posts:create'](ctx, next) { + const postRepo = ctx.db.getRepository('posts'); + await postRepo.create({ + values: { + ... . ctx.action.params.values, + // restrict the current user to be the creator of the post + userId: ctx.state.currentUserId + } + }); + + await next(); + } +}); +``` + +This adds a reasonable restriction in the business that users cannot create articles as other users. + +Custom operations for all global resources, such as adding `export` action to all collections. + +```ts +app.actions({ + // Add export method to all resources for exporting data + async export(ctx, next) { + const repo = ctx.db.getRepository(ctx.action.resource); + const results = await repo.find({ + filter: ctx.action.params.filter + }); + ctx.type = 'text/csv'; + // Splice to CSV format + ctx.body = results + .map(row => Object.keys(row) + .reduce((arr, col) => [... . arr, row[col]], []).join(',') + ).join('\n'); + + next(); + } +}); +``` + +The data in CSV format can then be exported as follows from the HTTP API. + +```bash +curl http://localhost:13000/api/:export +``` + +### Action parameters + +Once the client's request reaches the server, the relevant request parameters are parsed by rule and placed on the request's `ctx.action.params` object. there are three main sources for Action parameters. + +1. default parameters at the time of Action definition +2. carried by the client request +3. other middleware preprocessing + +The parameters from these three parts are combined in this order and eventually passed into the action's execution function before being processed by the real action handler. This is also true in multiple middleware, where the parameters from the previous middleware are continued to be passed to the next middleware with `ctx`. + +The parameters available for built-in actions can be found in the [@nocobase/actions](/api/actions) package. Except for custom actions, client requests mainly use these parameters, and custom actions can be extended with the required parameters according to business requirements. + +Middleware preprocessing mainly uses the `ctx.action.mergeParams()` method and has different merge strategies depending on the parameter types, see also the [mergeParams()](/api/resourcer/action#mergeparams) method for details. + +The default parameters of the built-in Action can only be executed with the `mergeParams()` method for each parameter's default policy when merging, in order to achieve the purpose of limiting certain operations on the server side. For example + +```ts +app.resource({ + name: 'posts', + actions: { + create: { + whitelist: ['title', 'content'], + blacklist: ['createdAt', 'createdById'], + }, + }, +}); +``` + +The above defines the `create` action for the `posts` resource, where `whitelist` and `blacklist` are whitelisted and blacklisted respectively for the `values` parameter, i.e. only the `title` and `content` fields in the `values` parameter are allowed, and the ` createdAt` and `createdById` fields in the `values` parameter are disabled. + +### Custom resources + +Data-based resources are also divided into standalone resources and association resources. + +- Standalone resources: `` +- Association resources: `. ` + +```ts +// Equivalent to app.resourcer.define() + +// Define article resources +app.resource({ + name: 'posts', +}); + +// Define the article's author resource +app.resource({ + name: 'posts.user', +}); + +// Define the article's comment resource +app.resource({ + name: 'posts.coments', +}); +``` + +The cases where customization is needed are mainly for non-database table-like resources, such as in-memory data, proxy interfaces for other services, etc., and for cases where specific actions need to be defined for existing table-like resources. + +For example, to define a database-independent resource that sends a notification action. + +```ts +app.resource({ + name: 'notifications', + actions: { + async send(ctx, next) { + await someProvider.send(ctx.request.body); + next(); + }, + }, +}); +``` + +Then it can be accessed in the HTTP API as follows + +```bash +curl -X POST -d '{"title": "Hello", "to": "hello@nocobase.com"}' 'http://localhost:13000/api/notifications:send' +``` + +## Example + +Let's continue the simple store scenario from the previous [Collections and fields example](/development/server/collections-fields#Example) to further understand the concepts related to resources and actions. It is assumed here that we base further resource and action definitions on the previous collection's example, so the definition of collection is not repeated here. + +As long as the corresponding collections are defined, we can use default actions directly for data resources such as products, orders, etc. in order to complete the most basic CRUD scenarios. + +### Overriding default actions + +Sometimes, there are operations that are not simply for a single record, or the parameters of the default actions need to have some control, we can override the default actions. For example, when we create an order, instead of the client submitting `userId` to represent the ownership of the order, the server should determine the ownership of the order based on the currently logged-in user, so we can override the default `create` action. For simple extensions, we write directly in the main class of the plugin. + +```ts +import { Plugin } from '@nocobase/server'; +import actions from '@nocobase/actions'; + +export default class ShopPlugin extends Plugin { + async load() { + // ... + this.app.resource({ + name: 'orders', + actions: { + async create(ctx, next) { + ctx.action.mergeParams({ + values: { + userId: ctx.state.user.id, + }, + }); + + return actions.create(ctx, next); + }, + }, + }); + } +} +``` + +In this way, we override the default `create` action for order data resources during plugin loading, but the default logic is still called after modifying the action parameters, so there is no need to write it yourself. The `mergeParams()` method that modifies the submit parameters is useful for the built-in default actions, which we will describe later. + +### Custom actions for collection resources + +When the built-in actions do not meet the business needs, we can extend the functionality of the resource by customizing the actions. For example, usually an order will have many statuses, if we design the values of the `status` field as a series of enumerated values. + +- `-1`: cancelled +- `0`: order placed, not paid +- `1`: Paid, not shipped +- `2`: shipped, not signed +- `3`: signed, order completed + +Then we can realize the change of order status through custom actions, such as a shipping action on the order. Although the simple case can be realized through the `update` action, if there are more complicated cases such as payment and signing, using only `update` will cause the problem of unclear semantics and confusing parameters, so we can realize it through custom actions. + +First we add a definition of a shipping information collection, saved to `collections/deliveries.ts`. + +```ts +export default { + name: 'deliveries', + fields: [ + { + type: 'belongsTo', + name: 'order', + }, + { + type: 'string', + name: 'provider', + }, + { + type: 'string', + name: 'trackingNumber', + }, + { + type: 'integer', + name: 'status', + }, + ], +}; +``` + +Also extend the orders collection with an associated field for shipping information (`collections/orders.ts`). + +```ts +export default { + name: 'orders', + fields: [ + // ... . other fields + { + type: 'hasOne', + name: 'delivery', + }, + ], +}; +``` + +Then we add the corresponding action definition in the main class of the plugin: + +```ts +import { Plugin } from '@nocobase/server'; + +export default class ShopPlugin extends Plugin { + async load() { + // ... + this.app.resource({ + name: 'orders', + actions: { + async deliver(ctx, next) { + const { filterByTk } = ctx.action.params; + const orderRepo = ctx.db.getRepository('orders'); + + const [order] = await orderRepo.update({ + filterByTk, + values: { + status: 2, + delivery: { + ... . ctx.action.params.values, + status: 0 + status: 0 } + } + }); + + ctx.body = order; + + next(); + } + } + }); + } +} +``` + +The Repository uses the data repository class of collection, from which most of the data reading and writing actions are done, see the [Repository API](/api/database/repository) section for details. + +Once defined, we can call the "ship" action from the client via the HTTP API: + +```bash +curl \ + -X POST \ + -H 'Content-Type: application/json' \ + -d '{"provider": "SF", "trackingNumber": "SF1234567890"}' \ + '/api/orders:deliver/' +``` + +Similarly, we can define more similar actions, such as payment, signup, etc. + +### Parameter merging + +Suppose we want to allow users to query their own and only their own orders, and we need to restrict them from querying cancelled orders, then we can define with the default parameters of the action. + +```ts +import { Plugin } from '@nocobase/server'; + +export default class ShopPlugin extends Plugin { + async load() { + // ... + this.app.resource({ + name: 'orders', + actions: { + // default parameters for list actions + list: { + filter: { + // Filter operator extended by the users plugin + $isCurrentUser: true, + status: { + $ne: -1, + }, + }, + fields: ['id', 'status', 'createdAt', 'updatedAt'], + }, + }, + }); + } +} +``` + +When the user queries from the client, additional parameters can also be added to the requested URL, such as + +```bash +curl 'http://localhost:13000/api/orders:list?productId=1&fields=id,status,quantity,totalPrice&appends=product' +``` + +The actual query criteria will be combined as + +```json +{ + "filter": { + "$and": { + "$isCurrentUser": true, + "status": { + "$ne": -1 + }, + "productId": 1 + } + }, + "fields": [ + "id", + "status", + "quantity", + "totalPrice", + "createdAt", + "updatedAt" + ], + "appends": ["product"] +} +``` + +and get the expected query results. + +Alternatively, if we need to restrict the interface for creating orders to fields such as order number (`id`), total price (`totalPrice`), etc. that cannot be submitted by the client, this can be controlled by defining default parameters for the `create` action as follows + +```ts +import { Plugin } from '@nocobase/server'; + +export default class ShopPlugin extends Plugin { + async load() { + // ... + this.app.resource({ + name: 'orders', + actions: { + create: { + blacklist: ['id', 'totalPrice', 'status', 'createdAt', 'updatedAt'], + values: { + status: 0, + }, + }, + }, + }); + } +} +``` + +This way, even if the client intentionally submits these fields, they will be filtered out and will not exist in the `ctx.action.params` parameter set. + +If there are more complex restrictions, such as only being able to place an order if the item is on the shelf and in stock, this can be achieved by configuring the middleware to + +```ts +import { Plugin } from '@nocobase/server'; + +export default class ShopPlugin extends Plugin { + async load() { + // ... + this.app.resource({ + name: 'orders', + actions: { + create: { + middlewares: [ + async (ctx, next) => { + const { productId } = ctx.action.params.values; + + const product = await ctx.db.getRepository('products').findOne({ + filterByTk: productId, + filter: { + enabled: true, + inventory: { + $gt: 0, + }, + }, + }); + + if (!product) { + return ctx.throw(404); + } + + await next(); + }, + ], + }, + }, + }); + } +} +``` + +Putting some of the business logic (especially the preprocessing) into middleware makes our code clearer and easier to maintain. + +## Summary + +With the above example we have described how to define resources and related actions. To review this chapter. + +- Automatic mapping of collections to resources +- Built-in default resource actions +- Custom actions on resources +- Parameter merging order and strategy for operations + +The code covered in this chapter is included in a complete sample package [packages/samples/shop-actions](https://github.com/nocobase/nocobase/tree/main/packages/samples/shop-actions), which can be run directly locally to see the results. diff --git a/docs/fr-FR/development/server/routing.md b/docs/fr-FR/development/server/routing.md new file mode 100644 index 000000000..c378a20c7 --- /dev/null +++ b/docs/fr-FR/development/server/routing.md @@ -0,0 +1 @@ +# 路由 diff --git a/docs/fr-FR/development/server/telemetry.md b/docs/fr-FR/development/server/telemetry.md new file mode 100644 index 000000000..4a54a28af --- /dev/null +++ b/docs/fr-FR/development/server/telemetry.md @@ -0,0 +1,111 @@ +# Telemetry + +:::warning{title=Experimental} +::: + +The telemetry module of NocoBase is encapsulated based on OpenTelemetry. This article introduces how to use the telemetry module to collect Trace and Metric data to enhance the observability of the NocoBase system. + +:::info{title=Tip} +NocoBase needs to be configured with the environment variable `TELEMETRY_ENABLED=true` before starting to enable telemetry data collection. See other configurations: [Environment Variables - Telemetry](../../welcome/getting-started/env.md#telemetry_enabled). +::: + +## Instrumentation + +### Metrics + +```ts +const meter = app.telemetry.metric.getMeter(); +const counter = meter.createCounter('event_counter', {}); +counter.add(1); +``` + +References: + +- https://opentelemetry.io/docs/instrumentation/js/manual/#acquiring-a-meter + +### Traces + +```ts +const tracer = app.telemetry.trace.getTracer(); +tracer.startActiveSpan(); +tracer.startSpan(); +``` + +References: + +- https://opentelemetry.io/docs/instrumentation/js/manual/#acquiring-a-tracer + +### Libraries + +```ts +import { Plugin } from '@nocobase/server'; +import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; + +class InstrumentationPlugin extends Plugin { + afterAdd() { + this.app.on('beforeLoad', (app) => { + app.telemetry.addInstrumentation(getNodeAutoInstrumentations()); + }); + } +} +``` + +:::warning +In NocoBase, the initialization location of the telemetry module is `app.beforeLoad`, refer to: [Lifecycle](../life-cycle.md). Therefore, not all instrumentation libraries are suitable for NocoBase. +For example, instrumentation-koa needs to be introduced before `Koa` is instantiated, but although NocoBase's `Application` is based on `Koa`, the telemetry module is initialized after the `Application` is instantiated, so it cannot be applied. +::: + +References: + +- https://opentelemetry.io/docs/instrumentation/js/libraries/ + +## Collection + +### Metrics + +```ts +import { Plugin } from '@nocobase/server'; +import { + PeriodicExportingMetricReader, + ConsoleMetricExporter, +} from '@opentelemetry/sdk-metrics'; + +class MetricReaderPlugin extends Plugin { + afterAdd() { + this.app.on('beforeLoad', (app) => { + app.telemetry.metric.registerReader( + 'console', + () => + new PeriodicExportingMetricReader({ + exporter: new ConsoleMetricExporter(), + }), + ); + }); + } +} +``` + +### Traces + +```ts +import { Plugin } from '@nocobase/server'; +import { + BatchSpanProcessor, + ConsoleSpanExporter, +} from '@opentelemetry/sdk-trace-base'; + +class TraceSpanProcessorPlugin extends Plugin { + afterAdd() { + this.app.on('beforeLoad', (app) => { + app.telemetry.trace.registerProcessor( + 'console', + () => new BatchSpanProcessor(new ConsoleSpanExporter()), + ); + }); + } +} +``` + +References: + +- https://opentelemetry.io/docs/instrumentation/js/exporters \ No newline at end of file diff --git a/docs/fr-FR/development/server/test.md b/docs/fr-FR/development/server/test.md new file mode 100644 index 000000000..d6f2b908c --- /dev/null +++ b/docs/fr-FR/development/server/test.md @@ -0,0 +1,241 @@ +# Testing + +Testing is based on the [Jest](https://jestjs.io/) testing framework. To facilitate writing tests, `mockDatabase()` and `mockServer()` are provided for testing database and server-side applications. + +:::warning +The test environment variables are configured in the `.env.test` file. It's recommended to use a separate test database for testing. +::: + +## `mockDatabase()` + +A fully isolated db testing environment is provided by default. + +```ts +import { mockDatabase } from '@nocobase/test'; + +describe('my db suite', () => { + let db; + + beforeEach(async () => { + db = mockDatabase(); + db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], + }); + await db.sync(); + }); + + afterEach(async () => { + await db.close(); + }); + + test('my case', async () => { + const repository = db.getRepository('posts'); + const post = await repository.create({ + values: { + title: 'hello', + }, + }); + + expect(post.get('title')).toEqual('hello'); + }); +}); +``` + +## `mockServer()` + +A mock server application instance is provided, with the corresponding app.db being a `mockDatabase()` instance. Additionally, a convenient `app.agent()` is available for testing HTTP APIs. For Resource Action specific to NocoBase, `app.agent().resource()` is encapsulated for testing the Action of resources. + +```ts +import { MockServer, mockServer } from '@nocobase/test'; + +// Each plugin's minimal installation app is different, the necessary plugins need to be added according to their own conditions. +async function createApp(options: any = {}) { + const app = mockServer({ + ...options, + plugins: [ + 'acl', + 'users', + 'collection-manager', + 'error-handler', + ...options.plugins, + ], + // Other configuration parameters might also be present. + }); + // Here, some logic that needs special handling can be supplemented, such as importing data tables needed for testing. + return app; +} + +// Most tests need to start the application, so a common startup method can also be provided. +async function startApp() { + const app = createApp(); + await app.quickstart({ + // Before running tests, clear the database. + clean: true, + }); + return app; +} + +describe('test example', () => { + let app: MockServer; + + beforeEach(async () => { + app = await startApp(); + }); + + afterEach(async () => { + // After running the tests, clear the database. + await app.destroy(); + // Stop without clearing the database. + await app.stop(); + }); + + test('case1', async () => { + // coding... + }); +}); +``` + +## Common Application Processes + +If you need to test different processes, you can execute related commands according to the following examples. + +### Install then Start + +Terminal command line + +```bash +yarn nocobase install +yarn start +``` + +Preliminary test process + +```ts +const app = mockServer(); +await app.runCommand('install'); +await app.runCommand('start'); +``` + +### Start then Install + +Terminal command line + +```bash +yarn start # Stay in memory +# Execute in another terminal +yarn nocobase install +``` + +Preliminary test process + +```ts +const app = mockServer(); +await app.runCommand('start'); +await app.runCommand('install'); +``` + +### Quickstart (Auto Install or Upgrade) + +Terminal command line + +```bash +yarn start --quickstart +``` + +Preliminary test process + +```ts +const app = mockServer(); +await app.runCommand('start', '--quickstart'); +``` + +### Reinstall an Already Installed and Started Application + +Terminal command line + +```bash +yarn start --quickstart +# Execute in another terminal +yarn nocobase install -f +``` + +Preliminary test process + +```ts +const app = mockServer(); +await app.runCommand('start', '--quickstart'); +await app.runCommand('install', '-f'); +``` + +### Upgrade the Application (Before Starting) + +Terminal command line + +```bash +yarn nocobase upgrade +yarn start +``` + +Preliminary test process + +```ts +const app = mockServer(); +await app.runCommand('upgrade', '-f'); +await app.runCommand('start', '--quickstart'); +``` + +### Upgrade the Application (After Starting) + +```bash +yarn start # Stay in memory +# Execute in another terminal +yarn nocobase upgrade +``` + +Preliminary test process + +```ts +const app = mockServer(); +await app.runCommand('start', '--quickstart'); +await app.runCommand('upgrade', '-f'); +``` + +### Activate a Plugin + +Terminal command line + +```bash +yarn start --quickstart +yarn pm enable @my-project/plugin-hello +``` + +Preliminary test process + +```ts +const app = mockServer(); +await app.runCommand('start', '--quickstart'); +await app.runCommand('pm', 'enable', '@my-project/plugin-hello'); +``` + +### Disable a Plugin + +Terminal command line + +```bash +yarn start --quickstart +yarn pm disable @my-project/plugin-hello +``` + +Preliminary test process + +```ts +const app = mockServer(); +await app.runCommand('start', '--quickstart'); +await app.runCommand('pm', 'disable', '@my-project/plugin-hello'); +``` \ No newline at end of file diff --git a/docs/fr-FR/development/your-fisrt-plugin.md b/docs/fr-FR/development/your-fisrt-plugin.md new file mode 100644 index 000000000..5f75e6110 --- /dev/null +++ b/docs/fr-FR/development/your-fisrt-plugin.md @@ -0,0 +1,148 @@ +# Develop the first plugin + +Before start, you need to install NocoBase:. + +- [create-nocobase-app installation](/welcome/getting-started/installation/create-nocobase-app) +- [Git source installation](/welcome/getting-started/installation/git-clone) + +Once NocoBase is installed, we can start our plugin development journey. + +## Create a plugin + +First, you can quickly create an empty plugin via the CLI with the following command. + +```bash +yarn pm create @my-project/plugin-hello +``` + +The directory where the plugin located is `packages/plugins/@my-project/plugin-hello` and the plugin directory structure is + +```bash +|- /packages/plugins/@my-project/plugin-hello + |- /src + |- /client # plugin client code + |- /server # plugin server code + |- client.d.ts + |- client.js + |- package.json # plugin package information + |- server.d.ts + |- server.js +``` + +Visit the Plugin Manager to view the plugin you just added, the default address is http://localhost:13000/admin/pm/list/local/ + + + +If the plugin is not shown in the plugin manager, you can add it manually with the `pm add` command. + +```bash +yarn pm add @my-project/plugin-hello +``` + +## Code the plugin + +Create a new collection file in the plugin, e.g. `. /src/server/collections/hello.ts` with the following contents: + +```ts +import { defineCollection } from '@nocobase/database'; + +export default defineCollection({ + name: 'hello', + fields: [{ type: 'string', name: 'name' }], +}); +``` + +Modify the `. /src/server/plugin.ts` file as follows + +```ts +import { Plugin } from '@nocobase/server'; + +export class PluginHelloServer extends Plugin { + async afterAdd() {} + + async beforeLoad() {} + + async load() { + // This is just an example. Expose all actions of the hello collection to the public + this.app.acl.allow('hello', '*', 'public'); + } + + async install() {} + + async afterEnable() {} + + async afterDisable() {} + + async remove() {} +} + +export default PluginHelloServer; +``` + +## Activate the plugin + +**Operated by command** + +```bash +yarn pm enable @my-project/plugin-hello +``` + +**Operated by UI** + +Visit the Plugin Manager to view the plugin you just added and click enable. +The Plugin Manager page defaults to http://localhost:13000/admin/pm/list/local/ + + + +:::info{title="INFO"} +The collection configured in the plugin is automatically synchronized with the database when the plugin is activated, generating the corresponding data tables and fields. If the plugin is already active, you need to handle the synchronization of the data tables with the upgrade command `yarn nocobase upgrade`. +::: + +## Debug the Plugin + +If the app is not started, you need to start the app first + +```bash +# for development +yarn dev + +# for production +yarn build +yarn start +``` + +Insert data into the hello collection of the plugin + +```bash +curl --location --request POST 'http://localhost:13000/api/hello:create' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "name": "Hello world" +}' +``` + +View the data + +```bash +curl --location --request GET 'http://localhost:13000/api/hello:list' +``` + +## Build the plugin + +If you cloned the source code, you need to execute `yarn build` for a full build, otherwise, a type error will be reported. + +```bash +yarn build @my-project/plugin-hello --tar + +# step by step +yarn build @my-project/plugin-hello +yarn nocobase tar @my-project/plugin-hello +``` + +The default saved path for the plugin tar is `storage/tar/@my-project/plugin-hello.tar.gz` + +## Upload to other NocoBase applications + +Only supported in v0.14 and above + + diff --git a/docs/fr-FR/handbook/acl/index.md b/docs/fr-FR/handbook/acl/index.md new file mode 100644 index 000000000..a209174b2 --- /dev/null +++ b/docs/fr-FR/handbook/acl/index.md @@ -0,0 +1,81 @@ +# Access Control + +## Introduction + +NocoBase's ACL module mainly consists of two parts: + +- `@nocobase/acl` in the kernel, which provides core functions +- `@nocobase/plugin-acl` in the plugin, which provides dynamic configuration capabilities + +## Installation + +Built-in plugin, no separate installation required. + +## Development Guide + +### Extending a new permission configuration tab + +Below is an example of the "Mobile Menu" configuration item, demonstrating how to extend a new permission configuration tab. The effect is shown in the figure below: + +![20240903210248](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240903210248.png) + +The code is as follows: + +```typescript +import { Plugin } from '@nocobase/client'; +import PluginACLClient from '@nocobase/plugin-acl/client'; + +class PluginMobileClient extends Plugin { + async load() { + const aclInstance = this.app.pm.get(PluginACLClient); + + aclInstance?.settingsUI.addPermissionsTab(({ t, TabLayout, activeKey }) => ({ + key: 'mobile-menu', + label: t('Mobile menu', { + ns: 'plugin-mobile', + }), + children: ( + + + + ), + })); + } +} +``` + +First, we need to obtain an instance of the `PluginACLClient` plugin ([other methods to obtain plugin instances](https://docs.nocobase.com/development/client/life-cycle#%E8%8E%B7%E5%8F%96%E6%8F%92%E4%BB%B6)), and add a new permission configuration tab using the `settingsUI.addPermissionsTab` method. In this example, we added a permission configuration tab named "Mobile Menu". + +The value of the `settingsUI` property is an instance of a class named `ACLSettingsUI`, and its type information is as follows: + +```typescript +import { TabsProps } from 'antd/es/tabs/index'; + +interface ACLSettingsUI { + addPermissionsTab(tab: Tab | TabCallback): void; + getPermissionsTabs(props: PermissionsTabsProps): Tab[]; +} + +type Tab = TabsProps['items'][0]; + +type TabCallback = (props: PermissionsTabsProps) => Tab; + +interface PermissionsTabsProps { + /** + * the key of the currently active tab panel + */ + activeKey: string; + /** + * the currently selected role + */ + role: Role; + /** + * translation function + */ + t: TFunction; + /** + * used to constrain the size of the container in the Tab + */ + TabLayout: React.FC; +} +``` diff --git a/docs/fr-FR/handbook/acl/user/index.md b/docs/fr-FR/handbook/acl/user/index.md new file mode 100755 index 000000000..3ff5e1b2a --- /dev/null +++ b/docs/fr-FR/handbook/acl/user/index.md @@ -0,0 +1,225 @@ +# Hand book + +## **Management Center** + +##### **Role Management** + +The application comes with two predefined roles: "Admin" and "Member," each with distinct default permission settings tailored to their functionalities. + +![](https://static-docs.nocobase.com/da7083c67d794e23dc6eb0f85b1de86c.png) + +##### **Adding, Deleting, and Modifying Roles** + +The role identifier, a unique system identifier, allows customization of default roles, but the system's predefined roles cannot be deleted. + +![](https://static-docs.nocobase.com/35f323b346db4f9f12f9bee4dea63302.png) + +##### **Setting the Default Role** + +The default role is the one automatically assigned to new users if no specific role is provided during their creation. + +![](https://static-docs.nocobase.com/f41bba7ff55ca28715c486dc45bc1708.png) + +##### **Configuring Permissions** + +###### **General Permission Settings** + +![](https://static-docs.nocobase.com/119a9650259f9be71210121d0d3a435d.png) + +1. **Allows to configure interface**: This permission governs whether a user can configure the interface. Activating it adds a UI configuration button. The "admin" role has this permission enabled by default. +2. **Allows to install, activate, disable plugins**: This permission dictates whether a user can enable or disable plugins. When active, the user gains access to the plugin manager interface. The "admin" role has this permission enabled by default. +3. **Allows to configure plugins**: This permission lets the user configure plugin parameters or manage plugin backend data. The "admin" role has this permission enabled by default. +4. **Allows to clear cache, reboot application**: This permission is tied to system maintenance tasks like clearing the cache and restarting the application. Once activated, related operation buttons appear in the personal center. This permission is disabled by default. +5. **New menu items are allowed to be accessed by default.**: Newly created menus are accessible by default, and this setting is enabled by default. + +###### **Action permissions** + +Action permissions apply universally to all data tables and are categorized by operation type. These permissions can be configured based on data scope: all data or the user's own data. The former allows operations on the entire data table, while the latter restricts operations to data relevant to the user. + +##### **Data Table Operation Permissions** + +![](https://static-docs.nocobase.com/6a6e0281391cecdea5b5218e6173c5d7.png) + +![](https://static-docs.nocobase.com/9814140434ff9e1bf028a6c282a5a165.png) + +Collection operation permissions allow fine-tuning of Action permissions by configuring access to resources within each data table. These permissions include: + +1. **Action permissions**: These include adding, viewing, editing, deleting, exporting, and importing actions. Permissions are set based on data scope: +- **All records**: Grants the user the ability to perform actions on all records within the data table. +- **Own records**: Restricts the user to perform actions only on records they have created. + +2. **Field Permissions**: Field permissions enable you to set specific permissions for each field during different operations. For instance, certain fields can be configured to be view-only, without editing privileges. + +##### **Menu permissions** + +Menu permissions control access based on menu items. + +![](https://static-docs.nocobase.com/28eddfc843d27641162d9129e3b6e33f.png) + +##### **Plugin Configuration Permissions** + +Plugin configuration permissions control the ability to configure specific plugin parameters. When enabled, the corresponding plugin management interface appears in the management center. + +![](https://static-docs.nocobase.com/5a742ae20a9de93dc2722468b9fd7475.png) + +#### **Personal Center** + +##### **Role Switching** + +Users can be assigned multiple roles and switch between them in the personal center. The default role when logging in is determined by the most recently switched role (this value updates with each switch) or, if not applicable, the first role (system default role). + +![](https://static-docs.nocobase.com/e331d11ec1ca3b8b7e0472105b167819.png) + +#### **Application in UI** + +##### **Data Block Permissions** + +Visibility of data blocks in a data table is controlled by view operation permissions, with individual configurations taking precedence over global settings. + +For example, under global permissions, the "admin" role has full access, but the order table may have individual permissions configured, making it invisible. + +![](https://static-docs.nocobase.com/3d026311739c7cf5fdcd03f710d09bc4.png) + +![](https://static-docs.nocobase.com/a88caba1cad47001c1610bf402a4a2c1.png) + +###### **Field Permissions** + +- **View**: Determines whether specific fields are visible at the field level, allowing control over which fields are visible to certain roles within the order table. + +![](https://static-docs.nocobase.com/30dea84d984d95039e6f7b180955a6cf.png) + +In the UI, only fields with configured permissions are visible within the order table block. System fields (Id, CreatedAt, LastUpdatedAt) retain view permissions even without specific configuration. + +![](https://static-docs.nocobase.com/40cc49b517efe701147fd2e799e79dcc.png) + +- **Edit**: Controls whether fields can be edited and saved (updated). + + In the UI, only fields with edit permissions are shown in the edit operation form block within the order table. + +![](https://static-docs.nocobase.com/6531ca4122f0887547b5719e2146ba93.png) + +Similarly, only fields with add permissions are shown in the add operation form block within the order table. + +![](https://static-docs.nocobase.com/12982450c311ec1bf87eb9dc5fb04650.png) + +![](https://static-docs.nocobase.com/1dbe559a9579c2e052e194e50edc74a7.gif) + +- **Add**: Determines whether fields can be added (created). + +![](https://static-docs.nocobase.com/3ab1bbe41e61915e920fd257f2e0da7e.png) + +In the UI, only fields with add permissions are displayed within the add operation form block of the order table. + +![](https://static-docs.nocobase.com/8d0c07893b63771c428974f9e126bf35.png) + +- **Export**: Controls whether fields can be exported. +- **Import**: Controls whether fields can be imported. + +##### **Operation Permissions** + +Individually configured permissions take the highest priority. If specific permissions are configured, they override global settings; otherwise, the global settings are applied. + +- **Add new**: Controls whether the add operation button is visible within a block. + +![](https://static-docs.nocobase.com/2e3123b5dbc72ae78942481360626629.png) + +When the add operation is permitted, the add button appears within the operation area of the order table block in the UI. + +![](https://static-docs.nocobase.com/f0458980d450544d94c73160d75ba96c.png) + +- **View**: Determines whether the data block is visible. + +![](https://static-docs.nocobase.com/6e4a1e6ea92f50bf84959dedbf1d5683.png) + +In the UI, data blocks for other data tables remain hidden, but the order table block is shown if individual permissions are set. + +![](https://static-docs.nocobase.com/f2dd142a40fe19fb657071fd901b2291.png) + +![](https://static-docs.nocobase.com/b92f0edc51a27b52e85cdeb76271b936.gif) + +- **Edit**: Controls whether the edit operation button is displayed within a block. + +![](https://static-docs.nocobase.com/fb1c0290e2a833f1c2b415c761e54c45.gif) + +Operation permissions can be further refined by setting the data scope. + +![](https://static-docs.nocobase.com/b082308f62a3a9084cab78a370c14a9f.gif) + +- **Delete**: Controls whether the delete operation button is visible within a block. + +![](https://static-docs.nocobase.com/021c9e79bcc1ad221b606a9555ff5644.gif) + +- **Export**: Controls whether the export operation button is visible within a block. +- **Import**: Controls whether the import operation button is visible within a block. + +#### Relationship Permissions + +##### When Used as a Field + +- The visibility of a relationship field is determined by the permissions set on the source table's fields. These permissions control whether the entire relationship field component appears in the user interface. + +For example, in the Order table, the "Customer" relationship field is restricted to view and import/export permissions, as depicted below: + +![Relationship Permissions Example](https://static-docs.nocobase.com/d0dc797aae73feeabc436af285dd4f59.png) + +In the UI, this configuration ensures that the "Customer" relationship field does not appear in the add and edit operation sections of the Order table. + +The complete configuration process is illustrated below: + +![Example Configuration Process](https://static-docs.nocobase.com/372f8a4f414feea097c23b2ba326c0ef.gif) + +- The permissions for fields within the relationship field component (such as those found in sub-tables or sub-forms) are determined by the permissions of the target data table. + +When the relationship field component is a sub-form: + +In this case, as shown, the "Customer" relationship field in the Order table is granted full permissions, while the Customer table itself is configured to be read-only. + +The permissions for the Order table are set as follows, granting the "Customer" relationship field full access: + +![Order Table Permissions](https://static-docs.nocobase.com/3a3ab9722f14a7b3a35361219d67fa40.png) + +The permissions for the Customer table are configured to allow view-only access: + +![Customer Table Permissions](https://static-docs.nocobase.com/46704d179b931006a9a22852e6c5089e.png) + +In the UI, this configuration results in the "Customer" relationship field being visible in the Order table section. However, when the interface is switched to a sub-form (where fields within the sub-form are visible in the details but hidden during new or edit operations), the behavior changes accordingly. + +The complete configuration process is demonstrated below: + +![Example Configuration Process](https://static-docs.nocobase.com/932dbf6ac46e36ee357ff3e8b9ea1423.gif) + +Further refinement of sub-form field permissions allows individual fields to be specifically controlled. + +For instance, as shown below, the Customer table can be configured so that the "Customer Name" field is neither visible nor editable: + +![Customer Table Field Permissions](https://static-docs.nocobase.com/e7b875521cbc4e28640f027f36d0413c.png) + +The complete configuration process for this setting is illustrated here: + +![Example Configuration Process](https://static-docs.nocobase.com/7a07e68c2fe2a13f0c2cef19be489264.gif) + +When dealing with a sub-table instead of a sub-form, the configuration principles remain the same: + +As illustrated, the "shipment" relationship field in the Order table has full permissions, while the shipment collection itself is set to read-only. + +In the UI, this setup allows the relationship field to be visible. However, when the interface is switched to a sub-table (where fields within the sub-table are visible during viewing operations but hidden during new or edit operations), the behavior adjusts accordingly. + +![shipment Relationship Field Permissions](https://static-docs.nocobase.com/fd4b7d81cdd765db789d9c85cf9dc324.gif) + +Fine-tuning sub-collection field permissions also enables specific control over individual fields. + +![Sub-table Field Permissions](https://static-docs.nocobase.com/51d70a624cb2b0366e421bcdc8abb7fd.gif) + +##### When Used as a Block + +- The visibility of a relationship block is governed by the permissions set on the target table associated with the relationship field, independent of the permissions on the relationship field itself. + +For example, the visibility of the "Customer" relationship block is controlled by the permissions configured for the Customer table: + +![Relationship Block Visibility](https://static-docs.nocobase.com/633ebb301767430b740ecfce11df47b3.gif) + +- The fields within a relationship block are controlled by the permissions set on the target table’s fields. + +As depicted below, the Customer table can be configured to allow viewing of specific fields only: + +![Customer Table Field View Permissions](https://static-docs.nocobase.com/35af9426c20911323b17f67f81bac8fc.gif) diff --git a/docs/fr-FR/handbook/acl/user/static/ApOObW9lGoRGE0xcFcscpDZ5nid.png b/docs/fr-FR/handbook/acl/user/static/ApOObW9lGoRGE0xcFcscpDZ5nid.png new file mode 100755 index 000000000..db526bc48 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/ApOObW9lGoRGE0xcFcscpDZ5nid.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/AtS4bAdLCojw2Ex4FvjcEn1tngx.gif b/docs/fr-FR/handbook/acl/user/static/AtS4bAdLCojw2Ex4FvjcEn1tngx.gif new file mode 100755 index 000000000..7fee988d6 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/AtS4bAdLCojw2Ex4FvjcEn1tngx.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/CIZCbruUtoFZe1xIHUWcS2HwnEh.png b/docs/fr-FR/handbook/acl/user/static/CIZCbruUtoFZe1xIHUWcS2HwnEh.png new file mode 100755 index 000000000..dab9413b2 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/CIZCbruUtoFZe1xIHUWcS2HwnEh.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/DAICbLqwLo6nLzx9LcpcRFj5nAf.png b/docs/fr-FR/handbook/acl/user/static/DAICbLqwLo6nLzx9LcpcRFj5nAf.png new file mode 100755 index 000000000..afa7b374f Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/DAICbLqwLo6nLzx9LcpcRFj5nAf.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/DYmDbQ2AGoZzCGxgQrcccDgNnVg.gif b/docs/fr-FR/handbook/acl/user/static/DYmDbQ2AGoZzCGxgQrcccDgNnVg.gif new file mode 100755 index 000000000..8dac8e660 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/DYmDbQ2AGoZzCGxgQrcccDgNnVg.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/E5P7bepyPobSYhxIFH3c1T1onRg.png b/docs/fr-FR/handbook/acl/user/static/E5P7bepyPobSYhxIFH3c1T1onRg.png new file mode 100755 index 000000000..f06b7366d Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/E5P7bepyPobSYhxIFH3c1T1onRg.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/EB0gbEm3bo7zXfxzcxocAh1snth.gif b/docs/fr-FR/handbook/acl/user/static/EB0gbEm3bo7zXfxzcxocAh1snth.gif new file mode 100755 index 000000000..b07b60867 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/EB0gbEm3bo7zXfxzcxocAh1snth.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/EIvgbZPupooY9IxeH5Gc0Vxan0g.png b/docs/fr-FR/handbook/acl/user/static/EIvgbZPupooY9IxeH5Gc0Vxan0g.png new file mode 100755 index 000000000..145e06603 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/EIvgbZPupooY9IxeH5Gc0Vxan0g.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/EiCSbyvcToilFqxngPlcabEnnog.gif b/docs/fr-FR/handbook/acl/user/static/EiCSbyvcToilFqxngPlcabEnnog.gif new file mode 100755 index 000000000..b396b58eb Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/EiCSbyvcToilFqxngPlcabEnnog.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/FoykbYbvNorP1axz1DKcdQ66nrh.png b/docs/fr-FR/handbook/acl/user/static/FoykbYbvNorP1axz1DKcdQ66nrh.png new file mode 100755 index 000000000..ace81a4ad Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/FoykbYbvNorP1axz1DKcdQ66nrh.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/FpqdbZ04noXYClxvvPBcYsPFnNf.png b/docs/fr-FR/handbook/acl/user/static/FpqdbZ04noXYClxvvPBcYsPFnNf.png new file mode 100755 index 000000000..16bfebd24 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/FpqdbZ04noXYClxvvPBcYsPFnNf.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/FshmbDt5connlpxtExrc73orn1b.png b/docs/fr-FR/handbook/acl/user/static/FshmbDt5connlpxtExrc73orn1b.png new file mode 100755 index 000000000..1d2f3dafb Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/FshmbDt5connlpxtExrc73orn1b.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/GR9jb8gPso3LRjxFIb9cndOBnub.gif b/docs/fr-FR/handbook/acl/user/static/GR9jb8gPso3LRjxFIb9cndOBnub.gif new file mode 100755 index 000000000..92d4a71db Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/GR9jb8gPso3LRjxFIb9cndOBnub.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/GYWIbViYxo2peYxT0xMcyZO2n5c.png b/docs/fr-FR/handbook/acl/user/static/GYWIbViYxo2peYxT0xMcyZO2n5c.png new file mode 100755 index 000000000..89d8a8a82 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/GYWIbViYxo2peYxT0xMcyZO2n5c.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/I5uKbd4NXoUBL0x3jpIc6UXrnCb.png b/docs/fr-FR/handbook/acl/user/static/I5uKbd4NXoUBL0x3jpIc6UXrnCb.png new file mode 100755 index 000000000..7205e40ce Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/I5uKbd4NXoUBL0x3jpIc6UXrnCb.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/IHmhbshM8oDxxJx3VYyc6A7rn1c.png b/docs/fr-FR/handbook/acl/user/static/IHmhbshM8oDxxJx3VYyc6A7rn1c.png new file mode 100755 index 000000000..67163711d Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/IHmhbshM8oDxxJx3VYyc6A7rn1c.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/JVxSbTW1soiPz3xDqiPcTR4Znbe.png b/docs/fr-FR/handbook/acl/user/static/JVxSbTW1soiPz3xDqiPcTR4Znbe.png new file mode 100755 index 000000000..c45934d82 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/JVxSbTW1soiPz3xDqiPcTR4Znbe.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/KHgXbk4oRo7qWQxlP2pc5Otnnsd.gif b/docs/fr-FR/handbook/acl/user/static/KHgXbk4oRo7qWQxlP2pc5Otnnsd.gif new file mode 100755 index 000000000..39af67150 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/KHgXbk4oRo7qWQxlP2pc5Otnnsd.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/KNeebcJghocQbVxLltycetuMnTb.gif b/docs/fr-FR/handbook/acl/user/static/KNeebcJghocQbVxLltycetuMnTb.gif new file mode 100755 index 000000000..9dc5738d9 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/KNeebcJghocQbVxLltycetuMnTb.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/MolVbOe3GozpHYx3efAcg5ZLnzg.png b/docs/fr-FR/handbook/acl/user/static/MolVbOe3GozpHYx3efAcg5ZLnzg.png new file mode 100755 index 000000000..c92bf6db6 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/MolVbOe3GozpHYx3efAcg5ZLnzg.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/OtZab2PZEomdf5xvZIhcosLAnGc.gif b/docs/fr-FR/handbook/acl/user/static/OtZab2PZEomdf5xvZIhcosLAnGc.gif new file mode 100755 index 000000000..e52399755 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/OtZab2PZEomdf5xvZIhcosLAnGc.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/PFYqbxqCvoAxVUx29UYctS8KnRf.png b/docs/fr-FR/handbook/acl/user/static/PFYqbxqCvoAxVUx29UYctS8KnRf.png new file mode 100755 index 000000000..dbf809de4 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/PFYqbxqCvoAxVUx29UYctS8KnRf.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/ROF6b4SkboxFezxftsjczo9GnOb.png b/docs/fr-FR/handbook/acl/user/static/ROF6b4SkboxFezxftsjczo9GnOb.png new file mode 100755 index 000000000..6493eec90 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/ROF6b4SkboxFezxftsjczo9GnOb.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/RXwSbzriCorfatxFtbXceEYynrL.png b/docs/fr-FR/handbook/acl/user/static/RXwSbzriCorfatxFtbXceEYynrL.png new file mode 100755 index 000000000..c7ee54d5f Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/RXwSbzriCorfatxFtbXceEYynrL.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/RgAIbdr1QofBorxbiYjcG7lun3e.gif b/docs/fr-FR/handbook/acl/user/static/RgAIbdr1QofBorxbiYjcG7lun3e.gif new file mode 100755 index 000000000..35ef5e034 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/RgAIbdr1QofBorxbiYjcG7lun3e.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/S5lbbuqAwovP2BxIMOjcy1wLnwb.gif b/docs/fr-FR/handbook/acl/user/static/S5lbbuqAwovP2BxIMOjcy1wLnwb.gif new file mode 100755 index 000000000..6906199be Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/S5lbbuqAwovP2BxIMOjcy1wLnwb.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/SNB8bN20JoxqFwx3BoXc5O9nnod.png b/docs/fr-FR/handbook/acl/user/static/SNB8bN20JoxqFwx3BoXc5O9nnod.png new file mode 100755 index 000000000..d48cfe9e7 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/SNB8bN20JoxqFwx3BoXc5O9nnod.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/SyiPbKA9WoJs5FxkZChcrXusnTf.png b/docs/fr-FR/handbook/acl/user/static/SyiPbKA9WoJs5FxkZChcrXusnTf.png new file mode 100755 index 000000000..3e44c7f6b Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/SyiPbKA9WoJs5FxkZChcrXusnTf.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/UY2Db5jEyotKkMxS8qoc7C2Nnnv.png b/docs/fr-FR/handbook/acl/user/static/UY2Db5jEyotKkMxS8qoc7C2Nnnv.png new file mode 100755 index 000000000..856e4c87a Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/UY2Db5jEyotKkMxS8qoc7C2Nnnv.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/Vpo9bBdw9oavWoxp2m4cBeDEnod.png b/docs/fr-FR/handbook/acl/user/static/Vpo9bBdw9oavWoxp2m4cBeDEnod.png new file mode 100755 index 000000000..001171bba Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/Vpo9bBdw9oavWoxp2m4cBeDEnod.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/WDiCbdoluonCzDxjHUtc3yKPnmb.png b/docs/fr-FR/handbook/acl/user/static/WDiCbdoluonCzDxjHUtc3yKPnmb.png new file mode 100755 index 000000000..1ae217312 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/WDiCbdoluonCzDxjHUtc3yKPnmb.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/WI0ab4oznobXB8xpL7Jc2PXgnhe.gif b/docs/fr-FR/handbook/acl/user/static/WI0ab4oznobXB8xpL7Jc2PXgnhe.gif new file mode 100755 index 000000000..93205b40d Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/WI0ab4oznobXB8xpL7Jc2PXgnhe.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/XEU3byFr6osZ5WxgCdCcOKjHnMf.gif b/docs/fr-FR/handbook/acl/user/static/XEU3byFr6osZ5WxgCdCcOKjHnMf.gif new file mode 100755 index 000000000..da214bb55 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/XEU3byFr6osZ5WxgCdCcOKjHnMf.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/XJytbsa8xopRSXxliqRc3YZUnTb.png b/docs/fr-FR/handbook/acl/user/static/XJytbsa8xopRSXxliqRc3YZUnTb.png new file mode 100755 index 000000000..565c94bfd Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/XJytbsa8xopRSXxliqRc3YZUnTb.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/Y3Yrb3bNGoHJLExWJsGc0I9Jn8d.png b/docs/fr-FR/handbook/acl/user/static/Y3Yrb3bNGoHJLExWJsGc0I9Jn8d.png new file mode 100755 index 000000000..9c57c69e7 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/Y3Yrb3bNGoHJLExWJsGc0I9Jn8d.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/Yi7pbJn5votBFXxi5bOcUWuRned.png b/docs/fr-FR/handbook/acl/user/static/Yi7pbJn5votBFXxi5bOcUWuRned.png new file mode 100755 index 000000000..81fee1119 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/Yi7pbJn5votBFXxi5bOcUWuRned.png differ diff --git a/docs/fr-FR/handbook/acl/user/static/Yot3bmSRSohJUDxbt4ccjc7Enbb.gif b/docs/fr-FR/handbook/acl/user/static/Yot3bmSRSohJUDxbt4ccjc7Enbb.gif new file mode 100755 index 000000000..b38181311 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/Yot3bmSRSohJUDxbt4ccjc7Enbb.gif differ diff --git a/docs/fr-FR/handbook/acl/user/static/ZtAbbjIk3oJzg8xH9fccXrFenmf.png b/docs/fr-FR/handbook/acl/user/static/ZtAbbjIk3oJzg8xH9fccXrFenmf.png new file mode 100755 index 000000000..dd90c2d85 Binary files /dev/null and b/docs/fr-FR/handbook/acl/user/static/ZtAbbjIk3oJzg8xH9fccXrFenmf.png differ diff --git a/docs/fr-FR/handbook/action-bulk-edit/index.md b/docs/fr-FR/handbook/action-bulk-edit/index.md new file mode 100644 index 000000000..758ec2fb1 --- /dev/null +++ b/docs/fr-FR/handbook/action-bulk-edit/index.md @@ -0,0 +1,25 @@ +# **Bulk Edit** + +## Introduction + +The Bulk editing feature is crafted for situations where different update logic must be applied to various groups of records, offering high flexibility in data processing tasks. When the user clicks the batch editing button, a configuration interface appears, enabling the user to define distinct assignment logic for each field. This allows for precise control over how each record is updated based on specific needs. + +![Bulk Editing Interface](https://static-docs.nocobase.com/70e1fb4122f56fc340405b16d229bd60.png) + +## Installation + +## User Guide + +1. Select the data for Bulk editing: either Selected or All, with the default option being Selected. + +![Bulk Editing Data Selection](https://static-docs.nocobase.com/c158538d86397bd48fdaed606b647166.png) + +2. Define the update logic for each field, with options to: + + - Leave unchanged + - Modify to a specified value + - Clear the field + +In the example shown, the Bulk editing operation is applied within the shipment table block. The selected data has the transportation mode updated to air freight, and both the delivery confirmation and actual arrival times are cleared. + +![Bulk Editing Configuration](https://static-docs.nocobase.com/65db9e898d11b01441b7830895f4dd76.gif) diff --git a/docs/fr-FR/handbook/action-bulk-edit/static/ADLkbw3g0o4dgBxncrGcqxsAnpf.png b/docs/fr-FR/handbook/action-bulk-edit/static/ADLkbw3g0o4dgBxncrGcqxsAnpf.png new file mode 100644 index 000000000..7d6e2fb1c Binary files /dev/null and b/docs/fr-FR/handbook/action-bulk-edit/static/ADLkbw3g0o4dgBxncrGcqxsAnpf.png differ diff --git a/docs/fr-FR/handbook/action-bulk-edit/static/H6CCbiXCJossUKxi15ucGt8mnyh.png b/docs/fr-FR/handbook/action-bulk-edit/static/H6CCbiXCJossUKxi15ucGt8mnyh.png new file mode 100644 index 000000000..950d527cb Binary files /dev/null and b/docs/fr-FR/handbook/action-bulk-edit/static/H6CCbiXCJossUKxi15ucGt8mnyh.png differ diff --git a/docs/fr-FR/handbook/action-bulk-edit/static/NTMAbTY1wowNOGx0iSacsd8anLh.gif b/docs/fr-FR/handbook/action-bulk-edit/static/NTMAbTY1wowNOGx0iSacsd8anLh.gif new file mode 100644 index 000000000..a9cd61e37 Binary files /dev/null and b/docs/fr-FR/handbook/action-bulk-edit/static/NTMAbTY1wowNOGx0iSacsd8anLh.gif differ diff --git a/docs/fr-FR/handbook/action-bulk-update/index.md b/docs/fr-FR/handbook/action-bulk-update/index.md new file mode 100644 index 000000000..137d5ff37 --- /dev/null +++ b/docs/fr-FR/handbook/action-bulk-update/index.md @@ -0,0 +1,16 @@ +# Bulk update + +## Introduction + +The bulk update function is designed for situations where you need to apply the same modification across multiple records. Before executing a batch update, users must first define the logic for assigning values to the fields that will be updated. This logic is applied to all selected records once the update button is clicked. + +![](https://static-docs.nocobase.com/d9e6804f7cdbecd43ce4695bb83561cd.png) + +## User Guide + +1. Set the Data to Update: Choose between "Selected" or "All," with "Selected" being the default option. +2. Field Assignment: Specify which fields will be included in the batch update; only these specified fields will be affected. + +In the example shown, the batch update operation is configured in the waybill table to mark the selected records as "Delivery Confirmed." + +![](https://static-docs.nocobase.com/41eb7980cd31ebfb013c05c1bbb747a5.gif) diff --git a/docs/fr-FR/handbook/action-bulk-update/static/CWWrbfcHho0vphxAHu1cQdDTnIf.gif b/docs/fr-FR/handbook/action-bulk-update/static/CWWrbfcHho0vphxAHu1cQdDTnIf.gif new file mode 100644 index 000000000..bb8289eee Binary files /dev/null and b/docs/fr-FR/handbook/action-bulk-update/static/CWWrbfcHho0vphxAHu1cQdDTnIf.gif differ diff --git a/docs/fr-FR/handbook/action-bulk-update/static/Tb0ZbOmd1oqw9TxWVamcOEhrntd.png b/docs/fr-FR/handbook/action-bulk-update/static/Tb0ZbOmd1oqw9TxWVamcOEhrntd.png new file mode 100644 index 000000000..33fc353d8 Binary files /dev/null and b/docs/fr-FR/handbook/action-bulk-update/static/Tb0ZbOmd1oqw9TxWVamcOEhrntd.png differ diff --git a/docs/fr-FR/handbook/action-custom-request/index.md b/docs/fr-FR/handbook/action-custom-request/index.md new file mode 100644 index 000000000..cc7695f37 --- /dev/null +++ b/docs/fr-FR/handbook/action-custom-request/index.md @@ -0,0 +1,51 @@ +# Custom Request + + +## Overview + +## Installation + +This plugin is built-in, so no separate installation is required. + +## Instructions for Use + +![20240426120014](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426120014.png) + +### Configuring Permissions + +When the "Allows to configuration interface" option is selected, you can set up custom requests. + +![20240426114957](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426114957.png) + +The customRequests table is system-level, and permissions are controlled via the acl.registerSnippet method. + +```typescript +this.app.acl.registerSnippet({ + name: 'ui.customRequests', // Permission for configuring interface related to ui.* + actions: ['customRequests:*'], +}); +``` +### Variables + +You can configure variables within both the URL and request body. + +- Current record +- Current user +- Current time +- API token (supported by v1.3.22-beta and above) + +![20240426120953](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426120953.png) + +![20240426121051](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426121051.png) + +## Operation Configuration Items + +### Request Settings + +![20240426120131](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426120131.png) + +### Access Control + +Each custom request can have custom role-based permissions, with default permissions granted to all users. + +![20240426120451](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426120451.png) diff --git a/docs/fr-FR/handbook/action-duplicate/index.md b/docs/fr-FR/handbook/action-duplicate/index.md new file mode 100644 index 000000000..7f9fcdda9 --- /dev/null +++ b/docs/fr-FR/handbook/action-duplicate/index.md @@ -0,0 +1,98 @@ +# Copy + + + +## Overview + +The copy feature allows users to create new data entries based on existing records. It supports two modes: direct copy and copy to a form for further editing. + +## Installation + +This is a built-in plugin, so no additional installation is needed. + +## Copy Modes + +### Direct Duplicate + +![](https://static-docs.nocobase.com/2c0ac5d1a539de4b72b49b7d966d8c09.png) + +- By default, data is copied using the direct copy mode; +- Target collection: Specifies where the copied data will be stored(For inherited tables, the data can be copied to a sub-table. Direct copy is limited to the current table); +- Data fields: Defines which fields to include in the copy. You can select all or specific fields, required. + +Once configured, simply click the button to copy the data. + +### Copy Into the Form and Continue to Fill in + +The fields defined in the template will be pre-filled as default values in a form, allowing you to modify them before submitting to complete the copy. + +You can choose to copy the data to the current table or a sub-table (in inherited cases). + +![](https://static-docs.nocobase.com/a072aa572fd0a0fe643eadf95471da2a.png) + +Template Field Configuration: Only the selected fields will be pre-filled in the form as default values. + +![](https://static-docs.nocobase.com/8032fa2025180ade275da55b97774b4d.png) + +The "Waybill" (o2m) relationship is copied, and its field components are set as a sub-form. The fields within the sub-form are configurable. + +![](https://static-docs.nocobase.com/b13c9287bae8601646727a2e78b81be7.png) + +#### Sync From Form Fields + +- The system will automatically interpret the fields already configured in the current form block as template fields; +- After modifying the form block fields (e.g., adjusting relationship components), you can reopen the template configuration and click the "Sync Form" button to ensure consistency between the form and the template. + +![](https://static-docs.nocobase.com/156b6d8d741521e63d12e49092414d58.png) + +Template data will populate the form with default values, allowing you to adjust them and submit to complete the copy operation. + +![](https://static-docs.nocobase.com/1c0a0ae0c59971f48b2282a68831d44b.png) + +Below is an example of setting up the copy function for an order list. + +![](https://static-docs.nocobase.com/fa8a89abf0ba136df04b6d0d838eae4e.gif) + +### Additional Information + +#### Copying, Referencing, and Preloading + +Different field types (with different relationships) require different handling logic, such as copying, referencing, or preloading. Modifications to relationship field components can also affect this logic (Select and Record picker components handle references, while Sub-form and Sub-table components handle copies). + +- Copying: + + - Standard fields are copied; + - For hasOne and hasMany relationships, fields can only be copied (i.e., these types of relationships cannot use Select or Record picker as components but must use Sub-form, Sub-table, etc.); + - Adjusting hasOne or hasMany field components won’t change the copying logic; + - All sub-fields of copied relationships can be selected. + +- Referencing + + - belongsTo and belongsToMany relationships are handled as references; + - **References can transform into copies. For example, if the field component changes from select to sub-form, the relationship turns from a reference to a copy. After this, all subfields become selectable.** + +- Preloading: Refers to relationship fields within referenced fields. + + - Fields within referenced relationships are preloaded; + - Adjustments to preloaded relationship fields can cause them to switch to a reference or copy logic. + +#### Select All + +- All copy and reference fields are selected by default. + +#### Fields Excluded When Selected as Data Templates: +- Primary keys of copied relationships are filtered out, but primary keys of references and preloaded data are not +- Foreign keys +- Fields that must remain unique +- Sorting fields +- Auto-generated fields +- Password field +- Creator +- Creation date +- Last updated by +- Last update date + +#### Sync From Form Fields + +- The fields already configured in the form block will be automatically parsed as template fields. +- After modifying the form block (e.g., adjusting relationship field components), reopen the template configuration and click the "Sync Form" button to ensure the form aligns with the template. diff --git a/docs/fr-FR/handbook/action-duplicate/static/KR15bOuXoo0u5QxZXmjcNbUJnoe.png b/docs/fr-FR/handbook/action-duplicate/static/KR15bOuXoo0u5QxZXmjcNbUJnoe.png new file mode 100644 index 000000000..e8f44ef8a Binary files /dev/null and b/docs/fr-FR/handbook/action-duplicate/static/KR15bOuXoo0u5QxZXmjcNbUJnoe.png differ diff --git a/docs/fr-FR/handbook/action-duplicate/static/Ox76b54eho4fTUxdk67cjcjenCc.png b/docs/fr-FR/handbook/action-duplicate/static/Ox76b54eho4fTUxdk67cjcjenCc.png new file mode 100644 index 000000000..f8b3c8950 Binary files /dev/null and b/docs/fr-FR/handbook/action-duplicate/static/Ox76b54eho4fTUxdk67cjcjenCc.png differ diff --git a/docs/fr-FR/handbook/action-duplicate/static/Pkf4bvn30oWEIjxrFmPc3d0lnPd.png b/docs/fr-FR/handbook/action-duplicate/static/Pkf4bvn30oWEIjxrFmPc3d0lnPd.png new file mode 100644 index 000000000..c237b712b Binary files /dev/null and b/docs/fr-FR/handbook/action-duplicate/static/Pkf4bvn30oWEIjxrFmPc3d0lnPd.png differ diff --git a/docs/fr-FR/handbook/action-duplicate/static/QqICbfLMMozpgBxYBpMcKuOKnmg.png b/docs/fr-FR/handbook/action-duplicate/static/QqICbfLMMozpgBxYBpMcKuOKnmg.png new file mode 100644 index 000000000..8038a1a90 Binary files /dev/null and b/docs/fr-FR/handbook/action-duplicate/static/QqICbfLMMozpgBxYBpMcKuOKnmg.png differ diff --git a/docs/fr-FR/handbook/action-duplicate/static/R3f2biRIdoEm7DxUO6Ec1abXnKc.gif b/docs/fr-FR/handbook/action-duplicate/static/R3f2biRIdoEm7DxUO6Ec1abXnKc.gif new file mode 100644 index 000000000..c31a4b050 Binary files /dev/null and b/docs/fr-FR/handbook/action-duplicate/static/R3f2biRIdoEm7DxUO6Ec1abXnKc.gif differ diff --git a/docs/fr-FR/handbook/action-duplicate/static/RZhIbo49lo2vV5xV5hZc0jkfn1d.png b/docs/fr-FR/handbook/action-duplicate/static/RZhIbo49lo2vV5xV5hZc0jkfn1d.png new file mode 100644 index 000000000..aef3d62f6 Binary files /dev/null and b/docs/fr-FR/handbook/action-duplicate/static/RZhIbo49lo2vV5xV5hZc0jkfn1d.png differ diff --git a/docs/fr-FR/handbook/action-duplicate/static/U9VCbG9I6ohTzQxzvPIc6oR3nid.png b/docs/fr-FR/handbook/action-duplicate/static/U9VCbG9I6ohTzQxzvPIc6oR3nid.png new file mode 100644 index 000000000..889475c16 Binary files /dev/null and b/docs/fr-FR/handbook/action-duplicate/static/U9VCbG9I6ohTzQxzvPIc6oR3nid.png differ diff --git a/docs/fr-FR/handbook/action-export-pro/index.md b/docs/fr-FR/handbook/action-export-pro/index.md new file mode 100644 index 000000000..4a6534a22 --- /dev/null +++ b/docs/fr-FR/handbook/action-export-pro/index.md @@ -0,0 +1,9 @@ +# Export Pro + + + +## Introduction + +:::warning +The plugin is currently under development. +::: \ No newline at end of file diff --git a/docs/fr-FR/handbook/action-export/index.md b/docs/fr-FR/handbook/action-export/index.md new file mode 100644 index 000000000..51ed077c4 --- /dev/null +++ b/docs/fr-FR/handbook/action-export/index.md @@ -0,0 +1,23 @@ +# Export + + + +## Introduction + +![20240426162728](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426162728.png) + +## Installation + +This plugin comes pre-installed, so no additional installation steps are required. + +## Operation Configuration Items + +![20240426163008](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426163008.png) + +### Exportable Fields + +- First Level: Displays all fields of the current collection. +- Second Level: If the field is a relational type, you'll need to select fields from the related table. +- Third Level: Only up to three levels of relationships are supported. Fields in the final relational level won't be shown. + +![20240426163433](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426163433.png) diff --git a/docs/fr-FR/handbook/action-import-pro/index.md b/docs/fr-FR/handbook/action-import-pro/index.md new file mode 100644 index 000000000..9b7f71c9c --- /dev/null +++ b/docs/fr-FR/handbook/action-import-pro/index.md @@ -0,0 +1,9 @@ +# Import Pro + + + +## Introduction + +:::warning +The plugin is currently under development. +::: \ No newline at end of file diff --git a/docs/fr-FR/handbook/action-import/index.md b/docs/fr-FR/handbook/action-import/index.md new file mode 100644 index 000000000..8199155f6 --- /dev/null +++ b/docs/fr-FR/handbook/action-import/index.md @@ -0,0 +1,215 @@ +# Import Data + +## Overview + +## Installation + +## Import Guidelines + +### Numeric Fields + +Numeric and percentage values are supported, while entries like `N/A` or `-` will be excluded. + +| Number 1 | Percentage | Number 2 | Number 3 | +| -------- | ---------- | -------- | -------- | +| 123 | 25% | N/A | - | + +After conversion to JSON: + +```ts +{ + "Number 1": 123, + "Percentage": 0.25, + "Number 2": null, + "Number 3": null, +} +``` + +### Boolean Fields + +The following text values are recognized (case-insensitive for English): + +- `Yes`, `Y`, `True`, `1`, `是` +- `No`, `N`, `False`, `0`, `否` + +| Field 1 | Field 2 | Field 3 | Field 4 | Field 5 | +| ------- | ------- | ------- | ------- | ------- | +| No | Yes | Y | true | 0 | + +After conversion to JSON: + +```ts +{ + "Field 1": false, + "Field 2": true, + "Field 3": true, + "Field 4": true, + "Field 5": false, +} +``` + +### Date Fields + +| DateOnly | Local (+08:00) | GMT | +| ------------------- | ------------------- | ------------------- | +| 2023-01-18 22:22:22 | 2023-01-18 22:22:22 | 2023-01-18 22:22:22 | + +After conversion to JSON: + +```ts +{ + "DateOnly": "2023-01-18T00:00:00.000Z", + "Local (+08:00)": "2023-01-18T14:22:22.000Z", + "GMT": "2023-01-18T22:22:22.000Z", +} +``` + +### Select Fields + +Option values and labels can be used interchangeably as input text. Multiple options can be separated by commas (`,` `,`) or by full-width commas ( `、`). + +For instance, if the `Priority` field has the following options: + +| Option Value | Option Label | +| ------------ | ------------ | +| low | Low | +| medium | Medium | +| high | High | + +Both the value and label can be used as input. + +| Priority | +| -------- | +| High | +| low | + +After conversion to JSON: + +```ts +[{ Priority: 'high' }, { Priority: 'low' }]; +``` + +### Chinese Administrative Region Fields + +| Region 1 | Region 2 | +| -------------- | -------------- | +| Beijing/City | Tianjin/City | + +After conversion to JSON: + +```ts +{ + "Region 1": ["11", "1101"], + "Region 2": ["12", "1201"] +} +``` + +### Attachment Fields + +| Attachment | +| ----------------------------------------- | +| https://www.nocobase.com/images/logo.png | + +After conversion to JSON: + +```ts +{ + "Attachment": [ + { + "filename": "logo.png", + "title": "logo.png", + "extname": ".png", + "url": "https://www.nocobase.com/images/logo.png" + } + ] +} +``` + +### Relationship Fields + +Multiple values can be separated by commas (`,` `,`) or full-width commas ( `、`). + +| Department/Name | Category/Title | +| --------------- | ---------------- | +| Development | Category 1, Category 2 | + +After conversion to JSON: + +```ts +{ + "Department": [1], // 1 is the record ID for the department named "Development" + "Category": [1, 2], // 1 and 2 are the record IDs for categories titled "Category 1" and "Category 2" +} +``` + +### JSON Fields + +| JSON1 | +| ------------------ | +| {"key":"value"} | + +After conversion to JSON: + +```ts +{ + "JSON": {"key":"value"} +} +``` + +### Map Geometry Fields + +| Point | Line | Polygon | Circle | +| ------ | ------------ | ----------------- | ------ | +| 1,2 | (1,2),(3,4) | (1,2),(3,4),(1,2) | 1,2,3 | + +After conversion to JSON: + +```ts +{ + "Point": [1,2], + "Line": [[1,2], [3,4]], + "Polygon": [[1,2], [3,4], [1,2]], + "Circle": [1,2,3] +} +``` + +## Custom Import Format + +You can register custom `ValueParser` methods through the `db.registerFieldValueParsers()` method. For example: + +```ts +import { BaseValueParser } from '@nocobase/database'; + +class PointValueParser extends BaseValueParser { + async setValue(value) { + if (Array isArray(value)) { + this.value = value; + } else if (typeof value was string) { + this.value = value.split(','); + } else { + this.errors.push('Value invalid'); + } + } +} + +const db = new Database(); + +// For fields of type=point, the data will be parsed using PointValueParser during import +db.registerFieldValueParsers({ + point: PointValueParser, +}); +``` + +### Example Import + +| Point | +| ----- | +| 1,2 | + +After conversion to JSON: + +```ts +{ + "Point": [1,2] +} +``` diff --git a/docs/fr-FR/handbook/action-print/index.md b/docs/fr-FR/handbook/action-print/index.md new file mode 100644 index 000000000..d743b8677 --- /dev/null +++ b/docs/fr-FR/handbook/action-print/index.md @@ -0,0 +1,13 @@ +# Print + + + +## Introduction + +The print button is a functional button in the details section. When clicked, it triggers the browser’s print function, allowing users to easily print the content to a physical document or other printing devices. + +## Installation + +This is a built-in plugin, no separate installation required. + +![20240426105637](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426105637.png) diff --git a/docs/fr-FR/handbook/action-qr-scan/index.md b/docs/fr-FR/handbook/action-qr-scan/index.md new file mode 100644 index 000000000..8a6b94fe8 --- /dev/null +++ b/docs/fr-FR/handbook/action-qr-scan/index.md @@ -0,0 +1,31 @@ +# Scan QR Code + +## Introduction + +The QR code scanning action can be added in the action panel block to facilitate navigation within the system. + +## Example + + + +## User Guide + +### Generate a QR Code + +1. Suppose the page link to redirect to is: `https://localhost:13000/m/page/vyoiwa25jig`. +2. Extract the relative link starting from `/page/` from the mobile page URL, and use it to generate a QR code. +3. Create a new Markdown block and use the following code: + +```markdown + +``` + +4. Add a "Scan QR Code" action to scan and navigate to the corresponding page. + +**Note**: +- The QR code scanning action only supports internal system relative links and must start with `/page/`. +- External page links are not supported at this time. + +For further details, check the [Action Panel Block](/handbook/block-action-panel) documentation. diff --git a/docs/fr-FR/handbook/api-doc/index.md b/docs/fr-FR/handbook/api-doc/index.md new file mode 100644 index 000000000..e6192a5ce --- /dev/null +++ b/docs/fr-FR/handbook/api-doc/index.md @@ -0,0 +1,51 @@ +# API Documentation + + + +## Introduction + +The plugin generates NocoBase HTTP API documentation based on Swagger. + +## Installation + +This is a built-in plugin, no installation required. Activate to use. + +## Usage Instructions + +### Accessing the API Documentation Page + +http://localhost:13000/admin/settings/api-doc/documentation + +![](https://static-docs.nocobase.com/8db51cf50e3c666aba5a850a0fb664a0.png) + +### Documentation Overview + +![](https://static-docs.nocobase.com/5bb4d3e5bba6c6fdfcd830592e72385b.png) + +- Total API Documentation: `/api/swagger:get` +- Core API Documentation: `/api/swagger:get?ns=core` +- All Plugins API Documentation: `/api/swagger:get?ns=plugins` +- Each Plugin's Documentation: `/api/swagger:get?ns=plugins/{name}` +- User Customized Collections API Documentation: `/api/swagger:get?ns=collections` +- Specified `${collection}` and related `${collection}.${association}` resources: `/api/swagger:get?ns=collections/{name}` + +## Developer Guide + +### How to Write Swagger Documentation for Plugins + +Add a `swagger/index.ts` file in the plugin's `src` folder with the following content: + +```typescript +export default { + info: { + title: 'NocoBase API - Auth plugin', + }, + tags: [], + paths: {}, + components: { + schemas: {}, + }, +}; +``` + +For detailed writing rules, please refer to the [Swagger Official Documentation](https://swagger.io/docs/specification/about/). \ No newline at end of file diff --git a/docs/fr-FR/handbook/api-doc/static/HYjubXpVOokLitxuC90cxSzHnJb.png b/docs/fr-FR/handbook/api-doc/static/HYjubXpVOokLitxuC90cxSzHnJb.png new file mode 100644 index 000000000..eddccb335 Binary files /dev/null and b/docs/fr-FR/handbook/api-doc/static/HYjubXpVOokLitxuC90cxSzHnJb.png differ diff --git a/docs/fr-FR/handbook/api-doc/static/NFhXbRvfgoP08QxpAwdclb17nfc.png b/docs/fr-FR/handbook/api-doc/static/NFhXbRvfgoP08QxpAwdclb17nfc.png new file mode 100644 index 000000000..869b047c9 Binary files /dev/null and b/docs/fr-FR/handbook/api-doc/static/NFhXbRvfgoP08QxpAwdclb17nfc.png differ diff --git a/docs/fr-FR/handbook/api-keys/image-1.png b/docs/fr-FR/handbook/api-keys/image-1.png new file mode 100644 index 000000000..d76a358b8 Binary files /dev/null and b/docs/fr-FR/handbook/api-keys/image-1.png differ diff --git a/docs/fr-FR/handbook/api-keys/image.png b/docs/fr-FR/handbook/api-keys/image.png new file mode 100644 index 000000000..d90cf25e4 Binary files /dev/null and b/docs/fr-FR/handbook/api-keys/image.png differ diff --git a/docs/fr-FR/handbook/api-keys/index.md b/docs/fr-FR/handbook/api-keys/index.md new file mode 100644 index 000000000..dc9ecd189 --- /dev/null +++ b/docs/fr-FR/handbook/api-keys/index.md @@ -0,0 +1,38 @@ +# API Key + +## Introduction + +## Installation + +## Usage Instructions + +http://localhost:13000/admin/settings/api-keys/configuration + +![](https://static-docs.nocobase.com/d64ccbdc8a512a0224e9f81dfe14a0a8.png) + +### Add API Key + +![](https://static-docs.nocobase.com/46141872fc0ad9a96fa5b14e97fcba12.png) + +**Notes** + +- The added API key is for the current user, and the role is the role to which the current user belongs +- Please make sure that the `APP_KEY` environment variable has been configured and is kept confidential. If the APP_KEY changes, all added API keys will become invalid. + +### How to configure APP_KEY + +For the docker version, modify the docker-compose.yml file + +```diff +services: + app: + image: nocobase/nocobase:main + environment: ++ - APP_KEY=4jAokvLKTJgM0v_JseUkJ +``` + +For the source code or create-nocobase-app installation, you can directly modify the APP_KEY in the .env file + +```bash +APP_KEY=4jAokvLKTJgM0v_JseUkJ +``` \ No newline at end of file diff --git a/docs/fr-FR/handbook/app-switching/index.md b/docs/fr-FR/handbook/app-switching/index.md new file mode 100644 index 000000000..7296c2b23 --- /dev/null +++ b/docs/fr-FR/handbook/app-switching/index.md @@ -0,0 +1,9 @@ +# App Switching + + + +## Introduction + +:::warning +The App Switching plugin is currently under development and has yet to be released. +::: diff --git a/docs/fr-FR/handbook/audit-logs/index.md b/docs/fr-FR/handbook/audit-logs/index.md new file mode 100644 index 000000000..78daafe7f --- /dev/null +++ b/docs/fr-FR/handbook/audit-logs/index.md @@ -0,0 +1,6 @@ +# Audit Log + +:::warning +Documentation to be added +::: + diff --git a/docs/fr-FR/handbook/auth-cas/index.md b/docs/fr-FR/handbook/auth-cas/index.md new file mode 100644 index 000000000..cd57cdab3 --- /dev/null +++ b/docs/fr-FR/handbook/auth-cas/index.md @@ -0,0 +1,35 @@ +# Auth: CAS + + + +## Introduction + +The Auth: CAS plugin follows the CAS (Central Authentication Service) protocol standard, allowing users to sign in to NocoBase using accounts provided by third-party identity authentication service providers (IdP). + +## Installation + +## User Manual + +### Activate Plugin + +![](https://static-docs.nocobase.com/469c48d9f2e8d41a088092c34ddb41f5.png) + +### Add CAS Authentication + +Visit the user authentication management page + +http://localhost:13000/admin/settings/auth/authenticators + +Add CAS authentication method + +![](https://static-docs.nocobase.com/a268500c5008d3b90e57ff1e2ea41aca.png) + +Configure CAS and activate + +![](https://static-docs.nocobase.com/2518b3fcc80d8a41391f3b629a510a02.png) + +### Visit the Sign in Page + +http://localhost:13000/signin + +![](https://static-docs.nocobase.com/49116aafbb2ed7218306f929ac8af967.png) diff --git a/docs/fr-FR/handbook/auth-cas/static/AGr7blmfHoef1kxKpDVc7JTnnlf.png b/docs/fr-FR/handbook/auth-cas/static/AGr7blmfHoef1kxKpDVc7JTnnlf.png new file mode 100644 index 000000000..74766a435 Binary files /dev/null and b/docs/fr-FR/handbook/auth-cas/static/AGr7blmfHoef1kxKpDVc7JTnnlf.png differ diff --git a/docs/fr-FR/handbook/auth-cas/static/OAYab64AWoL3jkxeLUDc3YBfnFs.png b/docs/fr-FR/handbook/auth-cas/static/OAYab64AWoL3jkxeLUDc3YBfnFs.png new file mode 100644 index 000000000..09ba5d7b2 Binary files /dev/null and b/docs/fr-FR/handbook/auth-cas/static/OAYab64AWoL3jkxeLUDc3YBfnFs.png differ diff --git a/docs/fr-FR/handbook/auth-cas/static/P3eDbyNhioPiJIxEIzWcfyTfnRe.png b/docs/fr-FR/handbook/auth-cas/static/P3eDbyNhioPiJIxEIzWcfyTfnRe.png new file mode 100644 index 000000000..36f5b556e Binary files /dev/null and b/docs/fr-FR/handbook/auth-cas/static/P3eDbyNhioPiJIxEIzWcfyTfnRe.png differ diff --git a/docs/fr-FR/handbook/auth-cas/static/XnzpbO09Vo5ha6xJfsTcifEunkh.png b/docs/fr-FR/handbook/auth-cas/static/XnzpbO09Vo5ha6xJfsTcifEunkh.png new file mode 100644 index 000000000..675375806 Binary files /dev/null and b/docs/fr-FR/handbook/auth-cas/static/XnzpbO09Vo5ha6xJfsTcifEunkh.png differ diff --git a/docs/fr-FR/handbook/auth-dingtalk/index.md b/docs/fr-FR/handbook/auth-dingtalk/index.md new file mode 100644 index 000000000..e1d66d57a --- /dev/null +++ b/docs/fr-FR/handbook/auth-dingtalk/index.md @@ -0,0 +1,55 @@ +# Auth: DingTalk + + + +## Introduction + +The **Auth: DingTalk** plugin enables users to log in to NocoBase using their DingTalk accounts, streamlining the login process. + +## Activating the Plugin + +![](https://static-docs.nocobase.com/202406120929356.png) + +## Applying for API Permissions in the DingTalk Developer Console + +Follow the steps outlined in the DingTalk Open Platform - Implement Login for Third-Party Websites guide to create your application. + +Once in the application management console, ensure you enable both "Personal Mobile Number Information" and "Address Book Personal Information Read Permissions." + +![](https://static-docs.nocobase.com/202406120006620.png) + +## Obtaining the Client Secret from the DingTalk Developer Console + +Copy your **Client ID** and **Client Secret** from the console. + +![](https://static-docs.nocobase.com/202406120000595.png) + +## Adding DingTalk Authentication to NocoBase + +Navigate to the **Authentication** plugin management page. + +![](https://static-docs.nocobase.com/202406112348051.png) + +Select **Add new - DingTalk** + +![](https://static-docs.nocobase.com/202406112349664.png) + +### Configuration + +![](https://static-docs.nocobase.com/202406120016896.png) + +- **Sign up automatically when the user does not exist** - When the phone number does not match an existing user, a new user is automatically created. +- **Client ID and Client Secret** - Enter the information you copied earlier. +- **Redirect URL** - Enter the callback URL, copy it, and proceed to the next step. + +## Configuring the Callback URL in the DingTalk Developer Console + +Paste the copied **Callback URL** into the appropriate field in the DingTalk Developer Console. + +![](https://static-docs.nocobase.com/202406120012221.png) + +## Login + +Go to the login page and click the button below the login form to initiate third-party login through DingTalk. + +![](https://static-docs.nocobase.com/202406120014539.png) diff --git a/docs/fr-FR/handbook/auth-ldap/index.md b/docs/fr-FR/handbook/auth-ldap/index.md new file mode 100644 index 000000000..cf62d45c8 --- /dev/null +++ b/docs/fr-FR/handbook/auth-ldap/index.md @@ -0,0 +1,55 @@ +# Auth: LDAP + + + +## Introduction + +The Auth: LDAP plugin follows the LDAP (Lightweight Directory Access Protocol) protocol standard, enabling users to sign in to NocoBase using their LDAP server credentials. + +## Activate plugin + + + +## Add LDAP Authentication + +Go to the authentication plugin settings page. + + + +Add - LDAP + + + +## Configuration + +### Basic Configuration + + + +- Sign up automatically when the user does not exist - Whether to automatically create a new user when no matching existing user is found. +- LDAP URL - LDAP server URL +- Bind DN - DN used to test server connection and search for users +- Bind password - Password of Bind DN +- Test connection - Click the button to test server connection and Bind DN authentication. + +### Search Configuration + + + +- Search DN - DN used to search for users +- Search filter - Filtering condition for searching users, using `{{account}}` to represent the user account used for login +- Scope - `Base`, `One level`, `Subtree`, default `Subtree` +- Size limit - Search page size + +### Attribute Mapping + + + +- Use this field to bind the user - Field used to bind existing users. If the login account is a username, choose username; if it is an email, choose email. Default is username. +- Attribute map - Mapping of user attributes to fields in the NocoBase user table. + +## Sign In + +Visit the sign in page and enter LDAP username and password in the sign in form. + + diff --git a/docs/fr-FR/handbook/auth-oidc/example/google.md b/docs/fr-FR/handbook/auth-oidc/example/google.md new file mode 100644 index 000000000..710d982ef --- /dev/null +++ b/docs/fr-FR/handbook/auth-oidc/example/google.md @@ -0,0 +1,21 @@ +# Sign in with Google + +> https://developers.google.com/identity/openid-connect/openid-connect + +## Get Google OAuth 2.0 Credentials + +[Google Cloud Console](https://console.cloud.google.com/apis/credentials) - Create Credentials - OAuth Client ID + +![](https://static-docs.nocobase.com/0f2946c8643565ecc4ac13249882638c.png) + +Go to the configuration interface and fill in the authorized redirect URL. The redirect URL can be obtained when adding an authenticator in Nocobase, usually it's `http(s)://host:port/api/oidc:redirect`. See the [User Manual - Configuration](../index.md#configuration) section. + +![](https://static-docs.nocobase.com/24078bf52ec966a16334894cb3d9d126.png) + +## Add a new Authenticator on NocoBase + +Plugin Settings - User Authentication - Add - OIDC + +![](https://static-docs.nocobase.com/0e4b1acdef6335aaee2139ae6629977b.png) + +Refer to the parameters introduced in [User Manual - Configuration](../index.md#configuration) to complete the authenticator configuration. \ No newline at end of file diff --git a/docs/fr-FR/handbook/auth-oidc/example/microsoft.md b/docs/fr-FR/handbook/auth-oidc/example/microsoft.md new file mode 100644 index 000000000..80bf30c4a --- /dev/null +++ b/docs/fr-FR/handbook/auth-oidc/example/microsoft.md @@ -0,0 +1,40 @@ +# MicroSoft Entra ID + +> https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app +> https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols-oidc + +## 在 NocoBase 上新增认证器 + +首先在 NocoBase 上新增一个认证器:插件设置 - 用户认证 - 添加 - OIDC. + +复制回调 URL. + +![](https://static-docs.nocobase.com/202412021504114.png) + +## 注册应用程序 + +打开 MicroSoft Entra 管理中心,注册一个新的应用程序。 + +![](https://static-docs.nocobase.com/202412021506837.png) + +此处填入刚才复制的回调 URL. + +![](https://static-docs.nocobase.com/202412021506380.png) + +## 获取并填写相应的信息 + +点击进入刚才注册的应用程序,在首页复制 **Application (client) ID** 和 **Directory (tenant) ID**. + +![](https://static-docs.nocobase.com/202412021509602.png) + +点击 Certificates & secrets, 创建一个新的客户端密钥 (Client secrets),并复制 **Value**. + +![](https://static-docs.nocobase.com/202412021512616.png) + +以上信息和 NocoBase 认证器配置的对应关系如下: + +| MicroSoft Entra 信息 | NocoBase 认证器配置 | +| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| Application (client) ID | Client ID | +| Client secrets - Value | Client secret | +| Directory (tenant) ID | Issuer:
    https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration, `{tenant}` 需要替换成相应的 Directory (tenant) ID | diff --git a/docs/fr-FR/handbook/auth-oidc/example/static/2023-12-03-17-20-14.png b/docs/fr-FR/handbook/auth-oidc/example/static/2023-12-03-17-20-14.png new file mode 100644 index 000000000..062e00894 Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/example/static/2023-12-03-17-20-14.png differ diff --git a/docs/fr-FR/handbook/auth-oidc/example/static/2023-12-03-17-23-18.png b/docs/fr-FR/handbook/auth-oidc/example/static/2023-12-03-17-23-18.png new file mode 100644 index 000000000..371893209 Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/example/static/2023-12-03-17-23-18.png differ diff --git a/docs/fr-FR/handbook/auth-oidc/example/static/2023-12-03-18-28-33.png b/docs/fr-FR/handbook/auth-oidc/example/static/2023-12-03-18-28-33.png new file mode 100644 index 000000000..a817b893a Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/example/static/2023-12-03-18-28-33.png differ diff --git a/docs/fr-FR/handbook/auth-oidc/index.md b/docs/fr-FR/handbook/auth-oidc/index.md new file mode 100644 index 000000000..9958384a5 --- /dev/null +++ b/docs/fr-FR/handbook/auth-oidc/index.md @@ -0,0 +1,77 @@ +# Auth: OIDC + + + +## Introduction + +The Auth: OIDC plugin follows the OIDC (Open ConnectID) protocol standard, using the Authorization Code Flow, to allow users to sign in to NocoBase using accounts provided by third-party identity authentication service providers (IdP). + +## Activate Plugin + +![](https://static-docs.nocobase.com/202411122358790.png) + +## Add OIDC Authentication + +Enter the user authentication plugin management page. + +![](https://static-docs.nocobase.com/202411130004459.png) + +Add - OIDC + +![](https://static-docs.nocobase.com/1efbde1c0e2f4967efc1c4336be45ca2.png) + +## Configuration + +### Basic Configuration + +![](https://static-docs.nocobase.com/202411130006341.png) + +| Configuration | Description | Version | +| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | --------------- | +| Sign up automatically when the user does not exist | Whether to automatically create a new user if no matching existing user is found. | - | +| Issuer | The issuer provided by the IdP, usually ending with `/.well-known/openid-configuration`. | - | +| Client ID | The Client ID | - | +| Client Secret | The Client Secret | - | +| scope | Optional, defaults to `openid email profile`. | - | +| id_token signed response algorithm | The signing algorithm for `id_token`, defaults to `RS256`. | - | +| Enable RP-initiated logout | Enables RP-initiated logout. Logs out the IdP session when the user logs out. The IdP logout callback should use the Post logout redirect URL provided in [Usage](#usage). | `v1.3.44-beta` | + +### Field Mapping + +| Configuration | Description | +| -------------------------------- | --------------------------------------------------------------------------------------------------------------- | +| Field Map | Field mapping. NocoBase supports mapping fields such as nickname, email, and phone number. The default nickname uses `openid`. | +| Use this field to bind the user | Used to match and bind with existing users. You can choose email or username, with email as the default. The IdP must provide `email` or `username` information. | + +### Advanced Configuration + +![](https://static-docs.nocobase.com/202411130013306.png) + +| Configuration | Description | Version | +| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | +| HTTP | Whether the NocoBase callback URL uses HTTP protocol, default is `https`. | - | +| Port | Port for the NocoBase callback URL, defaults to `443/80`. | - | +| State token | Used to verify the request source and prevent CSRF attacks. You can provide a fixed value, but **leaving it blank to generate random values by default is strongly recommended. If you use a fixed value, carefully evaluate your environment and security risks.** | - | +| Pass parameters in the authorization code grant exchange | Some IdPs may require passing Client ID or Client Secret as parameters when exchanging a code for a token. You can select this option and specify the corresponding parameter names. | - | +| Method to call the user info endpoint | The HTTP method used when requesting the user info API. | - | +| Where to put the access token when calling the user info endpoint | How the access token is passed when calling the user info API:
    - Header - In the request header (default).
    - Body - In the request body, used with `POST` method.
    - Query parameters - As query parameters, used with `GET` method. | - | +| Skip SSL verification | Skip SSL verification when requesting the IdP API. **This option exposes your system to risks of man-in-the-middle attacks. Only enable this option if you understand its purpose and implications. It is strongly discouraged in production environments.** | `v1.3.40-beta` | + +--- + +### Usage + +| Configuration | Description | +| ------------------------- | ----------------------------------------------------------------------------------------------- | +| Redirect URL | Used to configure the callback URL in the IdP. | +| Post logout redirect URL | Used to configure the Post logout redirect URL in the IdP when RP-initiated logout is enabled. | + +:::info +When testing locally, use `127.0.0.1` instead of `localhost` for the URL, as OIDC login requires writing state to the client cookie for security validation. If you see a flash of the login window but fail to log in successfully, check the server logs for state mismatch issues and ensure the state parameter is included in the request cookie. This issue often occurs when the state in the client cookie does not match the state in the request. +::: + +### Login + +Visit the login page and click the button below the login form to initiate third-party login. + +![](https://static-docs.nocobase.com/e493d156254c2ac0b6f6e1002e6a2e6b.png) diff --git a/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-18-22.png b/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-18-22.png new file mode 100644 index 000000000..00c7af990 Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-18-22.png differ diff --git a/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-19-33.png b/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-19-33.png new file mode 100644 index 000000000..b18c082b4 Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-19-33.png differ diff --git a/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-19-48.png b/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-19-48.png new file mode 100644 index 000000000..51493ba4d Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-19-48.png differ diff --git a/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-20-35.png b/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-20-35.png new file mode 100644 index 000000000..5ff8d62ea Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/static/2023-12-03-18-20-35.png differ diff --git a/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-40-02.png b/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-40-02.png new file mode 100644 index 000000000..1ad1a9fb1 Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-40-02.png differ diff --git a/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-41-56.png b/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-41-56.png new file mode 100644 index 000000000..6867e8567 Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-41-56.png differ diff --git a/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-42-44.png b/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-42-44.png new file mode 100644 index 000000000..18a403ea2 Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-42-44.png differ diff --git a/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-43-39.png b/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-43-39.png new file mode 100644 index 000000000..7d41418b0 Binary files /dev/null and b/docs/fr-FR/handbook/auth-oidc/static/2024-01-11-10-43-39.png differ diff --git a/docs/fr-FR/handbook/auth-saml/example/google.md b/docs/fr-FR/handbook/auth-saml/example/google.md new file mode 100644 index 000000000..ad51b719b --- /dev/null +++ b/docs/fr-FR/handbook/auth-saml/example/google.md @@ -0,0 +1,38 @@ +# Google Workspace + +## Set Google as IdP + +[Google Admin Console](https://admin.google.com/) - Apps - Web and mobile apps + +![](https://static-docs.nocobase.com/0812780b990a97a63c14ea8991959827.png) + +After setting up the app, copy the **SSO URL**, **Entity ID**, and **Certificate**. + +![](https://static-docs.nocobase.com/aafd20a794730e85411c0c8f368637e0.png) + +## Add a new Authenticator on NocoBase + +Plugin Settings - User Authentication - Add - SAML + +![](https://static-docs.nocobase.com/5bc18c7952b8f15828e26bb07251a335.png) + +Enter the copied information respectively: + +- SSO URL: SSO URL +- Public Certificate: Certificate +- idP Issuer: Entity ID +- http: Check if you are testing locally with http + +Then copy the SP Issuer/EntityID and ACS URL from Usage. + +## Fill in SP Information on Google + +Go back to the Google Console, on the **Service Provider Details** page, enter the ACS URL and Entity ID copied earlier, and check **Signed Response**. + +![](https://static-docs.nocobase.com/1536268bf8df4a5ebc72384317172191.png) + +![](https://static-docs.nocobase.com/c7de1f8b84c1335de110e5a7c96255c4.png) + +In the **Attribute Mapping** position, add mapping, you can map corresponding attributes. + +![](https://static-docs.nocobase.com/27180f2f46480c3fee3016df86d6fdb8.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-43-40.png b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-43-40.png new file mode 100644 index 000000000..072477707 Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-43-40.png differ diff --git a/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-53-20.png b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-53-20.png new file mode 100644 index 000000000..6ed94f840 Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-53-20.png differ diff --git a/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-57-33.png b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-57-33.png new file mode 100644 index 000000000..fb5d5fe6f Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-57-33.png differ diff --git a/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-58-06.png b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-58-06.png new file mode 100644 index 000000000..c73041321 Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-58-06.png differ diff --git a/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-59-27.png b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-59-27.png new file mode 100644 index 000000000..f7181e338 Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-17-59-27.png differ diff --git a/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-18-32-59.png b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-18-32-59.png new file mode 100644 index 000000000..122976753 Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/example/static/2023-12-03-18-32-59.png differ diff --git a/docs/fr-FR/handbook/auth-saml/index.md b/docs/fr-FR/handbook/auth-saml/index.md new file mode 100644 index 000000000..a169bec14 --- /dev/null +++ b/docs/fr-FR/handbook/auth-saml/index.md @@ -0,0 +1,56 @@ +# Auth: SAML 2.0 + + + +## Introduction + +The Auth: SAML 2.0 plugin follows the SAML 2.0 (Security Assertion Markup Language 2.0) protocol standard, allowing users to sign in to NocoBase using accounts provided by third-party identity authentication service providers (IdP). + +## Activate Plugin + +![](https://static-docs.nocobase.com/6a12f3d8073c47532a4f8aac900e4296.png) + +## Add SAML Authentication + +Enter the user authentication plugin management page. + +![](../auth-oidc/static/2023-12-03-18-19-33.png) + +Add - SAML + +![](https://static-docs.nocobase.com/5076fe56086b7799be308bbaf7c4425d.png) + +## Configuration + +![](https://static-docs.nocobase.com/976b66e589973c322d81dcddd22c6146.png) + +- SSO URL - Provided by IdP, used for single sign-on +- Public Certificate - Provided by IdP +- Entity ID (IdP Issuer) - Optional, provided by IdP +- http - If your NocoBase application is http protocol, please check +- Use this field to bind the user - The field used to match and bind with existing users, can choose email or username, default is email. The user information carried by IdP needs to contain the `email` or `username` field. +- Sign up automatically when the user does not exist - Whether to automatically create a new user when no matching existing user is found. +- Usage - `SP Issuer / EntityID` and `ACS URL` are used to copy and fill in the corresponding configuration in the IdP. + +## Field Mapping + +Field mapping needs to be configured on the IdP's configuration platform, you can refer to the [example](../auth-saml/example/google.md). + +The fields available for mapping in NocoBase are: + +- email (required) +- phone (only effective for platforms that support `phone` in scope, such as Alibaba Cloud, Lark) +- nickname +- username +- firstName +- lastName + +`nameID` is carried by the SAML protocol and does not need to be mapped, it will be saved as a unique user identifier. +The priority of the new user nickname use rule is: `nickname` > `firstName lastName` > `username` > `nameID` +Currently, user organization and role mapping are not supported. + +## Sign In + +Visit the sign in page and click the button under the sign in form to initiate third-party login. + +![](https://static-docs.nocobase.com/74963865c9d36a294948e6adeb5b24bc.png) diff --git a/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-29-18.png b/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-29-18.png new file mode 100644 index 000000000..8b57e2da0 Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-29-18.png differ diff --git a/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-29-45.png b/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-29-45.png new file mode 100644 index 000000000..f736ac2f8 Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-29-45.png differ diff --git a/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-30-08.png b/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-30-08.png new file mode 100644 index 000000000..12f903298 Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-30-08.png differ diff --git a/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-30-33.png b/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-30-33.png new file mode 100644 index 000000000..1460f97d9 Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-30-33.png differ diff --git a/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-32-21.png b/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-32-21.png new file mode 100644 index 000000000..122976753 Binary files /dev/null and b/docs/fr-FR/handbook/auth-saml/static/2023-12-03-18-32-21.png differ diff --git a/docs/fr-FR/handbook/auth-sms/index.md b/docs/fr-FR/handbook/auth-sms/index.md new file mode 100644 index 000000000..2c5772241 --- /dev/null +++ b/docs/fr-FR/handbook/auth-sms/index.md @@ -0,0 +1,31 @@ +# Auth: SMS + +## Introduction + +The SMS authentication plugin supports users to register through SMS and log in to NocoBase. + +> It needs to be used in conjunction with the SMS verification code function provided by the [`@nocobase/plugin-verification` plugin](../verification/) + +## Add SMS Authentication + +Enter the user authentication plugin management page. + +![](../auth-oidc/static/2023-12-03-18-19-33.png) + +Add - SMS + +![](https://static-docs.nocobase.com/29c8916492fd5e1564a872b31ad3ac0d.png) + +## Configuration + +![](https://static-docs.nocobase.com/a4d35ec63ba22ae2ea9e3e8e1cbb783d.png) + +For the configuration of the SMS verification code function, see the [Verification Plugin (@nocobase/plugin-verification) Documentation](../verification/index.md), the SMS login authentication function will use the configured and set default SMS verification code Provider to send SMS. + +Sign up automatically when the user does not exist: When this option is checked, when the user's mobile phone number does not exist, a new user will be registered using the mobile phone number as the nickname. + +## Log In + +Visit the login page to use. + +![](https://static-docs.nocobase.com/8d630739201bc27d8b0de076ab4f75e2.png) diff --git a/docs/fr-FR/handbook/auth-sms/static/2023-12-03-19-02-33.png b/docs/fr-FR/handbook/auth-sms/static/2023-12-03-19-02-33.png new file mode 100644 index 000000000..b5b41e7dc Binary files /dev/null and b/docs/fr-FR/handbook/auth-sms/static/2023-12-03-19-02-33.png differ diff --git a/docs/fr-FR/handbook/auth-sms/static/2023-12-03-19-04-34.png b/docs/fr-FR/handbook/auth-sms/static/2023-12-03-19-04-34.png new file mode 100644 index 000000000..b45ff98ae Binary files /dev/null and b/docs/fr-FR/handbook/auth-sms/static/2023-12-03-19-04-34.png differ diff --git a/docs/fr-FR/handbook/auth-sms/static/2023-12-03-19-06-26.png b/docs/fr-FR/handbook/auth-sms/static/2023-12-03-19-06-26.png new file mode 100644 index 000000000..cbe1b531a Binary files /dev/null and b/docs/fr-FR/handbook/auth-sms/static/2023-12-03-19-06-26.png differ diff --git a/docs/fr-FR/handbook/auth/dev/api.md b/docs/fr-FR/handbook/auth/dev/api.md new file mode 100644 index 000000000..9bd3f2ce9 --- /dev/null +++ b/docs/fr-FR/handbook/auth/dev/api.md @@ -0,0 +1,114 @@ +# API Reference + +## Server Side + +### Auth + +Kernel API, reference: [Auth](../../../api/auth/auth.md) + +### BaseAuth + +Kernel API, reference: [BaseAuth](../../../api/auth/base-auth.md) + +### AuthModel + +#### Overview + +`AuthModel` is the authenticator used in NocoBase applications (`Authenticator`, reference: [AuthManager - setStorer](../../../api/auth/auth-manager.md#setstorer) and [Auth - constructor](../../../api/auth/auth.md#constructor)) data model, providing some methods for interacting with the user data collection. In addition, methods provided by Sequelize Model can also be used. + +```ts +import { AuthModel } from '@nocobase/plugin-auth'; + +class CustomAuth extends BaseAuth { + async validate() { + // ... + const authenticator = this.authenticator as AuthModel; + this.authenticator.findUser(); + this.authenticator.newUser(); + this.authenticator.findOrCreateUser(); + // ... + } +} +``` + +#### Class Methods + +- `findUser(uuid: string): UserModel` - Query user by `uuid`. + + - `uuid` - User unique identifier from the current authentication type + +- `newUser(uuid: string, userValues?: any): UserModel` - Create a new user, bind the user to the current authenticator through `uuid`. + + - `uuid` - User unique identifier from the current authentication type + - `userValues` - Optional. Other user information. When not passed, `uuid` will be used as the user's nickname. + +- `findOrCreateUser(uuid: string, userValues?: any): UserModel` - Find or create a new user, the creation rule is the same as above. + - `uuid` - User unique identifier from the current authentication type + - `userValues` - Optional. Other user information. + +## Client Side + +### `plugin.registerType()` + +Register the client of the authentication type. + +```ts +import AuthPlugin from '@nocobase/plugin-auth/client'; + +class CustomAuthPlugin extends Plugin { + async load() { + const auth = this.app.pm.get(AuthPlugin); + auth.registerType('custom-auth-type', { + components: { + SignInForm, + // SignInButton + SignUpForm, + AdminSettingsForm, + }, + }); + } +} +``` + +#### Signature + +- `registerType(authType: string, options: AuthOptions)` + +#### Type + +```ts +export type AuthOptions = { + components: Partial<{ + SignInForm: ComponentType<{ authenticator: AuthenticatorType }>; + SignInButton: ComponentType<{ authenticator: AuthenticatorType }>; + SignUpForm: ComponentType<{ authenticatorName: string }>; + AdminSettingsForm: ComponentType; + }>; +}; +``` + +#### Details + +- `SignInForm` - Sign in form +- `SignInButton` - Sign in (third-party) button, can be used as an alternative to the sign-in form +- `SignUpForm` - Sign up form +- `AdminSettingsForm` - Admin configuration form + +### Route + +The frontend routes for registering the auth plugin are as follows: + +- Auth Layout + - name: `auth` + - path: `-` + - component: `AuthLayout` + +- SignIn Page + - name: `auth.signin` + - path: `/signin` + - component: `SignInPage` + +- SignUp Page + - name: `auth.signup` + - path: `/signup` + - component: `SignUpPage` diff --git a/docs/fr-FR/handbook/auth/dev/guide.md b/docs/fr-FR/handbook/auth/dev/guide.md new file mode 100644 index 000000000..bb57549a1 --- /dev/null +++ b/docs/fr-FR/handbook/auth/dev/guide.md @@ -0,0 +1,174 @@ +# Extend Authentication Type + +## Overview + +NocoBase supports extending user authentication types as needed. User authentication generally falls into two types: one is to determine user identity within the NocoBase application itself, such as password login, SMS login, etc.; the other is to have third-party services determine user identity and notify the NocoBase application of the result through callbacks, such as OIDC, SAML, and other authentication methods. The authentication process for these two different types of authentication methods in NocoBase is basically as follows: + +### No Third-party Callbacks are required + +1. The client uses the NocoBase SDK to call the login interface `api.auth.signIn()`, requesting the login interface `auth:signIn`, while carrying the current authenticator identifier through the request header `X-Authenticator` to the backend. +2. The `auth:signIn` interface forwards to the corresponding authentication type based on the authenticator identifier in the request header, and the `validate` method in the registered authentication class of that authentication type performs the corresponding logical processing. +3. The client retrieves user information and authentication token from the `auth:signIn` interface response, saves the token to Local Storage, and completes the login. This step is automatically handled internally by the SDK. + + + +### Dependent on Third-party Callbacks + +1. The client obtains the third-party login URL through its own registered interface (such as `auth:getAuthUrl`), and carries information such as the application name and authenticator identifier according to the protocol. +2. Redirect to the third-party URL to complete the login. The third-party service calls the callback interface of the NocoBase application (which needs to be registered by itself, such as `auth:redirect`), returns the authentication result, and returns information such as the application name and authenticator identifier. +3. In the callback interface method, parse the parameters to obtain the authenticator identifier, obtain the corresponding authentication class through `AuthManager`, and actively call the `auth.signIn()` method. The `auth.signIn()` method will call the `validate()` method to handle the authentication logic. +4. After the callback method obtains the authentication token, it redirects back to the frontend page with a 302 status code, and carries the `token` and authenticator identifier in the URL parameters, `?authenticator=xxx&token=yyy`. + + + +Next, we'll discuss how to register server-side interfaces and client-side user interfaces. + +## Server + +### Interface + +The NocoBase kernel provides registration and management for extending authentication types. The core logic processing of extending the login plugin requires inheriting the `Auth` abstract class of the kernel and implementing the corresponding standard interfaces. +For the complete API, see [Auth](../../../api/auth/auth.md). + +```typescript +import { Auth } from '@nocobase/auth'; + +class CustomAuth extends Auth { + set user(user) {} + get user() {} + + async check() {} + async signIn() {} +} +``` + +In most cases, the extended user authentication type can also use the existing JWT authentication logic to generate the credential for the user to access the API. The `BaseAuth` class in the kernel has done the basic implementation of the `Auth` abstract class, see [BaseAuth](../../../api/auth/base-auth.md). Plugins can directly inherit the `BaseAuth` class to reuse part of the logic code and reduce development costs. + +```javascript +import { BaseAuth } from '@nocobase/auth'; + +class CustomAuth extends BaseAuth { + constructor(config: AuthConfig) { + // Set user data table + const userCollection = config.ctx.db.getCollection('users'); + super({ ...config, userCollection }); + } + + // Implement user login logic + async validate() {} +} +``` + +### User Data + +In a NocoBase application, the related collections are defined by default as: + +| Collections | Description | Plugin | +| --------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | +| `users` | Store user information, such as email, nickname, and password | [User Plugin (`@nocobase/plugin-users`)](../../users/index.md) | +| `authenticators` | Store authenticator (authentication type entity) information, corresponding to authentication type and configuration | User Authentication Plugin (`@nocobase/plugin-auth`) | +| `usersAuthenticators` | Associates users and authenticators, saves user information under the corresponding authenticator | User Authentication Plugin (`@nocobase/plugin-auth`) | + +In general, extended login methods use `users` and `usersAuthenticators` to store corresponding user data. Only in special cases do you need to add a new Collection yourself. + +The main fields of `usersAuthenticators` are + +| Field | Description | +| --------------- | ------------------------------------------------------------------------------------------- | +| `uuid` | Unique identifier for this type of authentication, such as phone number, WeChat openid, etc | +| `meta` | JSON field, other information to be saved | +| `userId` | User ID | +| `authenticator` | Authenticator name (unique identifier) | + +For user query and creation operations, the `authenticators` data model `AuthModel` also encapsulates several methods that can be used in the `CustomAuth` class via `this.authenticator[methodName]`. For the complete API, see [AuthModel](../dev/api.md#authmodel). + +```ts +import { AuthModel } from '@nocobase/plugin-auth'; + +class CustomAuth extends BaseAuth { + async validate() { + // ... + const authenticator = this.authenticator as AuthModel; + this.authenticator.findUser(); // Query user + this.authenticator.newUser(); // Create new user + this.authenticator.findOrCreateUser(); // Query or create new user + // ... + } +} +``` + +### Authentication Type Registration + +The extended authentication method needs to be registered with the authentication management module. + +```javascript +class CustomAuthPlugin extends Plugin { + async load() { + this.app.authManager.registerTypes('custom-auth-type', { + auth: CustomAuth, + }); + } +} +``` + +## Client + +The client user interface is registered through the interface `registerType` provided by the user authentication plugin client: + +```ts +import AuthPlugin from '@nocobase/plugin-auth/client'; + +class CustomAuthPlugin extends Plugin { + async load() { + const auth = this.app.pm.get(AuthPlugin); + auth.registerType('custom-auth-type', { + components: { + SignInForm, // Sign in form + SignInButton, // Sign in (third party) button, can be either with the login form + SignUpForm, // Sign up form + AdminSettingsForm, // Backstage management form + }, + }); + } +} +``` + +### Sign In Form + +![](https://static-docs.nocobase.com/33afe18f229c3db45c7a1921c2c050b7.png) + +If multiple authenticators corresponding to the authentication type have registered login forms, they will be displayed in the form of Tabs. The Tab title is the title of the authenticator configured in the background. + +![](https://static-docs.nocobase.com/ada6d7add744be0c812359c23bf4c7fc.png) + +### Sign In Button + +![](https://static-docs.nocobase.com/e706f7785782adc77b0f4ee4faadfab8.png) + +Usually for third-party login buttons, but can actually be any component. + +### Sign Up Form + +![](https://static-docs.nocobase.com/f95c53431bf21ec312fcfd51923f0b42.png) + +If you need to jump from the login page to the sign up page, you need to handle it yourself in the login component. + +### Backend Management Form + +![](https://static-docs.nocobase.com/f4b544b5b0f5afee5621ad4abf66b24f.png) + +The top is the generic authenticator configuration, and the bottom is the part of the custom configuration form that can be registered. + +### Request APIs + +To initiate requests for user authentication-related interfaces on the client-side, you can use the SDK provided by NocoBase. + +```ts +import { useAPIClient } from '@nocobase/client'; + +// Use in component +const api = useAPIClient(); +api.auth.signIn(data, authenticator); +``` + +For detailed API references, see [@nocobase/sdk - Auth](../../../api/sdk/auth.md). diff --git a/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-08-49.png b/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-08-49.png new file mode 100644 index 000000000..5e9480e10 Binary files /dev/null and b/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-08-49.png differ diff --git a/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-12-45.png b/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-12-45.png new file mode 100644 index 000000000..94cb28e2b Binary files /dev/null and b/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-12-45.png differ diff --git a/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-17-07.png b/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-17-07.png new file mode 100644 index 000000000..33b86b927 Binary files /dev/null and b/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-17-07.png differ diff --git a/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-19-51.png b/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-19-51.png new file mode 100644 index 000000000..6db1aa6e7 Binary files /dev/null and b/docs/fr-FR/handbook/auth/dev/static/2023-12-20-12-19-51.png differ diff --git a/docs/fr-FR/handbook/auth/dev/static/2023-12-22-10-21-28.png b/docs/fr-FR/handbook/auth/dev/static/2023-12-22-10-21-28.png new file mode 100644 index 000000000..4912adf43 Binary files /dev/null and b/docs/fr-FR/handbook/auth/dev/static/2023-12-22-10-21-28.png differ diff --git a/docs/fr-FR/handbook/auth/index.md b/docs/fr-FR/handbook/auth/index.md new file mode 100644 index 000000000..62aecb052 --- /dev/null +++ b/docs/fr-FR/handbook/auth/index.md @@ -0,0 +1,19 @@ +# User Authentication + +## Introduction + +The user authentication module of NocoBase mainly consists of two parts: + +- The `@nocobase/auth` in the kernel defines login, registration, verification and other user authentication related expandable interfaces and middleware, and is also used for registering and managing various extended authentication methods. +- The `@nocobase/plugin-auth` in the plugin is used to initialize the authentication management module in the kernel, and also provides basic username (or email) / password authentication method. + +> It needs to be used in conjunction with the user management function provided by the [`@nocobase/plugin-users` plugin](../users/index.md) + +In addition, NocoBase also provides other various user authentication method plugins + +- [@nocobase/plugin-auth-sms](../auth-sms/index.md) - Provides SMS verification login function +- [@nocobase/plugin-auth-saml](../auth-saml/index.md) - Provides SAML SSO login function +- [@nocobase/plugin-auth-oidc](../auth-oidc/index.md) - Provides OIDC SSO login function +- [@nocobase/plugin-auth-cas](../auth-cas/index.md) - Provides CAS SSO login function + +Through the above plugins, after the administrator configures the corresponding authentication method, users can directly use the user identity provided by platforms such as Google Workspace, Microsoft Azure to log in to the system, and can also connect to Auth0, Logto, Keycloak and other platform tools. In addition, developers can also conveniently expand other authentication methods they need through the basic interfaces we provide. \ No newline at end of file diff --git a/docs/fr-FR/handbook/auth/user/index.md b/docs/fr-FR/handbook/auth/user/index.md new file mode 100644 index 000000000..53d776bb7 --- /dev/null +++ b/docs/fr-FR/handbook/auth/user/index.md @@ -0,0 +1,67 @@ +# User Manual + +## User Authentication Management + +When the user authentication plugin is installed, it will initialize an authentication method of `password`, based on the user's username and email. + +![](https://static-docs.nocobase.com/66eaa9d5421c9cb713b117366bd8a5d5.png) + +## Activate Authentication Type + +![](https://static-docs.nocobase.com/7f1fb8f8ca5de67ffc68eff0a65848f5.png) + +Only activated authentication types will be displayed on the login page + +![](https://static-docs.nocobase.com/8375a36ef98417af0f0977f1e07345dd.png) + +## User Authentication Types + +![](https://static-docs.nocobase.com/da4250c0cea343ebe470cbf7be4b12e4.png) + +The user authentication types currently supported by NocoBase are: + +- Password (Password), built-in user authentication plugin +- SMS (SMS), expanded by [sms-auth plugin](../../auth-sms/index.md) +- CAS, expanded by [cas-auth plugin](../../auth-cas/index.md) +- SAML, expanded by [saml-auth plugin](../../auth-saml/index.md) +- OIDC, expanded by [oidc-auth plugin](../../auth-oidc/index.md) + +In addition, you can also expand user authentication by yourself, refer to the [Developer's Guide](../dev/guide.md). + +## Password Authentication + +### Configuration Interface + +![](https://static-docs.nocobase.com/202411131505095.png) + +### Allow sign up + +When sign up is allowed, the login page will display the link to create an account, and you can go to the sign up page + +![](https://static-docs.nocobase.com/78903930d4b47aaf75cf94c55dd3596e.png) + +Sign up page + +![](https://static-docs.nocobase.com/ac3c3ab42df28cb7c6dc70b24e99e7f7.png) + +When sign up is not allowed, the login page will not display the link to create an account + +![](https://static-docs.nocobase.com/8d5e3b6df9991bfc1c2e095a93745121.png) + +When sign up is not allowed, the sign up page cannot be accessed + +![](https://static-docs.nocobase.com/09325c4b07e09f88f80a14dff8430556.png) + +### Sign up form Settings + +:::info +`v1.4.0-beta.7` and later versions supported. +::: + +You can set which fields in the user collection need to be displayed in the sign up form and whether they are required or not. At least one of username or email fields needs to be set to display and required. + +![](https://static-docs.nocobase.com/202411262133669.png) + +Sign up page + +![](https://static-docs.nocobase.com/202411262135801.png) diff --git a/docs/fr-FR/handbook/auth/user/static/EvrrbNVmUoJVczxJvkzclPKqn7e.png b/docs/fr-FR/handbook/auth/user/static/EvrrbNVmUoJVczxJvkzclPKqn7e.png new file mode 100644 index 000000000..4bbbf33a5 Binary files /dev/null and b/docs/fr-FR/handbook/auth/user/static/EvrrbNVmUoJVczxJvkzclPKqn7e.png differ diff --git a/docs/fr-FR/handbook/auth/user/static/GOJ0bwOYVoNkBKxkpmGcEqyqnI2.png b/docs/fr-FR/handbook/auth/user/static/GOJ0bwOYVoNkBKxkpmGcEqyqnI2.png new file mode 100644 index 000000000..17b7ca2a2 Binary files /dev/null and b/docs/fr-FR/handbook/auth/user/static/GOJ0bwOYVoNkBKxkpmGcEqyqnI2.png differ diff --git a/docs/fr-FR/handbook/auth/user/static/HYNZb9vvXo0GXuxpLCvcDTC5nfh.png b/docs/fr-FR/handbook/auth/user/static/HYNZb9vvXo0GXuxpLCvcDTC5nfh.png new file mode 100644 index 000000000..ae8df4ac9 Binary files /dev/null and b/docs/fr-FR/handbook/auth/user/static/HYNZb9vvXo0GXuxpLCvcDTC5nfh.png differ diff --git a/docs/fr-FR/handbook/auth/user/static/Kc72bM430oWacrxbxvScS3S3nGc.png b/docs/fr-FR/handbook/auth/user/static/Kc72bM430oWacrxbxvScS3S3nGc.png new file mode 100644 index 000000000..2f64684c0 Binary files /dev/null and b/docs/fr-FR/handbook/auth/user/static/Kc72bM430oWacrxbxvScS3S3nGc.png differ diff --git a/docs/fr-FR/handbook/auth/user/static/NsBebeTkAoDSnExFStmc84iondd.png b/docs/fr-FR/handbook/auth/user/static/NsBebeTkAoDSnExFStmc84iondd.png new file mode 100644 index 000000000..d7b11e602 Binary files /dev/null and b/docs/fr-FR/handbook/auth/user/static/NsBebeTkAoDSnExFStmc84iondd.png differ diff --git a/docs/fr-FR/handbook/auth/user/static/OyOHbaKJyogTBXxhW5wcO3QEn0e.png b/docs/fr-FR/handbook/auth/user/static/OyOHbaKJyogTBXxhW5wcO3QEn0e.png new file mode 100644 index 000000000..a33d56094 Binary files /dev/null and b/docs/fr-FR/handbook/auth/user/static/OyOHbaKJyogTBXxhW5wcO3QEn0e.png differ diff --git a/docs/fr-FR/handbook/auth/user/static/Rs2obD3ZRohmtjxlQxPcT123n7e.png b/docs/fr-FR/handbook/auth/user/static/Rs2obD3ZRohmtjxlQxPcT123n7e.png new file mode 100644 index 000000000..ac96e10d4 Binary files /dev/null and b/docs/fr-FR/handbook/auth/user/static/Rs2obD3ZRohmtjxlQxPcT123n7e.png differ diff --git a/docs/fr-FR/handbook/auth/user/static/Ut6KbpRe0oI1NoxHkbZcXftkndc.png b/docs/fr-FR/handbook/auth/user/static/Ut6KbpRe0oI1NoxHkbZcXftkndc.png new file mode 100644 index 000000000..04bc724ed Binary files /dev/null and b/docs/fr-FR/handbook/auth/user/static/Ut6KbpRe0oI1NoxHkbZcXftkndc.png differ diff --git a/docs/fr-FR/handbook/auth/user/static/UulRbfMpWogGHnxpk1Yc0asenFe.png b/docs/fr-FR/handbook/auth/user/static/UulRbfMpWogGHnxpk1Yc0asenFe.png new file mode 100644 index 000000000..9738d3045 Binary files /dev/null and b/docs/fr-FR/handbook/auth/user/static/UulRbfMpWogGHnxpk1Yc0asenFe.png differ diff --git a/docs/fr-FR/handbook/backup-restore/image-1.png b/docs/fr-FR/handbook/backup-restore/image-1.png new file mode 100644 index 000000000..942dc9a06 Binary files /dev/null and b/docs/fr-FR/handbook/backup-restore/image-1.png differ diff --git a/docs/fr-FR/handbook/backup-restore/image-2.png b/docs/fr-FR/handbook/backup-restore/image-2.png new file mode 100644 index 000000000..bc809d2df Binary files /dev/null and b/docs/fr-FR/handbook/backup-restore/image-2.png differ diff --git a/docs/fr-FR/handbook/backup-restore/image-3.png b/docs/fr-FR/handbook/backup-restore/image-3.png new file mode 100644 index 000000000..9494982c9 Binary files /dev/null and b/docs/fr-FR/handbook/backup-restore/image-3.png differ diff --git a/docs/fr-FR/handbook/backup-restore/image-4.png b/docs/fr-FR/handbook/backup-restore/image-4.png new file mode 100644 index 000000000..1c1c14047 Binary files /dev/null and b/docs/fr-FR/handbook/backup-restore/image-4.png differ diff --git a/docs/fr-FR/handbook/backup-restore/image-5.png b/docs/fr-FR/handbook/backup-restore/image-5.png new file mode 100644 index 000000000..ca9d37c3e Binary files /dev/null and b/docs/fr-FR/handbook/backup-restore/image-5.png differ diff --git a/docs/fr-FR/handbook/backup-restore/image-6.png b/docs/fr-FR/handbook/backup-restore/image-6.png new file mode 100644 index 000000000..ecec16573 Binary files /dev/null and b/docs/fr-FR/handbook/backup-restore/image-6.png differ diff --git a/docs/fr-FR/handbook/backup-restore/image.png b/docs/fr-FR/handbook/backup-restore/image.png new file mode 100644 index 000000000..e000b3027 Binary files /dev/null and b/docs/fr-FR/handbook/backup-restore/image.png differ diff --git a/docs/fr-FR/handbook/backup-restore/index.md b/docs/fr-FR/handbook/backup-restore/index.md new file mode 100644 index 000000000..defa0faa7 --- /dev/null +++ b/docs/fr-FR/handbook/backup-restore/index.md @@ -0,0 +1,51 @@ +# Backup and Restore + + + +## Introduction + +The backup and restore plugin can be used for scenarios such as application replication, migration, and upgrade. + +## Installation + +This plugin is built-in and does not require manual installation or activation. + +## User Instructions + +![Backup and Restore List Page](https://static-docs.nocobase.com/071b969c4db9bdc6d2c359e1b6bef5da.png) + +### Creating a Backup + +![Creating Backup](https://static-docs.nocobase.com/0e3d9410e6b1cfbda38044033f0b4053.png) + +### Restore Backup + +You can choose to upload a backup from your local device or click on a backup file to restore. + +![Restore Backup](https://static-docs.nocobase.com/e4b95a4376260fd516de7828fd9f1056.png) + +Select the data you need to restore, the selected data will completely overwrite the corresponding data table of the target application. + +![Restore Backup](https://static-docs.nocobase.com/9c7cb78b51c8f949e417b5a1e0180ae2.png) + +### Backup Instructions + +Click on "Learn more" to view the backup instructions. + +![Backup and Restore Instructions](https://static-docs.nocobase.com/4f54eba0fde2d6481274665cb184a79e.png) + +Backup Instructions + +![Backup and Restore Instructions](https://static-docs.nocobase.com/bd5c68cf7e35d04e525f9b13e48e32d9.png) + +Backup Groups + +- Required Data: Essential data for system operation. +- Skipped Data: Data skipped and not backed up. +- User Data: Data related to users. +- Log Data: Data used to record some actions log. +- Third-party Service Information: Generally information about various service providers, such as file storage services, map services, and SMS service provider configuration information, etc. +- Custom Collection Data: Data of collections added through the collection manager. +- Unknown Data: Data without configured backup rules. + +Note: You can choose the data you want to back up or restore by group. The selected data will completely overwrite when restoring. diff --git a/docs/fr-FR/handbook/backups/index.md b/docs/fr-FR/handbook/backups/index.md new file mode 100644 index 000000000..9c75c1641 --- /dev/null +++ b/docs/fr-FR/handbook/backups/index.md @@ -0,0 +1,87 @@ +# Backups Manager + + + +## Introduction + +The NocoBase backup manager plugin provides features for fully backing up of the NocoBase database and user uploaded files, including backup's scheduling, downloading, deleting, and restoring operation. + +## Installation + +This plugin is built into the NocoBase Professional Edition and does not require manual installation. Please refer to the commercial version for more details. + +:::warning{title="Attention"} + +- This plugin is based on the native database client. Before using it, the corresponding database client must be installed in the NocoBase server environment. + - [PostgreSQL client installation](./installation/postgres.md) + - [MySQL client installation](./installation/mysql.md) + - [MariaDB client installation](./installation/mariadb.md) +- During the restore operation, the version of the target database should not be lower than the version of the database that created the backup. + ::: + +## Usage Instructions + +![Main Interface](./static/main-screen.png) + +### Create New Backup + +Click the "New backup" button to create a new backup based on the backup configuration and display the backup status in the backup list. +![Create New Backup](./static/new-backup.png) + +### Restore Backup + +Supports restoring backups from the backup list or uploading local backup files to restore backups. +Restore operations are not allowed in the following scenarios: + +- When the current NocoBase version is lower than the NocoBase version in the backup file. +- When the current NocoBase database is inconsistent with the following configurations in the backup file: + - dialect + - underscored + - table prefix + - schema +- When the `Tolerant mode` is not enabled, and the database version when creating the backup is higher than the current application database version. + +> **Restore is a full database operation. It is recommended to back up the current database before restoring a backup.** + +#### Restore from the backup list + +Click the "Restore" button of the backup item in the backup list, enter the backup file encryption password in the pop-up window, and click "Confirm" to restore the backup. + +> Leave password empty for unencrypted backup. + +> If you need to restore the backup to a lower version of the database, you need to enable the tolerant mode. + +![Restore Backup](./static/restore-backup.png) + +#### Restore from local backup file + +Click the `Restore from local backup` button, select the local backup file in the pop-up window, enter the backup file encryption password, and click "Confirm" to restore the backup. + +> Leave password empty for unencrypted backup. + +> If you need to restore the backup to a lower version of the database, you need to enable the tolerant mode. + +![Restore from Local Backup](./static/restore-from-local.png) + +#### Download Backup File + +Click the `Download` button of the backup item in the backup list to download the backup file. + +#### Delete Backup + +Click the `Delete` button of the backup item in the backup list to delete the backup file. + +## Backup Settings + +Switch to the "Settings" tab, modify the backup settings, and click `Save` to take effect. +![Backup Settings](./static/backup-settings.png) + +### Backup Settings Description + +- `Automatic backup`: When enable `Run automatic backup on the cron schedule`, you can set automatic backups at specified times. +- `Maximum number of backups`: Set the maximum number of locally saved backup files. After exceeding the number, the earliest backup files will be automatically deleted. +- `Sync backup to cloud storage`: Set the cloud storage location where the backup files are automatically uploaded after successful backup, only support cloud storage. +- `Backup local storage files`: Whether to include files uploaded by users to the server's local storage (storage/uploads) in the backup. +- `Restore password`: If a restore password is set, it must be entered when restoring the backup. + +> **Please keep the restore password safe. Forgetting the password will make it impossible to restore the backup file.** diff --git a/docs/fr-FR/handbook/backups/installation/mariadb.md b/docs/fr-FR/handbook/backups/installation/mariadb.md new file mode 100644 index 000000000..f5c767bb4 --- /dev/null +++ b/docs/fr-FR/handbook/backups/installation/mariadb.md @@ -0,0 +1,94 @@ +# MariaDB Client Installation + +## Docker Installation + +### Enter the directory where the NocoBase Dockerfile is located and create a Dockerfile file + +```Dockerfile +# Based on the next version +FROM registry.cn-shanghai.aliyuncs.com/nocobase/nocobase:next + +# run installation script, choose the latest version of mysql +RUN apt-get update && apt-get install -y wget && \ + wget https://downloads.mysql.com/archives/get/p/23/file/mysql-community-client-core_8.1.0-1debian11_amd64.deb && \ + dpkg -x mysql-community-client-core_8.1.0-1debian11_amd64.deb /tmp/mysql-client && \ + cp /tmp/mysql-client/usr/bin/mysqldump /usr/bin/ &&\ + cp /tmp/mysql-client/usr/bin/mysql /usr/bin/ + ``` + +### Modify the docker-compose.yml file of NocoBase + +```diff +version: "3" + +networks: + nocobase: + driver: bridge + +services: + app: +- image: nocobase/nocobase:latest ++ build: ++ dockerfile: Dockerfile + networks: + - nocobase + depends_on: + - mariadb + environment: + # The application's secret key, used to generate user tokens, etc. + # If APP_KEY is changed, old tokens will also become invalid. + # It can be any random string, and make sure it is not exposed. + - APP_KEY=your-secret-key + # Database type, supports postgres, mysql, mariadb + - DB_DIALECT=mariadb + # Database host, can be replaced with the IP of an existing database server + - DB_HOST=mariadb + # Database name + - DB_DATABASE=nocobase + # Database user + - DB_USER=root + # Database password + - DB_PASSWORD=nocobase + # Whether to convert table and field names to snake case + - DB_UNDERSCORED=true + # Timezone + - TZ=Asia/Shanghai + volumes: + - ./storage:/app/nocobase/storage + ports: + - "13000:80" + # init: true + + # If using an existing database server, mariadb service can be omitted + mariadb: + image: mariadb:11 + environment: + MYSQL_DATABASE: nocobase + MYSQL_USER: nocobase + MYSQL_PASSWORD: nocobase + MYSQL_ROOT_PASSWORD: nocobase + restart: always + volumes: + - ./storage/db/mariadb:/var/lib/mysql + networks: + - nocobase +``` + +### Upgrade + +Previously, you would pull a new image for each update. Now, you need to build a new image for each update. + +```diff +# Pull the latest image +- docker-compose pull app +# Rebuild the app container ++ docker-compose build app --pull +# Start the app +docker-compose up -d app +# Check app logs +docker-compose logs app +``` + +## Other Installation Methods +If your NocoBase was installed with [create-nocobase-app](/welcome/getting-started/installation/create-nocobase-app) or [Git source code](/welcome/getting-started/installation/git-clone), please check the below MySQL official release page, and follow the official installation guide. +- Last versions: https://dev.mysql.com/downloads/mysql/ \ No newline at end of file diff --git a/docs/fr-FR/handbook/backups/installation/mysql.md b/docs/fr-FR/handbook/backups/installation/mysql.md new file mode 100644 index 000000000..c3c889c47 --- /dev/null +++ b/docs/fr-FR/handbook/backups/installation/mysql.md @@ -0,0 +1,95 @@ +# MySQL Client Installation + +## Docker Installation + +### Enter the directory where the NocoBase Dockerfile is located and create a Dockerfile file + +```Dockerfile +# Based on the next version +FROM registry.cn-shanghai.aliyuncs.com/nocobase/nocobase:next + +# run installation script, please replace the corresponding MySQL version link according to the actual situation +RUN apt-get update && apt-get install -y wget && \ + wget https://downloads.mysql.com/archives/get/p/23/file/mysql-community-client-core_8.1.0-1debian11_amd64.deb && \ + dpkg -x mysql-community-client-core_8.1.0-1debian11_amd64.deb /tmp/mysql-client && \ + cp /tmp/mysql-client/usr/bin/mysqldump /usr/bin/ &&\ + cp /tmp/mysql-client/usr/bin/mysql /usr/bin/ + ``` + +### Modify the docker-compose.yml file of NocoBase + +```diff +version: "3" + +networks: + nocobase: + driver: bridge + +services: + app: +- image: nocobase/nocobase:latest ++ build: ++ dockerfile: Dockerfile + networks: + - nocobase + depends_on: + - mysql + environment: + # The application's secret key, used to generate user tokens, etc. + # If APP_KEY is changed, old tokens will also become invalid. + # It can be any random string, and make sure it is not exposed. + - APP_KEY=your-secret-key + # Database type, supports postgres, mysql, mariadb + - DB_DIALECT=mysql + # Database host, can be replaced with the IP of an existing database server + - DB_HOST=mysql + # Database name + - DB_DATABASE=nocobase + # Database user + - DB_USER=root + # Database password + - DB_PASSWORD=nocobase + # Whether to convert table and field names to snake case + - DB_UNDERSCORED=true + # Timezone + - TZ=Asia/Shanghai + volumes: + - ./storage:/app/nocobase/storage + ports: + - "13000:80" + # init: true + + # If using an existing database server, mysql service can be omitted + mysql: + image: mysql:8 + environment: + MYSQL_DATABASE: nocobase + MYSQL_USER: nocobase + MYSQL_PASSWORD: nocobase + MYSQL_ROOT_PASSWORD: nocobase + restart: always + volumes: + - ./storage/db/mysql:/var/lib/mysql + networks: + - nocobase +``` + +### Upgrade + +Previously, you would pull a new image for each update. Now, you need to build a new image for each update. + +```diff +# Pull the latest image +- docker-compose pull app +# Rebuild the app container ++ docker-compose build app --pull +# Start the app +docker-compose up -d app +# Check app logs +docker-compose logs app +``` + +## Other Installation Methods +If your NocoBase was installed with [create-nocobase-app](/welcome/getting-started/installation/create-nocobase-app) or [Git source code](/welcome/getting-started/installation/git-clone), please check the below MySQL official release page, choose the appropriate MySQL version, and follow the official installation guide. +- History versions: https://downloads.mysql.com/archives/community/ +- Last versions: https://dev.mysql.com/downloads/mysql/ \ No newline at end of file diff --git a/docs/fr-FR/handbook/backups/installation/postgres.md b/docs/fr-FR/handbook/backups/installation/postgres.md new file mode 100644 index 000000000..6fdbc1bcb --- /dev/null +++ b/docs/fr-FR/handbook/backups/installation/postgres.md @@ -0,0 +1,92 @@ +# Postgres Client Installation + +## Docker Installation + +### Enter the directory where the NocoBase Dockerfile is located and create a Dockerfile file + +```Dockerfile +# Based on the next version +FROM registry.cn-shanghai.aliyuncs.com/nocobase/nocobase:next + +# Specify the desired PostgreSQL version, here we use version 16 as an example +ARG PG_VERSION=16 + +# Run installation script +RUN apt update && apt install -y postgresql-common gnupg \ + && /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y \ + && apt install -y postgresql-client-${PG_VERSION} +``` + +### Modify the docker-compose.yml file of NocoBase + +```diff +version: "3" + +networks: + nocobase: + driver: bridge + +services: + app: +- image: registry.cn-shanghai.aliyuncs.com/nocobase/nocobase:next ++ build: ++ dockerfile: Dockerfile + networks: + - nocobase + depends_on: + - postgres + environment: + # The application's secret key, used to generate user tokens, etc. + # If APP_KEY is changed, old tokens will also become invalid. + # It can be any random string, and make sure it is not exposed. + - APP_KEY=your-secret-key + # Database type, supports postgres, mysql, mariadb + - DB_DIALECT=postgres + # Database host, can be replaced with the IP of an existing database server + - DB_HOST=postgres + # Database name + - DB_DATABASE=nocobase + # Database user + - DB_USER=nocobase + # Database password + - DB_PASSWORD=nocobase + # Timezone + - TZ=Asia/Shanghai + volumes: + - ./storage:/app/nocobase/storage + ports: + - "13000:80" + # init: true + + # If using an existing database server, postgres service can be omitted + postgres: + image: postgres:16 + restart: always + command: postgres -c wal_level=logical + environment: + POSTGRES_USER: nocobase + POSTGRES_DB: nocobase + POSTGRES_PASSWORD: nocobase + volumes: + - ./storage/db/postgres:/var/lib/postgresql/data + networks: + - nocobase +``` + +### Upgrade + +Previously, you would pull a new image for each update. Now, you need to build a new image for each update. + +```diff +# Pull the latest image +- docker-compose pull app +# Rebuild the app container ++ docker-compose build app --pull +# Start the app +docker-compose up -d app +# Check app logs +docker-compose logs app +``` + +## Other Installation Methods +If your NocoBase was installed with [create-nocobase-app](/welcome/getting-started/installation/create-nocobase-app) or [Git source code](/welcome/getting-started/installation/git-clone), please check https://www.postgresql.org/download/, choose the appropriate PostgreSQL version, and follow the official installation guide. \ No newline at end of file diff --git a/docs/fr-FR/handbook/backups/static/backup-settings.png b/docs/fr-FR/handbook/backups/static/backup-settings.png new file mode 100644 index 000000000..4642a3455 Binary files /dev/null and b/docs/fr-FR/handbook/backups/static/backup-settings.png differ diff --git a/docs/fr-FR/handbook/backups/static/main-screen.png b/docs/fr-FR/handbook/backups/static/main-screen.png new file mode 100644 index 000000000..b696f854e Binary files /dev/null and b/docs/fr-FR/handbook/backups/static/main-screen.png differ diff --git a/docs/fr-FR/handbook/backups/static/new-backup.png b/docs/fr-FR/handbook/backups/static/new-backup.png new file mode 100644 index 000000000..5b3df8e50 Binary files /dev/null and b/docs/fr-FR/handbook/backups/static/new-backup.png differ diff --git a/docs/fr-FR/handbook/backups/static/restore-backup.png b/docs/fr-FR/handbook/backups/static/restore-backup.png new file mode 100644 index 000000000..e87d4c277 Binary files /dev/null and b/docs/fr-FR/handbook/backups/static/restore-backup.png differ diff --git a/docs/fr-FR/handbook/backups/static/restore-from-local.png b/docs/fr-FR/handbook/backups/static/restore-from-local.png new file mode 100644 index 000000000..c8af1ed06 Binary files /dev/null and b/docs/fr-FR/handbook/backups/static/restore-from-local.png differ diff --git a/docs/fr-FR/handbook/block-action-panel/index.md b/docs/fr-FR/handbook/block-action-panel/index.md new file mode 100644 index 000000000..8ad31780b --- /dev/null +++ b/docs/fr-FR/handbook/block-action-panel/index.md @@ -0,0 +1,42 @@ +# Block: Action Panel + +## Introduction + +It is used for placing various quick actions. Currently, it supports + +- [link](/handbook/ui/actions/types/link) +- [Scan QR code](/handbook/action-qr-scan) +- [Popup action](/handbook/action-popup) +- [Custom request](/handbook/action-custom-request) + +![20240612213229](https://static-docs.nocobase.com/20240612213229.png) + +## Action Types + +The action panel supports the following action types: + +### Link + + + +### Scan QR Code + + + +### Popup + +Consistent with the configured blocks on the page + + + +### Custom request + + diff --git a/docs/fr-FR/handbook/block-gantt/index.md b/docs/fr-FR/handbook/block-gantt/index.md new file mode 100644 index 000000000..48e31e69c --- /dev/null +++ b/docs/fr-FR/handbook/block-gantt/index.md @@ -0,0 +1,72 @@ +# Block Gantt + + + +## Introduction + +The Gantt chart block displays data in the form of a timeline, making it ideal for project management, event planning, engineering schedules, and task scheduling. + +## Installation + +It's a built-in plugin, no installation is required. + +## Adding a Block + +![](https://static-docs.nocobase.com/f064f8fadf52947c990f5dad97736f98.png) + +![](https://static-docs.nocobase.com/858112f44bc543973b6e5b03856a6360.png) + +- **Title Field**: Displays the information directly on the Gantt chart bars +- **Time Scale**: Sets the time scale, with the default level being days +- **Start Date Field**: Defines the start date for each task (required) +- **End Date Field**: Defines the end date for each task (required) +- **Progress Field**: Indicates the progress of a task (optional percentage field) +## Usage Instructions + +![](https://static-docs.nocobase.com/fff6fe1e1fe0a88d20f80b3bb7233608.gif) + +- Hover over a task to see a floating card that displays task duration and progress. +- Drag the task to adjust the start and end dates. +- Drag the progress bar to adjust task progress. + +## Block Configuration Options + +![20240419211301](https://static-docs.nocobase.com/20240419211301.png) + +### Set Data Range + +![20240419211033](https://static-docs.nocobase.com/20240419211033.png) + +For more details, refer to [Setting Data Range](/handbook/ui/blocks/block-settings/data-scope). + +- [Save as Block Template](/handbook/ui/blocks/block-settings/block-template) +- [Set Data Loading Mode](/handbook/ui/blocks/block-settings/loading-mode) + +## Action Configuration + +### Global Actions + +![20240419213653](https://static-docs.nocobase.com/20240419213653.png) + +- [Filter](/handbook/ui/actions/types/filter) +- [Add New](/handbook/ui/actions/types/add-new) +- [Delete](/handbook/ui/actions/types/delete) +- [Refresh](/handbook/ui/actions/types/refresh) +- [Import](/handbook/action-import) +- [Export](/handbook/action-export) +- [Add Record](/handbook/action-add-record) +- [Bulk Update](/handbook/action-bulk-update) +- [Bulk Edit](/handbook/action-bulk-edit) + +### Row Actions + +![20240419213823](https://static-docs.nocobase.com/20240419213823.png) + +- [View](/handbook/ui/actions/types/view) +- [Edit](/handbook/ui/actions/types/edit) +- [Duplicate](/handbook/action-duplicate) +- [Delete](/handbook/ui/actions/types/delete) +- [Pop-Up](/handbook/ui/actions/types/pop-up) +- [Update Record](/handbook/ui/actions/types/update-record) +- [Custom Request](/handbook/action-custom-request) +- [Trigger Workflow](/handbook/workflow/manual/triggers/custom-action) diff --git a/docs/fr-FR/handbook/block-gantt/static/BRIcbgJ8Do7SQ5xHshUcHVjdnMc.gif b/docs/fr-FR/handbook/block-gantt/static/BRIcbgJ8Do7SQ5xHshUcHVjdnMc.gif new file mode 100644 index 000000000..6a089df1c Binary files /dev/null and b/docs/fr-FR/handbook/block-gantt/static/BRIcbgJ8Do7SQ5xHshUcHVjdnMc.gif differ diff --git a/docs/fr-FR/handbook/block-gantt/static/LcyebGwVVoEBdvx4ZDicXOj1n8f.png b/docs/fr-FR/handbook/block-gantt/static/LcyebGwVVoEBdvx4ZDicXOj1n8f.png new file mode 100644 index 000000000..68c6937ec Binary files /dev/null and b/docs/fr-FR/handbook/block-gantt/static/LcyebGwVVoEBdvx4ZDicXOj1n8f.png differ diff --git a/docs/fr-FR/handbook/block-gantt/static/MDvAbz30ooHoiQxkqRYcDGG1npb.gif b/docs/fr-FR/handbook/block-gantt/static/MDvAbz30ooHoiQxkqRYcDGG1npb.gif new file mode 100644 index 000000000..fdb878a91 Binary files /dev/null and b/docs/fr-FR/handbook/block-gantt/static/MDvAbz30ooHoiQxkqRYcDGG1npb.gif differ diff --git a/docs/fr-FR/handbook/block-gantt/static/P3klb1WIOoL4msxQWiycleCgnPb.png b/docs/fr-FR/handbook/block-gantt/static/P3klb1WIOoL4msxQWiycleCgnPb.png new file mode 100644 index 000000000..e16701f84 Binary files /dev/null and b/docs/fr-FR/handbook/block-gantt/static/P3klb1WIOoL4msxQWiycleCgnPb.png differ diff --git a/docs/fr-FR/handbook/block-gantt/static/PK01bb2aOo97nIxBzwgcCoXlnjb.png b/docs/fr-FR/handbook/block-gantt/static/PK01bb2aOo97nIxBzwgcCoXlnjb.png new file mode 100644 index 000000000..3a3431307 Binary files /dev/null and b/docs/fr-FR/handbook/block-gantt/static/PK01bb2aOo97nIxBzwgcCoXlnjb.png differ diff --git a/docs/fr-FR/handbook/block-iframe/index.md b/docs/fr-FR/handbook/block-iframe/index.md new file mode 100644 index 000000000..39b88336a --- /dev/null +++ b/docs/fr-FR/handbook/block-iframe/index.md @@ -0,0 +1,44 @@ +# Iframe Block + + + +## Introduction +The Iframe block allows you to embed external web pages or content into the current page. + +## Installation + +It's a built-in plugin, no installation is required. + +## Adding Blocks + +![20240408220259](https://static-docs.nocobase.com/20240408220259.png) + +Configure the URL or Html to directly embed the external application. + +![20240408220322](https://static-docs.nocobase.com/20240408220322.png) + +## Template engine + +### string template + +The default rendering engine supports variables + +### Handlebars + +![20240811205239](https://static-docs.nocobase.com/20240811205239.png) + +For more information, refer to [Handlebars template](/handbook/template-handlebars) + +## Passing Variables + +### Html supports variable resolution + +![20240603120321](https://static-docs.nocobase.com/20240603120321.png) + +![20240603120629](https://static-docs.nocobase.com/20240603120629.gif) + +### Url supports variables + +![20240603142219](https://static-docs.nocobase.com/20240603142219.png) + +For more information on variables, refer to [Variables](/handbook/ui/variables) diff --git a/docs/fr-FR/handbook/block-kanban/index.md b/docs/fr-FR/handbook/block-kanban/index.md new file mode 100644 index 000000000..9a43f8f97 --- /dev/null +++ b/docs/fr-FR/handbook/block-kanban/index.md @@ -0,0 +1,78 @@ +# Kanban Block + + + +## Introduction + +The Kanban block presents data in a Kanban view, enabling drag-and-drop functionality to update the status of items. + +## Installation + +This is a built-in plugin, so no installation is needed. + +## Adding a Block + + + +![20240419214751](https://static-docs.nocobase.com/20240419214751.png) + +### Grouping Field + +Used to organize data into specific groups. When creating or configuring a Kanban block, you must select a single-choice field as the grouping field. + +### Sorting Field + +Used to arrange data within each group. Only fields tied to the grouping field can be selected for sorting. You can also quickly create a sorting field while setting up the Kanban block. + +![20240426170628](https://static-docs.nocobase.com/20240426170628.png) + +## Managing Kanban Data + +### Clicking a Card + +Clicking on a card opens a pop-up window where you can configure data blocks as needed, such as setting up an edit form to modify the current card's record. + +![20240419220115](https://static-docs.nocobase.com/20240419220115.png) + +You can also configure how the pop-up window opens and its size. + +![20240419220159](https://static-docs.nocobase.com/20240419220159.png) + +### Dragging a Card + +Example: Adjust the status of a product by dragging the card. Once dragging is complete, the data will be saved automatically. + + + +## Block Configuration Options + +### Setting Data Range + +Example: Default filtering for promotional products. + +![20240422095659](https://static-docs.nocobase.com/20240422095659.png) + +For more details, refer to [Setting Data Range](/handbook/ui/blocks/block-settings/data-scope). + +### Setting Block Height + +Example: Adjust the height of the order Kanban block, with the scrollbar appearing within the columns. + +![20240605220635](https://static-docs.nocobase.com/20240605220635.gif) + +For more details, refer to [Block Height](/handbook/ui/blocks/block-settings/block-height). + +## Configuring Fields + +![20240419215909](https://static-docs.nocobase.com/20240419215909.png) + +## Configuring Actions + +![20240419220903](https://static-docs.nocobase.com/20240419220903.png) + +- [Filter](/handbook/ui/actions/types/filter) +- [Add New](/handbook/ui/actions/types/add-new) diff --git a/docs/fr-FR/handbook/block-kanban/static/ER09beUFAoC59JxXPprctLmbnwE.gif b/docs/fr-FR/handbook/block-kanban/static/ER09beUFAoC59JxXPprctLmbnwE.gif new file mode 100644 index 000000000..fcb2e5f86 Binary files /dev/null and b/docs/fr-FR/handbook/block-kanban/static/ER09beUFAoC59JxXPprctLmbnwE.gif differ diff --git a/docs/fr-FR/handbook/block-kanban/static/GrhobxsDJoB72Bx0kCAcXPp8nwe.png b/docs/fr-FR/handbook/block-kanban/static/GrhobxsDJoB72Bx0kCAcXPp8nwe.png new file mode 100644 index 000000000..ac0a03fde Binary files /dev/null and b/docs/fr-FR/handbook/block-kanban/static/GrhobxsDJoB72Bx0kCAcXPp8nwe.png differ diff --git a/docs/fr-FR/handbook/block-kanban/static/JupDbsBBSowHoqx5fIhcWVn5nTg.png b/docs/fr-FR/handbook/block-kanban/static/JupDbsBBSowHoqx5fIhcWVn5nTg.png new file mode 100644 index 000000000..1b83edaa9 Binary files /dev/null and b/docs/fr-FR/handbook/block-kanban/static/JupDbsBBSowHoqx5fIhcWVn5nTg.png differ diff --git a/docs/fr-FR/handbook/block-map/index.md b/docs/fr-FR/handbook/block-map/index.md new file mode 100644 index 000000000..f5036f865 --- /dev/null +++ b/docs/fr-FR/handbook/block-map/index.md @@ -0,0 +1,108 @@ +# Block Map + + + +## Overview + +The Block Map is an essential tool for displaying and managing map-related data, offering support for four types of map fields: points, lines, circles, and polygons. + +## Installation + +This plugin comes pre-installed but must be activated before use. + +![20240421120958](https://static-docs.nocobase.com/20240421120958.png) + +After activation, map authentication details need to be configured. + +![20240421121032](https://static-docs.nocobase.com/20240421121032.png) + +Once configured, map fields can be integrated into your data tables. + +![20240426171356](https://static-docs.nocobase.com/20240426171356.png) + +## Adding Map Blocks + +Map blocks can only be added if the associated data table includes map fields. + +![20240408194209](https://static-docs.nocobase.com/20240408194209.png) + +![20240408194420](https://static-docs.nocobase.com/20240408194420.png) + +1. **Map Field:** Defines the type of map element (point, line, polygon). +2. **Marker Field:** Specifies map markers (applicable only for point types). + +## Points + +**Use Case:** Ideal for visualizing the distribution of retail store locations. + +![20240408195630](https://static-docs.nocobase.com/20240408195630.png) + +## Lines + +Lines are constructed from a sequence of map points, commonly used to illustrate paths, such as delivery routes. + +![20240408201608](https://static-docs.nocobase.com/20240408201608.png) + +## Circles + +![20240408201939](https://static-docs.nocobase.com/20240408201939.png) + +## Polygons + +**Use Case:** Perfect for area planning and zoning applications. + +![Polygon](https://static-docs.nocobase.com/20240408200546.png) + +## Block Settings + +![20240421121949](https://static-docs.nocobase.com/20240421121949.png) + +## Sequential Field Connections + +Connect points according to the order defined by sequential fields. + +![20240408202645](https://static-docs.nocobase.com/20240408202645.png) + +![20240421121917](https://static-docs.nocobase.com/20240421121917.png) + +![20240422101027](https://static-docs.nocobase.com/20240422101027.png) + +## Default Map Zoom Level + +The zoom level defaults to 13 but can be adjusted as needed. + +![20240408202854](https://static-docs.nocobase.com/20240408202854.png) + +## Defining Data Scope + +**Example:** Filter for waybills marked as "shipped" (using relational fields). Only waybills within the specified data scope will be displayed. + +![20240422101250](https://static-docs.nocobase.com/20240422101250.png) + +For further details, refer to [Setting Data Scope](/handbook/ui/blocks/block-settings/data-scope). + +## Adjusting Block Height + +**Example:** Modify the height of the map block to suit your layout. + +![20240605221111](https://static-docs.nocobase.com/20240605221111.gif) + +For more information, see [Block Height](/handbook/ui/blocks/block-settings/block-height). + +- [Edit Block Title](/handbook/ui/blocks/block-settings/block-title) +- [Connect Data Block](/handbook/ui/blocks/block-settings/connect-block) +- [Save as Block Template](/handbook/ui/blocks/block-settings/block-template) + +## Configuration Operations + +![20240421122020](https://static-docs.nocobase.com/20240421122020.png) + +## Batch Point Selection + +![20240422102334](https://static-docs.nocobase.com/20240422102334.gif) + +- [Filter](/handbook/ui/actions/types/filter) +- [Add](/handbook/ui/actions/types/add-new) +- [Refresh](/handbook/ui/actions/types/refresh) +- [Bulk Update](/handbook/action-bulk-update) +- [Bulk Edit](/handbook/action-bulk-edit) diff --git a/docs/fr-FR/handbook/block-multi-step-from/index.md b/docs/fr-FR/handbook/block-multi-step-from/index.md new file mode 100644 index 000000000..c92147f0c --- /dev/null +++ b/docs/fr-FR/handbook/block-multi-step-from/index.md @@ -0,0 +1,67 @@ +# Multi-step form + + + +## Introduction +Multi-step form is a block used to build a data entry and editing interface that supports step-by-step configuration on top of the capabilities of the form block. + +## Adding Blocks + + + +## Block Settings + +![](https://static-docs.nocobase.com/202410101717319.png) + + +### Linkage Rules + +Control the behavior of form fields through linkage rules. + +![](https://static-docs.nocobase.com/202410101717884.png) + +More content reference [Linkage rules](/handbook/ui/blocks/block-settings/linkage-rule) + + +### Block Height Setting + +Example: Set the block height to "Specify height" mode. + + + +More content reference [Block height](/handbook/ui/blocks/block-settings/block-height) + +## Step Setting + +### Add New Step + +![](https://static-docs.nocobase.com/202410101718482.png) + +### Update Step Title + +![](https://static-docs.nocobase.com/202410101718755.png) + +![](https://static-docs.nocobase.com/202410101718413.png) + +### Adjust Step Sequence + + + +## Configure Fields + +Refer to the field configuration items [Form configuration field](/handbook/ui/blocks/data-blocks/form#configure-fields) + +## Configure Actions + +![](https://static-docs.nocobase.com/202410101719893.png) + +- previous: return to the previous form +- next: switch to the next form +- [submit](/handbook/ui/actions/types/submit) +- [custom request](/handbook/action-custom-request) diff --git a/docs/fr-FR/handbook/block-tree/index.md b/docs/fr-FR/handbook/block-tree/index.md new file mode 100644 index 000000000..4725affe2 --- /dev/null +++ b/docs/fr-FR/handbook/block-tree/index.md @@ -0,0 +1,35 @@ +# Tree Filter Block + + + +## Introduction + +The tree filter block needs to be connected to the data block for use, providing filtering capabilities for the data block. + +## Adding Block + + + +## Block Settings + +![20240607144440](https://static-docs.nocobase.com/20240607144440.png) + +### Connecting Data Block + +Example: The form filter block connects to the detail data block to achieve linkage. + + + +For more information, refer to [Connecting Data Block](/handbook/ui/blocks/block-settings/connect-block) + +- [Editing Block Title](/handbook/ui/blocks/block-settings/block-title) +- [Linkage Rule](/handbook/ui/blocks/block-settings/linkage-rule) +- [Save as Block Template](/handbook/ui/blocks/block-settings/block-template) + +## Configuring Fields + +![20240607145820](https://static-docs.nocobase.com/20240607145820.png) diff --git a/docs/fr-FR/handbook/calendar/calendar-collection.md b/docs/fr-FR/handbook/calendar/calendar-collection.md new file mode 100644 index 000000000..cf35aad3c --- /dev/null +++ b/docs/fr-FR/handbook/calendar/calendar-collection.md @@ -0,0 +1,11 @@ +# Calendar collection + + + +## Introduction + +A calendar Collection is a specialized data table designed to store dates and date-related information. It is commonly used to manage and track time within applications or systems. The primary goal of the calendar table is to offer flexible and efficient access to date information, allowing for the swift retrieval of relevant data as needed. + +## User Manual + +![20240512182454](https://static-docs.nocobase.com/20240512182454.png) diff --git a/docs/fr-FR/handbook/calendar/index.md b/docs/fr-FR/handbook/calendar/index.md new file mode 100644 index 000000000..2fe4babbe --- /dev/null +++ b/docs/fr-FR/handbook/calendar/index.md @@ -0,0 +1,80 @@ +# Calendar Block + + + +## Introduction + +The Calendar Block offers a streamlined way to view and manage events and date-related data in a calendar format, making it perfect for scheduling meetings, planning events, and organizing your time efficiently. + +## Installation + +This plugin comes pre-installed, so no additional setup is required. + +## Adding Blocks + + + +1. Title Field: Displays key information directly on the calendar bars. +2. Start Time: Indicates when the task begins. +3. End Time: Marks when the task ends. + +Clicking on a task bar highlights the selection and opens a detailed pop-up window. + +![20240408171928](https://static-docs.nocobase.com/20240408171928.png) + +## Configure Fields + +![20240419203321](https://static-docs.nocobase.com/20240419203321.png) + +### Display Lunar Calendar + +![20240419203603](https://static-docs.nocobase.com/20240419203603.png) + +- [Edit Block Title](/handbook/ui/blocks/block-settings/block-title) +- [Save as Block Template](/handbook/ui/blocks/block-settings/block-template) + +### Set Data Range + +![20240419203751](https://static-docs.nocobase.com/20240419203751.png) + +For additional information, see [Set Data Range](/handbook/ui/blocks/block-settings/data-scope). + +### Set Block Height + +Example: Adjust the height of the order calendar block. No scrollbar will appear inside the calendar block. + +![20240605215742](https://static-docs.nocobase.com/20240605215742.gif) + +For more information, refer to [Block Height](/handbook/ui/blocks/block-settings/block-height) + +### Background Color Field + +:::info{title=Tip} +The version of NocoBase needs to be v1.4.0-beta or above. +::: + +This option can be used to configure the background color of calendar events. Here's how to use it: + +1. The calendar data table needs to have a field of type **Single select** or **Radio group**, and this field needs to be configured with colors. +2. Then, return to the calendar block configuration interface and select the field you just configured with colors in the **Background Color Field**. +3. Finally, you can try selecting a color for a calendar event and click submit. You'll see that the color has taken effect. + +![20240914192017_rec_](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240914192017_rec_.gif) + +## Configure Actions + +![20240419203424](https://static-docs.nocobase.com/20240419203424.png) + +### Today + +The "Today" button in the Calendar Block offers quick navigation, enabling users to instantly return to the current date after exploring other dates. + +![20240419203514](https://static-docs.nocobase.com/20240419203514.png) + +### Switch View + +The default view is set to Month. + +![20240419203349](https://static-docs.nocobase.com/20240419203349.png) diff --git a/docs/fr-FR/handbook/client/index.md b/docs/fr-FR/handbook/client/index.md new file mode 100644 index 000000000..03fbe9787 --- /dev/null +++ b/docs/fr-FR/handbook/client/index.md @@ -0,0 +1,9 @@ +# WEB Client + +## Introduction + +Offers a seamless user interface for interacting with the NocoBase server. + +## Installation + +As a built-in plugin, no additional installation is necessary. diff --git a/docs/fr-FR/handbook/client/user/index.md b/docs/fr-FR/handbook/client/user/index.md new file mode 100755 index 000000000..05cb5c00e --- /dev/null +++ b/docs/fr-FR/handbook/client/user/index.md @@ -0,0 +1,23 @@ +# User Manual + +This plugin is one of the core components built into NocoBase, providing the client interface. The client features an AdminLayout design, with the following key elements: + +## Plugin Manager + +Manage your plugins with options to add, activate, disable, or delete them. + +![](https://static-docs.nocobase.com/23ee6d074e2829617c4b766282c16627.png) + +## Plugin Management Center + +Access the configuration pages for each plugin. + +![](https://static-docs.nocobase.com/f0236b3cf5b65c39fa723c66a182d214.png) + +## User Profile Center + +![](https://static-docs.nocobase.com/58ff74ebe37542180e7fd2629f940a79.png) + +## UI Editor + +![](https://static-docs.nocobase.com/8dc5d2b1e4487622e40e8a6510e3e492.png) diff --git a/docs/fr-FR/handbook/client/user/plugin-manager/index.md b/docs/fr-FR/handbook/client/user/plugin-manager/index.md new file mode 100644 index 000000000..55d03d2ae --- /dev/null +++ b/docs/fr-FR/handbook/client/user/plugin-manager/index.md @@ -0,0 +1,42 @@ +# Plugin Manager + +The Plugin Manager offers a straightforward and intuitive interface for adding plugins, enhancing NocoBase's functionality with a lightweight and user-friendly experience. It allows for seamless expansion and customization of application features, including the installation, upgrade, and uninstallation of plugins. + +**Key Components of the Plugin Manager:** + +1. **Local Plugins/Plugin Marketplace**: Access and manage plugins available locally or through the marketplace. +2. **Plugin Classification**: Organize plugins by categories such as Built-in, Enabled, Disabled, and Problematic. The system supports fuzzy search by plugin name. +3. **Add New Plugin**: Easily expand functionality by adding new plugins. +4. **Plugin Configuration Main Body**: Centralize your plugin configurations in one place. + +![Plugin Manager Interface](https://static-docs.nocobase.com/86fb70757a77ab3654f97faffc2dce78.png) + +## Viewing Plugin Documentation + +A simple click on any plugin allows for a quick view of its documentation, which includes user instructions, compatibility checks for dependencies, and update logs. + +![View Plugin Documentation](https://static-docs.nocobase.com/a4015bea903d3c6874ca94e6c1085278.png) + +## Adding a Plugin + +With plug-and-play convenience, you can effortlessly add new plugins via the interface. The system supports downloading from the npm registry (private registries are also supported), local uploads, and URL downloads. + +![Add Plugin](https://static-docs.nocobase.com/103baa0ba0dd88e7481c0636147c7a7c.png) + +## Activating a Plugin + +![Activate Plugin](https://static-docs.nocobase.com/c76b7228678c358ba6f8f68ef05d3cd5.gif) + +## Disabling a Plugin + +![Disable Plugin](https://static-docs.nocobase.com/86f526669dba0d4f3245d24d9e9d35a9.gif) + +## Deleting a Plugin + +![Delete Plugin](https://static-docs.nocobase.com/b32d6507aaee2b708290311cf1e7ebca.gif) + +## Updating a Plugin + +Currently, the option to update plugins is available only for those located under storage/plugins, as illustrated below: + +![Update Plugin](https://static-docs.nocobase.com/7bfaec2785dc6a2e864fee2337fc57ef.png) diff --git a/docs/fr-FR/handbook/client/user/plugin-manager/static/DtkpbfloNog6gtxM6RWcqDYwnph.png b/docs/fr-FR/handbook/client/user/plugin-manager/static/DtkpbfloNog6gtxM6RWcqDYwnph.png new file mode 100644 index 000000000..cc02c0f8b Binary files /dev/null and b/docs/fr-FR/handbook/client/user/plugin-manager/static/DtkpbfloNog6gtxM6RWcqDYwnph.png differ diff --git a/docs/fr-FR/handbook/client/user/plugin-manager/static/Ehu2boQ2xowSrnxpMS1ctIprnMd.png b/docs/fr-FR/handbook/client/user/plugin-manager/static/Ehu2boQ2xowSrnxpMS1ctIprnMd.png new file mode 100644 index 000000000..ce13dfa7c Binary files /dev/null and b/docs/fr-FR/handbook/client/user/plugin-manager/static/Ehu2boQ2xowSrnxpMS1ctIprnMd.png differ diff --git a/docs/fr-FR/handbook/client/user/plugin-manager/static/K8JDbo9JCo9iCExVEw4cKHfOnPg.png b/docs/fr-FR/handbook/client/user/plugin-manager/static/K8JDbo9JCo9iCExVEw4cKHfOnPg.png new file mode 100644 index 000000000..43c3fe359 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/plugin-manager/static/K8JDbo9JCo9iCExVEw4cKHfOnPg.png differ diff --git a/docs/fr-FR/handbook/client/user/plugin-manager/static/LcP9b9oVwoN5ZQx2CZScJ7TAn9c.gif b/docs/fr-FR/handbook/client/user/plugin-manager/static/LcP9b9oVwoN5ZQx2CZScJ7TAn9c.gif new file mode 100644 index 000000000..5bafff096 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/plugin-manager/static/LcP9b9oVwoN5ZQx2CZScJ7TAn9c.gif differ diff --git a/docs/fr-FR/handbook/client/user/plugin-manager/static/Mgo0bjYccoNjmNxNT8rcfF0tndd.png b/docs/fr-FR/handbook/client/user/plugin-manager/static/Mgo0bjYccoNjmNxNT8rcfF0tndd.png new file mode 100644 index 000000000..c5c349d81 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/plugin-manager/static/Mgo0bjYccoNjmNxNT8rcfF0tndd.png differ diff --git a/docs/fr-FR/handbook/client/user/plugin-manager/static/NOz2b4To1o1fMbxqnb8cfqacnfT.gif b/docs/fr-FR/handbook/client/user/plugin-manager/static/NOz2b4To1o1fMbxqnb8cfqacnfT.gif new file mode 100644 index 000000000..71f3c87a5 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/plugin-manager/static/NOz2b4To1o1fMbxqnb8cfqacnfT.gif differ diff --git a/docs/fr-FR/handbook/client/user/plugin-manager/static/VehkbE6RqogLlcxoRrVcEvpJn0e.gif b/docs/fr-FR/handbook/client/user/plugin-manager/static/VehkbE6RqogLlcxoRrVcEvpJn0e.gif new file mode 100644 index 000000000..68ddab50c Binary files /dev/null and b/docs/fr-FR/handbook/client/user/plugin-manager/static/VehkbE6RqogLlcxoRrVcEvpJn0e.gif differ diff --git a/docs/fr-FR/handbook/client/user/plugin-settings/index.md b/docs/fr-FR/handbook/client/user/plugin-settings/index.md new file mode 100644 index 000000000..89eca97a4 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/plugin-settings/index.md @@ -0,0 +1,10 @@ +# Plugin Management + +The Management Center offers users a unified platform to manage and configure system information and work-related settings. It allows users to tailor the system, data table modeling, workflow configuration, and plugin settings to meet their specific business needs and personal preferences. + +## Overview of the Plugin Management Center + +1. Quick Configuration Items at the Top +2. List of All Activated Plugin Configurations +3. Plugin Tabs +4. Main Content Area diff --git a/docs/fr-FR/handbook/client/user/plugin-settings/static/N50VbOPHpoKvYVxacuUc1i6Cnrd.jpeg b/docs/fr-FR/handbook/client/user/plugin-settings/static/N50VbOPHpoKvYVxacuUc1i6Cnrd.jpeg new file mode 100644 index 000000000..0285ff522 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/plugin-settings/static/N50VbOPHpoKvYVxacuUc1i6Cnrd.jpeg differ diff --git a/docs/fr-FR/handbook/client/user/static/CbzRbkcI2onjbkxFOVccwafpnrh.png b/docs/fr-FR/handbook/client/user/static/CbzRbkcI2onjbkxFOVccwafpnrh.png new file mode 100755 index 000000000..2bcb66276 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/static/CbzRbkcI2onjbkxFOVccwafpnrh.png differ diff --git a/docs/fr-FR/handbook/client/user/static/M6U6b8YAgovpFIxTzaccmcp5nme.png b/docs/fr-FR/handbook/client/user/static/M6U6b8YAgovpFIxTzaccmcp5nme.png new file mode 100755 index 000000000..6d99e19ff Binary files /dev/null and b/docs/fr-FR/handbook/client/user/static/M6U6b8YAgovpFIxTzaccmcp5nme.png differ diff --git a/docs/fr-FR/handbook/client/user/static/PqPnbVWuYo9GYgxCrxfcTK8rnof.png b/docs/fr-FR/handbook/client/user/static/PqPnbVWuYo9GYgxCrxfcTK8rnof.png new file mode 100755 index 000000000..00b1be8fe Binary files /dev/null and b/docs/fr-FR/handbook/client/user/static/PqPnbVWuYo9GYgxCrxfcTK8rnof.png differ diff --git a/docs/fr-FR/handbook/client/user/static/T3J0b4zZ2o8ZiUxBG7lcgNYIn2g.png b/docs/fr-FR/handbook/client/user/static/T3J0b4zZ2o8ZiUxBG7lcgNYIn2g.png new file mode 100755 index 000000000..b1c4fb135 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/static/T3J0b4zZ2o8ZiUxBG7lcgNYIn2g.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/add-new.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/add-new.md new file mode 100644 index 000000000..620297226 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/add-new.md @@ -0,0 +1 @@ +# Add New diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/add-record.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/add-record.md new file mode 100644 index 000000000..01980a90a --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/add-record.md @@ -0,0 +1,5 @@ +# **Add Record** + +The custom add data operation empowers users to insert data into any table within the system. + +![](https://static-docs.nocobase.com/70c3982c59d6c7b7f36e225f4c208d2f.png) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/custom-request.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/custom-request.md new file mode 100644 index 000000000..326a81e50 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/custom-request.md @@ -0,0 +1,5 @@ +# **Custom Request** + +Configure the URL for custom request operations to cater to specific business needs. For additional information, refer to the custom request plugin documentation. + +![](https://static-docs.nocobase.com/69d610904dbec87ef719e5345915f5a2.png) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/delete.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/delete.md new file mode 100644 index 000000000..e546c6769 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/delete.md @@ -0,0 +1,5 @@ +# **Delete** + +The delete operation enables the removal of data records, whether through row buttons or batch operation buttons, and includes a confirmation dialog to ensure intent. + +![](https://static-docs.nocobase.com/96272ba867a128004738fce9f5d6d63f.png) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/duplicate.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/duplicate.md new file mode 100644 index 000000000..92da97b59 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/duplicate.md @@ -0,0 +1,79 @@ +# Duplicate + +The Duplicate operation enables users to duplicate a row of data to create new records, offering two methods: **direct duplicate** and **copy into the form and continue to fill in**. + +## Direct Duplicate + +![Direct Duplicate](https://static-docs.nocobase.com/2c0ac5d1a539de4b72b49b7d966d8c09.png) + +- By default, the data is copied directly. +- Target Data Table: This is the table where the copied data will be added. In cases involving inheritance, it can be copied to a sub-table; however, direct Duplicate only adds data to the current table. +- Template Fields: These specify the fields to be copied, allowing for full selection. This configuration is mandatory. + +Once the configuration is complete, simply click the button to duplicate the data. + +## Copy into the form and continue to fill in + +The template fields you configure will populate the form with default values, which can be modified before submission. + +You can choose either the current table or a sub-table as the target table for adding the copied data. + +![Copy to Form](https://static-docs.nocobase.com/a072aa572fd0a0fe643eadf95471da2a.png) + +Configure Template Fields: Template fields will serve as default values in the form, only including the values of selected fields. + +![Configure Template Fields](https://static-docs.nocobase.com/8032fa2025180ade275da55b97774b4d.png) + +The "Waybill" (o2m) relationship is duplicated. Adjust its field component to a sub-form, where you can configure the sub-form fields. + +![Waybill Relationship](https://static-docs.nocobase.com/b13c9287bae8601646727a2e78b81be7.png) + +Sync Form Fields: After configuring the form, click the sync form fields button. This will automatically select all configured fields within the form (note: each time the form field configuration is modified, it must be manually synced again). After syncing, you can further customize the template fields. + +![Sync Form Fields](https://static-docs.nocobase.com/156b6d8d741521e63d12e49092414d58.png) + +Clicking the Duplicate button will open a pop-up window, where the template data will populate the form with default values. You can then modify the data before submission to complete the copy process. + +![Duplicate Operation Example](https://static-docs.nocobase.com/1c0a0ae0c59971f48b2282a68831d44b.png) + +The complete example below demonstrates how to configure the duplicate operation within an order list. + +![Order List duplicate Example](https://static-docs.nocobase.com/fa8a89abf0ba136df04b6d0d838eae4e.gif) + +## Explanation of Different, Reference, and Preload + +Different fields (with different relationship types) follow distinct processing logics, such as duplicate, reference, and preload. Adjusting field components within relationship fields also influences the processing logic. For example, Select and Record Picker handle reference relationships, while Sub-form and Sub-table manage copy relationships. + +- Duplicate + + - Standard fields are duplicated. + - The relationship fields of hasOne and hasMany can only be copied (i.e., these types of relationship fields cannot use Select or Record Picker as field components; instead, Sub-form or Sub-table should be used). + - Changes to the field components of hasOne and hasMany do not alter the processing logic (copy). + - In copied relationship fields, all child fields are selectable. + +- Reference + + - belongsTo and belongsToMany are references. + - **References can be converted into copies. For instance, if the field component is changed from select to sub-form, the relationship transitions from reference to copy (after conversion, all child fields become selectable).** + +- Preload: Relationship fields within referenced fields + + - These relationship fields are preloaded. + - Preloaded relationship fields may shift to reference or copy following adjustments to the field components. + +## About Select All + +- All copy fields are selected. +- All reference fields are selected. + +## Template Data Processing Logic + +- All foreign key fields in relationships are filtered out. +- For copied relationships, primary key fields are also filtered out. +- References and preloads retain their primary key fields. + +## Understanding Sync Form Fields + +In most cases, form configurations involve a large number of fields. Managing such complex forms manually can be cumbersome. To streamline this process, the sync form fields button has been introduced. This feature automatically analyzes the form field configurations and applies the appropriate copy logic—whether copy, reference, or preload—based on the field types and relationship field components. Fields that have already been configured are selected by default. + +After any modifications to the form field configurations, the system does not automatically update these changes. Therefore, users need to manually click the sync form fields button to apply the latest configuration to the template settings. diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/edit.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/edit.md new file mode 100644 index 000000000..fa32d21dc --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/edit.md @@ -0,0 +1,5 @@ +# **Edit** + +The edit operation allows for data modification, typically achieved by configuring the relevant form block. + +![](https://static-docs.nocobase.com/9b412840521b7ae6d5c5f0372df2f349.png) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/export.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/export.md new file mode 100644 index 000000000..3d6b8d805 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/export.md @@ -0,0 +1,9 @@ +# Export + +The export operation is facilitated through plugin extensions, allowing you to batch export all data from the tables associated with a block. This feature also supports configuring the titles of the export fields. + +![Export Configuration](https://static-docs.nocobase.com/c074c4eb9d67a8408d98ff6299715157.png) + +- Configuring Exportable Fields + +![Export Fields Configuration](https://static-docs.nocobase.com/903b4c12bcd1b8e59e133d2f9822eb56.png) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/filter.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/filter.md new file mode 100644 index 000000000..d1495c7a9 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/filter.md @@ -0,0 +1,13 @@ +# Filtering + +The filtering operation typically appears within data blocks, enabling the configuration of various conditions to filter data. It is important to note that if a block already has a data range configured, the filtering operation will merge with the data range conditions to create the final filter criteria. + +![Filtering Operation](https://static-docs.nocobase.com/da548ad1c170bef3d2359ac82764b534.png) + +Supports configuring which fields can be filtered. + +![Filterable Fields Configuration](https://static-docs.nocobase.com/85815dc40157571ba072cc392fbe43d4.png) + +As shown below, a filter operation is set up for the waybill list, where data is filtered by adjusting the condition configurations. + +![Waybill Filtering](https://static-docs.nocobase.com/02cabf6201fdf4165747c9fcde687a5e.gif) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/import.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/import.md new file mode 100644 index 000000000..ca66f4970 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/import.md @@ -0,0 +1,17 @@ +# **Import** + +The import operation is facilitated through plugin extensions, currently allowing batch data import via **.xlsx** files. + +1. Set up the fields available for import. + +![](https://static-docs.nocobase.com/967a130c06237e0724e5815fc3b16903.png) + +![](https://static-docs.nocobase.com/0046c530677bff984db4d560956da35a.png) + +2. Download the import template, populate it with data, and then proceed with the import. + +![](https://static-docs.nocobase.com/1038ab1b1fcdc7ad6e5346cde27eed49.png) + +For further details, consult the import documentation. + +[https://github.com/nocobase/nocobase/tree/main/packages/plugins/%40nocobase/plugin-import#%E5%AF%BC%E5%85%A5%E8%AF%B4%E6%98%8E](https://github.com/nocobase/nocobase/tree/main/packages/plugins/%40nocobase/plugin-import#%E5%AF%BC%E5%85%A5%E8%AF%B4%E6%98%8E) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/index.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/index.md new file mode 100644 index 000000000..18feb0b52 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/index.md @@ -0,0 +1,45 @@ +# Actions + +In the UI, actions are buttons designed to trigger specific commands. These buttons can be placed directly on the page, within dialogs or drawers, and can also be used in combination with blocks. Currently, dynamic configurations of actions are primarily used in combination with blocks. + +## Actions in Blocks + +![Actions in Blocks](https://static-docs.nocobase.com/3e69f1f2991842ecad640705bc9feda4.png) + +## Action Designer (Toolbar) + +Unlike blocks and fields, the action designer only features two icons: + +- Drag +- Parameter Configuration + +![Action Designer](https://static-docs.nocobase.com/007422d42678c54f79668dfafe69b60e.png) + +## Action Drag Sorting + +By holding down the "Drag" icon in the button designer, you can reorder the buttons. + +```bash +A gif is missing +``` + +## General Parameter Configuration + +- Edit Button +- Open Mode: Drawer, Dialog +- Popup Size: Large, Medium, Small +- Delete + +![General Parameter Configuration](https://static-docs.nocobase.com/e99916932f6c4d58bcad4d892b5daf15.png) + +## Action Linkage Rules + +Actions with contextual data can also be configured with "Linkage Rules." + +![Action Linkage Rules](https://static-docs.nocobase.com/c431434a285278ea00bedf9e4dac4d45.png) + +Linkage Rules Configuration + +![Linkage Rules Configuration](https://static-docs.nocobase.com/149c049bb0c0ce931c6c0333e12b0610.png) + +Multiple rules can be added, with conditions similar to those used in filtering. These rules can control whether buttons are displayed, hidden, enabled, or disabled. diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/open-popup.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/open-popup.md new file mode 100644 index 000000000..88a0171b4 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/open-popup.md @@ -0,0 +1,9 @@ +# Open popup + +The Open popup operation presents data in a popup window, allowing you to customize detail blocks or form blocks. This feature is suitable for various scenarios. For example, when a data table has many fields, these fields can be divided into different operation blocks, allowing you to focus on viewing or modifying specific fields. You can create multiple customized data display or editing interfaces based on business needs. + +![Open popup](https://static-docs.nocobase.com/c859041afb43752431e78c6e81c44c43.png) + +As illustrated, the order table is configured with three Open popup operations: View Main Order (Order Main Information), View Products (Product Information associated with the Order), and View Customer (Customer Information associated with the Order). + +![Open popup Operations](https://static-docs.nocobase.com/110e2eed418c755ef40b7259e5816c73.png) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/print.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/print.md new file mode 100644 index 000000000..f098dd573 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/print.md @@ -0,0 +1,3 @@ +# Print + +![](https://static-docs.nocobase.com/ce71d14cb7889b1e2291fbdb104b00e5.png) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/refresh.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/refresh.md new file mode 100644 index 000000000..90cb8d561 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/refresh.md @@ -0,0 +1,5 @@ +# **Refresh** + +The refresh operation is designed to reload data within a data block, providing support for manual refresh. + +![](https://static-docs.nocobase.com/3488c8c8296e9048f815d89198a51c5a.png) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/save-record.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/save-record.md new file mode 100644 index 000000000..f0799ae2b --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/save-record.md @@ -0,0 +1,14 @@ +# Save Record + +Custom Save Record operations are unique to form blocks, supporting the customization of the operation's behavior: + +- Edit Button +- Assign Field Values: Upon clicking the custom button, the current data field assignments are saved. +- Skip Required Validation +- After successful submission + +![Save Data Configuration](https://static-docs.nocobase.com/2d35b787114dede3a0f08d7431edb37a.png) + +- Bind Workflow + +![Bind Workflow](https://static-docs.nocobase.com/6d93cd53d45c8408ed78b0289f0f5dae.png) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/ApcrbSF87oD3roxGW80cFkAxn2c.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/ApcrbSF87oD3roxGW80cFkAxn2c.png new file mode 100644 index 000000000..291a8c545 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/ApcrbSF87oD3roxGW80cFkAxn2c.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/BoEEbVUptoQCXOxvFJTc0p8Vnlb.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/BoEEbVUptoQCXOxvFJTc0p8Vnlb.png new file mode 100644 index 000000000..dcad0c620 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/BoEEbVUptoQCXOxvFJTc0p8Vnlb.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/C8RzbI7v5opcUNx7OWzcz1l6nxc.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/C8RzbI7v5opcUNx7OWzcz1l6nxc.png new file mode 100644 index 000000000..bc2264211 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/C8RzbI7v5opcUNx7OWzcz1l6nxc.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/CzfCbLjC3oPItSxoeGAcDh0Rnte.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/CzfCbLjC3oPItSxoeGAcDh0Rnte.png new file mode 100644 index 000000000..b811482e4 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/CzfCbLjC3oPItSxoeGAcDh0Rnte.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/DKwnbW8MfohvHjxplG4cVkcnn8d.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/DKwnbW8MfohvHjxplG4cVkcnn8d.png new file mode 100644 index 000000000..714ab3654 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/DKwnbW8MfohvHjxplG4cVkcnn8d.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/DTzUb0LcPoimfBxvHoHcDD5znAf.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/DTzUb0LcPoimfBxvHoHcDD5znAf.png new file mode 100644 index 000000000..d3520984c Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/DTzUb0LcPoimfBxvHoHcDD5znAf.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/G1bpbybaVoAWKlx4mCmc6HvQn0b.gif b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/G1bpbybaVoAWKlx4mCmc6HvQn0b.gif new file mode 100644 index 000000000..a304e56a1 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/G1bpbybaVoAWKlx4mCmc6HvQn0b.gif differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/H1hPbS7CWooWjpxAUfActBgbnsW.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/H1hPbS7CWooWjpxAUfActBgbnsW.png new file mode 100644 index 000000000..8669eaf5a Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/H1hPbS7CWooWjpxAUfActBgbnsW.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/J0udbzu0AoU7sVxJ9xtcvQdLnNc.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/J0udbzu0AoU7sVxJ9xtcvQdLnNc.png new file mode 100644 index 000000000..86939b8ed Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/J0udbzu0AoU7sVxJ9xtcvQdLnNc.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/JzDSbax1BoXxy2xrD6CcYuEKnRp.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/JzDSbax1BoXxy2xrD6CcYuEKnRp.png new file mode 100644 index 000000000..d588f826f Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/JzDSbax1BoXxy2xrD6CcYuEKnRp.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/KR15bOuXoo0u5QxZXmjcNbUJnoe.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/KR15bOuXoo0u5QxZXmjcNbUJnoe.png new file mode 100644 index 000000000..e8f44ef8a Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/KR15bOuXoo0u5QxZXmjcNbUJnoe.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/KsK1b5DOwoKI1qx4Qhscahrrneb.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/KsK1b5DOwoKI1qx4Qhscahrrneb.png new file mode 100644 index 000000000..b7d94bc38 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/KsK1b5DOwoKI1qx4Qhscahrrneb.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/MDtybwjRsoC8qfxrFAecdJpkngc.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/MDtybwjRsoC8qfxrFAecdJpkngc.png new file mode 100644 index 000000000..50d884b2c Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/MDtybwjRsoC8qfxrFAecdJpkngc.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/NRH9bnRw8ogxRkxZ7i3clbW1nRv.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/NRH9bnRw8ogxRkxZ7i3clbW1nRv.png new file mode 100644 index 000000000..7c39abb13 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/NRH9bnRw8ogxRkxZ7i3clbW1nRv.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/Ox76b54eho4fTUxdk67cjcjenCc.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/Ox76b54eho4fTUxdk67cjcjenCc.png new file mode 100644 index 000000000..f8b3c8950 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/Ox76b54eho4fTUxdk67cjcjenCc.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/PAgIbrq5xoMKKfxoG8mcOIOynpf.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/PAgIbrq5xoMKKfxoG8mcOIOynpf.png new file mode 100644 index 000000000..e56108875 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/PAgIbrq5xoMKKfxoG8mcOIOynpf.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/Pkf4bvn30oWEIjxrFmPc3d0lnPd.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/Pkf4bvn30oWEIjxrFmPc3d0lnPd.png new file mode 100644 index 000000000..c237b712b Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/Pkf4bvn30oWEIjxrFmPc3d0lnPd.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/QBHTb3fVBot2lqxdGnhcf29tnrb.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/QBHTb3fVBot2lqxdGnhcf29tnrb.png new file mode 100644 index 000000000..ab9a8a54e Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/QBHTb3fVBot2lqxdGnhcf29tnrb.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/QPq9bd2xaoB6unxVvEPccbJsnRg.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/QPq9bd2xaoB6unxVvEPccbJsnRg.png new file mode 100644 index 000000000..d8a0e40cf Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/QPq9bd2xaoB6unxVvEPccbJsnRg.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/QqICbfLMMozpgBxYBpMcKuOKnmg.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/QqICbfLMMozpgBxYBpMcKuOKnmg.png new file mode 100644 index 000000000..8038a1a90 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/QqICbfLMMozpgBxYBpMcKuOKnmg.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/R3f2biRIdoEm7DxUO6Ec1abXnKc.gif b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/R3f2biRIdoEm7DxUO6Ec1abXnKc.gif new file mode 100644 index 000000000..c31a4b050 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/R3f2biRIdoEm7DxUO6Ec1abXnKc.gif differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/R5eGbDbcEoLPrexCEzAcgnWfnjT.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/R5eGbDbcEoLPrexCEzAcgnWfnjT.png new file mode 100644 index 000000000..05ccd6fb2 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/R5eGbDbcEoLPrexCEzAcgnWfnjT.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/RDaibir7Jo6NHzx4IuGcYiKLnGb.gif b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/RDaibir7Jo6NHzx4IuGcYiKLnGb.gif new file mode 100644 index 000000000..6fe21f650 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/RDaibir7Jo6NHzx4IuGcYiKLnGb.gif differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/RUsJb4OBFow7zcxSgKocJN6Fnah.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/RUsJb4OBFow7zcxSgKocJN6Fnah.png new file mode 100644 index 000000000..4dbda7393 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/RUsJb4OBFow7zcxSgKocJN6Fnah.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/RZhIbo49lo2vV5xV5hZc0jkfn1d.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/RZhIbo49lo2vV5xV5hZc0jkfn1d.png new file mode 100644 index 000000000..aef3d62f6 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/RZhIbo49lo2vV5xV5hZc0jkfn1d.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/SGMubg0mCoVcbSxmOficmvisnHd.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/SGMubg0mCoVcbSxmOficmvisnHd.png new file mode 100644 index 000000000..7bdf8111c Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/SGMubg0mCoVcbSxmOficmvisnHd.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/SHP3b6s7YoabQ2xFO5pc8ZwDnNg.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/SHP3b6s7YoabQ2xFO5pc8ZwDnNg.png new file mode 100644 index 000000000..7256e94fc Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/SHP3b6s7YoabQ2xFO5pc8ZwDnNg.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/SU3PbOHyDoPT13xt4n2c785Engd.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/SU3PbOHyDoPT13xt4n2c785Engd.png new file mode 100644 index 000000000..701372956 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/SU3PbOHyDoPT13xt4n2c785Engd.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/U9AwbR4ehodjDyxFgdFcjZssn1e.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/U9AwbR4ehodjDyxFgdFcjZssn1e.png new file mode 100644 index 000000000..0c3e802e2 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/U9AwbR4ehodjDyxFgdFcjZssn1e.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/U9VCbG9I6ohTzQxzvPIc6oR3nid.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/U9VCbG9I6ohTzQxzvPIc6oR3nid.png new file mode 100644 index 000000000..889475c16 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/U9VCbG9I6ohTzQxzvPIc6oR3nid.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/Vz3kbrsk4oikc0xdbt6czL0Tn4b.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/Vz3kbrsk4oikc0xdbt6czL0Tn4b.png new file mode 100644 index 000000000..6d31a67d2 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/Vz3kbrsk4oikc0xdbt6czL0Tn4b.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/W7uJbyoy3oyeM1xQKZrc0GxMnhd.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/W7uJbyoy3oyeM1xQKZrc0GxMnhd.png new file mode 100644 index 000000000..c7922508b Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/W7uJbyoy3oyeM1xQKZrc0GxMnhd.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/WQAObL0sUocLRIx1dydcmaOEnQf.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/WQAObL0sUocLRIx1dydcmaOEnQf.png new file mode 100644 index 000000000..5fb62ae25 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/WQAObL0sUocLRIx1dydcmaOEnQf.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/WnChbrBPNoBvbFxZcVVccn5wnlg.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/WnChbrBPNoBvbFxZcVVccn5wnlg.png new file mode 100644 index 000000000..a8e7a0f73 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/WnChbrBPNoBvbFxZcVVccn5wnlg.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/WqjNbus2yozg3LxpRecccPA5nIb.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/WqjNbus2yozg3LxpRecccPA5nIb.png new file mode 100644 index 000000000..db5b0718a Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/WqjNbus2yozg3LxpRecccPA5nIb.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/static/XbxybS8u3od6TfxiQDYcTMq4n7g.png b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/XbxybS8u3od6TfxiQDYcTMq4n7g.png new file mode 100644 index 000000000..a5de56bc5 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/actions/static/XbxybS8u3od6TfxiQDYcTMq4n7g.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/submit-to-workflow.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/submit-to-workflow.md new file mode 100644 index 000000000..921e74c18 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/submit-to-workflow.md @@ -0,0 +1,9 @@ +# Submit to Workflow + +The Submit to Workflow operation is implemented via plugin extensions. + +1. Addition and update forms support the configuration and triggering of submission to workflows. +2. Multiple workflows can be triggered with one button click, each selecting a different workflow and data context (data is not restricted, and users are responsible for ensuring this). +3. Form button triggers only support the new workflow type "Form Event." + +For more details, refer to the Plugin Documentation. diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/submit.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/submit.md new file mode 100644 index 000000000..9fbbf947c --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/submit.md @@ -0,0 +1,17 @@ +# Submit + +The Submit operation is used to save form data (specific to form blocks). + +![Submit Operation](https://static-docs.nocobase.com/a8dd8cb5a0110c35a1197eb5800a099f.png) + +### Parameter Configuration + +- Save Method: Only supports configuring save methods in **new** operations for form blocks. + +![Save Method Configuration](https://static-docs.nocobase.com/25fc9b88760248e7015673b29b9487f4.png) + +- Bind Workflow: Supports binding with workflows, automatically triggering workflows after submission. By defining trigger data contexts, advanced automation tasks can be achieved, improving data processing efficiency and business process control. + +![Bind Workflow](https://static-docs.nocobase.com/a77bdff33353fb155b0c919db76e0474.png) + +For more details, refer to the Workflow Documentation. diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/update-record.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/update-record.md new file mode 100644 index 000000000..ad84da9bc --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/update-record.md @@ -0,0 +1,9 @@ +# Update record + +Custom row operations update record by configuring field assignments to specify the content to be modified. + +![Update Data Operation](https://static-docs.nocobase.com/03af47524a4b41742cdeb298b02500eb.png) + +As shown in the illustration, an update data operation is configured in the waybill table block to confirm delivery. + +![Waybill Update Operation](https://static-docs.nocobase.com/3057b0c6cd176342a15a3892488019fa.gif) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/actions/view.md b/docs/fr-FR/handbook/client/user/ui-designer/actions/view.md new file mode 100644 index 000000000..0c62750c1 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/actions/view.md @@ -0,0 +1,5 @@ +# View + +Detail operations are used to view detailed information about data, usually by configuring detail blocks. + +![View Operation](https://static-docs.nocobase.com/7252f4916033d26551d22ab3e6b95112.png) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/index.md b/docs/fr-FR/handbook/client/user/ui-designer/blocks/index.md new file mode 100644 index 000000000..16c09da4c --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/blocks/index.md @@ -0,0 +1,90 @@ +# Block + +A block serves as the content container, designed to be placed within a page, modal, or drawer. These blocks can be easily rearranged through drag-and-drop functionality, allowing for flexible layout customization. + +## Adding Blocks + +Blocks can be seamlessly integrated into a page, a modal, or a drawer, depending on the desired application. + +### Blocks within Pages + +Within pages, you can choose from various block types, including Data Blocks, Filter Blocks, and Other Blocks, each serving distinct purposes. + +![](https://static-docs.nocobase.com/dad0a394d33dd26f31c3202a76bb0153.png) + +### Blocks within Modals (Dialogs or Drawers) + +Modals, which include dialogs and drawers, also support block integration. While similar to pages, the blocks within modals are typically used for operations related to single records, such as adding, editing, or viewing data. Available block types include Current Data Blocks, Relationship Blocks, and Other Blocks. + +#### Drawers + +![](https://static-docs.nocobase.com/e18726fb0b52ddab89b9b1a44788f361.png) + +#### Dialogs + +![](https://static-docs.nocobase.com/4763fc5fc008bdf3915f84a7e433c0f8.png) + +## Block Designer + +Each block features three icons in the upper right corner, offering easy access to essential tools: + +1. Drag-and-Drop Layout +2. Quick Add Block +3. Block Parameter Configuration + +![](https://static-docs.nocobase.com/b488f3013532a246df59b89c0688a58f.png) + +For simple blocks, all configuration options are centralized under "Block Parameter Configuration," such as in Markdown blocks. + +![](https://static-docs.nocobase.com/f37e277863068b2661f66d4020af806a.png) + +More complex blocks, especially those dealing with data, provide additional embedded options like "Configure Field" and "Configure Action," offering greater flexibility. + +![](https://static-docs.nocobase.com/71b550da637d23145a5f62d48ee8521b.png) + +Moreover, you can explore advanced nesting possibilities, as demonstrated by the Chart Block. + +![](https://static-docs.nocobase.com/07588190b3f41ae3060e71d8b76b4447.png) + +## Block Layout + +To customize the layout, simply drag and drop blocks into your preferred arrangement. + +![](https://static-docs.nocobase.com/f6692295ac0917f3babce9a60ce80879.gif) + +## Block Templates + +You can save any data-type block as a template, which allows for quick duplication or referencing in future projects. For example, a form used for both adding and editing data can be saved as a template, streamlining your workflow by reusing it in different contexts. + +### How to Add and Use Templates + +1. Save a data block as a block template (note: only data-type blocks have this feature). + +![](https://static-docs.nocobase.com/b7718cea8784587d53524ade3c5b0a82.png) + +2. When adding a block, select either the duplicate or reference option for the template. + +![](https://static-docs.nocobase.com/135df7344e0f3080199e4bb1071c2fa6.png) + +### Difference Between Duplicate and Referencing + +Duplicate template a new block based on the template, with no link to the original template—any changes to the block will not affect the template. Referencing, however, directly links to the template, meaning any changes to the block will alter the template, and all instances where the template is referenced will be updated accordingly. + +## Block Types + +NocoBase categorizes blocks into four primary types: + +- **Data Blocks:** Used to display Collection data within the block. +- **Filter Blocks:** These can be added to pages and are specifically designed for filtering data within Data Blocks. +- **Relationship Blocks:** These are added to modals and are used for CRUD operations on data related to the current record. +- **Other Blocks:** These include standalone blocks like Markdown, Audit Log blocks, Workflow To-Do blocks, etc. + +### Data Blocks + +### Filter Blocks + +### Relationship Blocks + +### Other Blocks + +## Filter Interactions diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/BEmxbD2SgoUTDexnYjzcmh7Knhg.png b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/BEmxbD2SgoUTDexnYjzcmh7Knhg.png new file mode 100644 index 000000000..a2479759d Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/BEmxbD2SgoUTDexnYjzcmh7Knhg.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/EicAbMa7Jo2MD9x8FSfcpgTGnHc.png b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/EicAbMa7Jo2MD9x8FSfcpgTGnHc.png new file mode 100644 index 000000000..45698aa22 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/EicAbMa7Jo2MD9x8FSfcpgTGnHc.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/ImutbF0YDoWldOxrPilcwQFHnSe.png b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/ImutbF0YDoWldOxrPilcwQFHnSe.png new file mode 100644 index 000000000..32ab59bd3 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/ImutbF0YDoWldOxrPilcwQFHnSe.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/JNiLb7rksoY07ox092ycaarenGd.png b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/JNiLb7rksoY07ox092ycaarenGd.png new file mode 100644 index 000000000..d5b5018b2 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/JNiLb7rksoY07ox092ycaarenGd.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/L0aJb1V9DoETnNxrr1gcz0g0nDb.png b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/L0aJb1V9DoETnNxrr1gcz0g0nDb.png new file mode 100644 index 000000000..cc7603c71 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/L0aJb1V9DoETnNxrr1gcz0g0nDb.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/OpBcbf9UlooZ5UxZDwwcHZi8nWf.png b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/OpBcbf9UlooZ5UxZDwwcHZi8nWf.png new file mode 100644 index 000000000..717d3ea48 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/OpBcbf9UlooZ5UxZDwwcHZi8nWf.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/PSD8bf1fzoZkIUxJW7lc4XuGnee.png b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/PSD8bf1fzoZkIUxJW7lc4XuGnee.png new file mode 100644 index 000000000..b8aeaf4f3 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/PSD8bf1fzoZkIUxJW7lc4XuGnee.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/Tvjfb4qr4osyzxxPKdRcfn1knsd.png b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/Tvjfb4qr4osyzxxPKdRcfn1knsd.png new file mode 100644 index 000000000..77c986e9d Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/Tvjfb4qr4osyzxxPKdRcfn1knsd.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/Uo6ubaMwFo5bi1xVMU5cshlTn1g.png b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/Uo6ubaMwFo5bi1xVMU5cshlTn1g.png new file mode 100644 index 000000000..4abc2a9a8 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/Uo6ubaMwFo5bi1xVMU5cshlTn1g.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/XjdHbvC9ZotdQAx8GJoczwoancc.gif b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/XjdHbvC9ZotdQAx8GJoczwoancc.gif new file mode 100644 index 000000000..a43b0c671 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/blocks/static/XjdHbvC9ZotdQAx8GJoczwoancc.gif differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/fields/index.md b/docs/fr-FR/handbook/client/user/ui-designer/fields/index.md new file mode 100644 index 000000000..eef9de430 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/fields/index.md @@ -0,0 +1,59 @@ +### Fields + +In the UI, fields are field components that carry unit data, with different types of data presented by different field components. Fields can only be attached to blocks and cannot be used independently. + +#### Fields in Blocks + +Fields are generally not used alone but exist as sub-elements of data-type blocks. Data-type blocks typically have a "configure fields" option, and the field list is provided by the current data table. + +![](https://static-docs.nocobase.com/c5ea18ad1847332fe78075413f23de46.png) + +#### Field Designer (Toolbar) + +Like blocks, field components also have three icons in the upper right corner: + +- Drag to layout +- Quick add field +- Configure field parameters + +![](https://static-docs.nocobase.com/30cc5fcaeeb171862f79449a72a7fcf9.png) + +#### Field Layout + +The layout of fields within a block can be customized by dragging to move them. + +![](https://static-docs.nocobase.com/0825ea8c014c9073f505e74f707ded66.gif) + +#### General Parameter Configuration + +- Edit field title +- Display title +- Edit description +- Required +- Validation rules +- Set Default value +- Pattern + +![](https://static-docs.nocobase.com/cbb838c9e167f51636d6a0ad3b287b59.png) + +**Important Parameter Configuration:** + +##### Validation Rules + +(to be added) + +##### Default Value + +(to be added) + +##### Pattern + +Unlike blocks, field components have three display modes: + +- Editable +- Readonly (non-editable) +- Easy-reading (read mode) + +#### Field Types + +The fields in a block are provided by the data table. For more field type configurations, refer to [Data Table Field Types](https://nocobase.feishu.cn/wiki/BJKYw1xpHiVxFHkmgT3cKrKznkd). diff --git a/docs/fr-FR/handbook/client/user/ui-designer/fields/static/BpmibJbEgoijTgxHkqdcjodanVc.gif b/docs/fr-FR/handbook/client/user/ui-designer/fields/static/BpmibJbEgoijTgxHkqdcjodanVc.gif new file mode 100644 index 000000000..3205df33b Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/fields/static/BpmibJbEgoijTgxHkqdcjodanVc.gif differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/fields/static/MIcrb5RbUoGYoZxWazPcGMWInjc.png b/docs/fr-FR/handbook/client/user/ui-designer/fields/static/MIcrb5RbUoGYoZxWazPcGMWInjc.png new file mode 100644 index 000000000..270657578 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/fields/static/MIcrb5RbUoGYoZxWazPcGMWInjc.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/fields/static/P82Kbwh5moSEL5x5UeYcn6kIn3Y.png b/docs/fr-FR/handbook/client/user/ui-designer/fields/static/P82Kbwh5moSEL5x5UeYcn6kIn3Y.png new file mode 100644 index 000000000..2f16eb6e6 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/fields/static/P82Kbwh5moSEL5x5UeYcn6kIn3Y.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/fields/static/WBkubBX4QoUQ3HxPUHPcht2VnnK.png b/docs/fr-FR/handbook/client/user/ui-designer/fields/static/WBkubBX4QoUQ3HxPUHPcht2VnnK.png new file mode 100644 index 000000000..abb66a1a3 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/fields/static/WBkubBX4QoUQ3HxPUHPcht2VnnK.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/index.md b/docs/fr-FR/handbook/client/user/ui-designer/index.md new file mode 100644 index 000000000..a8b3bf346 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/index.md @@ -0,0 +1,15 @@ +# Interface Designer + +When the interface configuration button is activated, it enters the UI configuration state. + +![](https://static-docs.nocobase.com/0619e0aa0b24b81b8c08d7c572d3e0ba.jpg) + +### Components of the Interface Designer + +1. Menu +2. Page +3. Block + - Blocks without fields or operations + - Blocks with fields and operations +4. Fields (attached to blocks) +5. Operations (attached to blocks) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/menus/index.md b/docs/fr-FR/handbook/client/user/ui-designer/menus/index.md new file mode 100644 index 000000000..2bd12ae92 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/menus/index.md @@ -0,0 +1,49 @@ +### Menu + +#### Menu Item Types + +There are three built-in menu item types: + +- Group +- Page +- Link + +![](https://static-docs.nocobase.com/ccf6f42d3cc2677d440f9e33b9488d1c.png) + +##### Group + +When using a group, a submenu will appear on the left side. + +![](https://static-docs.nocobase.com/e59b2088fd68666cd240a26566616a3e.png) + +##### Page + +A page can be used to add various blocks. + +![](https://static-docs.nocobase.com/4cd259f6b79f6792df72ccc291da2af9.png) + +##### Link + +Used for URL redirection. + +![](https://static-docs.nocobase.com/80a6e6a875c565425224d9325332a1ad.png) + +#### Menu Item Designer + +In the upper right corner of each menu item, there are two icons: + +- Drag to move +- Configure menu item + +![](https://static-docs.nocobase.com/963ba10e36d04fd258fea0e996231f68.png) + +##### Menu Item Configuration + +![](https://static-docs.nocobase.com/0a9a05bd88d8bad9d711102a730f351d.png) + +- **Edit:** Modify the menu item title, icon, etc. +- **Move to:** Besides dragging to move, you can also use the "Move to" option to quickly relocate the menu item. +- **Insert before** +- **Insert after** +- **Insert inside** (only for group type) +- **Delete** diff --git a/docs/fr-FR/handbook/client/user/ui-designer/menus/static/Jp3NbdeVBojspWxvcWhcuDTlnOe.png b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/Jp3NbdeVBojspWxvcWhcuDTlnOe.png new file mode 100644 index 000000000..a2751410c Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/Jp3NbdeVBojspWxvcWhcuDTlnOe.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/menus/static/LTdGbCxxHopt9ix1Nuncj73VnQb.png b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/LTdGbCxxHopt9ix1Nuncj73VnQb.png new file mode 100644 index 000000000..f686eb3de Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/LTdGbCxxHopt9ix1Nuncj73VnQb.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/menus/static/OpdHbIbJ8oZX75x777ycylHxn1Q.png b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/OpdHbIbJ8oZX75x777ycylHxn1Q.png new file mode 100644 index 000000000..4a609a506 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/OpdHbIbJ8oZX75x777ycylHxn1Q.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/menus/static/SYzbbocHfoNFtsxomWJcUno7nog.png b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/SYzbbocHfoNFtsxomWJcUno7nog.png new file mode 100644 index 000000000..dc01db58a Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/SYzbbocHfoNFtsxomWJcUno7nog.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/menus/static/T0LTbjTBEo24UaxU9Btc6xgbnMf.png b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/T0LTbjTBEo24UaxU9Btc6xgbnMf.png new file mode 100644 index 000000000..197266e57 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/T0LTbjTBEo24UaxU9Btc6xgbnMf.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/menus/static/ZLYibDXwToMdqRxMTy4cyTion1f.png b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/ZLYibDXwToMdqRxMTy4cyTion1f.png new file mode 100644 index 000000000..a89a582a6 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/menus/static/ZLYibDXwToMdqRxMTy4cyTion1f.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/pages/index.md b/docs/fr-FR/handbook/client/user/ui-designer/pages/index.md new file mode 100644 index 000000000..a11795ba6 --- /dev/null +++ b/docs/fr-FR/handbook/client/user/ui-designer/pages/index.md @@ -0,0 +1,31 @@ +### Page + +#### Page Structure + +1. Page Designer +2. Page Title +3. Page Tabs (Subpages) +4. Page Body (Hosts blocks) + +![](https://static-docs.nocobase.com/0c84950f8d58246497da21fbdd2ffc6b.png) + +#### Page Designer + +![](https://static-docs.nocobase.com/19ce82228c9fb0681dcd9a73798b49f9.png) + +- **Enable page header:** Controls whether the header is displayed. +- **Display page title:** Controls whether the page title is displayed in the header. +- **Edit page title:** The default page title is the menu item title, but you can customize it. +- **Enable page tabs:** Tabs refer to the subpages of the page. + +#### Page Tabs + +After enabling page tabs, you can add subpages within the page. + +![](https://static-docs.nocobase.com/febacab3419e1a0ea98b178db63fa86d.png) + +#### Page Layout + +Multiple blocks can be arranged by dragging to adjust the layout. + +![](https://static-docs.nocobase.com/f6692295ac0917f3babce9a60ce80879.gif) diff --git a/docs/fr-FR/handbook/client/user/ui-designer/pages/static/C3xvb09t4oGOlhxxI5jcy2B7ncc.png b/docs/fr-FR/handbook/client/user/ui-designer/pages/static/C3xvb09t4oGOlhxxI5jcy2B7ncc.png new file mode 100644 index 000000000..ff6e6bf2c Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/pages/static/C3xvb09t4oGOlhxxI5jcy2B7ncc.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/pages/static/U0kXblh2Yo5S5hx91c2cYggrnYf.gif b/docs/fr-FR/handbook/client/user/ui-designer/pages/static/U0kXblh2Yo5S5hx91c2cYggrnYf.gif new file mode 100644 index 000000000..a43b0c671 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/pages/static/U0kXblh2Yo5S5hx91c2cYggrnYf.gif differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/pages/static/VpP2bTwhooaxrqxy5gYc4KJFnUc.png b/docs/fr-FR/handbook/client/user/ui-designer/pages/static/VpP2bTwhooaxrqxy5gYc4KJFnUc.png new file mode 100644 index 000000000..3a1725bca Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/pages/static/VpP2bTwhooaxrqxy5gYc4KJFnUc.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/pages/static/YPqEb1UEMoNzszxAHeDcNrsjnie.png b/docs/fr-FR/handbook/client/user/ui-designer/pages/static/YPqEb1UEMoNzszxAHeDcNrsjnie.png new file mode 100644 index 000000000..933e11052 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/pages/static/YPqEb1UEMoNzszxAHeDcNrsjnie.png differ diff --git a/docs/fr-FR/handbook/client/user/ui-designer/static/X8u0b5QJFomar7xbFTKceqIPngb.jpg b/docs/fr-FR/handbook/client/user/ui-designer/static/X8u0b5QJFomar7xbFTKceqIPngb.jpg new file mode 100644 index 000000000..23e19ebe1 Binary files /dev/null and b/docs/fr-FR/handbook/client/user/ui-designer/static/X8u0b5QJFomar7xbFTKceqIPngb.jpg differ diff --git a/docs/fr-FR/handbook/collection-expression/collection.md b/docs/fr-FR/handbook/collection-expression/collection.md new file mode 100644 index 000000000..7d58ec675 --- /dev/null +++ b/docs/fr-FR/handbook/collection-expression/collection.md @@ -0,0 +1,3 @@ +# Expression Collection + + diff --git a/docs/fr-FR/handbook/collection-fdw/enable-federated.md b/docs/fr-FR/handbook/collection-fdw/enable-federated.md new file mode 100644 index 000000000..df5ec4083 --- /dev/null +++ b/docs/fr-FR/handbook/collection-fdw/enable-federated.md @@ -0,0 +1,39 @@ +# How to Enable the Federated Engine in MySQL + +The MySQL database does not enable the federated module by default. You need to modify the my.cnf configuration. If you are using the Docker version, you can handle the extension situation through volumes: + +```yml +mysql: + image: mysql:8.1.0 + volumes: + - ./storage/mysql-conf:/etc/mysql/conf.d + environment: + MYSQL_DATABASE: nocobase + MYSQL_USER: nocobase + MYSQL_PASSWORD: nocobase + MYSQL_ROOT_PASSWORD: nocobase + restart: always + networks: + - nocobase +``` + +Create a new `./storage/mysql-conf/federated.cnf` file + +```conf +[mysqld] +federated +``` + +Restart MySQL + +```bash +docker compose up -d mysql +``` + +Check if federated is activated + +```sql +show engines +``` + +![Alt text](https://static-docs.nocobase.com/ac5d97cf902ad164e141633a41a23e46.png) diff --git a/docs/fr-FR/handbook/collection-fdw/image-1.png b/docs/fr-FR/handbook/collection-fdw/image-1.png new file mode 100644 index 000000000..28ad3aa62 Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image-1.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/image-10.png b/docs/fr-FR/handbook/collection-fdw/image-10.png new file mode 100644 index 000000000..3fa17d784 Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image-10.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/image-2.png b/docs/fr-FR/handbook/collection-fdw/image-2.png new file mode 100644 index 000000000..032241693 Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image-2.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/image-3.png b/docs/fr-FR/handbook/collection-fdw/image-3.png new file mode 100644 index 000000000..93c3e0631 Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image-3.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/image-4.png b/docs/fr-FR/handbook/collection-fdw/image-4.png new file mode 100644 index 000000000..72f11fdc5 Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image-4.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/image-5.png b/docs/fr-FR/handbook/collection-fdw/image-5.png new file mode 100644 index 000000000..01b08cd71 Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image-5.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/image-6.png b/docs/fr-FR/handbook/collection-fdw/image-6.png new file mode 100644 index 000000000..092b33cb6 Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image-6.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/image-7.png b/docs/fr-FR/handbook/collection-fdw/image-7.png new file mode 100644 index 000000000..793c6aef7 Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image-7.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/image-8.png b/docs/fr-FR/handbook/collection-fdw/image-8.png new file mode 100644 index 000000000..50a754339 Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image-8.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/image-9.png b/docs/fr-FR/handbook/collection-fdw/image-9.png new file mode 100644 index 000000000..26e966f7a Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image-9.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/image.png b/docs/fr-FR/handbook/collection-fdw/image.png new file mode 100644 index 000000000..332858e2c Binary files /dev/null and b/docs/fr-FR/handbook/collection-fdw/image.png differ diff --git a/docs/fr-FR/handbook/collection-fdw/index.md b/docs/fr-FR/handbook/collection-fdw/index.md new file mode 100644 index 000000000..09370b3b5 --- /dev/null +++ b/docs/fr-FR/handbook/collection-fdw/index.md @@ -0,0 +1,70 @@ +# Connect Foreign Data Tables(FDW) + + + +## Introduction + +This is a plugin that connects to remote data tables based on the foreign data wrapper of the database. Currently, it supports MySQL and PostgreSQL databases. + +:::info{title="Connecting Data Sources vs Connecting External Data Tables"} +- **Connecting data sources** refers to establishing a connection with a specific database or API service, and you can fully use the features of the database or the services provided by the API; +- **Connecting external data tables** refers to obtaining data from the outside and mapping it for local use. In the database, it is called FDW (Foreign Data Wrapper), which is a database technology that focuses on using remote tables as local tables and can only connect one by one. Because it is remote access, there will be various constraints and limitations when using it. +- +The two can also be used in combination. The former is used to establish a connection with the data source, and the latter is used for cross data-source access. For example, a certain PostgreSQL data source is connected, and a certain table in this data source is an external data table created based on FDW. +::: + +### MySQL + +MySQL uses the `federated` engine, which needs to be activated, and supports connecting to remote MySQL and protocol-compatible databases, such as MariaDB. For more details, refer to the [Federated Storage Engine](https://dev.mysql.com/doc/refman/8.0/en/federated-storage-engine.html) documentation. + +### PostgreSQL + +In PostgreSQL, different types of `fdw` extensions can be used to support different types of remote data. The currently supported extensions include: + +- [postgres_fdw](https://www.postgresql.org/docs/current/postgres-fdw.html): Connect to a remote PostgreSQL database in PostgreSQL. +- [mysql_fdw(under development)](https://github.com/EnterpriseDB/mysql_fdw): Connect to a remote MySQL database in PostgreSQL. +- For other types of fdw extensions, refer to [PostgreSQL Foreign Data Wrappers](https://wiki.postgresql.org/wiki/Foreign_data_wrappers). You need to implement the corresponding adaptation interface in the code. + +## Installation + +Prerequisites + +- If the Main database of NocoBase is MySQL, it needs to activate `federated`. Refer to [How to enable the federated engine in MySQL](./enable-federated.md) + +Then install and activate the plugin through the plugin manager + +![Install and activate the plugin](https://static-docs.nocobase.com/f84276c5712851fb3ff33af3f1ff0f59.png) + +## User Manual + +Under "Collection manager > Create collection", select "Connect to foreign data" + +![Connect External Data](https://static-docs.nocobase.com/029d946a6d067d1c35a39755219d623c.png) + +In the "Database Server" dropdown, select an existing database service, or "Create Database Server" + +![Database Service](https://static-docs.nocobase.com/766271708a911950a5599d60d6be4a4d.png) + +Create a database server + +![Create Database Service](https://static-docs.nocobase.com/1e357216e04cc4f200bd6212827281c8.png) + +After selecting the database server, in the "Remote table" dropdown, select the data table you need to connect. + +![Select the data table you need to connect](https://static-docs.nocobase.com/e91fd6152b52b4fc01b3808053cc8dc4.png) + +Configure field information + +![Configure field information](https://static-docs.nocobase.com/e618fecc5fe327f6a495e61405e5f040.png) + +If the remote table has structural changes, you can also "Sync from remote table" + +![Sync from Remote Table](https://static-docs.nocobase.com/3751a9a39f933889fb3fcc4d85a6f4ad.png) + +Remote table sync + +![Remote table sync](https://static-docs.nocobase.com/13f18200e31ea223fdd8dadaff1e9d28.png) + +Finally, display it on the interface + +![Display on the interface](https://static-docs.nocobase.com/368fca27a99277d9360ca81350949357.png) diff --git a/docs/fr-FR/handbook/collection-sql/index.md b/docs/fr-FR/handbook/collection-sql/index.md new file mode 100644 index 000000000..92d22146f --- /dev/null +++ b/docs/fr-FR/handbook/collection-sql/index.md @@ -0,0 +1,56 @@ +# SQL Collection + + + +## Introduction + +The SQL collection provides a powerful method for retrieving data using SQL queries. By extracting data fields through SQL queries and configuring the associated field metadata, users can utilize these fields as though they were working with a standard table. This feature is particularly beneficial for scenarios involving complex join queries, statistical analysis, and more. + +## User Manual + +### Creating a New SQL Collection + + + +1. Enter your SQL query in the provided input box and click Execute. The system will analyze the query to determine the tables and fields involved, automatically extracting the relevant field metadata from the source tables. + + + +2. If the system's analysis of the source tables and fields is incorrect, you can manually select the appropriate tables and fields to ensure the correct metadata is used. Start by selecting the source table, then choose the corresponding fields in the field source section below. + + + +3. For fields that do not have a direct source, the system will infer the field type based on the data type. If this inference is incorrect, you can manually select the proper field type. + + + +4. As you configure each field, you can preview its display in the preview area, allowing you to see the immediate impact of your settings. + + + +5. After you have completed the configuration and confirmed that everything is correct, click the Confirm button below the SQL input box to finalize the submission. + + + +### Editing + +1. If you need to modify the SQL query, click the Edit button to directly alter the SQL statement and reconfigure the fields as needed. + +2. To adjust the field metadata, use the Configure Fields option, which allows you to update the field settings just as you would for a regular table. + +### Synchronization + +If the SQL query remains unchanged but the underlying database table structure has been modified, you can synchronize and reconfigure the fields by selecting Configure Fields - Sync from Database. + + + +### Comparison Between SQL collection and Linked Database Views + +| Template Type | Best Suited For | Implementation Method | Support for CRUD Operations | +|--------------------------| -------------------------------------------------------------------------------------------- | ---------------------- | ---------------------------- | +| SQL | Simple models, lightweight use cases
    Limited interaction with the database
    Avoiding maintenance of views
    Prefer UI-driven operations | SQL subquery | Not Supported | +| Connect to database view | Complex models
    Requires database interaction
    Data modification needed
    Requires stronger and more stable database support | Database view | Partially Supported | + +:::warning +When using SQL collection, be sure to select tables that are manageable within NocoBase. Using tables from the same database that are not connected to NocoBase may lead to inaccurate SQL query parsing. If this is a concern, consider creating and linking to a view. +::: diff --git a/docs/fr-FR/handbook/collection-tree/index.md b/docs/fr-FR/handbook/collection-tree/index.md new file mode 100644 index 000000000..690e00cf8 --- /dev/null +++ b/docs/fr-FR/handbook/collection-tree/index.md @@ -0,0 +1,13 @@ +# Tree Collection + + + +## Introduction + +A tree structure collection is a data collection design pattern used for organizing hierarchical data. This collection structure mirrors a tree, where each data item may have one or more child items, and those child items can, in turn, have their own descendants. + +## User Manual + +![20240324143228](https://static-docs.nocobase.com/20240324143228.png) + +![20240324143555](https://static-docs.nocobase.com/20240324143555.png) diff --git a/docs/fr-FR/handbook/collection-view/index.md b/docs/fr-FR/handbook/collection-view/index.md new file mode 100644 index 000000000..f8ab4c101 --- /dev/null +++ b/docs/fr-FR/handbook/collection-view/index.md @@ -0,0 +1,9 @@ +# Database view + + + +## Introduction + +## Manu book + +![20240324145718](https://static-docs.nocobase.com/20240324145718.png) diff --git a/docs/fr-FR/handbook/custom-brand/index.md b/docs/fr-FR/handbook/custom-brand/index.md new file mode 100644 index 000000000..6c0c43e45 --- /dev/null +++ b/docs/fr-FR/handbook/custom-brand/index.md @@ -0,0 +1,35 @@ +# Custom Brand + + + +## Introduction + +The default brand name is "NocoBase", which is primarily displayed in the following three places as shown in the images: + +![20240409111100](https://static-docs.nocobase.com/20240409111100.png) + +On the bottom of the login page: + +![20240409111254](https://static-docs.nocobase.com/20240409111254.png) + +The logo at position number 1 can be configured via the system settings under the Logo option. Positions number 2 and 3 can be customized using this plugin. + +## User Guide + +After activating the plugin, you can access the configuration page by clicking on the 'Custom Brand' menu in the upper right corner of the page. + +![20240409113640](https://static-docs.nocobase.com/20240409113640.png) + +The `Brand` option is used to set the text at the bottom of the login page (position number 3), while the `About` option is used to configure the content of the menu in the upper right corner (as shown in the image below). + +![20240409113915](https://static-docs.nocobase.com/20240409113915.png) + +HTML is used for the configuration to allow users more flexibility in customizing their content. However, if you only need to make simple text changes, you can directly modify the existing content, as shown in the image below: + +![20240409114740](https://static-docs.nocobase.com/20240409114740.png) + +### Favicon(v1.2.23-alpha) + +In v1.2.23-alpha, we added the ability to set a favicon as shown below: + +![350438864-08053d02-5429-407f-a3f7-fed439993623](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/350438864-08053d02-5429-407f-a3f7-fed439993623.gif) diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/collection-select.md b/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/collection-select.md new file mode 100644 index 000000000..353d7a645 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/collection-select.md @@ -0,0 +1,10 @@ +# Collection Select + +## Introduction + +## Field configuration + +![20240512174047](https://static-docs.nocobase.com/20240512174047.png) + +## Instructions + diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/json.md b/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/json.md new file mode 100644 index 000000000..e560ebadf --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/json.md @@ -0,0 +1,11 @@ +# JSON + +## Introduction + +## Field configuration + +![20240512173905](https://static-docs.nocobase.com/20240512173905.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/nano-id.md b/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/nano-id.md new file mode 100644 index 000000000..423dd46dc --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/nano-id.md @@ -0,0 +1,11 @@ +# Nano ID + +## Introduction + +## Field configuration + +![20240512173225](https://static-docs.nocobase.com/20240512173225.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/sort.md b/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/sort.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/uuid.md b/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/uuid.md new file mode 100644 index 000000000..4ab7b9d4f --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/advanced/uuid.md @@ -0,0 +1,11 @@ +# UUID + +## Introduction + +## Field configuration + +![20240512173354](https://static-docs.nocobase.com/20240512173354.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/index.md b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/index.md new file mode 100644 index 000000000..ce74e1fcb --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/index.md @@ -0,0 +1,12 @@ +# Relationship Fields + +In NocoBase, relationship fields are not actual fields but are used to establish connections between collections. This concept is equivalent to relationships in relational databases. + +In relational databases, the most common types of relationships include the following: + +- [One-to-One](./o2o/index.md): Each entity in two collections corresponds to only one entity in the other collection. This type of relationship is usually used to store different aspects of an entity in separate collections to reduce redundancy and improve data consistency. +- [One-to-Many](./o2m/index.md): Each entity in one collection can be associated with multiple entities in another collection. This is one of the most common relationship types. For example, one author can write multiple articles, but each article can have only one author. +- [Many-to-One](./m2o/index.md): Multiple entities in one collection can be associated with one entity in another collection. This type of relationship is also common in data modeling. For instance, multiple students can belong to the same class. +- [Many-to-Many](./m2m/index.md): Multiple entities in two collections can be associated with each other. This type of relationship typically requires an intermediary collection to record the associations between the entities. For example, the relationship between students and courses—a student can enroll in multiple courses, and a course can have multiple students. + +These types of relationships play an important role in database design and data modeling, helping to describe complex real-world relationships and data structures. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/image-1.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/image-1.png new file mode 100644 index 000000000..56fad3132 Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/image-1.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/image-2.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/image-2.png new file mode 100644 index 000000000..c221def54 Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/image-2.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/image.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/image.png new file mode 100644 index 000000000..f4796caaa Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/image.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/index.md b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/index.md new file mode 100644 index 000000000..a674cf7dc --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2m/index.md @@ -0,0 +1,50 @@ +# Many-to-Many + +In a course enrollment system, there are two entities: students and courses. A student can enroll in multiple courses, and a course can have multiple students enrolled, constituting a many-to-many relationship. In a relational database, to represent the many-to-many relationship between students and courses, an intermediary collection, such as an enrollment collection, is usually used. This collection can record which courses each student has chosen and which students have enrolled in each course. This design effectively represents the many-to-many relationship between students and courses. + +ER Diagram: + +![alt text](https://static-docs.nocobase.com/0e9921228e1ee375dc639431bb89782c.png) + +Field Configuration: + +![alt text](https://static-docs.nocobase.com/8e2739ac5d44fb46f30e2da42ca87a82.png) + +## Parameter Description + +### Source Collection + +The source collection, which is the collection where the current field resides. + +### Target Collection + +The target collection, which is the collection to be associated with. + +### Through Collection + +The intermediary collection, used when a many-to-many relationship exists between two entities. The intermediary collection has two foreign keys that are used to maintain the association between the two entities. + +### Source Key + +The field in the source collection that is referenced by the foreign key. It must be unique. + +### Foreign Key 1 + +The field in the intermediary collection that establishes the association with the source collection. + +### Foreign Key 2 + +The field in the intermediary collection that establishes the association with the target collection. + +### Target Key + +The field in the target collection that is referenced by the foreign key. It must be unique. + +### ON DELETE + +ON DELETE refers to the rules applied to foreign key references in related child collections when records in the parent collection are deleted. It is an option used when defining a foreign key constraint. Common ON DELETE options include: + +- **CASCADE**: When a record in the parent collection is deleted, all related records in the child collection are automatically deleted. +- **SET NULL**: When a record in the parent collection is deleted, the foreign key values in the related child collection records are set to NULL. +- **RESTRICT**: The default option, it prevents the deletion of a parent collection record if there are related records in the child collection. +- **NO ACTION**: Similar to RESTRICT, it prevents the deletion of a parent collection record if there are related records in the child collection. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/image-1.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/image-1.png new file mode 100644 index 000000000..4b5520d27 Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/image-1.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/image-2.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/image-2.png new file mode 100644 index 000000000..de2fbe022 Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/image-2.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/image.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/image.png new file mode 100644 index 000000000..5dc4e6807 Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/image.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/index.md b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/index.md new file mode 100644 index 000000000..536c8d12f --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/m2o/index.md @@ -0,0 +1,38 @@ +# Many-to-One + +In a library database, there are two entities: books and authors. An author can write multiple books, but each book usually has only one author. In this case, the relationship between authors and books is many-to-one. Multiple books can be associated with the same author, but each book can have only one author. + +ER Diagram: + +![alt text](https://static-docs.nocobase.com/eaeeac974844db05c75cf0deeedf3652.png) + +Field Configuration: + +![alt text](https://static-docs.nocobase.com/3b4484ebb98d82f832f3dbf752bd84c9.png) + +## Parameter Description + +### Source Collection + +The source collection, which is the collection where the current field resides. + +### Target Collection + +The target collection, which is the collection to be associated with. + +### Foreign Key + +The field in the source collection that is used to establish the association between the two collections. + +### Target Key + +The field in the target collection that is referenced by the foreign key. It must be unique. + +### ON DELETE + +ON DELETE refers to the rules applied to foreign key references in related child collections when records in the parent collection are deleted. It is an option used when defining a foreign key constraint. Common ON DELETE options include: + +- **CASCADE**: When a record in the parent collection is deleted, all related records in the child collection are automatically deleted. +- **SET NULL**: When a record in the parent collection is deleted, the foreign key values in the related child collection records are set to NULL. +- **RESTRICT**: The default option, it prevents the deletion of a parent collection record if there are related records in the child collection. +- **NO ACTION**: Similar to RESTRICT, it prevents the deletion of a parent collection record if there are related records in the child collection. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2m/image-1.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2m/image-1.png new file mode 100644 index 000000000..b66a9543e Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2m/image-1.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2m/image.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2m/image.png new file mode 100644 index 000000000..2e40cab89 Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2m/image.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2m/index.md b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2m/index.md new file mode 100644 index 000000000..c620df3dd --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2m/index.md @@ -0,0 +1,42 @@ +# One-to-Many + +The relationship between a class and its students is an example of a one-to-many relationship: one class can have multiple students, but each student belongs to only one class. + +ER Diagram: + +![alt text](https://static-docs.nocobase.com/9475f044d123d28ac8e56a077411f8dc.png) + +Field Configuration: + +![alt text](https://static-docs.nocobase.com/a608ce54821172dad7e8ab760107ff4e.png) + +## Parameter Description + +### Source Collection + +The source collection, which is the collection where the current field resides. + +### Target Collection + +The target collection, which is the collection to be associated with. + +### Source Key + +The field in the source collection that is referenced by the foreign key. It must be unique. + +### Foreign Key + +The field in the target collection that is used to establish the association between the two collections. + +### Target Key + +The field in the target collection used to view each row record in the relationship block, usually a unique field. + +### ON DELETE + +ON DELETE refers to the rules applied to foreign key references in related child collections when records in the parent collection are deleted. It is an option used when defining a foreign key constraint. Common ON DELETE options include: + +- **CASCADE**: When a record in the parent collection is deleted, all related records in the child collection are automatically deleted. +- **SET NULL**: When a record in the parent collection is deleted, the foreign key values in the related child collection records are set to NULL. +- **RESTRICT**: The default option, it prevents the deletion of a parent collection record if there are related records in the child collection. +- **NO ACTION**: Similar to RESTRICT, it prevents the deletion of a parent collection record if there are related records in the child collection. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image-1.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image-1.png new file mode 100644 index 000000000..16a4f8591 Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image-1.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image-2.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image-2.png new file mode 100644 index 000000000..5cd4b9802 Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image-2.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image-3.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image-3.png new file mode 100644 index 000000000..003b1ae97 Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image-3.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image.png b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image.png new file mode 100644 index 000000000..72a5e325e Binary files /dev/null and b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/image.png differ diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/index.md b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/index.md new file mode 100644 index 000000000..7898c56f2 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/associations/o2o/index.md @@ -0,0 +1,62 @@ +# One-to-One + +In the relationship between employees and personal profiles, each employee can only have one personal profile record, and each personal profile record can only correspond to one employee. In this case, the relationship between the employee and the personal profile is one-to-one. + +The foreign key in a one-to-one relationship can be placed in either the source collection or the target collection. If it represents "having one," the foreign key is more appropriately placed in the target collection; if it represents "belonging to," then the foreign key is better placed in the source collection. + +For example, in the case mentioned above, where an employee has only one personal profile and the personal profile belongs to the employee, it is appropriate to place the foreign key in the personal profile collection. + +## One-to-One (Having One) + +This indicates that an employee has a personal profile record. + +ER Relationship + +![alt text](https://static-docs.nocobase.com/4359e128936bbd7c9ff51bcff1d646dd.png) + +Field Configuration + +![alt text](https://static-docs.nocobase.com/7665a87e094b4fb50c9426a108f87105.png) + +## One-to-One (Belonging Relationship) + +This indicates that a personal profile belongs to a specific employee. + +ER Relationship + +![](https://static-docs.nocobase.com/31e7cc3e630220cf1e98753ca24ac72d.png) + +Field Configuration + +![alt text](https://static-docs.nocobase.com/4f09eeb3c7717d61a349842da43c187c.png) + +## Parameter Descriptions + +### Source Collection + +The source collection, which is the collection where the current field is located. + +### Target Collection + +The target collection, the collection that is being related. + +### Foreign Key + +Used to establish a relationship between two collections. In a one-to-one relationship, the foreign key can be placed in either the source collection or the target collection. If it represents "having one," the foreign key is more appropriately placed in the target collection; if it represents "belonging to," then the foreign key is better placed in the source collection. + +### Source Key <- Foreign Key (Foreign Key in the Target collection) + +The field referenced by the foreign key constraint must be unique. When the foreign key is placed in the target collection, it indicates "having one." + +### Target Key <- Foreign Key (Foreign Key in the Source collection) + +The field referenced by the foreign key constraint must be unique. When the foreign key is placed in the source collection, it indicates a "belonging relationship." + +### ON DELETE + +ON DELETE refers to the action rules for the foreign key reference in the related child collection when deleting records from the parent collection. It is an option defined when establishing a foreign key constraint. Common ON DELETE options include: + +- CASCADE: When a record in the parent collection is deleted, automatically delete all related records in the child collection. +- SET NULL: When a record in the parent collection is deleted, set the foreign key value in the related child collection to NULL. +- RESTRICT: The default option, where deletion of a parent collection record is refused if there are related records in the child collection. +- NO ACTION: Similar to RESTRICT, deletion of a parent collection record is refused if there are related records in the child collection. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/color.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/color.md new file mode 100644 index 000000000..b3e483925 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/color.md @@ -0,0 +1,11 @@ +# Color + +## Introduction + +## Field configuration + +![20240512175956](https://static-docs.nocobase.com/20240512175956.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/email.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/email.md new file mode 100644 index 000000000..7d2354179 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/email.md @@ -0,0 +1,11 @@ +# Email + +## Introduction + +## Field configuration + +![20240512175609](https://static-docs.nocobase.com/20240512175609.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/icon.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/icon.md new file mode 100644 index 000000000..9dfd549e3 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/icon.md @@ -0,0 +1,11 @@ +# Icon + +## Introduction + +## Field configuration + +![20240512180027](https://static-docs.nocobase.com/20240512180027.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/input.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/input.md new file mode 100644 index 000000000..f05fba6ab --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/input.md @@ -0,0 +1,17 @@ +# Input + +## Introduction + +## Field configuration + +![20240512163555](https://static-docs.nocobase.com/20240512163555.png) + +## UI interface configuration + +Edit mode + +![20240512164001](https://static-docs.nocobase.com/20240512164001.png) + +Read mode + +![20240512164138](https://static-docs.nocobase.com/20240512164138.png) diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/integer.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/integer.md new file mode 100644 index 000000000..3f9eb8992 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/integer.md @@ -0,0 +1,11 @@ +# Integer + +## Introduction + +## Field configuration + +![20240512175723](https://static-docs.nocobase.com/20240512175723.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/number.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/number.md new file mode 100644 index 000000000..385807d73 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/number.md @@ -0,0 +1,11 @@ +# Number + +## Introduction + +## Field configuration + +![20240512175752](https://static-docs.nocobase.com/20240512175752.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/password.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/password.md new file mode 100644 index 000000000..4c3302c91 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/password.md @@ -0,0 +1,11 @@ +# Password + +## Introduction + +## Field configuration + +![20240512175917](https://static-docs.nocobase.com/20240512175917.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/percent.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/percent.md new file mode 100644 index 000000000..5f562c13b --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/percent.md @@ -0,0 +1,11 @@ +# Percent + +## Introduction + +## Field configuration + +![20240512175847](https://static-docs.nocobase.com/20240512175847.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/phone.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/phone.md new file mode 100644 index 000000000..0fce031f1 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/phone.md @@ -0,0 +1,11 @@ +# Phone + +## Introduction + +## Field configuration + +![20240512175526](https://static-docs.nocobase.com/20240512175526.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/textarea.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/textarea.md new file mode 100644 index 000000000..8f2bf0794 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/textarea.md @@ -0,0 +1,17 @@ +# TextArea + +## Introduction + +## Field configuration + +![20240512165017](https://static-docs.nocobase.com/20240512165017.png) + +## UI interface configuration + +Edit mode + +![20240512164001](https://static-docs.nocobase.com/20240512164001.png) + +Read mode + +![20240512164138](https://static-docs.nocobase.com/20240512164138.png) diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/basic/url.md b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/url.md new file mode 100644 index 000000000..87290eedd --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/basic/url.md @@ -0,0 +1,11 @@ +# URL + +## Introduction + +## Field configuration + +![20240512175641](https://static-docs.nocobase.com/20240512175641.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/choices/checkbox-group.md b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/checkbox-group.md new file mode 100644 index 000000000..5e28e2831 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/checkbox-group.md @@ -0,0 +1,9 @@ +# Checkbox-group + +## Introduction + +## Field configuration + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/choices/checkbox.md b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/checkbox.md new file mode 100644 index 000000000..40d56d4b5 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/checkbox.md @@ -0,0 +1,11 @@ +# Checkbox + +## Introduction + +## Field configuration + +![20240512180122](https://static-docs.nocobase.com/20240512180122.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/choices/china-region.md b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/china-region.md new file mode 100644 index 000000000..ed8bdac0f --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/china-region.md @@ -0,0 +1,11 @@ +# China Region + +## Introduction + +## Field configuration + +![20240512180305](https://static-docs.nocobase.com/20240512180305.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/choices/multiple-select.md b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/multiple-select.md new file mode 100644 index 000000000..b9da834ac --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/multiple-select.md @@ -0,0 +1,11 @@ +# Multiple Select + +## Introduction + +## Field configuration + +![20240512180236](https://static-docs.nocobase.com/20240512180236.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/choices/radio-group.md b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/radio-group.md new file mode 100644 index 000000000..ed9f4cdf6 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/radio-group.md @@ -0,0 +1,9 @@ +# Radio Group + +## Introduction + +## Field configuration + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/choices/select.md b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/select.md new file mode 100644 index 000000000..bcd01f4bb --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/choices/select.md @@ -0,0 +1,11 @@ +# Select (single) + +## Introduction + +## Field configuration + +![20240512180203](https://static-docs.nocobase.com/20240512180203.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/date.md b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/date.md new file mode 100644 index 000000000..c98f9450a --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/date.md @@ -0,0 +1,11 @@ +# Date + +## Introduction + +## Field configuration + +![20240512181142](https://static-docs.nocobase.com/20240512181142.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/datetime-without-tz.md b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/datetime-without-tz.md new file mode 100644 index 000000000..17b998539 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/datetime-without-tz.md @@ -0,0 +1,11 @@ +# Datetime(without time zone) + +## Introduction + +## Field configuration + +![20240512181142](https://static-docs.nocobase.com/20240512181142.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/datetime.md b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/datetime.md new file mode 100644 index 000000000..7b2c6e9b8 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/datetime.md @@ -0,0 +1,11 @@ +# Datetime(with time zone) + +## Introduction + +## Field configuration + +![20240512181142](https://static-docs.nocobase.com/20240512181142.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/index.md b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/index.md new file mode 100644 index 000000000..1b7694068 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/index.md @@ -0,0 +1,68 @@ +# DateTime Field Types + +DateTime field types can be categorized as follows: + +- **DateTime (with Time Zone):** These values are standardized to UTC (Coordinated Universal Time) and are subject to time zone adjustments when necessary. +- **DateTime (without Time Zone):** This type stores date and time data without incorporating any time zone information. +- **Date (without Time):** This format exclusively stores date information, omitting any time component. +- **Time:** Stores only time information, excluding the date. +- **Unix Timestamp:** This type represents the number of seconds that have elapsed since January 1, 1970, and is stored as a Unix timestamp. + +Here are examples for each DateTime-related field type: + +| **Field Type** | **Example Value** | **Description** | +|------------------------------|------------------------------|-------------------------------------------------------| +| DateTime (with Time Zone) | 2024-08-24T07:30:00.000Z | Converted to UTC and can be adjusted for time zones | +| DateTime (without Time Zone) | 2024-08-24 15:30:00 | Stores date and time without time zone considerations | +| Date (without Time) | 2024-08-24 | Captures only the date, with no time information | +| Time | 15:30:00 | Captures only the time, excluding any date details | +| Unix Timestamp | 1724437800 | Represents seconds since 1970-01-01 00:00:00 UTC | + +## Data Source Comparisons + +Below is a comparison table for NocoBase, MySQL, and PostgreSQL: + +| **Field Type** | **NocoBase** | **MySQL** | **PostgreSQL** | +|-------------------------------|----------------------------|----------------------------|----------------------------------------| +| DateTime (with Time Zone) | Datetime with timezone | TIMESTAMP
    DATETIME | TIMESTAMP WITH TIME ZONE | +| DateTime (without Time Zone) | Datetime without timezone | DATETIME | TIMESTAMP WITHOUT TIME ZONE | +| Date (without Time) | Date | DATE | DATE | +| Time | Time | TIME | TIME WITHOUT TIME ZONE | +| Unix Timestamp | Unix timestamp | INTEGER
    BIGINT | INTEGER
    BIGINT | +| Time (with Time Zone) | - | - | TIME WITH TIME ZONE | + +**Note:** +- MySQL’s TIMESTAMP type covers a range between `1970-01-01 00:00:01 UTC` and `2038-01-19 03:14:07 UTC`. For dates and times outside this range, it is recommended to use DATETIME or BIGINT to store Unix timestamps. + +## DateTime Storage Processing Workflow + +### With Time Zone + +This includes `DateTime (without Time Zone)` and `Unix Timestamp`. + +![20240824191933](https://static-docs.nocobase.com/20240824191933.png) + +**Note:** +- To accommodate a broader range of dates, NocoBase uses the DATETIME type in MySQL for DateTime (with Time Zone) fields. The date value stored is converted based on the server's TZ environment variable, meaning that if the TZ environment variable changes, the stored DateTime value will also change. +- Since there is a time zone difference between UTC and local time, directly displaying the raw UTC value could lead to user confusion. + +### Without Time Zone + +![20240824185600](https://static-docs.nocobase.com/20240824185600.png) + +## UTC + +UTC (Coordinated Universal Time) is the global time standard used to coordinate and synchronize time worldwide. It is a highly precise time standard, maintained by atomic clocks, and synchronized with the Earth's rotation. + +The difference between UTC and local time can cause confusion when displaying raw UTC values. For example: + +| **Time Zone** | **DateTime** | +|-----------------|---------------------------------| +| UTC | 2024-08-24T07:30:00.000Z | +| UTC+8 | 2024-08-24 15:30:00 | +| UTC+5 | 2024-08-24 12:30:00 | +| UTC-5 | 2024-08-24 02:30:00 | +| UTC+0 | 2024-08-24 07:30:00 | +| UTC-6 | 2024-08-23 01:30:00 | + +These different times all correspond to the same moment, merely expressed in various time zones. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/time.md b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/time.md new file mode 100644 index 000000000..10dcd3fb1 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/time.md @@ -0,0 +1,11 @@ +# time + +## Introduction + +## Field configuration + +![20240512181216](https://static-docs.nocobase.com/20240512181216.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/unix-timestamp.md b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/unix-timestamp.md new file mode 100644 index 000000000..5d7d5d137 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/datetime/unix-timestamp.md @@ -0,0 +1,11 @@ +# Unix timestamp + +## Introduction + +## Field configuration + +![20240512180432](https://static-docs.nocobase.com/20240512180432.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/circle.md b/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/circle.md new file mode 100644 index 000000000..6732ff47f --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/circle.md @@ -0,0 +1,11 @@ +# Circle + +## Introduction + +## Field configuration + +![20240512181522](https://static-docs.nocobase.com/20240512181522.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/line.md b/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/line.md new file mode 100644 index 000000000..b0a19d42a --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/line.md @@ -0,0 +1,11 @@ +# Line + +## Introduction + +## Field configuration + +![20240512181454](https://static-docs.nocobase.com/20240512181454.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/point.md b/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/point.md new file mode 100644 index 000000000..34849706a --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/point.md @@ -0,0 +1,11 @@ +# Point + +## Introduction + +## Field configuration + +![20240512181420](https://static-docs.nocobase.com/20240512181420.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/polygon.md b/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/polygon.md new file mode 100644 index 000000000..b6b8610ae --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/geometric/polygon.md @@ -0,0 +1,11 @@ +# Polygon + +## Introduction + +## Field configuration + +![20240512181547](https://static-docs.nocobase.com/20240512181547.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/index.md b/docs/fr-FR/handbook/data-modeling/collection-fields/index.md new file mode 100644 index 000000000..8e8b48da5 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/index.md @@ -0,0 +1,29 @@ +# Overview + +## Interface Types of Fields + +NocoBase classifies fields into the following categories from the Interface perspective: + +![20240512110352](https://static-docs.nocobase.com/20240512110352.png) + +## Field Data Types + +Each Field Interface has a default data type. For instance, for fields with the Interface as a Number, the default data type is double, but it can also be float, decimal, etc. The data types currently supported are: + +![20240512103733](https://static-docs.nocobase.com/20240512103733.png) + +## Field Type Mapping + +The process for adding new fields to the main database is as follows: + +1. Select the Interface type +2. Configure the optional data type for the current Interface + +![20240512172416](https://static-docs.nocobase.com/20240512172416.png) + +The process for field mapping from external data sources is: + +1. Automatically map the corresponding data type (Field type) and UI type (Field Interface) based on the field type of the external database. +2. Modify to a more suitable data type and Interface type as needed + +![20240512172759](https://static-docs.nocobase.com/20240512172759.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/media/field-attachment.md b/docs/fr-FR/handbook/data-modeling/collection-fields/media/field-attachment.md new file mode 100644 index 000000000..8db826302 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/media/field-attachment.md @@ -0,0 +1,3 @@ +# Attachment Field + + diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/media/markdown.md b/docs/fr-FR/handbook/data-modeling/collection-fields/media/markdown.md new file mode 100644 index 000000000..a29f50623 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/media/markdown.md @@ -0,0 +1,11 @@ +# Markdown + +## Introduction + +## Field configuration + +![20240512181311](https://static-docs.nocobase.com/20240512181311.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/media/rich-text.md b/docs/fr-FR/handbook/data-modeling/collection-fields/media/rich-text.md new file mode 100644 index 000000000..04c63bdfb --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/media/rich-text.md @@ -0,0 +1,11 @@ +# Rich Text + +## Introduction + +## Field configuration + +![20240512181002](https://static-docs.nocobase.com/20240512181002.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/system-info/created-at.md b/docs/fr-FR/handbook/data-modeling/collection-fields/system-info/created-at.md new file mode 100644 index 000000000..56ed22e8d --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/system-info/created-at.md @@ -0,0 +1,11 @@ +# Created At + +## Introduction + +## Field configuration + +![20240512174347](https://static-docs.nocobase.com/20240512174347.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/system-info/table-oid.md b/docs/fr-FR/handbook/data-modeling/collection-fields/system-info/table-oid.md new file mode 100644 index 000000000..db0f15100 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/system-info/table-oid.md @@ -0,0 +1,11 @@ +# Table OID + +## Introduction + +## Field configuration + +![20240512174746](https://static-docs.nocobase.com/20240512174746.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection-fields/system-info/updated-at.md b/docs/fr-FR/handbook/data-modeling/collection-fields/system-info/updated-at.md new file mode 100644 index 000000000..2d06b995c --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection-fields/system-info/updated-at.md @@ -0,0 +1,11 @@ +# Updated At + +## Introduction + +## Field configuration + +![20240512174826](https://static-docs.nocobase.com/20240512174826.png) + +## Instructions + +to be added. diff --git a/docs/fr-FR/handbook/data-modeling/collection.md b/docs/fr-FR/handbook/data-modeling/collection.md new file mode 100644 index 000000000..8a122f4dc --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/collection.md @@ -0,0 +1,17 @@ +# Overview + +NocoBase provides a unique DSL to describe the structure of data, known as Collection, which unifies the data structure from various sources, providing a reliable foundation for data management, analysis, and application. + +![20240512161522](https://static-docs.nocobase.com/20240512161522.png) + +To conveniently use various data models, it supports various types of collections: + +- [General collection](/handbook/data-source-main/general-collection): Built-in common system fields; +- [Inheritance collection](/handbook/data-source-main/inheritance-collection): You can create a parent collection and then derive a child collection from the parent collection. The child collection will inherit the structure of the parent collection and can also define its own columns. +- [Tree collection](/handbook/collection-tree): Tree structure collection, currently only supports adjacency collection design; +- [Calendar Tabcollectionle](/handbook/calendar/calendar-collection): Used to create calendar-related event collections; +- [File collection](/handbook/file-manager/file-collection): Used for file storage management; +- [Expression collection](/handbook/workflow-dynamic-calculation/expression): Used for dynamic expression scenarios in workflows; +- [SQL collection](/handbook/collection-sql): Not an actual database collection, but quickly presents SQL queries in a structured manner; +- [Connect to database view](/handbook/collection-view): Connects to existing database views; +- [Connect to foreign data](/handbook/collection-fdw): Allows the database system to directly access and query data in external data sources, based on FDW technology. \ No newline at end of file diff --git a/docs/fr-FR/handbook/data-modeling/data-source.md b/docs/fr-FR/handbook/data-modeling/data-source.md new file mode 100644 index 000000000..c6f84e11a --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/data-source.md @@ -0,0 +1,2 @@ +# Overview of Data Sources + diff --git a/docs/fr-FR/handbook/data-modeling/index.md b/docs/fr-FR/handbook/data-modeling/index.md new file mode 100644 index 000000000..d9a905651 --- /dev/null +++ b/docs/fr-FR/handbook/data-modeling/index.md @@ -0,0 +1,50 @@ +# Overview + +Data modeling is a key step in designing databases, involving a deep analysis and abstraction process of various data and their relationships in the real world. In this process, we try to reveal the intrinsic connections between data and formalize them into data models, laying the foundation for the database structure of the information system. NocoBase is a data model-driven platform with the following features: + +## Supports Access to Data from Various Sources + +The data source of NocoBase can be common databases, API (SDK) platforms, and files. + +![20240512085558](https://static-docs.nocobase.com/20240512085558.png) + +NocoBase provides a [data source manager](/handbook/data-source-manager) for managing various data sources and their data tables. The data source manager plugin only provides a management interface for all data sources and does not provide the ability to access data sources. It needs to be used in conjunction with various data source plugins. The currently supported data sources include: + +- [Main Database](/handbook/data-source-main): NocoBase's main database, supporting relational databases such as MySQL, PostgreSQL, SQLite, etc. +- [External MySQL](/handbook/data-source-external-mysql): Use an external MySQL database as a data source. +- [External MariaDB](/handbook/data-source-external-mariadb): Use an external MariaDB database as a data source. +- [External PostgreSQL](/handbook/data-source-external-postgres): Use an external PostgreSQL database as a data source. + +![20240512083651](https://static-docs.nocobase.com/20240512083651.png) + +## Provides a Variety of Data Modeling Tools + +**Simple data table management interface**: Used to create various models (data tables) or connect to existing models (data tables). + +![20240512090751](https://static-docs.nocobase.com/20240512090751.png) + +**Visual interface similar to ER diagrams**: Used to extract entities and their relationships from user and business requirements. It provides an intuitive and easy-to-understand way to describe data models. Through ER diagrams, you can more clearly understand the main data entities in the system and their relationships. + +![20240512091042](https://static-docs.nocobase.com/20240410075906.png) + +## Supports Various Types of Data Tables + +- [General collection](/handbook/data-source-main/general-collection): Built-in common system fields; +- [Inheritance collection](/handbook/data-source-main/inheritance-collection): You can create a parent collection and then derive a child collection from the parent collection. The child collection will inherit the structure of the parent collection and can also define its own columns. +- [Tree collection](/handbook/collection-tree): Tree structure collection, currently only supports adjacency collection design; +- [Calendar Tabcollectionle](/handbook/calendar/calendar-collection): Used to create calendar-related event collections; +- [File collection](/handbook/file-manager/file-collection): Used for file storage management; +- [Expression collection](/handbook/workflow-dynamic-calculation/expression): Used for dynamic expression scenarios in workflows; +- [SQL collection](/handbook/collection-sql): Not an actual database collection, but quickly presents SQL queries in a structured manner; +- [Connect to database view](/handbook/collection-view): Connects to existing database views; +- [Connect to foreign data](/handbook/collection-fdw): Allows the database system to directly access and query data in external data sources, based on FDW technology. + +![20240512102212](https://static-docs.nocobase.com/20240512102212.png) + +For more content, see the "[Collection / Overview](/handbook/data-modeling/collection)" section. + +## Provides a Rich Variety of Field Types + +![20240512110352](https://static-docs.nocobase.com/20240512110352.png) + +For more content, see the "[Collection Fields / Overview](/handbook/data-modeling/collection-fields)" section. \ No newline at end of file diff --git a/docs/fr-FR/handbook/data-source-external-mariadb/index.md b/docs/fr-FR/handbook/data-source-external-mariadb/index.md new file mode 100644 index 000000000..2d47d53a4 --- /dev/null +++ b/docs/fr-FR/handbook/data-source-external-mariadb/index.md @@ -0,0 +1,17 @@ +# External Data Source - MariaDB + + + +## Introduction + +Use an external MariaDB database as a data source. Currently supported versions: MariaDB >= 10.3 + +## Installation + +This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager. + +![20240323162741](https://static-docs.nocobase.com/20240323162741.png) + +## Usage Instructions + +Refer to the [Data Source / External Database](/handbook/data-source-manager/external-database) section. \ No newline at end of file diff --git a/docs/fr-FR/handbook/data-source-external-mssql/index.md b/docs/fr-FR/handbook/data-source-external-mssql/index.md new file mode 100644 index 000000000..fb2c898cd --- /dev/null +++ b/docs/fr-FR/handbook/data-source-external-mssql/index.md @@ -0,0 +1,17 @@ +# External Data Source - MSSQL + + + +## Introduction + +Use an external MSSQL database as a data source. Currently supported versions: SQL Server 2014-2019 + +## Installation + +This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager. + +![20240323162741](https://static-docs.nocobase.com/20240323162741.png) + +## Usage Instructions + +Refer to the [Data Source / External Database](/handbook/data-source-manager/external-database) section. \ No newline at end of file diff --git a/docs/fr-FR/handbook/data-source-external-mysql/index.md b/docs/fr-FR/handbook/data-source-external-mysql/index.md new file mode 100644 index 000000000..fe643d0c4 --- /dev/null +++ b/docs/fr-FR/handbook/data-source-external-mysql/index.md @@ -0,0 +1,17 @@ +# External Data Source - MySQL + + + +## Introduction + +Use an external MySQL database as a data source. Currently supported versions: MySQL ^5.7, ^8.0 + +## Installation + +This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager. + +![20240323162741](https://static-docs.nocobase.com/20240323162741.png) + +## Usage Instructions + +Refer to the [Data Source / External Database](/handbook/data-source-manager/external-database) section. \ No newline at end of file diff --git a/docs/fr-FR/handbook/data-source-external-oracle/index.md b/docs/fr-FR/handbook/data-source-external-oracle/index.md new file mode 100644 index 000000000..ee8d8b2dd --- /dev/null +++ b/docs/fr-FR/handbook/data-source-external-oracle/index.md @@ -0,0 +1,38 @@ +# External Data Source - Oracle + + + +## Introduction + +This plugin allows you to use an external Oracle database as a data source. It supports Oracle versions >= 11g. + +## Installation + +### Install Oracle Client + +For Oracle server versions earlier than 12.1, you need to install the Oracle client. + +![Oracle Client Installation](https://static-docs.nocobase.com/20241204164359.png) + +Example for Linux: + +```bash +apt-get update +apt-get install -y unzip wget libaio1 +wget https://download.oracle.com/otn_software/linux/instantclient/1925000/instantclient-basic-linux.x64-19.25.0.0.0dbru.zip +unzip instantclient-basic-linux.x64-19.25.0.0.0dbru.zip -d /opt/ +echo /opt/instantclient_19_25 > /etc/ld.so.conf.d/oracle-instantclient.conf +ldconfig +``` + +If the client is not installed as described above, you will need to specify the path to the client (for more details, refer to the [node-oracledb documentation](https://node-oracledb.readthedocs.io/en/latest/user_guide/initialization.html)). + +![Oracle Client Path Configuration](https://static-docs.nocobase.com/20241204165940.png) + +### Install the Plugin + +Follow the instructions in [Installing and Upgrading Commercial Plugins](/welcome/getting-started/plugin). + +## Use Cases + +For detailed instructions, refer to the [Data Source / External Database](/handbook/data-source-manager/external-database) section. diff --git a/docs/fr-FR/handbook/data-source-external-postgres/index.md b/docs/fr-FR/handbook/data-source-external-postgres/index.md new file mode 100644 index 000000000..f3973855a --- /dev/null +++ b/docs/fr-FR/handbook/data-source-external-postgres/index.md @@ -0,0 +1,17 @@ +# External Data Source - PostgreSQL + + + +## Introduction + +Use an external PostgreSQL database as a data source. Currently supported versions: PostgreSQL >= 9.5 + +## Installation + +This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager. + +![20240323162741](https://static-docs.nocobase.com/20240323162741.png) + +## Usage Instructions + +Refer to the [Data Source / External Database](/handbook/data-source-manager/external-database) section. diff --git a/docs/fr-FR/handbook/data-source-kingbase/index.md b/docs/fr-FR/handbook/data-source-kingbase/index.md new file mode 100644 index 000000000..3ff5c3186 --- /dev/null +++ b/docs/fr-FR/handbook/data-source-kingbase/index.md @@ -0,0 +1,136 @@ +# Data Source - KingbaseES Database + + + +## Introduction + +KingbaseES can be used as a data source, either as the primary database or an external database. + +:::warning +Currently, only KingbaseES databases running in pg mode are supported. +::: + +## Installation + +### Using as the Primary Database + +Refer to the [Installation Overview](/welcome/getting-started/installation) for the setup procedures, the difference is mainly due to the environment variables. + +#### Environment Variables + +Edit the .env file to add or modify the following environment variable configurations: + +```bash +# For accessing commercial plugins +NOCOBASE_PKG_URL=https://pkg.nocobase.com/ +NOCOBASE_PKG_USERNAME=your-username # Service platform username +NOCOBASE_PKG_PASSWORD=your-password # Service platform password + +# Adjust DB parameters as needed +DB_DIALECT=kingbase +DB_HOST=localhost +DB_PORT=54321 +DB_DATABASE=kingbase +DB_USER=nocobase +DB_PASSWORD=nocobase +``` + +#### Docker Installation + +```yml +version: "3" + +networks: + nocobase: + driver: bridge + + app: + image: registry.cn-shanghai.aliyuncs.com/nocobase/nocobase:latest + networks: + - nocobase + depends_on: + - postgres + environment: + # For accessing commercial plugins + - NOCOBASE_PKG_URL=https://pkg.nocobase.com/ + - NOCOBASE_PKG_USERNAME=your-username # Service platform username + - NOCOBASE_PKG_PASSWORD=your-password # Service platform password + # Application key for generating user tokens, etc. + # Changing APP_KEY invalidates old tokens + # Use a random string and keep it confidential + - APP_KEY=your-secret-key + # Database type + - DB_DIALECT=kingbase + # Database host, replace with existing database server IP if needed + - DB_HOST=kingbase + # Database name + - DB_DATABASE=kingbase + # Database user + - DB_USER=nocobase + # Database password + - DB_PASSWORD=nocobase + # Timezone + - TZ=Asia/Shanghai + volumes: + - ./storage:/app/nocobase/storage + ports: + - "13000:80" + + # Kingbase service for testing purposes only + kingbase: + image: registry.cn-shanghai.aliyuncs.com/nocobase/kingbase:v009r001c001b0030_single_x86 + platform: linux/amd64 + restart: always + privileged: true + networks: + - nocobase + volumes: + - ./storage/db/kingbase:/home/kingbase/userdata + environment: + ENABLE_CI: no # Must be set to no + DB_USER: nocobase + DB_PASSWORD: nocobase + DB_MODE: pg # pg only + NEED_START: yes + command: ["/usr/sbin/init"] +``` + +#### Installation Using create-nocobase-app + +```bash +yarn create nocobase-app my-nocobase-app -d kingbase \ + -e DB_HOST=localhost \ + -e DB_PORT=54321 \ + -e DB_DATABASE=kingbase \ + -e DB_USER=nocobase \ + -e DB_PASSWORD=nocobase \ + -e TZ=Asia/Shanghai +``` + +### Using as an External Database + +Edit the .env file to add environment variables for accessing commercial plugins: + +```bash +# For accessing commercial plugins +NOCOBASE_PKG_URL=https://pkg.nocobase.com/ +NOCOBASE_PKG_USERNAME=your-username # Service platform username +NOCOBASE_PKG_PASSWORD=your-password # Service platform password +``` + +Execute the installation or upgrade command + +```bash +yarn nocobase install +# or +yarn nocobase upgrade +``` + +Activate the Plugin + +![20241024121815](https://static-docs.nocobase.com/20241024121815.png) + +## User Guide + +- Primary Database: Refer to the [handbook](/handbook) +- External Database: See [Data Source / External Database](/handbook/data-source-manager/external-database) diff --git a/docs/fr-FR/handbook/data-source-main/general-collection.md b/docs/fr-FR/handbook/data-source-main/general-collection.md new file mode 100644 index 000000000..d4178f873 --- /dev/null +++ b/docs/fr-FR/handbook/data-source-main/general-collection.md @@ -0,0 +1,10 @@ +# General Collection + + + +## Introduction +It is used in most scenarios. A general collection can be used unless a special collection template is needed. + +## User Manual + +![20240324085739](https://static-docs.nocobase.com/20240324085739.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/data-source-main/index.md b/docs/fr-FR/handbook/data-source-main/index.md new file mode 100644 index 000000000..84f7893d4 --- /dev/null +++ b/docs/fr-FR/handbook/data-source-main/index.md @@ -0,0 +1,37 @@ +# Main DataBase + + + +## Introduction + +NocoBase's main database can be used to store both business data and the metadata of the application, including system table data and custom table data. The main database supports relational databases such as MySQL, PostgreSQL, SQLite, etc. During the installation of the NocoBase application, the main database must be installed synchronously and cannot be deleted. + +## Installation + +This is a built-in plugin, no separate installation is required. + +## User Manual + +![20240322230134](https://static-docs.nocobase.com/20240322230134.png) + +### Supporting the creation of various data tables + +- [General collection](/handbook/data-source-main/general-collection): built-in commonly used system fields; +- [Inheritance collection](/handbook/data-source-main/inheritance-collection): allows the creation of a parent table, from which child tables can be derived. Child tables will inherit the structure of the parent table, and can also define their own columns. +- [Tree collection](/handbook/collection-tree): tree-structured table, currently only supports adjacent table design; +- [Calendar collection](/handbook/calendar/calendar-collection): for creating calendar-related event tables; +- [File collection](/handbook/file-manager/file-collection): for managing file storage; +- [Expression Collection](/handbook/workflow-dynamic-calculation/expression): for dynamic expression scenarios in workflows; +- [SQL Collection](/handbook/collection-sql): Not an actual database table, but quickly presenting the SQL query in a structured manner; +- [Database View collection](/handbook/collection-view): connects to an existing database view; +- [FDW collection](/handbook/collection-fdw): allows the database system to directly access and query data in external data sources, based on FDW technology; + +### Supporting classification management of collections + +![20240322231520](https://static-docs.nocobase.com/20240322231520.png) + +### Offering a wide range of field types + +![20240322230950](https://static-docs.nocobase.com/20240322230950.png) + +See more in the [Data Table Fields / Overview](/handbook/data-modeling/collection-fields) section. \ No newline at end of file diff --git a/docs/fr-FR/handbook/data-source-main/inheritance-collection.md b/docs/fr-FR/handbook/data-source-main/inheritance-collection.md new file mode 100644 index 000000000..78de0a20c --- /dev/null +++ b/docs/fr-FR/handbook/data-source-main/inheritance-collection.md @@ -0,0 +1,20 @@ +# Inheritance Collection + + + +## Introduction + +You can create a parent collection and derive child collection from that parent collection. The child collection will inherit the structure of the parent collection, and can also define its own columns. This design pattern helps organize and manage data with similar structures but possible differences. + +Here are some common features of support for inheritable collections: + +- Parent Collection: The parent collection contains common columns and data, defining the basic structure of the entire inheritance hierarchy. +- Child Collection: The child collection inherits the structure of the parent collection, but can also define its own columns. This allows each child collection to have the common properties of the parent collection while containing attributes specific to the subclass. +- Querying: When querying, you can choose to query the entire inheritance hierarchy, just the parent collection, or a specific child collection. This allows different levels of data to be retrieved and processed as needed. +- Inheritance Relationship: An inheritance relationship is established between the parent collection and the child collection, meaning that the structure of the parent collection can be used to define consistent attributes, while allowing the child collection to extend or override these attributes. + +This design pattern helps to reduce data redundancy, simplify the database model, and make the data easier to maintain. However, it needs to be used with caution as inheritable collections can increase the complexity of queries, especially when dealing with the entire inheritance hierarchy. Databases that support inheritable collections generally provide specific syntax and tools to manage and query these collection structures. + +## User Manual + +![20240324085907](https://static-docs.nocobase.com/20240324085907.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/data-source-manager/external-database.md b/docs/fr-FR/handbook/data-source-manager/external-database.md new file mode 100644 index 000000000..199d66ee2 --- /dev/null +++ b/docs/fr-FR/handbook/data-source-manager/external-database.md @@ -0,0 +1,88 @@ +# Overview + +## Introduction + +Use an existing external database as a data source. Currently, the supported external databases are MySQL, MariaDB, and PostgreSQL. + +## Usage Instructions + +### Adding an External Database + +After activating the plugin, you can select and add it from the Add new dropdown menu in the data source management. + +![20240507204316](https://static-docs.nocobase.com/20240507204316.png) + +Fill in the information of the database you need to connect to. + +![20240507204820](https://static-docs.nocobase.com/20240507204820.png) + +### Data Table Synchronization + +After establishing a connection with the external database, all data tables in the data source will be directly read. The external database does not support directly adding data tables or modifying table structures. If modifications are needed, they can be made through the database client, and then the "Refresh" button can be clicked on the interface to synchronize. + +![20240507204725](https://static-docs.nocobase.com/20240507204725.png) + +### Configuring Fields + +The external database will automatically read the fields of the existing data tables and display them. You can quickly view and configure the title of the field, the data type (Field type), and the UI type (Field interface). You can also click the "Edit" button to modify more configurations. + +![20240507210537](https://static-docs.nocobase.com/20240507210537.png) + +Because the external database does not support modifying table structures, the only type available when adding new fields is the relationship field. Relationship fields are not real fields, but are used to establish connections between tables. + +![20240507220140](https://static-docs.nocobase.com/20240507220140.png) + +For more content, refer to the [Collection Fields/Overview](/handbook/data-modeling/collection-fields) section. + +### Field Type Mapping + +NocoBase will automatically map the corresponding data type (Field type) and UI type (Field Interface) for the field types of the external database. + +- Data type (Field type): Used to define the kind, format, and structure of data that the field can store. +- UI type (Field Interface): Refers to the type of control used to display and input field values in the user interface. + +The table below shows the mapping of field types for PostgreSQL, MySQL/MariaDB to NocoBase Data Type and NocoBase Interface Type. + +| PostgreSQL | MySQL/MariaDB | NocoBase Data Type | NocoBase Interface Type | +| - | - | - | - | +| BOOLEAN | BOOLEAN
    TINYINT(1) | boolean | checkbox
    switch | +| SMALLINT
    INTEGER
    SERIAL
    SMALLSERIAL | TINYINT
    SMALLINT
    MEDIUMINT
    INTEGER | integer
    boolean
    sort | integer
    sort
    checkbox
    switch
    select
    radioGroup | +| BIGINT
    BIGSERIAL | BIGINT | bigInt
    sort | integer
    sort
    checkbox
    switch
    select
    radioGroup
    unixTimestamp
    createdAt
    updatedAt | +| REAL | FLOAT | float | number
    percent | +| DOUBLE PRECISION | DOUBLE PRECISION | double | number
    percent | +| DECIMAL
    NUMERIC | DECIMAL | decimal | number
    percent
    currency | +| VARCHAR
    CHAR | VARCHAR
    CHAR | string
    password
    uuid
    nanoid | input
    email
    phone
    password
    color
    icon
    select
    radioGroup
    uuid
    nanoid | +| TEXT | TEXT
    TINYTEXT
    MEDIUMTEXT
    LONGTEXT | text
    json | textarea
    markdown
    vditor
    richText
    url
    json | +| UUID | - | uuid | uuid | +| JSON
    JSONB | JSON | json | json | +| TIMESTAMP | DATETIME
    TIMESTAMP | date | date
    time
    createdAt
    updatedAt | +| DATE | DATE | dateOnly | datetime | +| TIME | TIME | time | time | +| - | YEAR | | datetime | +| CIRCEL | | circle | json
    circle | +| PATH
    GEOMETRY(LINESTRING) | LINESTRING | lineString | Json
    lineString | +| POINT
    GEOMETRY(POINT) | POINT | point | json
    point | +| POLYGON
    GEOMETRY(POLYGON) | POLYGON | polygon | json
    polygon | +| GEOMETRY | GEOMETRY | - | - | +| BLOB | BLOB | blob | - | +| ENUM | ENUM | enum | select
    radioGroup | +| ARRAY | - | array | multipleSelect
    checkboxGroup | +| BIT | BIT | - | - | +| SET | SET | set | multipleSelect
    checkboxGroup | +| RANGE | - | - | - | + +### Unsupported Field Types + +Unsupported field types will be displayed separately. These fields need to be developed for adaptation before they can be used. + +![20240507221854](https://static-docs.nocobase.com/20240507221854.png) + +### Filter Target Key + +Data tables that are displayed as blocks must have a filter target key configured. The filter target key refers to filtering data based on a specific field, and the field value must be unique. The filter target key defaults to the primary key field of the data table. If it is a view or a data table without a primary key, or a data table with a composite primary key, you need to customize the filter target key. + +![20240507210230](https://static-docs.nocobase.com/20240507210230.png) + +Only data tables that have set a filter target key can be added to the page. + +![20240507222827](https://static-docs.nocobase.com/20240507222827.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/data-source-manager/index.md b/docs/fr-FR/handbook/data-source-manager/index.md new file mode 100644 index 000000000..a3af0de3a --- /dev/null +++ b/docs/fr-FR/handbook/data-source-manager/index.md @@ -0,0 +1,30 @@ +# Data Source Manager + + + +## Introduction + +NocoBase provides a data source management plugin for managing data sources and their data tables. The data source management plugin only provides a management interface for all data sources and does not provide the ability to access data sources. It needs to be used in conjunction with various data source plugins. The data sources currently supported for access include: + +- [Main Database](/handbook/data-source-main): NocoBase's main database, supporting relational databases such as MySQL, PostgreSQL, SQLite, etc. +- [External MySQL](/handbook/data-source-external-mysql): Use an external MySQL database as a data source. +- [External MariaDB](/handbook/data-source-external-mariadb): Use an external MariaDB database as a data source. +- [External PostgreSQL](/handbook/data-source-external-postgres): Use an external PostgreSQL database as a data source. + +In addition, more types can be extended through plugins, which can be common types of databases or platforms that provide APIs (SDKs). + +## Installation + +Built-in plugin, no separate installation required. + +## Usage Instructions + +When the application is initialized and installed, a data source will be provided by default to store NocoBase data, known as the main database. For more information, see the [Main Database](/handbook/data-source-main). + +![20240322220423](https://static-docs.nocobase.com/20240322220423.png) + +At the same time, it also supports external databases as data sources. For more information, see the [External Database / Introduction](/handbook/data-source-manager/external-database). + +![20240507204316](https://static-docs.nocobase.com/20240507204316.png) + +You can also access data from HTTP API sources. For more information, see the [HTTP API Data Source](/handbook/data-source-http-api). diff --git a/docs/fr-FR/handbook/data-source-rest-api/index.md b/docs/fr-FR/handbook/data-source-rest-api/index.md new file mode 100644 index 000000000..e5a00c6f0 --- /dev/null +++ b/docs/fr-FR/handbook/data-source-rest-api/index.md @@ -0,0 +1,227 @@ +# REST API Data Source + + + +## Introduction + +This plugin allows you to integrate data from REST API sources seamlessly. + +## Installation + +As a commercial plugin, it requires uploading and activation through the plugin manager. + +![20240323162741](https://static-docs.nocobase.com/20240323162741.png) + +## Adding a REST API Source + +After activating the plugin, you can add a REST API source by selecting it from the Add new dropdown menu in the data source management section. + +![20240721171420](https://static-docs.nocobase.com/20240721171420.png) + +### Configuring the REST API Source + +![20240721171507](https://static-docs.nocobase.com/20240721171507.png) + +## Adding a Collection + +In NocoBase, a RESTful resource is mapped to a Collection, such as a Users resource. + +```bash +GET /users +POST /users +GET /users/1 +PUT /users/1 +DELETE /users/1 +``` + +These API endpoints are mapped in NocoBase as follows: + +```bash +GET /users:list +POST /users:create +POST /users:get?filterByTk=1 +POST /users:update?filterByTk=1 +POST /users:destroy?filterByTk=1 +``` + +For a comprehensive guide on NocoBase API design specifications, refer to the API documentation. + +![20240716213344](https://static-docs.nocobase.com/20240716213344.png) + +Check the "NocoBase API - Core" chapter for detailed information. + +![20240716213258](https://static-docs.nocobase.com/20240716213258.png) + +The Collection configuration for a REST API data source includes the following: + +### List + +Map the interface for viewing a list of resources. + +![20240716211351](https://static-docs.nocobase.com/20240716211351.png) + +### Get + +Map the interface for viewing resource details. + +![20240716211532](https://static-docs.nocobase.com/20240716211532.png) + +### Create + +Map the interface for creating a resource. + +![20240716211634](https://static-docs.nocobase.com/20240716211634.png) + +### Update + +Map the interface for updating a resource. + +![20240716211733](https://static-docs.nocobase.com/20240716211733.png) + +### Destroy + +Map the interface for deleting a resource. + +![20240716211808](https://static-docs.nocobase.com/20240716211808.png) + +Both the List and Get interfaces are required to be configured. +## Debugging the API + +### Request parameter integration + +example: configure pagination parameters for the List API. + +if the third-party api does not support pagination natively, implement pagination will based on the retrieved list data. + +![20241121205229](https://static-docs.nocobase.com/20241121205229.png) + +Note: Only variables added to the API will work. + +| Third-party API params name | NocoBase params | +| --------------------------- | --------------------------- | +| page | {{request.params.page}} | +| limit | {{request.params.pageSize}} | + +You can easily debug the API by clicking Try it out. + +![20241121210320](https://static-docs.nocobase.com/20241121210320.png) + + + +### Response format transformation + +The response format of the third-party API may not be in NocoBase standard, and it needs to be transformed before it can be correctly displayed on the front end. + +![20241121214638](https://static-docs.nocobase.com/20241121214638.png) + +Adjust the conversion rules based on the response format of the third-party API to ensure the output conforms to the NocoBase standard. + +![20241121215100](https://static-docs.nocobase.com/20241121215100.png) + +### Debugging Process Overview + +![20240717110051](https://static-docs.nocobase.com/20240717110051.png) + +## Variables + +The REST API data source supports three types of variables for API integration: + +- Custom data source variables +- NocoBase request variables +- Third-party response variables + +### Custom Data Source Variables + +![20240716221937](https://static-docs.nocobase.com/20240716221937.png) + +![20240716221858](https://static-docs.nocobase.com/20240716221858.png) + +### NocoBase Request + +- Params: URL query parameters (Search Params), which vary depending on the interface. +- Headers: Custom request headers, primarily providing specific X- information from NocoBase. +- Body: The request body. +- Token: The API token for the current NocoBase request. + +![20240716222042](https://static-docs.nocobase.com/20240716222042.png) + +### Third-Party Responses + +Currently, only the response body is available. + +![20240716222303](https://static-docs.nocobase.com/20240716222303.png) + +Below are the variables available for each interface: + +### List + +| Parameter | Description | +| ----------------------- | ---------------------------------------------------------- | +| request.params.page | Current page | +| request.params.pageSize | Number of items per page | +| request.params.filter | Filter criteria (must meet NocoBase Filter format) | +| request.params.sort | Sorting criteria (must meet NocoBase Sort format) | +| request.params.appends | Fields to load on demand, typically for association fields | +| request.params.fields | Fields to include (whitelist) | +| request.params.except | Fields to exclude (blacklist) | + +### Get + +| Parameter | Description | +| ------------------------- | ---------------------------------------------------------- | +| request.params.filterByTk | Required, typically the current record ID | +| request.params.filter | Filter criteria (must meet NocoBase Filter format) | +| request.params.appends | Fields to load on demand, typically for association fields | +| request.params.fields | Fields to include (whitelist) | +| request.params.except | Fields to exclude (blacklist) | + +### Create + +| Parameter | Description | +| ------------------------ | ------------------------- | +| request.params.whiteList | Whitelist | +| request.params.blacklist | Blacklist | +| request.body | Initial data for creation | + +### Update + +| Parameter | Description | +| ------------------------- | -------------------------------------------------- | +| request.params.filterByTk | Required, typically the current record ID | +| request.params.filter | Filter criteria (must meet NocoBase Filter format) | +| request.params.whiteList | Whitelist | +| request.params.blacklist | Blacklist | +| request.body | Data for update | + +### Destroy + +| Parameter | Description | +| ------------------------- | ----------------------------------------- | +| request.params.filterByTk | Required, typically the current record ID | +| request.params.filter | Filtering conditions | + +## Field Configuration + +Field metadata (Fields) is extracted from the CRUD interface data of the adapted resource to serve as the fields of the collection. + +![20240716223636](https://static-docs.nocobase.com/20240716223636.png) + +Field metadata extraction. + +![20241121230436](https://static-docs.nocobase.com/20241121230436.png) + +Field and preview. + +![20240716224403](https://static-docs.nocobase.com/20240716224403.png) + +Edit fields (similar to other data sources). + +![20240716224704](https://static-docs.nocobase.com/20240716224704.png) + +## Adding REST API Data Source Blocks + +Once the collection is configured, you can add blocks to the interface. + +![20240716225120](https://static-docs.nocobase.com/20240716225120.png) diff --git a/docs/fr-FR/handbook/data-visualization-echarts/area.md b/docs/fr-FR/handbook/data-visualization-echarts/area.md new file mode 100644 index 000000000..ec798dba8 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/area.md @@ -0,0 +1,81 @@ +# Area Chart + +## Data Configuration + +### 1 or more measures, 1 dimension + +![1 or more measures, 1 dimension](https://static-docs.nocobase.com/202410091149684.png) + +### 1 measure, 1 axis dimension, 1 category dimension + +Configure 1 measure and 2 dimensions. One dimension will serve as the X-axis field, and the other will be used as the series (category) field. + +![1 measure, 1 axis dimension, 1 category dimension](https://static-docs.nocobase.com/202410091153441.png) + +## Configuration Options + +| Option | Description | +| ------------------------------- | --------------------------------------------------------------------------- | +| XField | The dimension field for the X-axis | +| seriesField | The dimension field used for categorization | +| Size | Define the chart size, either by fixed aspect ratio or fixed height | +| Light mode theme | Select this option to preview when the system is in light mode | +| Dark mode theme | Select this option to preview when the system is in dark mode | +| Show legend | Toggle the display of the legend | +| Legend orient | Choose the direction of the legend display, either horizontal or vertical | +| Legend position (left, bottom, right, top) | Define the relative position of the legend | +| Label type | Control the visibility and type of labels | +| Smooth curve | Enable or disable the smoothing of curves | +| Whether stack | Enable or disable data stacking | +| X-Axis title | Control the display position of the X-axis title | +| Y-Axis title | Control the display position of the Y-axis title | +| X-Axis label rotate | Set the rotation angle of X-axis labels, helpful for displaying more labels when they are dense | +| Padding | Adjust the internal padding of the chart | +| Split line | Configure the display and style of grid lines | +| Mark line | Add marker lines with custom title, value, and color | + +--- + +Now, I will move on to the final refinement stage. + +### Refinement Stage (Refinement Expert) + +For this final pass, I've refined the text to enhance readability and ensure clarity, while keeping it professional and technically accurate. + +--- + +### Area Chart + +#### Data Configuration + +##### 1 or More Measures, 1 Dimension + +![Image](https://static-docs.nocobase.com/202410091149684.png) + +##### 1 Measure, 1 Axis Dimension, 1 Category Dimension + +This setup includes 1 measure and 2 dimensions. One dimension acts as the X-axis field, while the other is used as the series (category) field. + +![Image](https://static-docs.nocobase.com/202410091153441.png) + +#### Configuration Options + +| Option | Description | +| ------------------------------- | --------------------------------------------------------------------------- | +| X-axis Field | Field used to define the X-axis dimension | +| Category Field | Field used to categorize data | +| Size | Specify chart size, either by fixed aspect ratio or fixed height | +| Light Mode Theme | Select for preview in light mode | +| Dark Mode Theme | Select for preview in dark mode | +| Show Legend | Toggle the visibility of the legend | +| Legend Direction | Set legend direction (horizontal or vertical) | +| Legend Position (Left, Bottom, Right, Top) | Set the position of the legend relative to the chart | +| Label Type | Manage the visibility and format of the labels | +| Smooth Curve | Enable smoothing of the curve for a more polished look | +| Stack Data | Option to stack values for cumulative data visualization | +| X-axis Title | Adjust the visibility and position of the X-axis title | +| Y-axis Title | Adjust the visibility and position of the Y-axis title | +| X-axis Label Rotation | Rotate X-axis labels to optimize space, useful when labels are densely packed | +| Padding | Customize the inner padding of the chart | +| Grid Lines | Define the visibility and style of grid lines | +| Marker Line | Add marker lines, and set their title, value, and color | diff --git a/docs/fr-FR/handbook/data-visualization-echarts/bar.md b/docs/fr-FR/handbook/data-visualization-echarts/bar.md new file mode 100644 index 000000000..e752b3b7d --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/bar.md @@ -0,0 +1,39 @@ +# Bar Chart + +## Data Configuration + +### 1 or more measures, 1 dimension + +![1 or more measures, 1 dimension](https://static-docs.nocobase.com/202410091114926.png) + +### 1 measure, 1 axis dimension, one category dimension + +Configure 1 measure and 2 dimensions. 1 dimension is used as the Y-axis field, and the other as the series field. + +![1 measure, 1 axis dimension, one category dimension](https://static-docs.nocobase.com/202410091117000.png) + +## Configuration Options + +| Option | Description | +| ----------------------------- | ----------------------------------------------------------------------------------------------------------- | +| yField | The dimension field for the Y-axis | +| seriesField | The dimension field for categorization | +| Size | Set the size of the chart, either with a fixed aspect ratio or a fixed height | +| Light mode theme | Choose this option to preview the chart when the system is in light mode | +| Dark mode theme | Choose this option to preview the chart when the system is in dark mode | +| Show legend | Control whether the legend is displayed | +| Legend orient | Control the direction of the legend, either horizontal or vertical | +| Legend position (left, bottom, right, top) | Control the relative position of the legend | +| Label type | Control whether the labels are displayed and the type of labels shown | +| Label position | Control the position of the labels, such as top, inside, or inside top | +| Stack | Control whether the bars are stacked: not stacked, stacked, or percentage stacked
    ![](https://static-docs.nocobase.com/202410091108049.png) | +| Bar width (min, max) | Control the width of the bars, which can be a fixed value or percentage, and can even be negative | +| Bar gap | Spacing between bars, as a percentage of the bar width | +| Bar category gap | Spacing between different categories, as a percentage of the bar width | +| Color by | Control whether the bar colors are distinguished by category or data | +| Colors | Precisely control the color for each category | +| X-Axis title | Control the position of the X-axis title | +| Y-Axis title | Control the position of the Y-axis title | +| Y-Axis label rotate | Control the rotation angle of the Y-axis labels, useful for displaying more labels when space is tight | +| Padding | Adjust the padding inside the chart | +| Split line | Control whether the grid lines are displayed and their style | diff --git a/docs/fr-FR/handbook/data-visualization-echarts/column.md b/docs/fr-FR/handbook/data-visualization-echarts/column.md new file mode 100644 index 000000000..9eadb1ac3 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/column.md @@ -0,0 +1,40 @@ +# Column Chart + +## Data Configuration + +### 1 or More Measures, 1 Dimension + +![1 or More Measures, 1 Dimension](https://static-docs.nocobase.com/202410091058207.png) + +### 1 Measure, 1 Axis Dimension, 1 Category Dimension + +Configure 1 measure and 2 dimensions. 1 dimension serves as the X-axis field (X field), and the other as the Series field. + +![1 Measure, 1 Axis Dimension, 1 Category Dimension](https://static-docs.nocobase.com/202410091105937.png) + +## Configuration Options + +| Option | Description | +| -------------------------- | ----------------------------------------------------------------------------------------------------- | +| xField | Dimension field for the X-axis | +| seriesField | Dimension field for categorization | +| Size | Set the chart size, either with a fixed aspect ratio or a fixed height | +| Light mode theme | Preview the chart when the system is in light mode | +| Dark mode theme | Preview the chart when the system is in dark mode | +| Show legend | Toggle the visibility of the legend | +| Legend orient Legend orient | Set the orientation of the legend, either horizontal or vertical | +| Legend position (left, bottom, right, top) | Set the position of the legend relative to the chart | +| Label type | Control whether to display labels and which type of labels to show | +| Label position | Set the position of the labels, such as top, inside, or inside top | +| Stack | Control whether the bars are stacked, with options for no stacking, stacking, or percentage stacking
    ![Stacking Options](https://static-docs.nocobase.com/202410091108049.png) | +| Bar width (min, max) | Control the width of the bars, which can be a fixed value, percentage, or even negative values | +| Bar gap | Set the spacing between bars, as a percentage of the bar width | +| Bar category gap | Set the spacing between different categories, as a percentage of the bar width | +| Color by | Set bar colors by category or by data | +| Colors | Fine-tune the color for each category | +| X-Axis title | Control the display position of the X-axis title | +| Y-Axis title | Control the display position of the Y-axis title | +| X-Axis label rotate | Adjust the rotation angle of the X-axis labels to display more labels when they are dense | +| Padding | Adjust the chart's inner padding | +| Split line | Control whether gridlines are displayed and their style | +| Mark line | Add marker lines with custom titles, values, and colors | diff --git a/docs/fr-FR/handbook/data-visualization-echarts/diverging-bar.md b/docs/fr-FR/handbook/data-visualization-echarts/diverging-bar.md new file mode 100644 index 000000000..e6d8a6337 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/diverging-bar.md @@ -0,0 +1,26 @@ +# Diverging-bar Chart + +## Data Configuration + +### 2 Metrics, 1 Dimension + +Configure 2 metrics and 1 dimension. One metric will be assigned as the left-side X-axis field, and the other as the right-side X-axis field. + +![2 Metrics, 1 Dimension](https://static-docs.nocobase.com/202410091121686.png) + +## Configuration Options + +| Option | Description | +| ----------------- | --------------------------------------------------------------------------- | +| Left X field | Metric field for the left-side X-axis | +| Right X field | Metric field for the right-side X-axis | +| yField | Dimension field | +| Size | Set the size of the chart, either with a fixed aspect ratio or fixed height | +| Light mode theme | Select this option to preview in the system's light mode | +| Dark mode theme | Select this option to preview in the system's dark mode | +| Show legend | Controls whether to display the legend | +| Label type | Controls whether to show labels and their display types | +| Colors | Allows fine control of the color for each category | +| Y-Axis label rotate | Controls the rotation angle of Y-axis labels, useful when labels are dense | +| Padding | Adjust the padding within the chart | +| Split line | Controls whether to display grid lines and their styles | diff --git a/docs/fr-FR/handbook/data-visualization-echarts/funnel.md b/docs/fr-FR/handbook/data-visualization-echarts/funnel.md new file mode 100644 index 000000000..94d732d0b --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/funnel.md @@ -0,0 +1,23 @@ +# Funnel Chart + +## Data Configuration + +### 1 Metric, 1 Dimension + +![1 Metric, 1 Dimension](https://static-docs.nocobase.com/202410091916090.png) + +## Configuration Options + +| Option | Description | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| Size | Set the chart size, choosing either a fixed aspect ratio or a fixed height. | +| Light mode theme | Required for previewing the chart in light mode. | +| Dark mode theme | Required for previewing the chart in dark mode. | +| Show legend | Toggles the visibility of the chart legend. | +| Legend orient | Sets the orientation of the legend, either horizontally or vertically. | +| Legend position (left, bottom, right, top) | Adjusts the position of the legend relative to the chart, offering flexibility in placement. | +| Label type | Controls whether labels are shown and specifies the label format. | +| Show label line | Determines whether the label line is displayed, applicable only when labels are positioned outside the funnel. | +| Label position | Sets the label position, either inside or outside of the funnel. | +| Funnel size (min, max) | Adjusts the size of the funnel chart. Modifying the minimum value controls whether the funnel ends in a pointed or flat base.
    ![](https://static-docs.nocobase.com/202410091919565.png) | +| Padding | Adjusts the internal padding around the chart. | diff --git a/docs/fr-FR/handbook/data-visualization-echarts/index.md b/docs/fr-FR/handbook/data-visualization-echarts/index.md new file mode 100644 index 000000000..b6435191e --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/index.md @@ -0,0 +1,5 @@ +# Overview + + + +The use of ECharts enables data visualization, supporting more chart types such as funnel charts, radar charts, and provides a more user-friendly visualization configuration. diff --git a/docs/fr-FR/handbook/data-visualization-echarts/line.md b/docs/fr-FR/handbook/data-visualization-echarts/line.md new file mode 100644 index 000000000..07d3e6ba6 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/line.md @@ -0,0 +1,36 @@ +# Line Chart + +## Data Configuration + +### 1 or More Measures, 1 Dimension + +![1 or More Measures, 1 Dimension](https://static-docs.nocobase.com/202410091022965.png) + +### 1 Measure, 1 Axis Dimension, one Classification Dimension + +Configure 1 measure and 2 dimensions. 1 dimension serves as the X-axis field, and the other as the series field. + +![1 Measure, 1 Axis Dimension, one Classification Dimension](https://static-docs.nocobase.com/202410091029410.png) + +## Configuration Options + +| Configuration Option | Description | +| -------------------------- | --------------------------------------------------------------------------------------------- | +| xField | The dimension field for the X-axis | +| seriesField | The dimension field for classification | +| Size | Set the chart size, either with a fixed aspect ratio or a fixed height | +| Light mode theme | Select to preview in light mode in systems with light mode enabled | +| Dark mode theme | Select to preview in dark mode in systems with dark mode enabled | +| Show legend | Control whether to display the legend | +| Legend orient | Control the direction of the legend, either horizontal or vertical
    ![](https://static-docs.nocobase.com/202410091050074.png) | +| Legend position (left, bottom, right, top) | Control the position of the legend relative to the chart | +| Label type | Control whether and how labels are displayed, only visible when marker points are displayed | +| Smooth curve | Enable or disable smooth curves in the line chart | +| Whether stack | Enable or disable stacked data values | +| Symbol | Control whether to display marker points and their styles | +| X-Axis title | Control the position of the X-axis title | +| Y-Axis title | Control the position of the Y-axis title | +| X-Axis label rotate | Control the rotation angle of X-axis labels, useful for displaying more labels in dense data | +| Padding | Adjust the chart’s internal padding | +| Split line | Control the visibility and style of grid lines | +| Mark line | Add marker lines and set title, value, and color
    ![](https://static-docs.nocobase.com/202410091051511.png) | diff --git a/docs/fr-FR/handbook/data-visualization-echarts/pie.md b/docs/fr-FR/handbook/data-visualization-echarts/pie.md new file mode 100644 index 000000000..93719caa9 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/pie.md @@ -0,0 +1,25 @@ +# Pie Chart + +## Data Configuration + +### 1 Metric, 1 Dimension + +![1 Metric, 1 Dimension](https://static-docs.nocobase.com/202410091138527.png) + +## Configuration Options + +| Option | Description | +| ---------------------------- | -------------------------------------------------------------------------------------------------------- | +| Size | Sets the chart's size, with a fixed aspect ratio or fixed height | +| Light mode theme | Must be selected to preview when the system is in light mode | +| Dark mode theme | Must be selected to preview when the system is in dark mode | +| Show legend | Controls whether the legend is displayed | +| Legend orient | Controls the orientation of the legend, either horizontal or vertical | +| Legend position (left, bottom, right, top) | Controls the relative position of the legend | +| Label type | Controls whether labels are displayed and their type | +| Show label line | Controls whether label lines are displayed, effective only when the labels are outside the pie | +| Label position | Controls the position of the labels: inside, outside, or middle. When in the middle, the label only appears when hovering over the corresponding part of the chart | +| Outter radius | Adjusts the outer radius of the chart | +| Inner radius | Adjusts the inner radius of the chart. Can be used to create a donut chart
    ![](https://static-docs.nocobase.com/202410091144473.png) | +| Center coordinates | Controls the position of the chart, which can be set with fixed values or percentages | +| Colors | Fine-tunes the color for each category | diff --git a/docs/fr-FR/handbook/data-visualization-echarts/radar.md b/docs/fr-FR/handbook/data-visualization-echarts/radar.md new file mode 100644 index 000000000..5520d6ec6 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/radar.md @@ -0,0 +1,32 @@ +# Radar Chart + +## Data Configuration + +### 1 or More Measures, 1 Dimension + +#### Using Dimensions as Variables + +Each value of the dimension field acts as a variable, with each measure forming one radar area. + +![](https://static-docs.nocobase.com/202410091924155.png) + +#### Using Measures as Variables + +Each measure acts as a variable, with each value of the dimension field forming one radar area. + +![](https://static-docs.nocobase.com/202410091927959.png) + +## Configuration Options + +| Option | Description | +| ---------------------------- | --------------------------------------------------------------------------- | +| Size | Set the size of the chart, either by fixing the aspect ratio or a fixed height | +| Light mode theme | Preview requires selection when the system is in light mode | +| Dark mode theme | Preview requires selection when the system is in dark mode | +| Show legend | Controls whether the legend is displayed | +| Legend orient | Controls the direction of the legend, either horizontal or vertical | +| Legend position (left, bottom, right, top) | Controls the relative position of the legend | +| Shape | Polygon or circle
    ![](https://static-docs.nocobase.com/202410091929018.png) | +| Range | Controls the minimum and maximum values of the variables | +| Radius | Adjusts the radius of the chart | +| Center coordinate | Controls the position of the chart, can be fixed values or percentages | diff --git a/docs/fr-FR/handbook/data-visualization-echarts/scatter.md b/docs/fr-FR/handbook/data-visualization-echarts/scatter.md new file mode 100644 index 000000000..6e790ca1d --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/scatter.md @@ -0,0 +1,33 @@ +# Scatter Chart + +## Data Configuration + +### 1 or Multiple Metrics, 1 Dimension + +![1 or Multiple Metrics, 1 Dimension](https://static-docs.nocobase.com/202410091202766.png) + +### 1 Metric, 1 Axis Dimension, One Category Dimension + +Configure one metric and two dimensions. One of the dimensions will serve as the X-axis field (X field), while the other will act as the series field. + +![1 Metric, 1 Axis Dimension, One Category Dimension](https://static-docs.nocobase.com/202410091202268.png) + +## Configuration Options + +| Configuration Option | Description | +| -------------------------- | ----------------------------------------------------------- | +| xField | Dimension field for the X-axis | +| seriesField | Dimension field for categorization | +| Size | Set the chart size, either fixed aspect ratio or fixed height | +| Light mode theme | Preview available when the system is in light mode | +| Dark mode theme | Preview available when the system is in dark mode | +| Show legend | Toggle the visibility of the legend | +| Legend orient | Control the orientation of the legend, either horizontal or vertical | +| Legend position (left, bottom, right, top) | Control the relative position of the legend | +| Label type | Control whether labels are shown and the type of labels | +| X-Axis title | Control the display position of the X-axis title | +| Y-Axis title | Control the display position of the Y-axis title | +| X-Axis label rotate | Adjust the rotation angle of the X-axis labels; useful when there are dense labels to display more effectively | +| Padding | Adjust the internal padding of the chart | +| Split line | Control whether the grid lines are displayed and their style | +| Mark line | Add reference lines, set their title, value, and color | diff --git a/docs/fr-FR/handbook/data-visualization-echarts/treemap.md b/docs/fr-FR/handbook/data-visualization-echarts/treemap.md new file mode 100644 index 000000000..69404f7bb --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/treemap.md @@ -0,0 +1,16 @@ +# Treemap Chart + +## Data Configuration + +### 1 Measure, 1 Dimension + +![1 Measure, 1 Dimension](https://static-docs.nocobase.com/202410091933526.png) + +## Configuration Options + +| Option | Description | +| ------------------ | -------------------------------------------------- | +| Size | Set the size of the chart, either with a fixed aspect ratio or fixed height | +| Light mode theme | Must be selected for preview when the system is in light mode | +| Dark mode theme | Must be selected for preview when the system is in dark mode | +| Label type | Controls whether labels are displayed and the type of display | diff --git a/docs/fr-FR/handbook/data-visualization-echarts/wordcloud.md b/docs/fr-FR/handbook/data-visualization-echarts/wordcloud.md new file mode 100644 index 000000000..99fffc950 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization-echarts/wordcloud.md @@ -0,0 +1,16 @@ +# Word Cloud Chart + +## Data Configuration + +### 1 Measure, 1 Dimension + +![1 Measure, 1 Dimension](https://static-docs.nocobase.com/202410091936018.png) + +## Configuration Options + +| Option | Description | +| ------------------ | ------------------------------------------------ | +| Size | Sets the size of the chart, with either a fixed aspect ratio or fixed height | +| Light mode theme | Select this option to preview when the system is in light mode | +| Dark mode theme | Select this option to preview when the system is in dark mode | +| Shape | Controls the shape of the chart | diff --git a/docs/fr-FR/handbook/data-visualization/antd-charts/bar.md b/docs/fr-FR/handbook/data-visualization/antd-charts/bar.md new file mode 100644 index 000000000..cbe053977 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/antd-charts/bar.md @@ -0,0 +1,24 @@ +# Bar Chart + +## Data Configuration + +### 1 Metric, 1 Dimension + +![1 Metric, 1 Dimension](https://static-docs.nocobase.com/202410101129463.png) + +### 1 Metric, 1 Axis Dimension, 1 Category Dimension + +In this setup, configure one metric and two dimensions. One dimension serves as the X-axis field (X field), while the other acts as the category field (Series field). The X-axis field and the category field can be the same. + +![1 Metric, 1 Axis Dimension, 1 Category Dimension](https://static-docs.nocobase.com/202410101130607.png) + +#### Configuration Options + +| Option | Description | +| ---------------- | -------------------------------------------------------- | +| X-axis Field | The field used for the X-axis dimension | +| Category Field | The field used for the category dimension | +| Size | Sets the chart size, either fixed aspect ratio or height| +| Grouping | Specifies whether to display grouped bars | +| Stacking | Specifies whether to stack the bars | +| Percentage View | Specifies whether percentage display | diff --git a/docs/fr-FR/handbook/data-visualization/antd-charts/column.md b/docs/fr-FR/handbook/data-visualization/antd-charts/column.md new file mode 100644 index 000000000..3e235279e --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/antd-charts/column.md @@ -0,0 +1,24 @@ +# Column Chart + +## Data Configuration + +### 1 Measure, 1 Dimension + +![Bar Chart Example](https://static-docs.nocobase.com/202410101121827.png) + +### 1 Measure, 1 Axis Dimension, 1 Category Dimension + +Configure 1 measure and 2 dimensions, where one dimension is used as the X-axis field (X field) and the other as the category field (Series field). The X-axis field and the category field can be the same. + +![Bar Chart with Category](https://static-docs.nocobase.com/202410101122347.png) + +## Configuration Options + +| Option | Description | +| ---------------- | --------------------------------------------------------------------------- | +| X-axis Field | The dimension field for the X-axis | +| Category Field | The dimension field for categorization | +| Size | Set the size of the chart, either with a fixed aspect ratio or fixed height | +| Grouped Display | Toggle grouped display
    ![Grouped Display](https://static-docs.nocobase.com/202410101125056.png) | +| Stacked Display | Toggle stacked display
    ![Stacked Display](https://static-docs.nocobase.com/202410101125891.png) | +| Percentage Display | Toggle percentage display
    ![Percentage Display](https://static-docs.nocobase.com/202410101126148.png) | diff --git a/docs/fr-FR/handbook/data-visualization/antd-charts/dual-axes.md b/docs/fr-FR/handbook/data-visualization/antd-charts/dual-axes.md new file mode 100644 index 000000000..e2c6f335c --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/antd-charts/dual-axes.md @@ -0,0 +1,13 @@ +# Dual-Axis Chart + +## Data Configuration + +### 2 metrics, 1 dimension + +![](https://static-docs.nocobase.com/202410101132724.png) + +#### Configuration Options + +| Option | Description | +| ------- | -------------------------------------------------------- | +| Size | Sets the chart size, either with a fixed aspect ratio or a fixed height | diff --git a/docs/fr-FR/handbook/data-visualization/antd-charts/line.md b/docs/fr-FR/handbook/data-visualization/antd-charts/line.md new file mode 100644 index 000000000..7564b2e64 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/antd-charts/line.md @@ -0,0 +1,25 @@ +# Line Chart + +## Data Configuration + +### 1 Measure, 1 Dimension + +The line chart can be configured with one measure and one dimension, as illustrated below: + +![1 Measure, 1 Dimension](https://static-docs.nocobase.com/202410101109866.png) + +### 1 Measure, 1 Axis Dimension, One Category Dimension + +Configure one metric and two dimensions. One of the dimensions is the X-axis field (X field) and the other is the Series field (Series field). + +![1 Measure, 1 Axis Dimension, One Category Dimension](https://static-docs.nocobase.com/202410101113944.png) + +## Configuration Options + +| Configuration Option | Description | +| -------------------- | --------------------------------------------------- | +| X-axis Field | The dimension field that defines the X-axis | +| Series Field | The dimension field that defines the categories | +| Size | Set the size of the chart, either fixed aspect ratio or fixed height | +| Smooth Curves | Enable or disable smooth curve rendering | +| Stack Data | Whether to stack the data values on top of each other | diff --git a/docs/fr-FR/handbook/data-visualization/antd-charts/overview.md b/docs/fr-FR/handbook/data-visualization/antd-charts/overview.md new file mode 100644 index 000000000..1aa68b12a --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/antd-charts/overview.md @@ -0,0 +1,4 @@ +# Overview + +Use Ant Design Charts 2.x for data visualization, supporting common basic chart types. + diff --git a/docs/fr-FR/handbook/data-visualization/antd-charts/pie.md b/docs/fr-FR/handbook/data-visualization/antd-charts/pie.md new file mode 100644 index 000000000..39e1cc182 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/antd-charts/pie.md @@ -0,0 +1,13 @@ +# Pie Chart + +## Data Configuration + +### 1 Metric, 1 Dimension + +![1 Metric, 1 Dimension](https://static-docs.nocobase.com/202410101131823.png) + +## Configuration Options + +| Option | Description | +| -------- | ----------------------------------------------------------------- | +| Size | Adjust the chart size, either by maintaining a fixed aspect ratio or setting a fixed height. | diff --git a/docs/fr-FR/handbook/data-visualization/antd-charts/scatter.md b/docs/fr-FR/handbook/data-visualization/antd-charts/scatter.md new file mode 100644 index 000000000..4e476e0a9 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/antd-charts/scatter.md @@ -0,0 +1,21 @@ +# Scatter Chart + +## Data Configuration + +### 1 Measure, 1 Dimension + +![1 Measure, 1 Dimension](https://static-docs.nocobase.com/202410101138172.png) + +### 1 Measure, 1 Axis Dimension, One Series Dimension + +Configure one metric and two dimensions. One of the dimensions is the X-axis field (X field) and the other is the Series field (Series field). + +![1 Measure, 1 Axis Dimension, One Series Dimension](https://static-docs.nocobase.com/202410101137837.png) + +## Configuration Options + +| Option | Description | +| -------------- | ------------------------------------------------------- | +| X-axis Field | The dimension used to define the X-axis of the chart. | +| Series Field | The dimension used to categorize data points into distinct series. | +| Size | Set chart’s size, either by setting a fixed aspect ratio or a fixed height. | diff --git a/docs/fr-FR/handbook/data-visualization/antd/overview.md b/docs/fr-FR/handbook/data-visualization/antd/overview.md new file mode 100644 index 000000000..8907126dc --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/antd/overview.md @@ -0,0 +1,4 @@ +# Overview + +Provide tables and statistical presentations using Ant Design. + diff --git a/docs/fr-FR/handbook/data-visualization/antd/statistic.md b/docs/fr-FR/handbook/data-visualization/antd/statistic.md new file mode 100644 index 000000000..b95b2c1e5 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/antd/statistic.md @@ -0,0 +1,13 @@ +# Statistical Values + +## Data Configuration + +### 1 Metric + +![1 Metric](https://static-docs.nocobase.com/202410101147166.png) + +## Configuration Options + +| Configuration Item | Description | +| ------------------ | -------------------------------- | +| Link | Fixed link, clickable for redirection | diff --git a/docs/fr-FR/handbook/data-visualization/antd/table.md b/docs/fr-FR/handbook/data-visualization/antd/table.md new file mode 100644 index 000000000..3ab6d09a2 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/antd/table.md @@ -0,0 +1,22 @@ +# Table + +## Data Configuration + +### Multiple Metrics, Multiple Dimensions + +![Multiple Metrics, Multiple Dimensions](https://static-docs.nocobase.com/202410101142369.png) + +## Common JSON Configuration + +### Adjusting Column Order + +```json +{ + "columns": [ + { "key": "fieldName1", "dataIndex": "fieldName1", "title": "fieldTitle1" }, + { "key": "fieldName2", "dataIndex": "fieldName2", "title": "fieldTitle2" } + ] +} +``` + +![](https://static-docs.nocobase.com/202410101145770.png) diff --git a/docs/fr-FR/handbook/data-visualization/block-charts.md b/docs/fr-FR/handbook/data-visualization/block-charts.md new file mode 100644 index 000000000..eb14202e7 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/block-charts.md @@ -0,0 +1,4 @@ +# Block Charts + + + diff --git a/docs/fr-FR/handbook/data-visualization/dev/index.md b/docs/fr-FR/handbook/data-visualization/dev/index.md new file mode 100644 index 000000000..6e5670b30 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/dev/index.md @@ -0,0 +1,621 @@ +# Extend Chart Types + +## Overview + +NocoBase uses [Ant Design Charts](https://g2plot.antv.antgroup.com/) as the default chart library, which includes commonly used chart types. Besides the built-in chart types, NocoBase also supports integrating other chart types or libraries, such as ECharts. This section primarily explains how to extend a new chart type. + +## Defining a Chart + +In the visualization plugin, each chart type is defined using a class that must implement the [ChartType](#charttype) interface. To simplify development, we provide a [Chart](#chart) base class, which partially implements the `ChartType` interface. In most cases, to extend a chart type, you only need to inherit from the `Chart` class and implement the required methods. + +```ts +class CustomChart extends Chart { + constructor({ name, title, Component, config }: ChartProps) { + // ... + } + + init( + fields: FieldOption[], + { + measures, + dimensions, + }: { measures: MeasureProps[]; dimensions: DimensionProps[] }, + ) { + // ... + } + + getProps({ data, general, advanced, fieldProps }: RenderProps) { + // ... + } + + getReference() { + // ... + } +} +``` + +### Chart Information + +The basic information for a chart type includes: + +| Parameter | Description | +| ----------- | --------------------- | +| `name` | Identifier | +| `title` | Display title | +| `Component` | Component used to render the chart | +| `config` | Basic visualization configuration form | + + + +Example: + +```ts +new CustomChart({ + name: 'custom', + title: 'Custom Chart', + Component: CustomChart, + config: ['xField', 'yField', 'seriesField'], +}); +``` + +Refer to [Chart](#chart) for specific usage. + +### Initializing Chart Configuration + +When a user selects a chart, we may want to initialize the chart configuration based on the user’s data query settings to reduce manual configuration. +Each time a chart is selected, the plugin internally calls the `init()` method of the chart class, passing all the field configurations from the current data table, as well as the current measures and dimensions configuration. The `init()` method can then initialize the chart configuration based on the parameters. +The `Chart` class includes an `infer()` method, which can be used to easily infer the initial x-axis, y-axis, and category fields configuration. +Example: + +```ts +init( + fields: FieldOption[], + { + measures, + dimensions, + }: { measures: MeasureProps[]; dimensions: DimensionProps[] }, +) { + const { xField, yField, seriesField } = this.infer(fields, { measures, dimensions }); + return { + general: { + xField: xField?.value, + yField: yField?.value, + seriesField: seriesField?.value, + }, + }; +} +``` + +### Retrieving Chart Component Properties + +After obtaining the user’s chart configuration, we may need to further process the data before passing it as properties to the chart component. The `getProps()` method accepts chart data, chart configuration, and related field information as parameters, processes them, and returns the final properties passed to the chart component. + +For example, in a “statistics” chart: + +```ts +getProps({ data, fieldProps, general, advanced }: RenderProps) { + const record = data[0] || {}; + const field = general?.field; + const props = fieldProps[field]; + return { + value: record[field], + formatter: props?.transformer, + ...general, + ...advanced, + }; +} +``` + +### Retrieving Chart Component References + +The `getReference()` method retrieves reference documentation for the current chart type. + +```ts +getReference() { + return { + title: this.title, + link: `https://ant.design/components/${this.name}`, + }; +} +``` + +## Adding a Chart + +After defining the chart class, we need to add the class instance to the data visualization plugin. When selecting charts, they are grouped for display, with the default group being "Built-in". + + + +We can add a group of charts or add charts to an existing group. + +```typescript +import DataVisualization from '@nocobase/plugin-data-visualization' + +class CustomChartsPlugin extends Plugin { + async load() { + const plugin = this.app.pm.get(DataVisualization); + + // Add a group of charts + plugin.charts.addGroup('custom', [...]); + + // Set a group of charts, + // can be used for overriding an exist group + plugin.charts.setGroup('custom', [...]); + + // Append a chart to an exist group + // The name of the chart is required to be unique in a group + plugin.charts.add('Built-in', new CustomChart({ + // ... + })); + } +} +``` + +Refer to [ChartGroup](#chartgroup) for more details + +## Examples + +- [src/client/chart/g2plot](https://github.com/nocobase/nocobase/tree/main/packages/plugins/%40nocobase/plugin-data-visualization/src/client/chart/g2plot) + +- [src/client/chart/antd](https://github.com/nocobase/nocobase/tree/main/packages/plugins/%40nocobase/plugin-data-visualization/src/client/chart/antd) + +- [ECharts Integration Example](../step-by-step/index.md) + +## API + +### ChartGroup + +#### `addGroup()` + +Add a group of charts. + +```typescript +import DataVisualization from '@nocobase/plugin-data-visualization' + +class CustomChartsPlugin extends Plugin { + async load() { + const plugin = this.app.pm.get(DataVisualization); + + // Add a group of charts + plugin.charts.addGroup('custom', { + title: 'Custom', + charts: [...], + sort: 1 + }); + } +} +``` + +**Signature** + +- `addGroup(name: string, charts: ChartType[])` + +**Types** + +```ts +interface Group { + title: string; + charts: ChartType[]; + sort?: number; +} +``` + +**Details** + +| Parameter | Type | Description | +| --------- | ------------- | ----------------------- | +| `name` | `string` | Grouped Chart Title | +| `charts` | `ChartType[]` | Array of charts | +| `sort` | `number` | Optional, Grouped Chart Sorting| + +#### `add()` + +Add a chart to an existing group. + +```typescript +import DataVisualization from '@nocobase/plugin-data-visualization'; + +class CustomChartsPlugin extends Plugin { + async load() { + const plugin = this.app.pm.get(DataVisualization); + + plugin.charts.add( + 'Built-in', + new CustomChart({ + // ... + }), + ); + } +} +``` + +**Signature** + +- `add(group: string, chart: ChartType)` + +**Details** + +| Parameter | Type | Description | +| ---------- | ----------- | ----------------------- | +| `group` | `string` | Unique identifier for the chart group | +| `chart` | `ChartType` | Chart to add | + +### Chart + +#### `constructor()` + +Constructor to create a new `Chart` instance. + +**Signature** + +- `constructor({ name, title, Component, config }: ChartProps)` + +**Types** + +```ts +export type ChartProps = { + name: string; + title: string; + Component: React.FC; + config?: Config[]; +}; + +export type FieldConfigProps = Partial<{ + name: string; + title: string; + required: boolean; + defaultValue: any; + description: string; + options: { label: string; value: any }[]; + componentProps: Record; +}>; +export type ConfigType = + | (FieldConfigProps & { configType?: string }) + | ((props?: FieldConfigProps) => AnySchemaProperties) + | AnySchemaProperties; +export type Config = string | ConfigType; +``` + +**Details** + +| Property | Type | Description | +| ----------- | --------------------- | --------------------------------- | +| `name` | `string` | Unique identifier for the chart | +| `title` | `string` | Display title of the chart | +| `Component` | `React.FC` | Component used to render the chart | +| `config` | [`Config[]`](#config) | Optional. Visualization configuration form | + +##### Config + +The `config` supports multiple formats, which can be used in combination: + +1. UI Schema field configuration. If you want to use fields already configured in the "Data Configuration" section within the UI Schema, you can use `x-reactions': '{{ useChartFields }}'`. + +```ts +{ + xField: { + title: 'xField', + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-reactions': '{{ useChartFields }}', + required, + } +} +``` + +2. Using predefined UI Schema. + +For example, `config: ['field']` corresponds to: + +```typescript +{ + field: { + title: 'Field', + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-reactions': '{{ useChartFields }}', + required, + } +} +``` + +3. Using predefined UI Schema with some properties replaced, where `property` refers to the predefined UI Schema identifier. + +```typescript +config: [ + { + property: 'field', + name: 'angleField', + title: 'angleField', + defaultValue: 'default', + }, +]; +``` + +This corresponds to: + +```typescript +{ + angleField: { + title: 'angleField', + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-reactions': '{{ useChartFields }}', + required, + defaultValue: 'default', + } +} +``` + +You can find all predefined UI Schema options in the `/src/client/chart/config.ts` file. +Additionally, you can add new predefined UI Schema options using the [`addConfigs()`](#addconfigs) method. + +#### `addConfigTypes()` + +Adds predefined UI Schema for the chart's visualization configuration form. + +```ts +// Add +const boolean = ({ name, title, defaultValue = false }: FieldConfigProps) => { + return { + [name]: { + 'x-content': lang(title), + type: 'boolean', + 'x-decorator': 'FormItem', + 'x-component': 'Checkbox', + default: defaultValue, + }, + }; +}; +chart.addConfigTypes({ booleanField }); + +// Usage +new Chart({ + config: [ + 'boolean', + { + configType: 'boolean', + name: 'customBooleanField', + title: 'Custom Boolean Field', + defaultValue: true, + }, + ], +}); +``` + +**Signature** + +- `addConfigTypes(configs: { [key: string]: ConfigType })` + +**Types** + +```ts +export type ConfigType = + | (FieldConfigProps & { configType?: string }) + | ((props?: FieldConfigProps) => AnySchemaProperties) + | AnySchemaProperties; +``` + +**Details** + +`addConfigTypes()` accepts an object, where the `key` is the unique identifier of the configuration, and the value is a method that retrieves a predefined UI Schema. This method takes parameters that can be replaced and returns the corresponding UI Schema field configuration. + +#### `init()` + +This function initializes the chart configuration when a chart is selected. It defines the initial settings for the chart’s properties. + +**Signature** + +```ts +init?: ( + fields: FieldOption[], + query: { + measures?: MeasureProps[]; + dimensions?: DimensionProps[]; + }, +) => { + general?: any; + advanced?: any; +}; +``` + +**Types** + +```ts +export type FieldOption = { + value: string; + label: string; + key: string; + alias?: string; + name?: string; + type?: string; + interface?: string; + uiSchema?: ISchema; + target?: string; + targetFields?: FieldOption[]; +}; + +export type MeasureProps = { + field: string | string[]; + aggregation?: string; + alias?: string; +}; + +export type DimensionProps = { + field: string | string[]; + alias?: string; + format?: string; +}; +``` + +**Details** + +| Parameter | Type | Description | +| -------------------- | ----------------- | ------------------------------------------------ | +| `fields` | `FieldOption[]` | Contains key attributes of the fields in the current data table. | +| `query.measures` | `MeasureProps[]` | Configuration details for the measure fields. | +| `query.dimensions` | `DimensionProps[]`| Configuration details for the dimension fields. | + +#### `infer()` + +Deriving the Initial Configuration of Charts. + +```ts +// Example for a pie chart +init(fields, { measures, dimensions }) { + const { xField, yField } = this.infer(fields, { measures, dimensions }); + return { + general: { + colorField: xField?.value, + angleField: yField?.value, + }, + }; +}; +``` + +**Signature** + +```ts +infer: (fields: FieldOption[], query: { + measures?: MeasureProps[]; + dimensions?: DimensionProps[]; +}) => { + xField: FieldOption; + yField: FieldOption; + seriesField: FieldOption; + colorField: FieldOption; + yFields: FieldOption[]; +} +``` + +**Details** + +| Property | Type | Description | +| -------------- | --------------- | ----------------- | +| `xField` | `FieldOption` | The field to be used on the x-axis. | +| `yField` | `FieldOption` | The field to be used on the y-axis. | +| `seriesField` | `FieldOption` | The field representing categories or series. | +| `colorField` | `FieldOption` | The field used to define the color in the chart. | +| `yFields` | `FieldOption[]` | Multiple fields for the y-axis (used in complex charts). | + +#### `getProps()` + +This function processes the raw chart data and chart configuration metadata and transforms them into properties required by the rendering component. + +**signature** + +- `getProps({ data, general, advanced, fieldProps }: RenderProps)` + +**Types** + +```ts +export type RenderProps = { + data: Record[]; + general: any; + advanced: any; + fieldProps: { + [field: string]: { + label: string; + transformer: Transformer; + interface: string; + }; + }; +}; +``` + +| Property | Type | Description | +| -------------- | --------------------------------- | --------------------------------------- | +| `data` | `Record[]` | The raw data to be displayed in the chart. | +| `general` | `any` | The configuration options from the chart’s visualization form. | +| `advanced` | `any` | The advanced JSON-based configuration for the chart. | +| `fieldProps` | `{ [field: string]: FieldProps }` | Metadata about the fields from the data table, used for display purposes. | + +##### FieldProps + +| Property | Type | Description | +| -------------- | ------------- | ----------------------- | +| `label` | `string` | The label displayed for the field. | +| `transformer` | `Transformer` | A function for transforming field values. | +| `interface` | `string` | The interface type of the field. | + +#### `getReference()` + +Retrieves reference documentation for the chart component, including the title and a direct link to the documentation. + +```ts +getReference() { + return { + title: this.title, + link: `https://ant.design/components/${this.name}`, + }; +} +``` + +**Signature** + +```ts +getReference?: () => { + title: string; + link: string; +}; +``` + +### ChartType + +#### `name` + +- `string`. Identifier for the chart type. + +#### `title` + +- `string`. The display title of the chart. + +#### `Component` + +- `React.FC`. The React component used to render the chart. + +#### `schema` + +- `ISchema`. The UI Schema for the chart’s visualization configuration. + +#### `init()` + +This function initializes the chart configuration. + +**Signature** + +```ts +init?: ( + fields: FieldOption[], + query: { + measures?: MeasureProps[]; + dimensions?: DimensionProps[]; + }, +) => { + general?: any; + advanced?: any; +}; +``` + +#### `getProps()` + +Handles the processing and retrieval of properties for the chart component. + +**Signature** + +- `getProps(props: RenderProps): any` + +#### `getReference()` + +Retrieves reference documentation for the chart component. + +**Signature** + +```ts +getReference?: () => { + title: string; + link: string; +}; +``` diff --git a/docs/fr-FR/handbook/data-visualization/dev/static/FHzPbretYo6KWexv9wccM91Hnff.png b/docs/fr-FR/handbook/data-visualization/dev/static/FHzPbretYo6KWexv9wccM91Hnff.png new file mode 100644 index 000000000..836973ae8 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/dev/static/FHzPbretYo6KWexv9wccM91Hnff.png differ diff --git a/docs/fr-FR/handbook/data-visualization/faq.md b/docs/fr-FR/handbook/data-visualization/faq.md new file mode 100644 index 000000000..94384ccb8 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/faq.md @@ -0,0 +1,43 @@ +# FAQ + +## How should JSON configuration be used? + +Refer to the documentation or use a demo to understand the properties supported by different components through the chart component reference link. Configuration is done using JSON key-value pairs. + +
    + + + +### Example: Changing the Order of Table Columns + +The table component used is Antd's table component. Open the reference link Table. The API section corresponds to all the configurable properties supported by the component. + + + +To adjust the order of table columns, modify the `columns` configuration. Example: + +```ts +{ + "columns": [ + { "key": "fieldName1", "dataIndex": "fieldName1", "title": "fieldTitle1" }, + { "key": "fieldName2", "dataIndex": "fieldName2", "title": "fieldTitle2" } + ] +} +``` + +## Can JSON configuration support the use of functions? + +JavaScript expressions can be wrapped in `{{}}`. Example: + +```json +{ + "label": { + "type": "inner", + "content": "{{ ({ percent }) => `${(percent * 100).toFixed(0)}%` }}" + } +} +``` + +## What is the primary use case for custom fields in chart filter blocks? + +When there are charts from different data tables within a chart block and the same filter field is needed to filter these charts, [custom fields](./user/filter.md#custom-fields) can be used. For example, you might want to filter data within a specific time period. diff --git a/docs/fr-FR/handbook/data-visualization/index.md b/docs/fr-FR/handbook/data-visualization/index.md new file mode 100644 index 000000000..2ea5cfb98 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/index.md @@ -0,0 +1,33 @@ +# Data Visualization + + + +## Introduction + +The NocoBase data visualization plugin provides robust data retrieval features and a rich variety of chart components. Based on system Collection data, users can quickly build visual dashboards, organize charts with flexibility, and conduct insightful business data analysis. + +![](https://static-docs.nocobase.com/51be43d5400d6294f6c20d11009f23c4.png) + +## Installation + +This is a built-in plugin, so no additional installation is required. + +## Related Documentation + +- User Manual + - [Chart Block](./user/chart-block.md) + - [Configuring Charts](./user/configure.md) + - [Filter Block](./user/filter.md) +- Developer Guide + - [API Reference](./dev/index.md) + - [Step-by-Step Tutorial](./step-by-step/index.md) +- [FAQ](./faq.md) + +## RoadMap + +- Simplified data processing and transformation +- Ability to add charts in pop-up windows +- Embed other blocks (e.g., Markdown) in chart blocks +- Save configurations as templates +- Enable data drill-down +- Improved permissions control diff --git a/docs/fr-FR/handbook/data-visualization/static/2023-11-28-14-06-23.png b/docs/fr-FR/handbook/data-visualization/static/2023-11-28-14-06-23.png new file mode 100644 index 000000000..defc3e8a5 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/static/2023-11-28-14-06-23.png differ diff --git a/docs/fr-FR/handbook/data-visualization/step-by-step/index.md b/docs/fr-FR/handbook/data-visualization/step-by-step/index.md new file mode 100644 index 000000000..e7c112965 --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/step-by-step/index.md @@ -0,0 +1,369 @@ +# Extended Tutorial + +> Using the addition of ECharts charts as an example, the complete code is available in the `@nocobase/plugin-sample-add-custom-charts` plugin. + +## Creating a New Plugin + +Follow the steps in the [Plugin Development Guide](https://docs.nocobase.com/development/your-first-plugin) to create a new plugin. Be sure to include the dependencies `echarts`, `echarts-for-react`, and `@nocobase/plugin-data-visualization`, placing these external dependencies in the `devDependencies` section of the `package.json` file. + +```bash +yarn pm create @nocobase/plugin-sample-add-custom-charts +npx lerna add echarts --scope=@nocobase/plugin-sample-add-custom-charts --dev +npx lerna add echarts-for-react --scope=@nocobase/plugin-sample-add-custom-charts --dev +``` + +```typescript +// package.json + +{ + "name": "@nocobase/plugin-sample-add-custom-charts", + "version": "0.14.0-alpha.7", + "main": "dist/server/index.js", + "devDependencies": { + "echarts": "^5.4.3", + "echarts-for-react": "^3.0.2" + }, + "peerDependencies": { + "@nocobase/client": "0.x", + "@nocobase/server": "0.x", + "@nocobase/test": "0.x", + "@nocobase/plugin-data-visualization": "0.x" + } +} +``` + +## ECharts React Component + +Unlike G2Plot, where each chart type is a distinct component, ECharts utilizes a single component that can render various charts by passing different parameters. Since the component provided by `echarts-for-react` is a `PureComponent`, we need to wrap it into a `FunctionComponent`. + +```typescript +// client/echarts/react-echarts.tsx + +import React, { useEffect } from 'react'; +import ReactEChartsComponent, { EChartsInstance, EChartsReactProps } from 'echarts-for-react'; + +export const ReactECharts = (props: EChartsReactProps['option']) => { + const echartRef = React.useRef(); + useEffect(() => { + echartRef.current?.resize(); + }); + return (echartRef.current = e)} />; +}; +``` + +The `echarts-for-react` component does not execute a `resize` operation on its initial render. As the NocoBase visualization plugin might need to determine whether to display the component based on the current configuration while setting up charts, this could result in the component not displaying correctly. Therefore, we manually execute `resize` each time to ensure proper rendering. + +## Extending the `Chart` Class + +> Before proceeding, please refer to the [Development Guide](../dev/index.md) to familiarize yourself with the relevant APIs. + +### Step 1 + +Since ECharts serves as a comprehensive charting library, we may need to add multiple chart types simultaneously. To facilitate this, we start by extending the basic `Chart` class to create an `ECharts` class that implements some foundational methods. + +```typescript +// client/echarts/echarts.ts + +import { Chart } from '@nocobase/plugin-data-visualization/client'; + +export class ECharts extends Chart { + constructor({ + name, + title, + series, + config, + }: { + name: string; + title: string; + series: any; + config?: ChartProps['config']; + }) { + super({ + name, + title, + component: ReactECharts, + config: ['xField', 'yField', 'seriesField', ...(config || [])], + }); + this.series = series; + } +} +``` + +ECharts primarily configures different types of charts via the `series` parameter. Therefore, when constructing the base class, we add a `series` parameter and pass in the previously defined `ReactECharts` component. The `config` parameter is preset with default values for `xField`, `yField`, and `seriesField`, enabling our default visualization configuration to produce results similar to those shown in the example. + +![](https://static-docs.nocobase.com/9a1ff5ff7c9f409978292f0d771b4358.png) + +### Step 2 + +Since most commonly used chart types require configurations for the x-axis, y-axis, and classification fields, we first implement a general `init` interface to initialize the chart’s default configuration. If a chart requires additional configuration items upon initialization, this method can be overridden in derived classes. In the implementation, we can leverage the `infer` method from the `Chart` class to determine default field configurations based on the provided measures and dimensions. + +```typescript +init: ChartType['init'] = (fields, { measures, dimensions }) => { + const { xField, yField, seriesField } = this.infer(fields, { + measures, + dimensions, + }); + return { + general: { + xField: xField?.value, + yField: yField?.value, + seriesField: seriesField?.value, + }, + }; +}; +``` + +### Step 3 + +Next, we implement the `getProps` method, which primarily retrieves chart-related configurations and converts them into properties corresponding to the ECharts component. This method can also set default properties that we prefer not to expose in the configuration options. The following code implementation serves as a general guide. + +```typescript +getProps({ data, general, advanced, fieldProps }: RenderProps) { + const { xField, yField, seriesField } = general; + const xLabel = fieldProps[xField]?.label; + const yLabel = fieldProps[yField]?.label; + let seriesName = [yLabel]; + if (seriesField) { + seriesName = Array.from(new Set(data.map((row: any) => row[seriesField]))).map((value) => value || 'null'); + } + return deepmerge( + { + legend: { + data: seriesName, + }, + tooltip: { + data: seriesName, + }, + dataset: [ + { + dimensions: [xField, ...(seriesField ? seriesName : [yField])], + source: data, + }, + { + transform: [ + { + type: 'data-visualization:transform', + config: { fieldProps }, + }, + { + type: 'data-visualization:toSeries', + config: { xField, yField, seriesField }, + }, + ], + }, + ], + series: seriesName.map((name) => ({ + name, + datasetIndex: 1, + ...this.series, + })), + xAxis: { + name: xLabel, + type: 'category', + }, + yAxis: { + name: yLabel, + }, + animation: false, + }, + advanced, + ); + } +``` + +This logic primarily involves processing raw data, chart configurations, field metadata, and data transformation settings into the format required for component rendering. In ECharts, data processing can be managed by registering `transform` functions, as detailed in the ECharts documentation. + +### Step 4 + +Finally, we implement a method to retrieve reference documentation via `getReference`. ECharts consolidates all chart parameters on a single page, so we define this method straightforwardly. + +```typescript +getReference() { + return { + title: 'ECharts', + link: 'https://echarts.apache.org/en/option.html', + }; + } +``` + +## Defining Charts + +With the `ECharts` class established, defining charts becomes a straightforward process. For most common 2D charts, the general logic is already encapsulated within the `ECharts` class, eliminating the need for additional extensions. + +```typescript +new ECharts({ + name: 'line', + title: 'Line Chart', + series: { type: 'line' }, +}); + +new ECharts({ + name: 'column', + title: 'Column Chart', + series: { type: 'bar' }, +}); + +new ECharts({ + name: 'area', + title: 'Area Chart', + series: { type: 'line', areaStyle: {} }, +}); +``` + +You can also extend some visualization configurations as needed. + +```typescript +new ECharts({ + name: 'line', + title: 'Line Chart', + series: { type: 'line' }, + config: [ + { + property: 'booleanField', + name: 'smooth', + title: 'isSmooth', + }, + ], +}); +``` + +For certain charts, the general methods may not suffice, requiring further customization. + +Bar Chart: + +```typescript +export class Bar extends ECharts { + constructor() { + super({ + name: 'bar', + title: 'Bar Chart', + series: { type: 'bar' }, + }); + this.config = [ + { + property: 'yField', + title: 'xField', + }, + { + property: 'xField', + title: 'yField', + }, + 'seriesField', + ]; + } + + getProps({ data, general, advanced, fieldProps }: RenderProps) { + const props = super.getProps({ data, general, advanced, fieldProps }); + const xLabel = fieldProps[general.xField]?.label; + const yLabel = fieldProps[general.yField]?.label; + props.xAxis = { + ...props.xAxis, + type: 'value', + name: yLabel, + }; + props.yAxis = { + ...props.yAxis, + type: 'category', + name: xLabel, + }; + return props; + } +} + +new Bar(); +``` + +Pie Chart: + +```typescript +export class Pie extends ECharts { + constructor() { + super({ + name: 'pie', + title: 'Pie Chart', + series: { type: 'pie' }, + }); + this.config = [ + { + property: 'field', + name: 'angleField', + title: 'angleField', + required: true, + }, + { + property: 'field', + name: 'colorField', + title: 'colorField', + required: true, + }, + ]; + } + + init: ChartType['init'] = (fields, { measures, dimensions }) => { + const { xField, yField } = this.infer(fields, { measures, dimensions }); + return { + general: { + colorField: xField?.value, + angleField: yField?.value, + }, + }; + }; + + getProps({ data, general, advanced, fieldProps }: RenderProps) { + return deepmerge( + { + legend: {}, + tooltip: {}, + dataset: [ + { + dimensions: [general.colorField, general.angleField], + source: data, + }, + { + transform: { + type: 'data-visualization:transform', + config: { fieldProps }, + }, + }, + ], + series: { + name: fieldProps[general.angleField]?.label, + datasetIndex: 1, + ...this.series, + }, + }, + advanced, + ); + } +} + +new Pie(); +``` + +## Adding Charts + +```typescript +// client/index.ts +import DataVisualizationPlugin from '@nocobase/plugin-data-visualization/client'; + +export class PluginSampleAddCustomChartClient extends Plugin { + async afterAdd() { + // await this.app.pm.add() + } + + async beforeLoad() { + const plugin = this.app.pm.get(DataVisualizationPlugin); + plugin.charts.addGroup('echarts', { + title: 'ECharts', + charts: [ + new ECharts(), + // ... + // ... + ], + }); + } + + // You can get and modify the app instance here + async load() {} +} +``` diff --git a/docs/fr-FR/handbook/data-visualization/step-by-step/static/IJiQbtTxwoLz8lxsgbwc77Ggntb.png b/docs/fr-FR/handbook/data-visualization/step-by-step/static/IJiQbtTxwoLz8lxsgbwc77Ggntb.png new file mode 100644 index 000000000..82d6ea93f Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/step-by-step/static/IJiQbtTxwoLz8lxsgbwc77Ggntb.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/chart-block.md b/docs/fr-FR/handbook/data-visualization/user/chart-block.md new file mode 100644 index 000000000..58d38260a --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/user/chart-block.md @@ -0,0 +1,69 @@ +# Chart Block + +The chart block is a panel used for organizing multiple charts. + +## Add Block + +Click "Add Block" - "Charts" to create an empty chart block. + +![](https://static-docs.nocobase.com/790faf0a126e4ffcc3ff976818325cfd.png) + +Inside the chart block, click "Add Block" - "Chart" and select the corresponding data Collection to create and configure charts. Only tables that the user has permission to view can be used for chart configuration, otherwise, they will be hidden from the options. + +![](https://static-docs.nocobase.com/93ed2fada2478fba1b243d8705717a34.png) + +## Block Settings + +![](https://static-docs.nocobase.com/202409022042315.png) + +- Edit Block Title - Allows setting a title for multiple charts in the block. +- Show Background - Determines whether to display the background color of the chart block. +- Show Padding - Determines whether to display the padding of the chart block. + +The background and padding settings are particularly useful when there is only one chart in the block or when viewing on mobile devices, helping the style appear more comfortable. + + + +The charts within a chart block can be freely dragged and organized like regular blocks. + +- Click the "Configure" button to modify the settings of the current chart. +- Click the "Duplicate" button to quickly copy the current chart. +- Click the "Delete" button to remove the current chart. + +## Configure Block Operations + +:::warning{title=Note} +The configuration operation feature applies to chart blocks added in version `v1.4.0-alpha` and later. +::: + +### Refresh and Auto-Refresh + +Chart blocks support configuring a refresh button. Clicking it refreshes all the charts within the block. + +![](https://static-docs.nocobase.com/202409022051107.png) + +In configuration mode, you can set the refresh button to configure the auto-refresh interval, which will apply to all charts in the block. The auto-refresh interval configured here will apply to all users who access the page by default. + +![](https://static-docs.nocobase.com/202409022054189.png) + +Users can also modify the auto-refresh interval using the button on the right, but this adjustment is only effective temporarily and will reset after the page is refreshed. + +![](https://static-docs.nocobase.com/202409022056097.png) + +## Configure Chart Operations + +:::info{title=Note} +The operation buttons configured for individual charts will only appear when the mouse hovers over the chart and will automatically hide when the mouse leaves. +::: + +### Refresh and Auto-Refresh + +Individual charts also support configuring a refresh button, functioning the same way as the block's refresh button, but only affecting the current chart. + +![](https://static-docs.nocobase.com/202409022101033.png) + +:::info{title=Note} + +- If both the chart block and an individual chart are configured with auto-refresh intervals, the interval configured for the individual chart takes precedence. +- If the chart block is configured with an auto-refresh interval, and an individual chart either has auto-refresh disabled or has no refresh button configured, the auto-refresh interval of the chart block will apply. +::: diff --git a/docs/fr-FR/handbook/data-visualization/user/configure.md b/docs/fr-FR/handbook/data-visualization/user/configure.md new file mode 100644 index 000000000..7025248dd --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/user/configure.md @@ -0,0 +1,120 @@ +# Configuration Panel + +The chart configuration panel is organized into three primary sections: Data Configuration, Chart Configuration, and Chart Preview. + +![Configuration Panel Image](https://static-docs.nocobase.com/202404192019222.png) + +## Data Configuration + +![Data Configuration Image](https://static-docs.nocobase.com/202404192020544.png) + +- The drop-down at the top represents the current Collection being configured, which can be switched using the drop-down menu. +- Once the configuration is complete, clicking "Run Query" will retrieve the data according to the settings. The "Data" panel will display the resulting data. + +### Measures + +![Measures Image](https://static-docs.nocobase.com/202404192023854.png) + +Measure fields contain the key data that the chart will display. These fields can be aggregated using functions such as `Sum`, `Count`, `Avg`, `Max`, and `Min`. You can add multiple measure fields, and assign aliases to them as needed. + +### Dimensions + +![Dimensions Image](https://static-docs.nocobase.com/202404192025717.png) + +Dimension fields determine how the data is grouped within the chart. For date-type fields, various formatting options are available, as shown in the image. Formatting is handled by database functions (e.g., `date_format` in MySQL). For other data types, refer to the [Data Transformation](#数据转换) section. + +:::info +**Dimension Formatting VS Data Transformation** + +- Dimension formatting occurs before the final data is fetched, grouping data according to the formatted dimension values. This is commonly needed when filtering data by time periods. +- Data transformation further refines the data after it is retrieved, enhancing readability and presentation. This transformation is applied on the frontend. + ::: + +### Filter + +![Filter Image](https://static-docs.nocobase.com/202404192029597.png) + +Filters are applied to the data before grouping. You can use variables for dynamic filtering: + +- Current User: Information related to the currently logged-in user. +- Date Variables: Date ranges dynamically calculated based on the current date. + - Current Filter: Custom filter fields set within the current chart block. Refer to [Filter Block](./filter.md). + +### Sort and Limit + +![Sort and Limit Image](https://static-docs.nocobase.com/202404192034106.png) + +The default DataSet is limited to a maximum of 2000 entries. + +### Cache + +![Cache Image](https://static-docs.nocobase.com/202404192035918.png) + +When enabled cache, the chart will display data from the cache. You can configure the cache duration as needed. + +## Chart Configuration + +### Container Configuration + +This section allows you to configure the properties of the container component that displays the chart. + +- Chart Title +- Show Chart Border + +![Container Configuration Image](https://static-docs.nocobase.com/202404192037644.png) + +The display effect of the chart title: + +![Chart Title Display Image](https://static-docs.nocobase.com/202404192048473.png) + +The display effect when showing the chart border: + +![Chart Border Display Image](https://static-docs.nocobase.com/202404192048223.png) + +### Chart Configuration + +![Chart Configuration Image](https://static-docs.nocobase.com/202404192050696.png) + +- **Chart Type**: This is where you select the type of chart to display. NocoBase uses Ant Design Charts 2.x as the default chart library. To extend and use other chart libraries or components, see the [Development Guide](../dev/index.md). +- **Basic Configuration**: After selecting a chart type, basic visual configuration options appear, such as fields for the x-axis, y-axis, and classification. These field configurations are provided via dropdown menus, which list the basic fields and field aliases from the Collection. +- **JSON Configuration**: If the basic configuration doesn’t meet your requirements, you can configure additional chart component properties using JSON. Refer to the chart component documentation for details. To include JavaScript expressions in the JSON configuration, wrap them in `{{}}`. For example: + +```json +{ + "label": { + "type": "inner", + "content": "{{ ({ percent }) => `${(percent * 100).toFixed(0)}%` }}" + } +} +``` + +## Data Transformation + +![Data Transformation Image](https://static-docs.nocobase.com/202404192109597.png) + +Data transformation enables further processing of response data. The supported data types for transformation are `number`, `date`, `time`, and `datetime`. For fields not belonging to these types, you can manually assign one of these types to apply the corresponding transformation methods. + +Multiple transformation methods can be applied to the same field. The transformations are executed in sequence, with each step passing its result to the next. You can reorder the transformation steps by dragging them. + +:::warning +Be mindful that some transformation methods may alter the original data type. When applying multiple transformations, ensure that you choose the correct method based on the data type after each step. For instance, when formatting a number as currency by adjusting precision and adding a prefix, you should first apply the precision adjustment and then the prefix. This is because after adding the prefix, the number is converted to a string, and further precision adjustments will no longer apply. +::: + +Supported transformation methods: + +| Type | Method | Description | Converted Type | +| ------------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------ | +| Number (`number`) | Prefix | | `string` | +| | Suffix | | `string` | +| | Precision |`1`, `1.0`, `1.00`, `1.000`. | `number` | +| | Separator |`100,000.00` (English), `100.000,00` (German), etc. | `string` | +| | Percentage | | `string` | +| | Scientific Notation | | `number` | +| | Abbreviation | `1K`, `1M`, `1T`, `1B`, etc. | `string` | +| DateTime (`datetime`, `date`, `time`) | Formatting | Uses preset or custom formats like `YYYY-MM-DD`. Refer to the [dayjs](https://day.js.org/docs/en/display/format) documentation. | `string` | +| | Prefix | | `string` | +| | Suffix | | `string` | +| String (`string`) | Type Conversion| Converts the string into another type, such as date/time or number. | `Date` \| `number` | +| | Prefix | | `string` | +| | Suffix | | `string` | + diff --git a/docs/fr-FR/handbook/data-visualization/user/filter.md b/docs/fr-FR/handbook/data-visualization/user/filter.md new file mode 100644 index 000000000..a2617db2a --- /dev/null +++ b/docs/fr-FR/handbook/data-visualization/user/filter.md @@ -0,0 +1,60 @@ +# Filter Blocks + +The filter block within a chart block allows for dynamic filtering across multiple charts within the same block. + +## Enabling/Disabling + +To enable or disable a filter block, navigate within the chart block and select "Add Block" - "Filter." + +![](https://static-docs.nocobase.com/d0e6b116952fa6b719acb0f858b432c3.png) + +## Configuring Fields + +### Collection Fields + +For charts within the current chart block, you can create a filter form field by selecting the relevant fields directly from the associated Collection. + +![](https://static-docs.nocobase.com/e2ef150e9beb8c78004d9049a7536219.png) + +The form fields can be configured as follows: + +![](https://static-docs.nocobase.com/215f0b996e69bf2d5b99746e6d521c3d.png) + +- Edit field title. +- Edit description. +- Define the operator to be used when applying the filter. + ![](https://static-docs.nocobase.com/d6a593a330d27da4ea78124dfdb8450d.png) + +- Assign a default value to the field, utilizing variables if needed. The variable’s data type must align with the data type of the current field. + ![](https://static-docs.nocobase.com/37dee4008f3283db24d491fb8f0404fa.png) + + For instance: + + - Set the default value to the current user ID to automatically filter data for the current user when the page loads. + - Set the default value to the current date to automatically filter data for the current date when the page loads. + +### Custom Fields + +In certain scenarios, you may need to use a single filter field to filter different fields across various tables. For example, a single date field might be used to filter different date fields in different tables. In such cases, you can opt to create a custom field. + +![](https://static-docs.nocobase.com/87544594246453d175ef265030c0801a.png) + +When adding a custom field, you'll need to specify the field title, choose the appropriate field component, and configure it accordingly. Additionally, you can select a field from the data tables used in the current block to apply that field's metadata configuration directly, avoiding redundancy. + +![](https://static-docs.nocobase.com/ef09136d674d4b7356e819350bcac804.png) + +To implement a custom filter field, open the configuration of the relevant chart, then in the data query filter settings, add filter conditions using variables from the "Current filter." Ensure that the type of the field being filtered matches the type of the custom filter field. + +![](https://static-docs.nocobase.com/f9f2487c4da4b2024af1556743beab6c.png) + +For custom fields, you can also set the title, description, and default value. + +![](https://static-docs.nocobase.com/4a8feb12404f5cc5e74d589263307e5a.png) + +## Configuring Block Actions + +- **Filter:** Apply the filter conditions. +- **Reset:** Reset the filter form. +- **Collapse / Expand:** Collapse into a single row or expand into multiple rows. + +![](https://static-docs.nocobase.com/8619ac90fa045b3a9c6d6610f7be1a81.png) diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-15-16-21.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-15-16-21.png new file mode 100644 index 000000000..7127e73a7 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-15-16-21.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-15-17-23.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-15-17-23.png new file mode 100644 index 000000000..8a23b77ba Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-15-17-23.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-15-19-16.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-15-19-16.png new file mode 100644 index 000000000..2228432a5 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-15-19-16.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-17-48-11.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-17-48-11.png new file mode 100644 index 000000000..d127ba7a5 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-17-48-11.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-18-03-03.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-18-03-03.png new file mode 100644 index 000000000..030514f64 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-18-03-03.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-23-34.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-23-34.png new file mode 100644 index 000000000..ae3348255 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-23-34.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-27-51.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-27-51.png new file mode 100644 index 000000000..24f15ca77 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-27-51.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-29-44.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-29-44.png new file mode 100644 index 000000000..8e7f90175 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-29-44.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-32-30.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-32-30.png new file mode 100644 index 000000000..e5f02f3df Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-32-30.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-38-59.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-38-59.png new file mode 100644 index 000000000..e9b974b83 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-38-59.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-39-43.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-39-43.png new file mode 100644 index 000000000..4705a6ad2 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-39-43.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-42-32.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-42-32.png new file mode 100644 index 000000000..075874c61 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-42-32.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-45-41.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-45-41.png new file mode 100644 index 000000000..8979f6012 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-45-41.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-49-18.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-49-18.png new file mode 100644 index 000000000..17485590d Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-49-18.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-50-20.png b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-50-20.png new file mode 100644 index 000000000..1318273d2 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/2023-11-28-20-50-20.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/A680brszPoHrB7xFEWucIdjjnSg.png b/docs/fr-FR/handbook/data-visualization/user/static/A680brszPoHrB7xFEWucIdjjnSg.png new file mode 100644 index 000000000..970e3462b Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/A680brszPoHrB7xFEWucIdjjnSg.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/BlkEby9Z7or3CWxvhTCcLXumnHf.png b/docs/fr-FR/handbook/data-visualization/user/static/BlkEby9Z7or3CWxvhTCcLXumnHf.png new file mode 100644 index 000000000..dfef1a101 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/BlkEby9Z7or3CWxvhTCcLXumnHf.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/DEFSbBh6WoujLyxoktHcXEADnom.png b/docs/fr-FR/handbook/data-visualization/user/static/DEFSbBh6WoujLyxoktHcXEADnom.png new file mode 100644 index 000000000..6ae09ac62 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/DEFSbBh6WoujLyxoktHcXEADnom.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/E2pwbBm4BofyHzxut4jcjonJn0s.png b/docs/fr-FR/handbook/data-visualization/user/static/E2pwbBm4BofyHzxut4jcjonJn0s.png new file mode 100644 index 000000000..ee654dd5b Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/E2pwbBm4BofyHzxut4jcjonJn0s.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/K0trbvxhxoVayLx84sUcX5nLnUh.png b/docs/fr-FR/handbook/data-visualization/user/static/K0trbvxhxoVayLx84sUcX5nLnUh.png new file mode 100644 index 000000000..42ec6e996 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/K0trbvxhxoVayLx84sUcX5nLnUh.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/OjTRbDlhHo32npxFBsicKGJinXd.png b/docs/fr-FR/handbook/data-visualization/user/static/OjTRbDlhHo32npxFBsicKGJinXd.png new file mode 100644 index 000000000..68d884f5c Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/OjTRbDlhHo32npxFBsicKGJinXd.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/R0VlbVbkEoVcL1xA2xEcxHQLn1c.png b/docs/fr-FR/handbook/data-visualization/user/static/R0VlbVbkEoVcL1xA2xEcxHQLn1c.png new file mode 100644 index 000000000..a07d41fb0 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/R0VlbVbkEoVcL1xA2xEcxHQLn1c.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/SVYhbc1LNoFSvzxYoOAc78mvn3e.png b/docs/fr-FR/handbook/data-visualization/user/static/SVYhbc1LNoFSvzxYoOAc78mvn3e.png new file mode 100644 index 000000000..53b307c6a Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/SVYhbc1LNoFSvzxYoOAc78mvn3e.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/SdgrbugCjopiffxOrLZcZKhxnEh.png b/docs/fr-FR/handbook/data-visualization/user/static/SdgrbugCjopiffxOrLZcZKhxnEh.png new file mode 100644 index 000000000..7fea06831 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/SdgrbugCjopiffxOrLZcZKhxnEh.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/TUZCbKXHOo6fN6xfxSWcjkhhngg.png b/docs/fr-FR/handbook/data-visualization/user/static/TUZCbKXHOo6fN6xfxSWcjkhhngg.png new file mode 100644 index 000000000..05d7e9a83 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/TUZCbKXHOo6fN6xfxSWcjkhhngg.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/TdsOb1FBfomRaxxSdrHciggGnub.png b/docs/fr-FR/handbook/data-visualization/user/static/TdsOb1FBfomRaxxSdrHciggGnub.png new file mode 100644 index 000000000..5fed0a072 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/TdsOb1FBfomRaxxSdrHciggGnub.png differ diff --git a/docs/fr-FR/handbook/data-visualization/user/static/UrFGbUN1GonqkpxyaUUclAefns3.png b/docs/fr-FR/handbook/data-visualization/user/static/UrFGbUN1GonqkpxyaUUclAefns3.png new file mode 100644 index 000000000..9ff3163b8 Binary files /dev/null and b/docs/fr-FR/handbook/data-visualization/user/static/UrFGbUN1GonqkpxyaUUclAefns3.png differ diff --git a/docs/fr-FR/handbook/departments/index.md b/docs/fr-FR/handbook/departments/index.md new file mode 100644 index 000000000..1bdb2dcd5 --- /dev/null +++ b/docs/fr-FR/handbook/departments/index.md @@ -0,0 +1,17 @@ +# Departments + + + +## Introduction + +The departments plugin supports organizing users in the form of departments in NocoBase, setting up superior-subordinate relationships. You can control a group of users' permissions by binding roles to departments. It supports using department information as variables for workflows and expressions and other places that support setting variables. + +![](https://static-docs.nocobase.com/a6eb94a5cc85a6c7b310f33173a5259d.png) + +## Installation + +This plugin is a commercial plugin, which needs to be uploaded and activated through the plugin manager. + +![](https://static-docs.nocobase.com/907d85bc27f90eaa91b17d568f6dbbd7.png) + +![](https://static-docs.nocobase.com/c1e704259f7ae6ef4998a04a1d21e480.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/departments/manual.md b/docs/fr-FR/handbook/departments/manual.md new file mode 100644 index 000000000..5c056e360 --- /dev/null +++ b/docs/fr-FR/handbook/departments/manual.md @@ -0,0 +1,89 @@ +# User Manual + +## Department Management + +![](https://static-docs.nocobase.com/a6eb94a5cc85a6c7b310f33173a5259d.png) + +### Create a New Department + +![](https://static-docs.nocobase.com/4857910991ae374b63251cee99511e93.png) + +![](https://static-docs.nocobase.com/0cd13d99dcd21ced0bb1683557f0b76b.png) + +### Create a Sub-Department + +![](https://static-docs.nocobase.com/0be8c7db8d12c23f6fe137e7ce23688a.png) + +![](https://static-docs.nocobase.com/2db2fc2037ed383edd60117a46fc9dd0.png) + +### Edit Department + +![](https://static-docs.nocobase.com/a147319577e5cc36b5862c1e511f6722.png) + +![](https://static-docs.nocobase.com/f206f866753cf30ac78aadf4f76bad32.png) + +### Change Superior Department + +Modify the superior department field in the department editing form. The current department and its sub-departments are not selectable. + +![](https://static-docs.nocobase.com/9d80ddf42f32c77186566ed8ada70128.png) + +## Department Member Management + +### View Department Member List + +![](https://static-docs.nocobase.com/2aaf4d9bf55da105b5fca4e9f7e23ca7.png) + +### Add Members to the Department + +A user can join multiple departments at the same time. The first department they join is the default main department. A user only has one main department. + +![](https://static-docs.nocobase.com/60afd282f33b555e6fe0662b9da544cc.png) + +Users who are already department members will not appear in the user selection list. + +![](https://static-docs.nocobase.com/6bcd93173c169973f970de35d2657993.png) + +### Set Department Head + +Click on the owners field in the department editing form to select a department member as the owner. Multiple selections are supported. Members who are already department owner will not appear in the member selection list. + +![](https://static-docs.nocobase.com/92970546cbd0aeb5a8b6a36da87583bd.png) + +### Configure Departments for Users + +In addition to adding members to the department, you can also configure departments for users from the user's perspective. + +![](https://static-docs.nocobase.com/ca82a802012572e225570e8be93a4094.png) + +Departments that have already been joined are not selectable. + +![](https://static-docs.nocobase.com/70e16d17ee9c4b5d43f8a5e1c633b177.png) + +### Change Main Department + +![](https://static-docs.nocobase.com/da92dd1e10268adcd35445e9f1dac771.png) + +## Department Role Management + +By associating one or more roles with a department, members of the current department can have these roles. + +There are two ways to associate roles with a department. + +The first is to select a role in the role field of the department editing form. + +![](https://static-docs.nocobase.com/70f77bb89aa1fb415c152a51a51cc23b.png) + +The second is to add departments to the corresponding role in role management. + +![](https://static-docs.nocobase.com/f2a7bec937cf2f179ce868a92b98416d.png) + +Departments that already have this role are not selectable. + +![](https://static-docs.nocobase.com/be10299893581e1f97a4e01ddd5c7e59.png) + +## Search for Users and Departments + +Search for users by nickname, username, phone, email, and search for departments by department name. + +![](https://static-docs.nocobase.com/2d71346a5400205b22436b4db331a9b8.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/departments/static/2024-03-03-17-53-47.png b/docs/fr-FR/handbook/departments/static/2024-03-03-17-53-47.png new file mode 100644 index 000000000..281ee356e Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-03-17-53-47.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-25-32.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-25-32.png new file mode 100644 index 000000000..e47a2146a Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-25-32.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-27-44.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-27-44.png new file mode 100644 index 000000000..9c77df12e Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-27-44.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-28-38.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-28-38.png new file mode 100644 index 000000000..b65900d87 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-28-38.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-51-21.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-51-21.png new file mode 100644 index 000000000..8e50495a0 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-51-21.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-52-50.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-52-50.png new file mode 100644 index 000000000..62c4677ab Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-52-50.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-54-00.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-54-00.png new file mode 100644 index 000000000..0282c0598 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-54-00.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-56-10.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-56-10.png new file mode 100644 index 000000000..2ad79f904 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-56-10.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-56-23.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-56-23.png new file mode 100644 index 000000000..d183db4d4 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-56-23.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-57-41.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-57-41.png new file mode 100644 index 000000000..2d0c1bbe2 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-57-41.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-57-54.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-57-54.png new file mode 100644 index 000000000..ba70313f0 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-57-54.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-11-59-30.png b/docs/fr-FR/handbook/departments/static/2024-03-04-11-59-30.png new file mode 100644 index 000000000..c000e2b7a Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-11-59-30.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-12-00-58.png b/docs/fr-FR/handbook/departments/static/2024-03-04-12-00-58.png new file mode 100644 index 000000000..8a12e391e Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-12-00-58.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-12-04-03.png b/docs/fr-FR/handbook/departments/static/2024-03-04-12-04-03.png new file mode 100644 index 000000000..72ad017e8 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-12-04-03.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-12-04-46.png b/docs/fr-FR/handbook/departments/static/2024-03-04-12-04-46.png new file mode 100644 index 000000000..c8be2f73c Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-12-04-46.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-12-05-59.png b/docs/fr-FR/handbook/departments/static/2024-03-04-12-05-59.png new file mode 100644 index 000000000..eee712deb Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-12-05-59.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-20-24-34.png b/docs/fr-FR/handbook/departments/static/2024-03-04-20-24-34.png new file mode 100644 index 000000000..72e3663b9 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-20-24-34.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-20-25-31.png b/docs/fr-FR/handbook/departments/static/2024-03-04-20-25-31.png new file mode 100644 index 000000000..96a4cf265 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-20-25-31.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-20-26-42.png b/docs/fr-FR/handbook/departments/static/2024-03-04-20-26-42.png new file mode 100644 index 000000000..41d44cc9a Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-20-26-42.png differ diff --git a/docs/fr-FR/handbook/departments/static/2024-03-04-20-27-04.png b/docs/fr-FR/handbook/departments/static/2024-03-04-20-27-04.png new file mode 100644 index 000000000..69f1c232a Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/2024-03-04-20-27-04.png differ diff --git a/docs/fr-FR/handbook/departments/static/image.png b/docs/fr-FR/handbook/departments/static/image.png new file mode 100644 index 000000000..1dcee93a9 Binary files /dev/null and b/docs/fr-FR/handbook/departments/static/image.png differ diff --git a/docs/fr-FR/handbook/embed/index.md b/docs/fr-FR/handbook/embed/index.md new file mode 100644 index 000000000..983ff68aa --- /dev/null +++ b/docs/fr-FR/handbook/embed/index.md @@ -0,0 +1,25 @@ +# Embed NocoBase + + + +## Introduction + +This plugin is used to embed NocoBase pages into other websites or applications. + +## Installation + +This plugin is a commercial plugin and needs to be uploaded and activated through the plugin manager. + +![20240323162741](https://static-docs.nocobase.com/20240323162741.png) + +## User Guide + +After activating the interface configuration, click "Copy embedded link" in the page's configuration menu (top right corner). + +![](https://static-docs.nocobase.com/f11bd6d5e88d38731d7cd3cb149022c8.png) + +After clicking, you will get a link that can be opened separately, for example, `https://xxx.com/embed/qs087rz4o2b`. + +![](https://static-docs.nocobase.com/9d847805a00fd07372a474665ec0e968.png) + +If you want to embed NocoBase pages into other websites or applications, user authentication is required, and the `token` needs to be appended to the link, for example, `https://xxx.com/embed/qs087rz4o2b?token=xxx`. For detailed instructions on user authentication, please refer to [User Authentication](/handbook/auth). \ No newline at end of file diff --git a/docs/fr-FR/handbook/embed/static/embed-1.png b/docs/fr-FR/handbook/embed/static/embed-1.png new file mode 100755 index 000000000..bd3671d90 Binary files /dev/null and b/docs/fr-FR/handbook/embed/static/embed-1.png differ diff --git a/docs/fr-FR/handbook/embed/static/embed-2.png b/docs/fr-FR/handbook/embed/static/embed-2.png new file mode 100755 index 000000000..ec1fd7822 Binary files /dev/null and b/docs/fr-FR/handbook/embed/static/embed-2.png differ diff --git a/docs/fr-FR/handbook/field-attachment-url/index.md b/docs/fr-FR/handbook/field-attachment-url/index.md new file mode 100644 index 000000000..d13f6828b --- /dev/null +++ b/docs/fr-FR/handbook/field-attachment-url/index.md @@ -0,0 +1,25 @@ +# Data Field: Attachment (URL) + + + +## Introduction + +Supports attachments in URL format. + +## Installation + +This plugin is a commercial plugin. + +## User Manual + +### Field Configuration + +![20241017092323](https://static-docs.nocobase.com/20241017092323.png) + +### External Data Source + +![20241017092456](https://static-docs.nocobase.com/20241017092456.png) + +### Interface + +![20241017092759](https://static-docs.nocobase.com/20241017092759.png) diff --git a/docs/fr-FR/handbook/field-china-region/index.md b/docs/fr-FR/handbook/field-china-region/index.md new file mode 100644 index 000000000..21b85b887 --- /dev/null +++ b/docs/fr-FR/handbook/field-china-region/index.md @@ -0,0 +1,13 @@ +# China region + + + +## Introduction + +## Field configuration + +![20240512180305](https://static-docs.nocobase.com/20240512180305.png) + +## Examples + +To be added. diff --git a/docs/fr-FR/handbook/field-component-mask/index.md b/docs/fr-FR/handbook/field-component-mask/index.md new file mode 100644 index 000000000..bd4200654 --- /dev/null +++ b/docs/fr-FR/handbook/field-component-mask/index.md @@ -0,0 +1,53 @@ +# Mask + + + +## Overview + +The Mask Field Component allows you to display field values in a masked format, which is particularly useful for handling sensitive information like passwords or credit card numbers. + +## Installation + +This is a commercial plugin. + +## Field Configuration Options + +![Field Configuration Options](https://static-docs.nocobase.com/Solution/202410222334271729611267.png) + +- [Field Component](/handbook/ui/fields/field-settings/field-component): Switch between the default field component and the mask field component. +- Mask Settings: Configure mask rules and set permissions for the field. + +## Mask Settings + +![Mask Settings](https://static-docs.nocobase.com/Solution/202410222340521729611652.png) + +### Mask Rules + +#### Predefined Mask Rules + +- `******`: Masks the data entirely with six asterisks. +- `***abc`: Masks the data with three asterisks followed by the last three characters of the original data. +- `**ab**`: Masks the data with two asterisks at both the beginning and end, revealing the middle two characters of the original data. +- `abc***`: Masks the data by showing the first three characters followed by three asterisks. + +#### Custom Mask Rules + +If the predefined mask rules don't meet your needs, you can select `Custom` to define your own mask rules. +The syntax for custom mask rules is as follows: + +- `*` represents a placeholder, and the mask will display a specified number of `*`. +- All other characters will display as they appear in the original data. + +Examples: + +- `a*a*a*`: Masks the original data `123456` as `1*3*5*`. +- `a****a`: Masks the original data `123456789` as `1****9`. +- `ab***abc`: Masks the original data `asdfghjkl` as `as***jkl`. + +### Roles Authorized to View Original Values + +You can specify which user roles are permitted to view the original, unmasked field values. By default, only the root user has this permission. + +:::info{title="INFO"} +When the field is in edit mode, the original value is always visible, regardless of role settings. +::: diff --git a/docs/fr-FR/handbook/field-encryption/index.md b/docs/fr-FR/handbook/field-encryption/index.md new file mode 100644 index 000000000..72e947ca0 --- /dev/null +++ b/docs/fr-FR/handbook/field-encryption/index.md @@ -0,0 +1,35 @@ +# Encryption + + + +## Introduction + +Sensitive business data, such as customer phone numbers, email addresses, and card numbers, can be encrypted to ensure privacy. Once encrypted, this data is securely stored in the database as ciphertext. + +![20240802175127](https://static-docs.nocobase.com/20240802175127.png) + +## Environment Variables + +:::warning +Losing the `ENCRYPTION_FIELD_KEY` will make it impossible to decrypt the data. +::: + +To enable the encryption feature, you must set up the `ENCRYPTION_FIELD_KEY` environment variable, which acts as the encryption key. This key must be exactly 32 characters long, for example: + +```bash +ENCRYPTION_FIELD_KEY='2%&glK; + +## Introduction + +## Field Configuration + +![20240512173541](https://static-docs.nocobase.com/20240512173541.png) + +## Instructions + +To be added. diff --git a/docs/fr-FR/handbook/field-m2m-array/index.md b/docs/fr-FR/handbook/field-m2m-array/index.md new file mode 100644 index 000000000..e8af287ad --- /dev/null +++ b/docs/fr-FR/handbook/field-m2m-array/index.md @@ -0,0 +1,42 @@ +# Many-to-Many (Array) + + + +## Introduction + +This feature allows you to use array fields in a data Collection to store multiple unique keys from the target table, thereby creating a many-to-many relationship between the two tables. For instance, consider the entities Articles and Tags. An article can be linked to multiple tags, with the article table storing the IDs of the corresponding records from the tags table in an array field. + +:::warning{title=Note} + +- Whenever possible, it's recommended to use a junction Collection to establish a standard [many-to-many](../data-modeling/collection-fields/associations/m2m/index.md) relationship instead of relying on this method. +- Currently, only PostgreSQL supports filtering source Collection data using fields from the target table for many-to-many relationships established with array fields. For example, in the scenario above, you can filter articles based on other fields in the tags table, such as the title. + + ::: + +### Field Configuration + +![many-to-many(array) field configuration](https://static-docs.nocobase.com/202407051108180.png) + +## Parameter Description + +### Source Collection + +The source Collection, where the current field resides. + +### Target Collection + +The target Collection with which the relationship is established. + +### Foreign Key + +The array field in the source Collection that stores the target key from the target table. + +The corresponding relationships for array field types are as follows: + +| NocoBase | PostgreSQL | MySQL | SQLite | +| -------- | ---------- | ------ | ------ | +| `set` | `array` | `JSON` | `JSON` | + +### Target Key + +The field in the target Collection that corresponds to the values stored in the source table's array field. This field must be unique. diff --git a/docs/fr-FR/handbook/field-markdown-vditor/index.md b/docs/fr-FR/handbook/field-markdown-vditor/index.md new file mode 100644 index 000000000..77ef88835 --- /dev/null +++ b/docs/fr-FR/handbook/field-markdown-vditor/index.md @@ -0,0 +1,11 @@ +# Markdown (Vditor) + +## Introduction + +## Field Configuration + +![20240512180647](https://static-docs.nocobase.com/20240512180647.png) + +## Example + +Coming soon. diff --git a/docs/fr-FR/handbook/field-sequence/index.md b/docs/fr-FR/handbook/field-sequence/index.md new file mode 100644 index 000000000..d5f5c7c2e --- /dev/null +++ b/docs/fr-FR/handbook/field-sequence/index.md @@ -0,0 +1,13 @@ +# Sequence + + + +## Introduction + +## Field Configuration + +![20240512173752](https://static-docs.nocobase.com/20240512173752.png) + +## Example + +To be added diff --git a/docs/fr-FR/handbook/field-snapshot/index.md b/docs/fr-FR/handbook/field-snapshot/index.md new file mode 100644 index 000000000..e7a070018 --- /dev/null +++ b/docs/fr-FR/handbook/field-snapshot/index.md @@ -0,0 +1,3 @@ +# snapshot field + + diff --git a/docs/fr-FR/handbook/field-sort/index.md b/docs/fr-FR/handbook/field-sort/index.md new file mode 100644 index 000000000..f65da26c8 --- /dev/null +++ b/docs/fr-FR/handbook/field-sort/index.md @@ -0,0 +1,147 @@ +# Sort Field + + + +## Introduction + +Sort fields are used to sort records in the collection, supporting group first then sort (sort1). + +:::warning +Since the sort field is a field in the current collection, when sorting by group, it does not support the same record being divided into multiple groups. +::: + +## Installation + +Built-in plugin, no separate installation required. + +## User Manual + +### Create a Sort Field + +![20240409091123_rec_](https://static-docs.nocobase.com/20240409091123_rec_.gif) + +When creating sort fields, the sort values will be initialized: + +- If group sorting is not selected, initialization will be based on the primary key field and creation date field. +- If group sorting is selected, the data will be grouped first, and then initialization will be based on the primary key field and creation date field. + +:::warning{title="Explanation of Transaction Consistency"} +- When creating a field, if the sort value initialization fails, the sort field will not be created; +- Within a certain range, if a record moves from position A to position B, the sort values of all records in the AB interval will change. If one fails, the move will fail, and the sort values of the related records will not change. +::: + +#### Example 1: Create the sort1 field + +The sort1 field is not grouped + +![20240409091510](https://static-docs.nocobase.com/20240409091510.png) + +The sort fields of each record will be initialized based on the primary key field and creation date field. + +![20240409092305](https://static-docs.nocobase.com/20240409092305.png) + +#### Example 2: Create a sort2 field based on Class ID grouping + +![20240409092620](https://static-docs.nocobase.com/20240409092620.png) + +At this time, all records in the collection will be grouped first (grouped by Class ID), and then the sort field (sort2) will be initialized. The initial values of each record are: + +![20240409092847](https://static-docs.nocobase.com/20240409092847.png) + +### Drag-and-Drop Sorting + +Sort fields are mainly used for drag-and-drop sorting of various block records. The blocks currently supporting drag-and-drop sorting include tables and boards. + +:::warning +- When the same sort field is used for drag-and-drop sorting, mixed use of multiple blocks may disrupt the existing order; +- The field for table drag-and-drop sorting cannot choose a sort field with a grouping rule; + - Exception: In a one-to-many relationship table block, the foreign key can serve as a group; +- Currently, only the board block supports group drag-and-drop sorting. +::: + +#### Drag-and-Drop Sorting of Table Rows + +Table block + +![20240409104621_rec_](https://static-docs.nocobase.com/20240409104621_rec_.gif) + +Relationship table block + + + +:::warning +In a one-to-many relationship block + +- If an ungrouped sort field is selected, all records may participate in the sorting; +- If it is first grouped based on the foreign key and then sorted, the sorting rule will only affect the data within the current group. + +The final effect is consistent, but the number of records participating in sorting is different, for more explanation, see [Sorting Rule Explanation](#Sorting Rule Explanation) +::: + +#### Drag-and-Drop Sorting of Board Cards + +![20240409110423_rec_](https://static-docs.nocobase.com/20240409110423_rec_.gif) + +### Sorting Rule Explanation + +#### Displacement between ungrouped (or same group) elements + +Suppose there is a set of data + +``` +[1,2,3,4,5,6,7,8,9] +``` + +When an element, suppose 5, moves forward to position 3, at this time, only the sequence numbers 3,4,5 have changed, 5 occupies the position of 3, and 3,4 each move back one position. + +``` +[1,2,5,3,4,6,7,8,9] +``` + +At this time, continue to move 6 back to position 8, 6 occupies the position of 8, 7,8 each move forward one position. + +``` +[1,2,5,3,4,7,8,6,9] +``` + +#### Movement of elements between different groups + +When sorting by group, when a record moves to another group, the group where it belongs will also change. As shown in the example below: + +``` +A: [1,2,3,4] +B: [5,6,7,8] +``` + +When 1 moves to 6 (default behind), the group where 1 belongs will also change from A to B + +``` +A: [2,3,4] +B: [5,6,1,7,8] +``` + +#### Sort changes are unrelated to the data displayed on the screen + +For example, there is a set of data + +``` +[1,2,3,4,5,6,7,8,9] +``` + +The screen only shows + +``` +[1,5,9] +``` + +When 1 moves to position 9, the positions of the intervening 2,3,4,5,6,7,8 data will all change + +``` +[2,3,4,5,6,7,8,9,1] +``` + +The screen displays + +``` +[5,9,1] +``` \ No newline at end of file diff --git a/docs/fr-FR/handbook/file-manager/development/index.md b/docs/fr-FR/handbook/file-manager/development/index.md new file mode 100644 index 000000000..a3f7b2773 --- /dev/null +++ b/docs/fr-FR/handbook/file-manager/development/index.md @@ -0,0 +1,138 @@ +# Development + +## Extend client file type + +For uploaded files, the client UI can display different previews based on file types. The attachment field of file-manager uses a built-in browser-based (iframe) file preview capacity, supporting most file types (such as images, videos, audio, and PDFs) for direct preview in the browser. When a file type is not supported for browser preview or requires special interaction, additional preview components can be extended based on the file type. + +### Example + +For example, if you want to extend a carousel component for image files, you can use the following code: + +```ts +import match from 'mime-match'; +import { Plugin, attachmentFileTypes } from '@nocobase/client'; + +class MyPlugin extends Plugin { + load() { + attachmentFileTypes.add({ + match(file) { + return match(file.mimetype, 'image/*'); + }, + Previewer({ index, list, onSwitchIndex }) { + const onDownload = useCallback( + (e) => { + e.preventDefault(); + const file = list[index]; + saveAs(file.url, `${file.title}${file.extname}`); + }, + [index, list], + ); + return ( + onSwitchIndex(null)} + onMovePrevRequest={() => onSwitchIndex((index + list.length - 1) % list.length)} + onMoveNextRequest={() => onSwitchIndex((index + 1) % list.length)} + imageTitle={list[index]?.title} + toolbarButtons={[ + , + ]} + /> + ); + }, + }); + } +} +``` + +The `attachmentFileTypes` is an entry object provided by the `@nocobase/client` package for extending file types. You can use its `add` method to extend a file type descriptor. + +Each file type must implement a `match()` method to check if the file type meets the requirements. In the example, the `mime-match` package is used to check the file's `mimetype` attribute. If it matches `image/*`, it is considered a file type that needs processing. If it does not match, it will fall back to the built-in type. + +The `Previewer` property on the type descriptor is the component used for previewing. When the file type matches, this component will be rendered for preview. It is generally recommended to use a modal component (like ``) as the base container and place the preview and interactive content within that component to implement the preview functionality. + +### API + +```ts +export interface FileModel { + id: number; + filename: string; + path: string; + title: string; + url: string; + extname: string; + size: number; + mimetype: string; +} + +export interface PreviewerProps { + index: number; + list: FileModel[]; + onSwitchIndex(index): void; +} + +export interface AttachmentFileType { + match(file: any): boolean; + Previewer?: React.ComponentType; +} + +export class AttachmentFileTypes { + add(type: AttachmentFileType): void; +} +``` + +#### `attachmentFileTypes` + +`attachmentFileTypes` is a global instance which could be imported from `@nocobase/client` package: + +```ts +import { attachmentFileTypes } from '@nocobase/client'; +``` + +#### `attachmentFileTypes.add()` + +Register file type descriptor to the file type registry. The type of the descriptor is `AttachmentFileType`. + +#### `AttachmentFileType` + +##### `match()` + +The match method of file type. + +The argument `file` is the uploaded file data object, including some properties could be used to check types. + +* `mimetype`: Mimetype +* `extname`: Extension name of file, including "." +* `path`: Relative path of the file storing +* `url`: File URL + +The return value type is `boolean`, means matched or not. + +##### `Previewer` + +Component used to preview file. + +Props: + +* `index`: Index value in attachemnts list +* `list`: Attachemnt list +* `onSwitchIndex`: Method to switch preview index + +For `onSwitchIndex`, any index value in the list could be used, to switch to other file. If `null` is used as argument, the preview component will be closed. + +```ts +onSwitchIndex(null); +``` diff --git a/docs/fr-FR/handbook/file-manager/field-attachment.md b/docs/fr-FR/handbook/file-manager/field-attachment.md new file mode 100644 index 000000000..7cc354a12 --- /dev/null +++ b/docs/fr-FR/handbook/file-manager/field-attachment.md @@ -0,0 +1,15 @@ +# Attachment Field + + + +## Introduction + +The attachment field is a specialized relational field that connects directly to the file collection. + +## Field Configuration + +![20240512180916](https://static-docs.nocobase.com/20240512180916.png) + +## Example + +(Example to be added) diff --git a/docs/fr-FR/handbook/file-manager/file-collection.md b/docs/fr-FR/handbook/file-manager/file-collection.md new file mode 100644 index 000000000..707fd08ab --- /dev/null +++ b/docs/fr-FR/handbook/file-manager/file-collection.md @@ -0,0 +1,29 @@ +# File Collecton + + + +## Introduction + +Files are collection records with a specific structure, the collection is known as file collection, which store the metadata of files and can be managed through the File Manager. + +## User Manual + +Creating File Collection + +![20240324090414](https://static-docs.nocobase.com/20240324090414.png) + +Preset Fields in File Collection + +![20240324090527](https://static-docs.nocobase.com/20240324090527.png) + +Using in Blocks + +![20240324090848](https://static-docs.nocobase.com/20240324090848.png) + +Association Field + +![20240324091529](https://static-docs.nocobase.com/20240324091529.png) + +Association Blocks + +![20240324091321](https://static-docs.nocobase.com/20240324091321.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/file-manager/index.md b/docs/fr-FR/handbook/file-manager/index.md new file mode 100644 index 000000000..7fb52b40b --- /dev/null +++ b/docs/fr-FR/handbook/file-manager/index.md @@ -0,0 +1,31 @@ +# File Manager + + + +## Introduction + +The File Manager plugin provides a file collection, attachment field, and file storage services for effectively managing files. Files are structured data table records known as file collection, which store file metadata and can be managed through the File Manager. Attachment fields are specific relational fields associated with the file collection. The plugin supports multiple storage methods, including local storage, Alibaba Cloud OSS, Amazon S3, and Tencent Cloud COS. + +## User Manual + +### File Collection + +An attachments collection is built-in to store all files associated with attachment fields. Additionally, new file collections can be created to store specific files. + +[More usage information can be found in the file table introduction document](/handbook/file-manager/file-collection) + +### Attachment Field + +Attachment fields are specific relational fields related to the file collection, which can be created through "Attachment field" or configured through "Association field". + +[More usage information can be found in the attachment field introduction document](/handbook/file-manager/field-attachment) + +### File Storage + +The file storage engine is used to save files to specific services, including local storage (saving to the server's hard drive), cloud storage, etc. + +[More usage information can be found in the file storage introduction document](./storage/index.md) + +### Development + +* [Extend client file type](./development/client-file-type.md) diff --git a/docs/fr-FR/handbook/file-manager/storage/aliyun-oss.md b/docs/fr-FR/handbook/file-manager/storage/aliyun-oss.md new file mode 100644 index 000000000..202db3e71 --- /dev/null +++ b/docs/fr-FR/handbook/file-manager/storage/aliyun-oss.md @@ -0,0 +1,31 @@ +# Aliyun OSS + +Storage engine based on Aliyun OSS, you need to prepare relevant accounts and permissions in advance. + +## Options + +![Example of Aliyun OSS options](https://static-docs.nocobase.com/20240712220011.png) + +:::info{title=Hint} +Only the special parameters of the Aliyun OSS storage engine are introduced here. For common parameters, please refer to the [Common Engine Parameters](./index.md#common-engine-parameters). +::: + +### Region + +Specify the region of the OSS storage, for example: `oss-cn-hangzhou`. + +:::info{title=Hint} +You can view the region information of the storage bucket in the [Aliyun OSS console](https://oss.console.aliyun.com/), and only need to take the prefix part of the region (without the complete domain name). +::: + +### AccessKey ID + +Fill in the ID of the Alibaba Cloud authorized access key. + +### AccessKey Secret + +Fill in the secret of the Alibaba Cloud authorized access key. + +### Bucket + +Fill in the name of the OSS bucket. diff --git a/docs/fr-FR/handbook/file-manager/storage/amazon-s3.md b/docs/fr-FR/handbook/file-manager/storage/amazon-s3.md new file mode 100644 index 000000000..2584e0bc5 --- /dev/null +++ b/docs/fr-FR/handbook/file-manager/storage/amazon-s3.md @@ -0,0 +1,10 @@ +# Amazon S3 + +:::warning +Documentation Pending +::: + + diff --git a/docs/fr-FR/handbook/file-manager/storage/index.md b/docs/fr-FR/handbook/file-manager/storage/index.md new file mode 100644 index 000000000..41814e9b3 --- /dev/null +++ b/docs/fr-FR/handbook/file-manager/storage/index.md @@ -0,0 +1,57 @@ +# Overview + +## Built-in Engines + +Currently, NocoBase supports the following built-in engine types: + +- [Local Storage](./local.md) +- [Alibaba Cloud OSS](./aliyun-oss.md) +- [Amazon S3](./amazon-s3.md) +- [Tencent Cloud COS](./tencent-cos.md) + +A local storage engine is automatically added during system installation and can be used directly. New engines can also be added or existing engine parameters can be edited. + +## Common Engine Parameters + +In addition to specific parameters for different engine categories, the following are common parameters: + +### Title + +The name of the storage engine for human recognition. + +### System Name + +The system name of the storage engine for system identifying. It must be unique in system-wide. If not provided, it will be generate randomly. + +### Access base URL + +The prefix part of the URL address accessible to the file externally, which can be the access URL base of a CDN, for example: "`https://cdn.nocobase.com/app`" (without the trailing "`/`"). + +### Path + +The relative path used when storing files. This part will also be automatically concatenated to the final URL when accessed. For example: "`user/avatar`" (without the leading or trailing "`/`"). + +### File Size Limit + +The size limit for uploading files to this storage engine. Files larger than this setting will not be uploaded. The system maximum limit is 1GB. + +### Default Storage Engine + +When checked, it is set as the default storage engine for the system. Files uploaded in attachment fields or file collections without specifying a storage engine will be saved to the default storage engine. The default storage engine cannot be deleted. + +### Keep Files When Destroying Records + +When checked, uploaded files in the storage engine will be retained even when the data records in attachment fields or file collections are deleted. By default, files in the storage engine are deleted when records are deleted. + +See local storage as an example: + +![Example of File Storage Engine Configuration](https://static-docs.nocobase.com/20240529115151.png) + +:::info{title=Note} +After file upload, the final access path is composed of several parts: + +``` +// +``` +For example: `https://cdn.nocobase.com/app/user/avatar/20240529115151.png`. +::: diff --git a/docs/fr-FR/handbook/file-manager/storage/local.md b/docs/fr-FR/handbook/file-manager/storage/local.md new file mode 100644 index 000000000..8508baace --- /dev/null +++ b/docs/fr-FR/handbook/file-manager/storage/local.md @@ -0,0 +1,18 @@ +# Local storage + +The uploaded files will be saved in a local directory on the server. Suitable for scenarios small scale or experimental usage, which the quantity of files is finite. + +## Options + +![Example of file storage engine options](https://static-docs.nocobase.com/20240529115151.png) + +:::info{title=Hint} +This section only covers the specific options for the local storage engine. For common parameters, please refer to the [General Engine Parameters](./index.md#general-engine-parameters). +::: + +### Path + +The path represents both the relative path of the file stored on the server and the URL access path. For example, "`user/avatar`" (without the leading and trailing "`/`") represents: + +1. The relative path of the uploaded file stored on the server: `/path/to/nocobase-app/storage/uploads/user/avatar`. +2. The URL prefix for accessing the file: `http://localhost:13000/storage/uploads/user/avatar`. diff --git a/docs/fr-FR/handbook/file-manager/storage/tencent-cos.md b/docs/fr-FR/handbook/file-manager/storage/tencent-cos.md new file mode 100644 index 000000000..1f7c0b62b --- /dev/null +++ b/docs/fr-FR/handbook/file-manager/storage/tencent-cos.md @@ -0,0 +1,31 @@ +# Tencent COS + +The storage engine based on Tencent Cloud COS, you need to prepare relevant accounts and permissions in advance. + +## Options + +![Example of Tencent COS options](https://static-docs.nocobase.com/20240712222125.png) + +:::info{title=Hint} +This section only covers the specific options for the Tencent Cloud COS storage engine. For common parameters, please refer to [Common Engine Parameters](./index.md#common-engine-parameters). +::: + +### Region + +Fill in the region of the COS storage, for example: `ap-chengdu`. + +:::info{title=Hint} +You can view the region information of the storage bucket in the [Tencent Cloud COS Console](https://console.cloud.tencent.com/cos), and only need to take the prefix part of the region (without the complete domain name). +::: + +### SecretId + +Fill in the ID of the Tencent Cloud authorized access key. + +### SecretKey + +Fill in the secret of the Tencent Cloud authorized access key. + +### Bucket + +Fill in the name of the COS bucket, for example: `qing-cdn-1234189398`. diff --git a/docs/fr-FR/handbook/file-storage-cos/index.md b/docs/fr-FR/handbook/file-storage-cos/index.md new file mode 100644 index 000000000..d052d8f9e --- /dev/null +++ b/docs/fr-FR/handbook/file-storage-cos/index.md @@ -0,0 +1,7 @@ +# Tencent Cloud COS + + + +## Introduction + +## Hand book diff --git a/docs/fr-FR/handbook/file-storage-oss/index.md b/docs/fr-FR/handbook/file-storage-oss/index.md new file mode 100644 index 000000000..50d159d17 --- /dev/null +++ b/docs/fr-FR/handbook/file-storage-oss/index.md @@ -0,0 +1,7 @@ +# Alibaba Cloud OSS + + + +## Introduction + +## Hand book diff --git a/docs/fr-FR/handbook/file-storage-s3/index.md b/docs/fr-FR/handbook/file-storage-s3/index.md new file mode 100644 index 000000000..b5ba7d79d --- /dev/null +++ b/docs/fr-FR/handbook/file-storage-s3/index.md @@ -0,0 +1,7 @@ +# Amazon S3 + + + +## Introduction + +## Hand book diff --git a/docs/fr-FR/handbook/graph-collection-manager/index.md b/docs/fr-FR/handbook/graph-collection-manager/index.md new file mode 100644 index 000000000..a8b7686d6 --- /dev/null +++ b/docs/fr-FR/handbook/graph-collection-manager/index.md @@ -0,0 +1,17 @@ +# Graph Collection Manager + + + +## Introduction + +This is a tool similar to ER diagrams, which currently only supports the main database. + +## Installation + +This preset plugin needs to be activated before it can be used. + +![20240322221627](https://static-docs.nocobase.com/20240322221627.png) + +## User Manual + +![20240410075906](https://static-docs.nocobase.com/20240410075906.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/index.md b/docs/fr-FR/handbook/index.md new file mode 100644 index 000000000..4d8a92cdc --- /dev/null +++ b/docs/fr-FR/handbook/index.md @@ -0,0 +1,11 @@ +# Handbook Guide + +1. If you are first exposed to NocoBase, it is recommended that you start with "[Data Modeling - Overview](/handbook/data-modeling)". In this chapter, you can understand the features of NocoBase data modeling; +2. Going further, you can add "[Pages](/handbook/ui/pages)" and "[Blocks](/handbook/ui/blocks)" in the interface. You can choose suitable blocks to display the data in the data source; +3. Next, "[Configure Fields](/handbook/ui/fields)" and "[Configure Actions](/handbook/ui/actions)" for the data blocks. By this step, simple data processing procedures can be done; +4. If you want to orchestrate actions, you can check the "[Workflow](/handbook/workflow)" chapter. The workflow provides various triggers and action nodes, which can satisfy your unlimited imagination for orchestrating operations; +5. Permissions need to be configured for actions. You can check "[Users and Permissions](/handbook/acl)". In addition to understanding how to configure action permissions, this chapter can also further understand the concept of "[Departments](/handbook/departments)", which includes the management of users, roles, and departments. +6. If you already have a ready-made IdP (Identity Provider), refer to the "[User Authentication](/handbook/auth)" chapter, which can help you understand how to access third-party user service providers; +7. You can enable multiple languages in "[System Settings](/handbook/system-settings)". If the translation of the language you use is incomplete, you can use "[Localization Management](/handbook/localization-management)" to translate, and you are also welcome to contribute translations to NocoBase; +8. "[Logs and Monitoring](/handbook/logger)" is an important tool for managing and maintaining NocoBase. It can help developers discover and solve problems in time, optimize system performance, ensure system security and stability, and improve system reliability and availability; +9. You can view all added plugins in the "[Plugin Manager](/handbook/plugin-manager)". Plugins need to be activated before they can be used. If the existing plugins cannot meet your needs, you can also "[Develop Plugins](/development)" by yourself and then add them through the plugin manager. diff --git a/docs/fr-FR/handbook/localization-management/index.md b/docs/fr-FR/handbook/localization-management/index.md new file mode 100644 index 000000000..a0c51a6af --- /dev/null +++ b/docs/fr-FR/handbook/localization-management/index.md @@ -0,0 +1,53 @@ +# Localization Management + + + +## Introduction + +The Localization Management plugin is designed to assist in managing and implementing the localization process for NocoBase. It translates NocoBase's menus, data tables, fields, and all plugins to adapt to the language and culture of a specific region. + +## Installation + +This is a built-in plugin, so no additional installation is required. + +## User Manual + +### Activating the Plugin + +![](https://static-docs.nocobase.com/d16f6ecd6bfb8d1e8acff38f23ad37f8.png) + +### Localization Management + +![](https://static-docs.nocobase.com/c117b5337941f0afd564152053666480.png) + +### Synchronizing Translation Entries + +![](https://static-docs.nocobase.com/bc380a4ebdb2af075abcab5f16287cf9.png) + +After synchronization, it will list all the translatable entries for the current language. + +![](https://static-docs.nocobase.com/cf501e6b4d2f67520ad35b00d1ed3446.png) + +### Publishing + +After completing the translation, you need to click the "Publish" button to make the changes take effect. + +![](https://static-docs.nocobase.com/1f9dc52defb37ac67912011ba31c3160.png) + +### Translating Other Languages + +Enable other languages in "System Settings," such as Simplified Chinese. + +![](https://static-docs.nocobase.com/618830967aaeb643c892fce355d59a73.png) + +Switch to that language. + +![](https://static-docs.nocobase.com/35548a7bf099df4f30d160c72863c6b8.png) + +Synchronize the entries. + +![](https://static-docs.nocobase.com/12f39cfcd7d8d9ce3d367426b959af16.png) + +Translate and publish. + +![](https://static-docs.nocobase.com/eb22725dcab6807dc8a410f5e10e9492.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/localization-management/static/BFRcbhE31oEAHOxss5ncRnEvnZb.png b/docs/fr-FR/handbook/localization-management/static/BFRcbhE31oEAHOxss5ncRnEvnZb.png new file mode 100644 index 000000000..3e52179dc Binary files /dev/null and b/docs/fr-FR/handbook/localization-management/static/BFRcbhE31oEAHOxss5ncRnEvnZb.png differ diff --git a/docs/fr-FR/handbook/localization-management/static/DxQ8bDrtsoi8ObxadwZcCYntn9d.png b/docs/fr-FR/handbook/localization-management/static/DxQ8bDrtsoi8ObxadwZcCYntn9d.png new file mode 100644 index 000000000..b51c6e242 Binary files /dev/null and b/docs/fr-FR/handbook/localization-management/static/DxQ8bDrtsoi8ObxadwZcCYntn9d.png differ diff --git a/docs/fr-FR/handbook/localization-management/static/GaqEbrgAdokzgJxqicMcdKxMnQf.png b/docs/fr-FR/handbook/localization-management/static/GaqEbrgAdokzgJxqicMcdKxMnQf.png new file mode 100644 index 000000000..ec4c28e92 Binary files /dev/null and b/docs/fr-FR/handbook/localization-management/static/GaqEbrgAdokzgJxqicMcdKxMnQf.png differ diff --git a/docs/fr-FR/handbook/localization-management/static/IkBhbaqrfodzsMxxueIcUENnnTd.png b/docs/fr-FR/handbook/localization-management/static/IkBhbaqrfodzsMxxueIcUENnnTd.png new file mode 100644 index 000000000..ff36c8d38 Binary files /dev/null and b/docs/fr-FR/handbook/localization-management/static/IkBhbaqrfodzsMxxueIcUENnnTd.png differ diff --git a/docs/fr-FR/handbook/localization-management/static/IkFDbWE8ios6qSxp78scf2BOnQg.png b/docs/fr-FR/handbook/localization-management/static/IkFDbWE8ios6qSxp78scf2BOnQg.png new file mode 100644 index 000000000..dd15f11be Binary files /dev/null and b/docs/fr-FR/handbook/localization-management/static/IkFDbWE8ios6qSxp78scf2BOnQg.png differ diff --git a/docs/fr-FR/handbook/localization-management/static/Pi1nbxvVEoqSIox28FkcYkw7nID.png b/docs/fr-FR/handbook/localization-management/static/Pi1nbxvVEoqSIox28FkcYkw7nID.png new file mode 100644 index 000000000..8d3a23243 Binary files /dev/null and b/docs/fr-FR/handbook/localization-management/static/Pi1nbxvVEoqSIox28FkcYkw7nID.png differ diff --git a/docs/fr-FR/handbook/localization-management/static/S49abMq61oBfMFxRvs7cZTgHnoh.png b/docs/fr-FR/handbook/localization-management/static/S49abMq61oBfMFxRvs7cZTgHnoh.png new file mode 100644 index 000000000..a1db38f6a Binary files /dev/null and b/docs/fr-FR/handbook/localization-management/static/S49abMq61oBfMFxRvs7cZTgHnoh.png differ diff --git a/docs/fr-FR/handbook/localization-management/static/TmD3bXzJ2onTXcxyaWXc2g30n0e.png b/docs/fr-FR/handbook/localization-management/static/TmD3bXzJ2onTXcxyaWXc2g30n0e.png new file mode 100644 index 000000000..562afbd77 Binary files /dev/null and b/docs/fr-FR/handbook/localization-management/static/TmD3bXzJ2onTXcxyaWXc2g30n0e.png differ diff --git a/docs/fr-FR/handbook/localization-management/static/XO9TbVodPo01SrxFPrkcUsVmngg.png b/docs/fr-FR/handbook/localization-management/static/XO9TbVodPo01SrxFPrkcUsVmngg.png new file mode 100644 index 000000000..970b990d5 Binary files /dev/null and b/docs/fr-FR/handbook/localization-management/static/XO9TbVodPo01SrxFPrkcUsVmngg.png differ diff --git a/docs/fr-FR/handbook/logger/index.md b/docs/fr-FR/handbook/logger/index.md new file mode 100644 index 000000000..c8e112c8e --- /dev/null +++ b/docs/fr-FR/handbook/logger/index.md @@ -0,0 +1,148 @@ +# Logging + +## Introduction + +Logs are an important tool for us to locate system issues. NocoBase's server logs mainly include interface request logs and system operation logs, supporting configuration of log level, rolling strategy, size, printing format, and more. This document mainly introduces the related content of NocoBase server logs, as well as how to use the logging plugin to package and download server logs. + +## Log Configuration + +Log-related parameters such as log level, output method, and printing format can be configured through [environment variables](../../welcome/getting-started/env.md#logger_transport). + +## Log Formats + +NocoBase supports configuring four different log formats. + +### `console` + +The default format in development environment, messages are highlighted in color. + +``` +2023-12-30 22:40:06 [info ] response method=GET path=/api/uiSchemas:getJsonSchema/nocobase-admin-menu res={"status":200} action={"actionName":"getJsonSchema","resourceName":"uiSchemas","params":{"filterByTk":"nocobase-admin-menu","resourceName":"uiSchemas","resourceIndex":"nocobase-admin-menu","actionName":"getJsonSchema"}} userId=1 status=200 cost=5 app=main reqId=ccf4e3bd-beb0-4350-af6e-b1fc1d9b6c3f +2023-12-30 22:43:12 [debug] Database dialect: mysql module=application method=install app=main reqId=31ffa8b5-f377-456b-a295-0c8a28938228 +2023-12-30 22:43:12 [warn ] app is installed module=application method=install app=main reqId=31ffa8b5-f377-456b-a295-0c8a28938228 +``` + +### `json` + +The default format in production environment. + +```json +{ + "level": "info", + "timestamp": "2023-12-26 22:04:56", + "reqId": "7612ef42-58e8-4c35-bac2-2e6c9d8ec96e", + "message": "response", + "method": "POST", + "path": "/api/authenticators:publicList", + "res": { "status": 200 }, + "action": { + "actionName": "publicList", + "resourceName": "authenticators", + "params": { "resourceName": "authenticators", "actionName": "publicList" } + }, + "status": 200, + "cost": 16 +} +``` + +### `logfmt` + +Check out https://brandur.org/logfmt for more information. + +``` +level=info timestamp=2023-12-21 14:18:02 reqId=8b59a40d-68ee-4c97-8001-71a47a92805a +message=response method=POST path=/api/authenticators:publicList res={"status":200} +action={"actionName":"publicList","resourceName":"authenticators","params":{"resourceName":"authenticators","actionName":"publicList"}} +userId=undefined status=200 cost=14 +``` + +### `delimiter` + +Separated by delimiter `|`. + +``` +info|2023-12-26 22:07:09|13cd16f0-1568-418d-ac37-6771ee650e14|response|POST|/api/authenticators:publicList|{"status":200}|{"actionName":"publicList","resourceName":"authenticators","params":{"resourceName":"authenticators","actionName":"publicList"}}||200|25 +``` + +## Log Directory + +The main directory structure of NocoBase log files is: + +- `storage/logs` - Log output directory + - `main` - Main application name + - `request_YYYY-MM-DD.log` - Request log + - `system_YYYY-MM-DD.log` - System log + - `system_error_YYYY-MM-DD.log` - System error log + - `sql_YYYY-MM-DD.log` - SQL execution log + - ... + - `sub-app` - Sub-application name + - `request_YYYY-MM-DD.log` + - ... + +## Log Files + +### Request Log + +`request_YYYY-MM-DD.log`, interface request and response logs. + +| Field | Description | +| ------------- | ------------------------------------ | +| `level` | Log level | +| `timestamp` | Log print time `YYYY-MM-DD hh:mm:ss` | +| `message` | `request` or `response` | +| `userId` | Only in `response` | +| `method` | Request method | +| `path` | Request path | +| `req` / `res` | Request/Response content | +| `action` | Requested resources and parameters | +| `status` | Response status code | +| `cost` | Request time | +| `app` | Current application name | +| `reqId` | Request ID | + +:::info{title=Note} +`reqId` will be carried to the front end via the `X-Request-Id` response header. +::: + +### System Log + +`system_YYYY-MM-DD.log`, application, middleware, plugins, and other system operation logs, `error` level logs will be printed separately to `system_error_YYYY-MM-DD.log`. + +| Field | Description | +| ----------- | -------------------------------------- | +| `level` | Log level | +| `timestamp` | Log print time `YYYY-MM-DD hh:mm:ss` | +| `message` | Log message | +| `module` | Module | +| `submodule` | Submodule | +| `method` | Called method | +| `meta` | Other related information, JSON format | +| `app` | Current application name | +| `reqId` | Request ID | + +### SQL Execution Log + +`sql_YYYY-MM-DD.log`, database SQL execution logs. `INSERT INTO` statements are limited to the first 2000 characters. + +| Field | Description | +| ----------- | ------------------------------------ | +| `level` | Log level | +| `timestamp` | Log print time `YYYY-MM-DD hh:mm:ss` | +| `sql` | SQL statement | +| `app` | Current application name | +| `reqId` | Request ID | + +## Log Packaging and Downloading + + + +1. Navigate to the log management page. +2. Select the log files you wish to download. +3. Click the download button. + +![2024-04-10_10-50-50](https://static-docs.nocobase.com/2024-04-10_10-50-50.png) + +## Related Documents + +- [Plugin Development - Server - Logging](../../development/server/logger) +- [API Reference - @nocobase/logger](../../api/logger) diff --git a/docs/fr-FR/handbook/logger/static/2023-12-26-23-01-17.png b/docs/fr-FR/handbook/logger/static/2023-12-26-23-01-17.png new file mode 100644 index 000000000..b5ecfdbc2 Binary files /dev/null and b/docs/fr-FR/handbook/logger/static/2023-12-26-23-01-17.png differ diff --git a/docs/fr-FR/handbook/mobile-client/index.md b/docs/fr-FR/handbook/mobile-client/index.md new file mode 100644 index 000000000..971694f9e --- /dev/null +++ b/docs/fr-FR/handbook/mobile-client/index.md @@ -0,0 +1,17 @@ +# Mobile + + + +## Introduction + +Provides the capability to configure mobile pages. + +## Installation + +It's a pre-installed plugin that needs to be activated before use. + +![20240324171718](https://static-docs.nocobase.com/20240324171718.png) + +## Usage + +![20240324171605](https://static-docs.nocobase.com/20240324171605.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/mobile/index.md b/docs/fr-FR/handbook/mobile/index.md new file mode 100644 index 000000000..2cff35dbd --- /dev/null +++ b/docs/fr-FR/handbook/mobile/index.md @@ -0,0 +1,71 @@ +# Mobile + + + +## Introduction + +This plugin facilitates the configuration of mobile pages, leveraging a core framework built on Ant Design Mobile. It offers a variety of extension points and supports the integration of specific desktop blocks. + +:::warning +The older `plugin-mobile-client` has been deprecated. Starting from version v1.3, it is recommended to transition to `plugin-mobile`. These two plugins are incompatible, so the new version will necessitate a complete reconfiguration of mobile settings. +::: + +## Installation + +This plugin comes pre-installed but requires activation to function. + +![20240712113500](https://static-docs.nocobase.com/20240712113500.png) + +## User Manual + +### UI Configuration Interface + +NocoBase provides a specialized UI configuration interface tailored for mobile use. + +![20240828220321](https://static-docs.nocobase.com/20240828220321.png) + +### Tab Bar + +Supports the addition of two types: links and pages. + +![20240828223244](https://static-docs.nocobase.com/20240828223244.png) + +### Adding Blocks + +The following desktop blocks can currently be added: + +![20240828223454](https://static-docs.nocobase.com/20240828223454.png) + +### Page Configuration + +![20240828221452](https://static-docs.nocobase.com/20240828221452.png) + +### Page Tabs + +![20240828222225](https://static-docs.nocobase.com/20240828222225.png) + +### Sub-Pages + +On mobile devices, pop-up actions open as sub-pages with swipe-back functionality. + + + +### Filtering + +Filtering utilizes a [Popup](https://mobile.ant.design/components/popup) interaction method. + +![20240828230549](https://static-docs.nocobase.com/20240828230549.png) + +### Configure menu access permissions + +You can configure menu access permissions just like on the desktop side, as shown below (the mobile plugin must be enabled first): + +![20240903221327_rec_](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240903221327_rec_.gif) + +## Development Guide + +Currently supported extension points include: + +![20240712115610](https://static-docs.nocobase.com/20240712115610.png) diff --git a/docs/fr-FR/handbook/multi-app-manager/index.md b/docs/fr-FR/handbook/multi-app-manager/index.md new file mode 100644 index 000000000..34959c3a5 --- /dev/null +++ b/docs/fr-FR/handbook/multi-app-manager/index.md @@ -0,0 +1,54 @@ +# Multi-App Manager + + + +## Introduction + +Dynamically manage multiple applications without the need for separate deployments, with each application being an independent instance. + +:::warning +The multi-app management plugin does not provide the capability for user sharing. It can be integrated through the "[Authentication plugin](/handbook/auth)" or handled using the "[App Switching plugin](/handbook/app-switching)". +::: + +## Installation + +This is a preset plugin that needs to be activated before use. + +![20240327144151](https://static-docs.nocobase.com/20240327144151.png) + +## User Manual + +![20240327144327](https://static-docs.nocobase.com/20240327144327.png) + +### Adding Applications + +![20240327150722](https://static-docs.nocobase.com/20240327150722.png) + +### Starting Methods + +Two starting methods are provided: + +- Start on first visit: The sub-application starts only when a user visits the sub-application's URL for the first time; +- Start with the main application: When the main application starts, the sub-applications start as well, which increases the startup time of the main application. + +![20240327170218](https://static-docs.nocobase.com/20240327170218.png) + +### Custom Domain Name + +Sub-applications can be accessed via subpaths `/apps/:appName/admin/`, for example: + +```bash +http://localhost:13000/apps/a_7zkxoarusnx/admin/z45sjaukasd +``` + +Additionally, sub-applications can be configured with independent subdomains, which require domain resolution to the current IP. If nginx is used, the domain also needs to be added in the nginx configuration. + +![20240327170301](https://static-docs.nocobase.com/20240327170301.png) + +### Display in the Menu + +:::warning +The list of sub-applications displayed in the current right drop-down menu is only a set of quick links. Users are not shared; sub-applications require login and can only be used by the main application's root account. Full application switching capabilities will be provided in the commercial plugin "[App Switching](//handbook/app-switching)". +::: + +![20240327151239](https://static-docs.nocobase.com/20240327151239.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/notification-email/index.md b/docs/fr-FR/handbook/notification-email/index.md new file mode 100644 index 000000000..332ff1137 --- /dev/null +++ b/docs/fr-FR/handbook/notification-email/index.md @@ -0,0 +1,25 @@ +# Notification: email + + + +## Introduction + +Send notifications through the email channel, currently supporting only the SMTP transmission method. + +## Installation + +This is a built-in plugin that must be activated before use. + +![20240928192940](https://static-docs.nocobase.com/20240928192940.png) + +## User Manual + +### Email Channel Configuration + +Currently, only the SMTP transmission method is supported. + +![20240928191819](https://static-docs.nocobase.com/20240928191819.png) + +### Workflow Notification Configuration + +![20240928191935](https://static-docs.nocobase.com/20240928191935.png) diff --git a/docs/fr-FR/handbook/notification-in-app-message/index.md b/docs/fr-FR/handbook/notification-in-app-message/index.md new file mode 100644 index 000000000..8ae24ad1d --- /dev/null +++ b/docs/fr-FR/handbook/notification-in-app-message/index.md @@ -0,0 +1,45 @@ +# Notification: In-App Message + + + +## Introduction + +Enables users to receive real-time message notifications directly within the NocoBase application. + +## Installation + +This plugin is pre-installed, so no additional setup is required. + +## Adding an In-App Message Channel + +Go to the notification management section, click adding button and select In-app message. +![2024-11-08-08-33-26-20241108083326](https://static-docs.nocobase.com/2024-11-08-08-33-26-20241108083326.png) + +Fill in the channel name and description, then click submit. +![2024-11-08-08-34-32-20241108083431](https://static-docs.nocobase.com/2024-11-08-08-34-32-20241108083431.png) + +The new channel will now appear in the list. + +![2024-11-08-08-34-52-20241108083452](https://static-docs.nocobase.com/2024-11-08-08-34-52-20241108083452.png) + +## Example Usage Scenario + +To clarify the use of In-app message, here’s an example for "Marketing Lead Follow-Up". + +Imagine your team is running a major marketing campaign aimed at tracking responses and needs from potential clients. Using in-app messages, you can: + +**Set Up a Notification Channel:** Begin by creating a channel called "Marketing Clue" in notification management, making it easy for team members to identify its purpose. + +![2024-11-08-08-34-32-20241108083431](https://static-docs.nocobase.com/2024-11-08-08-34-32-20241108083431.png) + +**Configure a Workflow:** Create a workflow that automatically triggers notifications whenever a new lead is generated. Add a notification node to this workflow, select the "Marketing Clue" channel, and customize the message content according to campaign needs. For example: + +![image-1-2024-10-27-14-07-17](https://static-docs.nocobase.com/image-1-2024-10-27-14-07-17.png) + +**Receive Notifications in Real-Time:** Once the workflow triggers, all relevant team members will receive notifications instantly, allowing for quick responses. + +![image-2-2024-10-27-14-07-22](https://static-docs.nocobase.com/image-2-2024-10-27-14-07-22.png) + +**Message Management and Tracking:** In-app messages are grouped by channel name, and you can filter messages by read or unread status to prioritize important information. Clicking "View" redirects you to a configured link, allowing you to manage tasks seamlessly. + +![20241027140648-2024-10-27-14-06-51-2024-10-29-13-26-41](https://static-docs.nocobase.com/20241027140648-2024-10-27-14-06-51-2024-10-29-13-26-41.png) diff --git a/docs/fr-FR/handbook/notification-manager/development/api.md b/docs/fr-FR/handbook/notification-manager/development/api.md new file mode 100644 index 000000000..898f4d045 --- /dev/null +++ b/docs/fr-FR/handbook/notification-manager/development/api.md @@ -0,0 +1,131 @@ +# API + +## Server Side + +### `BaseNotificationChannel` + +This abstract class represents a base for different types of notification channels, defining essential interfaces for channel implementation. To add a new notification channel, you must extend this class and implement its methods. + +```ts +export abstract class BaseNotificationChannel { + constructor(protected app: Application) {} + abstract send(params: { + channel: ChannelOptions; + message: Message; + }): Promise<{ message: Message; status: 'success' | 'fail'; reason?: string }>; +} +``` + +### `PluginNotificationManagerServer` + +This server-side plugin serves as a notification management tool, providing methods for registering notification channel types and sending notifications. + +#### `registerChannelType()` + +This method registers a new channel type on the server side. Example usage is provided below. + +```ts +import PluginNotificationManagerServer from '@nocobase/plugin-notification-manager'; +import { Plugin } from '@nocobase/server'; +import { ExampleServer } from './example-server'; +export class PluginNotificationExampleServer extends Plugin { + async load() { + const notificationServer = this.pm.get(PluginNotificationManagerServer) as PluginNotificationManagerServer; + notificationServer.registerChannelType({ type: 'example-sms', Channel: ExampleServer }); + } +} + +export default PluginNotificationExampleServer; +``` + +##### Signature + +`registerChannelType({ type, Channel }: {type: string, Channel: BaseNotificationChannel })` + +#### `send()` + +The `send` method is used to dispatch notifications via a specified channel. + +```ts +send('in-app-message', + message: [ + receivers: [1, 2, 3], + receiverType: 'userId', + content: 'In-app message test', + title: 'In-app message test title' + ], + triggerFrom: 'workflow') + +send('email', + message: [ + receivers: ['a@163.com', 'b@163.com'], + receiverType: 'email', + content: 'Email test', + title: 'Email test title' + ], + triggerFrom: 'workflow') +``` + +##### Signature + +`send(sendConfig: {channelName: String, message: Object, receivers: ReceiversType, triggerFrom: String })` + +The `receivers` field currently supports two formats: NocoBase user IDs`userId` or custom channel configurations`channel-self-defined`. + +```ts +type ReceiversType = + | { value: number[]; type: 'userId' } + | { value: any; type: 'channel-self-defined'; channelType: string }; +``` + +##### Detailed Information + +`sendConfig` + +| Property | Type | Description | +| -------------- | ---------------- | ------------------------ | +| `channelName` | `string` | Channel identifier | +| `message` | `object` | Message object | +| `receivers` | `ReceiversType` | Recipients | +| `triggerFrom` | `string` | Source of trigger | + +## Client Side + +### `PluginNotificationManagerClient` + +#### `channelTypes` + +The library of registered channel types. + +##### Signature + +`channelTypes: Registry` + +#### `registerChannelType()` + +Registers a client-side channel type. + +##### Signature + +`registerChannelType(params: registerTypeOptions)` + +##### Type + +```ts +type registerTypeOptions = { + title: string; // Display title for the channel + type: string; // Channel identifier + components: { + ChannelConfigForm?: ComponentType // Channel configuration form component; + MessageConfigForm?: ComponentType<{ variableOptions: any }> // Message configuration form component; + ContentConfigForm?: ComponentType<{ variableOptions: any }> // Content configuration form component (for message content only, excluding recipient configuration); + }; + meta?: { // Metadata for channel configuration + createable?: boolean // Whether new channels can be added; + editable?: boolean // Whether channel configuration is editable; + deletable?: boolean // Whether channel configuration is deletable; + }; +}; + +type RegisterChannelType = (params: ChannelType) => void +``` diff --git a/docs/fr-FR/handbook/notification-manager/development/extension.md b/docs/fr-FR/handbook/notification-manager/development/extension.md new file mode 100644 index 000000000..842100700 --- /dev/null +++ b/docs/fr-FR/handbook/notification-manager/development/extension.md @@ -0,0 +1,283 @@ +## Extension + +NocoBase supports the expansion of notification channel types, such as SMS notifications and app push notifications,etc. + +## Client + +### Channel Type Registration + +The client channel configuration and message configuration interface are registered through the `registerChannelType` method provided by the notification management plugin client: + +```ts +import PluginNotificationManagerClient from '@nocobase/plugin-notification-manager/client'; + +class PluginNotificationExampleClient extends Plugin { + async afterAdd() {} + + async beforeLoad() {} + + async load() { + const notification = this.pm.get(PluginNotificationManagerClient); + notification.registerChannelType({ + title: 'Example SMS', // Channel type name + type: 'example-sms', // Channel type identifier + components: { + ChannelConfigForm, // Channel configuration form + MessageConfigForm, // Message configuration form + }, + }); + } +} + +export default PluginNotificationExampleClient; +``` + +## Server + +### Extending Abstract Class + +The core of server development involves extending the `BaseNotificationChannel` abstract class and implementing the `send` method, which contains the business logic for sending notifications through the extended plugin. + +```ts +import { BaseNotificationChannel } from '@nocobase/plugin-notification-manager'; + +export class ExampleServer extends BaseNotificationChannel { + async send(args): Promise { + console.log('ExampleServer send', args); + return { status: 'success', message: args.message }; + } +} +``` + +### Server Registration + +The `registerChannelType` method of the notification server core should be called to register the server implementation class in the core: + +```ts +import PluginNotificationManagerServer from '@nocobase/plugin-notification-manager'; +import { Plugin } from '@nocobase/server'; +import { ExampleServer } from './example-server'; +export class PluginNotificationExampleServer extends Plugin { + async load() { + const notificationServer = this.pm.get(PluginNotificationManagerServer) as PluginNotificationManagerServer; + notificationServer.registerChannelType({ type: 'example-sms', Channel: ExampleServer }); + } +} + +export default PluginNotificationExampleServer; +``` + +## Full Example + +Here is a sample notification extension to describe in detail how to develop an extension. +Suppose we want to add SMS notification to NocoBase using a platform's SMS gateway. + +### Plugin Creation + +1. Run the command to create the plugin `yarn pm add @nocobase/plugin-notification-example` + +### Client Development + +For the client, develop two form components: `ChannelConfigForm` (Channel Configuration Form) and `MessageConfigForm` (Message Configuration Form). + +#### ChannelConfigForm + +To send SMS messages, an API key and secret are required. Create a new file named `ChannelConfigForm.tsx` in the `src/client` directory: + +```ts +import React from 'react'; +import { SchemaComponent } from '@nocobase/client'; +import useLocalTranslation from './useLocalTranslation'; + +const ChannelConfigForm = () => { + const t = useLocalTranslation(); + return ( + + ); +}; + +export default ChannelConfigForm; +``` + +#### MessageConfigForm + +The message configuration form mainly includes the configuration for recipients (`receivers`) and message content (`content`). Create a new file named `MessageConfigForm.tsx` in the `src/client` directory: + +```ts +import React from 'react'; +import { SchemaComponent } from '@nocobase/client'; +import useLocalTranslation from './useLocalTranslation'; + +const MessageConfigForm = ({ variableOptions }) => { + const { t } = useLocalTranslation(); + return ( + + ); +}; + +export default MessageConfigForm +``` + +#### Client Component Registration + +After developing the form configuration components, register them in the notification management core. Assume the platform name is "Example." Edit `src/client/index.tsx` as follows: + +```ts +import { Plugin } from '@nocobase/client'; +import PluginNotificationManagerClient from '@nocobase/plugin-notification-manager/client'; +import { tval } from '@nocobase/utils/client'; +import ChannelConfigForm from './ChannelConfigForm'; +import MessageConfigForm from './MessageConfigForm'; + +class PluginNotificationExampleClient extends Plugin { + async afterAdd() {} + + async beforeLoad() {} + + async load() { + const notification = this.pm.get(PluginNotificationManagerClient); + notification.registerChannelType({ + title: tval('Example SMS', { ns: '@nocobase/plugin-notification-example' }), + type: 'example-sms', + components: { + ChannelConfigForm, + MessageConfigForm, + }, + }); + } +} + +export default PluginNotificationExampleClient; +``` + +At this point, the development of the client is complete + +### Server Development + +The core of server development involves extending the `BaseNotificationChannel` abstract class and implementing the `send` method. In the `src/server` directory, add a file named `example-server.ts`: + +```ts +import { BaseNotificationChannel } from '@nocobase/plugin-notification-manager'; + +export class ExampleServer extends BaseNotificationChannel { + async send(args): Promise { + console.log('ExampleServer send', args); + return { status: 'success', message: args.message }; + } +} +``` + +Next, register the server extension plugin by editing `src/server/plugin.ts`: + +```ts +import PluginNotificationManagerServer from '@nocobase/plugin-notification-manager'; +import { Plugin } from '@nocobase/server'; +import { ExampleServer } from './example-server'; +export class PluginNotificationExampleServer extends Plugin { + async load() { + const notificationServer = this.pm.get(PluginNotificationManagerServer) as PluginNotificationManagerServer; + notificationServer.registerChannelType({ type: 'example-sms', Channel: ExampleServer }); + } +} + +export default PluginNotificationExampleServer; +``` + +### Plugin Registration and Launch + +1. Run the registration command: `yarn pm add @nocobase/plugin-notification-example` +2. Run the enable command: `yarn pm enable @nocobase/plugin-notification-example` + +### Channel Configuration + +Upon visiting the Notification management channel page, you can see that the `Example SMS` channel has been enabled. +![20241009164207-2024-10-09-16-42-08](https://static-docs.nocobase.com/20241009164207-2024-10-09-16-42-08.png) + +Add a sample channel. +![20241009164519-2024-10-09-16-45-20](https://static-docs.nocobase.com/20241009164519-2024-10-09-16-45-20.png) + +Create a new workflow and configure the notification node. +![20241009172737-2024-10-09-17-27-38](https://static-docs.nocobase.com/20241009172737-2024-10-09-17-27-38.png) + +Trigger the workflow execution to view the following information output in the console. +![20241009181617-2024-10-09-18-16-18](https://static-docs.nocobase.com/20241009181617-2024-10-09-18-16-18.png) diff --git a/docs/fr-FR/handbook/notification-manager/index.md b/docs/fr-FR/handbook/notification-manager/index.md new file mode 100644 index 000000000..002cea80c --- /dev/null +++ b/docs/fr-FR/handbook/notification-manager/index.md @@ -0,0 +1,34 @@ +# Notification Manager + + + +## Introduction + +The Notification Manager is a centralized service that integrates various notification channels, offering a unified interface for channel configuration, management of notifications, and log recording. It’s also designed to be highly flexible, allowing for the expansion of additional channels. + +![20240928112556](https://static-docs.nocobase.com/20240928112556.png) + +- Purple section: The Notification Manager provides a comprehensive service that includes channel configuration and log recording, with the option to expand to other notification channels. +- Green section: In-App Message, a built-in channel, enables users to receive notifications directly within the application. +- Red section: Email, an extendable channel, allows users to receive notifications through email. + +## Channel Management + +![20240928181752](https://static-docs.nocobase.com/20240928181752.png) + +The currently supported channels include: + +- [In-App Message](/handbook/notification-in-app-message) (under development) +- [Email](/handbook/notification-email) (built-in SMTP protocol) + +For additional channels, refer to the [Channel Expansion](./extension) documentation. + +## Notification Logs + +The system logs each notification's details and status, offering a valuable tool for both analysis and troubleshooting. + +![20240928181649](https://static-docs.nocobase.com/20240928181649.png) + +## Workflow Notification Node + +![20240928181726](https://static-docs.nocobase.com/20240928181726.png) diff --git a/docs/fr-FR/handbook/plugin-manager/index.md b/docs/fr-FR/handbook/plugin-manager/index.md new file mode 100644 index 000000000..6bde6c7e3 --- /dev/null +++ b/docs/fr-FR/handbook/plugin-manager/index.md @@ -0,0 +1,16 @@ +# Plugin Management + + + + +## Plugin Manager + +By clicking the plugin manager icon in the top right corner, you can access the plugin manager page. Here, you can view, install, enable, and disable plugins. + +![2024-04-10_08-47-45](https://static-docs.nocobase.com/2024-04-10_08-47-45.png) + +## Plugin Settings Center + +Plugins usually come with their own settings page. By clicking on the settings icon in the top right corner, you can see the menu of all plugin settings pages. By clicking on the relevant menu, you can set the corresponding plugin. + +![2024-04-10_08-52-41](https://static-docs.nocobase.com/2024-04-10_08-52-41.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/public-forms/index.md b/docs/fr-FR/handbook/public-forms/index.md new file mode 100644 index 000000000..df8db9b4e --- /dev/null +++ b/docs/fr-FR/handbook/public-forms/index.md @@ -0,0 +1,43 @@ +# Public Forms + + + +## Introduction + +Share public forms externally to gather information from anonymous users. + +## Installation + +This is a pre-installed plugin that must be activated before use. + +![20241028150028](https://static-docs.nocobase.com/20241028150028.png) + +## Usage Instructions + +Public Form List + +![20241028150853](https://static-docs.nocobase.com/20241028150853.png) + +Creating a Public Form + +![20241028150937](https://static-docs.nocobase.com/20241028150937.png) + +Configuring the Form + +![20241028151223](https://static-docs.nocobase.com/20241028151223.png) + +Public Form Settings + +![20241028151353](https://static-docs.nocobase.com/20241028151353.png) + +Viewing the Public Form + +![20241028151415](https://static-docs.nocobase.com/20241028151415.png) + +Password Protection + +![20241028151438](https://static-docs.nocobase.com/20241028151438.png) + +Submission Success Notification + +![20241028152554](https://static-docs.nocobase.com/20241028152554.png) diff --git a/docs/fr-FR/handbook/system-settings/index.md b/docs/fr-FR/handbook/system-settings/index.md new file mode 100644 index 000000000..993cc6ec5 --- /dev/null +++ b/docs/fr-FR/handbook/system-settings/index.md @@ -0,0 +1,10 @@ +# System Settings + + + +## Introduction +To set the global information of the system, such as system name, main LOGO, enabled language, etc. + +## User Manual + +![20240324191444](https://static-docs.nocobase.com/20240324191444.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/system-settings/language-settings.md b/docs/fr-FR/handbook/system-settings/language-settings.md new file mode 100644 index 000000000..e72540eba --- /dev/null +++ b/docs/fr-FR/handbook/system-settings/language-settings.md @@ -0,0 +1,15 @@ +# Language Settings + + + +In "System Settings" by setting "Enabled Languages," you can adjust the global language environment of the system, with the first language being the default. + +![20240324192005](https://static-docs.nocobase.com/20240324192005.png) + +When multiple languages are enabled, users can set their language preferences in the user's personal center (top right corner). + +![20240324192509](https://static-docs.nocobase.com/20240324192509.png) + +If the language environment you are using is not translated, you can use the "[Localization Management](/handbook/localization-management)" plugin to perform translations. + +![20240324193055](https://static-docs.nocobase.com/20240324193055.png) \ No newline at end of file diff --git a/docs/fr-FR/handbook/telemetry-prometheus/index.md b/docs/fr-FR/handbook/telemetry-prometheus/index.md new file mode 100644 index 000000000..244ea1081 --- /dev/null +++ b/docs/fr-FR/handbook/telemetry-prometheus/index.md @@ -0,0 +1,71 @@ +# Telemetry - Prometheus + + + +## Introduction + +This plugin is used to convert OpenTelemetry protocol (OTLP) data into Prometheus format and expose an interface for Prometheus to scrape metric data. + +## Installation + +:::info{title=Note} +This is a commercial plugin. Please see [NocoBase commercial version](https://www.nocobase.com/commercial) for details. +::: + +## User Manual + +### Environment Variables + +Configure the environment variables before starting NocoBase. + +#### TELEMETRY_ENABLED + +Set to `on`. + +```bash +TELEMETRY_ENABLED=on +``` + +#### TELEMETRY_METRIC_READER + +Add `prometheus`. + +```bash +TELEMETRY_METRIC_READER=prometheus +``` + +#### TELEMETRY_PROMETHEUS_SERVER + +Whether to start a separate server. + +- `off`. The scraping interface is `/api/prometheus:metrics`. +- `on`. The scraping interface is `:port/metrics`. + +#### TELEMETRY_PROMETHEUS_PORT + +The port for the separate server when activated. Default `9464`. + +#### Related Documents + +- [Environment Variables](../../welcome/getting-started/env.md#telemetry_enabled) + +### Prometheus Configuration + +Separate server + +```yaml +scrape_configs: + - job_name: 'nocobase' + static_configs: + - targets: ['localhost:9464'] +``` + +Internal API + +```yaml +scrape_configs: + - job_name: 'nocobase' + metrics_path: '/api/prometheus:metrics' + static_configs: + - targets: ['localhost:13001'] +``` \ No newline at end of file diff --git a/docs/fr-FR/handbook/template-handlebars/index.md b/docs/fr-FR/handbook/template-handlebars/index.md new file mode 100644 index 000000000..2270cdd88 --- /dev/null +++ b/docs/fr-FR/handbook/template-handlebars/index.md @@ -0,0 +1,145 @@ +# Handlebars Template + +## Introduction + +Handlebars is a popular templating engine that allows us to dynamically embed data into HTML using a simple template syntax. + +## Usage + +### Basic Template Syntax + +In Handlebars, the basic syntax includes: + +- Interpolation expression `{{variable}}` to output data. +- Conditional expression `{{#if condition}}...{{/if}}` for logical conditions. +- Looping `{{#each array}}...{{/each}}` to iterate over arrays. + +For example, given the following data: + +```javascript +const context = { + title: "Handlebars Template Example", + items: ["Apple", "Banana", "Orange"] +}; +``` + +With the following template: + +```handlebars +

    {{title}}

    +
      + {{#each items}} +
    • {{this}}
    • + {{/each}} +
    +``` + +The generated HTML will be: + +```html +

    Handlebars Template Example

    +
      +
    • Apple
    • +
    • Banana
    • +
    • Orange
    • +
    +``` + +For more content refer to +- [Core](/api/handlebars-helpers/core) + +### Comparison Operations + +You can use comparison operators for conditional statements. Supported comparison functions include `eq` (equals), `ne` (not equals), `gt` (greater than), `lt` (less than), etc. + +```handlebars +{{#if (eq 10 10)}} +

    Equal

    +{{else}} +

    Not equal

    +{{/if}} +``` + +Logical operators like `and`, `or`, `not` can also be used: + +```handlebars +{{#if (and true true)}} +

    Both are true!

    +{{/if}} +``` + +```handlebars +{{#if (or false true)}} +

    One of them is true!

    +{{/if}} +``` + +For more content, refer to + +- [Comparison](/api/handlebars-helpers/comparison) + +### Mathematical Operations + +You can perform simple mathematical operations in templates: + +```handlebars +{{add 4 5}} +{{minus 10 3}} +``` + +For more content refer to + +- [Math](/api/handlebars-helpers/math) + +### String Handling + +```handlebars +{{uppercase "hello world"}} + +{{ellipsis "foo bar baz", 7}} + +``` + +For more content, refer to + +- [String](/api/handlebars-helpers/string) + +### Date Handling + +```handlebars +

    {{dateFormat "2024-09-25" "YYYY"}}

    +``` + +For more content refer to +- [Date](/api/handlebars-helpers/date) + +### Array and Object Operations + +```handlebars +

    First element: {{first items}}

    +

    Last element: {{last items}}

    +``` + +For more content, refer to + +- [Array](/api/handlebars-helpers/array) +- [Object](/api/handlebars-helpers/object) + +### More Helpers + + +| Category | Description | +| ------------------------------------------------ | ---------------------------------- | +| [Core](/api/handlebars-helpers/core) | Built-in Handlebars methods | +| [Array](/api/handlebars-helpers/array) | Methods for handling arrays | +| [Comparison](/api/handlebars-helpers/comparison) | Comparison operators and methods | +| [Date](/api/handlebars-helpers/date) | Methods for date and time | +| [HTML](/api/handlebars-helpers/html) | Methods for HTML document handling | +| [I18n](/api/handlebars-helpers/i18n) | Internationalization support | +| [Math](/api/handlebars-helpers/math) | Mathematical functions | +| [Number](/api/handlebars-helpers/number) | Number formatting and handling | +| [Object](/api/handlebars-helpers/object) | Methods for object handling | +| [Path](/api/handlebars-helpers/path) | Methods for path and filesystem | +| [Regex](/api/handlebars-helpers/regex) | Regular expression methods | +| [String](/api/handlebars-helpers/string) | String manipulation methods | +| [URL](/api/handlebars-helpers/url) | URL parsing and building methods | diff --git a/docs/fr-FR/handbook/template-json/index.md b/docs/fr-FR/handbook/template-json/index.md new file mode 100644 index 000000000..6e1e06fb2 --- /dev/null +++ b/docs/fr-FR/handbook/template-json/index.md @@ -0,0 +1,57 @@ +# JSON Template + +## Introduction + +In a JSON template, variables are represented in string format and must be enclosed in double quotes, such as {{xxxx}}. During the parsing process, each variable's value is converted to its appropriate type based on its actual content. Thus, while the variable itself is a string, the resulting parsed value may not necessarily remain a string. + +## Example + +The JSON template is as follows + +```json +{ + "key1": "{{current.key1}}", + "key2": "{{current.key2}}", + "key3": "{{current.key3}}", + "key4": "{{current.key4}}", + "key5": "{{current.key5}}", + "key6": "{{current.key6}}", + "key7": { + "key1": "{{current.key1}}", + "key2": "{{current.key2}}" + }, + "key8": ["{{current.key1}}", "{{current.key3}}"], + "key9": "{{current.key1}} - \"{{current.key3}}\" - {{current.key3}} - val9" +} +``` + +The current variables are as follows + +```json +{ + "key1": "val1", + "key2": null, + "key3": 3, + "key4": {"k": "v"}, + "key5": [1, 2, 3], + "key6": undefined +} +``` + +The parsed result will be + +```json +{ + "key1": "val1", + "key2": null, + "key3": 3, + "key4": {"k": "v"}, + "key5": [1, 2, 3], + "key7": { + "key1": "val1", + "key2": null + }, + "key8": ["val1", 3], + "key9": "val1 - \"3\" - 3 - val9" +} +``` diff --git a/docs/fr-FR/handbook/template-string/index.md b/docs/fr-FR/handbook/template-string/index.md new file mode 100644 index 000000000..1933010f1 --- /dev/null +++ b/docs/fr-FR/handbook/template-string/index.md @@ -0,0 +1,2 @@ +# 字符串模板 + diff --git a/docs/fr-FR/handbook/theme-editor/index.md b/docs/fr-FR/handbook/theme-editor/index.md new file mode 100644 index 000000000..41e8a8612 --- /dev/null +++ b/docs/fr-FR/handbook/theme-editor/index.md @@ -0,0 +1,57 @@ +# Theme Editor + +> Note: The current theme feature is implemented based on antd 5.x version. It is recommended to read about the [Customizing Theme](https://ant.design/docs/react/customize-theme#%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%BB%E9%A2%98) concept before proceeding with this document. + +## Introduction + +The plugin is essentially a tool for modifying the style of the entire front-end page. It currently supports editing global [SeedToken](https://ant.design/docs/react/customize-theme#seedtoken), [MapToken](https://ant.design/docs/react/customize-theme#maptoken), and [AliasToken](https://ant.design/docs/react/customize-theme#aliastoken), as well as enabling a [switch](https://ant.design/docs/react/customize-theme#%E4%BD%BF%E7%94%A8%E9%A2%84%E8%AE%BE%E7%AE%97%E6%B3%95) to Dark Mode and Compact Mode. In the future, it may support [component-level](https://ant.design/docs/react/customize-theme#%E4%BF%AE%E6%94%B9%E7%BB%84%E4%BB%B6%E5%8F%98%E9%87%8F-component-token) theme customization. + +## Usage Instructions + +### Enabling The Theme Plugin + +Firstly, update NocoBase to the latest version (v0.11.1 or above). Then, search for the `Theme Editor` card in the `Plugin Management` Page. Click on the Enable button at the bottom right of the card and wait for the page to refresh. + +![20240409132838](https://static-docs.nocobase.com/20240409132838.png) + +### Navigate to the Theme Configuration Page + +After enabling, click on the settings button at the bottom left of the card, and you will be redirected to the theme editing page. By default, there are four theme options: `Default Theme`, `Dark Theme`, `Compact Theme`, and `Compact Dark Theme`. + +![20240409133020](https://static-docs.nocobase.com/20240409133020.png) + +## Adding a New Theme + +Click the `Add New Theme` button and choose `Create a Brand New Theme`. A Theme Editor will pop up on the right side of the page, allowing you to edit Colors, Sizes, Styles, and more. After editing, enter a theme name and click save to add the new theme. + +![20240409133147](https://static-docs.nocobase.com/20240409133147.png) + +## Applying the New Theme + +You can move the mouse to the top right corner of the page, where you will see a theme switcher. Clicking on it allows you to switch to other themes, such as the newly added theme. + +![20240409133247](https://static-docs.nocobase.com/20240409133247.png) + +## Editing an Existing Theme + +Click the `Edit` button at the bottom left of the card. Similar to adding a new theme, a Theme Editor will pop up on the right side of the page. After editing, click save to complete the theme modification. + +![20240409134413](https://static-docs.nocobase.com/20240409134413.png) + +## User Options for Theme Switching + +Newly added themes are by default available for users to switch to. If you do not want users to switch to a certain theme, you can turn off the `User selectable` switch at the bottom right of the theme card, making it unavailable for users to choose. + +![20240409133331](https://static-docs.nocobase.com/20240409133331.png) + +## Setting as Default Theme (The Default Theme Cannot Be Deleted) + +Initially, the `Default Theme` is set as the default. If you want to set a specific theme as the new default, switch on the `Default Theme` toggle at the bottom right of the card. This will ensure that when users open the page for the first time, they will be presented with this theme. + +![20240409133409](https://static-docs.nocobase.com/20240409133409.png) + +## Deleting a Theme + +Click on the Delete button below the card, then click on the confirmation button that pops up to remove the theme. + +![20240409133435](https://static-docs.nocobase.com/20240409133435.png) diff --git a/docs/fr-FR/handbook/ui-schema-storage/index.md b/docs/fr-FR/handbook/ui-schema-storage/index.md new file mode 100644 index 000000000..399455130 --- /dev/null +++ b/docs/fr-FR/handbook/ui-schema-storage/index.md @@ -0,0 +1,12 @@ +# UI Schema Storage + +:::warning +Document pending. +::: + + diff --git a/docs/fr-FR/handbook/ui/actions/action-settings/affter-successful.md b/docs/fr-FR/handbook/ui/actions/action-settings/affter-successful.md new file mode 100644 index 000000000..b53b3b748 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/action-settings/affter-successful.md @@ -0,0 +1,13 @@ +# After Successful Submission + +## Introduction + +The After successful submission enables customization of the response behavior upon completion. It supports defining custom success messages, selecting automatic or manual dismissal of success notifications, and choosing whether to remain on the current page, return to the previous popup or page, or redirect to a specified route, depending on the requirements. + +![20240413213519](https://static-docs.nocobase.com/20240413213519.png) + +![20241012125623](https://static-docs.nocobase.com/20241012125623.png) + +- Stay on the current popup or page: After the operation is successful, the pop-up window or route is not closed +- Return to the previous popup or page(default): Close the popup window after the operation is successful +- Redirect to: After the operation succeeds, the route is switched to the specified route diff --git a/docs/fr-FR/handbook/ui/actions/action-settings/assign-values.md b/docs/fr-FR/handbook/ui/actions/action-settings/assign-values.md new file mode 100644 index 000000000..54747d7fe --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/action-settings/assign-values.md @@ -0,0 +1,29 @@ +# Assign Field Values + +## Introduction + +Field values assignment allows you to preset values for fields before executing operations. This feature ensures that data is automatically populated when updating or creating records, eliminating the need for manual input. Common scenarios include bulk updating order statuses or automatically setting the delivery time to the current time when an order is delivered. + +![20240413103137](https://static-docs.nocobase.com/20240413103137.png) + +![20240413215221](https://static-docs.nocobase.com/20240413215221.png) + +## Usage Instructions + +### Configuring Fields + +Only fields within the current table can be configured. + +![20240413103207](https://static-docs.nocobase.com/20240413103207.png) + +### Constants + +![20240426153323](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426153323.png) + +### Variables + +Different field types support various variable types, offering flexibility depending on the data you're working with. + +![20240426153534](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426153534.png) + +For more information on variables, refer to the [Variables](/handbook/ui/variables) section. diff --git a/docs/fr-FR/handbook/ui/actions/action-settings/bind-workflow.md b/docs/fr-FR/handbook/ui/actions/action-settings/bind-workflow.md new file mode 100644 index 000000000..2b83dc882 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/action-settings/bind-workflow.md @@ -0,0 +1,20 @@ +# Bind Workflows + +## Introduction + +Binding a workflow is a powerful way to automate data processing. By linking an operation to a workflow, you ensure that data flows seamlessly through business processes. It’s important to note that workflows are triggered only after a successful data submission; if the operation fails, the workflow will not be activated. + +![20240413095247](https://static-docs.nocobase.com/20240413095247.png) + +![20240413095309](https://static-docs.nocobase.com/20240413095309.png) + +The following operation buttons currently support workflow binding: + +"Submit" and "Save" buttons for new forms. + +"Submit" and "Save" buttons for update forms. + +"Update Data" button in data rows (including tables, lists, kanban, etc.). + +For more details, see [Post-Action Events](/handbook/workflow-action-trigger) in the workflow documentation. + diff --git a/docs/fr-FR/handbook/ui/actions/action-settings/double-check.md b/docs/fr-FR/handbook/ui/actions/action-settings/double-check.md new file mode 100644 index 000000000..8fd39dc35 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/action-settings/double-check.md @@ -0,0 +1,15 @@ +# Secondary Confirmation + +## Introduction + +The Double check configuration is designed to ensure that an operation is deliberate before it proceeds. When an action is clicked, a confirmation box will appear. By default, the delete button has secondary confirmation enabled to prevent accidental operations that could lead to data loss or irreversible outcomes. + +![20240919164638](https://static-docs.nocobase.com/20240919164638.png) + +Support customizing secondary confirmation content and titles + +![20240919164704](https://static-docs.nocobase.com/20240919164704.png) + +![20240919164800](https://static-docs.nocobase.com/20240919164800.png) + + diff --git a/docs/fr-FR/handbook/ui/actions/action-settings/edit-button.md b/docs/fr-FR/handbook/ui/actions/action-settings/edit-button.md new file mode 100644 index 000000000..154d96227 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/action-settings/edit-button.md @@ -0,0 +1,9 @@ +# Edit Button + +## Introduction + +You can personalize the button’s name, icon, and background color. There are three color choices: default, highlighted, or Danger red. + +![20240413093715](https://static-docs.nocobase.com/20240413093715.png) + +![20240413093745](https://static-docs.nocobase.com/20240413093745.png) diff --git a/docs/fr-FR/handbook/ui/actions/action-settings/linkage-rule.md b/docs/fr-FR/handbook/ui/actions/action-settings/linkage-rule.md new file mode 100644 index 000000000..1c30ecf21 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/action-settings/linkage-rule.md @@ -0,0 +1,36 @@ +# Linkage Rule + +## Introduction + +The linkage rules for actions are configured based on contextual data conditions and execution results. By configuring these linkage rules, you can control the status of actions (Visible, Hidden, Enabled, Disabled). + +![20240423113057](https://static-docs.nocobase.com/20240423113057.png) + +## Usage Instructions + +![20240413102150](https://static-docs.nocobase.com/20240413102150.png) + +When conditions are met (by default, they pass without conditions), the action is triggered. Constants and variables can be used in the condition evaluation. + +### Applicable Buttons for Linkage Rules + +Currently, only buttons with data context support configuring linkage rules. + +Row buttons in blocks such as tables and Gantt charts; + +Buttons in detail blocks; + + +### Constants + +Example: Hide the copy button for orders that have been canceled. + +![20240423113212](https://static-docs.nocobase.com/20240423113212.png) + +### Variables + +Example: Disable the delete button for orders with a delivery date later than today. + +![20240423113504](https://static-docs.nocobase.com/20240423113504.png) + +For further details on using variables, see the [Variables](/handbook/ui/variables) section. diff --git a/docs/fr-FR/handbook/ui/actions/action-settings/open-mode.md b/docs/fr-FR/handbook/ui/actions/action-settings/open-mode.md new file mode 100644 index 000000000..f634f76b9 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/action-settings/open-mode.md @@ -0,0 +1,15 @@ +# Open Mode + +## Introduction + +There are two ways to open a popup: using a drawer or dialog, with the drawer being the default. Drawers are ideal for managing large amounts of information and complex operations, while dialog boxes are better suited for straightforward content or quick actions. The popup can be closed by clicking on the overlay. + +![20240413102507](https://static-docs.nocobase.com/20240413102507.png) + +- drawer + +![20240423120702](https://static-docs.nocobase.com/20240423120702.png) + +- dialog + +![20240423120721](https://static-docs.nocobase.com/20240423120721.png) diff --git a/docs/fr-FR/handbook/ui/actions/action-settings/popup-size.md b/docs/fr-FR/handbook/ui/actions/action-settings/popup-size.md new file mode 100644 index 000000000..87dda5122 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/action-settings/popup-size.md @@ -0,0 +1,7 @@ +# Popup Size + +## Introduction + +Popups are available in three sizes: Large, Middle, and Small, with Middle being the default. You can adjust the Popup size to match the content. + +![20240413102716](https://static-docs.nocobase.com/20240413102716.png) diff --git a/docs/fr-FR/handbook/ui/actions/index.md b/docs/fr-FR/handbook/ui/actions/index.md new file mode 100644 index 000000000..0d012add5 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/index.md @@ -0,0 +1,21 @@ +# Actions + +In the UI, Actions are represented by buttons that trigger specific commands. These buttons can be directly placed on pages, within dialogs, or inside drawers, and they can also be combined with blocks. The current dynamic configuration options for Actions are primarily used when combined with blocks. + +#### Actions within Blocks + +![20240412113815](https://static-docs.nocobase.com/20240412113815.png) + +#### Operation Designer (Toolbar) + +Unlike blocks and fields, the operation designer features only two icons: +- Drag +- Configuration actions + +![20240412113855](https://static-docs.nocobase.com/20240412113855.png) + +#### Operation Drag-and-Drop Sorting + +To reorder buttons, simply hold down the "Drag" icon in the button designer and rearrange the buttons as needed. + +![20240412114236](https://static-docs.nocobase.com/20240412114236.gif) diff --git a/docs/fr-FR/handbook/ui/actions/types/add-new.md b/docs/fr-FR/handbook/ui/actions/types/add-new.md new file mode 100644 index 000000000..95493f6bb --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/add-new.md @@ -0,0 +1,17 @@ +# Add New +## Introduction + +The add operation is used to add records to the current block's data table. By configuring the form block, you can enter new data records into the current block's data table. + +![20240413210523](https://static-docs.nocobase.com/20240413210523.png) + +![20240423200432](https://static-docs.nocobase.com/20240423200432.png) + +## Operation Configuration Items + +![20240413210716](https://static-docs.nocobase.com/20240413210716.png) + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button) +- [Open Mode](/handbook/ui/actions/action-settings/open-mode) +- [Popup Size](/handbook/ui/actions/action-settings/popup-size) +- Enable Sub-table (Inherited Table) diff --git a/docs/fr-FR/handbook/ui/actions/types/add-record.md b/docs/fr-FR/handbook/ui/actions/types/add-record.md new file mode 100644 index 000000000..38470bd4c --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/add-record.md @@ -0,0 +1,39 @@ +# Add Record + +## Introduction + +The "Add Record" feature allows users to seamlessly insert records into any data table as part of an operation. + +![20240423202949](https://static-docs.nocobase.com/20240423202949.png) + +Select the target data table and add a form block. + +![20240423203010](https://static-docs.nocobase.com/20240423203010.png) + +## Using Tables to Select Records + +This functionality is currently designed for setting default field values in the "Add Record" operation within table blocks. + +For example, the Order table and the Product table have a many-to-many relationship. In the Product table block, you can configure the "Add Record" operation to input data into the Order table. + +![20240426101803](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426101803.png) + +In this case, set the default value of the "Product" relationship field in the Order table to "Table selected records". + +![20240426101823](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426101823.png) + +![20240426101922](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426101922.png) + +Here's the complete operation: + + + +## Operation Configuration Items + +![20240423203050](https://static-docs.nocobase.com/20240423203050.png) + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button) +- [Open Mode](/handbook/ui/actions/action-settings/open-mode) +- [Popup Size](/handbook/ui/actions/action-settings/popup-size) diff --git a/docs/fr-FR/handbook/ui/actions/types/delete.md b/docs/fr-FR/handbook/ui/actions/types/delete.md new file mode 100644 index 000000000..d87cd7c5e --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/delete.md @@ -0,0 +1,15 @@ +## Delete + +### Introduction + +The delete operation allows for the removal of data records. This can be done by configuring a row deletion button or utilizing the bulk action button for multiple records at once. + +![20240413211215](https://static-docs.nocobase.com/20240413211215.png) + +### Operation Configuration Items + +![20240413211439](https://static-docs.nocobase.com/20240413211439.png) + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button) +- [Secondary Confirmation](/handbook/ui/actions/action-settings/double-check) +- Refresh data after execution: Enabled by default, this option automatically refreshes the block data once the operation is successfully completed. diff --git a/docs/fr-FR/handbook/ui/actions/types/edit.md b/docs/fr-FR/handbook/ui/actions/types/edit.md new file mode 100644 index 000000000..b0ce2db91 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/edit.md @@ -0,0 +1,26 @@ +# Edit + +## Introduction + +The edit function is part of the row actions, with the current record serving as its context. It opens in a popup window, allowing users to configure and customize various blocks as needed. + +![20240412115736](https://static-docs.nocobase.com/20240412115736.png) + +Configure data blocks according to your requirements. + +![20240421110538](https://static-docs.nocobase.com/20240421110538.png) + +## Operation Configuration Items + +![20240421110728](https://static-docs.nocobase.com/20240421110728.png) + +### Linkage Rules + +Example: Editing is disabled for orders that have been received. +![20240423211911](https://static-docs.nocobase.com/20240423211911.png) + +For more information, see [Linkage Rule](/handbook/ui/actions/action-settings/linkage-rule). + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button): Customize the title, color, and icon of the edit button. +- [Open Mode](/handbook/ui/actions/action-settings/open-mode): Choose between Pop-up or Drawer. +- [Popup Size](/handbook/ui/actions/action-settings/popup-size): The default size is Middle (available sizes: Large/Middle/Small). diff --git a/docs/fr-FR/handbook/ui/actions/types/filter.md b/docs/fr-FR/handbook/ui/actions/types/filter.md new file mode 100644 index 000000000..bee9e34d9 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/filter.md @@ -0,0 +1,21 @@ +# Filter + +## Introduction + +Filtering operations are commonly found within data blocks, allowing users to filter data by setting various conditions. It's essential to note that if a data block has a predefined data range, the filtering criteria will be combined with the range conditions to create the final filtering rules. + +![20240413105921](https://static-docs.nocobase.com/20240413105921.png) + +## Operation Configuration Items + +![20240413110004](https://static-docs.nocobase.com/20240413110004.png) + +### Filterable Fields + +By default, all fields in the table are enabled, and only enabled fields can be selected from the condition field list. + +Fields from related tables can also be used as filterable fields. + +![20240423200041](https://static-docs.nocobase.com/20240423200041.png) + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button) diff --git a/docs/fr-FR/handbook/ui/actions/types/link.md b/docs/fr-FR/handbook/ui/actions/types/link.md new file mode 100644 index 000000000..d2cf30b8b --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/link.md @@ -0,0 +1,40 @@ +# Link + +## Introduction + +The link operation, which functions via route navigation, supports the passing of variables. The target page can dynamically adjust its content based on the provided data, making it configurable for use within data blocks. + +![20240603150755](https://static-docs.nocobase.com/20240603150755.png) + +## Operation Configuration + +![20240603150823](https://static-docs.nocobase.com/20240603150823.png) + +### Edit Link + +![20240603150944](https://static-docs.nocobase.com/20240603150944.png) + +![20240603224322](https://static-docs.nocobase.com/20240603224322.png) + +### Usage Scenarios + +Example: The author and article tables have a one-to-many relationship. In the author table, you can configure the "View posts" link operation. By clicking this link, the author's ID is passed as a parameter to the article table, allowing the target page to filter the articles based on the specified author's ID. + +![20240603151934](https://static-docs.nocobase.com/20240603151934.png) + +### Open in New Window + +When the "Open in new window" option is selected, the link will open in a new window. + +![20240718160541](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240718160541.png) + +Here is a complete configuration example: + + + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button): Customize the button's title, color, and icon. +- [Linkage Rule](/handbook/ui/actions/action-settings/linkage-rule): Dynamically control the button's state. diff --git a/docs/fr-FR/handbook/ui/actions/types/pop-up.md b/docs/fr-FR/handbook/ui/actions/types/pop-up.md new file mode 100644 index 000000000..f548721d1 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/pop-up.md @@ -0,0 +1,20 @@ +# Custom Pop-up + +## Introduction + +The custom pop-up feature functions much like the view and edit actions. It's part of the table's row buttons and uses the current record as its context. Users can set up multiple pop-up actions within the row operations of a table. + +![20240413104530](https://static-docs.nocobase.com/20240413104530.png) + +Configure blocks as needed in the pop-up window. + +![20240426161322](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240426161322.png) + +## Operation Configuration Items + +![20240413104602](https://static-docs.nocobase.com/20240413104602.png) + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button): Customize the title, color, and icon of the edit button +- [Linkage Rule](/handbook/ui/actions/action-settings/linkage-rule): Dynamically control the button’s state (Visible/Disabled) +- [Open Mode](/handbook/ui/actions/action-settings/open-mode): Pop-up/Drawer +- [Pop-up Size](/handbook/ui/actions/action-settings/popup-size): The default size is Middle(Large/Middle/Small) diff --git a/docs/fr-FR/handbook/ui/actions/types/refresh.md b/docs/fr-FR/handbook/ui/actions/types/refresh.md new file mode 100644 index 000000000..8ddd6c845 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/refresh.md @@ -0,0 +1,3 @@ +# Refresh + +![20240421112050](https://static-docs.nocobase.com/20240421112050.png) diff --git a/docs/fr-FR/handbook/ui/actions/types/save-record.md b/docs/fr-FR/handbook/ui/actions/types/save-record.md new file mode 100644 index 000000000..73241eb6f --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/save-record.md @@ -0,0 +1,26 @@ +# Save Record + +### Introduction + +The save data operation enables assigning values to fields through field assignment, which takes precedence over any values entered in the form. This operation can be paired with workflows to automate data processes seamlessly. + +![20240413214755](https://static-docs.nocobase.com/20240413214755.png) + +![20240413214926](https://static-docs.nocobase.com/20240413214926.png) + +### Operation Configuration Items + +#### Assign Field Values + +When field assignment is configured, the assigned value will override any input provided in the form for the same field, ensuring consistency and priority for the predefined value. + +![20240423213245](https://static-docs.nocobase.com/20240423213245.png) + +For more details, refer to [Assign Field Values](/handbook/ui/actions/action-settings/assign-value) + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button) +- [Secondary Confirmation](/handbook/ui/actions/action-settings/double-check) +- [After Successful Submission](/handbook/ui/actions/action-settings/affter-successful) +- [Bind Workflow](/handbook/ui/actions/action-settings/bind-workflow) +- Skip Required Validation +- Refresh After Execution diff --git a/docs/fr-FR/handbook/ui/actions/types/submit.md b/docs/fr-FR/handbook/ui/actions/types/submit.md new file mode 100644 index 000000000..747a5c1e5 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/submit.md @@ -0,0 +1,34 @@ +# Submit + +## Introduction + +The submission function is designed to save form data (unique to form blocks) and can be integrated with workflows to streamline data automation. + +![20240413093210](https://static-docs.nocobase.com/20240413093210.png) + +## Operation Configuration Items + +![20240413095124](https://static-docs.nocobase.com/20240413095124.png) + +### Save Mode + +The submission operation for form blocks that only add new data supports configuring the save method. + +![20240413101209](https://static-docs.nocobase.com/20240413101209.png) + +![20240413100531](https://static-docs.nocobase.com/20240413100531.png) + +1. Insert and create new records directly; +2. Insert only if the record doesn't exist (requires fields to determine the record’s existence); +3. Insert if the record doesn't exist, otherwise update (requires fields to check for existing records). + +### Bind Workflows + +The bound workflow will only be triggered once the data has been successfully submitted. + +![20240417120149](https://static-docs.nocobase.com/20240417120149.png) + +For further details, see [Bind Workflows](/handbook/ui/actions/action-settings/bind-workflow). + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button) +- [Secondary Confirmation](/handbook/ui/actions/action-settings/double-check) diff --git a/docs/fr-FR/handbook/ui/actions/types/trigger-workflow.md b/docs/fr-FR/handbook/ui/actions/types/trigger-workflow.md new file mode 100644 index 000000000..f238f61d7 --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/trigger-workflow.md @@ -0,0 +1,5 @@ +# Trigger Workflow + + + + diff --git a/docs/fr-FR/handbook/ui/actions/types/update-record.md b/docs/fr-FR/handbook/ui/actions/types/update-record.md new file mode 100644 index 000000000..1bedbcb5d --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/update-record.md @@ -0,0 +1,33 @@ +# Update Record + +## Introduction + +Custom row operations enable data updates by configuring field assignments and setting precise update logic for each field. + +![20240413212430](https://static-docs.nocobase.com/20240413212430.png) + +## Operation Configuration Items + +![20240413212816](https://static-docs.nocobase.com/20240413212816.png) + +### Linkage Rules + +Example: The button is hidden when the bill status is cancelled. + +![20240423210252](https://static-docs.nocobase.com/20240423210252.png) + +For more details, see [Linkage Rule](/handbook/ui/actions/action-settings/linkage-rule). + +### Assign Field Values + +Example: Update the receipt time in the current record to reflect the current time. + +![20240423210506](https://static-docs.nocobase.com/20240423210506.png) + +For more information, refer to [Assign Field Values](/handbook/ui/actions/action-settings/assign-values). + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button) +- [Secondary Confirmation](/handbook/ui/actions/action-settings/double-check) +- [After Successful Submission](/handbook/ui/actions/action-settings/affter-successful) +- [Bind Workflows](/handbook/ui/actions/action-settings/bind-workflow) +- Refresh the data after the execution diff --git a/docs/fr-FR/handbook/ui/actions/types/view.md b/docs/fr-FR/handbook/ui/actions/types/view.md new file mode 100644 index 000000000..6716d9a9a --- /dev/null +++ b/docs/fr-FR/handbook/ui/actions/types/view.md @@ -0,0 +1,18 @@ + +# View + +## Overview + +The "View" operation is a row-level button, utilizing the current record as its context. Displayed within a pop-up window, it offers users the ability to customize configuration blocks, enhancing flexibility in the interface. + +![20240412115458](https://static-docs.nocobase.com/20240412115458.png) + + +### Operation Configuration Items + +![20240413104839](https://static-docs.nocobase.com/20240413104839.png) + +- [Edit Button](/handbook/ui/actions/action-settings/edit-button) +- [Linkage Rule](/handbook/ui/actions/action-settings/linkage-rule) +- [Open Mode](/handbook/ui/actions/action-settings/open-mode) +- [Popup Size](/handbook/ui/actions/action-settings/popup-size) diff --git a/docs/fr-FR/handbook/ui/blocks/block-settings/block-delete.md b/docs/fr-FR/handbook/ui/blocks/block-settings/block-delete.md new file mode 100644 index 000000000..06e562297 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-settings/block-delete.md @@ -0,0 +1,7 @@ +# Delete Block + +## Introduction + +Deleting a block from the current page is an irreversible action. + +![20240407175143](https://static-docs.nocobase.com/20240407175143.png) diff --git a/docs/fr-FR/handbook/ui/blocks/block-settings/block-height.md b/docs/fr-FR/handbook/ui/blocks/block-settings/block-height.md new file mode 100644 index 000000000..c9e9ad58f --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-settings/block-height.md @@ -0,0 +1,40 @@ +# Block Height + +## Introduction + +Block height settings in NocoBase accommodate three scenarios: default height, specified height, and full height. This feature is supported by most blocks, with the exception of Gantt chart blocks. For chart blocks, height is controlled through specific parameters. + +![20240602194552](https://static-docs.nocobase.com/20240602194552.png) + +![20240602194609](https://static-docs.nocobase.com/20240602194609.png) + +### Default Height + +Each block type handles default height uniquely. For instance, table and form blocks dynamically adjust their height to fit the content, while kanban blocks default to 70% of the viewport height. + +### Specified Height + +Users have the flexibility to define the overall height of a block's outer frame. The block's internal components then automatically calculate and distribute the available space. + +![20240604172359](https://static-docs.nocobase.com/20240604172359.gif) + +### Full Height + +The full height mode, akin to specified height, automatically determines and allocates block height based on the window's visible area. This approach eliminates page-level scrollbars, confining them to the interior of individual blocks. + +Height handling varies subtly across different block types: + +- Tables: Scrolling occurs within the tbody; +- Forms/Details: The Grid area scrolls, excluding the operations section; +- Lists/Grid Cards: The Grid area scrolls, excluding operations and pagination; +- Kanban: Each column scrolls independently; +- Maps and Calendars: Adapt to full height without scrollbars; +- Iframes/Markdown: The block's outer frame height is fixed, with scrolling inside the block. + +#### Full Height Table Example + +![20240604172439](https://static-docs.nocobase.com/20240604172439.gif) + +#### Full Height Form Example + +![20240604222711](https://static-docs.nocobase.com/20240604222711.gif) diff --git a/docs/fr-FR/handbook/ui/blocks/block-settings/block-layout.md b/docs/fr-FR/handbook/ui/blocks/block-settings/block-layout.md new file mode 100644 index 000000000..bde59d4aa --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-settings/block-layout.md @@ -0,0 +1,27 @@ +# Layout + +:::info{title=Tip} +The version of NocoBase needs to be v1.3.34-beta or above. +::: +## Introduction + +Form components, such as form blocks, detail blocks, and list blocks, support layout settings. The layout options include vertical layout (where labels and input fields are arranged in separate rows) and horizontal layout (where labels and input fields are placed side by side). This flexible layout choice can optimize the user experience based on specific needs, ensuring that information input is both clear and efficient. + +![20241021204953](https://static-docs.nocobase.com/20241021204953.png) + +### Vertical(default) + +Subforms and subform (popup) also support layout configuration, with the default layout set to vertical. + +![20241021205047](https://static-docs.nocobase.com/20241021205047.png) + +### Horizontal + +Horizontal layout places labels and input fields side by side, making better use of space. + + +![20241021205131](https://static-docs.nocobase.com/20241021205131.png) + +The main form uses a vertical layout, while the subform uses a horizontal layout. + +![20241021205203](https://static-docs.nocobase.com/20241021205203.png) diff --git a/docs/fr-FR/handbook/ui/blocks/block-settings/block-template.md b/docs/fr-FR/handbook/ui/blocks/block-settings/block-template.md new file mode 100644 index 000000000..555aa271c --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-settings/block-template.md @@ -0,0 +1,24 @@ +# Save as template + + +## Introduction + +Saving a block as a template allows you to save both the block and its associated data tables. These templates can be centrally managed on the template management page. When adding a block, you can choose to reference or copy a template to quickly create a new block. + +## User Guide + +![20240407175846](https://static-docs.nocobase.com/20240407175846.png) + +You can customize the name of the block template. + +![20240407153407](https://static-docs.nocobase.com/20240407153407.png) + +All block templates can be centrally managed on the block template management page. + +![20240407153550](https://static-docs.nocobase.com/20240407153550.png) + +When adding a block, you can either reference or copy a template to create the block quickly. + +![20240422095346](https://static-docs.nocobase.com/20240422095346.png) + +For more information about block templates, refer to [Block Templates](/handbook/ui/blocks/block-templates). diff --git a/docs/fr-FR/handbook/ui/blocks/block-settings/block-title.md b/docs/fr-FR/handbook/ui/blocks/block-settings/block-title.md new file mode 100644 index 000000000..399eab09b --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-settings/block-title.md @@ -0,0 +1,9 @@ +# Block Title + +## Introduction + +Custom block title. + +![20240407175754](https://static-docs.nocobase.com/20240407175754.png) + +![20240423110346](https://static-docs.nocobase.com/20240423110346.png) diff --git a/docs/fr-FR/handbook/ui/blocks/block-settings/connect-block.md b/docs/fr-FR/handbook/ui/blocks/block-settings/connect-block.md new file mode 100644 index 000000000..2ea054dc7 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-settings/connect-block.md @@ -0,0 +1,36 @@ +# Connecting Data Blocks + +## Introduction + +Connecting data blocks is a powerful feature that enables dynamic filtering linkage between different data components. At its core, this functionality involves establishing a relationship between two collections: a source collection (primary collection) and a target collection (foreign key collection). This connection facilitates seamless data filtering and interaction. + +The options for connecting blocks are versatile, including: +- Data blocks from the same collection on the current page or pop-up window +- Blocks from different collections with foreign key constraints +- Blocks from collections with inheritance relationships + +Users can connect multiple blocks simultaneously, enhancing the flexibility of data interactions. Regardless of the chosen method, the underlying principle remains consistent: the source collection (actively connecting collection) supplies filter parameters to the target collection (connected collection), enabling precise data filtering and display. + +## User Manual + +### Connecting Filter Blocks to Data Blocks + +![Illustration of connecting filter blocks to data blocks](https://static-docs.nocobase.com/20240407180953.png) + +### Connecting Data Blocks to Data Blocks + +#### Linkage Between Data Blocks from the Same collection + +Example: Creating a dynamic linkage between an order collection block and its corresponding order details block. + + + +#### Linkage Between Related Data collection Blocks (Different collection Blocks with Foreign Key Constraints) + +Example: Leveraging the many-to-one relationship between the order collection and customer collection to implement filtering linkage. This setup allows users to query order data for a specific customer by creating a connection between the customer collection block and the order collection block. + + diff --git a/docs/fr-FR/handbook/ui/blocks/block-settings/data-scope.md b/docs/fr-FR/handbook/ui/blocks/block-settings/data-scope.md new file mode 100644 index 000000000..a8fdd596a --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-settings/data-scope.md @@ -0,0 +1,39 @@ +# Data scope + +## Introduction + +Data scope is a powerful feature that allows users to define default filtering conditions for data blocks. This functionality enables users to dynamically adjust the scope of displayed data, tailoring it to their specific needs and enhancing the overall user experience. + +## User Manual + +![20240407180322](https://static-docs.nocobase.com/20240407180322.png) + +Filter fields support selecting fields from the current table, as well as from related tables (up to three levels of relationships). + +![20240422113637](https://static-docs.nocobase.com/20240422113637.png) + +### Operators + +Different field types support various operators. For instance, text fields support operators such as "equals," "not equals," and "contains." Numeric fields allow for operators like "greater than" and "less than," while date fields offer options such as "within a range" or "before a specific date." + +![20240424154003](https://static-docs.nocobase.com/20240424154003.png) + +### Static Values + +Example: Setting an Order "Status" to "Shipped". + + + +### Variable Values + +Example: "Delivery Date" is earlier than "yesterday." + +![20240422090134](https://static-docs.nocobase.com/20240422090134.png) + + + +For more information about variables, refer to [Variables](/handbook/ui/variables). diff --git a/docs/fr-FR/handbook/ui/blocks/block-settings/linkage-rule.md b/docs/fr-FR/handbook/ui/blocks/block-settings/linkage-rule.md new file mode 100644 index 000000000..941aef003 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-settings/linkage-rule.md @@ -0,0 +1,62 @@ +# Linkage Rules + +## Introduction + +Linkage rules allow dynamic adjustment of form field states based on user behavior, such as Visible/Hidden, Required/Not Required, and value assignment. Currently, the following components support configuring linkage rules: [Form Blocks](https://docs.nocobase.com/handbook/ui/blocks/data-blocks/form#linkage-rules), [Details Blocks](https://docs.nocobase.com/handbook/ui/blocks/data-blocks/details#linkage-rules), [Action Buttons](https://docs.nocobase.com/handbook/ui/actions/action-settings/linkage-rule), [Sub Forms](https://docs.nocobase.com/handbook/ui/fields/specific/nester) (requires v1.3.17-beta or above), and [Sub Tables](https://docs.nocobase.com/handbook/ui/fields/specific/sub-table) (requires v1.3.17-beta or above). + + +![20240408100711](https://static-docs.nocobase.com/20240408100711.png) + +![20240408100757](https://static-docs.nocobase.com/20240408100757.png) + +## Usage Instructions + +1. Field Configuration: Ensure all form fields utilized in the rules are properly configured to guarantee rule effectiveness and accuracy. + +2. Conditional Activation: When rule conditions are satisfied (optional), the system automatically executes the specified property modifications. + +3. Multi-Rule Support: Forms can accommodate multiple linkage rules. When several rule conditions are simultaneously met, the system executes the results sequentially, following the order of rule definition. + +4. Rule Management: Enjoy comprehensive control with features for custom naming, sorting, deleting, enabling, disabling, and duplicating rules. + +5. Constant and Variable Integration: Leverage constants or variables in field assignments and condition configurations. For detailed information on variables, consult the [Variables](/handbook/ui/variables) section. + +### Value Assignment + +Illustration: Automatically evaluate and designate customer levels (e.g., A+, A, A-) based on projected annual purchase amounts. + +- Estimated annual purchase exceeding 20,000: Customer classified as A+. + +![20240408102241](https://static-docs.nocobase.com/20240408102241.png) + +- Estimated annual purchase between 10,000 and 20,000 (inclusive): Customer classified as A. + +![20240408102303](https://static-docs.nocobase.com/20240408102303.png) + +- Estimated annual purchase below 10,000: Customer classified as A-. + +![20240408102324](https://static-docs.nocobase.com/20240408102324.png) + +### Field Requirement + +Illustration: Dynamically adjust the requirement status of the product's promotional price based on its promotion status. + +- When "IsPromotion" is active, promotional price becomes mandatory. + +![20240408105031](https://static-docs.nocobase.com/20240408105031.png) + +- When "IsPromotion" is inactive, promotional price becomes optional. + +![20240408105115](https://static-docs.nocobase.com/20240408105115.png) + +### Visibility Control + +Illustration: Manage the visibility of the promotional price input field based on the product's promotion status. + +- When "IsPromotion" is true, the promotional price field is displayed and required. + +![20240408115240](https://static-docs.nocobase.com/20240408115240.png) + +- When "IsPromotion" is false, the promotional price field is hidden and not required. + +![20240408115338](https://static-docs.nocobase.com/20240408115338.png) diff --git a/docs/fr-FR/handbook/ui/blocks/block-settings/loading-mode.md b/docs/fr-FR/handbook/ui/blocks/block-settings/loading-mode.md new file mode 100644 index 000000000..4be07cfe4 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-settings/loading-mode.md @@ -0,0 +1,13 @@ +# Data Loading Mode + +## Introduction + +The default data loading method is "Load all data when filter criteria are empty." The "filter criteria" refers to the values in the **Filter Block**. Another option is "Do not load data when filter criteria are empty." + +### Load all data when filter is empty + +![![20240407170234](httpsstatic-docs.nocobase.com20240407170234.png)](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/![20240407170234](httpsstatic-docs.nocobase.com20240407170234.png).gif) + +### Do not load data when filter is empty + +![20240721160327_rec_](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240721160327_rec_.gif) diff --git a/docs/fr-FR/handbook/ui/blocks/block-settings/sorting-rule.md b/docs/fr-FR/handbook/ui/blocks/block-settings/sorting-rule.md new file mode 100644 index 000000000..b99b9548d --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-settings/sorting-rule.md @@ -0,0 +1,23 @@ +# Sorting Rules + +## Introduction + +Configuring sort rules allows you to define default sorting criteria for data blocks, ensuring that the information within each block is presented in a specific, predetermined order. + +## User Guide + +![20240407192159](https://static-docs.nocobase.com/20240407192159.png) + +![20240421115056](https://static-docs.nocobase.com/20240421115056.png) + +At present, the system only supports sorting based on fields within the current table. + +### Single Sort Rule + +![20240407192248](https://static-docs.nocobase.com/20240407192248.png) + +### Multiple Sort Rules + +This feature is ideal for complex sorting scenarios. For instance, you might want to first organize data by order status, and then arrange items within each status category according to their delivery time. + +![20240407193837](https://static-docs.nocobase.com/20240407193837.png) diff --git a/docs/fr-FR/handbook/ui/blocks/block-templates.md b/docs/fr-FR/handbook/ui/blocks/block-templates.md new file mode 100644 index 000000000..cf06decb4 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/block-templates.md @@ -0,0 +1,26 @@ +# Block Template + + + +## Introduction + +Save a data block as a template, enabling you to effortlessly copy or reference this template when adding new blocks in the future. For instance, if a form for a data table is used both for adding new records and editing existing ones, you can save this form as a template and reference it in both the data entry and editing interfaces. + +## How to Add and Use a Template? + +1. Save as block template. + +![](https://static-docs.nocobase.com/b7718cea8784587d53524ade3c5b0a82.png) + +2. When adding a block, choose **Reference template** or **Duplicate template**. + +![](https://static-docs.nocobase.com/135df7344e0f3080199e4bb1071c2fa6.png) + +## Copying vs. Referencing: What's the Difference? + +Copying creates an entirely new block based on the block template, allowing for adjustments without affecting the original template. Referencing, on the other hand, directly uses the block template. Any changes made to a referenced block will modify the template itself, affecting all blocks that reference it. + +## Important Notes + +- Templates created with relationship blocks can only be used to create relationship blocks. +- Templates created with non-relationship blocks can only be used to create non-relationship blocks. diff --git a/docs/fr-FR/handbook/ui/blocks/data-blocks/details.md b/docs/fr-FR/handbook/ui/blocks/data-blocks/details.md new file mode 100644 index 000000000..6349e98ad --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/data-blocks/details.md @@ -0,0 +1,55 @@ +# Details Block + +## Introduction + +The details block is used to display the values of each field for each data item in detail. It supports flexible field layout and has built-in various actions. + +## Adding Blocks + + + +## Block Settings + +![20240417122949](https://static-docs.nocobase.com/20240417122949.png) + +### Set Data Scope + +Example: Default filtering of delivered orders + +![20240417122910](https://static-docs.nocobase.com/20240417122910.png) + +For more details, please refer to [Setting Data Scope](/handbook/ui/blocks/block-settings/data-scope) + +### Set Default Sorting Rule + +![20240417123300](https://static-docs.nocobase.com/20240417123300.png) + +For more details, please refer to [Sorting Rules](/handbook/ui/blocks/block-settings/sorting-rule) + +- [Set Data Loading Method](/handbook/ui/blocks/block-settings/loading-mode) +- [Save as Block Template](/handbook/ui/blocks/block-settings/block-template) + +## Configure Fields + +### The Current Collecton Fields + +![20240417213735](https://static-docs.nocobase.com/20240417213735.png) + +### The Association Fields + +![20240417214006](https://static-docs.nocobase.com/20240417214006.png) + +For more details on detail field configuration, please refer to [Detail Fields](/handbook/ui/fields/generic/detail-form-item) + +## Configure Actions + +![20240417214433](https://static-docs.nocobase.com/20240417214433.png) + +- [Edit](/handbook/ui/actions/types/edit) +- [Delete](/handbook/ui/actions/types/delete) +- [Pop-up](/handbook/ui/actions/types/pop-up) +- [Update Record](/handbook/ui/actions/types/update-record) +- [Custom Request](/handbook/action-custom-request) +- [Trigger workflow](/handbook/workflow/manual/triggers/cutom-action-trigger) diff --git a/docs/fr-FR/handbook/ui/blocks/data-blocks/form.md b/docs/fr-FR/handbook/ui/blocks/data-blocks/form.md new file mode 100644 index 000000000..4c2078b0d --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/data-blocks/form.md @@ -0,0 +1,102 @@ +# Form Block + +## Introduction + +The form block is an essential block for building data input and editing interfaces. It is highly customizable and uses corresponding components based on the data model to display the required fields. Through linkage rules, the form block can dynamically display fields. Additionally, it can be combined with workflows to achieve automated process triggering and data processing, further enhancing work efficiency or implementing logical orchestration. + +## Adding Blocks + + + +## Block Settings + +![20240416220148](https://static-docs.nocobase.com/20240416220148.png) + +### Linkage Rules + +Control form field behavior through linkage rules. + +![20240416220254](https://static-docs.nocobase.com/20240416220254.png) + +For more information, refer to [Linkage Rules](/handbook/ui/blocks/block-settings/linkage-rule). + +### Form Data Templates (Supports Form for Adding New Data Only) + +The purpose of the form data templates is to simplify the data entry process and improve efficiency. By filtering out a single piece or a group of records as a template from the data range, the selected target data template will be populated as the default values in the form. + +![20240408143719](https://static-docs.nocobase.com/20240408143719.png) + +![20240424143911](https://static-docs.nocobase.com/20240424143911.png) + +1. Filter out a single piece or a group of records as template data. +2. Select the title field to identify the template data. +3. Check the template fields, and the selected fields will be automatically populated into the form. + +#### Synchronize From Form Fields + +- Automatically parse the configured fields in the current form block as template fields. +- If there are subsequent modifications to the form block fields (such as adjustments to association field components), you can reopen the template configuration and click the sync form button to ensure consistency between the form and the template. + +#### The following fields' data will be filtered out for the selected data template record: +- Primary Key +- Foreign Key +- Fields disallowing duplicates +- Sort fields +- Sequence fields +- Password +- Created by +- Created at +- Last updated by +- Last updated at + +#### For Association Fields +- Regular fields and hasOne and hasMany relationship fields are copied. +- belongsTo and belongsToMany relationship fields are referenced, and references may become copies. For example, after changing from select to sub-form, the relationship changes from reference to copy (after becoming a copy, all fields are optional). + +#### Example Scenarios + +Scenario Description: An e-commerce platform needs to frequently add new products, and these new products are similar or identical to existing products in many attributes. + +Solution: Select an existing product as a template and use its attribute information as the form data template. When creating a new product, users can choose to apply this template, thus quickly copying the attribute information of the template product to the new product, improving the efficiency of entering new products. + +- Create a product promotion template + +![20240408145855](https://static-docs.nocobase.com/20240408145855.png) + +- Create promotional products quickly + + + +- [Edit Block Title](/handbook/ui/blocks/block-settings/block-title) +- [Save as Block Template](/handbook/ui/blocks/block-settings/block-template) + +## Configure Fields + +### Fields in Current Collection + +![20240416230739](https://static-docs.nocobase.com/20240416230739.png) + +### Fields in Related Collections + +Fields in related tables are read-only in the form and are typically used in conjunction with relationship fields to display multiple field values of related data. + +![20240416230811](https://static-docs.nocobase.com/20240416230811.png) + + + +Form field configuration options can be found in [Form Fields](/handbook/ui/fields/generic/form-item). + +## Configure Actions + +![20240417115249](https://static-docs.nocobase.com/20240417115249.png) + +- [Submit](/handbook/ui/actions/types/submit) +- [Save Data](/handbook/ui/actions/types/save-record) +- [Custom Request](/handbook/action-custom-request) +- [Trigger workflow](/handbook/workflow/manual/triggers/cutom-action-trigger) diff --git a/docs/fr-FR/handbook/ui/blocks/data-blocks/grid-card.md b/docs/fr-FR/handbook/ui/blocks/data-blocks/grid-card.md new file mode 100644 index 000000000..eb5deaa63 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/data-blocks/grid-card.md @@ -0,0 +1,88 @@ +# Grid Cards + +## Introduction + +The Grid Card block offers a concise and visually appealing way to display summary information of data records. Designed for flexibility, it allows you to configure the number of columns based on screen size, ensuring a seamless user experience across all devices. + +## Adding Blocks + + + +## Block Settings + +![20240419220708](https://static-docs.nocobase.com/20240419220708.png) + +### Data Scope + + + +For a detailed guide, see [Setting the Data Scope](/handbook/ui/blocks/block-settings/data-scope). + +### Configuring the Number of Columns per Row + +![20240408160228](https://static-docs.nocobase.com/20240408160228.png) + +You can adjust the number of columns to fit different screen sizes, ensuring optimal display. + +![20240408160844](https://static-docs.nocobase.com/20240408160844.png) + +### Configuring the Data Loading Method + +Example: Connecting data blocks and setting the appropriate data loading method. + +The Orders table and Products table have a many-to-many relationship. The Orders Table block and Products Grid Card block can be linked to enable data filtering. In this setup, the grid block’s data loading method is configured to load "After Filtering Data." + + + +### Setting Block Height + +Example: Configure the Orders Grid Card block to display in "Full Height" mode for an expansive view. + +![20240604232619](https://static-docs.nocobase.com/20240604232619.gif) + +For more details, refer to [Block Height](/handbook/ui/blocks/block-settings/block-height). + +- [Setting Sorting Rules](/handbook/ui/blocks/block-settings/sorting-rule) +- [Saving as a Block Template](/handbook/ui/blocks/block-settings/block-template) + +## Configuring Fields + +### Fields of the Current Table + +![20240418123118](https://static-docs.nocobase.com/20240418123118.png) + +### Fields of Related Tables + +![20240418123147](https://static-docs.nocobase.com/20240418123147.png) + +For a comprehensive guide to field configuration options for the Grid Card block, see [Detail Fields](/handbook/ui/fields/generic/detail-form-item). + +## Configuring Actions + +### Global Actions + +![20240418122905](https://static-docs.nocobase.com/20240418122905.png) + +- [Filter](/handbook/ui/actions/types/filter) +- [Add](/handbook/ui/actions/types/add-new) +- [Delete](/handbook/ui/actions/types/delete) +- [Refresh](/handbook/ui/actions/types/refresh) +- [Import](/handbook/action-import) +- [Export](/handbook/action-export) + +### Row Actions + +![20240419222251](https://static-docs.nocobase.com/20240419222251.png) + +- [Edit](/handbook/ui/actions/types/edit) +- [Delete](/handbook/ui/actions/types/delete) +- [Pop-up](/handbook/ui/actions/types/pop-up) +- [Update Record](/handbook/ui/actions/types/update-record) +- [Custom Request](/handbook/action-custom-request) +- [Trigger Workflow](/handbook/workflow/manual/triggers/custom-action) diff --git a/docs/fr-FR/handbook/ui/blocks/data-blocks/list.md b/docs/fr-FR/handbook/ui/blocks/data-blocks/list.md new file mode 100644 index 000000000..9598f9c22 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/data-blocks/list.md @@ -0,0 +1,87 @@ +# List Block + +## Introduction + +The list block displays data in a list format, suitable for scenarios such as task lists, news updates, product information, and other data presentation needs. + +## Adding a Block + + + +## Block Configuration Options + +![20240417224539](https://static-docs.nocobase.com/20240417224539.png) + +### Setting Data Scope + +As shown in the image: The default filter selects orders with a "Refunded" status. + +![20240417224701](https://static-docs.nocobase.com/20240417224701.png) + +For more details, refer to [Setting Data Scope](/handbook/ui/blocks/block-settings/data-scope). + +### Setting Sorting Rules + +As shown in the image: Orders are sorted in descending order by order amount. + +![20240417225302](https://static-docs.nocobase.com/20240417225302.png) + +For more details, refer to [Setting Sorting Rules](/handbook/ui/blocks/block-settings/sorting-rule). + +### Setting Data Loading Method + +Typically used in conjunction with the filter block to load data only when filtered. + + + +For more details, refer to [Setting Data Loading Method](/handbook/ui/blocks/block-settings/loading-mode). + +### Setting Block Height + +Example: Set the height of the order list block to "Full Height" mode. + +![20240604233102](https://static-docs.nocobase.com/20240604233102.gif) + +For more details, refer to [Block Height](/handbook/ui/blocks/block-settings/block-height). + +- [Edit Block Title](/handbook/ui/blocks/block-settings/block-title) +- [Save as Block Template](/handbook/ui/blocks/block-settings/block-template) + +## Configuring Fields + +### Main Table Fields + +![20240417230027](https://static-docs.nocobase.com/20240417230027.png) + +### Related Table Fields + +![20240417230115](https://static-docs.nocobase.com/20240417230115.png) + +For more details on configuring list fields, refer to [Detail Fields](/handbook/ui/fields/generic/detail-form-item). + +## Configuring Actions + +### Global Actions + +![20240421115811](https://static-docs.nocobase.com/20240421115811.png) + +- [Filter](/handbook/ui/actions/types/filter) +- [Add New](/handbook/ui/actions/types/add-new) +- [Refresh](/handbook/ui/actions/types/refresh) +- [Import](/handbook/action-import) +- [Export](/handbook/action-export) + +### Row Actions + +![20240418114424](https://static-docs.nocobase.com/20240418114424.png) + +- [View](/handbook/ui/actions/types/view) +- [Edit](/handbook/ui/actions/types/edit) +- [Delete](/handbook/ui/actions/types/delete) +- [Pop-Up](/handbook/ui/actions/types/pop-up) +- [Update Record](/handbook/ui/actions/types/update-record) +- [Custom Request](/handbook/action-custom-request) diff --git a/docs/fr-FR/handbook/ui/blocks/data-blocks/table.md b/docs/fr-FR/handbook/ui/blocks/data-blocks/table.md new file mode 100644 index 000000000..cfbd0be5b --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/data-blocks/table.md @@ -0,0 +1,91 @@ +# Table Block + +## Introduction + +The table block is one of the core data blocks built into NocoBase, displaying and managing structured data in table form. It features flexible configuration options for customizing table columns, column widths, sorting rules, data scope, and includes various built-in actions for configuration: filter, add new, duplicate, edit, delete, etc. + +## Adding Blocks + + + +## Block Settings + +![20240415215319](https://static-docs.nocobase.com/20240415215319.png) + +### Data Scope + +Example: Default filter for invoices with the "Shipped" status. + +![20240415215404](https://static-docs.nocobase.com/20240415215404.png) + +For more information, refer to [Setting Data Scope](/handbook/ui/blocks/block-settings/data-scope). + +### Setting Sorting Rule + +Example: Display invoices in reverse order by shipping date. + +![20240415215509](https://static-docs.nocobase.com/20240415215509.png) + +For more information, refer to [Setting Sorting Rule](/handbook/ui/blocks/block-settings/sorting-rule). + +### Connecting Data Blocks + +Example: Connect the order table block with the order details block to achieve filter linkage. + + + +For more information, refer to [Connecting Data Blocks](/handbook/ui/blocks/block-settings/connect-block). + +- [Edit Block Title](/handbook/ui/blocks/block-settings/block-title) +- [Set Data Loading Mode](/handbook/ui/blocks/block-settings/loading-mode) +- [Save as Block Template](/handbook/ui/blocks/block-settings/block-template) + +## Configure Fields + +### Fields in Current Collection + +![20240415223714](https://static-docs.nocobase.com/20240415223714.png) + +### Fields in Related Collections + +![20240415223746](https://static-docs.nocobase.com/20240415223746.png) + +### Display Inherited Table Fields (Parent Table Fields) + +Example: Lease order table inherits from the order table. + +![20240415224242](https://static-docs.nocobase.com/20240415224242.png) + +Configuration options for table column fields can be found in [Table Column Fields](/handbook/ui/fields/generic/table-column). + +## Configure Actions + +### Global Actions + +![20240415225525](https://static-docs.nocobase.com/20240415225525.png) + +- [Filter](/handbook/ui/actions/types/filter) +- [Add](/handbook/ui/actions/types/add-new) +- [Delete](/handbook/ui/actions/types/delete) +- [Refresh](/handbook/ui/actions/types/refresh) +- [Import](/handbook/action-import) +- [Export](/handbook/action-export) +- [Add record](/handbook/action-add-record) +- [Bulk Update](/handbook/action-bulk-update) +- [Bulk Edit](/handbook/action-bulk-edit) + +### Row Actions + +![20240415225657](https://static-docs.nocobase.com/20240415225657.png) + +- [View](/handbook/ui/actions/types/view) +- [Edit](/handbook/ui/actions/types/edit) +- [Duplicate](/handbook/action-duplicate) +- [Delete](/handbook/ui/actions/types/delete) +- [Popup](/handbook/ui/actions/types/pop-up) +- [Update Record](/handbook/ui/actions/types/update-record) +- [Custom Request](/handbook/action-custom-request) diff --git a/docs/fr-FR/handbook/ui/blocks/filter-blocks/collapse.md b/docs/fr-FR/handbook/ui/blocks/filter-blocks/collapse.md new file mode 100644 index 000000000..c93ada1a9 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/filter-blocks/collapse.md @@ -0,0 +1,38 @@ +# Collapse Filter Block + +## Introduction + +The Collapse filtering block needs to be used in connection with the data block to provide filtering capabilities for the data block. It supports selecting association fields and option fields as filtering fields, and displays them in a collapsible panel effect. + +## Adding Block + +![20240408212222](https://static-docs.nocobase.com/20240408212222.png) + +Example: Configure the order collapse block and order table block to achieve filter linkage. + + + +## Block Settings + +![20240421173427](https://static-docs.nocobase.com/20240421173427.png) + +### Connecting Data Blocks + +Example: Connect the same data table block in the pop-up window to achieve filter linkage. + + + +For more content, refer to [Connecting Data Blocks](/handbook/ui/blocks/block-settings/connect-block) + +- [Edit Block Title](/handbook/ui/blocks/block-settings/block-title) +- [Save as Block Template](/handbook/ui/blocks/block-settings/block-template) + +## Configuring Fields + +Only relational fields and option fields are supported as filter fields. + +![20240408212301](https://static-docs.nocobase.com/20240408212301.png) diff --git a/docs/fr-FR/handbook/ui/blocks/filter-blocks/form.md b/docs/fr-FR/handbook/ui/blocks/filter-blocks/form.md new file mode 100644 index 000000000..aaa7e6837 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/filter-blocks/form.md @@ -0,0 +1,60 @@ +# Form Filter Block + +## Introduction + +The Form filter block can be connected with the data block. Once connected, it can provide filtering capabilities. + +## Adding Block + + + +## Block Settings + +![20240421172115](https://static-docs.nocobase.com/20240421172115.png) + +### Connect to Data Block + +Example: The Form filter block connects to the details data block to implement linkage. + + + +For more content, refer to [Connect to Data Block](/handbook/ui/blocks/block-settings/connect-block) + +- [Edit Block Title](/handbook/ui/blocks/block-settings/block-title) +- [Linkage Rules](/handbook/ui/blocks/block-settings/linkage-rule) +- [Save as Block Template](/handbook/ui/blocks/block-settings/block-template) + +## Field Configuration + +### Fields in This Collection + +![20240421171135](https://static-docs.nocobase.com/20240421171135.png) + +### Fields in Related Collections +> In version v1.3.14-beta and above, it supports configuring "many-to-many" and "one-to-many" relationship fields. + +Supports using the fields of the related collections as filtering conditions + +Example: The order collection has a many-to-one relationship field "Customer", filter the orders by customer name and phone number as filtering conditions + + + +### Setting Default Values for Fields + +Like a normal [Form Block](/handbook/ui/blocks/data-blocks/form), you can set default values for normal fields and relationship fields. **When a field has a default value, a filtering operation will be automatically triggered at the first rendering of the page, so that the data block connected with it can display the matching data.** + +## Configuration Operations + +![Filter Operations](https://static-docs.nocobase.com/20240421171839.png) + +### Reset button + +By default, clicking the "Reset" button will preserve the default values of the fields. If you want to clear the default values of the fields, you can open the configuration options and enable the "Clear Default Values" option. + +![20240716183611](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240716183611.png) diff --git a/docs/fr-FR/handbook/ui/blocks/index.md b/docs/fr-FR/handbook/ui/blocks/index.md new file mode 100644 index 000000000..8b3b25082 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/index.md @@ -0,0 +1,56 @@ +# Block + +Blocks are carriers of data and content. They can be placed in a Page, a Modal dialog, or a Drawer, and multiple blocks can be freely dragged and arranged. + +## Block Types + +![Block Types](https://static-docs.nocobase.com/f71af45b5cd914ea0558f760ddbbba58.png) + +- Data Blocks: Used to display data from the data sources on the interface. +- Filter Blocks: Used to use data from the data sources as filtering criteria for other data blocks. +- Other Blocks: Used to contain specific or independent content such as workflow tasks, audit logs, Markdown, etc. + +## Adding Blocks + +Blocks can be placed in a Page, Modal dialog, or Drawer. + +### Blocks in a Page + +Currently, the types of blocks in a page include: Data Blocks, Filter Blocks, and Other Blocks. + +![](https://static-docs.nocobase.com/dad0a394d33dd26f31c3202a76bb0153.png) + +### Blocks in a Popup (Modal or Drawer) + +Popups come in two forms: Modals and Drawers, and, like pages, can also have blocks added to them. The difference is that blocks in popups are generally used for adding, editing, or viewing individual records. The types of blocks include Data Blocks and Other Blocks. + +![2024-04-10_11-27-04](https://static-docs.nocobase.com/2024-04-10_11-27-04.png) + +## Block Designer + +Every block has three small icons in the upper right corner, from left to right they are: + +1. Drag Layout +2. Quick Add Block +3. Block Configuration + +![](https://static-docs.nocobase.com/b488f3013532a246df59b89c0688a58f.png) + +Simple blocks have all their configuration items concentrated in "Block Configuration," such as Markdown. + +![](https://static-docs.nocobase.com/f37e277863068b2661f66d4020af806a.png) + +Complex data type blocks will also provide separate embedded "Configure Fields" and "Configure Actions". + +![](https://static-docs.nocobase.com/71b550da637d23145a5f62d48ee8521b.png) + +Besides, there is also the potential for more nested possibilities, such as Chart Blocks. + +![](https://static-docs.nocobase.com/07588190b3f41ae3060e71d8b76b4447.png) + +## Block Layout + +Multiple blocks can adjust the layout by dragging. + +![](https://static-docs.nocobase.com/f6692295ac0917f3babce9a60ce80879.gif) + diff --git a/docs/fr-FR/handbook/ui/blocks/other-blocks/markdown.md b/docs/fr-FR/handbook/ui/blocks/other-blocks/markdown.md new file mode 100644 index 000000000..b63198993 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/other-blocks/markdown.md @@ -0,0 +1,111 @@ +# Markdown Block + +## Introduction + +Markdown blocks can be used without binding to a data source. They are defined using Markdown syntax and are suitable for displaying formatted text content. + +## Adding Blocks + +Markdown blocks can be added within pages or pop-ups. + +![20240612205004](https://static-docs.nocobase.com/20240612205004.png) + +Inline Markdown blocks can also be added within form blocks and details blocks. + +![20240612205215](https://static-docs.nocobase.com/20240612205215.png) + +## Template engine + +### string template + +Use {{xxx}} for interpolation. + +![20240817175031](https://static-docs.nocobase.com/20240817175031.png) + +### Handlebars + +Support using rich syntax such as conditions and loops to dynamically generate HTML content. + +![20240817175355](https://static-docs.nocobase.com/20240817175355.png) + +![20240817175501](https://static-docs.nocobase.com/20240817175501.png) + +For more information, refer to [Handlebars template](/handbook/template-handlebars) + +## Using Variables + +Variables supported in Markdown vary depending on the location. + +Markdown on the page supports common system variables, such as the current user, current role, date variables, etc. + +![20240612205857](https://static-docs.nocobase.com/20240612205857.png) + +Markdown in block row operation popups (or subpages) supports more data context variables, such as the current record, current popup record, etc. + +![20240612210333](https://static-docs.nocobase.com/20240612210333.png) + +### Association data in variables + +For example, order/shipment (one-to-one). + +Use the 'current popup record' variable in the detail operation popup's Markdown block to display the shipping number of the current order. + +#### String templates will automatically handle association data (by automatically loading the required association data) + +![20241210165519](https://static-docs.nocobase.com/20241210165519.png) + +![20241210165541](https://static-docs.nocobase.com/20241210165541.png) + +#### Currently, Handlebars does not support preloading association data. Users need to explicitly configure the corresponding association fields in the data block to retrieve the relevant data during rendering. + +![20241210165625](https://static-docs.nocobase.com/20241210165625.png) + +After configuring the 'Shipment' association field in the order table block, the Markdown block in the detail operation (using Handlebars) will be able to access and render the association data. + +![20241210165655](https://static-docs.nocobase.com/20241210165655.png) + +### Syntax rules + +In addition to the difference in association data preloading, there are also syntax rule differences between the two templates. For example, when using variables with a to-many association, the retrieved data is usually an array. The two templates handle array-type data differently. + +For example, order/product (many-to-many) + +Use the 'current popup record' variable in the detail operation popup's Markdown block to display the names of the products associated with the current order (multiple items). + +#### String templates display arrays by separating the elements with commas (',') + +![20241210170508](https://static-docs.nocobase.com/20241210170508.png) + +![20241210170545](https://static-docs.nocobase.com/20241210170545.png) + +#### Handlebars templates use #each to iterate over array data + +![20241210205357](https://static-docs.nocobase.com/20241210205357.png) + +The related data to be used must be configured in the data block + +![20241210170814](https://static-docs.nocobase.com/20241210170814.png) + +```javascript + +
      + {{#each $nPopupRecord.products }} +
    • {{this.product_name}}
    • + {{/each}} +
    +``` + +For more introductions to variables, check out the [Edit UI / Variables](/handbook/ui/variables) section. + +## QR Codes + +Markdown also supports the configuration of QR codes, which can be used in combination with variables. + +```html + +``` + +## RoadMap + +- Planned or in progress + - Handlebars supports association data preloading. \ No newline at end of file diff --git a/docs/fr-FR/handbook/ui/blocks/other-blocks/workflow-approval.md b/docs/fr-FR/handbook/ui/blocks/other-blocks/workflow-approval.md new file mode 100644 index 000000000..a1e941088 --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/other-blocks/workflow-approval.md @@ -0,0 +1,3 @@ +# Workflow: Approval blocks + + diff --git a/docs/fr-FR/handbook/ui/blocks/other-blocks/workflow-manual-todos.md b/docs/fr-FR/handbook/ui/blocks/other-blocks/workflow-manual-todos.md new file mode 100644 index 000000000..551b416ad --- /dev/null +++ b/docs/fr-FR/handbook/ui/blocks/other-blocks/workflow-manual-todos.md @@ -0,0 +1,3 @@ +# Workflow: Manual todos block + + diff --git a/docs/fr-FR/handbook/ui/blocks/static/BEmxbD2SgoUTDexnYjzcmh7Knhg.png b/docs/fr-FR/handbook/ui/blocks/static/BEmxbD2SgoUTDexnYjzcmh7Knhg.png new file mode 100644 index 000000000..a2479759d Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/BEmxbD2SgoUTDexnYjzcmh7Knhg.png differ diff --git a/docs/fr-FR/handbook/ui/blocks/static/EicAbMa7Jo2MD9x8FSfcpgTGnHc.png b/docs/fr-FR/handbook/ui/blocks/static/EicAbMa7Jo2MD9x8FSfcpgTGnHc.png new file mode 100644 index 000000000..45698aa22 Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/EicAbMa7Jo2MD9x8FSfcpgTGnHc.png differ diff --git a/docs/fr-FR/handbook/ui/blocks/static/ImutbF0YDoWldOxrPilcwQFHnSe.png b/docs/fr-FR/handbook/ui/blocks/static/ImutbF0YDoWldOxrPilcwQFHnSe.png new file mode 100644 index 000000000..32ab59bd3 Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/ImutbF0YDoWldOxrPilcwQFHnSe.png differ diff --git a/docs/fr-FR/handbook/ui/blocks/static/JNiLb7rksoY07ox092ycaarenGd.png b/docs/fr-FR/handbook/ui/blocks/static/JNiLb7rksoY07ox092ycaarenGd.png new file mode 100644 index 000000000..d5b5018b2 Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/JNiLb7rksoY07ox092ycaarenGd.png differ diff --git a/docs/fr-FR/handbook/ui/blocks/static/L0aJb1V9DoETnNxrr1gcz0g0nDb.png b/docs/fr-FR/handbook/ui/blocks/static/L0aJb1V9DoETnNxrr1gcz0g0nDb.png new file mode 100644 index 000000000..cc7603c71 Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/L0aJb1V9DoETnNxrr1gcz0g0nDb.png differ diff --git a/docs/fr-FR/handbook/ui/blocks/static/OpBcbf9UlooZ5UxZDwwcHZi8nWf.png b/docs/fr-FR/handbook/ui/blocks/static/OpBcbf9UlooZ5UxZDwwcHZi8nWf.png new file mode 100644 index 000000000..717d3ea48 Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/OpBcbf9UlooZ5UxZDwwcHZi8nWf.png differ diff --git a/docs/fr-FR/handbook/ui/blocks/static/PSD8bf1fzoZkIUxJW7lc4XuGnee.png b/docs/fr-FR/handbook/ui/blocks/static/PSD8bf1fzoZkIUxJW7lc4XuGnee.png new file mode 100644 index 000000000..b8aeaf4f3 Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/PSD8bf1fzoZkIUxJW7lc4XuGnee.png differ diff --git a/docs/fr-FR/handbook/ui/blocks/static/Tvjfb4qr4osyzxxPKdRcfn1knsd.png b/docs/fr-FR/handbook/ui/blocks/static/Tvjfb4qr4osyzxxPKdRcfn1knsd.png new file mode 100644 index 000000000..77c986e9d Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/Tvjfb4qr4osyzxxPKdRcfn1knsd.png differ diff --git a/docs/fr-FR/handbook/ui/blocks/static/Uo6ubaMwFo5bi1xVMU5cshlTn1g.png b/docs/fr-FR/handbook/ui/blocks/static/Uo6ubaMwFo5bi1xVMU5cshlTn1g.png new file mode 100644 index 000000000..4abc2a9a8 Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/Uo6ubaMwFo5bi1xVMU5cshlTn1g.png differ diff --git a/docs/fr-FR/handbook/ui/blocks/static/XjdHbvC9ZotdQAx8GJoczwoancc.gif b/docs/fr-FR/handbook/ui/blocks/static/XjdHbvC9ZotdQAx8GJoczwoancc.gif new file mode 100644 index 000000000..a43b0c671 Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/XjdHbvC9ZotdQAx8GJoczwoancc.gif differ diff --git a/docs/fr-FR/handbook/ui/blocks/static/image.png b/docs/fr-FR/handbook/ui/blocks/static/image.png new file mode 100644 index 000000000..9f9954a8a Binary files /dev/null and b/docs/fr-FR/handbook/ui/blocks/static/image.png differ diff --git a/docs/fr-FR/handbook/ui/fields/association-field.md b/docs/fr-FR/handbook/ui/fields/association-field.md new file mode 100644 index 000000000..2f4ce1d34 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/association-field.md @@ -0,0 +1,89 @@ +# Association Field Component + +## Introduction + +NocoBase's association field components are designed to help users better display and handle associated data. Regardless of the type of relationship, these components are flexible and universal. Users can select and configure these components according to specific needs. + +### Dropdown Selector + +All association fields whose target collection is not a file collection, the default component in the edit state is a drop-down selector. The drop-down option displays the value of the title field, which is suitable for quickly selecting associated data by displaying a key field information. + +![20240429205659](https://static-docs.nocobase.com/20240429205659.png) + +For more information, refer to [Dropdown Selector](/handbook/ui/fields/specific/select) + +### Record Picker + +The record picker presents data in the form of a pop-up window. Users can configure relationship fields (including relationship's relationship fields) in the record selector, allowing for more accurate selection of associated data. + +![20240429210824](https://static-docs.nocobase.com/20240429210824.png) + +For more information, refer to [Record Picker](/handbook/ui/fields/specific/picker) + +### Cascade Selector + +The cascade selector is suitable for relationship fields where the target collection is a tree collection. It allows users to select data according to the hierarchical structure of the tree collection data. It is applicable to scenarios such as province-city-district, industry classification, product attributes, and other cascade selection scenarios. + +![20240429213256](https://static-docs.nocobase.com/20240429213256.png) + +For more information, refer to [Cascade Selector](/handbook/ui/fields/specific/cascade-select) + +### Sub-Form + +When dealing with more complex relationship data, using a dropdown selector or data selector can be inconvenient. In this case, users need to frequently open pop-up windows. For this scenario, a sub-form can be used. Users can directly maintain relationship fields on the current page or current pop-up, without repeatedly opening new pop-ups, making the operation process smoother. Multi-level relationships are presented in the form of nested forms. + +![20240429215953](https://static-docs.nocobase.com/20240429215953.png) + +For more information, refer to [Sub-Form](/handbook/ui/fields/specific/nester) + +### Sub-Form (Pop-up) + +When the relationship level is deep and there are many data fields, the sub-form layout may appear lengthy, making it difficult to effectively present the primary and secondary relationship of the form. For this scenario, you can use a sub-form (pop-up). Users can move some non-key or infrequently used relationship fields from the main form to an independent pop-up for filling out, making the main form more concise and clear. + +The Sub-Form (Pop-up) not only simplifies the form layout, but also solves the problem of not being able to directly fill in relationship field data in the sub-table. + +![20240429222237](https://static-docs.nocobase.com/20240429222237.gif) + +For more information, refer to [Sub-Form (Pop-up)](/handbook/ui/fields/specific/popover-nester) + +### Sub-Table + +The sub-table presents one-to-many or many-to-many relationship records in the form of a table. It provides a clear, structured way to display and manage associated data, supporting the creation of new data in batches or the selection of existing data for association. + +![20240429222505](https://static-docs.nocobase.com/20240429222505.png) + +For more information, refer to [Sub-Table](/handbook/ui/fields/specific/sub-table) + +### Sub-Detail + +The sub-detail are the corresponding components of the sub-form in reading mode, and the multi-level relational data is displayed in a nested form. + + +![20240822223651](https://static-docs.nocobase.com/20240822223651.png) + +For more information, refer to [Sub-Detail](/handbook/ui/fields/specific/sub-detail) + + +### File Manager + +The file manager is a relationship field component specifically for dealing with relationship target collections as file collections. + +![20240429222753](https://static-docs.nocobase.com/20240429222753.png) + +For more information, refer to [File Manager](/handbook/ui/fields/specific/file-manager) + +### Title + +The title component is a relationship field component used in reading mode, displaying key information of associated data through the configuration of the title field. + +![20240429223646](https://static-docs.nocobase.com/20240429223646.png) + +For more information, refer to [Title](/handbook/ui/fields/specific/title) + +### Tag + +The tag component is a relationship field component used in reading mode. Using the tag component in data presentation can better classify and identify relationship data. It needs to configure the title field and color field (selected from the target table fields). + +![20240429225054](https://static-docs.nocobase.com/20240429225054.png) + +For more information, refer to [Tag](/handbook/ui/fields/specific/tag) \ No newline at end of file diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/data-scope.md b/docs/fr-FR/handbook/ui/fields/field-settings/data-scope.md new file mode 100644 index 000000000..1e00fc5e9 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/data-scope.md @@ -0,0 +1,35 @@ +# Set The Data Scope + +## Introduction + +The data scope for relationship fields is similar to the data scope setting for blocks, allowing you to set default filtering criteria for relational data. + +## Instructions + +![20240422153711](https://static-docs.nocobase.com/20240422153711.png) + +### Static Value + +Example: Only products currently for sale can be selected as related items. + +![20240422155953](https://static-docs.nocobase.com/20240422155953.png) + +### Variable Value + +Example: Only products with a production date earlier than last month can be selected as related items. + +![20240422163640](https://static-docs.nocobase.com/20240422163640.png) + +For more information on variables, refer to [Variables](/handbook/ui/variables). + +### Relationship Field Linkage + +Relationship fields can be linked by setting the data scope. + +Example: In the order form, there are many-to-many relationship fields "Products" and a many-to-one relationship field "Customers." The product table has a many-to-many relationship field "Customers." In the order form block, the selectable products are those associated with the customer selected in the current form. + +![20240422154145](https://static-docs.nocobase.com/20240422154145.png) + + diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/default-value.md b/docs/fr-FR/handbook/ui/fields/field-settings/default-value.md new file mode 100644 index 000000000..958df8cb1 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/default-value.md @@ -0,0 +1,126 @@ +# Default Value + +## Introduction + +Default values are the initial values for fields in a new state. You can set default values when configuring fields in a data table, or you can specify default values for fields in a new form block. These values can be constants or variables. + +## Where Can Default Values Be Configured? + +### Data Table Fields + +![20240411095933](https://static-docs.nocobase.com/20240411095933.png) + +### Fields in New Forms + +Most fields in new forms support setting default values. + +![20240411100030](https://static-docs.nocobase.com/20240411100030.png) + +### Adding Subforms + +Whether adding subforms in new or edit forms, the added sub-data will have default values. + +Subform "Add new" + +![20240411100341](https://static-docs.nocobase.com/20240411100341.png) + +Subtable "Add new" + +![20240411100424](https://static-docs.nocobase.com/20240411100424.png) + +![20240411100634](https://static-docs.nocobase.com/20240411100634.png) + +When editing existing data, if the data is empty, it will not be filled with default values; only newly added data will be filled with default values and will not be saved. + +![20240411100729](https://static-docs.nocobase.com/20240411100729.png) + +### Default Values for Relationship Data + +Default values are only available for "many-to-one" and "many-to-many" relationship types when using selector components (Select, RecordPicker). + +![20240411101025](https://static-docs.nocobase.com/20240411101025.png) + +## Default Value Variables + +### What Variables Are Available? + +- Date variables; +- Current user; +- Current record (the concept only applies to existing data); +- Current form (ideally, only fields in the form are listed); +- Current object (concept for each row of data in a subform); +- Form selected records (currently limited to the "Table Block + Add Record Form" combination); + +For more information on variables, refer to [Variables](/handbook/ui/variables). + +### Field Default Value Variables + +There are two types: non-relational field variables and relational field variables. + +#### Relational Field Default Value Variables + +- The variable object must be a collection record; +- It must be from a table on the inheritance path, either the current table or a parent-child table; +- The "Form selected records" variable is only available for "many-to-many" and "one-to-many/many-to-one" relationship fields; +- **For multiple levels, flatten and deduplicate the data** + +```typescript +// Table selected records: +[{id:1},{id:2},{id:3},{id:4}] + +// Table selected records/one-to-one: +[{one-to-one: {id:2}}, {one-to-one: {id:3}}, {one-to-one: {id:3}}] +// Flatten and deduplicate +[{id: 2}, {id: 3}] + +// Table selected records/many-to-many: +[{many-to-many: [{id: 1}, {id:2}]}, {many-to-many: {[id:3}, {id:4}]}] +// Flatten +[{id:1},{id:2},{id:3},{id:4}] +``` + +#### Non-relational Default Value Variables + +- The type must be consistent or compatible, such as strings being compatible with numbers, and all objects that provide a toString method; +- JSON fields are special and can store any type of data; + +### Field Hierarchy (Optional Fields) + +![20240411101157](https://static-docs.nocobase.com/20240411101157.png) + +- Non-relational default value variables + + - When selecting fields with multiple levels, only one-to-one relationships are supported; many-to-many relationships are not supported; + - JSON fields are special and may have fewer restrictions; + +- Relational default value variables + + - hasOne: only supports one-to-one relationships; + - hasMany: supports both one-to-one (internally converted) and many-to-many relationships; + - belongsToMany: supports both one-to-one (internally converted) and many-to-many relationships; + - belongsTo: generally for one-to-one relationships, but when the parent relationship is hasMany, it also supports many-to-many (as hasMany/belongsTo is essentially a many-to-many relationship); + +## Special Cases + +### "Many-to-many" is equivalent to a "one-to-many/many-to-one" combination + +Model + +![20240411101558](https://static-docs.nocobase.com/20240411101558.png) + +When setting default value variables for a many-to-many relationship, if the variable has multiple records, the selected data will have multiple records, as shown below: +When the data table in the table block and the relationship field data table are the same. + +![20240411103021](https://static-docs.nocobase.com/20240411103021.png) + +### Why Don't One-to-one and One-to-many Relationships Have Default Values? + +For example, in an A.B relationship, if b1 is associated with a1, it cannot be associated with a2. If b1 is associated with a2, it will disassociate from a1. In this case, the data is not shared, while default values operate on a shared mechanism (both can be associated), so one-to-one and one-to-many cannot have default values. + +### Why Can't Subforms or Subtables with Many-to-one and Many-to-many Relationships Have Default Values? + +Because subforms and subtables focus on directly editing relationship data (including adding or removing), and relationship default values work on a shared mechanism where both can be associated but cannot modify the relationship data. Therefore, it is not suitable to provide default values in this scenario. + +Additionally, subforms or subtables have subfields, so it would be unclear whether the default value is for rows or columns. + +Considering this, it is more appropriate not to allow setting default values for any type of subform or subtable relationship. diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/display-title.md b/docs/fr-FR/handbook/ui/fields/field-settings/display-title.md new file mode 100644 index 000000000..d8e4f589a --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/display-title.md @@ -0,0 +1,10 @@ +# Display Title + +## Introduction + +This option controls whether field titles are displayed. It is enabled by default but allows you to disable it based on different layout requirements, hiding the title display when necessary. + +![20240411113316](https://static-docs.nocobase.com/20240411113316.png) + + +![20240411113353](https://static-docs.nocobase.com/20240411113353.png) diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/edit-description.md b/docs/fr-FR/handbook/ui/fields/field-settings/edit-description.md new file mode 100644 index 000000000..81551e198 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/edit-description.md @@ -0,0 +1,11 @@ +# Edit description + +## Introduction + +Field descriptions are short descriptive text displayed in light gray below the field component, which can be used to help users understand the purpose of the field and the input requirements. + +![20240411114048](https://static-docs.nocobase.com/20240411114048.png) + +![20240423111043](https://static-docs.nocobase.com/20240423111043.png) + +![20240411114433](https://static-docs.nocobase.com/20240411114433.png) diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/edit-title.md b/docs/fr-FR/handbook/ui/fields/field-settings/edit-title.md new file mode 100644 index 000000000..6b18b5e72 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/edit-title.md @@ -0,0 +1,10 @@ +# Edit field title + +## Introduction + +The field title refers to the name or label defined by the field, which can be personalized according to the needs of different blocks. + +![20240411110825](https://static-docs.nocobase.com/20240411110825.png) + + +![20240418093955](https://static-docs.nocobase.com/20240418093955.png) diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/edit-tooltip.md b/docs/fr-FR/handbook/ui/fields/field-settings/edit-tooltip.md new file mode 100644 index 000000000..74cb17ded --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/edit-tooltip.md @@ -0,0 +1,9 @@ +# Edit tooltip + +## Introduction + +When a user hovers over a field, a tooltip with additional information or guidance appears. This tooltip typically provides details such as the field's purpose, input format, and any restrictions, helping users to better understand and utilize the field.![20240412112137](https://static-docs.nocobase.com/20240412112137.png) + +![20240412112218](https://static-docs.nocobase.com/20240412112218.png) + +![20240412112247](https://static-docs.nocobase.com/20240412112247.png) diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/field-component.md b/docs/fr-FR/handbook/ui/fields/field-settings/field-component.md new file mode 100644 index 000000000..12027a4b3 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/field-component.md @@ -0,0 +1,13 @@ +# Field Component + +## Introduction + +Certain fields support multiple components, allowing us to select the most appropriate one to display the field’s value. For instance, the `URL` component can be switched to a `Preview` component. + +![20240807092556](https://static-docs.nocobase.com/20240807092556.png) + +![20240807092716](https://static-docs.nocobase.com/20240807092716.png) + +![20240807092859](https://static-docs.nocobase.com/20240807092859.png) + +If you need to expand more components, referring to [Expand Value Field Components](/plugin-samples/field/value)。 diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/number-format.md b/docs/fr-FR/handbook/ui/fields/field-settings/number-format.md new file mode 100644 index 000000000..7a0d908e6 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/number-format.md @@ -0,0 +1,23 @@ +# Number Format + +## Introduction + +Number **Format** is the process of visually enhancing and standardizing numerical fields (including formula fields) to make them more readable. This includes configuring options such as thousand separators, decimal precision, unit conversion, and scientific notation. By setting up numerical formatting, you can cater to the numerical expression preferences of different regions and industries. + +![20240417220017](https://static-docs.nocobase.com/20240417220017.png) + +![20240417220039](https://static-docs.nocobase.com/20240417220039.png) + +## Instructions for Use + +This feature supports simple unit conversions, thousand separators, prefixes and suffixes, precision adjustments, and scientific notation. + +Example: Formatting an order amount to include a currency symbol (such as the Chinese Yuan symbol ¥), thousand separators (like commas or periods), and specific decimal precision to ensure the amount is clearly and easily understood. + + + +Scientific notation in use. + +![20240417220416](https://static-docs.nocobase.com/20240417220416.png) diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/pattern.md b/docs/fr-FR/handbook/ui/fields/field-settings/pattern.md new file mode 100644 index 000000000..283a19d9f --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/pattern.md @@ -0,0 +1,11 @@ +# Pattern + +##### Introduction + +Unlike blocks, field components offer three distinct Pattern, specifically for fields within forms. Switching between these modes adjusts the corresponding field configuration options. + +- Editable +- Readonly (non-editable) +- Easy-reading (view mode) + +![20240411112743](https://static-docs.nocobase.com/20240411112743.png) diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/required.md b/docs/fr-FR/handbook/ui/fields/field-settings/required.md new file mode 100644 index 000000000..c48b3fc0a --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/required.md @@ -0,0 +1,23 @@ +# Required Fields + +## Introduction + +"Required" is a fundamental rule in form validation. You can enable it directly within the field settings or dynamically configure it through form linkage rules. + +## Static Setting + +You can directly designate a field as required, which is ideal for fields that must always be completed by users, such as username and password. + +![20240411114641](https://static-docs.nocobase.com/20240411114641.png) + +## Dynamic Setting (Conditional Required) + +Required fields can be set conditionally using the form block's linkage rules. + +Example: The shipping date field becomes required when the order status is marked as "shipped." + +![20240412110939](https://static-docs.nocobase.com/20240412110939.png) + + diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/style.md b/docs/fr-FR/handbook/ui/fields/field-settings/style.md new file mode 100644 index 000000000..e0855c3b3 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/style.md @@ -0,0 +1,22 @@ +# Style Configuration + +## Introduction + +Users can adjust the style of fields in the style menu (currently supporting color and background color settings). Additionally, styles can be dynamically adjusted based on field values or system variables. + +## How to Use + +Suppose we have a bank transaction detail table with a column for transaction amounts. We want to set positive amounts (income) to green and negative amounts (expenses) to red. Here are the specific steps: + +1. First, open the settings menu for the transaction amount field and click on the style option. +![Screenshot_2024-08-08_14-56-12-2024-08-08-22-57-37](https://static-docs.nocobase.com/Screenshot_2024-08-08_14-56-12-2024-08-08-22-57-37.png) + +2. Click "Add Dynamic Rule" and set the first rule: when the transaction amount is greater than 0, set the field color to green. +![Screenshot_2024-08-08_14-58-17-2024-08-08-22-58-36](https://static-docs.nocobase.com/Screenshot_2024-08-08_14-58-17-2024-08-08-22-58-36.png) + +3. Click "Add Dynamic Rule" again to set the second rule: when the transaction amount is less than 0, set the field color to red. + +![Screenshot_2024-08-08_14-59-03-2024-08-08-22-59-14](https://static-docs.nocobase.com/Screenshot_2024-08-08_14-59-03-2024-08-08-22-59-14.png) + +The final result will look like this: +![Screenshot_2024-08-08_14-59-20-2024-08-08-22-59-28](https://static-docs.nocobase.com/Screenshot_2024-08-08_14-59-20-2024-08-08-22-59-28.png) diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/title-field.md b/docs/fr-FR/handbook/ui/fields/field-settings/title-field.md new file mode 100644 index 000000000..d55396f08 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/title-field.md @@ -0,0 +1,23 @@ +# Title Field + +## Introduction + +The title field is a key element in relational field components, serving as the visible identifier of relational data within the user interface. + +## Configuration Locations for the Title Field + +### Global Configuration in the Data Table + +This setting applies across the entire application. + +![20240422210646](https://static-docs.nocobase.com/20240422210646.png) + +### Configuration within Relational Field Components + +This setting is limited to the specific block, taking precedence over global settings. + +![20240422210935](https://static-docs.nocobase.com/20240422210935.png) + +![20240422211020](https://static-docs.nocobase.com/20240422211020.png) + +![20240422211116](https://static-docs.nocobase.com/20240422211116.png) diff --git a/docs/fr-FR/handbook/ui/fields/field-settings/validation-rules.md b/docs/fr-FR/handbook/ui/fields/field-settings/validation-rules.md new file mode 100644 index 000000000..e37ab61a7 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/field-settings/validation-rules.md @@ -0,0 +1,27 @@ +# Validation Rules + +## Introduction + +Setting validation rules is crucial to ensure that user-entered data aligns with expected standards. While there are preset format validations, users also have the flexibility to define custom rules. + +![20240411112215](https://static-docs.nocobase.com/20240411112215.png) + +We provide several preset format validations for commonly used data types, including numerical values, ID numbers, email addresses, and phone numbers. + +![20240411112413](https://static-docs.nocobase.com/20240411112413.png) + +### Length/Size Validation + +This feature allows for validating the minimum value of numerical data, with current support limited to constants. + + + +### Custom Regular Expression Validation + +Example: Create a custom regular expression to validate Singaporean phone numbers and configure the corresponding error messages. + +![20240417222427](https://static-docs.nocobase.com/20240417222427.png) + +![20240417222548](https://static-docs.nocobase.com/20240417222548.png) diff --git a/docs/fr-FR/handbook/ui/fields/generic/bulk-edit-form-item.md b/docs/fr-FR/handbook/ui/fields/generic/bulk-edit-form-item.md new file mode 100644 index 000000000..502ccff88 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/generic/bulk-edit-form-item.md @@ -0,0 +1,31 @@ +# Bulk Edit Fields + +## Introduction + +The Bulk edit form is a specialized form block designed for batch editing operations. + +![20240425100652](https://static-docs.nocobase.com/20240425100652.png) + +![20240422151115](https://static-docs.nocobase.com/20240422151115.png) + +## Field Configuration + +You can configure only the fields within the current table. There are three methods for updating fields: + +- **No Update:** The field retains its original value after submission. +- **Modify To:** The field becomes required. +- **Clear:** The field's value is cleared after submission. + +![20240425100730](https://static-docs.nocobase.com/20240425100730.png) + +For relationship fields, you can flexibly switch between different field components. + +![20240425100857](https://static-docs.nocobase.com/20240425100857.png) + +## Field Configuration Options + +- [Edit Field Title](/handbook/ui/fields/field-settings/edit-title) +- [Display Title](/handbook/ui/fields/field-settings/display-title) +- [Edit Field Description](/handbook/ui/fields/field-settings/edit-description) +- [Edit Field Tooltip](/handbook/ui/fields/field-settings/edit-tooltip) +- [Set Validation Rules](/handbook/ui/fields/field-settings/validation-rules) diff --git a/docs/fr-FR/handbook/ui/fields/generic/detail-form-item.md b/docs/fr-FR/handbook/ui/fields/generic/detail-form-item.md new file mode 100644 index 000000000..228ed925f --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/generic/detail-form-item.md @@ -0,0 +1,44 @@ +# Details Fields + +## Introduction + +In detail blocks, list blocks, and grid blocks, the field configuration remains largely consistent, primarily focusing on how fields are presented in a reading view. + +![20240409131155](https://static-docs.nocobase.com/20240409131155.png) + +## Field Configuration Options + +### Date Field Formatting + +![20240417223807](https://static-docs.nocobase.com/20240417223807.png) + +For more information, see [Date Formatting](/handbook/ui/fields/specific/date-picker). + +### Numeric Field Formatting + +![20240417223608](https://static-docs.nocobase.com/20240417223608.png) + +This feature supports basic unit conversions, thousand separators, prefix and suffix customization, precision settings, and scientific notation. + +![20240417223709](https://static-docs.nocobase.com/20240417223709.png) + +For more details, see [Number Formatting](/handbook/ui/fields/field-settings/number-format). + +- [Edit Field Title](/handbook/ui/fields/field-settings/edit-title) +- [Display Title](/handbook/ui/fields/field-settings/display-title) +- [Edit Field Description](/handbook/ui/fields/field-settings/edit-description) +- [Edit Field Tooltip](/handbook/ui/fields/field-settings/edit-tooltip) + +### Field Component + +Certain fields allow for switching to different components. For instance, the `URL` component can be changed to a `Preview` component. + +![20240806165321](https://static-docs.nocobase.com/20240806165321.png) + +If you need to add more components, refer to [Extending Field Value Components](/plugin-samples/field/value). + +### Style + +![2024-06-26-15-16-09-表单样式入口](https://static-docs.nocobase.com/2024-06-26-15-16-09-表单风格入口.png) +![2024-06-26-15-21-31-样式配置](https://static-docs.nocobase.com/2024-06-26-15-21-31-样式配置.png) +![2024-06-26-15-22-42-表单-最终效果](https://static-docs.nocobase.com/2024-06-26-15-22-42-表单-最终效果.png) diff --git a/docs/fr-FR/handbook/ui/fields/generic/filter-collapse-item.md b/docs/fr-FR/handbook/ui/fields/generic/filter-collapse-item.md new file mode 100644 index 000000000..8b7f5ab6e --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/generic/filter-collapse-item.md @@ -0,0 +1,31 @@ +# Collaps Panel Fields + +## Introduction + +The Collapse filter block exclusively supports the selection of relational fields and option fields as filter criteria. + +## Field Configuration Options + +![20240409120906](https://static-docs.nocobase.com/20240409120906.png) + +### Setting the Data Scope + +Define the data scope for relational fields. + +![20240422152530](https://static-docs.nocobase.com/20240422152530.png) + +Example: Filtering out non-promotional products. + +![20240422152614](https://static-docs.nocobase.com/20240422152614.png) + +For additional information, refer to [Setting the Data Scope](/handbook/ui/fields/field-settings/data-scope). + +### Title Field + +![20240423085854](https://static-docs.nocobase.com/20240423085854.png) + +For further details, refer to [Title Field](/handbook/ui/fields/field-settings/title-field). + +- Default display (collapsed by default) +- Define sorting rules (for relational data) +- Customize the title diff --git a/docs/fr-FR/handbook/ui/fields/generic/filter-form-item.md b/docs/fr-FR/handbook/ui/fields/generic/filter-form-item.md new file mode 100644 index 000000000..84c0bfa86 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/generic/filter-form-item.md @@ -0,0 +1,28 @@ +# Filter blocks - Form Fields + +## Introduction + +The filter form allows you to select fields from both the current table and related tables (including fields from associated relationships) to serve as filter criteria. + +![20240409100014](https://static-docs.nocobase.com/20240409100014.png) + +**Example:** Suppose you want to filter orders using fields from a related table. The order table and the customer table have a one-to-many relationship. In this case, you can configure the customer's name and phone number fields from the customer table as filter criteria to help narrow down the orders. + +![20240422151626](https://static-docs.nocobase.com/20240422151626.png) + +## Field Configuration Options + +### Operators + +Selecting the right operators for filtering is crucial to enhance accuracy and efficiency. For string-type fields, fuzzy matching is enabled by default. + +![20240412112748](https://static-docs.nocobase.com/20240412112748.png) + +![20240412112823](https://static-docs.nocobase.com/20240412112823.png) + +![20240422151953](https://static-docs.nocobase.com/20240422151953.png) + +- [Edit Field Title](/handbook/ui/fields/field-settings/edit-title) +- [Display Title](/handbook/ui/fields/field-settings/display-title) +- [Edit Field Description](/handbook/ui/fields/field-settings/edit-description) +- [Edit Field Tooltip](/handbook/ui/fields/field-settings/edit-tooltip) diff --git a/docs/fr-FR/handbook/ui/fields/generic/form-item.md b/docs/fr-FR/handbook/ui/fields/generic/form-item.md new file mode 100644 index 000000000..624d8d0b6 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/generic/form-item.md @@ -0,0 +1,59 @@ +# Data blocks - Form Fields + +## Introduction + +Different types of fields in a form have different configuration options, allowing users to extend the configuration options through plugins to meet more personalized needs. + +![20240408221914](https://static-docs.nocobase.com/20240408221914.png) + +Displays fields related to associated tables (one-to-one or many-to-one relationship fields) as read-only. + +![20240413222636](https://static-docs.nocobase.com/20240413222636.png) + + + +## Field Configuration Options + +### Default Values + +Supports setting constants/variables as the default values for fields. + +![20240417094124](https://static-docs.nocobase.com/20240417094124.png) + +For more information, refer to [Setting Default Values](/handbook/ui/fields/field-settings/default-value). + +### Setting Validation Rules + +![20240417095037](https://static-docs.nocobase.com/20240417095037.png) + +For more information, refer to [Setting Validation Rules](/handbook/ui/fields/field-settings/validation-rules). + +### Required Fields + +![20240417111850](https://static-docs.nocobase.com/20240417111850.png) + +For more information, refer to [Required Fields](/handbook/ui/fields/field-settings/required). + +- [Edit Field Title](/handbook/ui/fields/field-settings/edit-title) +- [Display Title](/handbook/ui/fields/field-settings/display-title) +- [Edit Field Description](/handbook/ui/fields/field-settings/edit-description) +- [Edit Field Tooltip](/handbook/ui/fields/field-settings/edit-tooltip) +- [Pattern](/handbook/ui/fields/field-settings/pattern) + +### Field Components + +Some fields support switching to other components. For example, the `URL` component can be switched to the `Preview` component. + +![20240806164801](https://static-docs.nocobase.com/20240806164801.png) + +If you need to extend more components, refer to [Extending Value Field Components](/plugin-samples/field/value). + +### Style + +In reading mode, the form can be styled. + +![2024-06-26-15-16-09-Form Style Entry](https://static-docs.nocobase.com/2024-06-26-15-16-09-表单风格入口.png) +![2024-06-26-15-21-31-Style Configuration](https://static-docs.nocobase.com/2024-06-26-15-21-31-样式配置.png) +![2024-06-26-15-22-42-Final Form Effect](https://static-docs.nocobase.com/2024-06-26-15-22-42-表单-最终效果.png) diff --git a/docs/fr-FR/handbook/ui/fields/generic/table-column.md b/docs/fr-FR/handbook/ui/fields/generic/table-column.md new file mode 100644 index 000000000..486dad5f8 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/generic/table-column.md @@ -0,0 +1,72 @@ +# Table Fields + +## Introduction + +Table fields offer a robust set of features beyond basic column width adjustment, field titles, and sorting. They provide enhanced display configurations for specialized fields such as date fields, relationship fields, and numerical fields, allowing for a more tailored and informative data presentation. + +![20240511140644](https://static-docs.nocobase.com/20240511140644.png) + +## Field Configuration Options + +### Date Field Formatting + +![20240417114116](https://static-docs.nocobase.com/20240417114116.png) + +For comprehensive information on date formatting options, consult the [Date Formatting](/handbook/ui/fields/specific/date-picker) guide. + +### Numerical Field Formatting + +![20240417215229](https://static-docs.nocobase.com/20240417215229.png) + +The numerical field formatting feature offers versatile options including: +- Simple unit conversion +- Thousands separators +- Prefixes and suffixes +- Precision control +- Scientific notation + +![20240417215425](https://static-docs.nocobase.com/20240417215425.png) + +For an in-depth exploration of numerical formatting capabilities, refer to the [Number Formatting](/handbook/ui/fields/field-settings/number-format) documentation. + +### Sorting + +The current sorting functionality allows for single-column sorting within the current page data. Note that sorting by relationship fields is not supported in this version. + +![20240422115501](https://static-docs.nocobase.com/20240422115501.png) + +### Fixed Columns + +![20240511140524](https://static-docs.nocobase.com/20240511140524.png) + +### Field Components + +Certain fields offer the flexibility to switch between different component types. For instance, the `URL` component can be toggled to function as a `Preview` component. + +![20240806165152](https://static-docs.nocobase.com/20240806165152.png) + +For developers looking to expand the range of available components, the [Extending Value Field Components](/plugin-samples/field/value) guide provides valuable insights. + +### Styles + +The styling feature enables dynamic configuration of column colors and background colors based on specified conditions. To illustrate this powerful functionality, let's walk through an example using a bank transaction details table: + +Scenario: We want to visually differentiate between income (positive amounts) and expenses (negative amounts) in the transaction amount column. + +Step-by-step guide: + +1. Access the field settings for the transaction amount column and navigate to the Style option. +![style-menu-2024-08-08-18-23-13](https://static-docs.nocobase.com/style-menu-2024-08-08-18-23-13.png) + +2. Create the first conditional rule: For positive transactions (income), set the field color to green. + - Click "Add Linkage Rule" + - Configure: When transaction amount > 0, apply green color +![style-green-2024-08-08-18-33-34](https://static-docs.nocobase.com/style-green-2024-08-08-18-33-34.png) + +3. Establish the second conditional rule: For negative transactions (expenses), set the field color to red. + - Click "Add Linkage Rule" again + - Configure: When transaction amount < 0, apply red color +![style-red-2024-08-08-18-35-01](https://static-docs.nocobase.com/style-red-2024-08-08-18-35-01.png) + +The result is a visually intuitive representation of financial data: +![result-2024-08-08-18-38-05](https://static-docs.nocobase.com/result-2024-08-08-18-38-05.png) diff --git a/docs/fr-FR/handbook/ui/fields/index.md b/docs/fr-FR/handbook/ui/fields/index.md new file mode 100644 index 000000000..be6677653 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/index.md @@ -0,0 +1,33 @@ +# Fields + +In the UI, fields refer to components that serve as carriers for individual data units. Various types of data are represented through different field components. Fields must be attached to blocks and cannot function independently. + +## Fields within Blocks + +Fields are typically not used in isolation but rather as sub-elements within data-type blocks. These blocks generally include "configured columns," with the list of fields provided by the current data table. + +![](https://static-docs.nocobase.com/c5ea18ad1847332fe78075413f23de46.png) + +## Field Designer (Toolbar) + +Like blocks, field components feature three icons in the upper right corner: + +- Drag and Drop Layout +- Quick Add Field +- Field Parameter Configuration + +![](https://static-docs.nocobase.com/30cc5fcaeeb171862f79449a72a7fcf9.png) + +## Field Layout + +You can customize the layout of fields within a block by dragging and rearranging them as needed. + +![](https://static-docs.nocobase.com/0825ea8c014c9073f505e74f707ded66.gif) + +## Field Components + +Certain fields support switching between different components. For example, the `URL` component can be switched to the `Preview` component. + +![20240806164801](https://static-docs.nocobase.com/20240806164801.png) + +If you need to add more components, refer to [Extending Value Field Components](/plugin-samples/field/value). diff --git a/docs/fr-FR/handbook/ui/fields/specific/cascade-select.md b/docs/fr-FR/handbook/ui/fields/specific/cascade-select.md new file mode 100644 index 000000000..7b2559ebc --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/cascade-select.md @@ -0,0 +1,21 @@ +# Cascading Select + +## Introduction + +The cascading selector is tailored for relational fields where the target table follows a tree structure. It allows users to select data according to the hierarchical levels of the tree, with support for fuzzy search to streamline the selection process. + +## Instructions + +- For one-to-one relationships, the cascading selector is configured for single selection. + +![20240409205542](https://static-docs.nocobase.com/20240409205542.png) + +- For one-to-many relationships, the cascading selector enables multi-selection and supports drag-and-drop sorting for more intuitive organization. + +![20240409210705](https://static-docs.nocobase.com/20240409210705.png) + +## Field Configuration Options + +- [Title Field](/handbook/ui/fields/field-settings/title-field): Defines the content displayed by the cascading component (title field) for easier identification. + +- [Field Component](/handbook/ui/fields/association-field): Offers the flexibility to switch to other relational field components, such as dropdown selectors, data pickers, and more. diff --git a/docs/fr-FR/handbook/ui/fields/specific/date-picker.md b/docs/fr-FR/handbook/ui/fields/specific/date-picker.md new file mode 100644 index 000000000..27828fd5c --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/date-picker.md @@ -0,0 +1,21 @@ +# Date picker + +## Introduction + +The date field offers flexibility with customizable date and time formats to suit your needs. + +## Configuring Date Formats + +### Data Table Fields + +![20240417114311](https://static-docs.nocobase.com/20240417114311.png) + +### Field Settings + +![20240409174158](https://static-docs.nocobase.com/20240409174158.png) + +Beyond the array of preset date and time formats, the system accommodates custom formats, allowing you to tailor the display to your specific preferences. + +![20240409174559](https://static-docs.nocobase.com/20240409174559.png) + +![20240422165602](https://static-docs.nocobase.com/20240422165602.png) diff --git a/docs/fr-FR/handbook/ui/fields/specific/file-manager.md b/docs/fr-FR/handbook/ui/fields/specific/file-manager.md new file mode 100644 index 000000000..4c0451057 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/file-manager.md @@ -0,0 +1,13 @@ +# File Manager + +## Introduction + +The File Manager is a sophisticated relational field component designed to manage relationships where the target table is a file table. This powerful tool streamlines file handling within your database structure. + +![20240410213026](https://static-docs.nocobase.com/20240410213026.png) + +## Field Configuration Options + +- [Field Component](/handbook/ui/fields/association-field): Seamlessly switch between various relational field components, including dropdown selections, data selectors, and more, to suit your specific needs. +- Quick Upload: Enabled by default, this feature allows for effortless file association immediately upon upload, enhancing workflow efficiency. +- Select File: Also enabled by default, this option provides the flexibility to associate previously uploaded files, leveraging existing resources within your system. diff --git a/docs/fr-FR/handbook/ui/fields/specific/nester.md b/docs/fr-FR/handbook/ui/fields/specific/nester.md new file mode 100644 index 000000000..f2bd70992 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/nester.md @@ -0,0 +1,40 @@ +# Nester + +## Introduction + +Sub-form offer an elegant solution for scenarios where relational data needs to be created before association. They present multi-level relational data in a clear, nested structure. Unlike data selectors and dropdown menus, subforms allow direct management of relational table fields within the current page block. Moreover, they ensure that relational data is submitted seamlessly alongside the main form. + +## Usage Instructions + +### Subforms for Many-to-Many Relationships + +![20240409213911](https://static-docs.nocobase.com/20240409213911.png) + +Effortlessly display nested multi-level relationship fields, such as products and their associated inventory. + +![20240422172545](https://static-docs.nocobase.com/20240422172545.png) + +### Subforms for One-to-One Relationships + +![20240409214419](https://static-docs.nocobase.com/20240422172545.png) + +## Field Configuration Options + +### Multiple Record Addition/Association (Enabled by Default) + +When activated, this feature allows users to add multiple records with a simple click of the + icon. + +![20240422172237](https://static-docs.nocobase.com/20240422172237.png) + +### Field Component + +[Field Component](/handbook/ui/fields/association-field): Switch to other relationship field components, such as dropdown select, data selector, etc. + +### Linkage Rules +:::info{title=Tip} +The version of NocoBase needs to be v1.3.17-beta or above. +::: + +![20240906083737_rec_](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240906083737_rec_.gif) + +For more information, refer to [Linkage Rules](/handbook/ui/blocks/block-settings/linkage-rule) diff --git a/docs/fr-FR/handbook/ui/fields/specific/picker.md b/docs/fr-FR/handbook/ui/fields/specific/picker.md new file mode 100644 index 000000000..6be65ae88 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/picker.md @@ -0,0 +1,43 @@ +# Record picker + +## Introduction + +The **Record picker**, presented as a popup table selector, allows users to select existing data associations for the target table or add new data to the target table and then associate it. + +![20240410114516](https://static-docs.nocobase.com/20240410114516.png) + +The order table features a many-to-many relationship field called "Products". + +Data that has already been selected will not appear in the table selector. + + + +Within the table selector, users can further manage the relationship target table (add, delete, import, export, etc.). + +![20240410115239](https://static-docs.nocobase.com/20240410115239.png) + +## Field Configuration Options + +### Allow Adding Data + +This option enables users to add data to the target table and then select that newly added data. + + + +### Allow Adding/Associating Multiple Items + +This setting restricts multiple relationship data to allow associating only one piece of data. + +### Title Field + +![20240422205632](https://static-docs.nocobase.com/20240422205632.gif) + +For more information, refer to [Title Field](/handbook/ui/fields/field-settings/title-field) + +- [Popup Size](/handbook/ui/actions/action-settings/popup-size) + +- [Field Components](/handbook/ui/fields/association-field) diff --git a/docs/fr-FR/handbook/ui/fields/specific/popover-nester.md b/docs/fr-FR/handbook/ui/fields/specific/popover-nester.md new file mode 100644 index 000000000..cfd8caa75 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/popover-nester.md @@ -0,0 +1,46 @@ +# Popover Nester + +## Introduction + +In complex relational tables with intricate hierarchies and numerous fields, effectively presenting data relationships within a sub-form layout can be challenging. The Sub-form (Popup) solution enhances this by presenting relational field sub-forms in a convenient popup format, simplifying data interaction and visualization. + +## Usage Instructions + +### In Sub-table + +![20240422204245](https://static-docs.nocobase.com/20240422204245.png) + +![20240422204155](https://static-docs.nocobase.com/20240422204155.png) + +### In Form Blocks + +![20240430094409](https://static-docs.nocobase.com/20240430094409.png) + +## Field Configuration Options + +### Title Field + +![20240409230258](https://static-docs.nocobase.com/20240409230258.png) + +The title field value is displayed dynamically outside the popup, providing real-time updates. + +![20240409225851](https://static-docs.nocobase.com/20240409225851.png) + +### Allow Adding/Associating Multiple Entries (Default Enabled) + +By default, multiple entries can be added or associated. When this option is disabled, only a single entry can be added or associated. + +![20240422202542](https://static-docs.nocobase.com/20240422202542.png) + +### Field Component + +[Field Component](/handbook/ui/fields/association-field): Switch to other relationship field components, such as dropdown select, data selector, etc. + +### Linkage Rules +:::info{title=Tip} +The version of NocoBase needs to be v1.3.17-beta or above. +::: + +![20240906085955_rec_](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240906085955_rec_.gif) + +For more information, refer to [Linkage Rules](/handbook/ui/blocks/block-settings/linkage-rule) diff --git a/docs/fr-FR/handbook/ui/fields/specific/select.md b/docs/fr-FR/handbook/ui/fields/specific/select.md new file mode 100644 index 000000000..0c7946ebf --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/select.md @@ -0,0 +1,59 @@ +# Select + +## Introduction + +The selector offers a streamlined way to select or associate data within the target table, whether you're working with existing records or newly added entries. The dropdown options also support fuzzy search for easier navigation. + +![20240409230638](https://static-docs.nocobase.com/20240409230638.png) + +## Field Configuration Options + +### Quick Creation: Add Data First, Then Select + +#### Add via Dropdown Menu + +When new data is added to the target table, it will be automatically selected and linked upon form submission. This method is ideal for straightforward data scenarios, such as tagging. + +For example, the order table contains a many-to-one relationship field called "Tag" + + + +#### Add Popup + +This option allows you to configure a new form in a popup window, making it suitable for more complex scenarios, such as product entries. + +For instance, the order table includes a many-to-many relationship field named "Products." + + + +### Set Data Range + +Define the range of data that will appear in the dropdown list. + +![20240422204957](https://static-docs.nocobase.com/20240422204957.png) + +For more information, refer to [Set Data Range](/handbook/ui/fields/field-settings/data-scope). + +### Set Sorting Rules + +Determine the order in which the dropdown options are displayed. + +Example: Display in descending order based on the production date. + +![20240422205340](https://static-docs.nocobase.com/20240422205340.png) + +### Allow Multiple Add/Associate + +Limit the association in many-to-many relationship fields to a single data item. + +### Title Field + +![20240422205632](https://static-docs.nocobase.com/20240422205632.gif) + +For additional details, see [Title Field](/handbook/ui/fields/field-settings/title-field). + +- [Field Components](/handbook/ui/fields/association-field) diff --git a/docs/fr-FR/handbook/ui/fields/specific/sub-detail.md b/docs/fr-FR/handbook/ui/fields/specific/sub-detail.md new file mode 100644 index 000000000..fee282d57 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/sub-detail.md @@ -0,0 +1,42 @@ +# Sub detail + +## Introduction + +Sub-details serve as the dedicated components for sub-forms in reading mode. Unlike label and title components, sub-details provide the ability to display more extensive data from the current table and enable the configuration of related table data. This allows multi-level relational data to be presented clearly in a nested format. + +## Instructions + +### Sub-details for Many-to-Many Relationship Fields + +![20240822225058](https://static-docs.nocobase.com/20240822225058.png) + +This feature supports the nested display of multi-level relationship fields, such as Orders/Products/Inventory or Orders/Products/Suppliers. + +![20240822225231](https://static-docs.nocobase.com/20240822225231.png) + +### Sub-details for One-to-One Relationship Fields + +![20240822230215](https://static-docs.nocobase.com/20240822230215.png) + +## Field Configuration Options + +#### Setting Sorting Rules + +You can adjust the display order for many-to-many relational data. + +![20240822230359](https://static-docs.nocobase.com/20240822230359.png) + +![20240822230422](https://static-docs.nocobase.com/20240822230422.png) + +### Field Component + +[Field Component](/handbook/ui/fields/association-field): Switch to other relationship field components, such as dropdown select, data selector, etc. + +### Linkage Rules +:::info{title=Tip} +The version of NocoBase needs to be v1.3.17-beta or above. +::: + +![20240906090603_rec_](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240906090603_rec_.gif) + +For more information, refer to [Linkage Rules](/handbook/ui/blocks/block-settings/linkage-rule) diff --git a/docs/fr-FR/handbook/ui/fields/specific/sub-table.md b/docs/fr-FR/handbook/ui/fields/specific/sub-table.md new file mode 100644 index 000000000..94940d697 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/sub-table.md @@ -0,0 +1,60 @@ +# Sub table + +## Introduction + +Sub table are ideal for managing many-to-many relationship fields. They support bulk creation of target table data with associations, or selecting from existing data for association. + +## Instructions for Use + +![20240410151306](https://static-docs.nocobase.com/20240410151306.png) + +Different field types in the sub table display distinct field components. Larger fields (such as rich text, JSON, and multi-line text) are edited via a floating pop-up window. + +![20240410154316](https://static-docs.nocobase.com/20240410154316.png) + +Relationship fields in the sub table: + +Order (one-to-many) > Product (one-to-many) > Inventory. + +![20240410152232](https://static-docs.nocobase.com/20240410152232.png) + +By default, relationship field components are dropdown selectors (supporting data selectors or subforms via pop-up windows). + +![20240410152847](https://static-docs.nocobase.com/20240410152847.png) + +Supports drag-and-drop sorting. + +![20240422215629](https://static-docs.nocobase.com/20240422215629.gif) + +## Field Configuration Options + +### Allow Selecting Existing Data (disabled by default) + +Supports associating data from existing records. + +![20240410160432](https://static-docs.nocobase.com/20240410160432.png) + +![20240410160714](https://static-docs.nocobase.com/20240410160714.png) + +### Field Component + +[Field Component](/handbook/ui/fields/association-field): Switch to other relationship field components, such as dropdown select, data selector, etc. + +### Linkage Rules +:::info{title=Tip} +The version of NocoBase needs to be v1.3.17-beta or above. +::: + +![20240906084911_rec_](https://static-docs.nocobase.com/20240906084911_rec_.gif) + +For more information, refer to [Linkage Rules](/handbook/ui/blocks/block-settings/linkage-rule) + +### Allow disassociation + +:::info{title=Tip} +The version of NocoBase needs to be v1.3.34-beta or above. +::: + +![20241021210710](https://static-docs.nocobase.com/20241021210710.png) + +![20241021211909](https://static-docs.nocobase.com/20241021211909.png) diff --git a/docs/fr-FR/handbook/ui/fields/specific/tag.md b/docs/fr-FR/handbook/ui/fields/specific/tag.md new file mode 100644 index 000000000..1979e9742 --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/tag.md @@ -0,0 +1,35 @@ +# Tags + +## Introduction + +Tags serve as a display component within the relational field view mode, requiring you to configure both the title field and the color field. + +## Usage Instructions + +### Using Tags in a Table + +In the order table, there is a many-to-one relational field labeled "Tags." + +The tags table includes two fields: "Tag Name" and "Tag Color." + +![20240410212554](https://static-docs.nocobase.com/20240410212554.png) + +### Using Tags in Details + +![20240410212625](https://static-docs.nocobase.com/20240410212625.png) + +## Field Configuration Options + +### Title Field + +![20240422220237](https://static-docs.nocobase.com/20240422220237.png) + +For further details, see [Title Field](/handbook/ui/fields/field-settings/title-field). + +### Enable Link (Enabled by Default) + +Clicking on the link will open a popup window where you can configure the details of the current relational record or edit the form. + +![20240410212643](https://static-docs.nocobase.com/20240410212643.png) + +For further information, see [Field Component](/handbook/ui/fields/association-field). diff --git a/docs/fr-FR/handbook/ui/fields/specific/title.md b/docs/fr-FR/handbook/ui/fields/specific/title.md new file mode 100644 index 000000000..f9680d86b --- /dev/null +++ b/docs/fr-FR/handbook/ui/fields/specific/title.md @@ -0,0 +1,17 @@ +# Title + +## Introduction + +In reading mode, the default component for relationship fields is the title component, which marks the current associated record by displaying the value of the title field. + +## Field Configuration Options + +![20240429223353](https://static-docs.nocobase.com/20240429223353.png) + +### Enable Link (Enabled by default) + +Clicking will open a pop-up window, allowing you to customize the configuration block for data management. + +![20240429223831](https://static-docs.nocobase.com/20240429223831.png) + +For more details, see [Field Components](/handbook/ui/fields/association-field). diff --git a/docs/fr-FR/handbook/ui/menus/index.md b/docs/fr-FR/handbook/ui/menus/index.md new file mode 100644 index 000000000..1b91acb61 --- /dev/null +++ b/docs/fr-FR/handbook/ui/menus/index.md @@ -0,0 +1,51 @@ +# Menu + +Menus are used to organize pages and external links. In the default page layout template of NocoBase, the menu is located at the top and on the left side. Among them, the top is the primary menu, and the left side is for secondary and infinitely nested sub-menus. + +## Types of Menu Items + +NocoBase has three built-in types of menu items: + +- Group +- Page +- Link + +![](https://static-docs.nocobase.com/ccf6f42d3cc2677d440f9e33b9488d1c.png) + +### Group + +"Group" is used to group menu items, which can be located at the top or on the left side. Within a group, you can continue to create sub-groups, meaning the menu can have an infinite hierarchy. + +![](https://static-docs.nocobase.com/e59b2088fd68666cd240a26566616a3e.png) + +### Page + +A page can serve as a container for blocks, housing a variety of blocks. (See [Pages](./pages/index.md)) + +![](https://static-docs.nocobase.com/4cd259f6b79f6792df72ccc291da2af9.png) + +### Link + +Links can redirect to third-party URLs. You can use variables in the URL and Search params. + +![20240709231114](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240709231114.png) + +## Configuring the Menu + +After entering the interface configuration mode, there are two icons in the upper right corner of the menu item: + +- Drag to move +- Menu item configuration + +![](https://static-docs.nocobase.com/963ba10e36d04fd258fea0e996231f68.png) + +### Menu Item Configuration + +![](https://static-docs.nocobase.com/0a9a05bd88d8bad9d711102a730f351d.png) + +- Edit: Includes the menu item's title, icon, etc. +- Move to: In addition to dragging to move, you can also quickly move a menu item via "Move to", allowing you to move a menu item to the front, back, or inside of another menu item. +- Insert before +- Insert after +- Insert inner (Only for group types) +- Delete diff --git a/docs/fr-FR/handbook/ui/menus/static/Jp3NbdeVBojspWxvcWhcuDTlnOe.png b/docs/fr-FR/handbook/ui/menus/static/Jp3NbdeVBojspWxvcWhcuDTlnOe.png new file mode 100644 index 000000000..a2751410c Binary files /dev/null and b/docs/fr-FR/handbook/ui/menus/static/Jp3NbdeVBojspWxvcWhcuDTlnOe.png differ diff --git a/docs/fr-FR/handbook/ui/menus/static/LTdGbCxxHopt9ix1Nuncj73VnQb.png b/docs/fr-FR/handbook/ui/menus/static/LTdGbCxxHopt9ix1Nuncj73VnQb.png new file mode 100644 index 000000000..f686eb3de Binary files /dev/null and b/docs/fr-FR/handbook/ui/menus/static/LTdGbCxxHopt9ix1Nuncj73VnQb.png differ diff --git a/docs/fr-FR/handbook/ui/menus/static/OpdHbIbJ8oZX75x777ycylHxn1Q.png b/docs/fr-FR/handbook/ui/menus/static/OpdHbIbJ8oZX75x777ycylHxn1Q.png new file mode 100644 index 000000000..4a609a506 Binary files /dev/null and b/docs/fr-FR/handbook/ui/menus/static/OpdHbIbJ8oZX75x777ycylHxn1Q.png differ diff --git a/docs/fr-FR/handbook/ui/menus/static/SYzbbocHfoNFtsxomWJcUno7nog.png b/docs/fr-FR/handbook/ui/menus/static/SYzbbocHfoNFtsxomWJcUno7nog.png new file mode 100644 index 000000000..dc01db58a Binary files /dev/null and b/docs/fr-FR/handbook/ui/menus/static/SYzbbocHfoNFtsxomWJcUno7nog.png differ diff --git a/docs/fr-FR/handbook/ui/menus/static/T0LTbjTBEo24UaxU9Btc6xgbnMf.png b/docs/fr-FR/handbook/ui/menus/static/T0LTbjTBEo24UaxU9Btc6xgbnMf.png new file mode 100644 index 000000000..197266e57 Binary files /dev/null and b/docs/fr-FR/handbook/ui/menus/static/T0LTbjTBEo24UaxU9Btc6xgbnMf.png differ diff --git a/docs/fr-FR/handbook/ui/menus/static/ZLYibDXwToMdqRxMTy4cyTion1f.png b/docs/fr-FR/handbook/ui/menus/static/ZLYibDXwToMdqRxMTy4cyTion1f.png new file mode 100644 index 000000000..a89a582a6 Binary files /dev/null and b/docs/fr-FR/handbook/ui/menus/static/ZLYibDXwToMdqRxMTy4cyTion1f.png differ diff --git a/docs/fr-FR/handbook/ui/pages/index.md b/docs/fr-FR/handbook/ui/pages/index.md new file mode 100644 index 000000000..39c61ff1f --- /dev/null +++ b/docs/fr-FR/handbook/ui/pages/index.md @@ -0,0 +1,55 @@ +# Page + +NocoBase's pages can act as containers for blocks. They are like a canvas where you can freely place a variety of blocks. + +## Page Structure + +After creating a page through the [menu](/handbook/ui/menus), you can see that an empty page consists of the following two parts: + +1. Header + 1. Page title + 2. Tabs +2. Block container + +![2024-01-20_08-23-10](https://static-docs.nocobase.com/2024-01-20_08-23-10.jpg) + +## Page Settings + +Hovering the mouse over the configuration icon at the top right of the page, you can see the page configuration options: + +![2024-01-20_08-24-27](https://static-docs.nocobase.com/2024-01-20_08-24-27.jpg) + +Configurable items include: + +- Enable page header: Controls whether to display the header; +- Display page title: Whether to display the page title in the header; +- Edit page title: The default page title is the menu item title, which can be customized; +- Enable tabs: Off by default, enabling this option allows adding multiple tabs. + +### Enable Header + +Typically, we need to enable the header area to display the page title and tabs. However, there are situations where we might not want to enable it, for instance, when creating a Dashboard page where a top-level menu can effectively reflect the content of the page. In this case, we can disable the header and only display the blocks within the page. + +![20240120084618](https://static-docs.nocobase.com/20240120084618.png) + +### Page Title + +The default page title is the name of the menu item. By clicking "Edit Page Title," it can be modified. Just like with the header, sometimes we don't need to display the page title and only need to show the tabs, in which case you can disable the title. + +![2024-01-20_08-28-43](https://static-docs.nocobase.com/2024-01-20_08-28-43.jpg) + +### Enable Tabs + +When the content of a page is too much, or it is appropriate to divide it into several independent parts, we can enable tabs. Each tab is an independent block container. As shown below, we added 3 tabs to the orders page to display all orders, completed orders, and refunded orders. By moving the mouse to the tab title, you can see the sort and configuration buttons at the top right corner. + +![2024-01-20_08-47-15](https://static-docs.nocobase.com/2024-01-20_08-47-15.jpg) + +## Adding Blocks + +Click "Add block" to add an unlimited number of blocks to the page (see the introduction of [Blocks](./blocks/index.md)). + +![2024-01-20_08-48-36](https://static-docs.nocobase.com/2024-01-20_08-48-36.jpg) + +After adding several blocks, you can use the move button at the top right corner of each block to drag and arrange them freely, adjusting the layout to achieve the most suitable effect. + +![page-block](https://static-docs.nocobase.com/page-block.gif) \ No newline at end of file diff --git a/docs/fr-FR/handbook/ui/pages/static/C3xvb09t4oGOlhxxI5jcy2B7ncc.png b/docs/fr-FR/handbook/ui/pages/static/C3xvb09t4oGOlhxxI5jcy2B7ncc.png new file mode 100644 index 000000000..ff6e6bf2c Binary files /dev/null and b/docs/fr-FR/handbook/ui/pages/static/C3xvb09t4oGOlhxxI5jcy2B7ncc.png differ diff --git a/docs/fr-FR/handbook/ui/pages/static/U0kXblh2Yo5S5hx91c2cYggrnYf.gif b/docs/fr-FR/handbook/ui/pages/static/U0kXblh2Yo5S5hx91c2cYggrnYf.gif new file mode 100644 index 000000000..a43b0c671 Binary files /dev/null and b/docs/fr-FR/handbook/ui/pages/static/U0kXblh2Yo5S5hx91c2cYggrnYf.gif differ diff --git a/docs/fr-FR/handbook/ui/pages/static/VpP2bTwhooaxrqxy5gYc4KJFnUc.png b/docs/fr-FR/handbook/ui/pages/static/VpP2bTwhooaxrqxy5gYc4KJFnUc.png new file mode 100644 index 000000000..3a1725bca Binary files /dev/null and b/docs/fr-FR/handbook/ui/pages/static/VpP2bTwhooaxrqxy5gYc4KJFnUc.png differ diff --git a/docs/fr-FR/handbook/ui/pages/static/YPqEb1UEMoNzszxAHeDcNrsjnie.png b/docs/fr-FR/handbook/ui/pages/static/YPqEb1UEMoNzszxAHeDcNrsjnie.png new file mode 100644 index 000000000..933e11052 Binary files /dev/null and b/docs/fr-FR/handbook/ui/pages/static/YPqEb1UEMoNzszxAHeDcNrsjnie.png differ diff --git a/docs/fr-FR/handbook/ui/pop-up.md b/docs/fr-FR/handbook/ui/pop-up.md new file mode 100644 index 000000000..f7db7efde --- /dev/null +++ b/docs/fr-FR/handbook/ui/pop-up.md @@ -0,0 +1,105 @@ +# Popup + +## Introduction + +A popup window is a small window on the page, used to display some extended content within the current page. It can be presented in the form of a drawer or a dialog box, such as the details of a particular order or product, and can also be used for editing data. Popup operations play a very important role in the NocoBase interface configuration. Many blocks provide various popup operations, which can be used to add, view, edit data, etc. At the same time, various popup operations can be customized to adapt to various scenarios and needs. + +## Types & Size + +> In version v1.3.0-alpha and above, it supports opening as a [page](/handbook/ui/pop-up#page). + +Pop-ups come in two types: drawer and dialog. Configure the type and size of the pop-up during the configuration of actions. + + + +### Drawer + +![2024-06-13_09-45-33-2024-06-13-09-46-11](https://static-docs.nocobase.com/2024-06-13_09-45-33-2024-06-13-09-46-11.png) + +### Dialog + +![2024-06-13_09-45-56-2024-06-13-09-46-20](https://static-docs.nocobase.com/2024-06-13_09-45-56-2024-06-13-09-46-20.png) + +### Page + +:::info{title=Tip} +The version of NocoBase needs to be v1.3.0-alpha or above. +::: + +![20240809170648](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240809170648.png) + +## Use Cases + +The main scenarios of the popup window currently include: + +- Popup actions of the block, which can be used to add, view, edit the data of the block; +- Popup actions of relationship data, which can be used to view and edit the extended information of relationship data. + +### Popup Actions of the Block + +![20240511141127](https://static-docs.nocobase.com/20240511141127.png) + +### Popup Actions of Relationship Data + +![20240511141247](https://static-docs.nocobase.com/20240511141247.png) + +### Sharing a Single Record's Data + +:::info{title=Tip} +The version of NocoBase needs to be v1.3.0-alpha or above. +::: + +If you want to share the data of a single record with others, you can directly copy the URL of the browser address bar after opening the popup window, and then share it with others. When others open this URL, the corresponding popup window will automatically pop up on the page. + +![20240809173339_rec_](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240809173339_rec_.gif) + +## Adding Blocks + +The block added in the popup window can currently be used to add the following types of blocks. + +![20240511141349](https://static-docs.nocobase.com/20240511141349.png) + +The data in the popup window is divided into three dimensions: + +- Current record: used to display the current record; +- Relationship record: used to display the relationship data related to the current record; +- Other records: used to display data from other tables; + +![20240511141442](https://static-docs.nocobase.com/20240511141442.png) + +### Current Record + +Example: Display the current order data. + +![20240511141809](https://static-docs.nocobase.com/20240511141809.gif) + +### Relationship Record + +Example: Display the product data associated with the current order. + +![20240511143040](https://static-docs.nocobase.com/20240511143040.gif) + +### Other Records + +Example: Configure the warehouse details block in the popup operation of the order table block. + +![20240511143415](https://static-docs.nocobase.com/20240511143415.gif) + +## Use Variables + +- Row action popup: Each popup has a "Current popup record" variable, representing the current row record. +- Association field popup: Each popup has a "Current popup record" variable, representing the clicked relationship record. + +The blocks in the popup can use the "Current popup record" variable, with the following use cases: + +- Configuring data scope for blocks +- Configuring data scope for association fields +- Configuring default values for fields (form for adding data) +- Configuring linkage rules for actions +- Assign field values configuration for form submit actions + +For more content, refer to [Variables](/handbook/ui/variables) diff --git a/docs/fr-FR/handbook/ui/ui-editor/index.md b/docs/fr-FR/handbook/ui/ui-editor/index.md new file mode 100644 index 000000000..116232c84 --- /dev/null +++ b/docs/fr-FR/handbook/ui/ui-editor/index.md @@ -0,0 +1,45 @@ +# UI Editor + +## What You See Is What You Get + +NocoBase employs a what-you-see-is-what-you-get (WYSIWYG) interface configuration mode. By clicking the UI Editor button, you can switch between the configuration mode and the usage mode. + +![2024-01-20_11-42-20](https://static-docs.nocobase.com/2024-01-20_11-42-20.jpg) + +Usage mode: + +![2024-01-20_11-28-46](https://static-docs.nocobase.com/2024-01-20_11-28-46.jpg) + +Configuration mode: + +![2024-01-20_11-29-50](https://static-docs.nocobase.com/2024-01-20_11-29-50.jpg) + +## Layout Template + +NocoBase includes a layout template with navigation areas on the top and left sides, and a content area on the right. + +![2024-01-20_11-36-38](https://static-docs.nocobase.com/2024-01-20_11-36-38.jpg) + +## Configuration Items + +Upon entering the interface configuration mode, orange configurable items will appear on the interface. Typically, the entry point for each configurable element's options is located at the top right corner of that element. Almost all elements can be configured and reviewed in real-time on the interface, with the following as some examples: + +Configuration items for the menu: + +![2024-01-20_11-30-29](https://static-docs.nocobase.com/2024-01-20_11-30-29.jpg) + +Configuration items for the page: + +![2024-01-20_11-30-52](https://static-docs.nocobase.com/2024-01-20_11-30-52.jpg) + +Configuration items for the block: + +![2024-01-20_11-31-20](https://static-docs.nocobase.com/2024-01-20_11-31-20.jpg) + +Configuration items for the action: + +![2024-01-20_11-31-50](https://static-docs.nocobase.com/2024-01-20_11-31-50.jpg) + +Configuration items for the table column: + +![2024-01-20_11-32-08](https://static-docs.nocobase.com/2024-01-20_11-32-08.jpg) \ No newline at end of file diff --git a/docs/fr-FR/handbook/ui/variables.md b/docs/fr-FR/handbook/ui/variables.md new file mode 100644 index 000000000..0fdbae349 --- /dev/null +++ b/docs/fr-FR/handbook/ui/variables.md @@ -0,0 +1,173 @@ +# Variables + +## Introduction +Variables are a set of tokens used to identify a value in the current context. They can be used in scenarios such as configuration block data scope, field default values, linkage rules, workflows, etc. + +![2024-09-25_20-08-38-2024-09-25-20-11-51](https://static-docs.nocobase.com/2024-09-25_20-08-38-2024-09-25-20-11-51.png) + +## Currently Supported Variables + +### Current user + +Represents the data of the currently logged-in user. + +![20240416154950](https://static-docs.nocobase.com/20240416154950.png) + +### Current Role + +Represents the role identifier (role name) of the currently logged-in user. + +![20240416155100](https://static-docs.nocobase.com/20240416155100.png) + +### Current form + +The value of the current form, only used in form blocks. It is used in the following scenarios: + +- Linkage rules of the current form +- Default values for form fields (only valid when adding new data) +- Data scope settings for association fields +- Assign field values configuration for submit actions + +#### Linkage rules of the current form + +![20240416170732_rec_](https://static-docs.nocobase.com/20240416170732_rec_.gif) + +#### Default values for form fields (only valid when adding new data) + +![20240416171129_rec_](https://static-docs.nocobase.com/20240416171129_rec_.gif) + +#### Data scope settings for association fields + +Used to handle linkages between relationships, for example: + +![20240416171743_rec_](https://static-docs.nocobase.com/20240416171743_rec_.gif) + +#### Assign field values configuration for submit actions + +![20240416171215_rec_](https://static-docs.nocobase.com/20240416171215_rec_.gif) + +### Current object + +Currently only used for field configuration in subforms and subtables of form blocks, representing the value of each item: + +- Default values for subfields +- Data scope for sub-association fields + +#### Default values for subfields + +![20240416172933_rec_](https://static-docs.nocobase.com/20240416172933_rec_.gif) + +#### Data scope for sub-association fields + +![20240416173043_rec_](https://static-docs.nocobase.com/20240416173043_rec_.gif) + +### Parent object + +Similar to the "Current object", it represents the parent object of the current object. Supported in NocoBase v1.3.34-beta and above. + +### Current record + +A record refers to a row in a collection, with each row representing a record. The "Current record" variable is used in the "Row Action Linkage Rules" of display blocks. + +#### Row Action Linkage Rules + +![20240416174813_rec_](https://static-docs.nocobase.com/20240416174813_rec_.gif) + +### Current popup record + +Popup actions play a very important role in the NocoBase interface configuration. + +- Row action popup: Each popup has a "Current popup record" variable, representing the current row record. +- Association field popup: Each popup has a "Current popup record" variable, representing the clicked relationship record. + +The blocks in the popup can use the "Current popup record" variable, with the following use cases: + +- Configuring data scope for blocks +- Configuring data scope for association fields +- Configuring default values for fields (form for adding data) +- Configuring linkage rules for actions +- Assign field values configuration for form submit actions + +#### Configuring data scope for blocks + +![20240416224307_rec_](https://static-docs.nocobase.com/20240416224307_rec_.gif) + +#### Configuring data scope for association fields + +![20240416224641_rec_](https://static-docs.nocobase.com/20240416224641_rec_.gif) + +#### Configuring default values for fields (form for adding data) + +![20240416223846_rec_](https://static-docs.nocobase.com/20240416223846_rec_.gif) + +#### Configuring linkage rules for actions + +![20240416223101_rec_](https://static-docs.nocobase.com/20240416223101_rec_.gif) + +#### Assign field values configuration for form submit actions + +![20240416224014_rec_](https://static-docs.nocobase.com/20240416224014_rec_.gif) + +### Table Select Record + +Default values for form fields that are currently only used for the Add record action for a table block + +#### The default value of the form field for the Add record action + +### Parent record (Deprecated) + +Only used in association blocks, representing the source record of the association data. + +:::warning +"Parent record" is deprecated, it is recommended to use the equivalent "Current popup record" instead. +::: + +### Date variables + +Related variables include: + +- Current time +- Yesterday +- Today +- Tomorrow +- Last week +- This week +- Next week +- Last month +- This month +- Next month +- Last quarter +- This quarter +- Next quarter +- Last year +- This year +- Next year +- Last 7 days +- Next 7 days +- Last 30 days +- Next 30 days +- Last 90 days +- Next 90 days + +
    + +:::warning +Except for the Current time which is a moment (string), other date variables are time periods (arrays). Currently, time periods can only be used in data scope and cannot be used in field default values. +::: + +Related use cases include: + +- Date field condition settings for block data scope +- Date field condition settings for association field data scopes +- Date field condition settings for action linkage rules +- Date field default value settings + +### URL search params + +This variable represents the search parameters in the current page URL. This variable is only available when there is a query string in the page URL. It is more convenient to use it together with [Link](/handbook/ui/actions/types/link). + +![20240603200410](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240603200410.gif) + +### API token + +This variable's value is a string that serves as a credential for accessing the NocoBase API. It can be used to authenticate the user's identity. diff --git a/docs/fr-FR/handbook/user-data-sync/dev/resource.md b/docs/fr-FR/handbook/user-data-sync/dev/resource.md new file mode 100644 index 000000000..f90b0cbc3 --- /dev/null +++ b/docs/fr-FR/handbook/user-data-sync/dev/resource.md @@ -0,0 +1,61 @@ +# Extending Sync Target Resources + +## Overview + +NocoBase natively supports syncing user data to the **User** and **Department** tables. It also allows for extending the target resources for data synchronization to write data to other tables or perform custom processing as needed. + +:::warning{title=Experimental} +Full documentation is pending. +::: + +## Target Resource Handler Interface + +```ts +export abstract class UserDataResource { + name: string; + accepts: SyncAccept[]; + db: Database; + logger: SystemLogger; + + constructor(db: Database, logger: SystemLogger) { + this.db = db; + this.logger = logger; + } + + abstract update( + record: OriginRecord, + resourcePks: PrimaryKey[], + matchKey?: string, + ): Promise; + abstract create( + record: OriginRecord, + matchKey: string, + ): Promise; + + get syncRecordRepo() { + return this.db.getRepository('userDataSyncRecords'); + } + + get syncRecordResourceRepo() { + return this.db.getRepository('userDataSyncRecordsResources'); + } +} +``` + +## Registering Target Resources + +`registerResource(resource: UserDataResource, options?: ToposortOptions)` + +```ts +import { Plugin } from '@nocobase/server'; +import PluginUserDataSyncServer from '@nocobase/plugin-user-data-sync'; + +class CustomUserResourcePluginServer extends Plugin { + async load() { + const userDataSyncPlugin = this.app.pm.get(PluginUserDataSyncServer); + if (userDataSyncPlugin && userDataSyncPlugin.enabled) { + userDataSyncPlugin.resourceManager.registerResource(new CustomDataSyncResource(this.db, this.app.logger)); + } + } +} +``` diff --git a/docs/fr-FR/handbook/user-data-sync/dev/source.md b/docs/fr-FR/handbook/user-data-sync/dev/source.md new file mode 100644 index 000000000..1a9b6a4fd --- /dev/null +++ b/docs/fr-FR/handbook/user-data-sync/dev/source.md @@ -0,0 +1,146 @@ +# Extending Synchronized Data Sources + +## Overview + +NocoBase allows users to extend data source types for user data synchronization as needed. + +## Server Side + +### Data Source Interface + +The built-in user data synchronization plugin provides registration and management for data source types. To extend a data source type, inherit the `SyncSource` abstract class provided by the plugin and implement the relevant standard interfaces. + +```ts +import { SyncSource, UserData } from '@nocobase/plugin-user-data-sync'; + +class CustomSyncSource extends SyncSource { + async pull(): Promise { + return []; + } +} +``` + +The `SyncSource` class includes an `options` property to retrieve custom configurations for the data source. + +```ts +import { SyncSource, UserData } from '@nocobase/plugin-user-data-sync'; + +class CustomSyncSource extends SyncSource { + async pull(): Promise { + //... + const { appid, secret } = this.options; + //... + return []; + } +} +``` + +### Description of `UserData` Fields + +| Field | Description | +| ------------ | ----------------------------------------- | +| `dataType` | Data type, options are `user` and `department` | +| `uniqueKey` | Unique identifier field | +| `records` | Data records | +| `sourceName` | Data source name | + +If `dataType` is `user`, the `records` field contains the following fields: + +| Field | Description | +| ------------- | ---------------- | +| `id` | User ID | +| `nickname` | User nickname | +| `avatar` | User avatar | +| `email` | Email | +| `phone` | Phone number | +| `departments` | Array of department IDs | + +If `dataType` is `department`, the `records` field contains the following fields: + +| Field | Description | +| --------- | -------------------- | +| `id` | Department ID | +| `name` | Department name | +| `parentId`| Parent department ID | + +### Example Implementation of the Data Source Interface + +```ts +import { SyncSource, UserData } from '@nocobase/plugin-user-data-sync'; + +class CustomSyncSource extends SyncSource { + async pull(): Promise { + // ... + const ThirdClientApi = new ThirdClientApi( + this.options.appid, + this.options.secret, + ); + const departments = await this.clientapi.getDepartments(); + const users = await this.clientapi.getUsers(); + // ... + return [ + { + dataType: 'department', + uniqueKey: 'id', + records: departments, + sourceName: this.instance.name, + }, + { + dataType: 'user', + uniqueKey: 'id', + records: users, + sourceName: this.instance.name, + }, + ]; + } +} +``` + +### Registering a Data Source Type + +The extended data source must be registered with the data management module. + +```ts +import UserDataSyncPlugin from '@nocobase/plugin-user-data-sync'; + +class CustomSourcePlugin extends Plugin { + async load() { + const syncPlugin = this.app.pm.get( + UserDataSyncPlugin, + ) as UserDataSyncPlugin; + if (syncPlugin) { + syncPlugin.sourceManager.registerType('custom-source-type', { + syncSource: CustomSyncSource, + title: 'Custom Source', + }); + } + } +} +``` + +--- + +## Client Side + +The client user interface registers data source types using the `registerType` method provided by the user data synchronization plugin's client interface: + +```ts +import SyncPlugin from '@nocobase/plugin-user-data-sync/client'; + +class CustomSourcePlugin extends Plugin { + async load() { + const sync = this.app.pm.get(SyncPlugin); + sync.registerType(authType, { + components: { + AdminSettingsForm, // Backend management form + }, + }); + } +} +``` + +### Backend Management Form + +![Backend Management Form](https://static-docs.nocobase.com/202412041429835.png) + +The top section provides general data source configuration, while the bottom section allows for registration of custom configuration forms. diff --git a/docs/fr-FR/handbook/user-data-sync/index.md b/docs/fr-FR/handbook/user-data-sync/index.md new file mode 100644 index 000000000..0b41d0d3c --- /dev/null +++ b/docs/fr-FR/handbook/user-data-sync/index.md @@ -0,0 +1,45 @@ +# User Data Synchronization + + + +## Introduction + +This feature allows you to register and manage user data synchronization sources. By default, an HTTP API is provided, but additional data sources can be supported through plugins. It supports syncing data to the **Users** and **Departments** tables by default, with the possibility to extend synchronization to other target resources using plugins. + +## Installation + +This is a built-in plugin and does not require separate installation. + +## Data Source Management and Synchronization + +![](https://static-docs.nocobase.com/202412041043465.png) + +:::info +If no plugins providing user data synchronization sources are installed, user data can be synchronized using the HTTP API. Refer to [Data Source - HTTP API](./sources/api). +::: + +## Adding a Data Source + +Once you install a plugin that provides a user data synchronization source, you can add the corresponding data source. Only enabled data sources will display the "Sync" and "Task" buttons. + +> Example: WeCom (Enterprise WeChat) + +![](https://static-docs.nocobase.com/202412041053785.png) + +## Synchronizing Data + +Click the **Sync** button to start synchronizing data. + +![](https://static-docs.nocobase.com/202412041055022.png) + +Click the **Task** button to view the synchronization status. After successful synchronization, you can view the data in the Users and Departments lists. + +![](https://static-docs.nocobase.com/202412041202337.png) + +For failed synchronization tasks, you can click **Retry**. + +![](https://static-docs.nocobase.com/202412041058337.png) + +In case of synchronization failures, you can troubleshoot the issue through system logs. Additionally, raw synchronization records are stored in the `user-data-sync` directory under the application logs folder. + +![](https://static-docs.nocobase.com/202412041205655.png) diff --git a/docs/fr-FR/handbook/user-data-sync/sources/api.md b/docs/fr-FR/handbook/user-data-sync/sources/api.md new file mode 100644 index 000000000..c5fc00221 --- /dev/null +++ b/docs/fr-FR/handbook/user-data-sync/sources/api.md @@ -0,0 +1,75 @@ +# Synchronizing User Data via HTTP API + +## Obtain an API Key + +Refer to [API Keys](../api-keys). Ensure that the role associated with the API key has the necessary permissions to sync user data. + +## API Overview + +### Example + +```bash +curl 'https://localhost:13000/api/userData:push' \ + -H 'Authorization: Bearer ' \ + --data-raw '{"dataType":"user","records":[]}' # See details of the request body below +``` + +### Endpoint + +```bash +POST /api/userData:push +``` + +### User Data Format + +#### UserData + +| Parameter | Type | Description | +|--------------|------------------------------------|-----------------------------------------------------------------------------| +| `dataType` | `'user' \| 'department'` | Required. Type of data being pushed. Use `user` for pushing user data. | +| `matchKey` | `'username' \| 'email' \| 'phone'` | Optional. Used to match existing system users based on the specified field. | +| `records` | `UserRecord[]` | Required. Array of user data records. | + +#### UserRecord + +| Parameter | Type | Description | +|----------------|------------|-----------------------------------------------------------------------------| +| `uid` | `string` | Required. Unique identifier for the source user data. Immutable for a user. | +| `nickname` | `string` | Optional. User's nickname. | +| `username` | `string` | Optional. Username. | +| `email` | `string` | Optional. User's email address. | +| `phone` | `string` | Optional. User's phone number. | +| `departments` | `string[]` | Optional. Array of department UIDs the user belongs to. | +| `isDeleted` | `boolean` | Optional. Indicates whether the record is deleted. | +| `` | `any` | Optional. Custom fields in the user table. | + +### Department Data Format + +:::info +Pushing department data requires the [Departments](../../departments) plugin to be installed and enabled. +::: + +#### DepartmentData + +| Parameter | Type | Description | +|--------------|--------------------------|-------------------------------------------------------------------------| +| `dataType` | `'user' \| 'department'` | Required. Type of data being pushed. Use `department` for department data. | +| `records` | `DepartmentRecord[]` | Required. Array of department data records. | + +#### DepartmentRecord + +| Parameter | Type | Description | +|----------------|-----------|-----------------------------------------------------------------------------| +| `uid` | `string` | Required. Unique identifier for the source department data. Immutable. | +| `title` | `string` | Required. Department title. | +| `parentUid` | `string` | Optional. UID of the parent department. | +| `isDeleted` | `boolean` | Optional. Indicates whether the record is deleted. | +| `` | `any` | Optional. Custom fields in the department table. | + +:::info + +1. Data pushing is idempotent, ensuring consistent results with multiple pushes. +2. If a parent department is not yet created when pushing department data, it cannot be associated. Re-push the data after creating the parent department. +3. Similarly, if a department is not yet created when pushing user data, it cannot associate users with their departments. Push the department data first, then re-push the user data. + +::: diff --git a/docs/fr-FR/handbook/users/field-created-by.md b/docs/fr-FR/handbook/users/field-created-by.md new file mode 100644 index 000000000..ef731cfd7 --- /dev/null +++ b/docs/fr-FR/handbook/users/field-created-by.md @@ -0,0 +1,13 @@ +# Creator + + + +## Introduction + +## Field Configuration + +![20240512174625](https://static-docs.nocobase.com/20240512174625.png) + +## Example + +To be added. diff --git a/docs/fr-FR/handbook/users/field-updated-by.md b/docs/fr-FR/handbook/users/field-updated-by.md new file mode 100644 index 000000000..038ca9ae3 --- /dev/null +++ b/docs/fr-FR/handbook/users/field-updated-by.md @@ -0,0 +1,13 @@ +# Last Updated By + + + +## Introduction + +## Field Configuration + +![20240512174708](https://static-docs.nocobase.com/20240512174708.png) + +## Example + +To be added. diff --git a/docs/fr-FR/handbook/users/index.md b/docs/fr-FR/handbook/users/index.md new file mode 100644 index 000000000..d491eb17c --- /dev/null +++ b/docs/fr-FR/handbook/users/index.md @@ -0,0 +1,53 @@ +# https://static-docs.nocobase.com + + + +## Introduction + +The https://static-docs.nocobase.com plugin provides a basic user model and a user management interface. + +## Installation + +Built-in plugin, no separate installation required. + +## Usage Instructions + +### User Management + +This plugin provides a user management interface in the configuration center. After application initialization, an undeletable super admin account will be added. The super admin has Root permissions and can access all resources. + +![](https://static-docs.nocobase.com/44bf40f56b45d4dd96c424fb08082cf6.png) + +In addition, you can also add various different blocks of the https://static-docs.nocobase.com collection to manage https://static-docs.nocobase.com, such as table blocks: + +![](https://static-docs.nocobase.com/76b5a4652f869541a9e8f18a4568a7c9.png) + +### Add User + +![](https://static-docs.nocobase.com/4f8ef9ffc1c17f275b62b462f6385b19.png) + +![](https://static-docs.nocobase.com/437828173950bd7c21b40a6243ffe150.png) + +### Modify User Profile + +![](https://static-docs.nocobase.com/d25e06872bd1d48ed8c1139728fa5ff3.png) + +![](https://static-docs.nocobase.com/c140bcaab240385b9b5aca32a2ec2801.png) + +### Change User Password + +![](https://static-docs.nocobase.com/26c24c4cebda3d144dc4e9b728c2ede5.png) + +![](https://static-docs.nocobase.com/23a2b2223cb5b387b3699cc6143302e8.png) + +### Settings + +:::info{title=Tip} +The version of NocoBase needs to be v1.3.34-beta or above. +::: + +Configure whether to allow editing user profiles and changing user passwords (applies to all users). + +![20241021212438](https://static-docs.nocobase.com/20241021212438.png) + +![20241021212659](https://static-docs.nocobase.com/20241021212659.png) diff --git a/docs/fr-FR/handbook/users/static/2024-03-02-12-10-34.png b/docs/fr-FR/handbook/users/static/2024-03-02-12-10-34.png new file mode 100644 index 000000000..6ef217efa Binary files /dev/null and b/docs/fr-FR/handbook/users/static/2024-03-02-12-10-34.png differ diff --git a/docs/fr-FR/handbook/users/static/2024-03-03-17-26-33.png b/docs/fr-FR/handbook/users/static/2024-03-03-17-26-33.png new file mode 100644 index 000000000..74a2471c4 Binary files /dev/null and b/docs/fr-FR/handbook/users/static/2024-03-03-17-26-33.png differ diff --git a/docs/fr-FR/handbook/users/static/2024-03-03-17-44-08.png b/docs/fr-FR/handbook/users/static/2024-03-03-17-44-08.png new file mode 100644 index 000000000..83bd6b0eb Binary files /dev/null and b/docs/fr-FR/handbook/users/static/2024-03-03-17-44-08.png differ diff --git a/docs/fr-FR/handbook/users/static/2024-03-03-17-45-32.png b/docs/fr-FR/handbook/users/static/2024-03-03-17-45-32.png new file mode 100644 index 000000000..e8bbc9e5a Binary files /dev/null and b/docs/fr-FR/handbook/users/static/2024-03-03-17-45-32.png differ diff --git a/docs/fr-FR/handbook/users/static/2024-03-03-17-45-58.png b/docs/fr-FR/handbook/users/static/2024-03-03-17-45-58.png new file mode 100644 index 000000000..9813fe233 Binary files /dev/null and b/docs/fr-FR/handbook/users/static/2024-03-03-17-45-58.png differ diff --git a/docs/fr-FR/handbook/users/static/2024-03-03-17-46-29.png b/docs/fr-FR/handbook/users/static/2024-03-03-17-46-29.png new file mode 100644 index 000000000..df8d070b0 Binary files /dev/null and b/docs/fr-FR/handbook/users/static/2024-03-03-17-46-29.png differ diff --git a/docs/fr-FR/handbook/users/static/2024-03-03-17-46-49.png b/docs/fr-FR/handbook/users/static/2024-03-03-17-46-49.png new file mode 100644 index 000000000..d03f0d6b7 Binary files /dev/null and b/docs/fr-FR/handbook/users/static/2024-03-03-17-46-49.png differ diff --git a/docs/fr-FR/handbook/users/static/2024-03-03-17-47-09.png b/docs/fr-FR/handbook/users/static/2024-03-03-17-47-09.png new file mode 100644 index 000000000..19734cf17 Binary files /dev/null and b/docs/fr-FR/handbook/users/static/2024-03-03-17-47-09.png differ diff --git a/docs/fr-FR/handbook/verification/index.md b/docs/fr-FR/handbook/verification/index.md new file mode 100644 index 000000000..deabac81a --- /dev/null +++ b/docs/fr-FR/handbook/verification/index.md @@ -0,0 +1,12 @@ +# Verification Code + +:::warning +To be added. +::: + + diff --git a/docs/fr-FR/handbook/wecom/auth.md b/docs/fr-FR/handbook/wecom/auth.md new file mode 100644 index 000000000..2e8d3147b --- /dev/null +++ b/docs/fr-FR/handbook/wecom/auth.md @@ -0,0 +1,108 @@ +# 认证:企业微信 + + + +## 介绍 + +**企业微信**插件支持用户使用企业微信账号登录 NocoBase. + +## 激活插件 + +![](https://static-docs.nocobase.com/202406272056962.png) + +## 创建和配置企业微信自建应用 + +进入企业微信管理后台,创建企业微信自建应用。 + +![](https://static-docs.nocobase.com/202406272101321.png) + +![](https://static-docs.nocobase.com/202406272102087.png) + +点击应用进入详情页,下拉页面,点击「企业微信授权登录」。 + +![](https://static-docs.nocobase.com/202406272104655.png) + +设置授权回调域为 NocoBase 应用域名。 + +![](https://static-docs.nocobase.com/202406272105662.png) + +回到应用详情页,点击「网页授权及 JS-SDK」。 + +![](https://static-docs.nocobase.com/202406272107063.png) + +设置并验证可作为应用 OAuth2.0 网页授权功能的回调域名。 + +![](https://static-docs.nocobase.com/202406272107899.png) + +在应用详情页,点击「企业可信 IP」。 + +![](https://static-docs.nocobase.com/202406272108834.png) + +配置 NocoBase 应用 IP. + +![](https://static-docs.nocobase.com/202406272109805.png) + +## 从企业微信管理后台获取密钥 + +在企业微信管理后台 - 我的企业,复制「企业 ID」. + +![](https://static-docs.nocobase.com/202406272111637.png) + +在企业微信管理后台 - 应用管理,进入上一步创建的应用的详情页,复制 AgentId 和 Secret + +![](https://static-docs.nocobase.com/202406272122322.png) + +## 在 NocoBase 上添加企业微信认证 + +进入用户认证插件管理页面。 + +![](https://static-docs.nocobase.com/202406272115044.png) + +添加 - 企业微信 + +![](https://static-docs.nocobase.com/202406272115805.png) + +### 配置 + +![](https://static-docs.nocobase.com/202412041459250.png) + +| 配置项 | 说明 | 版本要求 | +| ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | -------- | +| When a phone number does not match an existing user,
    should a new user be created automatically | 当使用手机号匹配不到已有用户时,是否自动创建新用户 | - | +| Company ID | 企业 ID, 从企业微信管理后台获取 | - | +| AgentId | 从企业微信管理后台自建应用配置获取 | - | +| Secret | 从企业微信管理后台自建应用配置获取 | - | +| Origin | 当前应用域名 | - | +| Workbench application redirect link | 成功登录后跳转的应用路径 | `v1.4.0` | +| Automatic login | 在企业微信浏览器里打开应用链接时,自动登录。当配置有多个企业微信认证器的时候,只有一个能开启该选项。 | `v1.4.0` | +| Workbench application homepage link | 工作台应用主页链接 | - | + +## 配置企业微信应用首页 + +:::info +`v1.4.0` 以上版本,在启用「自动登录」选项的情况下,应用主页链接可以简化为: `https:///`,例如 `https://example.nocobase.com/admin`. + +也可以将分别配置手机和电脑端,例如 `https://example.nocobase.com/m` 和 `https://example.nocobase.com/admin`. +::: + +进入企业微信管理员后台,将复制的工作台应用主页链接填写到对应应用的应用主页地址栏。 + +![](https://static-docs.nocobase.com/202406272123631.png) + +![](https://static-docs.nocobase.com/202406272123048.png) + +## 登录 + +访问登录页面,点击登录表单下方按钮发起第三方登录。 + +![](https://static-docs.nocobase.com/202406272124608.png) + +:::warning +由于企业微信对于手机号等敏感信息的权限限制,只能在企业微信客户端内完成授权。第一次使用企业微信登录时,请参考以下步骤在企业微信客户端内完成首次登录授权。 +::: + +## 初次登录 + +从企业微信客户端进入工作台,下拉至底部,点击应用进入前面填写的应用主页,即可完成首次授权登录,之后就可以在 NocoBase 应用内使用企业微信登录。 + + diff --git a/docs/fr-FR/handbook/wecom/index.md b/docs/fr-FR/handbook/wecom/index.md new file mode 100644 index 000000000..a8abd9868 --- /dev/null +++ b/docs/fr-FR/handbook/wecom/index.md @@ -0,0 +1,13 @@ +# 企业微信 + + + +## 介绍 + +**企业微信**插件提供企业微信集成的能力,包括认证方式、通知渠道和用户数据同步来源。 + +参考: + +- [认证:企业微信](./auth.md) +- [通知:企业微信](./notification.md) +- [同步来源:企业微信](./user-data-sync.md) diff --git a/docs/fr-FR/handbook/wecom/notification.md b/docs/fr-FR/handbook/wecom/notification.md new file mode 100644 index 000000000..05508bdfe --- /dev/null +++ b/docs/fr-FR/handbook/wecom/notification.md @@ -0,0 +1,27 @@ +# 通知:企业微信 + + + +## 介绍 + +**企业微信**插件支持应用向企业微信用户发送通知消息。 + +## 添加和配置企业微信认证器 + +首先需要在 NocoBase 上添加和配置一个企业微信认证器,参考 [用户认证 - 企业微信](./auth),只有经过企业微信登录的系统用户,才可以通过企业微信接收系统通知。 + +## 添加企业微信通知渠道 + +![](https://static-docs.nocobase.com/202412041522365.png) + +## 配置企业微信通知渠道 + +选择刚才配置的认证器。 + +![](https://static-docs.nocobase.com/202412041525284.png) + +## 工作流通知节点配置 + +选择配置好的企业微信通知渠道,支持三种消息类型:文本卡片,Markdown, 模版卡片。 + +![](https://static-docs.nocobase.com/202412041529319.png) diff --git a/docs/fr-FR/handbook/wecom/user-data-sync.md b/docs/fr-FR/handbook/wecom/user-data-sync.md new file mode 100644 index 000000000..57ecfc669 --- /dev/null +++ b/docs/fr-FR/handbook/wecom/user-data-sync.md @@ -0,0 +1,43 @@ +# 从企业微信同步用户数据 + + + +## 介绍 + +**企业微信**插件支持用户从企业微信同步用户和部门数据。 + +## 创建和配置企业微信自建应用。 + +首先需要在企业微信管理后台,创建企业微信自建应用,并获取**企业 ID**, **AgentId** 和 **Secret**. + +参考 [用户认证 - 企业微信](./auth)。 + +## 在 NocoBase 上添加同步数据源 + +用户和权限 - 同步 - 添加,填写获取的相关信息。 + +![](https://static-docs.nocobase.com/202412041251867.png) + +## 配置通讯录同步 + +进入企业微信管理后台 - 安全和管理 - 管理工具,点击通讯录同步。 + +![](https://static-docs.nocobase.com/202412041249958.png) + +按如图所示设置,并设置企业可信 IP. + +![](https://static-docs.nocobase.com/202412041250776.png) + +接下来就可以进行用户数据同步了。 + +## 设置接收事件服务器 + +如果希望企业微信侧的用户、部门数据变动可以及时同步给 NocoBase 应用,可以进一步设置。 + +在填写了前面的配置信息之后,可以复制通讯录回调通知地址。 + +![](https://static-docs.nocobase.com/202412041256547.png) + +填写到企业微信设置上,并获取 Token 和 EncodingAESKey, 完成 NocoBase 用户同步数据源配置。 + +![](https://static-docs.nocobase.com/202412041257947.png) diff --git a/docs/fr-FR/handbook/workflow-action-trigger/action.md b/docs/fr-FR/handbook/workflow-action-trigger/action.md new file mode 100644 index 000000000..91d671b36 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-action-trigger/action.md @@ -0,0 +1,17 @@ +# Action Configuration + +When configuring actions in local trigger mode, once the workflow setup is complete, you'll need to return to the user interface and link the workflow to the relevant form operation button in the corresponding data block. + +The workflow associated with the "Submit" button (including the "Save record" button) will be triggered after the user submits the form and the data operation is completed. + +![Operation After Event_Submit Button](https://static-docs.nocobase.com/ae12d219b8400d75b395880ec4cb2bda.png) + +To bind a workflow, simply select "Bind Workflows" from the button configuration menu to open the binding configuration dialog. Here, you can set up multiple workflows to be triggered. If none are configured, it indicates that no workflows will be triggered. For each workflow, you'll need to determine whether the trigger involves data from the entire form or data from a specific relational field within the form. Then, based on the selected data model, choose the form workflow that corresponds to the data model of the associated table. + +![Operation After Event_Bind Workflow Configuration_Context Selection](https://static-docs.nocobase.com/358315fc175849a7fbadbe3276ac6fed.png) + +![Operation After Event_Bind Workflow Configuration_Workflow Selection](https://static-docs.nocobase.com/175a71a61b93540cce62a1cb124eb0b5.png) + +:::info{title="Note"} +Ensure that the workflow is enabled before attempting to select it in the above interface. +::: diff --git a/docs/fr-FR/handbook/workflow-action-trigger/example.md b/docs/fr-FR/handbook/workflow-action-trigger/example.md new file mode 100644 index 000000000..585f5b62f --- /dev/null +++ b/docs/fr-FR/handbook/workflow-action-trigger/example.md @@ -0,0 +1,34 @@ +# Example + +**Output:** Final Polished Translation + +--- + +Here, we will walk through the process by adding a new operation. + +Imagine a scenario involving a "Expenses applications." After an employee submits an expense reimbursement, the system needs to perform an automatic review of the amount and, if necessary, trigger a manual review for amounts exceeding a set limit. Only requests that pass these reviews will be approved and subsequently forwarded to the finance department for processing. + +To start, we can create a "Expenses" collection with the following fields: + +- **Project Name:** Single-line Text +- **Applicant:** Many-to-One (User) +- **Amount:** Numeric +- **Status:** Single Choice (Options: "Approved", "Processed") + +Next, we'll create a workflow categorized as a "Post-action Event" and configure the trigger's data table model to point to the "Expenses" collection: + +![Example_Trigger Configuration_Select Data Table](https://static-docs.nocobase.com/6e1abb5c3e1198038676115943714f07.png) + +Once the workflow is enabled, we can proceed with configuring the specific processing nodes. + +Then, on the user interface, create a table block for the "Expenses" data table and add an "Add" button to the toolbar, ensuring the corresponding form fields are properly configured. In the settings for the form's "Submit" button, open the "Bind Workflow" configuration dialog, select the entire form's data as the context, and link it to the workflow we previously created: + +![Example_Form Button Configuration_Bind Workflow](https://static-docs.nocobase.com/fc00bdcdb975bb8850e5cab235f854f3.png) + +Once the form configuration is complete, return to the workflow to arrange the logic. For instance, if the reimbursement amount exceeds 500, the system will require an administrator's manual review; otherwise, it will automatically approve the request. Upon approval, a expenses record is generated and forwarded to finance for further processing (details omitted). + +![Example_Process Flow](https://static-docs.nocobase.com/059e8e3d5ffb34cc2da6880fa3dc490b.png) + +Setting aside the subsequent financial processing, this completes the configuration of the expenses application process. When an employee fills out and submits a expenses request, the system triggers the corresponding workflow. If the amount is under 500, a record is automatically created and awaits further action by finance. If the amount exceeds this threshold, the request undergoes a supervisor's review. Upon approval, the record is created and handed over to finance for processing. + +This example workflow can also be applied to a standard "Submit" button, depending on whether the business scenario requires a record to be created before moving on to subsequent steps. diff --git a/docs/fr-FR/handbook/workflow-action-trigger/http-api.md b/docs/fr-FR/handbook/workflow-action-trigger/http-api.md new file mode 100644 index 000000000..ba7061947 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-action-trigger/http-api.md @@ -0,0 +1,48 @@ +# HTTP API + +Post-action events can be triggered not only through user interface interactions but also via HTTP API calls, providing a flexible way to initiate workflows programmatically. + +:::info{title="Note"} +When triggering post-operation events through HTTP API calls, it's essential to ensure that the workflow is active and the data table configuration is correctly matched. If these conditions aren't met, the call may fail or produce errors. +::: + +For workflows associated with specific operation buttons, you can trigger them using the following method (illustrated here with the `posts` table creation button): + +```bash +curl -X POST -H 'Authorization: Bearer ' -H 'X-Role: ' -d \ + '{ + "title": "Hello, world!", + "content": "This is a test post." + }' + "http://localhost:3000/api/posts:create?triggerWorkflows=workflowKey" +``` + +In this example, the URL parameter `triggerWorkflows` specifies the workflow key, with multiple workflows separated by commas if needed. You can obtain this key by hovering over the workflow name at the top of the workflow canvas: + +![Method to View Workflow Key](https://static-docs.nocobase.com/20240426135108.png) + +Upon successful execution, this call will trigger the appropriate post-operation event for the `posts` table. + +:::info{title="Note"} +Since external API calls require user authentication, the same credentials used for standard interface requests must be provided in HTTP API calls. This includes the `Authorization` request header or `token` parameter (obtained during login), and the `X-Role` request header, which specifies the current user's role. +::: + +If you need to trigger an event related to a one-to-one relationship (currently unsupported for many-to-one relationships), you can use the `!` symbol in the parameters to indicate the relationship field's trigger data: + +```bash +curl -X POST -H 'Authorization: Bearer ' -H 'X-Role: ' -d \ + '{ + "title": "Hello, world!", + "content": "This is a test post.", + "category": { + "title": "Test category" + } + }' + "http://localhost:3000/api/posts:create?triggerWorkflows=workflowKey!category" +``` + +Upon successful execution, this will trigger the corresponding post-operation event for the `categories` table. + +:::info{title="Note"} +If the event is set up in global mode, there's no need to specify the workflow using the `triggerWorkflows` URL parameter. Simply triggering the relevant data table operation will automatically initiate the associated workflow. +::: diff --git a/docs/fr-FR/handbook/workflow-action-trigger/index.md b/docs/fr-FR/handbook/workflow-action-trigger/index.md new file mode 100644 index 000000000..e9456b837 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-action-trigger/index.md @@ -0,0 +1,50 @@ +# Overview + + + +In the system, all user-generated data changes are typically carried out through some form of operation, usually by clicking a button. This button could be a submit button on a form or an action button within a data block. Post-action events are designed to bind specific workflows to these button actions, ensuring that a particular process is triggered upon successful user interaction. + +For instance, when adding or updating data, users can configure the "Bind Workflows" option on a button. Once the action is completed, the bound workflow will be triggered automatically. + +From an implementation standpoint, since Post-action event processing occurs at the middleware level (using Koa middleware), even making an HTTP API call to NocoBase can trigger defined Post-action events. + +:::info{title="Note"} +The Post-action event was initially called "Form Event." In earlier versions, this feature was limited to form buttons. However, starting from version `v0.20`, it has also become available for operation buttons within more data blocks, leading to its renaming as "Post-action event." +::: + +## FAQ + +### Difference Between Post-action and Pre-action Events + +The distinction between Post-action and Pre-action events lies in the timing of their triggers during the operation request and response cycle. One is triggered before the operation is processed, while the other is triggered afterward, as illustrated below: + +![Operation Sequence](https://static-docs.nocobase.com/Handbook/20240916013804.png) + +Pre-action events are triggered before the operation is executed, meaning they occur before the request is processed. These events can be utilized to validate or manipulate the request data, and if the request is blocked, the operation will not proceed. + +Conversely, Post-action events are triggered after the user's action has been successfully completed. At this stage, the data has already been submitted successfully, and the related processes can proceed based on the successful outcome. + +### Difference Between Post-action and Table Events + +Post-action events and table events have similarities in that both are triggered after data changes occur. However, their implementations differ. Post-action events are focused on the API level, whereas table events are concerned with changes in data within tables. + +Table events are closer to the system's core. In some instances, a single event may trigger data changes that lead to another event, creating a chain reaction. This is particularly true when related table data is altered during operations on the current table, which can trigger events in associated tables. + +Table events do not contain user-related information. In contrast, Post-action events are more closely linked to the user end, reflecting the results of user actions. The context of these processes will include user-related information, making them suitable for handling workflows resulting from user actions. In NocoBase's future design, more Post-action events may be added to expand the triggers available, so it is **recommended to use Post-action events** for managing workflows stemming from data changes caused by user actions. + +Another key difference is that Post-action events can be selectively bound to specific forms. If there are multiple forms, some can trigger the event upon submission, while others do not. On the other hand, table events are tied to data changes across the entire table and cannot be selectively bound. + +## Installation + +This plugin is built-in and does not require installation. + +## User Manual + +The use of Post-action events is divided into several parts: + +- [Trigger Configuration](./trigger.md) +- [Action Configuration](./action.md) + +You can also refer to [Examples](./example.md) to understand their application in real-world scenarios. + +If external system calls are necessary, please refer to [External Calls](./http-api.md). diff --git a/docs/fr-FR/handbook/workflow-action-trigger/trigger.md b/docs/fr-FR/handbook/workflow-action-trigger/trigger.md new file mode 100644 index 000000000..9c90d4361 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-action-trigger/trigger.md @@ -0,0 +1,48 @@ +# Trigger Configuration + +#### Creating a Workflow + +To create a workflow, begin by selecting "Post-action Event" as the type: + +![Creating Workflow with Post-action Trigger](https://static-docs.nocobase.com/13c87035ec1bb7332514676d3e896007.png) + +#### Execution Mode + +When setting up post-action events, you have the option to choose between "Synchronous" and "Asynchronous" execution modes: + +![Creating Workflow - Choosing Synchronous or Asynchronous](https://static-docs.nocobase.com/bc83525c7e539d578f9e2e20baf9ab69.png) + +Use the synchronous mode if the process needs to execute and provide feedback immediately after a user operation. For other scenarios, the default asynchronous mode is generally suitable. In asynchronous mode, the user operation completes instantly, and the workflow continues to execute in the background as part of a queued process. + +#### Configuring the Data Table + +To begin configuration, navigate to the workflow canvas and click on the trigger to open the settings window. The first step is to select the data table that you wish to bind: + +![Workflow Configuration - Selecting Data Table](https://static-docs.nocobase.com/35c49a91eba731127edcf76719c97634.png) + +#### Selecting Trigger Mode + +Next, determine the trigger mode by choosing between Local Mode and Global Mode: + +![Workflow Configuration - Choosing Trigger Mode](https://static-docs.nocobase.com/317809c48b2f2a2d38aedc7d08abdadc.png) + +- **Local Mode**: This mode triggers the workflow only on the action buttons that have been explicitly bound to it. If the workflow is not bound, clicking the button will not initiate the workflow. This mode is ideal when you want to tailor the workflow to specific forms or actions. +- **Global Mode**: In this mode, the workflow is triggered by any action button configured within the data table, regardless of the form's origin, and does not require specific workflow binding. + +In Local Mode, you can currently bind the following action buttons: + +- The "Submit" and "Save" buttons in new forms. +- The "Submit" and "Save" buttons in update forms. +- The "Update Data" button within data rows (such as in tables, lists, or kanban views). + +#### Choosing Action Type + +When using Global Mode, you also need to specify the action type. The available options are "Create record action" and "Update record action." The workflow is triggered upon the successful completion of either operation. + +#### Preloading Related Data + +If subsequent workflow steps require the use of related data from the trigger, you can select the relationship fields to preload: + +![Workflow Configuration - Preloading Relationships](https://static-docs.nocobase.com/5cded063509c7ba1d34f49bec8d68227.png) + +These preloaded related data will then be readily accessible throughout the workflow after it is triggered. diff --git a/docs/fr-FR/handbook/workflow-aggregate/index.md b/docs/fr-FR/handbook/workflow-aggregate/index.md new file mode 100644 index 000000000..08c2739ba --- /dev/null +++ b/docs/fr-FR/handbook/workflow-aggregate/index.md @@ -0,0 +1,67 @@ +# Aggregate + + + +This plugin is designed to execute aggregate function queries on specific data within a table that meets defined conditions, returning the relevant statistical outcomes. It is particularly useful for generating statistical data for reports. + +The node operates using database aggregate functions and currently supports querying a single field within a single data table. The resulting statistics are stored within the node’s output, making them available for subsequent nodes in the workflow. + +## Installation + +This is a built-in plugin, so no installation steps are required. + +## User Manual + +### Creating a Node + +In the workflow configuration interface, click the plus ("+") button within the process flow to add an "Aggregate Query" node: + +![Create Aggregate Query Node](https://static-docs.nocobase.com/7f9d806ebf5064f80c30f8b67f316f0f.png) + +### Node Configuration + +![Aggregate Query Node_Configuration](https://static-docs.nocobase.com/57362f747b9992230567c6bb5e986fd2.png) + +#### Aggregate Functions + +This plugin supports five SQL aggregate functions: `COUNT`, `SUM`, `AVG`, `MIN`, and `MAX`. You can select any one of these functions to perform the aggregate query on your data. + +#### Target Type + +There are two methods for selecting the target of the aggregate query. The first is to directly select the target data table and one of its fields. The second is to choose a related data table and field from the existing data objects in the workflow context to perform the aggregate query. + +#### Distinct + +This feature corresponds to the `DISTINCT` keyword in SQL. The distinct field must be the same as the selected data table field, and currently, different fields cannot be selected for the distinct and target fields. + +#### Filter Conditions + +You can apply filter conditions similar to those in a standard data table query, using the workflow’s context variables. + +### Example + +The aggregate target "Collection Table Data" is quite intuitive, so let's illustrate the usage of the aggregate target as "Related Collection Table Data" with the example of "counting the total number of articles in a category after adding a new article to that category." + +First, create two data tables: "Posts" and "Categories." The "Posts" collection includes a many-to-one relationship field pointing to the "Categories" collection, and a reverse relationship field that allows one category to contain multiple articles: + +| Field Name | Type | +| ----------------- | ------------------ | +| Title | Single Line Text | +| Category | Many-to-One (Category) | + +| Field Name | Type | +|---------------| ------------------ | +| Category Name | Single Line Text | +| Posts | One-to-Many (Articles) | + +Next, create a workflow triggered by an event in the data table, specifically when new data is added to the "Articles" table. + +Then, add an aggregate query node with the following configuration: + +![Aggregate Query Node_Example_Configuration](https://static-docs.nocobase.com/542272e638c6c0a567373d1b37ddda78.png) + +Once the workflow is triggered, the aggregate query node will calculate the total number of articles within the category of the newly added article and save this count as the node’s output. + +:::info{title=Tip} +If you need to access related data in a collection table event trigger, ensure you configure the relevant fields for "Preload associations" in the trigger; otherwise, these fields won’t be selectable. +::: diff --git a/docs/fr-FR/handbook/workflow-approval/action.md b/docs/fr-FR/handbook/workflow-approval/action.md new file mode 100644 index 000000000..0501324b7 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-approval/action.md @@ -0,0 +1,11 @@ +# Initiate Approval Configuration + +After configuring and activating an approval workflow, you can link it to the submit button of the relevant data table form. This setup allows users to automatically initiate the approval process when they submit the form: + +![Initiate Approval_Bind Workflow](https://static-docs.nocobase.com/2872ff108c61d7bf6d0bfb19886774c6.png) + +Once the workflow is linked, users will trigger the approval process upon submitting the form. + +:::info{title=Tip} +The approval initiation button currently only supports the "Submit" (or "Save") button in "Add" or "Update" forms. It does not support the "Submit to Workflow" button (which can only be linked to "Post-action event"). +::: diff --git a/docs/fr-FR/handbook/workflow-approval/advanced.md b/docs/fr-FR/handbook/workflow-approval/advanced.md new file mode 100644 index 000000000..2f11e2228 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-approval/advanced.md @@ -0,0 +1,37 @@ +# Advanced Understanding + +## Snapshot of Submitted Data for Approval + +In the approval process, data is governed by the principle of transactional data immutability. Each submission generates a snapshot that is then tracked and circulated during the approval process. The flow of this process is as follows: + +![Approval Data Snapshot Process Diagram](https://static-docs.nocobase.com/62a545a85d9e72c6b47e4b52707c4380.png) + +When actions such as "withdraw" or "return" are triggered within the process, the system preserves a snapshot of the data as it existed at that point within the same application document: + +![Approval Data Snapshot Process Example](https://static-docs.nocobase.com/62800d88772c88f1eaa11f6f493aea55.png) + +As illustrated above, every time data is withdrawn and then resubmitted, a new snapshot is saved for that particular submission process. + +## Approval Process Statuses + +For the initiator, an application document's status field indicates the current stage of the approval process, typically reflecting the following states: + +| Status | Description | +|----------------| ----------- | +| Draft | The applicant has temporarily saved the application form's data but has not yet officially submitted it to start the process. | +| Submitted | The application has been submitted and is awaiting approval. At this stage, no approver has yet processed it, and if allowed by the configuration, the initiator can still withdraw the application. | +| On going | The application has moved through at least one approval node, with at least one approver having submitted their decision. The initiator can no longer withdraw the application at this stage. | +| Returned | The application has been returned by one of the approvers, allowing the initiator to modify and resubmit it. | +| Approved | All approval nodes have been processed, and the application has been approved at each stage, marking the process as complete. | +| Rejected | The application has been rejected at one of the approval nodes, thereby terminating the process. | + +For each approval node, a record of the processing action is generated for the designated approver. Each approver’s record includes a status field indicating the current state of their processing, which typically includes the following statuses: + +| Status | Description | +| --------- | ----------- | +| Assigned | A record for the corresponding approver has been created, but since the processing rule requires serial handling, the approver must wait for the previous approver to finish before they can proceed. | +| Pending | The application is awaiting action from the current approver. | +| Returned | The current approver has returned the application. | +| Approved | The current approver has approved the application. | +| Rejected | The current approver has rejected the application. | +| Unprocessed | The application has reached a terminal state according to the node's processing rules after being handled by other approvers, or the workflow has become invalid, so the current approver is no longer required to take action. | diff --git a/docs/fr-FR/handbook/workflow-approval/block.md b/docs/fr-FR/handbook/workflow-approval/block.md new file mode 100644 index 000000000..a5406af4c --- /dev/null +++ b/docs/fr-FR/handbook/workflow-approval/block.md @@ -0,0 +1,65 @@ +# Approval Relevant Blocks + +## Approval Block in Data Details + +In the data details pop-up for a submitted item, an approval block can be configured to display the relevant approval records and provide entry points for processing them: + +![Details Approval Block_Creating Block](https://static-docs.nocobase.com/6b40f47474609d1dfd33618d80228189.png) + +### Actions by the Initiator + +The approval block displays the basic application information and approval history. The initiator can view the details of their submitted application within the pop-up. If retraction is enabled and the process is still in its initial approval stage—before any approver has taken action—the initiator can withdraw the application: + +![Details Approval Block_Initiator's View](https://static-docs.nocobase.com/5c7d4a6dca8de820d154487e41808c2a.png) + +If the initiator withdraws the application, the withdrawal record will appear in the approval block. By clicking on it, the application pop-up will reopen: + +![Details Approval Block_Initiator's View After Withdrawal](https://static-docs.nocobase.com/df52cb5203c1fd0a2f7af1757fbf6ecd.png) + +The pop-up's content remains unchanged, allowing the initiator to make adjustments and resubmit: + +![Details Approval Block_Initiator's Resubmission](https://static-docs.nocobase.com/4b3a6119e9871760d2dbdc8a2a75ff2c.png) + +### Actions by the Approver + +Approvers can also review the approval content through this block. In the processing history, if the logged-in user is one of the persons responsible for a node, a "View" button will appear in the details column. Clicking it will open the approval pop-up: + +![Details Approval Block_Approver's Node Handling](https://static-docs.nocobase.com/b160090482823ff5dc87592d0d5cedec.png) + +The pop-up will display the approver's interface for that approval node, typically including the approval details and an action bar: + +![Details Approval Block_Approver's Processing Pop-up](https://static-docs.nocobase.com/26acffffd314e86a658334ae9bef9d9b.png) + +Approvers can take actions such as approve, reject, or return within the pop-up. After an action is taken, a corresponding record will be added to the processing history. If the action is a return, the initiator can modify the application and resubmit it: + +![Details Approval Block_Approver's Return](https://static-docs.nocobase.com/5da879b24923ed25c31be658636ada64.png) + +Approving or rejecting will trigger the corresponding status based on the node's configured rules: + +![Details Approval Block_Approver's Approval](https://static-docs.nocobase.com/b020b1f82fce7c27b905ecf0b4c0046d.png) + +## Approval Center Block + +The approval plugin offers two global blocks for centrally managing approval processes: "Initiations" and "Todos": + +![Approval Center Block_Creation](https://static-docs.nocobase.com/fb3957320f082159f6f1f908937894b6.png) + +The "Initiations" block provides the initiator's perspective, allowing the user to initiate a new approval from the block's action bar: + +![Approval Center Block_Initiating Approval](https://static-docs.nocobase.com/a888630f892f15882eb1ec6b8826c528.png) + +If the approval trigger is configured "Initiate and approve in both data blocks and global approval blocks", the corresponding approval process will appear in the drop-down menu under the "Initiate" button. + +Users can also monitor the status of approvals they have initiated: + +![Approval Center Block_View Initiated List](https://static-docs.nocobase.com/4379ff809ae6a545dccab434cf6a6cfb.png) + +Clicking "View" opens a pop-up similar to the approval block in data details. The key difference is that the initiator's submission and the approval history are displayed on separate tabs: + +![Approval Center Block_Initiator's View of Details](https://static-docs.nocobase.com/234edf3af9a3fb9e3c7aa820c3befd66.png) + +The "Todos" block serves the approver's perspective, allowing users to view pending approvals. Clicking the corresponding "View" button opens a processing pop-up, similar to the approval block in data details, with the distinction that the approver's form and the approval history are shown on separate tabs: + +![Approval Center Block_Approver's View of Processed Details](https://static-docs.nocobase.com/bc425bd18837d6a918c609849c38da5d.png) + +If the approval has already been processed, the submitted content is displayed as is and cannot be modified. diff --git a/docs/fr-FR/handbook/workflow-approval/http-api.md b/docs/fr-FR/handbook/workflow-approval/http-api.md new file mode 100644 index 000000000..6a4108e79 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-approval/http-api.md @@ -0,0 +1,44 @@ +# HTTP API + +Approval events aren’t confined to actions within the user interface; they can also be triggered through HTTP API calls. + +For approvals initiated from data blocks and approval center blocks, you can trigger them using an API call (using the creation button for the `posts` table as an example): + +```bash +curl -X POST -H 'Authorization: Bearer ' -H 'X-Role: ' -d \ + '{ + "title": "Hello, world!", + "content": "This is a test post." + }' + "http://localhost:3000/api/posts:create?triggerWorkflows=workflowKey" +``` + +The URL parameter `triggerWorkflows` is the key of the workflow, with multiple workflows separated by commas. You can find this key by hovering over the workflow name at the top of the workflow canvas: + +![How to View Workflow Key](https://static-docs.nocobase.com/20240426135108.png) + +Once the call is successful, the approval workflow for the `posts` table will be triggered. + +:::info{title="Note"} +Because external calls also rely on user identity, HTTP API calls must include authentication details, just like standard interface requests. This includes the `Authorization` header or the `token` parameter (token obtained during login), as well as the `X-Role` header (indicating the user’s current role). +::: + +If you need to trigger an event related to a one-to-one relationship (note that one-to-many relationships are not yet supported), you can use `!` in the parameters to specify the related field that should trigger the event: + +```bash +curl -X POST -H 'Authorization: Bearer ' -H 'X-Role: ' -d \ + '{ + "title": "Hello, world!", + "content": "This is a test post.", + "category": { + "title": "Test category" + } + }' + "http://localhost:3000/api/posts:create?triggerWorkflows=workflowKey!category" +``` + +When the call is successfully executed, the approval event for the `categories` table will be triggered. + +:::info{title="Note"} +When triggering events via HTTP API calls, ensure that the workflow is enabled and that the data table configuration is correct; otherwise, the call may not be successful or may result in errors. +::: diff --git a/docs/fr-FR/handbook/workflow-approval/index.md b/docs/fr-FR/handbook/workflow-approval/index.md new file mode 100644 index 000000000..b4e857bfe --- /dev/null +++ b/docs/fr-FR/handbook/workflow-approval/index.md @@ -0,0 +1,20 @@ +# Overview + + + +Approval processes are tailored specifically for workflows initiated and managed by individuals to determine the status of related data. Commonly employed in office automation and other scenarios requiring human decision-making, these processes include creating and managing workflows such as "Leave Requests," "Expense Reimbursement Approvals," and "Material Procurement Approvals." + +The approval plugin offers a dedicated workflow type (trigger) known as "Approval (Event)" and a specialized "Approval" node. When paired with NocoBase's unique custom data tables and blocks, it enables the rapid and flexible creation and management of various approval scenarios. + +## User Manual + +The approval process is organized into several key sections: + +- [Trigger Configuration](./trigger.md) +- [Approval Node Configuration](./node.md) +- [Initiate Approval Configuration](./action.md) +- [Approval Relevant Blocks](./block.md) + +For a deeper dive into these concepts, see [Advanced](./advanced.md). + +To invoke this process from an external system, consult [HTTP API](./http-api.md). diff --git a/docs/fr-FR/handbook/workflow-approval/node.md b/docs/fr-FR/handbook/workflow-approval/node.md new file mode 100644 index 000000000..b0a17ba4b --- /dev/null +++ b/docs/fr-FR/handbook/workflow-approval/node.md @@ -0,0 +1,92 @@ +# Approval Node Configuration + +In an approval workflow, a dedicated "Approval" node is required to configure the logic for approvers to handle (approve, reject, or return) the initiated approval request. This "Approval" node is exclusively used within approval workflows. + +:::info{title=Tip} +**Difference from the general "Manual" node:** The general "Manual" node is versatile and can be used across various workflows for manual data input, decision-making on process continuation, and other scenarios. In contrast, the "Approval" Node is specialized for approval workflows and is not applicable in other types of workflows. +::: + +## Creating a Node + +To create an "Approval" node, click the plus sign ("+") in the workflow. Then, select one of the available pass modes to configure the approval node: + +![Approval Node Creation](https://static-docs.nocobase.com/f15d61208a3918d005cd2031fc9b6ce7.png) + +## Pass Modes + +There are two pass modes available: + +1. Direct Pass Mode: This mode is ideal for simpler workflows, where the outcome at the approval node determines whether the process ends. If the request is not approved, the process exits immediately. + + ![Approval Node Pass Mode - Direct Pass Mode](https://static-docs.nocobase.com/a9d446a186f61c546607cf1c2534b287.png) + +2. Branching Mode: This mode is typically used for more complex workflows. After the approval node produces a result, subsequent nodes can execute within the resulting branches. + + ![Approval Node Pass Mode - Branching Mode](https://static-docs.nocobase.com/57dc6a8907f3bb02fb28c354c241e4e5.png) + + If the node is configured with a "Return" operation, a "Return" branch will be created, and the process will forcibly exit after the return branch is completed. + + Once this node is "approved," the process continues through both the pass branch and the subsequent workflow. Following a "reject" operation, the default setting allows the process to continue through the subsequent workflow, although you can configure the node to end the process after executing the rejection branch. + +:::info{title=Tip} +The pass mode cannot be modified once the node is created. +::: + +## Approvers + +Approvers are the users responsible for the approval actions at the node. They can consist of one or more users, selected from a static list or a dynamic value specified by a variable. + +![Approval Node_Approvers](https://static-docs.nocobase.com/29c64297d577b9ca9457b1d7ac62287d.png) + +When using a variable, only primary keys or foreign keys from user data in the context and node results can be selected. If the selected variable is an array (in cases of many-to-many relationships), each user in the array will be merged into the overall approver collection. + +## Negotiation Modes + +If there is only one approver (including cases where multiple variables are deduplicated), the approval will be handled solely by that user, regardless of the negotiation mode chosen. + +For multiple approvers, the selected negotiation mode determines the handling method: + +1. Or: The node passes with the approval of any one person; all must reject for the node to be rejected. +2. And: The node passes only if all approvers approve; a single rejection results in rejection. +3. Voting: The node passes if a majority (as specified) of approvers approve; otherwise, the node is rejected. + +For the return operation, if any user in the approver collection opts for a return, the node will directly exit the workflow. + +## Processing Order + +For multiple approvers, the processing order dictates the sequence of actions: + +1. Parallelly: All approvers can act in any order, with no sequence required. +2. Sequentially: Approvers act in the order defined in the approver collection, where each subsequent user can only proceed after the previous one has submitted their decision. + +Regardless of whether "Sequentially" processing is set, the results generated will follow the rules outlined in the "Negotiation Modes" section, with the node completing execution once the conditions are met. + +## Exit Workflow After Rejection Branch Completion + +When "Branch Mode" is set for "Pass Mode," you can opt to exit the workflow after the rejection branch is completed. If selected, a "✗" symbol will appear at the end of the rejection branch, indicating that no further nodes will be executed after this branch concludes: + +![Exit After Rejection](https://static-docs.nocobase.com/1e740df93c128fb6fe54bf85a740e683.png) + +## Approver Interface Configuration + +The approver interface configuration provides the interface for approvers when the workflow reaches this node. Click the configuration button to open the settings window: + +![Approver Interface Configuration Pop-up](https://static-docs.nocobase.com/2c321ae164b436f1c572305ff27cc9dd.png) + +In this configuration window, you can add blocks such as approval submission details, operation bars, and custom prompt text: + +![Add Block in Interface Configuration](https://static-docs.nocobase.com/9f8f11926e935ad8f8fbeec368edebfe.png) + +The approval content details block includes the data submitted by the initiator. Similar to a standard data block, you can freely add field components from the data table and arrange them to organize the content that the approver needs to review: + +![Details Block in Interface Configuration](https://static-docs.nocobase.com/1140ec13caeea1b364d12e057720a29c.png) + +The operation bar can include buttons supported by this node, such as "Approve," "Reject," and "Return": + +![Operation Bar in Interface Configuration](https://static-docs.nocobase.com/1bb090ed123f62ba8a524a3e9e7da328.png) + +Additionally, the operation bar can include fields for approvers to fill out, such as a "Comment" field. + +:::warning{title=Important} +If you enable or disable a button in the operation bar, be sure to save the node configuration after closing the interface configuration window. Otherwise, the changes will not take effect. +::: diff --git a/docs/fr-FR/handbook/workflow-approval/trigger.md b/docs/fr-FR/handbook/workflow-approval/trigger.md new file mode 100644 index 000000000..b8b93b265 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-approval/trigger.md @@ -0,0 +1,55 @@ +# Trigger Configuration + +## Creating a Workflow + +To set up an approval workflow, start by selecting the "Approval" type during the workflow creation process: + +![Approval Trigger_Create Approval Workflow](https://static-docs.nocobase.com/f52dda854f46a669e0c1c7fb487a17ea.png) + +Next, in the workflow configuration interface, click on the trigger to open a popup window for additional configuration options. + +## Binding Data Tables + +NocoBase’s approval plugin is designed with flexibility in mind, allowing it to be integrated with any custom data collection. This means there’s no need to repeatedly configure the data model for approval processes. Instead, you can reuse existing data collections. When configuring the trigger, the first step is to select a data table to determine which data entries will trigger the workflow upon creation or update: + +![Approval Trigger_Trigger Configuration_Select Data Table](https://static-docs.nocobase.com/8732a4419b1e28d2752b8f601132c82d.png) + +After selecting the data table, bind the workflow to the submit button in the form used for creating or editing data within the chosen table: + +![Initiate Approval_Bind Workflow](https://static-docs.nocobase.com/2872ff108c61d7bf6d0bfb19886774c6.png) + +Once the form is submitted, the corresponding approval workflow will be triggered. The submitted data will be saved in the specified data table and also snapshotted within the approval flow for future review by approvers. + +## Where to Initiate an Approval + +There are two locations within the user interface where approvals can be initiated: +1. Through the submission of a data collection form that has been bound to an approval process, typically used for initiating a single approval process. +2. Via the Approval block, which allows for the centralized initiation of global processes. + +![Approval Trigger_Trigger Configuration_Where to Initiate Approval](https://static-docs.nocobase.com/1a193ec0acfa6cde221c6e5d49a50b3e.png) + +By selecting "Initiate and approve in both data blocks and global approval blocks" the process will appear in the “Initiations” dropdown menu within the Approval Center block, enabling users to manage various approvals from a central location. + +## Withdrawn + +If the approval process permits the initiator to withdraw the request, select the "Allowed to be withdrawn" option: + +![Approval Trigger_Trigger Configuration_Allow Withdrawal](https://static-docs.nocobase.com/09185712fc55bc536892136ce0ade4a8.png) + +When this option is selected, the initiator can withdraw the approval request at any time before any approver has processed it. However, once any subsequent approval nodes have been processed, the approval can no longer be withdrawn. + +## Configuring the Form Interface for Initiating Approvals + +Finally, you’ll need to configure the form interface for the initiator. This interface is used when initiating an approval from the Approval Center block or when re-initiating after a withdrawal. Click the configuration button to open a popup window: + +![Approval Trigger_Trigger Configuration_Initiator Form](https://static-docs.nocobase.com/ca8b7e362d912138cf7d73bb60b37ac1.png) + +You can add a form based on the bound data table or include explanatory text (Markdown) to guide the initiator. A form is required; otherwise, the initiator will not be able to proceed upon entering this interface. + +After adding the form block, you can configure the corresponding data table's field components and arrange them as needed to organize the content to be filled out, similar to the regular form configuration interface: + +![Approval Trigger_Trigger Configuration_Initiator Form_Field Configuration](https://static-docs.nocobase.com/5a1e7f9c9d8de092c7b55585dad7d633.png) + +In addition to the submit button, you can also add a “Save Draft” button to support the temporary storage of data during the process: + +![Approval Trigger_Trigger Configuration_Initiator Form_Action Configuration](https://static-docs.nocobase.com/2f4850d2078e94538995a9df70d3d2d1.png) diff --git a/docs/fr-FR/handbook/workflow-custom-action-trigger/action.md b/docs/fr-FR/handbook/workflow-custom-action-trigger/action.md new file mode 100644 index 000000000..83aad6e1e --- /dev/null +++ b/docs/fr-FR/handbook/workflow-custom-action-trigger/action.md @@ -0,0 +1,19 @@ +# Action Configuration + +Within any data block, you have the option to add a "Trigger Workflow" button to the action bar for individual rows of data, whether in forms, tables, or detail pages: + +![Add Action Button to Block_Form](https://static-docs.nocobase.com/20240509165428.png) + +![Add Action Button to Block_Table Row](https://static-docs.nocobase.com/20240509165340.png) + +![Add Action Button to Block_Detail](https://static-docs.nocobase.com/20240509165545.png) + +Once the button is added, you can link it to the workflow you previously created: + +![Button Bind to Workflow](https://static-docs.nocobase.com/20240509165631.png) + +![Select Workflow to Bind](https://static-docs.nocobase.com/20240509165658.png) + +Afterward, simply clicking this button will initiate the custom action event: + +![Trigger Result After Button Click](https://static-docs.nocobase.com/20240509170453.png) diff --git a/docs/fr-FR/handbook/workflow-custom-action-trigger/example.md b/docs/fr-FR/handbook/workflow-custom-action-trigger/example.md new file mode 100644 index 000000000..bf9317b3c --- /dev/null +++ b/docs/fr-FR/handbook/workflow-custom-action-trigger/example.md @@ -0,0 +1,47 @@ +# Example + +Imagine we have a "Sample" collection. For samples marked as "Collected," a "Send to Testing" operation is needed. This operation first checks the sample's basic information, generates a "Testing" Record, and then updates the sample's status to "Testing". This entire process is too complex to be handled by simple "Create, Read, Update, Delete" button clicks. In such scenarios, custom operation events are the perfect solution. + +To start, create a "Sample" collection and a "Testing" collection, and input some basic test data into the Sample collection: + +![Example_Sample_Data_Table](https://static-docs.nocobase.com/20240509172234.png) + +Next, you'll need to create a "Custom action Event" workflow. If you require immediate feedback during the operation, opt for the synchronous mode (bear in mind that synchronous mode doesn't support asynchronous nodes like human intervention): + +![Example_Create_Workflow](https://static-docs.nocobase.com/20240509173106.png) + +Within the trigger configuration, choose "Sample" as the collection: + +![Example_Trigger_Configuration](https://static-docs.nocobase.com/20240509173148.png) + +Now, arrange the logic of the process according to your business needs. For instance, you might set it so that the "Send to Testing" operation is only allowed when the index parameter exceeds `90`; otherwise, a relevant warning is provided: + +![Example_Business_Logic_Arrangement](https://static-docs.nocobase.com/20240509174159.png) + +:::info{title=Note} +The "[Response Message](../../nodes/response-message.md)" node can be utilized in synchronous custom operation events to send feedback messages to the client. This feature isn't available in asynchronous mode. +::: + +After setting up and enabling the workflow, return to the table interface, and add a "Trigger Workflow" button in the operations column: + +![Example_Add_Operation_Button](https://static-docs.nocobase.com/20240509174525.png) + +Next, in the button's configuration menu, select the option to bind the workflow, and open the configuration window: + +![Example_Open_Workflow_Binding_Popup](https://static-docs.nocobase.com/20240509174633.png) + +Add the workflow that was previously enabled: + +![Example_Select_Workflow](https://static-docs.nocobase.com/20240509174723.png) + +After submission, rename the button to reflect the action, like "Testing," and the configuration is complete. + +To use the feature, select any sample data from the table and click the "Send to Testing" button to trigger the custom operation event. As per the pre-arranged logic, if the sample's index parameter is below 90, you'll see a warning message like this: + +![Example_Inspection_Criteria_Not_Met](https://static-docs.nocobase.com/20240509175026.png) + +If the index parameter is over 90, the process will proceed as expected, creating a "Testing Record" entry and updating the sample's status to "Testing": + +![Example_Inspection_Successful](https://static-docs.nocobase.com/20240509175247.png) + +And there you have it—a simple custom operation event. This approach can be similarly applied to other complex business operations, such as order processing or report submission, using custom operation events to achieve the desired results. diff --git a/docs/fr-FR/handbook/workflow-custom-action-trigger/http-api.md b/docs/fr-FR/handbook/workflow-custom-action-trigger/http-api.md new file mode 100644 index 000000000..a541bd1d4 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-custom-action-trigger/http-api.md @@ -0,0 +1,63 @@ +# HTTP API + +Custom action events can be triggered not only through user interface actions but also via HTTP API calls. Specifically, these events introduce a new operation type called `trigger` for all collection operations, allowing workflows to be initiated through the NocoBase standard operation API. + +For instance, a workflow typically triggered by a button can be invoked using the following command: + +```bash +curl -X POST -H 'Authorization: Bearer ' -H 'X-Role: ' \ + "http://localhost:3000/api/samples:trigger/<:id>?triggerWorkflows=workflowKey" +``` + +Since this operation targets a single data entry, when calling it for existing data, you must specify the ID of the data row by replacing the `<:id>` portion of the URL. + +When invoking the API for a form submission (such as adding or updating data), you can omit the ID for new entries but must provide the relevant data as the execution context: + +```bash +curl -X POST -H 'Authorization: Bearer ' -H 'X-Role: ' -d \ + '{ + "title": "Sample 1", + "indicator": 91 + }' + "http://localhost:3000/api/samples:trigger?triggerWorkflows=workflowKey" +``` + +For updating a form, you need to include both the data row ID and the updated data: + +```bash +curl -X POST -H 'Authorization: Bearer ' -H 'X-Role: ' -d \ + '{ + "title": "Sample 1", + "indicator": 91 + }' + "http://localhost:3000/api/samples:trigger/<:id>?triggerWorkflows=workflowKey" +``` + +If both the ID and data are provided, the specified data row will be loaded first, and then the provided data will overwrite the original row to generate the final trigger context. + +:::warning{title="Note"} +If relational data is provided, it will also be overwritten. Take special care when handling relational data with Preload associations to avoid unintentionally altering related data. +::: + +Additionally, the URL parameter `triggerWorkflows` designates the workflow key(s). Multiple workflows can be separated by commas. You can obtain this key by hovering over the workflow name at the top of the workflow canvas: + +![Workflow Key View Method](https://static-docs.nocobase.com/20240426135108.png) + +Once the call is successful, the custom operation event for the `samples` table will be triggered. + +:::info{title="Tip"} +Since external API calls also require user authentication, you must include authentication information in the request, similar to requests sent from the standard interface. This includes the `Authorization` header or `token` parameter (the token obtained after login) and the `X-Role` header (the user's current role name). +::: + +If you need to trigger an event for a many-to-one data item (currently not supported for many-to-many relationships), you can specify the related field’s trigger data using `!` in the parameter: + +```bash +curl -X POST -H 'Authorization: Bearer ' -H 'X-Role: ' \ + "http://localhost:3000/api/posts:trigger/<:id>?triggerWorkflows=workflowKey!category" +``` + +After a successful call, the custom operation event for the corresponding `categories` table will be triggered. + +:::info{title="Tip"} +When triggering an event via HTTP API, ensure that the workflow is enabled and that the collection configuration is correct. Otherwise, the call may fail or result in errors. +::: diff --git a/docs/fr-FR/handbook/workflow-custom-action-trigger/index.md b/docs/fr-FR/handbook/workflow-custom-action-trigger/index.md new file mode 100644 index 000000000..54ad90d94 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-custom-action-trigger/index.md @@ -0,0 +1,20 @@ +# Overview + + + +NocoBase provides built-in standard data operations like create, read, update, and delete. However, when these operations aren't sufficient to meet complex business requirements, custom action events within workflows can be utilized. These events can be linked to the "Trigger Workflow" button on page blocks, enabling you to perform custom data operations tailored to specific needs. + +:::info{title=Note} +The "Custom Action Event" evolved from the "Submit to Workflow" mode found in the "Post-Action Event" feature. As of version `v1.0.0-alpha.7`, it has been separated into its own event and renamed as "Custom Action Event." +::: + +## User Manual + +Custom action events are used in several key areas: + +- [Trigger Configuration](./trigger.md) +- [Action Configuration](./action.md) + +For practical examples of how to use these events, refer to the [Examples](./example.md) section. + +If integration with an external system is needed, consult the [Http Api](./http-api.md) guide. diff --git a/docs/fr-FR/handbook/workflow-custom-action-trigger/trigger.md b/docs/fr-FR/handbook/workflow-custom-action-trigger/trigger.md new file mode 100644 index 000000000..832bfd5ce --- /dev/null +++ b/docs/fr-FR/handbook/workflow-custom-action-trigger/trigger.md @@ -0,0 +1,23 @@ +# Trigger Configuration + +## Creating a Workflow + +When setting up a workflow, begin by selecting "Custom action event": + +![Creating "Custom Operation Event" Workflow](https://static-docs.nocobase.com/20240509091820.png) + +## Trigger Configuration + +### Data Table + +Since custom operation events are tied to specific data rows, you'll need to first choose the data table that will be associated with your data model: + +![Trigger Configuration_Select Data Table](https://static-docs.nocobase.com/20240509150515.png) + +### Related Data to Utilize + +If your workflow requires the use of related data from the triggered data row, you can select the necessary deep relationship fields here: + +![Trigger Configuration_Select Data Relations to Use](https://static-docs.nocobase.com/20240509154856.png) + +These fields will be automatically preloaded into the workflow's context once the event is triggered, making them available for use within the workflow. diff --git a/docs/fr-FR/handbook/workflow-date-calculation/index.md b/docs/fr-FR/handbook/workflow-date-calculation/index.md new file mode 100644 index 000000000..366704218 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-date-calculation/index.md @@ -0,0 +1,129 @@ +# Date Calculation + + + +The Date Calculation node offers a set of nine powerful functions, enabling operations such as adding or subtracting time periods, formatting time strings, and converting duration units. Each function is designed with specific input and output value types, and can seamlessly integrate the results from other nodes as parameter variables. By chaining these functions through a calculation pipeline, you can achieve the desired output with precision. + +## User Manual + +### Creating a Node + +To add a "Date Calculation" node in the workflow configuration interface, simply click the plus (“+”) button within the process: + +![Create Node for Date Calculation](https://static-docs.nocobase.com/[图片].png) + +### Node Configuration + +![Node Configuration for Date Calculation](https://static-docs.nocobase.com/20240817184423.png) + +#### Input Value + +Input values can be either variables or date constants. Variables might include data that triggers the workflow or results from upstream nodes. Constants can be any selected date. + +#### Input Value Type + +The input value type determines how the input will be processed and is categorized into two types: + +* **Date Type:** This includes any input that can be converted into a date-time format, such as numeric timestamps or strings representing time. +* **Number Type:** The input value type influences the selection of time calculation steps, so it’s crucial to choose the correct type. + +#### Calculation Steps + +Each calculation step consists of a specific function and its parameter configuration. The pipeline design allows the output of one function to feed directly into the next, enabling a sequence of time calculations and conversions. + +The output type after each step is fixed, which in turn determines the functions available for the next step. If the types are compatible, the calculation continues; if not, the result of the current step becomes the final output of the node. + +### Calculation Functions + +#### Add a range + +- **Accepted Input Value Type:** Date +- **Parameters:** + - The amount to add, which can be a numeric value or a variable from within the node. + - The time unit (e.g., days, hours). +- **Output Value Type:** Date +- **Example:** If the input value is `2024-7-15 00:00:00`, the amount is `1`, and the unit is "days," the output will be `2024-7-16 00:00:00`. + +#### Subtract a range + +- **Accepted Input Value Type:** Date +- **Parameters:** + - The amount to subtract, which can be a numeric value or a variable from within the node. + - The time unit (e.g., days, hours). +- **Output Value Type:** Date +- **Example:** If the input value is `2024-7-15 00:00:00`, the amount is `1`, and the unit is "days," the output will be `2024-7-14 00:00:00`. + +#### Get difference with another data value + +- **Accepted Input Value Type:** Date +- **Parameters:** + - The date for comparison, which can be a constant or a variable in the workflow context. + - The time unit (e.g., days, hours). + - Whether to take the absolute value. + - Rounding options: retain decimals, round off, round up, or round down. +- **Output Value Type:** Numeric +- **Example:** If the input value is `2024-7-15 00:00:00`, and you compare it with `2024-7-16 06:00:00`, using "days" as the unit, without taking the absolute value and retaining decimals, the output will be `-1.25`. + +:::info{title=Note} +If both absolute value and rounding are selected, the absolute value is applied first, followed by rounding. +::: + +#### Get value on specific unit of input date + +- **Accepted Input Value Type:** Date +- **Parameters:** + - The time unit (e.g., days, hours). +- **Output Value Type:** Numeric +- **Example:** If the input value is `2024-7-15 00:00:00` and the unit is "days," the output will be `15`. + +#### Set to time of unit start + +- **Accepted Input Value Type:** Date +- **Parameters:** + - The time unit (e.g., days, hours). +- **Output Value Type:** Date +- **Example:** If the input value is `2024-7-15 14:26:30` and the unit is "days," the output will be `2024-7-15 00:00:00`. + +#### Set to time of unit end + +- **Accepted Input Value Type:** Date +- **Parameters:** + - The time unit (e.g., days, hours). +- **Output Value Type:** Date +- **Example:** If the input value is `2024-7-15 14:26:30` and the unit is "days," the output will be `2024-7-15 23:59:59`. + +#### Is leap year + +- **Accepted Input Value Type:** Date +- **Parameters:** None +- **Output Value Type:** Boolean +- **Example:** If the input value is `2024-7-15 14:26:30`, the output will be `true`. + +#### Format to String + +- **Accepted Input Value Type:** Date +- **Parameters:** + - The format, as specified in [Day.js: Format](https://day.js.org/docs/zh-CN/display/format). +- **Output Value Type:** String +- **Example:** If the input value is `2024-7-15 14:26:30` and the format is `the time is YYYY/MM/DD HH:mm:ss`, the output will be `the time is 2024/07/15 14:26:30`. + +#### Convert unit + +- **Accepted Input Value Type:** Numeric +- **Parameters:** + - The original time unit. + - The target time unit. + - Rounding options: retain decimals, round off, round up, or round down. +- **Output Value Type:** Numeric +- **Example:** If the input value is `2`, the original unit is "weeks," the target unit is "days," and no decimals are retained, the output will be `14`. + +### Example + +![Example of Date Calculation Node](https://static-docs.nocobase.com/20240817184137.png) + +Imagine a promotional activity where you want to automatically set an end time for the promotion when a product is created. This end time would be the last day of the following week at 23:59:59. To achieve this, you can create two time functions and link them in a pipeline: + +1. Calculate the date for the following week. +2. Adjust the date to the last day of that week at 23:59:59. + +By doing this, you'll generate the desired time value, which can then be passed to the next node, such as a data table modification node, to set the promotion end time in the database. diff --git a/docs/fr-FR/handbook/workflow-delay/index.md b/docs/fr-FR/handbook/workflow-delay/index.md new file mode 100644 index 000000000..b19417f19 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-delay/index.md @@ -0,0 +1,37 @@ +# Delay + + + +The delay node allows you to introduce a pause within a workflow. Once the delay concludes, you can configure whether to proceed with the next step or terminate the workflow prematurely. + +This node is often used in tandem with parallel branch nodes. By adding a delay node to one of the branches, you can effectively manage timeouts. For example, in a scenario where one branch requires manual processing while another includes a delay node, you can determine the outcome if the manual process exceeds the allotted time. Selecting "timeout failure" means that the manual process must be completed within the specified timeframe. On the other hand, choosing "timeout continuation" allows the workflow to bypass the manual process once the delay has elapsed. + +## Installation + +This plugin is built-in and requires no installation. + +## User Manual + +### Creating a Node + +In the workflow configuration interface, click the plus sign ("+") within the flow to add a "Delay" node: + +![Create Delay Node](https://static-docs.nocobase.com/d0816999c9f7acaec1c409bd8fb6cc36.png) + +### Node Configuration + +![Delay Node Configuration](https://static-docs.nocobase.com/5fe8a36535f20a087a0148ffa1cd2aea.png) + +#### Delay Time + +You can specify the delay duration by entering a number and selecting a time unit. Supported units include seconds, minutes, hours, days, and weeks. + +#### Timeout Status + +You can set the timeout status to either "Succeed and continue" or "Fail and Exit." The "Succeed and continue" option ensures that the workflow progresses to the next steps after the delay ends. Conversely, the "Fail and Exit" option terminates the workflow with a failure status once the delay concludes. + +### Example + +In a scenario where a work order must be addressed within a certain timeframe, you can add a manual node to one branch and a delay node to the other in parallel branches. If the manual process fails to respond within 10 minutes, the work order status will be updated to "Timeout Unprocessed." + +![Delay Node Example - Workflow Organization](https://static-docs.nocobase.com/898c84adc376dc211b003a62e16e8e5b.png) diff --git a/docs/fr-FR/handbook/workflow-dynamic-calculation/collection.md b/docs/fr-FR/handbook/workflow-dynamic-calculation/collection.md new file mode 100644 index 000000000..d85332047 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-dynamic-calculation/collection.md @@ -0,0 +1,23 @@ +# Expression Collection + +## Creating an “Expression collection” Template + +Before utilizing dynamic expression operation nodes within a workflow, it's essential to first create an “Expression” template table using the data table management tool. This table serves as a repository for various expressions: + +![Creating an Expression Template Table](https://static-docs.nocobase.com/33afe3369a1ea7943f12a04d9d4443ce.png) + +## Entering Expression Data + +Following this, you can set up a table block and input several formula entries into the template table. Each row in the “Expression” template table can be viewed as a calculation rule designed for a specific data model within the table. You can utilize different fields from the data models of various tables as variables, crafting unique expressions as calculation rules. Moreover, you can leverage different calculation engines as needed. + +![Entering Expression Data](https://static-docs.nocobase.com/761047f8daabacccbc6a924a73564093.png) + +:::info{title=Tip} +Once the formulas are established, they need to be linked to the business data. Directly associating each row of business data with formula data can be tedious, so a common approach is to use a metadata table, similar to a classification table, to create a many-to-one (or one-to-one) relationship with the formula table. Then, the business data is associated with the classified metadata in a many-to-one relationship. This approach allows you to simply specify the relevant classified metadata when creating business data, making it easy to locate and utilize the corresponding formula data through the established association path. +::: + +## Loading Relevant Data into the Process + +As an example, consider creating a workflow triggered by a data table event. When an order is created, the trigger should preload the associated product data along with the product-related expression data: + +![Data Table Event_Trigger Configuration](https://static-docs.nocobase.com/f181f75b10007afd5de068f3458d2e04.png) diff --git a/docs/fr-FR/handbook/workflow-dynamic-calculation/example.md b/docs/fr-FR/handbook/workflow-dynamic-calculation/example.md new file mode 100644 index 000000000..dcc40f09a --- /dev/null +++ b/docs/fr-FR/handbook/workflow-dynamic-calculation/example.md @@ -0,0 +1,65 @@ +# Example + +Following the configuration steps outlined above, let's illustrate how to calculate the final price for different products by applying various Price Rules during the order placement process. + +1. Set Up the Product Collection: + + | Field Name | Type | + | -------------- | ---------------------- | + | Product Name | Text | + | Price | Number | + | Price Rule | `belongsTo` (Price Rule Collection) | + +2. Set Up the Price Rule Collection (using the expression Collection template): + + | Field Name | Type | + | --------------- | --------------------------- | + | Rule Name | Text | + | Collection | Single Select (Data Collection) | + | Calculation Engine | Single Select (mathjs/formulajs) | + | Expression | Text | + +3. Input Price Rules: + + | ID | Name | Collection | Calculation Engine | Expression | + | --- |---------| ---------- | ------------------ | ------------------------- | + | 1 | 80% off | Product | formula.js | `{{Product.Price}} * 0.8` | + | 2 | 90% off | Product | formula.js | `{{Product.Price}} * 0.9` | + +4. Create Products and Assign Price Rules: + + | ID | Product Name | Price | Price Rule | + | --- | ------------- | ----- | ------------- | + | 1 | iPhone 14 Pro | 7999 | 2 | + | 2 | iPhone 13 Pro | 6999 | 1 | + +5. Set Up a Workflow Triggered by Order Creation: + + ![Trigger_CreateOrder](https://static-docs.nocobase.com/f181f75b10007afd5de068f3458d2e04.png) + +6. Create a Dynamic Expression Calculation Node and Configure it Using Trigger Data/Product/Price Rule: + + ![SelectDynamicExpressionData](https://static-docs.nocobase.com/21ccc63e604dd90b7d26c3c33c12d671.png) + + Set the variable data source to the product in the trigger data: + + ![SelectVariableDataSource](https://static-docs.nocobase.com/afbffe9661539d26e4b175ae8a4b28f7.png) + +7. Add a Data Update Node to Update the Order Total Price with the Result from the Calculation Node: + + ![UpdateOrderData](https://static-docs.nocobase.com/5cc7ffb113c8d6a2fd3b1b34abe06dcc.png) + +8. Trigger the Workflow Upon Order Creation and Verify the Prices in the Order List: + + | Order Product | Price | Price Rule | Total Price | + | ---------------- | -------------- |----------------|----------------------| + | iPhone 14 Pro | 7999 | Rule1: 90% off | 7999 \* 0.9 = 7199.1 | + | iPhone 13 Pro | 6999 | Rule2: 80% off | 6999 \* 0.8 = 5599.2 | + + The final price displayed in the image below should match the calculated price in the Collection above: + + ![OrderTotalPrice_AfterCreation](https://static-docs.nocobase.com/a5610aca292e79c4841c97457bd3cc7c.png) + + :::info{title=Tip} + Since the workflow operates asynchronously, the total price might not be immediately reflected in the Collection after the order is created. You may need to wait a moment before refreshing the page to see the updated total price. + ::: diff --git a/docs/fr-FR/handbook/workflow-dynamic-calculation/index.md b/docs/fr-FR/handbook/workflow-dynamic-calculation/index.md new file mode 100644 index 000000000..f56edc8d7 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-dynamic-calculation/index.md @@ -0,0 +1,20 @@ +# Overview + + + +Dynamic Calculation nodes stand out from Operator nodes by allowing diverse calculations based on data-associated expressions. While traditional formula fields are limited to applying a single fixed formula across all data rows, Dynamic calculation solve this limitation by enabling workflows to handle different calculation methods for varying data rows. + +For example, different product categories in order data may require distinct statistical formulas to compute specific report data. + +## Installation + +This plugin comes pre-installed and does not require any additional setup. + +## User Manual + +Using dynamic expressions involves several key sections: + +- ["Expression" Template Table](./collection.md) +- [Node](./node.md) + +For practical examples, refer to the [Examples](./example.md) section. diff --git a/docs/fr-FR/handbook/workflow-dynamic-calculation/node.md b/docs/fr-FR/handbook/workflow-dynamic-calculation/node.md new file mode 100644 index 000000000..5f2ac803a --- /dev/null +++ b/docs/fr-FR/handbook/workflow-dynamic-calculation/node.md @@ -0,0 +1,23 @@ +# Node Configuration + +## Creating a Node + +Create a dynamic calculation node: + +![Creating a Dynamic Calculation Node](https://static-docs.nocobase.com/14613f73a7dfc822a30276c8c04cdeb7.png) + +## Node Configuration + +## Calculation Expression + +Unlike the expression options in a standard calculation node, dynamic expressions must be selected based on preloaded data rather than directly inputting the expression. Choose the preloaded product discount rule data from the trigger: + +![Select Dynamic Expression Data](https://static-docs.nocobase.com/21ccc63e604dd90b7d26c3c33c12d671.png) + +### Variable Data Source + +You also need to select the data row object from the table to be used as a variable in the expression. This can be chosen from the workflow context, where results have been preloaded or queried. The object must be a data row from the table associated with the expression data. In this case, select the product data: + +![Select Variable Data Source](https://static-docs.nocobase.com/afbffe9661539d26e4b175ae8a4b28f7.png) + +Saving the node configuration completes the entire setup process. diff --git a/docs/fr-FR/handbook/workflow-javascript/index.md b/docs/fr-FR/handbook/workflow-javascript/index.md new file mode 100644 index 000000000..3f231789e --- /dev/null +++ b/docs/fr-FR/handbook/workflow-javascript/index.md @@ -0,0 +1,122 @@ +# JavaScript + + + +The JavaScript node allows users to execute custom Node.js scripts within a workflow. These scripts can utilize upstream workflow variables as parameters and return values that subsequent nodes can use. + +The script supports most Node.js features but has some differences from the native execution environment. See the [Feature List](#feature-list) for details. + +## User Manual + +### Creating a Node + +In the workflow configuration interface, click the plus (“+”) button in the workflow to add a “Script” node: + +![20241007122632](https://static-docs.nocobase.com/20241007122632.png) + +### Node Configuration + +![20241007122825](https://static-docs.nocobase.com/20241007122825.png) + +#### Parameters + +Use parameters to pass variables or static values from the workflow context into the script, making them accessible in the script logic. `name` represents the parameter name, which will serve as the variable name in the script. `value` represents the parameter value, which can be a workflow variable or a constant. + +#### Script Content + +The script content functions as a single function where you can write any JavaScript code supported by the Node.js environment. Use the `return` statement to provide a value as the node's output, making it available as a variable for downstream nodes. + +After writing the script, use the test button below the editor to open a test execution dialog. Populate parameters with static values for simulation. The dialog displays the return value and output (logs) after execution. + +![20241007153631](https://static-docs.nocobase.com/20241007153631.png) + +#### Timeout Setting + +Set the timeout in milliseconds. A value of `0` means no timeout. + +#### Continue Workflow on Error + +If enabled, the workflow will continue even if the script encounters an error or timeout. + +:::info{title="Note"} +When a script fails, it will not return a value, and the node's output will contain the error message. If subsequent nodes use the result variable from this script node, handle it carefully. +::: + +## Feature List + +### Node.js Version + +The Node.js version matches the version used by the main application. + +### Module Support + +The script allows restricted use of modules, adhering to the CommonJS standard. Use the `require()` directive to import modules in your code. + +It supports Node.js native modules and modules installed in `node_modules` (including dependencies used by NocoBase). To make modules available in the code, declare them in the application environment variable `WORKFLOW_SCRIPT_MODULES`. Separate multiple module names with commas, e.g.: + +```ini +WORKFLOW_SCRIPT_MODULES=crypto,timers,lodash,dayjs +``` + +:::info{title="Note"} +Modules not declared in `WORKFLOW_SCRIPT_MODULES`, including native Node.js modules or installed `node_modules`, **cannot** be used in scripts. This strategy allows administrators to control the modules accessible to users, reducing the risk of excessive script permissions. +::: + +### Global Variables + +Global variables such as `global`, `process`, `__dirname`, and `__filename` are **not supported**. + +```js +console.log(global); // will throw error: "global is not defined" +``` + +### Input Parameters + +Parameters configured in the node are treated as global variables in the script and can be used directly. Only basic types such as `boolean`, `number`, `string`, `object`, and arrays are supported. `Date` objects are converted to ISO-formatted strings when passed. Other complex types, such as custom class instances, cannot be directly passed. + +### Return Values + +Use the `return` statement to return data of basic types (same as parameter rules) to the node as its output. If the code does not contain a `return` statement, the node will have no output value. + +```js +return 123; +``` + +### Output (Logs) + +**Supports** logging via `console`. + +```js +console.log('hello world!'); +``` + +The script node’s output will also be recorded in the corresponding workflow’s log files. + +### Asynchronous Operations + +**Supports** asynchronous functions using `async` and `await`. It also **supports** the global `Promise` object. + +```js +async function test() { + return Promise.resolve(1); +} + +const value = await test(); +return value; +``` + +### Timers + +To use methods like `setTimeout`, `setInterval`, or `setImmediate`, import them from the Node.js `timers` package. + +```js +const { setTimeout, setInterval, setImmediate, clearTimeout, clearInterval, clearImmediate } = require('timers'); + +async function sleep(time) { + return new Promise((resolve) => setTimeout(resolve, time)); +} + +await sleep(1000); + +return 123; +``` diff --git a/docs/fr-FR/handbook/workflow-json-query/index.md b/docs/fr-FR/handbook/workflow-json-query/index.md new file mode 100644 index 000000000..50ce15abf --- /dev/null +++ b/docs/fr-FR/handbook/workflow-json-query/index.md @@ -0,0 +1,138 @@ +# JSON query + + + +This plugin is designed to parse complex JSON data generated by various nodes, enabling subsequent nodes to effectively utilize this data. For instance, SQL operations and HTTP request nodes often return results in JSON format. The JSON query node allows you to transform this data into the specific values and variable formats required by later stages in the workflow. + +## User Manual + +### Creating a Node + +To add a “JSON query” node in the workflow configuration interface, simply click the plus (“+”) button within the process: + +![Creating a Node](https://static-docs.nocobase.com/7de796517539ad9dfc88b7160f1d0dd7.png) + +:::info{title=Tip} +JSON query nodes are generally positioned beneath other data nodes to facilitate parsing their output. +::: + +### Node Configuration + +#### Parsing Engine + +The JSON query node offers support for various parsing engines, each with its own unique syntax. You can select an engine based on your specific needs and preferences. Currently, three parsing engines are available: + +- [JMESPath](https://jmespath.org/) +- [JSONPath Plus](https://jsonpath-plus.github.io/JSONPath/docs/ts/) +- [JSONata](https://jsonata.org/) + +![Parsing Engine Selection](https://static-docs.nocobase.com/29be3b92a62b7d20312d1673e749f2ec.png) + +#### Data Source + +The data source can be either the output of an upstream node or a data object within the process context. This is typically an unstructured data object, such as the results from an SQL node or an HTTP request node. + +![Data Source](https://static-docs.nocobase.com/f5a97e20693b3d30b3a994a576aa282d.png) + +:::info{title=Tip} +Data objects related to data tables are usually already structured through table configuration information and do not typically require parsing by a JSON query node. +::: + +#### Parsing Expression + +You can create a custom parsing expression based on your specific needs and the parsing engine you’ve selected. + +![Parsing Expression](https://static-docs.nocobase.com/181abd162fd32c09b62f6aa1d1cb3ed4.png) + +:::info{title=Tip} +Different parsing engines use different syntaxes; refer to the linked documentation for detailed information. +::: + +As of version `v1.0.0-alpha.15`, expressions now support the use of variables. These variables are pre-parsed before the specific engine executes, replacing the variables with the corresponding string values according to string template rules and merging them with other static elements in the expression. This feature is particularly valuable when dynamically constructing expressions, such as when parsing JSON content that requires dynamic keys. + +#### Properties mapping + +When the parsed result is an object (or an array of objects), you can use properties mapping to convert the desired attributes into sub-variables for use by subsequent nodes. + +![properties mapping](https://static-docs.nocobase.com/b876abe4ccf6b4709eb8748f21ef3527.png) + +:::info{title=Tip} +For object (or array of objects) results, if you do not perform properties mapping, the entire object (or array of objects) will be stored as a single variable in the node's result, making it impossible to directly access the object's attribute values as individual variables. +::: + +### Example + +Suppose you need to parse data from an SQL node that returns a set of order data: + +```json +[ + [ + { + "id": 1, + "products": [ + { + "id": 1, + "title": "Product 1", + "price": 100, + "quantity": 1 + }, + { + "id": 2, + "title": "Product 2", + "price": 120, + "quantity": 2 + } + ] + }, + { + "id": 2, + "products": [ + { + "id": 3, + "title": "Product 3", + "price": 130, + "quantity": 1 + }, + { + "id": 4, + "title": "Product 4", + "price": 140, + "quantity": 2 + } + ] + } + ] +] +``` + +:::info{title=Tip} +The outer array in the code above is intentional; it reflects the typical output of an SQL node. This is because the SQL node’s result is a binary array, where the first element contains the query results and the second element contains metadata about the query. +::: + +If you need to parse and calculate the total price for each order and assemble this data into an object with the corresponding order ID, ready to update the order's total price, you would configure it as follows: + +![Example - SQL Parsing Configuration](https://static-docs.nocobase.com/e62322a868b26ff98120bfcd6dcdb3bd.png) + +1. Select the JSONata parsing engine; +2. Choose the SQL node’s result as the data source; +3. Use the JSONata expression `$[0].{"id": id, "total": products.(price * quantity)}` for parsing; +4. Choose properties mapping to map `id` and `total` as sub-variables; + +The final parsed result would look like this: + +```json +[ + { + "id": 1, + "total": 340 + }, + { + "id": 2, + "total": 410 + } +] +``` + +You can then iterate over the array of completed orders to update the total price of each order. + +![Update the Corresponding Order’s Total Price](https://static-docs.nocobase.com/b3329b0efe4471f5eed1f0673bef740e.png) diff --git a/docs/fr-FR/handbook/workflow-loop/index.md b/docs/fr-FR/handbook/workflow-loop/index.md new file mode 100644 index 000000000..8ecb7e3bf --- /dev/null +++ b/docs/fr-FR/handbook/workflow-loop/index.md @@ -0,0 +1,113 @@ +## Loop + + + +The loop functions in a manner akin to `for`, `while`, or `forEach` constructs in programming languages. It’s designed for situations where you need to repeat certain operations a specific number of times or iterate over a dataset (such as an array). The loop node is your go-to tool for such tasks. + +## Installation + +This plugin comes pre-installed, so no additional setup is necessary. + +## User Manual + +### Creating Node + +In the workflow configuration interface, you can add a "Loop" node by clicking the plus sign ("+") in the process: + +![Creating a Loop Node](https://static-docs.nocobase.com/b3c8061a66bfff037f4b9509ab0aad75.png) + +Once you create the loop node, an internal branch specifically for the loop is generated. You can then populate this branch with any number of nodes. These nodes will have access to not only the workflow context variables but also the local variables defined within the loop context—such as the current data object or the iteration index (which starts at `0`). These local variables are scoped exclusively to the loop. For nested loops, you can use variables specific to each loop level. + +### Node Configuration + +![20241016135326](https://static-docs.nocobase.com/20241016135326.png) + +#### Loop Object + +The loop node can handle various data types for the loop object, each in a different way: + +1. **Array**: This is the most common use case. Typically, you'll select a workflow context variable, such as the results from a query node or preloaded data from a many-to-many relationship. If an array is selected, the loop node will iterate over each element, assigning the current element to a local variable within the loop context for each iteration. + +2. **Number**: When the loop object is a number, it’s treated as the number of iterations. The index within the local variable will match the loop object’s value. + +3. **String**: If the loop object is a string, the loop will iterate according to the string's length, processing each character by its index. + +4. **Others**: Other data types (including objects) are treated as a single loop object, resulting in just one iteration—typically not requiring a loop. + +You can also input constants directly when working with numbers and strings. For instance, inputting `5` (number type) will cause the loop to run 5 times, while inputting `abc` (string type) will result in 3 iterations, processing `a`, `b`, and `c` individually. The variable selection tool allows you to choose the type of constant you want to use. + +#### Loop condition + +From version `v1.4.0-beta` on, loop condition options are added, and could be enabled in node configuration. + +**Condition** + +Similar to the configuration in a condition node, combination of conditions can be configured, and variables from the current loop, such as the loop item and loop index, can also be used. + +**Checkpoint** + +Similar to `while` and `do/while` in programming languages, conditions can be configured to be evaluated either before each loop iteration or after it ends. Post-condition evaluation can execute other nodes in the loop body first before performing the condition check. + +**When condition is not met** + +Similar to `break` and `continue` clause in programming languages, could be use to determine whether to break or continue the loop. + +#### Error handling of internal nodes in loop + +From version `v1.4.0-beta` on, when an internal node in a loop fails to execute (due to unmet conditions, errors, etc.), the next step can be determined through this configuration. Three handling methods are supported: + +* Exit the process (default) +* Exit the loop and continue the process +* Continue to the next loop item + +You can choose the appropriate method as needed. + +### Example + +Consider the following scenario: when placing an order, you need to check the inventory of each product in the order. If the inventory is sufficient, the stock is deducted; otherwise, the product in the order details is marked as invalid. + +1. Create three collections: Product <-(1:m)-- Order Details --(m:1)-> Order , with the following data model: + +| Field Name | Field Type | +| -------------- | ----------------- | +| Order Details | Many-to-One (Details) | +| Total Price | Number | + +| Field Name | Field Type | +| ---------- | ----------------- | +| Product | One-to-Many (Product) | +| Quantity | Number | + +| Field Name | Field Type | +| ----------- | ----------- | +| Product Name | Single-line Text | +| Price | Number | +| Inventory | Integer | + +2. Create a workflow, selecting "Collection event" as the trigger, and choose the "Order" table with "Create record" as the trigger. Additionally, preload relationship data from the "Order Details" table and the Product Table under details: + +![Loop Node Example Trigger Configuration](https://static-docs.nocobase.com/0086601c2fc0e17a64d046a4c86b49b7.png) + +3. Create a loop node, selecting the loop object as "Trigger Data / Order Details," which loops through each record in the order details table: + +![Loop Node Example Loop Node Configuration](https://static-docs.nocobase.com/2507becc32db5a9a0641c198605a20da.png) + +4. Inside the loop node, create a "Condition" node to check if the product inventory is sufficient: + +![Loop Node Example Condition Node Configuration](https://static-docs.nocobase.com/a6d08d15786841e1a3512b38e4629852.png) + +5. If the inventory is sufficient, create a "Calculation" and an "Update record" node under the "Yes" branch to update the inventory after deduction: + +![Loop Node Example Calculation Node Configuration](https://static-docs.nocobase.com/8df3604c71f8f8705b1552d3ebfe3b50.png) + +![Loop Node Example Update Inventory Node Configuration](https://static-docs.nocobase.com/2d84baa9b3b01bd85fccda9eec992378.png) + +6. If the inventory is insufficient, create an "Update record" node under the "No" branch to update the status of the order detail to "Invalid": + +![Loop Node Example Update Order Details Node Configuration](https://static-docs.nocobase.com/4996613090c254c69a1d80f3b3a7fae2.png) + +The complete process structure is illustrated below: + +![Loop Node Example Process Structure](https://static-docs.nocobase.com/6f59ef246c1f19976344a7624c4c4151.png) + +After configuration and activation of this workflow, every time a new order is created, the system will automatically check the inventory of each product in the order. If sufficient inventory is available, the stock will be deducted; otherwise, the product in the order details will be marked as invalid (helping to calculate the valid total order price). diff --git a/docs/fr-FR/handbook/workflow-manual/block.md b/docs/fr-FR/handbook/workflow-manual/block.md new file mode 100644 index 000000000..90251ee9c --- /dev/null +++ b/docs/fr-FR/handbook/workflow-manual/block.md @@ -0,0 +1,19 @@ +# Todo Block + +To facilitate manual processing, a todo list should be added to the page. This list will display tasks that require attention, allowing relevant personnel to easily access and manage specific tasks within the manual node. + +## Adding Blocks + +To add a todo list block, select "Workflow Todo" from the available blocks on the page: + +![Add Todo Block for Manual Node](https://static-docs.nocobase.com/198b417454cd73b704267bf30fe5e647.png) + +Here is an example of a todo list block: + +![Todo List Example](https://static-docs.nocobase.com/cfefb0d2c6a91c5c9dfa550d6b220f34.png) + +## Todo Details + +Personnel can click on the relevant todo task to open a pop-up window for manual processing: + +![Todo Details](https://static-docs.nocobase.com/ccfd0533deebff6b3f6ef4408066e688.png) diff --git a/docs/fr-FR/handbook/workflow-manual/example.md b/docs/fr-FR/handbook/workflow-manual/example.md new file mode 100644 index 000000000..7350898e2 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-manual/example.md @@ -0,0 +1,85 @@ +# Example + +### Article Review + +Imagine a scenario where a regular user submits an article. Before this article can be published, it must be reviewed and approved by an administrator. If the article does not pass this review process, it will remain in draft form, unpublished. This entire workflow can be implemented using an "Update Form" node within a manual process. + +To start, create a workflow that is triggered by the action "Add Article" and then add a manual node to it: + +
    + Manual Node Example Article Review Workflow +
    + +Within this manual node, assign the responsibility to an administrator. Next, in the configuration interface, add a block that displays the details of the newly added article based on the trigger data: + +
    + Manual Node Example Article Review Node Configuration Details Block +
    + +Following this, add a block that utilizes the "Update Data Form" in the configuration interface. This block should be linked to the article table, allowing the administrator to decide whether the article should be approved. Once the form is added, a "Continue the process" button will be automatically generated, signaling approval if clicked. Additionally, you should add a "Terminate the process" button to handle cases where the article is rejected: + +
    + Manual Node Example Article Review Node Configuration Form and Actions +
    + +When the process continues, the status of the article will need to be updated. There are two primary ways to handle this. The first method involves displaying the article's status field directly within the form, giving the operator the choice. This method is particularly useful for scenarios where the form requires active input, such as providing feedback: + +
    + Manual Node Example Article Review Node Configuration Form Fields +
    + +For a more streamlined process, you can instead configure the form's field values directly on the "Continue the process" button. Here, you would add a "Status" field with the value set to "Published," ensuring that once the operator clicks the button, the article will be automatically updated to a published status: + +
    + Manual Node Example Article Review Node Configuration Form Assignment +
    + +Next, from the configuration menu at the top right of the form block, select the conditions that will filter the data to be updated. In this case, you would choose the "Article" table and set the filter condition as "ID equals Trigger Variables / Trigger Data / ID": + +
    + Manual Node Example Article Review Node Configuration Form Conditions +
    + +Finally, to enhance user-friendliness, you can customize the titles of the various blocks, the text on the buttons, and the placeholder text within the form fields: + +
    + Manual Node Example Article Review Node Configuration Final Form +
    + +After completing these steps, close the configuration panel and click the submit button to save the node configuration. Your workflow is now complete. Once this workflow is enabled, whenever a new article is added, it will automatically trigger the workflow. The administrator will then see this task in their to-do list. Upon clicking to view, the task details will be displayed: + +
    + Manual Node Example Article Review Task List +
    + +
    + Manual Node Example Article Review Task Details +
    + +Based on the article details, the administrator can then decide whether the article should be published. If approved, clicking the "Pass" button will update the article to a published status. If rejected, clicking the "Reject" button will ensure that the article remains in draft status. + +### Leave Approval + +Now, consider a scenario where an employee needs to request leave. This leave request must be approved by a supervisor before it can take effect, and the corresponding leave data for the employee will be adjusted accordingly. Regardless of whether the request is approved or rejected, a notification SMS will be sent to the employee using a request node (as detailed in the [HTTP Request](#_HTTP_Request) section). This process can be efficiently managed using a custom form within a manual node. + +Start by creating a workflow triggered by "Add Leave Request" and then add a manual node, similar to the article review process. However, in this case, the responsible person is the supervisor. Add a block based on the trigger data in the configuration interface to display the details of the newly submitted leave request. Then, add a block based on a custom form where the supervisor can decide whether to approve the request. This custom form should include fields for the approval status and reasons for rejection: + +
    + Manual Node Example Leave Approval Node Configuration +
    + +Unlike the article review process, because subsequent steps depend on the supervisor's decision, only a "Continue Process" button is configured here for submission purposes, omitting the "Terminate Process" button. + +Additionally, after the manual node, a condition node can be added to determine whether the supervisor approved the leave request. In the approved branch, you would add a data processing node to adjust the leave data, and after the branch ends, include a request node to send an SMS notification to the employee. This would complete the process as shown below: + +
    + Manual Node Example Leave Approval Workflow Arrangement +
    + +The condition node should be configured with the following criteria: "**Node result / Supervisor / Process form / Approval** equals '**Approved**'": + +
    + Manual Node Example Leave Approval Condition Judgment +
    + +The data within the request node can be tailored using the corresponding form variables from the manual node, allowing for different SMS content based on whether the request was approved or rejected. With this configuration, the workflow is now complete. Once the workflow is activated, supervisors can manage leave requests directly from their to-do tasks, with actions similar to those in the article review process. diff --git a/docs/fr-FR/handbook/workflow-manual/index.md b/docs/fr-FR/handbook/workflow-manual/index.md new file mode 100644 index 000000000..067553276 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-manual/index.md @@ -0,0 +1,20 @@ +# Overview + + + +When a business process cannot be fully automated, a manual node can be implemented to transfer part of the decision-making authority to a human operator. + +Upon reaching a manual node, the process will pause and generate a task for the assigned user. Based on the status selected by the user during submission, the process will either resume, remain on hold, or be terminated. This functionality is particularly valuable in scenarios requiring process approval. + +## Installation + +This is a built-in plugin, requiring no installation. + +## User Manual + +The use of manual nodes is divided into two parts: + +- [Node Configuration](./node.md) +- [ToDo Block](./block.md) + +For further insight into practical applications, you can refer to the [Examples](./example.md) section. diff --git a/docs/fr-FR/handbook/workflow-manual/node.md b/docs/fr-FR/handbook/workflow-manual/node.md new file mode 100644 index 000000000..bb093ab84 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-manual/node.md @@ -0,0 +1,79 @@ +# Manual Node + +## Creating a Node + +In the workflow configuration interface, click the plus (“+”) button within the process to add a "Manual" node: + +![Create Manual Node](https://static-docs.nocobase.com/4dd259f1aceeaf9b825abb4b257df909.png) + +## Configuring the Node + +### Assignees + +A manual node requires assigning a user who will be responsible for executing the pending task. You can add a list of pending tasks when setting up blocks on the page. Additionally, the content of each node's task pop-up window needs to be configured within the node’s interface. + +You can either select a specific user or use variables to choose the primary or foreign key of user data from the context. + +![Manual Node Configuration - Assignee Variable Selection](https://static-docs.nocobase.com/22fbca3b8e21fda3a831019037001445.png) + +:::info{title=Note} +At present, the assignee option for manual nodes does not support multi-user processing, though this feature is planned for future versions. +::: + +### Configuring the User Interface + +The interface setup for the to-do list is central to configuring the manual node. By clicking the “Configure” button, you can open a separate pop-up window for configuration. This interface works like a regular page, allowing you to design it using a WYSIWYG (What You See Is What You Get) editor: + +![Manual Node Configuration - User Interface Configuration](https://static-docs.nocobase.com/fd360168c879743cf22d57440cd2590f.png) + +#### Tabs + +Tabs can be utilized to differentiate between various content types. For example, one tab might be used for approved form submissions, another for rejected submissions, or you might use them to display details of related data. These tabs can be configured freely according to your needs. + +#### Blocks + +The blocks you can use primarily fall into two categories: Data Blocks and Form Blocks. In addition, Markdown blocks are available for informational prompts and other static content. + +##### Data Blocks + +Data blocks allow you to display information from triggers or the results of any node processing, providing necessary context for the task assignee. For example, if the workflow is triggered by a form event, a data block can be created to show the details of the triggered data. This setup is similar to configuring details on a regular page, where you can select any fields from the triggered data for display: + +![Manual Node Configuration - Data Block - Trigger](https://static-docs.nocobase.com/675c3e58a1a4f45db310a72c2d0a404c.png) + +Similarly, node data blocks can be configured to display data results from upstream nodes as reference information for the task assignee. For example, if an upstream calculation node generates results, these can be displayed as contextual data: + +![Manual Node Configuration - Data Block - Node Data](https://static-docs.nocobase.com/a583e26e508e954b47e5ddff80d998c4.png) + +:::info{title=Note} +Since the workflow is in a non-executing state during interface configuration, data blocks won’t display specific data. The relevant data will only appear in the to-do pop-up interface once the workflow is triggered and executed. +::: + +##### Form Blocks + +Form blocks are crucial in the to-do interface, as they determine whether the workflow continues. Failing to configure a form block will cause the workflow to halt. There are three types of form blocks available: + +- Custom Form +- Create record form +- Update record form + +![Manual Node Configuration - Form Block Types](https://static-docs.nocobase.com/2d068f3012ab07e32a265405492104a8.png) + +For Create record forms and Update record forms, you'll need to select the data table they are based on. When the assignee submits the form, the values entered will be used to add or update data in the selected table. The Custom Form allows you to create a temporary form not linked to any data table, with the submitted values available for use in subsequent nodes. + +You can configure the form submission button with one of three options: + +- Continue the process +- Terminate the process +- Save temporarily + +![Manual Node Configuration - Form Button Types](https://static-docs.nocobase.com/6b45995b14152e85a821dff6f6e3189a.png) + +These three button options correspond to different node states in the workflow: "Complete," "Reject," or "Waiting." At least one of the first two options must be configured to determine how the workflow proceeds. + +On the "Continue the process" button, you can configure specific values for form fields: + +![Manual Node Configuration - Set Form Values](https://static-docs.nocobase.com/2cec2d4e2957f068877e616dec3b56dd.png) + +![Manual Node Configuration - Set Form Values Pop-up](https://static-docs.nocobase.com/5ff51b60c76cdb76e6f1cc95dc3d8640.png) + +In the pop-up window, you can assign values to any field in the form. Once the form is submitted, these values will be used as the final values for those fields. This feature is particularly useful when reviewing data. You can configure multiple "Continue the process" buttons in the form, each setting different enumeration values for similar fields, allowing the workflow to continue with varying outcomes based on these values. diff --git a/docs/fr-FR/handbook/workflow-parallel/index.md b/docs/fr-FR/handbook/workflow-parallel/index.md new file mode 100644 index 000000000..f0edef7df --- /dev/null +++ b/docs/fr-FR/handbook/workflow-parallel/index.md @@ -0,0 +1,35 @@ +# Parallel Branches + +Parallel branch nodes enable the division of a process into multiple branches, each configurable with distinct nodes. Depending on the selected mode of the branch, the execution approach varies. When multiple operations need to be carried out simultaneously, the parallel branch node proves highly effective. + +## Installation + +This feature is a built-in plugin, so no installation is necessary. + +## User Manual + +### Creating a Node + +In the workflow configuration interface, click the plus (“+”) button to add a "Parallel Branch" node to the process: + +![Parallel Branch_Add](https://static-docs.nocobase.com/9e0f3faa0b9335270647a30477559eac.png) + +Once a parallel branch node is added to the process, it will automatically create two sub-branches by default. You can add more branches by clicking the appropriate button. Each branch can include as many nodes as needed, and unnecessary branches can be removed by clicking the delete button at the start of the branch. + +![Parallel Branch_Branch Management](https://static-docs.nocobase.com/36088a8b7970c8a1771eb3ee9bc2a757.png) + +### Node Configuration + +#### Branch Modes + +Parallel branch nodes offer three modes: + +- **All succeeded**: The process continues to execute nodes following the branches only if all branches succeed. If any branch terminates early—whether due to failure, error, or any non-success state—the entire parallel branch node terminates in that state. This is also referred to as "All Mode." +- **Any succeeded**: The process will proceed to execute subsequent nodes once any branch succeeds. The entire parallel branch node will only terminate early if all branches fail or terminate prematurely, regardless of the reason. This is known as "Any Mode." +- **Any succeeded or failed**: The process will continue executing subsequent nodes once any branch succeeds. However, if any branch fails, the entire parallel branch node will terminate early in that state. This is also known as "Race Mode." + +In all modes, branches are executed sequentially from left to right. The process continues executing subsequent nodes or terminates early once the conditions of the selected mode are met. + +### Example + +Refer to the example provided in the [Delay Node](/handbook/workflow-delay#示例) section. diff --git a/docs/fr-FR/handbook/workflow-request-interceptor/action.md b/docs/fr-FR/handbook/workflow-request-interceptor/action.md new file mode 100644 index 000000000..40db1d4e8 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-request-interceptor/action.md @@ -0,0 +1,13 @@ +# Action Configuration + +If you set the trigger configuration to "Triggered only when a form bound to this workflow is submitted", you must return to the form interface and bind the workflow to the appropriate action button: + +![Binding Workflow to New Order](https://static-docs.nocobase.com/bae3931e60f9bcc51bbc222e40e891e5.png) + +In the workflow binding configuration, select the relevant workflow. Typically, choosing "Entire Form Data" as the context for triggering data is sufficient: + +![Select Workflow to Bind](https://static-docs.nocobase.com/78e2f023029bd570c91ee4cd19b7a0a7.png) + +:::info{title=Note} +Currently, buttons bound to pre-action events only support the "Submit" (or "Save"), "Update records," and "Delete" buttons in forms for new entries or updates. The "Trigger Workflow" button is not supported (this button can only be bound to post-action events). +::: diff --git a/docs/fr-FR/handbook/workflow-request-interceptor/advanced.md b/docs/fr-FR/handbook/workflow-request-interceptor/advanced.md new file mode 100644 index 000000000..5a220866f --- /dev/null +++ b/docs/fr-FR/handbook/workflow-request-interceptor/advanced.md @@ -0,0 +1,42 @@ +# Advanced Understanding + +**Conditions for Interception** + +In "pre-action events," two specific conditions may cause the corresponding operation to be intercepted: + +1. The process reaches an "End Process" node. As explained earlier, if the triggering data does not meet the conditions set in the "Condition" node, the process will follow the "No" branch, executing the "End Process" node. This causes the process to terminate, and the requested operation is intercepted. +2. Any node within the process fails to execute—whether due to an error or other exceptional circumstances. In such cases, the process concludes with the corresponding status, and the operation is intercepted. For instance, if an "HTTP Request" is used to fetch external data and the request fails, the process ends in a failed state, simultaneously intercepting the corresponding operation request. + +Once these interception conditions are met, the operation in question is halted entirely. For example, if an order submission is intercepted, no corresponding order data will be generated. + +**Parameters for Corresponding Operations** + +In "pre-action event" workflows, various data points are available as variables within the process, depending on the operation: + +| Operation Type \\ Variable | "User acted" | "Role of user acted" | Operation Parameter: "ID" | Parameter: "Values submitted" | +| -------------------------- | ---------- | -------------------------- | ------------------------- | -------------------------------------------- | +| Create a record | ✓ | ✓ | - | ✓ | +| Update a record | ✓ | ✓ | ✓ | ✓ | +| Delete one or more records | ✓ | ✓ | ✓ | - | + +:::info{title=Tip} +The variables "Trigger variables / Parameter / Values submitted" in pre-action events are not the actual data stored in the database but the parameters submitted with the operation. To retrieve actual database data, you must use the "Query record" node within the process. + +Additionally, for delete operations, when dealing with a single record, the "ID" in the operation parameters is a simple value. For multiple records, however, the "ID" is an array. +::: + +**Response Messages** + +Once the trigger is configured, you can define the relevant logic within the workflow. Typically, the "Condition" node's branching mechanism is used to decide whether to "End Process" based on specific business conditions, returning a pre-defined "Response Message": + +![Interception Process Configuration](https://static-docs.nocobase.com/cfddda5d8012fd3d0ca09f04ea610539.png) + +At this stage, the workflow configuration is complete. You can test it by submitting data that does not meet the configured conditions, triggering the interception logic. This will result in the return of a response message: + +![Error Response Message](https://static-docs.nocobase.com/06bd4a6b6ec499c853f0c39987f63a6a.png) + +**Response Message Status** + +If the "End Process" node is set to exit with a "Success" status and the process reaches this node, the operation request will still be intercepted. However, the returned response message will display a "Success" (instead of "Error") status: + +![Success Status Response Message](https://static-docs.nocobase.com/9559bbf56067144759451294b18c790e.png) diff --git a/docs/fr-FR/handbook/workflow-request-interceptor/example.md b/docs/fr-FR/handbook/workflow-request-interceptor/example.md new file mode 100644 index 000000000..68a65bdcc --- /dev/null +++ b/docs/fr-FR/handbook/workflow-request-interceptor/example.md @@ -0,0 +1,21 @@ +# Example + +Building on the basic instructions provided earlier, let's explore an example scenario of "Order Submission." In this scenario, we need to verify the stock levels of all products selected by the user at the time of order submission. If any product has insufficient stock, the order submission will be blocked, and a relevant notification will be displayed. The system will iterate through each product, and if all products have sufficient stock, the order data will be generated successfully. + +The other steps follow the same procedure outlined in the instructions. However, since an order may include multiple products, in addition to establishing a many-to-many relationship between "Order" <-- m:1 -- "Details" -- 1:m --> "Product" during data modeling, it's necessary to introduce a "Loop" node in the "Pre-Action Event" workflow. This loop will be used to check the stock level of each product: + +![Example_Loop Check Process](https://static-docs.nocobase.com/8307de47d5629595ab6cf00f8aa898e3.png) + +The loop object should be set to the "Details" array within the submitted order data: + +![Example_Loop Object Configuration](https://static-docs.nocobase.com/ed662b54cc1f5425e2b472053f89baba.png) + +Within the loop, a condition check node is employed to determine whether the stock of the current product is sufficient: + +![Example_Condition Check in Loop](https://static-docs.nocobase.com/4af91112934b0a04a4ce55e657c0833b.png) + +The other configurations remain consistent with those in the basic usage instructions. Upon order submission, if any product's stock is insufficient, the order will be blocked, and a corresponding notification will be returned. During testing, you can attempt to submit multiple products in one order, with one product having insufficient stock and another having sufficient stock. The response message you receive will look like this: + +![Example_Submission Response Message](https://static-docs.nocobase.com/dd9e81084aa237bda0241d399ac19270.png) + +As illustrated, the response message does not flag the insufficient stock of the first product, "iPhone 15 Pro," but it does indicate the insufficient stock of the second product, "iPhone 14 Pro." This happens because the first product's stock was adequate, allowing the submission to proceed, while the second product's insufficient stock led to the order being blocked. diff --git a/docs/fr-FR/handbook/workflow-request-interceptor/http-api.md b/docs/fr-FR/handbook/workflow-request-interceptor/http-api.md new file mode 100644 index 000000000..12b3cfef9 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-request-interceptor/http-api.md @@ -0,0 +1,65 @@ +# HTTP API + +The pre-operation event is integrated during the request processing phase, enabling it to be triggered via an HTTP API call. + +For workflows that are locally bound to an action button, you can trigger them with the following command (using a button for the `posts` table as an example): + +```bash +curl -X POST -H 'Authorization: Bearer ' -H 'X-Role: ' -d \ + '{ + "title": "Hello, world!", + "content": "This is a test post." + }' + "http://localhost:3000/api/posts:create?triggerWorkflows=workflowKey" +``` + +The URL parameter `triggerWorkflows` specifies the key of the workflow, with multiple workflows separated by commas. You can find this key by hovering your mouse over the workflow name at the top of the workflow canvas: + +![How to view workflow key](https://static-docs.nocobase.com/20240426135108.png) + +After executing the above command, the corresponding pre-operation event for the `posts` table will be triggered. Once the associated workflow is processed synchronously, the data will be created and returned as usual. + +If the configured workflow reaches an "End process," the request will be intercepted, and no data will be created, following the same logic as an interface operation. If the End Node status is set to failure, the response status code will be `400`; if successful, it will be `200`. + +If a "Response Message" node is configured before the End Node, the generated message will be included in the response. The error message structure is as follows: + +```json +{ + "errors": [ + { + "message": "message from 'Response Message' node" + } + ] +} +``` + +When the "End Node" is configured as successful, the message structure is as follows: + +```json +{ + "messages": [ + { + "message": "message from 'Response Message' node" + } + ] +} +``` + +:::info{title=Note} +Since multiple "Response Message" nodes can be added within the workflow, the returned message data structure is presented as an array. +::: + +If the pre-operation event is configured globally, there’s no need to specify the corresponding workflow using the URL parameter `triggerWorkflows` when calling the HTTP API. Simply calling the corresponding data table operation will automatically trigger it. + +```bash +curl -X POST -H 'Authorization: Bearer ' -H 'X-Role: ' -d \ + '{ + "title": "Hello, world!", + "content": "This is a test post." + }' + "http://localhost:3000/api/posts:create" +``` + +:::info{title="Note"} +When triggering post-operation events via an HTTP API call, ensure the workflow is enabled and that the data table configuration matches the expected setup. Otherwise, the call may fail or result in errors. +::: diff --git a/docs/fr-FR/handbook/workflow-request-interceptor/index.md b/docs/fr-FR/handbook/workflow-request-interceptor/index.md new file mode 100644 index 000000000..b24638d1b --- /dev/null +++ b/docs/fr-FR/handbook/workflow-request-interceptor/index.md @@ -0,0 +1,16 @@ +# Overview + + + +The pre-operation event plugin introduces a powerful mechanism for intercepting form operation requests. This interception occurs after a form operation is submitted but before it’s processed. If the process triggered includes an "End Process" node or if any other nodes fail to execute correctly (whether due to errors or incomplete execution), the form operation will be intercepted. Otherwise, the operation will proceed as planned. When paired with the "Response Message" node, this feature allows you to configure the process to return specific response messages to the client, offering clear and relevant prompts. Pre-operation events are ideal for business validation or logic checks, enabling the approval or interception of client-submitted requests for creating, updating, or deleting records. + +## User Guide + +Using pre-operation events involves several key steps: + +- [Trigger Configuration](./trigger.md) +- [Operation Configuration](./node.md) + +For a deeper understanding, you can explore [Advanced Usage](./advanced.md), and see how it’s applied in real scenarios by reviewing the [Examples](./example.md). + +If you need to integrate with an external system, refer to [External Call](./http-api.md). diff --git a/docs/fr-FR/handbook/workflow-request-interceptor/trigger.md b/docs/fr-FR/handbook/workflow-request-interceptor/trigger.md new file mode 100644 index 000000000..febdfda3d --- /dev/null +++ b/docs/fr-FR/handbook/workflow-request-interceptor/trigger.md @@ -0,0 +1,21 @@ +# Trigger Configuration + +## Creating a Trigger + +When setting up a workflow, select "Pre-action event" as the event type: + +![Pre-action event](https://static-docs.nocobase.com/2add03f2bdb0a836baae5fe9864fc4b6.png) + +## Selecting the Data Table + +The first step in configuring a trigger for intercepting workflows is to select the data table associated with the action: + +![Intercept Event Configuration_Data Table](https://static-docs.nocobase.com/8f7122caca8159d334cf776f838d53d6.png) + +Next, choose the intercept mode. You can either intercept only the action buttons linked to this workflow or intercept all selected actions for the data table (regardless of the form the action originates from and without needing to bind the corresponding workflow): + +## Intercept Mode + +![Intercept Event Configuration_Intercept Mode](https://static-docs.nocobase.com/145a7f7c3ba440bb6ca93a5ee84f16e2.png) + +Currently, the supported action types include "Create," "Update," and "Delete." You can select multiple action types simultaneously. diff --git a/docs/fr-FR/handbook/workflow-request/index.md b/docs/fr-FR/handbook/workflow-request/index.md new file mode 100644 index 000000000..c01f522bf --- /dev/null +++ b/docs/fr-FR/handbook/workflow-request/index.md @@ -0,0 +1,87 @@ +# HTTP Requests + + + +When you need to interact with another web system, the HTTP Request node is your go-to tool. This node allows you to send an HTTP request to a specified address, complete with data in JSON or `application/x-www-form-urlencoded` formats, facilitating seamless communication with external systems. + +If you're already familiar with tools like Postman, mastering the HTTP Request node will be straightforward. However, unlike traditional tools, this node leverages context variables from the current workflow, making it a powerful addition to your business process integration. + +### Installation + +This is a built-in plugin, so there's no need for installation. + +### User Guide + +#### Creating a Node + +In the workflow configuration interface, click the plus (“+”) button within your process to add an "HTTP Request" node: + +![HTTP Request_Add](https://static-docs.nocobase.com/46f2a6fc3f6869c80f8fbd362a54e644.png) + +#### Node Configuration + +![HTTP Request Node_Configuration](https://static-docs.nocobase.com/2fcb29af66b892fa704add52e2974a52.png) + +**Request Method** + +Choose from the available HTTP request methods: `GET`, `POST`, `PUT`, `PATCH`, and `DELETE`. + +**Request URL** + +Specify the URL of the HTTP service, including the protocol (`http://` or `https://`). For security, `https://` is recommended. + +**Request Data Format** + +This defines the `Content-Type` in the request header, with options for `application/json` and `application/x-www-form-urlencoded`. + +**Request Header Configuration** + +Set key-value pairs for the request headers, with values that can dynamically reference variables from the workflow context. + +:::info{title=Note} +The `Content-Type` header is predetermined by the request data format setting. Manual input here will not override this configuration. +::: + +**Request Parameters** + +Define key-value pairs for the query string. Values can dynamically utilize variables from the workflow context. + +**Request Body** + +Currently, the request body supports only standard JSON format. Use the variable button in the upper-right corner of the text editor to insert context variables. + +:::info{title=Note} +Ensure that variables within JSON are used as strings, for example: `"a": "{{$context.data.a}}"`. +::: + +**Timeout Settings** + +If the request takes too long to respond, the timeout setting will cancel it, leading to the premature termination of the current workflow with a failure status. + +**Ignore Failure** + +The request node considers any HTTP status code between `200` and `299` as a success. Codes outside this range are deemed failures. If you select the "Ignore failed requests and continue workflow" option, the workflow will proceed with subsequent nodes, even if the request fails. + +### Using Response Results + +The HTTP request's response results can be parsed using the [JSON Query](./plugins/json-query.md) node, enabling further use in subsequent workflow nodes. + +Starting from version `v1.0.0-alpha.16`, the request node’s response includes three components that can be used as variables: + +- Status Code +- Response Headers +- Data + +![HTTP Request Node_Response Result Usage](https://static-docs.nocobase.com/20240529110610.png) + +The response status code is a standard numerical HTTP status code, such as `200` or `403`, as provided by the service. + +Response headers are in JSON format, and the response data—also in JSON—must be parsed using the JSON node before being utilized. + +### Example + +For instance, you can configure the request node to interface with a cloud platform for sending notification SMS. Here’s how you would set up the Alibaba Cloud SMS API (with parameters adapted according to the relevant documentation): + +![HTTP Request Node_Configuration](https://static-docs.nocobase.com/20240515124004.png) + +When the workflow triggers this node, it will call Alibaba Cloud’s SMS API based on the configuration. If successful, a text message will be sent via the cloud SMS service. diff --git a/docs/fr-FR/handbook/workflow-response-message/index.md b/docs/fr-FR/handbook/workflow-response-message/index.md new file mode 100644 index 000000000..d67a3f8e9 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-response-message/index.md @@ -0,0 +1,55 @@ +# Response Message + + + +The Response Message node is designed to deliver custom messages to the client who initiates an operation within certain types of workflows. + +:::info{title=Note} +This node currently can be used in the workflow types "Pre-Action Event" and "Custom Action Event (synchronous mode)". +::: + +## User Manual + +### Creating a Node + +Within the supported workflow types, you can insert a "Response Message" node at any point in the workflow. To do this, click the plus ("+") button within the workflow to add the "Response Message" node: + +![Add Node](https://static-docs.nocobase.com/eac2b3565e95e4ce59f340624062ed3d.png) + +Throughout the entire request process, response messages are accumulated in an array. When the process reaches a Response Message node, the new message content is appended to this array. Upon the server sending the response content, all messages within the array are delivered together to the client. + +### Node Configuration + +The message content is structured as a template string, allowing the insertion of variables. You can customize the template's content in the node configuration as needed: + +![Node Configuration](https://static-docs.nocobase.com/d5fa5f4002d50baf3ba16048818fddfc.png) + +As the process executes and reaches this node, the template is parsed to generate the final message content. In the example configuration above, the variable "Scope variables / Loop all products / Loop target / Product / Title" will be replaced with specific values during the actual workflow, such as: + +``` +Insufficient stock for product "iPhone 14 Pro" +``` + +![Message Content](https://static-docs.nocobase.com/06bd4a6b6ec499c853f0c39987f63a6a.png) + +### Process Configuration + +The status prompt of the response message is determined by the success or failure of the process execution. If any node in the process fails to execute, the entire process is considered a failure. In this case, the message content will be returned to the client with a failure status as a notification. + +If you need to actively define a failure status within the process, you can use the "End Node" and configure it as a failure. When the process reaches this node, it will exit with a failure status, and the message will be returned to the client with a failure status. + +If the entire process completes without any failure and reaches the end successfully, the message content will be returned to the client with a success status. + +:::info{title=Note} +If multiple response message nodes are defined in the process, the content of the executed nodes will be appended to an array. When the process is completed, all message content will be returned to the client together as a notification. +::: + +### Use Cases + +#### "Pre-Action Event" Workflow + +In a "Pre-Action Event" workflow, a response message can be used to provide feedback to the client upon completion of the process. For further details, refer to [Request Interception](../triggers/pre-action.md). + +#### "Post-Action Event" Workflow + +In synchronous mode within a "Post-Action Event" workflow, the response message is sent to the client after the process is completed. Unlike the "Pre-Action Event" workflow, where the result might vary, the message displayed here is always a "success" notification. This consistency occurs because the triggering operation has already been successfully executed, and the success of the linked workflow does not impact the original operation's result. diff --git a/docs/fr-FR/handbook/workflow-sql/index.md b/docs/fr-FR/handbook/workflow-sql/index.md new file mode 100644 index 000000000..3d28cdf32 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-sql/index.md @@ -0,0 +1,74 @@ +# SQL Actions + +In certain scenarios where the standard data table operation nodes fall short for more complex tasks, you can directly employ the SQL Action node to execute sophisticated SQL queries within the database. + +Unlike executing SQL operations by connecting to the database externally, within the workflow, you can leverage variables from the workflow context as parameters within your SQL statements. + +## FAQ + +### How can the results of an SQL Action node be utilized? + +When using a `SELECT` statement, the query results are stored in the node in Sequelize's JSON format. You can parse and utilize these results through the [JSON-query](/handbook/workflow-json-query) plugin. + +### Will SQL actions trigger table events? + +**No**. SQL actions directly execute SQL commands on the database. Actions such as `CREATE` / `UPDATE` / `DELETE` occur in the database, while table events are managed at the Node.js application layer (ORM processing). As a result, these operations do not trigger table events. + +## Installation + +This plugin is built-in, so no installation is necessary. + +## User Guide + +### Creating a Node + +In the workflow configuration interface, click the plus sign (“+”) within the flow to add an "SQL Action" node: + +![Adding SQL Actions](https://static-docs.nocobase.com/0ce40a226d7a5bf3717813e27da40e62.png) + +### Configuring the Node + +![SQL Node Configuration](https://static-docs.nocobase.com/98611dc13bcda04348bd0856561a7b04.png) + +#### Data Source + +Select the data source for executing the SQL. + +The data source must be of a database type, such as the main data source, PostgreSQL type, or any other data source compatible with Sequelize. + +#### SQL Content + +Edit the SQL statement. Currently, only one SQL statement is supported. + +You can insert required variables by clicking the variable button in the upper right corner of the editor. Before execution, the variables will be replaced with their corresponding values in the text, and the final SQL statement will be sent to the database for querying. + +### Node Execution Results + +Starting from `v1.3.15-beta`, the result of the SQL node execution is an array consisting purely of data. Prior to this version, the result was a Sequelize native structure that included query metadata (for more details, see: [`sequelize.query()`](https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-method-query)). + +For example, the following query: + +```sql +select count(id) from posts; +``` + +Result before `v1.3.15-beta`: + +```json +[ + [ + { "count": 1 } + ], + { + // meta + } +] +``` + +Result after `v1.3.15-beta`: + +```json +[ + { "count": 1 } +] +``` diff --git a/docs/fr-FR/handbook/workflow-variable/index.md b/docs/fr-FR/handbook/workflow-variable/index.md new file mode 100644 index 000000000..2eb7019a2 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-variable/index.md @@ -0,0 +1,78 @@ +# Custom Variables + + + +In workflows, variables can be declared or assigned values to existing ones, typically to store temporary data during the process. + +## User Manual + +### Creating Nodes + +To add a "Variable" node in the workflow configuration interface, click the plus (“+”) button in the process: + +![Add Variable Node](https://static-docs.nocobase.com/53b1e48e777bfff7f2a08271526ef3ee.png) + +### Configuring Nodes + +#### Mode + +Like programming variables, a variable node must first be declared before it can be used or assigned a value. When creating a variable node, you must choose its mode. There are two options: + +![Select Mode](https://static-docs.nocobase.com/49d8b7b501de6faef6f303262aa14550.png) + +- Declare a new variable: This creates a new variable. +- Assign value to an existing variable: This assigns a value to a previously declared variable, effectively updating its value. + +If the node being created is the first variable node in the process, only the declare mode is available, as there are no pre-existing variables to assign values to. + +When assigning a value to an existing variable, you’ll need to select the target variable, which is the node where the variable was originally declared: + +![Select the Variable to Assign](https://static-docs.nocobase.com/1ce8911548d7347e693d8cc8ac1953eb.png) + +#### Value + +The value of a variable can be of any type—such as a constant (e.g., strings, numbers, booleans, dates) or another variable within the workflow. + +In declare mode, setting a variable value is equivalent to assigning it an initial value. + +![Declare Initial Value](https://static-docs.nocobase.com/4ce2c508986565ad537343013758c6a4.png) + +In assign mode, setting a variable value modifies the value of the target variable to the new value, which will be used in subsequent steps. + +![Assign Trigger Variable Value to Declared Variable](https://static-docs.nocobase.com/858bae180712ad279ae6a964a77a7659.png) + +### Using Variable Values + +In nodes following the variable node, you can use the value of the variable by selecting it from the "Node result" group. For example, in a query node, the value of a variable can be used as a query condition: + +![Use Variable Value as Query Filter Condition](https://static-docs.nocobase.com/1ca91c295254ff85999a1751499f14bc.png) + +### Example + +Variable nodes are particularly useful in branches where new values need to be calculated or combined with existing values (similar to `reduce` or `concat` in programming). These values can then be used after the branch ends. The following example demonstrates how to create a concatenated recipient string using loop and variable nodes. + +Start by creating a workflow triggered by a data table update. This workflow will be activated when "Article" data is updated, and it preloads the related "Authors" relational data (used to get recipients): + +![Configure Trigger](https://static-docs.nocobase.com/93327530a93c695c637d74cdfdcd5cde.png) + +Next, create a variable node to store the recipient string: + +![Recipient Variable Node](https://static-docs.nocobase.com/d26fa4a7e7ee4f34e0d8392a51c6666e.png) + +Then, create a loop branch node to iterate over the authors of the article and concatenate their details into the recipient variable: + +![Loop through Authors of the Article](https://static-docs.nocobase.com/083fe62c943c17a643dc47ec2872e07c.png) + +Within the loop branch, first create a Operator node to concatenate the current author with the stored author string: + +![Concatenate Recipient String](https://static-docs.nocobase.com/5d21a990162f32cb8818d27b16fd1bcd.png) + +After the Operator node, create another variable node in assign mode. Select the recipient variable node as the target, and set its value to the result of the Operator node: + +![Assign Concatenated Recipient String to Recipient Node](https://static-docs.nocobase.com/fc40ed95dd9b61d924b7ca11b23f9482.png) + +When the loop branch ends, the recipient variable will store the concatenated recipient string of all the article's authors. You can then use an HTTP request node after the loop to call the email-sending interface, passing the recipient variable’s value as the recipient parameter: + +![Send Email to Recipient through Request Node](https://static-docs.nocobase.com/37f71aa1a63e172bcb2dce10a250947e.png) + +In this way, a simple bulk email function is implemented using loop and variable nodes. diff --git a/docs/fr-FR/handbook/workflow-webhook/index.md b/docs/fr-FR/handbook/workflow-webhook/index.md new file mode 100644 index 000000000..05812e452 --- /dev/null +++ b/docs/fr-FR/handbook/workflow-webhook/index.md @@ -0,0 +1,93 @@ +# Webhook Event + + + +The Webhook trigger provides a system-generated URL for third-party systems to call via HTTP POST requests. This URL triggers workflow execution when specific events occur, such as payment callbacks or notifications. + +## User Guide + +### Creating a Trigger + +Create a workflow, select "Webhook Event" as the workflow type: + +![20241210105049](https://static-docs.nocobase.com/20241210105049.png) + +:::info{title="Tip"} +The key difference between "Synchronous" and "Asynchronous" workflows lies in their response behavior. Synchronous workflows wait until the workflow execution is complete before returning a response. In contrast, asynchronous workflows immediately return a pre-configured response, then execute the workflow in the background. +::: + +### Trigger Configuration + +![20241210105441](https://static-docs.nocobase.com/20241210105441.png) + +#### Webhook URL + +The URL is automatically generated and tied to the workflow. Use the copy button to paste the URL into the third-party system. + +HTTP requests must use the POST method. Other methods return a `405` error. + +#### Security + +Basic HTTP authentication is supported. By enabling this option and setting a username and password, you can secure the Webhook. The third-party system must include the username and password in the Webhook URL for authentication (Criteria Detail: [MDN: HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme)). + +When the user name and password are set, the system checks whether the user name and password in the request match, and returns a `401` error when no match is provided or no match is provided. + +#### Parsing Request Data + +Data in HTTP requests must be parsed to make it usable in Workflow. Parsed data is available as variables in subsequent nodes. + +Parsing an HTTP request is divided into three parts: + +1. Request Headers + + Headers are simple key-value pairs in string format. Specify the fields you need, such as `Date` , `X-Request-Id`, etc. + +2. Request Parameters + + Request parameter is the URL of query parameters, such as `http://localhost:13000/api/webhook:trigger/1hfmkioou0d? query=1` 'query' parameter. Paste the complete URL sample or query only the parameter part of the sample and click the parse button to automatically parse the key-value pairs. + + ! [20241210111155](https://static-docs.nocobase.com/20241210111155.png) + + Automatic parsing converts the parameter portion of the URL into a JSON structure, and generates a path based on the parameter hierarchy such as `query[0]`, `query[0].a`, etc. The path name can be manually modified if it does not meet the requirements, but usually does not need to be modified. Aliases are optional for displaying the name of a variable when used as a variable. At the same time, all parameter tables in the sample are generated. If there are unnecessary parameters, you can delete them. + +3. Request Body + + The request Body is the body of the HTTP request. Currently, only the request body in Content-Type format application/json is supported. You can directly configure the path to be parsed, or enter a JSON example and click the parse button for automatic parsing. + + ! [20241210112529](https://static-docs.nocobase.com/20241210112529.png) + + Automatic parsing JSON structure will be the key/value pair into paths, such as `{" a ": 1," b ": {" c" : 2}}` generates `a`, `b`, `b.c` path, etc. Aliases are optional for displaying the name of a variable when used as a variable. At the same time, all parameter tables in the sample are generated. If there are unnecessary parameters, you can delete them. + +#### Response Settings + +The response part of Webhook is configured differently in synchronous and asynchronous workflows. The asynchronous workflows are directly configured in the trigger. After receiving the Webhook request, the response configuration in the trigger is immediately returned to the third-party system before the workflow is executed. Synchronous workflows need to be handled in the process by adding response nodes as required by the business (Detail: [Response nodes](#response nodes)). + +Typically, the response to an asynchronously triggered Webhook event has a status code of `200` and a response body of `ok`. You can also customize the status code, response header, and response body of the response. + +! [20241210114312](https://static-docs.nocobase.com/20241210114312.png) + +### Response node + +It is only supported for use in synchronous mode Webhook workflows for responses returned to third-party systems. For example, if there is an unexpected result (such as an error or failure) during the processing of a payment callback, the response node can return an error response to the third-party system so that some third-party systems can retry later according to the status. + +In addition, the execution of the response node terminates the execution of the workflow, and subsequent nodes do not execute. If the entire workflow is not configured with a response node, the system will automatically respond according to the state of the process execution, returning `200` for successful execution and `500` for failed execution. + +#### Creating a response node + +In the workflow configuration interface, click the plus sign ("+") button in the process to add the "Response" node: + +! [20241210115120](https://static-docs.nocobase.com/20241210115120.png) + +#### Response configuration + +! [20241210115500](https://static-docs.nocobase.com/20241210115500.png) + +Variables in the workflow context can be used in the response body. + +#### Example + +In the Webhook workflow in synchronous mode, different responses can be returned according to different business conditions, as shown in the figure below: + +! [20241210120655](https://static-docs.nocobase.com/20241210120655.png) + +Check whether a service status is satisfied through the conditional branch node. If yes, a success message is displayed. Otherwise, a failure message is displayed. diff --git a/docs/fr-FR/handbook/workflow/advanced/executions.md b/docs/fr-FR/handbook/workflow/advanced/executions.md new file mode 100644 index 000000000..761704684 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/advanced/executions.md @@ -0,0 +1,54 @@ +# Execution Plan (History) + +After each workflow is triggered, a corresponding execution plan will be created to track the process of this task. Each execution plan has a status value to indicate the current execution status, which can be viewed in the list and details of the execution history: + +![Execution plan status](https://static-docs.nocobase.com/d4440d92ccafac6fac85da4415bb2a26.png) + +When all nodes in the main branch of the process are executed to the end of the process with a "Resolved" status, the entire execution plan will end with a "Resolved" status. When nodes in the main branch of the process appear in final status such as "failed", "error", "canceled" or "rejected", etc., the entire execution plan will be terminated early with the corresponding status. When nodes in the main branch of the process are in a "pending" status, the entire execution plan will be paused, but still display an "On going" status, until the waiting node is resumed and continues execution. Different node types have different ways of handling the "pending" status. For example, "Manual" nodes need to wait for manual processing, while "Delay" nodes need to wait until the time arrives to continue execution. + +The status of the execution plan is as follows: + +| Status | Corresponds to the State of
    Last Executed Node of the Main Process | Explanation | +| ------- | ----------------------------------------------| ----------------------------------------------- | +| Queueing | - | The process has been triggered and an execution plan has been generated, waiting in the queue for scheduling by the scheduler. | +| On going | Pending | The node requests a pause, waiting for further input or callback to continue. | +| Resolved | Resolved | No problems encountered, all nodes executed as expected one by one and completed. | +| Failed | Failed | Failed due to unmet the logic of node configurations. | +| Error | Error | The node encountered an uncaught program error and terminated early. | +| Canceled | Canceled | The waiting node was externally canceled from execution by the administrator, and terminated early. | +| Rejected | Rejected | In nodes requiring manual processing, it was rejected by user and no longer continued with subsequent processes. | + +In the examples of [Quick S tart](../quick-start.md), we already know that checking the details of the execution history of a workflow can check whether all nodes in the execution are executed normally, and the status and result data of each executed node. In some advanced workflows and nodes, the executed results of the nodes may be multiple, such as the results of "Loop" nodes: + +![Results of nodes executed multiple times](https://static-docs.nocobase.com/bbda259fa2ddf62b0fc0f982efbedae9.png) + +:::info{title=Note} +Workflow can be triggered concurrently, but executed one by one in queue, even if multiple workflows are triggered simultaneously, they will be executed sequentially, not in parallelly. So when the status shows "Queueing" it means that one of the workflows is executing and need to wait. + +The "On going" status only indicates that the execution plan has started and is usually paused due to the pending status of some node, and does not mean that the execution plan preemptively occupies the execution resources at the head of the queue. Therefore, when there are "On going" execution plans, other "Queueing" execution plans can still be scheduled and executed. +::: + +## Node Execution Status + +The status of the execution plan is determined by each node. In an execution plan after a trigger, each executed node will produce a node status, and the status will determine whether the subsequent process continues to process. Usually, after a node is executed successfully, the next node will continue to execute until all nodes are executed in sequence, or interrupted. When encountering process control nodes, such as "Branch", "Loop", "Parallel" and "Delay", etc., the next node's execution flow will be determined according to the control node's configured conditions and the runtime context data. + +The possible status that may be produced after each node is executed are following: + +| Status | Is a Final status? | Will it Terminates Early? | Explanation | +| ------ | :------------------------: | :-------------------------: | -------------------------------------------------------- | +| Pending | No | No | The node requests a pause, waiting for further input or callback to continue. | +| Resolved | Yes | No | No problems encountered, executed successfully, and continue to execute the next node until the end. | +| Failed | Yes | Yes | Failed due to unmet node configurations. | +| Error | Yes | Yes | The node encountered an uncaught program error and terminated early. | +| Canceled | Yes | Yes | The pending node was canceled externally by the administrator, and terminated early. | +| Rejected | Yes | Yes | In nodes requiring manual processing, it was rejected by user and no longer continued with subsequent processes. | + +Except for the "Pending" status, all other status are final status of node execution. Only when the final status is "Resolved" the process will continue to execute, otherwise the execution of the entire process will be terminated early. When a node is in a branch process ("Parallel branchs", "Condition", "Loop", etc.), the final status generated by the node will be taken over and processed by the node that opens the branch, and so on, determining the entire process flow. + +For example, when we use a "Condition" node with the "continue when 'Yes'" mode, if the result is "false" during execution, the entire process execution will be terminated early and exited with a failed status, as shown in the figure below: + +![Node execution failed](https://static-docs.nocobase.com/993aecfa1465894bb574444f0a44313e.png) + +:::info{title=Note} +All final status other than "Resolved" can be regarded as failures, but the reasons for failure will be different, by checking the results of the nodes to know more about the failure. +::: diff --git a/docs/fr-FR/handbook/workflow/advanced/options.md b/docs/fr-FR/handbook/workflow/advanced/options.md new file mode 100644 index 000000000..3711b7f32 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/advanced/options.md @@ -0,0 +1,29 @@ +# Advanced Options + +## Execution Modes + +Workflow execution is based on the trigger type selected when creating, and can be executed in "Asynchronously" or "Synchronously" mode. "Asynchronously" mode means that after a specific event is triggered, it will enter the execution queue and be executed one by one by the background scheduler, while "synchronously" mode will not enter the scheduling queue after triggering, and will start execution directly, and will immediately provide feedback after execution. + +Collection event, post-action event, custom action event, schedule event and approval event will be executed asynchronously by default, while pre-action event will be executed synchronously by default. Among them, collection event, post-action event and custom action event support both modes, and you can choose when creating a workflow: + +![Synchronous mode: Creating synchronous workflow](https://static-docs.nocobase.com/39bc0821f50c1bde4729c531c6236795.png) + +:::info{title=Note} +Synchronously mode workflow are limited by their mode and cannot use nodes that generate a "pending" status, such as "manual process" etc. +::: + +## Automatically Delete History + +When workflows are triggered frequently, you can reduce interference and database storage pressure by configuring automatic deletion of historical executions. + +Similarly, in the pop-up for creating and editing workflows, you can configure whether the corresponding process automatically deletes history: + +![Configure automatic deletion of history](https://static-docs.nocobase.com/b2e4c08e7a01e213069912fe04baa7bd.png) + +Automatic deletion can be configured based on the status of the execution. In most cases, it is recommended to only select the "Succeeded" status, so that history of execution failures can be retained for subsequent troubleshooting. + +It is recommended not to enable automatic deletion of history when debugging workflows, so that the execution logic of the workflows can be reviewed in history. + +:::info{title=Note} +Deleting the history of workflows will not reduce the count of workflows already executed. +::: diff --git a/docs/fr-FR/handbook/workflow/advanced/revisions.md b/docs/fr-FR/handbook/workflow/advanced/revisions.md new file mode 100644 index 000000000..2916d9105 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/advanced/revisions.md @@ -0,0 +1,21 @@ +# Revisions + +After a configured workflow is triggered at least once, if you want to modify the configuration of the workflow or its nodes, you need to create a new version and then modify it, which also ensures that when reviewing execution history of workflows that have been triggered, they are not affected by future modifications. + +On the configuration page of the workflow, you can view existing workflow versions in the version menu in the top right corner: + +![View workflow versions](https://static-docs.nocobase.com/ad93d2c08166b0e3e643fb148713a63f.png) + +In the more operations ("...") menu on the right side, you can do "copy to new version" based on the current version being viewed: + +![Copy workflow to new version](https://static-docs.nocobase.com/2805798e6caca2af004893390a744256.png) + +After copying to a new version, click the "Enable"/"Disable" switch. After switching the corresponding version to the enabled status, the new workflow version will take effect. + +If you need to use an old version again, switch one from the version menu, and then switch to the enabled status by clicking the "On"/"Off" switch again, then the current viewed version will take effect, and further triggers will run on the corresponding version of the workflow. + +When need to disable a workflow, after clicking the "Enable"/"Disable" switch to the disabled status, the workflow will no longer be triggered. + +:::info{title=Note} +Different from "Duplicate" a workflow in the workflow management list,"Copy to new version" will still be grouped in the same group of workflows, but can be distinguished by version. However, duplicating a workflow will be make a completely new workflow, unrelated to the previous versions of the workflow, and the execution count will also be reset to zero. +::: diff --git a/docs/fr-FR/handbook/workflow/advanced/variables.md b/docs/fr-FR/handbook/workflow/advanced/variables.md new file mode 100644 index 000000000..f9b7fc1c2 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/advanced/variables.md @@ -0,0 +1,61 @@ +# Using Variables + +## Core Conception + +Just like variables in programming languages, **variables** are important tools for connecting and organizing processes in workflow. + +When each node is executed after the workflow is triggered, variables can be used in some configuration options, and the source of the variables is from data result of upstream node, including the following categories: + +- Trigger Context Data: In cases such as action triggers and collection triggers, single record object can be used by all nodes. The specific implementation may differ based on the individual trigger. +- Upstream node data: When executing any node, the result data of the previously completed nodes. +- Scope variables: When the node is in some special branch structures, scope variables specific to the corresponding branch can be used, such as in loop structures, where data objects for each round of the loop can be used. +- System variables: Some built-in system parameters, such as the current time, etc. + +We have used the function of variables many times in [Quick Start](../quick-start.md), for example, in the calculation node, we can use variables to reference trigger context data for calculation: + +![Function and variable usage in the calculation node](https://static-docs.nocobase.com/837e4851a4c70a1932542caadef3431b.png) + +In the update node, use trigger context data as the filtering condition variable, and refer to the result of the calculation node as the field value variable to update record: + +![Variable in update data node](https://static-docs.nocobase.com/2e147c93643e7ebc709b9b7ab4f3af8c.png) + +## Data Structure + +The internal of a variable is a JSON structure, which can usually be used to access specific parts of the data according to the JSONPath. Because many variables are based on the data collection of NocoBase, association data will be composed as a tree-like structure of objects, such as selecting the value of a field of related data that is queried. In addition, when association data is a to-many structure, the variable may be an array. + +Selecting a variable will most of the time require selecting the last layer value attribute, usually a simple data type such as number, string, etc. However, when there is an array in the variable hierarchy, the attributes at the end level will also be mapped to an array, and only when the corresponding node supports array can the array data be correctly processed. For example, in the calculation node, some calculation engines have functions specially designed for arrays, and in the loop node, the loop object can directly select an array. + +For example, when a query node queries multiple data rows, the node result will be an array containing multiple rows of homogeneous data: + +```json +[ + { + "id": 1, + "title": "Title 1" + }, + { + "id": 2, + "title": "Title 2" + } +] +``` + +However, when it is used as a variable in subsequent nodes, if the selected variable is in the form of `Node Result / Query Node / Title`, it will be mapped to an flat array of corresponding field values: + +```json +["Title 1", "Title 2"] +``` + +If it is a multi-dimensional array (such as a many-to-many association fields), it will be a one-dimensional array after the corresponding field is flattened. + +## Builtin System Variables + +### System Time + +Retrieve the system time at the moment of execution based on the node where it is executed, the time zone is the time zone set by the server. + +### Date Range Parameters + +This can be used for configuring date field filter conditions in query, update, and delete nodes. It only supports "Is" comparisons, and the start and end points of the date range are based on the server's time zone settings. + +![Date Range Parameters](https://static-docs.nocobase.com/20240817175354.png) diff --git a/docs/fr-FR/handbook/workflow/development/api.md b/docs/fr-FR/handbook/workflow/development/api.md new file mode 100644 index 000000000..74a337b4b --- /dev/null +++ b/docs/fr-FR/handbook/workflow/development/api.md @@ -0,0 +1,351 @@ +# API Reference + +## Server-Side + +The API available in the server-side package is shown in the following code: + +```ts +import PluginWorkflowServer, { + Trigger, + Instruction, + EXECUTION_STATUS, + JOB_STATUS, +} from '@nocobase/plugin-workflow'; +``` + +### `PluginWorkflowServer` + +The Workflow Plugin class. + +Typically, during an application's runtime, the Workflow Plugin instance can be retrieved by calling `app.pm.get(PluginWorkflowServer)` from any location where the application instance `app` is accessible (hereinafter referred to as `plugin`). + +### `registerTrigger()` + +Registers a new trigger type. + +**Signature** + +`registerTrigger(type: string, trigger: typeof Trigger | Trigger)` + +**Parameters** + +| Parameter | Type | Description | +| ----------- | --------------------------- | ----------------------- | +| `type` | `string` | Trigger type identifier | +| `trigger` | `typeof Trigger \| Trigger` | Trigger type or instance| + +**Example** + +```ts +import PluginWorkflowServer, { Trigger } from '@nocobase/plugin-workflow'; + +function handler(this: MyTrigger, workflow: WorkflowModel, message: string) { + // trigger workflow + this.workflow.trigger(workflow, { data: message.data }); +} + +class MyTrigger extends Trigger { + messageHandlers: Map = new Map(); + on(workflow: WorkflowModel) { + const messageHandler = handler.bind(this, workflow); + // listen for some event to trigger workflow + process.on( + 'message', + this.messageHandlers.set(workflow.id, messageHandler), + ); + } + + off(workflow: WorkflowModel) { + const messageHandler = this.messageHandlers.get(workflow.id); + // remove listener + process.off('message', messageHandler); + } +} + +export default class MyPlugin extends Plugin { + load() { + // get workflow plugin instance + const workflowPlugin = + this.app.pm.get(PluginWorkflowServer); + + // register trigger + workflowPlugin.registerTrigger('myTrigger', MyTrigger); + } +} +``` + +### `registerInstruction()` + +Registers a new node type. + +**Signature** + +`registerInstruction(type: string, instruction: typeof Instruction | Instruction)` + +**Parameters** + +| Parameter | Type | Description | +| -------------- | ----------------------------------- | -------------------------- | +| `type` | `string` | Instruction type identifier| +| `instruction` | `typeof Instruction \| Instruction` | Instruction type or instance| + +**Example** + +```ts +import PluginWorkflowServer, { Instruction, JOB_STATUS } from '@nocobase/plugin-workflow'; + +class LogInstruction extends Instruction { + run(node, input, processor) { + console.log('my instruction runs!'); + return { + status: JOB_STATUS.RESOLVED, + }; + } +}; + +export default class MyPlugin extends Plugin { + load() { + // get workflow plugin instance + const workflowPlugin = this.app.pm.get(PluginWorkflowServer); + + // register instruction + workflowPlugin.registerInstruction('log', LogInstruction); + } +} +``` + +### `trigger()` + +Triggers a specific workflow. This is mainly used within custom triggers to activate the corresponding workflow when a specific custom event is detected. + +**Signature** + +`trigger(workflow: Workflow, context: any)` + +**Parameters** + +| Parameter | Type | Description | +| --------- | -------------- | ------------------------------------ | +| `workflow`| `WorkflowModel`| The workflow object to be triggered | +| `context` | `object` | The context data provided when triggering | + +:::info{title=Tip} +`context` is currently a required parameter; the workflow will not trigger without it. +::: + +**Example** + +```ts +import { Trigger } from '@nocobase/plugin-workflow'; + +class MyTrigger extends Trigger { + timer: NodeJS.Timeout; + + on(workflow) { + // register event + this.timer = setInterval(() => { + // trigger workflow + this.plugin.trigger(workflow, { date: new Date() }); + }, workflow.config.interval ?? 60000); + } +} +``` + +### `resume()` + +Resumes the execution of a paused workflow at a specific node task. + +- Only workflows in the `EXECUTION_STATUS.STARTED` state can be resumed. +- Only node tasks in the `JOB_STATUS.PENDING` state can be resumed. + +**Signature** + +`resume(job: JobModel)` + +**Parameters** + +| Parameter | Type | Description | +| --------- | ---------- | -------------------------- | +| `job` | `JobModel` | The updated task object | + +:::info{title=Tip} +The task object passed in is usually the updated object and typically has the `status` updated to a value other than `JOB_STATUS.PENDING`; otherwise, it will remain paused. +::: + +**Example** + +See [source code](https://github.com/nocobase/nocobase/blob/main/packages/plugins/%40nocobase/plugin-workflow-manual/src/server/actions.ts#L99). + +## `Trigger` + +Base class for triggers, used to extend custom trigger types. + +| Parameter | Type | Description | +| ----------------- | ----------------------------------------------------------- | ----------------------------- | +| `constructor` | `(public readonly workflow: PluginWorkflowServer): Trigger` | Constructor | +| `on?` | `(workflow: WorkflowModel): void` | Event handler when workflow is started | +| `off?` | `(workflow: WorkflowModel): void` | Event handler when workflow is stopped | + +`on`/`off` are used to register/unregister event listeners when the workflow is enabled/disabled. The passed parameter is the workflow instance corresponding to the trigger, which can be processed according to the configuration. For certain trigger types that already listen to events globally, these methods may not need to be implemented. For example, in a timed trigger, a timer can be registered in `on` and unregistered in `off`. + +## `Instruction` + +Base class for instruction types, used to extend custom instruction types. + +| Parameter | Type | Description | +| ----------------- | --------------------------------------------------------------- | ----------------------------------- | +| `constructor` | `(public readonly workflow: PluginWorkflowServer): Instruction` | Constructor | +| `run` | `Runner` | Execution logic when entering the node for the first time | +| `resume?` | `Runner` | Execution logic when resuming after an interruption | +| `getScope?` | `(node: FlowNodeModel, data: any, processor: Processor): any` | Provides local variables generated by the branch node | + +**Related Types** + +```ts +export type Job = + | { + status: JOB_STATUS[keyof JOB_STATUS]; + result?: unknown; + [key: string]: unknown; + } + | JobModel + | null; + +export type InstructionResult = Job | Promise; + +export type Runner = ( + node: FlowNodeModel, + input: JobModel, + processor: Processor, +) => InstructionResult; + +export class Instruction { + run: Runner; + resume?: Runner; +} +``` + +`getScope` can be referred to in the [loop node implementation](https://github.com/nocobase/nocobase/blob/main/packages/plugins/%40nocobase/plugin-workflow-loop/src/server/LoopInstruction.ts#L83), which is used to provide local variables for the branch. + +## `EXECUTION_STATUS` + +A table of constants representing the status of workflow execution plans, used to indicate the current status of the execution plan. + +| Constant Name | Meaning | +| --------------------------------| ---------------------| +| `EXECUTION_STATUS.QUEUEING` | Queueing | +| `EXECUTION_STATUS.STARTED` | In Progress | +| `EXECUTION_STATUS.RESOLVED` | Successfully Completed | +| `EXECUTION_STATUS.FAILED` | Failed | +| `EXECUTION_STATUS.ERROR` | Execution Error | +| `EXECUTION_STATUS.ABORTED` | Aborted | +| `EXECUTION_STATUS.CANCELED` | Canceled | +| `EXECUTION_STATUS.REJECTED` | Rejected | +| `EXECUTION_STATUS.RETRY_NEEDED` | Retry Needed | + +Apart from the first three, all other statuses represent failure states, but they can indicate different reasons for failure. + +## `JOB_STATUS` + +A table of constants representing the status of workflow node tasks, used to indicate the current status of the node task. The status generated by the node also affects the status of the entire execution plan. + +| Constant Name | Meaning | +| ---------------------------- | ------------------------------------------ | +| `JOB_STATUS.PENDING` | Pending: The node has been reached, but the instruction requires suspension | +| `JOB_STATUS.RESOLVED` | Successfully Completed | +| `JOB_STATUS.FAILED` | Failed: The node execution did not meet the configured conditions | +| `JOB_STATUS.ERROR` | Error: An uncaught error occurred during node execution | +| `JOB_STATUS.ABORTED` | Aborted: The node was terminated by other logic after suspension | +| `JOB_STATUS.CANCELED` | Canceled: The node was manually canceled after suspension | +| `JOB_STATUS.REJECTED` | Rejected: The node was manually rejected after suspension | +| `JOB_STATUS.RETRY_NEEDED` | Retry Needed | + +## Client-Side + +The API available in the client-side package is shown in the following code: + +```ts +import PluginWorkflowClient, { + Trigger, + Instruction, +} from '@nocobase/plugin-workflow/client'; + + +``` + +### `PluginWorkflowClient` + +### `registerTrigger()` + +Registers the configuration panel corresponding to the trigger type. + +**Signature** + +`registerTrigger(type: string, trigger: typeof Trigger | Trigger): void` + +**Parameters** + +| Parameter | Type | Description | +| ----------- | --------------------------- | --------------------------------------- | +| `type` | `string` | Trigger type identifier, consistent with the identifier used during registration | +| `trigger` | `typeof Trigger \| Trigger` | Trigger type or instance | + +### `registerInstruction()` + +Registers the configuration panel corresponding to the node type. + +**Signature** + +`registerInstruction(type: string, instruction: typeof Instruction | Instruction): void` + +**Parameters** + +| Parameter | Type | Description | +| -------------- | ----------------------------------- | --------------------------------------- | +| `type` | `string` | Node type identifier, consistent with the identifier used during registration | +| `instruction` | `typeof Instruction \| Instruction` | Node type or instance | + +## `Trigger` + +Base class for triggers, used to extend custom trigger types. + +| Parameter | Type | Description | +| -------------------- | ---------------------------------------------------------------- | --------------------------------------- | +| `title` | `string` | Trigger type name | +| `fieldset` | `{ [key: string]: ISchema }` | Set of trigger configuration options | +| `scope?` | `{ [key: string]: any }` | Object set that may be used in the configuration schema | +| `components?` | `{ [key: string]: React.FC }` | Component set that may be used in the configuration schema | +| `useVariables?` | `(config: any, options: UseVariableOptions) => VariableOptions` | Value getter for trigger context data | + +- If `useVariables` is not set, it means that this type of trigger does not provide a value-fetching function, and the trigger's context data cannot be selected in the flow node. + +## `Instruction` + +Base class for instructions, used to extend custom node types. + +| Parameter | Type | Description | +| ------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------- | +| `group` | `string` | Node type group identifier, currently optional: `'control'`/`'collection'`/`'manual'`/`'extended'` | +| `fieldset` | `Record` | Set of node configuration options | +| `scope?` | `Record` | Object set that may be used in the configuration schema | +| `components?` | `Record` | Component set that may be used in the configuration schema | +| `Component?` | `React.FC` | Custom rendering component for the node | +| `useVariables?` | `(node, options: UseVariableOptions) => VariableOption` | Method for providing node variable options | +| `useScopeVariables?` | `(node, options?) => VariableOptions` | Method for providing local variable options for the branch | +| `useInitializers?` | `(node) => SchemaInitializerItemType` | Method for providing initializer options for the node | +| `isAvailable?` | `(ctx: NodeAvailableContext) => boolean` | Method for determining whether the node is available in the current environment | + +**Related Types** + +```ts +export type NodeAvailableContext = { + workflow: object; + upstream: object; + branchIndex: number; +}; +``` + +- If `useVariables` is not set, it means that this node type does not provide a value-fetching function, and the result data of this node type cannot be selected in the flow. If the result value is singular (non-selectable), a static content that expresses the corresponding information can be returned (refer to the [calculation node source code](https://github.com/nocobase/nocobase/blob/main/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/calculation.tsx#L68)). If selection is required (e.g., a property in an Object), a custom selection component output can be provided (refer to the [Create Data Node source code](https://github.com/nocobase/nocobase/blob/main/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/create.tsx#L41)). +- `Component`: Custom rendering component for the node, used when the default node rendering is not sufficient, allowing for complete customization of the node view. For example, to provide more operation buttons or other interactive elements for the start node of a branch type, this method should be used (refer to the [Parallel Branch source code](https://github.com/nocobase/nocobase/blob/main/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/ParallelInstruction.tsx)). +- `useInitializers`: Used to provide methods for initialization blocks, for example, in a manual node, it can initialize relevant user blocks based on the upstream node. If this method is provided, it will be available during the initialization block in the manual node configuration interface (refer to the [Create Data Node source code](https://github.com/nocobase/nocobase/blob/main/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/create.tsx#L71)). +- `isAvailable`: Mainly used to determine whether the node can be used (added) in the current environment. The current environment includes the current workflow, upstream nodes, and the current branch index. diff --git a/docs/fr-FR/handbook/workflow/development/index.md b/docs/fr-FR/handbook/workflow/development/index.md new file mode 100644 index 000000000..ecac680d6 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/development/index.md @@ -0,0 +1,12 @@ +# Overview + +While the built-in features of workflows are robust, they may not cover every possible scenario. For instance, the default node types might not accommodate all the operations required in diverse business contexts. To address these gaps, we offer an extension framework for workflows, enabling you to expand trigger types and node functionalities. When the built-in features fall short, these extensions allow you to customize solutions using low-code techniques. + +These extensions are categorized into two main areas: + +- [Extend Trigger Types](./trigger.md) +- [Extend Node Types](./instruction.md) + +## Additional Resources + +- [API Reference](./api.md) diff --git a/docs/fr-FR/handbook/workflow/development/instruction.md b/docs/fr-FR/handbook/workflow/development/instruction.md new file mode 100644 index 000000000..09f535beb --- /dev/null +++ b/docs/fr-FR/handbook/workflow/development/instruction.md @@ -0,0 +1,302 @@ +# Extend Node Type + +The type of a node essentially represents an operation command, with different commands corresponding to different operations performed during a workflow. + +Similar to triggers, extending the type of a node involves both backend and frontend components. The backend is responsible for implementing the logic of registered commands, while the frontend provides the configuration interface for the parameters related to the node where the command resides. + +## Backend + +### The Simplest Node Command + +The core of a command is a function, meaning the `run` method in the command class must be implemented to execute the command's logic. This function can perform any necessary operations, such as database operations, file operations, or third-party API calls. + +All commands must be derived from the `Instruction` base class. The simplest command only needs to implement a `run` function: + +```ts +import { Instruction, JOB_STATUS } from '@nocobase/plugin-workflow'; + +export class MyInstruction extends Instruction { + run(node, input, processor) { + console.log('my instruction runs!'); + return { + status: JOB_STATUS.RESOLVED, + }; + } +} +``` + +Then, register this command with the workflow plugin: + +```ts +export default class MyPlugin extends Plugin { + load() { + // get workflow plugin instance + const workflowPlugin = this.app.getPlugin(WorkflowPlugin); + + // register instruction + workflowPlugin.registerInstruction('my-instruction', MyInstruction); + } +} +``` + +The status value (`status`) in the returned object of the command is mandatory and must be one of the values in the `JOB_STATUS` constant. This value will determine the subsequent flow of the process after the node is executed. Generally, `JOB_STATUS.RESOLVED` is used, indicating that the node has been successfully executed, and the subsequent nodes will continue to execute. If there are results that need to be saved early, you can also call the `processor.saveJob` method and return the object generated by this method. The executor will generate an execution result record based on this object. + +### Node Result Values + +If there is a specific execution result, especially data intended for use by subsequent nodes, it can be returned through the `result` attribute and saved in the node task object: + +```ts +import { Instruction, JOB_STATUS } from '@nocobase/plugin-workflow'; + +export class RandomStringInstruction extends Instruction { + run(node, input, processor) { + // customized config from node + const { digit = 1 } = node.config; + const result = `${Math.round(10 ** digit * Math.random())}`.padStart( + digit, + '0', + ); + return { + status: JOB_STATUS.RESOLVED, + result, + }; + } +}; +``` + +The `node.config` is the node's configuration item, which can be any required value and will be saved as a `JSON` type field in the corresponding node record in the database. + +### Command Error Handling + +If there may be exceptions during execution, they can be caught in advance and a failure status returned: + +```ts +import { JOB_STATUS } from '@nocobase/plugin-workflow'; + +export const errorInstruction = { + run(node, input, processor) { + try { + throw new Error('exception'); + } catch (error) { + return { + status: JOB_STATUS.ERROR, + result: error, + }; + } + }, +}; +``` + +If predictable exceptions are not caught, the workflow engine will automatically catch and return an error status to avoid program crashes due to uncaught exceptions. + +### Asynchronous Nodes + +When it is necessary to control the flow or perform asynchronous (time-consuming) I/O operations, the `run` method can return an object with a `status` of `JOB_STATUS.PENDING`, indicating to the executor to wait (suspend) until some external asynchronous operation is completed, after which the workflow engine will be notified to continue execution. If a pending status is returned in the `run` function, the command must implement the `resume` method; otherwise, the workflow cannot resume. + +```ts +import { Instruction, JOB_STATUS } from '@nocobase/plugin-workflow'; + +export class PayInstruction extends Instruction { + async run(node, input, processor) { + // job could be created first via processor + const job = await processor.saveJob({ + status: JOB_STATUS.PENDING, + }); + + const { plugin } = processor; + // do payment asynchronously + paymentService.pay(node.config, (result) => { + // notify processor to resume the job + return plugin.resume(job.id, result); + }); + + // return created job instance + return job; + } + + resume(node, job, processor) { + // check payment status + job.set('status', job.result.status === 'ok' ? JOB_STATUS.RESOLVED : JOB_STATUS.REJECTED); + return job; + } +}; +``` + +The `paymentService` refers to a payment service, and the workflow resumes the corresponding task after being triggered by a callback from the service, while the current process exits first. After that, the workflow engine creates a new processor, handing over the task to the node’s `resume` method to continue executing the previously suspended node. + +:::info{title=Tip} +The "asynchronous operations" mentioned here are not the same as `async` functions in JavaScript but refer to interactions with other external systems where certain operations may not return immediately. For example, a payment service may require waiting for a subsequent notification to know the result. +::: + +### Node Result Status + +The execution status of a node affects the success or failure of the entire process. Generally, in the absence of branches, a node failure will directly lead to the failure of the entire process. The most common scenario is that when a node is successfully executed, the next node in the node table continues until there are no more subsequent nodes, at which point the workflow completes with a successful status. + +If a node returns a failure status during execution, the engine will handle it differently depending on the following two situations: + +1. If the node that returns a failure status is in the main process and not within any branch process opened by an upstream node, the entire main process will be considered a failure, and the process will exit. + +2. If the node that returns a failure status is within a branch process, the responsibility for determining the next state of the process is delegated to the node that opened the branch. The internal logic of that node will decide the subsequent state of the process, recursively tracing back to the main process. + +Eventually, the final state of the entire process will be determined by the node in the main process. If the node in the main process returns a failure, the entire process ends with a failure status. + +If any node returns a "pending" status after execution, the entire execution process will be temporarily suspended, waiting for an event defined by the corresponding node to resume the process. For example, in a [manual node](../manual/nodes/manual), the process pauses at this node with a "pending" status, waiting for manual intervention to decide whether to proceed. If the status input by the user is "approved," the subsequent nodes continue; otherwise, the failure logic is processed as described earlier. + +For more command return statuses, refer to the [Workflow API Reference](./api#JOB_STATUS) section. + +### Early Exit + +In some special processes, it may be necessary to end the process directly within a certain node, which can be done by returning `null`. This indicates that the current process is exited, and the subsequent nodes will not continue to execute. + +This situation is more common in flow control-type nodes, such as in the [parallel branch node](../manual/nodes/parallel) (see [code reference](https://github.com/nocobase/nocobase/blob/main/packages/plugins/%40nocobase/plugin-workflow-parallel/src/server/ParallelInstruction.ts#L87)). The current node process exits, but new processes are opened for each sub-branch and continue to execute. + +:::warn{title=Tip} +Scheduling branch processes with extended nodes is complex and requires careful handling and thorough testing. +::: + +### Learn More + +For a detailed definition of each parameter in defining node types, refer to the [Workflow API Reference](./api#instruction) section. + +## Frontend + +Similar to triggers, the configuration form of a command (node type) needs to be implemented on the frontend. + +### The Simplest Node Command + +All commands must be derived from the `Instruction` base class, with relevant properties and methods used to configure and utilize the node. + +For example, we need to provide a configuration interface for the random number string type (`randomString`) node defined on the backend. This node has a configuration item `digit` representing the number of digits in the random number. In the configuration form, we use a number input box to accept user input. + +```tsx | pure +import WorkflowPlugin, { Instruction, VariableOption } from '@nocobase/workflow/client'; + +class MyInstruction extends Instruction { + title = 'Random number string'; + type = 'randomString'; + group = 'extended'; + fieldset = { + 'digit': { + type: 'number', + title: 'Digit', + name: 'digit', + 'x-decorator': 'FormItem', + 'x-component': 'InputNumber', + 'x-component-props': { + min: 1, + max: 10, + }, + default: 6, + }, + }; + useVariables(node, options): VariableOption { + return { + value: node.key, + label: node.title, + }; + } +} + +export default class MyPlugin extends Plugin { + load() { + // get workflow plugin instance + const workflowPlugin = this.app.getPlugin(WorkflowPlugin); + + // register instruction + workflowPlugin.registerInstruction('log', + + LogInstruction); + } +} +``` + +:::info{title=Tip} +The node type identifier registered on the client side must be consistent with the one on the server side; otherwise, errors will occur. +::: + +### Providing Node Results as Variables + +Notice the `useVariables` method in the example above. If the result of a node (`result` part) needs to be used as a variable by subsequent nodes, this method should be implemented in the derived command class, returning an object that conforms to the `VariableOption` type. This object describes the structure of the node’s run result, providing variable name mapping for selection and use in subsequent nodes. + +The `VariableOption` type is defined as follows: + +```ts +export type VariableOption = { + value?: string; + label?: string; + children?: VariableOption[] | null; + [key: string]: any; +}; +``` + +The core attribute is `value`, representing the segmented path value of the variable name, `label` for displaying on the interface, and `children` for representing a multi-level variable structure when the node’s result is a deep object. + +A usable variable is expressed internally in the system as a path template string separated by `.`. For example, `{{jobsMapByNodeKey.2dw92cdf.abc}}`. Here, `$jobsMapByNodeKey` represents the result set of all nodes (internally defined, no need to handle), `2dw92cdf` is the node’s `key`, and `abc` is a custom attribute in the node’s result object. + +Additionally, since the node’s result can also be a simple value, the first layer **must** be the node's description: + +```ts +{ + value: node.key, + label: node.title, +} +``` + +That is, the first layer is the `key` and title of the node. For example, in the calculation node's [code reference](https://github.com/nocobase/nocobase/blob/main/packages/plugins/%40nocobase/plugin-workflow/src/client/nodes/calculation.tsx#L77), the options on the interface when using the result of the calculation node are as follows: + +![Calculation Node Result](https://static-docs.nocobase.com/20240514230014.png) + +When the node result is a complex object, you can use `children` to continue describing the deep-level attributes. For example, a custom command returns the following JSON data: + +```json +{ + "message": "ok", + "data": { + "id": 1, + "name": "test", + } +} +``` + +Then the `useVariables` method can return: + +```ts +useVariables(node, options): VariableOption { + return { + value: node.key, + label: node.title, + children: [ + { + value: 'message', + label: 'Message', + }, + { + value: 'data', + label: 'Data', + children: [ + { + value: 'id', + label: 'ID', + }, + { + value: 'name', + label: 'Name', + }, + ], + }, + ], + }; +} +``` + +This way, the following interface can be used to select among the variables in subsequent nodes: + +![Mapped Result Variables](https://static-docs.nocobase.com/20240514230103.png) + +:::info{title="Tip"} +When a structure in the result is a deep object array, `children` can also be used to describe the path, but it cannot contain array indices. This is because, in NocoBase workflow variable handling, the variable path description for object arrays is automatically flattened into an array of deep values, and array indices cannot be used to access a specific value. You can refer to the content in the "Workflow: Advanced Usage" section of [Advanced Variables](../manual/advanced#Using Variables). +::: + +### Learn More + +For a detailed definition of each parameter in defining node types, refer to the [Workflow API Reference](./api#instruction-1) section. diff --git a/docs/fr-FR/handbook/workflow/development/trigger.md b/docs/fr-FR/handbook/workflow/development/trigger.md new file mode 100644 index 000000000..ffab374da --- /dev/null +++ b/docs/fr-FR/handbook/workflow/development/trigger.md @@ -0,0 +1,108 @@ +# **Extend Trigger Types** + +Every workflow must be configured with a specific trigger that serves as the entry point for executing the process. + +Trigger types typically correspond to specific system events. Throughout an application's lifecycle, any event that offers a subscription option can be defined as a trigger type. Examples include receiving requests, data table operations, or scheduled tasks. + +Trigger types are registered in the plugin's trigger registry using unique string identifiers. The workflow plugin comes with several built-in triggers: + +- `'collection'`: Triggered by data table operations. +- `'schedule'`: Triggered by scheduled tasks. +- `'action'`: Triggered by post-operation events. + +When extending trigger types, it's essential to ensure that each identifier is unique. The server side should handle the registration for subscribing and unsubscribing to triggers, while the client side should provide the corresponding configuration interface. + +## **Server-Side Implementation** + +Any custom trigger should extend the `Trigger` base class and implement the `on` and `off` methods, which manage the subscription and unsubscription to specific system events. The `on` method must invoke `this.workflow.trigger()` within the event callback to trigger the workflow. The `off` method should ensure proper cleanup during unsubscription. + +The `this.workflow` property refers to the workflow plugin instance, passed into the `Trigger` base class during construction. + +```ts +import { Trigger } from '@nocobase/plugin-workflow'; + +class MyTrigger extends Trigger { + timer: NodeJS.Timeout; + + on(workflow) { + // Register event + this.timer = setInterval(() => { + // Trigger workflow + this.workflow.trigger(workflow, { date: new Date() }); + }, workflow.config.interval ?? 60000); + } + + off(workflow) { + // Unregister event + clearInterval(this.timer); + } +} +``` + +Next, register the trigger instance with the workflow engine in the plugin that extends the workflow: + +```ts +import WorkflowPlugin from '@nocobase/plugin-workflow'; + +export default class MyPlugin extends Plugin { + load() { + // Get workflow plugin instance + const workflowPlugin = this.app.pm.get(WorkflowPlugin) as WorkflowPlugin; + + // Register trigger + workflowPlugin.registerTrigger('interval', MyTrigger); + } +} +``` + +Once the server is up and running, the `'interval'` trigger type will be available for addition and execution. + +## **Client-Side Configuration** + +On the client side, the primary task is to provide a configuration interface tailored to the specific settings required for each trigger type. Each trigger type should also be registered with the workflow plugin. + +For instance, to configure the interval-based trigger mentioned earlier, define the `interval` configuration field in the form interface: + +```ts +import { Trigger } from '@nocobase/workflow/client'; + +class MyTrigger extends Trigger { + title = 'Interval Timer Trigger'; + // Fields of trigger config + fieldset = { + interval: { + type: 'number', + title: 'Interval', + name: 'config.interval', + 'x-decorator': 'FormItem', + 'x-component': 'InputNumber', + default: 60000, + }, + }; +} +``` + +Then, register this trigger type with the workflow plugin instance in the extending plugin: + +```ts +import { Plugin } from '@nocobase/client'; +import WorkflowPlugin from '@nocobase/plugin-workflow/client'; + +import MyTrigger from './MyTrigger'; + +export default class extends Plugin { + // Modify the app instance here if necessary + async load() { + const workflow = this.app.pm.get(WorkflowPlugin) as WorkflowPlugin; + workflow.registerTrigger('interval', MyTrigger); + } +} +``` + +Once registered, the new trigger type will appear in the workflow configuration interface. + +:::info{title=Tip} +Ensure that the trigger type identifier registered on the client side matches the one on the server side to avoid errors. +::: + +For further details on defining trigger types, refer to the [Workflow API Reference](./api#pluginregisterTrigger) section. diff --git a/docs/fr-FR/handbook/workflow/index.md b/docs/fr-FR/handbook/workflow/index.md new file mode 100755 index 000000000..a549afaef --- /dev/null +++ b/docs/fr-FR/handbook/workflow/index.md @@ -0,0 +1,35 @@ +# Overview + +## Introduction + +The Workflow plugin is a powerful tool commonly known as a Business Process Management (BPM) tool in the industry. It is used for designing and orchestration of business processes based on data models. By organizing the trigger conditions and flow nodes, it makes the business process running automatically. + +In NocoBase applications, the Workflow plugin is designed for no-code scenarios, allowing users to orchestrate and process common business tasks through the UI. Therefore they can change the business processes in the system runtime dynamically. + +Each workflow consists of a trigger and several nodes. Through the specific functionality of each node, the workflow describes the business logic that needs to be processed when the corresponding event occurs in the system. A typical workflow is illustrated in the following diagram: + +![Example of workflow](https://static-docs.nocobase.com/4511011beac54779cb68e66555ebf8a8.png) + +The functionality of the above workflow is as follows: When a user submits an order form, the system automatically checks the inventory of the products in the order. If there is sufficient stock, the inventory will be deducted; otherwise, the order will be updated as invalid. + +As a more general perspective, workflows in NocoBase applications can address the following scenarios: + +- **Data automation processing**: For example, automatically process data in a collection according to predefined workflows, such as calculating and updating associated data after a triggered event. +- **Human-involved business processes**: When a business process cannot be fully automated, partial decision-making can be assigned to user through manual nodes, such as approval and review. After the results of processing are submitted by user, the subsequent processes continue. +- **Integration with external systems**: API interfaces of external systems can be called through request nodes (or nodes that extend various types of third-party function calls) to achieve data interaction with external systems. + +## Installation + +Workflow is a built-in plugin in NocoBase and does not require additional installation. + +## Learn More + +- [Quick start](./quick-start.md) +- Advanced understanding + - [Executions](./advanced/executions.md) + - [Advanced Options](./advanced/options.md) + - [Variables](./advanced/variables.md) + - [Revisions](./advanced/revisions.md) +- [Triggers](./triggers/index.md) +- [Nodes](./nodes/index.md) +- [Development Guide](./development/index.md) diff --git a/docs/fr-FR/handbook/workflow/nodes/aggregate.md b/docs/fr-FR/handbook/workflow/nodes/aggregate.md new file mode 100644 index 000000000..5439ce1bf --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/aggregate.md @@ -0,0 +1,3 @@ +# Aggregate Query + + diff --git a/docs/fr-FR/handbook/workflow/nodes/approval.md b/docs/fr-FR/handbook/workflow/nodes/approval.md new file mode 100644 index 000000000..0ad06ffa6 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/approval.md @@ -0,0 +1,9 @@ +# Approval + + + + + +## Related Content + +Except for node configuration, there are also some related contents about approval that can be further understood through the [plugin documentation](../../workflow-approval/index.md). diff --git a/docs/fr-FR/handbook/workflow/nodes/calculation.md b/docs/fr-FR/handbook/workflow/nodes/calculation.md new file mode 100644 index 000000000..761916cf3 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/calculation.md @@ -0,0 +1,39 @@ +# Calculation + +Although the calculation node does not control the flow of the process, it is an important function in the workflow. The calculation node can evaluate an expression, and the result will be stored in the corresponding node's result for later use by other nodes. It is a tool for calculating, processing, and transforming data. To some extent, it can replace the functionality of calling a function to compute a value in programming languages and assigning it to a variable. + +## Creating a Node + +In the workflow configuration UI, click the plus ("+") button in the flow to add a "Calculation" node: + +![Calculation Node - Adding](https://static-docs.nocobase.com/58a455540d26945251cd143eb4b16579.png) + +## Node Configuration + +![Calculation Node - Configuration](https://static-docs.nocobase.com/6a155de3f6a883d8cd1881b2d9c33874.png) + +### Calculation Engine + +The calculation engine specifies the syntax supported of the expression. Currently supported calculation engines include [Math.js](https://mathjs.org/) and [Formula.js](https://formulajs.info/), each of which has built-in support for a large number of common functions and methods for data manipulation. Specific usage can be found in their official documentation. + +:::info{title=Note} +It's important to note that there is a difference in array indexing between the them. In Math.js, indexing starts from `1`, while in Formula.js, it starts from `0`. +::: + +Additionally, if simple string concatenation is needed, the "String Template" can be used directly. This engine will replace variables in the expression with their corresponding values and then return the concatenated string. + +### Expression + +The expression is a string representation of a calculation formula, composed of variables, constants, operators, and supported functions. Variables from the workflow context can be used, such as results from preceding nodes of the calculation node or scope variables from loops. + +If the expression input does not comply with the syntax, an error will be prompted in the node configuration. If a variable does not exist during execution or its type does not match, or if an undefined function is used, the calculation node will terminate prematurely with an error status. + +## Example + +### Calculating Total Order Price + +Typically, an order may contain multiple items, each with different prices and quantities. The total price of the order requires calculating the sum of the products of prices and quantities for all items. You can use a calculation node to compute the total order price after loading the list of order details (a many-to-many relationship dataset): + +![Calculation Node - Example - Node Configuration](https://static-docs.nocobase.com/85966b0116afb49aa966eeaa85e78dae.png) + +Where the `SUMPRODUCT` function from Formula.js calculates the sum of the products of two arrays of the same length, and then summing them up yields the total order price. diff --git a/docs/fr-FR/handbook/workflow/nodes/condition.md b/docs/fr-FR/handbook/workflow/nodes/condition.md new file mode 100644 index 000000000..46e8d6407 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/condition.md @@ -0,0 +1,33 @@ +# Condition + +Similar to the `if` statement in programming languages, the condition node determines the direction of the subsequent flow based on the result of the configured condition. + +## Creating a Node + +There are two modes for condition: "Continue if 'true'" and "Continue if 'true' or 'false'". When creating the node, you need to choose one of these modes, and it cannot be changed in the node's configuration afterward. + +![Mode Selection for Condition](https://static-docs.nocobase.com/3de27308c1179523d8606c66bf3a5fb4.png) + +In the "Continue if 'true'" mode, when the result of the condition judgment is "true", workflow will continue to execute the subsequent nodes; otherwise, the flow will terminate and exit prematurely with a failed status. + +![Continue if 'true' Mode](https://static-docs.nocobase.com/0f6ae1afe61d501f8eb1f6dedb3d4ad7.png) + +This mode is suitable for scenarios where the flow should not continue if the condition is not met. For example, when configuring a form button to submit an order which bound with a "Pre-action event", if there is insufficient stock for the items in the order, the process should not continue to generate the order but instead fail and exit. + +In the "Continue if 'true' or 'false'" mode, the condition node will produce two branches of the flow, corresponding to the scenarios where the condition judgment results are "true" and "false". Each branch can have subsequent nodes configured separately. After either branch completes execution, it will automatically return back to the parent branch where the condition node is located and continue executing the subsequent nodes. + +![Continue if 'true' or 'false' Mode](https://static-docs.nocobase.com/974a1fcd8603629b64ffce6c55d59282.png) + +This mode is suitable for scenarios where different operations need to be performed depending on whether the condition is met or not. For example, checking if a piece of data exists, and if it doesn't, inserting it; if it does, updating it. + +## Node Configuration + +### Calculation Engine + +Currently, three engines are supported: + +- **Basic**: Obtains logical results through simple binary calculations and grouping with "AND" and "OR". +- **Math.js**: Computes logical results from expressions supported by the [Math.js](https://mathjs.org/) engine. +- **Formula.js**: Computes logical results from expressions supported by the [Formula.js](https://formulajs.info/) engine. + +All three calculations can use variables from the workflow context as operands for computation. diff --git a/docs/fr-FR/handbook/workflow/nodes/create.md b/docs/fr-FR/handbook/workflow/nodes/create.md new file mode 100644 index 000000000..4dce38894 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/create.md @@ -0,0 +1,41 @@ +# Create record + +Used to add a new row of data to a specific collection. + +The field values ​​of the new record can use variables from the workflow context. Assigning values to association fields can directly reference the corresponding data variables in the context, which can be objects or foreign key values. If variables are not used, you need to manually enter the values ​​of the foreign keys, and for multiple association fields, multiple foreign key values ​​need to be separated by commas. + +## Creating a Node + +In the workflow configuration UI, click the plus ("+") button in the flow to add a "Create record" node: + +![Creating a create record node](https://static-docs.nocobase.com/386c8c01c89b1eeab848510e77f4841a.png) + +## Node Configuration + +![New Node Example Node Configuration](https://static-docs.nocobase.com/5f7b97a51b64a1741cf82a4d4455b610.png) + +### Collection + +Select the collection to which the new record will be added. + +### Field Values + +Assign values ​​to the fields of the collection. Variables from the workflow context can be used, or static values ​​can be manually entered. + +:::info{title="Note"} +Record added by the create node in the workflow will not automatically handle fields such as "Creator" and "Last Modifier", and you need to configure the values ​​of these two fields according to the situation. +::: + +### Preload Related Data + +If the fields of the new record include association fields, and you want to use the corresponding related data in subsequent workflows, you can check the corresponding association fields in the preload configuration. In this way, after adding the new record, the corresponding association data will be automatically loaded and stored together in the result data of the node. + +## Example + +For example, when a record is added or updated in the "Posts" collection, it is required to automatically add a "Post Versions" row to record the change history of the post. This can be achieved using the create node: + +![New Node Example Flow Configuration](https://static-docs.nocobase.com/dfd4820d49c145fa331883fc09c9161f.png) + +![New Node Example Node Configuration](https://static-docs.nocobase.com/1a0992e66170be12a068da6503298868.png) + +With this configuration enabled, when data changes in the "Posts" collection, a "Post Version" row will be automatically added to record the change history of the article. diff --git a/docs/fr-FR/handbook/workflow/nodes/date-calculation.md b/docs/fr-FR/handbook/workflow/nodes/date-calculation.md new file mode 100644 index 000000000..a2776f749 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/date-calculation.md @@ -0,0 +1,3 @@ +# Date Calculation + + diff --git a/docs/fr-FR/handbook/workflow/nodes/delay.md b/docs/fr-FR/handbook/workflow/nodes/delay.md new file mode 100644 index 000000000..368ed5414 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/delay.md @@ -0,0 +1,3 @@ +# Delay + + diff --git a/docs/fr-FR/handbook/workflow/nodes/destroy.md b/docs/fr-FR/handbook/workflow/nodes/destroy.md new file mode 100644 index 000000000..59a8ac941 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/destroy.md @@ -0,0 +1,35 @@ +# Delete Record + +Used to delete data from a specific collection that meets certain conditions. + +The basic usage of the delete node is similar to the update node, except that the delete node does not require field assignments, only the selection of the collection and filter conditions are needed. The result of the delete node will return the number of rows deleted successfully, which can only be viewed in the execution history and cannot be used as a variable in subsequent nodes. + +:::info{title=Note} +Currently, the delete node does not support deleting one by one, all deletions are performed in batches, so other events triggered by each data deletion will not be triggered. +::: + +## Creating a Node + +In the workflow configuration interface, click the plus ("+") button in the flow to add a "Delete Record" node: + +![Creating a Delete Record Node](https://static-docs.nocobase.com/e1d6b8728251fcdbed6c7f50e5570da2.png) + +## Node Configuration + +![Delete Node Node Configuration](https://static-docs.nocobase.com/580600c2b13ef4e01dfa48b23539648e.png) + +### Collection + +Select the collection from which data will be deleted. + +### Filter Conditions + +Similar to the filter conditions used in regular collection queries, variables from the workflow context can be used. + +## Example + +For example, to regularly clean up invalid historical order data that has been canceled, you can use a delete node: + +![Delete Node Example Node Configuration](https://static-docs.nocobase.com/b94b75077a17252f8523c3f13ce5f320.png) + +The workflow will be triggered periodically and execute to delete all invalid historical order data that has been canceled. diff --git a/docs/fr-FR/handbook/workflow/nodes/dynamic-calculation.md b/docs/fr-FR/handbook/workflow/nodes/dynamic-calculation.md new file mode 100644 index 000000000..71b98bb77 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/dynamic-calculation.md @@ -0,0 +1,7 @@ +# Dynamic Calculation + + + +## Related Content + +Except for node configuration, there are also some related contents about dynamic calculation that can be further understood through the [plugin documentation](../../workflow-dynamic-calculation/index.md). diff --git a/docs/fr-FR/handbook/workflow/nodes/end.md b/docs/fr-FR/handbook/workflow/nodes/end.md new file mode 100644 index 000000000..960a0bc57 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/end.md @@ -0,0 +1,23 @@ +# End Process + +When executed, this node will immediately end the current workflow execution and end it with the status as configured in the node. It is typically used for specific logic flow control, to exit the current workflow after meeting certain logical conditions, and not continue with subsequent processing. It can be compared to the `return` instruction in programming languages, used to exit the currently executing function. + +## Creating a Node + +In the workflow configuration UI, click the plus ("+") button in the flow to add an "End Process" node: + +![Add End Process](https://static-docs.nocobase.com/672186ab4c8f7313dd3cf9c880b524b8.png) + +## Node Configuration + +![End Process Node Configuration](https://static-docs.nocobase.com/bb6a597f25e9afb72836a14a0fe0683e.png) + +### End Status + +The end status will affect the final status of the execution plan of the workflow. It can be configured as "Success" or "Failure". When the workflow reaches this node, it will immediately exit with the configured status. + +:::info{title=Note} +When used in workflows of the "Pre-action" type, it will intercept the action requests. For more details, please refer to the ["Pre-action" usage instructions](../triggers/pre-action). + +Besides intercepting the action requests, the configuration of the end status will also affect the status of the feedback information in the "Response Message" in this type of workflow. +::: diff --git a/docs/fr-FR/handbook/workflow/nodes/index.md b/docs/fr-FR/handbook/workflow/nodes/index.md new file mode 100755 index 000000000..029ec6f1c --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/index.md @@ -0,0 +1,36 @@ +# Overview + +Nodes are the basic units of logical arrangement in a workflow. A workflow can contains any number of nodes, and each node type represents an instruction that determines the behavior of the node. The configuration of a node corresponds to the parameters of the instruction, which determining the operation data object or other content of its behavior. + +:::info{title=Note} +Workflow triggers are not considered to be nodes but are displayed in the workflow diagram as entry nodes. They are different concepts from nodes. For details, please refer to the [Triggers](../triggers/index.md) section. +::: + +From a functional perspective, the nodes implemented so far are in four categories (a total of 21 types of nodes): + +- Flow Control + - [Condition](./condition.md) + - [Delay](./delay.md) (provided by plugin @nocobase/plugin-workflow-deley) + - [End Process](./end.md) + - [Loop](./loop.md) (provided by plugin @nocobase/plugin-workflow-loop) + - [Parallel Branch](./parallel.md) (provided by plugin @nocobase/plugin-workflow-parallel) + - [Custom Variable](./variable.md) (provided by plugin @nocobase/plugin-workflow-variable) +- Calculation + - [Calculation](./calculation.md) + - [Dynamic Expression Calculation](./dynamic-calculation.md) (provided by plugin @nocobase/plugin-workflow-dynamic-calculation) + - [Date Calculation](./date-calculation.md) (provided by plugin @nocobase/plugin-workflow-date-calculation) +- Data Table Operations + - [Create record](./create.md) + - [Update record](./update.md) + - [Delete record](./destroy.md) + - [Query record](./query.md) + - [Aggregate Query](./aggregate.md) (provided by plugin @nocobase/plugin-workflow-aggregate) + - [SQL Operation](./sql.md) (provided by plugin @nocobase/plugin-workflow-sql) +- Manual Processing + - [Manual Processing](./manual.md) (provided by plugin @nocobase/plugin-workflow-manual) + - [Approval](./approval.md) (provided by plugin @nocobase/plugin-workflow-approval) +- Other Extensions + - [HTTP Request](./request.md) (provided by plugin @nocobase/plugin-workflow-request) + - [Response Message](./response-message.md) (provided by plugin @nocobase/plugin-workflow-response-message) + - [JavaScript](./javascript.md) (provided by plugin @nocobase/plugin-workflow-javascript) + - [JSON query](./json-query.md) (provided by plugin @nocobase/plugin-workflow-json-query) diff --git a/docs/fr-FR/handbook/workflow/nodes/javascript.md b/docs/fr-FR/handbook/workflow/nodes/javascript.md new file mode 100644 index 000000000..ced52fb87 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/javascript.md @@ -0,0 +1,3 @@ +# JavaScript + + diff --git a/docs/fr-FR/handbook/workflow/nodes/json-query.md b/docs/fr-FR/handbook/workflow/nodes/json-query.md new file mode 100644 index 000000000..4d0773a43 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/json-query.md @@ -0,0 +1,3 @@ +# JSON Query + + diff --git a/docs/fr-FR/handbook/workflow/nodes/loop.md b/docs/fr-FR/handbook/workflow/nodes/loop.md new file mode 100644 index 000000000..9b57df665 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/loop.md @@ -0,0 +1,3 @@ +# Loop + + diff --git a/docs/fr-FR/handbook/workflow/nodes/manual.md b/docs/fr-FR/handbook/workflow/nodes/manual.md new file mode 100644 index 000000000..ac1235bb6 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/manual.md @@ -0,0 +1,9 @@ +# Manual Process + + + + + +## Related Content + +Except for node configuration, there are also some related contents about manual process that can be further understood through the [plugin documentation](../../workflow-manual/index.md). diff --git a/docs/fr-FR/handbook/workflow/nodes/parallel.md b/docs/fr-FR/handbook/workflow/nodes/parallel.md new file mode 100644 index 000000000..13ac5a6c7 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/parallel.md @@ -0,0 +1,3 @@ +# Parallel Branch + + diff --git a/docs/fr-FR/handbook/workflow/nodes/query.md b/docs/fr-FR/handbook/workflow/nodes/query.md new file mode 100644 index 000000000..4938a966b --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/query.md @@ -0,0 +1,42 @@ +# Query Record + +Used to query and retrieve data records that meet certain conditions from a collection. + +It can be configured to query single or multiple data records, and the query result can be used as a variable in subsequent nodes. When querying multiple data records, the query result is an array. When the query result is empty, you can choose whether to continue executing subsequent nodes. + +## Creating a Node + +In the workflow configuration UI, click the plus ("+") button in the workflow and add a "Query Record" node: + +![Query Record_Add](https://static-docs.nocobase.com/c1ef2b851b437806faf7a39c6ab9d33a.png) + +## Node Configuration + +![Query Node_Node Configuration](https://static-docs.nocobase.com/20240520131324.png) + +### Collection + +Select the collection to query record from. + +### Result type + +There are two result types: "Single Data" and "Multiple record": + +- Single record: The result will be an object of the first matching record only, or null if no matched record. +- Multiple records: The result will be an array containing matched records, or an empty one if no matching records. This can be used to be processed in a loop node. + +### Filter Conditions + +Similar to the filter conditions when querying a normal collection, you can use context variables of the workflow. + +### Sorting + +When querying one or more data records, sorting rules can be used to control the desired results. For example, to query the latest data record, you can sort by the "Created at" field in descending order. + +### Pagination + +When the result set may be large, pagination can be used to control the number of query results. For example, to query the latest 10 data records, you can sort by the "Creation Time" field in descending order and then set pagination to 1 page with 10 data records. + +### Handling Empty Results + +In single result mode, if there are no data records that meet the conditions, the query result will be `null`; in multiple result mode, it will be an empty array (`[]`). You can choose whether to check "Exit the workflow if the query result is empty". After checked, if the query result is empty, subsequent nodes will not be executed, and the workflow will exit prematurely with a failed status. diff --git a/docs/fr-FR/handbook/workflow/nodes/request.md b/docs/fr-FR/handbook/workflow/nodes/request.md new file mode 100644 index 000000000..02c79587d --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/request.md @@ -0,0 +1,3 @@ +# HTTP Request + + diff --git a/docs/fr-FR/handbook/workflow/nodes/response-message.md b/docs/fr-FR/handbook/workflow/nodes/response-message.md new file mode 100644 index 000000000..ea1cd011a --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/response-message.md @@ -0,0 +1,3 @@ +# Response Message + + diff --git a/docs/fr-FR/handbook/workflow/nodes/response.md b/docs/fr-FR/handbook/workflow/nodes/response.md new file mode 100644 index 000000000..a886d97ee --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/response.md @@ -0,0 +1,5 @@ +# HTTP Response + +HTTP Response node could be used in Webhook event (under synchronous mode) to return response to the third-party system. + +See: [Response](/handbook/workflow-webhook#Response)。 \ No newline at end of file diff --git a/docs/fr-FR/handbook/workflow/nodes/sql.md b/docs/fr-FR/handbook/workflow/nodes/sql.md new file mode 100644 index 000000000..970f47014 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/sql.md @@ -0,0 +1,3 @@ +# SQL Operation + + diff --git a/docs/fr-FR/handbook/workflow/nodes/update.md b/docs/fr-FR/handbook/workflow/nodes/update.md new file mode 100644 index 000000000..142db11cc --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/update.md @@ -0,0 +1,41 @@ +# Update Record + +Used to update data records that meet certain conditions in a collection. + +The collection and field assignment sections are the same as in the "Create Record" node. The main difference between "Update Record" node and "Create record" node is the filter conditions, and the need to select an update mode. In addition, the update node will return the number of rows of successfully updated data, which can only be viewed in the execution history and cannot be used as a variable in subsequent nodes. + +## Creating a Node + +In the workflow configuration UI, click the plus ("+") button in the workflow and add an "Update Record" node: + +![Update Record_Add](https://static-docs.nocobase.com/9ff24d7bc173b3a71decc1f70ca9fb66.png) + +## Node Configuration + +![Update Node_Node Configuration](https://static-docs.nocobase.com/98e0f941c57275fc835f08260d0b2e86.png) + +### Collection + +Select the collection to update record in. + +### Update Mode + +There are "Batch" and "Individual" modes for updating. In batch mode, each record updating will not trigger the collection events; whereas, in individual mode, each record updating could trigger the collection events. However, there may be performance issues with individual updates, especially with large amounts of data, so use with caution. Typically, choose based on the target data to be updated and whether other workflow events need to be triggered. If updating a single data record based on a primary key, it is recommended to use individual updates; if updating multiple data records based on conditions, it is recommended to use batch updates. + +### Filter Conditions + +Similar to the filter conditions when querying a normal collection, you can use context variables of the workflow. + +### Field Values + +Similar to the field assignment in the "Create Record" node, you can use variables from the workflow context or manually enter static values. + +Note: The update node in the workflow does not automatically handle the "Last Modified By" data; you need to configure the value of this field based on the situation. + +## Example + +For example, when a "Post" created, the "Post Category" collection needs to be automatically updated with the "Post Count" field. This can be achieved using an update node: + +![Update Node_Example_Node Configuration](https://static-docs.nocobase.com/98e0f941c57275fc835f08260d0b2e86.png) + +When the workflow is triggered, the "Post Count" field in the "Post Category" collection will automatically be updated to the current post count +1. diff --git a/docs/fr-FR/handbook/workflow/nodes/variable.md b/docs/fr-FR/handbook/workflow/nodes/variable.md new file mode 100644 index 000000000..a4956b91a --- /dev/null +++ b/docs/fr-FR/handbook/workflow/nodes/variable.md @@ -0,0 +1,3 @@ +# Custom Variable + + diff --git a/docs/fr-FR/handbook/workflow/plugins/aggregate.md b/docs/fr-FR/handbook/workflow/plugins/aggregate.md new file mode 100644 index 000000000..08c2739ba --- /dev/null +++ b/docs/fr-FR/handbook/workflow/plugins/aggregate.md @@ -0,0 +1,67 @@ +# Aggregate + + + +This plugin is designed to execute aggregate function queries on specific data within a table that meets defined conditions, returning the relevant statistical outcomes. It is particularly useful for generating statistical data for reports. + +The node operates using database aggregate functions and currently supports querying a single field within a single data table. The resulting statistics are stored within the node’s output, making them available for subsequent nodes in the workflow. + +## Installation + +This is a built-in plugin, so no installation steps are required. + +## User Manual + +### Creating a Node + +In the workflow configuration interface, click the plus ("+") button within the process flow to add an "Aggregate Query" node: + +![Create Aggregate Query Node](https://static-docs.nocobase.com/7f9d806ebf5064f80c30f8b67f316f0f.png) + +### Node Configuration + +![Aggregate Query Node_Configuration](https://static-docs.nocobase.com/57362f747b9992230567c6bb5e986fd2.png) + +#### Aggregate Functions + +This plugin supports five SQL aggregate functions: `COUNT`, `SUM`, `AVG`, `MIN`, and `MAX`. You can select any one of these functions to perform the aggregate query on your data. + +#### Target Type + +There are two methods for selecting the target of the aggregate query. The first is to directly select the target data table and one of its fields. The second is to choose a related data table and field from the existing data objects in the workflow context to perform the aggregate query. + +#### Distinct + +This feature corresponds to the `DISTINCT` keyword in SQL. The distinct field must be the same as the selected data table field, and currently, different fields cannot be selected for the distinct and target fields. + +#### Filter Conditions + +You can apply filter conditions similar to those in a standard data table query, using the workflow’s context variables. + +### Example + +The aggregate target "Collection Table Data" is quite intuitive, so let's illustrate the usage of the aggregate target as "Related Collection Table Data" with the example of "counting the total number of articles in a category after adding a new article to that category." + +First, create two data tables: "Posts" and "Categories." The "Posts" collection includes a many-to-one relationship field pointing to the "Categories" collection, and a reverse relationship field that allows one category to contain multiple articles: + +| Field Name | Type | +| ----------------- | ------------------ | +| Title | Single Line Text | +| Category | Many-to-One (Category) | + +| Field Name | Type | +|---------------| ------------------ | +| Category Name | Single Line Text | +| Posts | One-to-Many (Articles) | + +Next, create a workflow triggered by an event in the data table, specifically when new data is added to the "Articles" table. + +Then, add an aggregate query node with the following configuration: + +![Aggregate Query Node_Example_Configuration](https://static-docs.nocobase.com/542272e638c6c0a567373d1b37ddda78.png) + +Once the workflow is triggered, the aggregate query node will calculate the total number of articles within the category of the newly added article and save this count as the node’s output. + +:::info{title=Tip} +If you need to access related data in a collection table event trigger, ensure you configure the relevant fields for "Preload associations" in the trigger; otherwise, these fields won’t be selectable. +::: diff --git a/docs/fr-FR/handbook/workflow/quick-start.md b/docs/fr-FR/handbook/workflow/quick-start.md new file mode 100644 index 000000000..5fbd9d423 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/quick-start.md @@ -0,0 +1,94 @@ +# Quick Start + +## Configure a Workflow + +To configure a workflow, go to the management page of the Workflow plugin by accessing the plugin configuration menu in the top navigation bar: + +![Workflow Plugin Management Entry](https://static-docs.nocobase.com/872169fb0cf277715178d1a6804e12cd.png) + +The management page will display all the created workflows: + +![Workflow Management](https://static-docs.nocobase.com/6d31e5c6c94a51513e6569dbc410c01f.png) + +Click the "Add new" button to create a new workflow and select a collection event: + +![Create Workflow](https://static-docs.nocobase.com/57f23ce3c91d153ea235f95268a63d98.png) + +Click the "Configure" link in the list to enter the workflow configuration page: + +![An Empty Workflow](https://static-docs.nocobase.com/d6a3bc6b3fd03cba5bb10f142c38e2bf.png) + +Then, click on the trigger card to open the trigger configuration drawer. Select a previously created collection (e.g., "Posts") and choose the trigger condition "After record added", click the "Save" button to complete the trigger configuration: + +![Configure Trigger](https://static-docs.nocobase.com/f96015efe87759d6836d2a1c58d92884.png) + +Next, you can click the plus button in the workflow to add a node. For example, select an calculation node to concatenate the "Title" and "ID" fields of the trigger data: + +![Add Operation Node](https://static-docs.nocobase.com/60eeee25e6847a91fad50784c8c508ad.png) + +Click on the node card to open the node configuration drawer. Use the `CONCATENATE` function provided by Formula.js to concatenate the "Title" and "ID" fields, and insert the fields using the variable selector: + +![Operation Node with Function and Variable](https://static-docs.nocobase.com/837e4851a4c70a1932542caadef3431b.png) + +Then create an "Update record" node to save the result to the "Title" field: + +![Create Update Data Node](https://static-docs.nocobase.com/494f72dff72b4410240b04c59cbbd322.png) + +Similarly, click on the card to open the configuration drawer of the "Update record" node. Select the "Posts" collection, choose the record ID from the trigger, select the "Title" field to update, and choose the result from the calculation node as the value to update: + +![Configure Update Data Node](https://static-docs.nocobase.com/2e147c93643e7ebc709b9b7ab4f3af8c.png) + +Finally, click the "On/Off" switch in the top-right toolbar to switch the workflow to the enabled state. This allows the workflow to be triggered and executed. + +## Trigger a Workflow + +Go back to the main pages and create an post using the its data block. Fill in the post title: + +![Create Post Data](https://static-docs.nocobase.com/d21a1a5833d5f54f52678ea18e9922f2.png) + +After submission and refreshing the block, you will see that the post title has been automatically updated to the form of "Post title + Post ID": + +![Post Title Modified by Workflow](https://static-docs.nocobase.com/3a700445896965c46c70ac51a07bbdb9.png) + +:::info{title=Note} +Since workflow triggered in collection will be executed asynchronously, you may not immediately see the updated record on the submission page. However, refreshing the page or block after a moment, updated content will show. +::: + +## View Execution History + +The workflow we triggered earlier has been successfully executed. We can go back to the workflow management page to view the corresponding execution history: + +![View Workflow List](https://static-docs.nocobase.com/92952de7fe6472db7d247a915e36100a.png) + +In the workflow list, you can see that there is one execution in the workflow history. Clicking the number link in the "Executed" column will open the execution history of the corresponding workflow: + +![Execution History List of the Corresponding Workflow](https://static-docs.nocobase.com/00537af15c6ae43d745106178242bc09.png) + +Clicking the "View" link will take you to the details page of that particular execution. Here, you can see the execution status and result data of each node: + +![Workflow Execution History Details](https://static-docs.nocobase.com/93ec7ce25391d71cf7a109c9d03d5a48.png) + +The context data of trigger and the result data of node can be viewed by clicking the status button in the top right corner of the corresponding card. For example, let's view the result data of an operation node: + +![Result of calculation node](https://static-docs.nocobase.com/10c22b923d3de0a0d58fa9283780f592.png) + +You can see that the result data of the calculation node includes the computed title, which is the data updated by the subsequent "Update record" node. + +## Summary + +Through the above steps, we have completed the configuration and triggering of a simple workflow, and have also been introduced to the following basic concepts: + +- **Workflow**: It defines the basic information of the workflow, including its name, trigger type, and On/Off status. Within a workflow, you can configure multiple nodes. It serves as the container for the process. +- **Trigger**: Each workflow contains a trigger, which can be configured to specific conditions that triggers the workflow. It serves as the entry point of the workflow. +- **Node**: A node is an instruction unit within the workflow that performs specific actions. Multiple nodes within a workflow are interconnected in an upstream and downstream relationship, forming a complete process flow. +- **Execution**: The execution represents the specific objects that are executed after the workflow is triggered. It is also known as execution record or execution history, and it includes information such as the execution status and trigger context data. For each node, there is a corresponding execution result which includes the node's execution status and data. + +For more in-depth usage, you can refer to the following resources: + +- advanced Understanding + - [Using Variables](./advanced/variables.md) + - [Execution Plan (History)](./advanced/executions.md) + - [Revisions](./advanced/revisions.md) + - [Advanced Options](./advanced/options.md) +- [Overview of Triggers](./triggers/index.md) +- [Overview of Nodes](./nodes/index.md) diff --git a/docs/fr-FR/handbook/workflow/triggers/approval.md b/docs/fr-FR/handbook/workflow/triggers/approval.md new file mode 100644 index 000000000..f3ff5c97f --- /dev/null +++ b/docs/fr-FR/handbook/workflow/triggers/approval.md @@ -0,0 +1,9 @@ +# Approval + + + + + +## Related Content + +Except for trigger configuration, there are also some related contents about approval that can be further understood through the [plugin documentation](../../workflow-approval/index.md). diff --git a/docs/fr-FR/handbook/workflow/triggers/collection.md b/docs/fr-FR/handbook/workflow/triggers/collection.md new file mode 100644 index 000000000..b15e8ed68 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/triggers/collection.md @@ -0,0 +1,86 @@ +# Collection event + +Trigger types of collection events will listen for adding, deleting and updating events of the collection. When an action on the record of collection occurs and meets the configured conditions, the corresponding workflow will be triggered. For example, reducing the inventory of goods after adding a new order, waiting for manual review after adding a comment, etc. + +## Basic Usage + +There are several types of changes to the collection: + +1. After a record added. +2. After a record updated. +3. After a record added or updated. +4. After a record deleted. + +![Collection Events_Trigger Timing Selection](https://static-docs.nocobase.com/81275602742deb71e0c830eb97aa612c.png) + +You can choose the timing of the trigger according to the needs of the business. When change type selected that includes updating a record, you can also limit the fields that have changed. Only when the selected fields change will the trigger condition be satisfied. If none are selected, it means that all fields changing will trigger. + +![Collection Events_Selection of Fields that Have Changed](https://static-docs.nocobase.com/874a1475f01298b3c00267b2b4674611.png) + +In more detail, conditions can be configured for each field of the triggered record. It only triggers when the conditions of the fields are met. + +![Collection Events_Configuring Conditions for Data Satisfying](https://static-docs.nocobase.com/264ae3835dcd75cee0eef7812c11fe0c.png) + +After the collection event is triggered, the source record of the event will be injected into the execution plan as trigger context data for subsequent nodes to use as variables. However, when subsequent nodes need to use the association fields of this record, preloading of the association fields needs to be configured first. The selected association fields will be injected into the context after triggering and can be selected and used by path. + +## Related Tips + +### Batch data action triggering is not supported + +Collection events do not support triggering on batch data action for now. For example, when adding article record and simultaneously adding multiple tag records of the article (many-to-many relationship data), only the workflow for adding the article will be triggered, and the workflows for adding multiple tags simultaneously will not be triggered. For associating or adding of many-to-many association records, the workflow of the intermediate collection will not be triggered either. + +### Data operations out of NocoBase application will not trigger + +Data actions on collections through HTTP API calls to the application interface can also trigger corresponding events. However, if the data changes are not made through the NodoBase application but directly through database operations, the corresponding events will not be triggered. For example, the triggers in the database itself will not be associated with workflows in the application. + +Also, using the SQL node to operate on the database is equivalent to directly operating on the database and will not trigger collection events. + +### External Data Sources + +from `0.20`, workflow started to support external data sources. If an external data source plugin is used and the collection event is configured for an external data source, as long as the data operation on this data source is completed within the application (user addition, update, and workflow data operations, etc.), the corresponding collection event can be triggered. However, if the data change is made through other systems or directly within the external database, the collection event will not be triggered. + +## Example + +Take an example scenario of calculating the total price and deducting inventory after adding an order. + +First, we create the product collection and the order collection, and the data model is as follows: + +| Field Name | Field Type | +| ---------- | ---------- | +| Product Name | Single Line Text | +| Price | Number | +| Inventory | Integer | + +| Field Name | Field Type | +| ---------- | ---------- | +| Order Number | Auto Number | +| Order Product | Many-to-One (Product) | +| Order Total Price | Number | + +And add basic product data: + +| Product Name | Price | Inventory | +| ------------ | ----- | -------- | +| iPhone 14 Pro | 7999 | 10 | +| iPhone 13 Pro | 5999 | 0 | + +Then create a workflow based on the collection event of the order: + +![Collection Events_Example_Add Order Trigger](https://static-docs.nocobase.com/094392a870dddc65aeb20357f62ddc08.png) + +Several configuration items: + +- Data collection: Select the "Order" table. +- Trigger on: Select "After Adding Data" trigger. +- Condition: Leave it blank. +- Preload associations: Check "Product". + +Then configure other nodes based on the logic of the workflow, check if the product inventory is greater than 0, and deduct inventory if it is, otherwise delete the order as it is invalid: + +![Collection Events_Example_Add Order Workflow Arrangement](https://static-docs.nocobase.com/7713ea1aaa0f52a0dc3c92aba5e58f05.png) + +The configuration of the nodes will be detailed in the documentation of the specific types. + +Enable the workflow and test by adding an order through the UI. After placing an order for "iPhone 14 Pro", the inventory of the corresponding product will be reduced to 9. However, if an order is placed for "iPhone 13 Pro", the order will be deleted due to insufficient inventory. + +![Collection Events_Example_Add Order Execution Result](https://static-docs.nocobase.com/24cbe51e24ba4804b3bd48d99415c54f.png) diff --git a/docs/fr-FR/handbook/workflow/triggers/custom-action.md b/docs/fr-FR/handbook/workflow/triggers/custom-action.md new file mode 100644 index 000000000..b6cfabc43 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/triggers/custom-action.md @@ -0,0 +1,9 @@ +# Custom action event + + + + + +## Related content + +Except for trigger configuration, there are also some related contents about custom action trigger that can be further understood through the [plugin documentation](../../workflow-custom-action-trigger/index.md). diff --git a/docs/fr-FR/handbook/workflow/triggers/index.md b/docs/fr-FR/handbook/workflow/triggers/index.md new file mode 100755 index 000000000..b06f6e728 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/triggers/index.md @@ -0,0 +1,23 @@ +# Overview + +Triggers are the entry points for workflow execution. When an event that meets the trigger conditions occurs during the application runtime, the workflow will be triggered. The type of trigger is also the type of workflow, chosen when creating the workflow and cannot be modified afterward. The currently supported trigger types are as follows: + +- [Collection Events](./collection.md) (built-in) +- [Scheduled Tasks](./schedule.md) (built-in) +- [Pre-Action Events](./pre-action.md) (provided by plugin @nocobase/plugin-workflow-request-interceptor) +- [Custom Action Events](./custom-action.md) (provided by plugin @nocobase/plugin-workflow-custom-action-trigger) +- [Post-Action Events](./post-action.md) (provided by plugin @nocobase/plugin-workflow-action-trigger) +- [Approval](./approval.md) (provided by plugin @nocobase/plugin-workflow-approval) +- [Webhook](./webhook.md) (provided by plugin @nocobase/plugin-workflow-webhook) + +The timing of each event trigger type is shown in the following diagram: + +![Workflow Events](https://static-docs.nocobase.com/20240514214606.png) + +For example, when a user submits a form, or data in a collection changes due to user action or program calls, or when a task reaches its scheduled time, the corresponding workflow will be triggered. + +Triggers related to data (such as actions, collection events) usually carry trigger context data. This data can be referenced in the nodes of the workflow to achieve automated data processing. For instance, when a user submits a form bound to a workflow, the submitted data will be injected into the context environment of the execution plan, allowing subsequent nodes to use it as variables. + +After creating a workflow, the trigger will appear as an entry node at the beginning of the flow on the workflow view page. Click the card to open the configuration drawer. Depending on the trigger type, relevant conditions can be configured. + +![Trigger_Entry Node](https://static-docs.nocobase.com/e8dc1937e41b2712b67d84d60e94b11e.png) diff --git a/docs/fr-FR/handbook/workflow/triggers/post-action.md b/docs/fr-FR/handbook/workflow/triggers/post-action.md new file mode 100644 index 000000000..9a2896968 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/triggers/post-action.md @@ -0,0 +1,10 @@ +# Post-action event + + + + + + +## Related content + +Except for trigger configuration, there are also some related contents about post-action trigger that can be further understood through the [plugin documentation](../../workflow-action-trigger/index.md). diff --git a/docs/fr-FR/handbook/workflow/triggers/pre-action.md b/docs/fr-FR/handbook/workflow/triggers/pre-action.md new file mode 100644 index 000000000..03cf4a278 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/triggers/pre-action.md @@ -0,0 +1,9 @@ +# Pre-action trigger + + + + + +## Related content + +Except for trigger configuration, there are also some related contents about pre-action trigger that can be further understood through the [plugin documentation](../../workflow-request-interceptor/index.md). diff --git a/docs/fr-FR/handbook/workflow/triggers/schedule.md b/docs/fr-FR/handbook/workflow/triggers/schedule.md new file mode 100644 index 000000000..7a3867678 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/triggers/schedule.md @@ -0,0 +1,73 @@ +# Schedule event + +Scheduled tasks are events triggered based on time conditions, including two modes: + +- Custom Time: Regularly scheduled triggers similar to cron based on system time. +- Time field of collection: Triggered according to the value of the time field in the collection. + +When the system reaches the time (accurate to seconds) that meets the configured trigger conditions, the corresponding workflow will be triggered. + +## Basic Usage + +### Creating Schedule event + +Select the "Schedule event" type when creating a workflow in the workflow list: + +![Create Scheduled event](https://static-docs.nocobase.com/e09b6c9065167875b2ca7de5f5a799a7.png) + +### Custom Time Mode + +For the regular mode, start by configuring the start time to any point in time (accurate to seconds). The start time can be set to a future time or a past time. When set to a past time, it will check whether it is time based on the configured repeat condition. If no repeat condition is configured, the workflow will not be triggered if the start time is in the past. + +There are two ways to configure repeat rules: + +- Interval Time: Trigger every fixed interval after the start time, such as every hour, every 30 minutes, etc. +- Advanced Mode: Using cron rules, it can be configured to occur at fixed rule of dates and times. + +After configuring the repeat rule, you can also configure the end condition, which can end at a fixed point in time or by the number of times executed. + +### Time Field of Collection Mode + +Using the time field of the collection to determine the start time is a trigger mode that combines ordinary scheduled tasks with the collection time field. Using this mode can simplify some nodes in specific processes and make the configuration more intuitive. For example, to change the status of orders that have not been paid for more than 30 minutes to canceled, you can simply configure a scheduled task in the collection time field mode, select the start time as 30 minutes after the order created time field. + +## Related Tips + +### Scheduled Tasks in Application Not Started + +If the configured time conditions are met but the entire NocoBase application service is in a stopped or shutdown state, the scheduled tasks that should be triggered at the corresponding time point will be missed, and after the service restarts, missed tasks will not be triggered again. So, it may be necessary to consider handling corresponding situations or backup measures when using it. + +### Repeat Count + +When the repeat count is configured in the end condition, it calculates the total number of executions of the same workflow including all versions. For example, if a scheduled task has been executed 10 times in version 1, and the repeat count is also set to 10 times, the workflow will no longer be triggered. Even if it is copied to a new version, it will not be triggered unless the repeat count is modified to a number greater than 10. However, if it is duplicated to a new workflow, the number of executions will be recalculated from 0. Without modifying the relevant configuration, the new workflow can be triggered 10 more times. + +### Difference Between Interval Time and Advanced Mode in Repeat Rules + +The interval time in the repeat rule is relative to the time point of the previous trigger (start time), while the advanced mode triggers at fixed time points. For example, if it is configured to trigger every 30 minutes, and the last trigger is at 2021-09-01 12:01:23, the next trigger time will be 2021-09-01 12:31:23. The advanced mode, same as cron, configures rules to trigger at fixed time points, for example, it can be configured to trigger at 01 and 31 minutes past every hour. + +## Example + +Suppose we want to check orders that have not been paid for more than 30 minutes every minute and automatically change their status to canceled. We'll implement it using both modes. + +### Custom Time Mode + +Create a workflow based on a scheduled task, select the "Custom Time" mode in the trigger configuration, choose any time point not later than the current time as the start time, select "Every Minute" for the repeat rule, and leave the end condition blank: + +![Scheduled Task_Trigger Configuration_Custom Time Mode](https://static-docs.nocobase.com/71131e3f2034263f883062389b356cbd.png) + +Then, configure other nodes according to the logic of the workflow, calculating a time 30 minutes before current system time, and updating the status to canceled if unpaid which created before then: + +![Scheduled Task_Trigger Configuration_Custom Time Mode](https://static-docs.nocobase.com/188bc5287ffa1fb24a4e7baa1de6eb29.png) + +After enabling the workflow, it will trigger every minute from the start time, calculate 30 minutes before now, and update the status of orders created before that time to canceled. + +### Time Field of Collection Mode + +Create a workflow based on a scheduled task, select the "Collection Time Field" mode in the trigger configuration, choose the "Orders" collection, select 30 minutes after the order created time as the start time, and choose "No Repeat" for the repeat rule: + +![Scheduled Task_Trigger Configuration_Collection Time Field Mode_Trigger](https://static-docs.nocobase.com/d40d5aef57f42799d31cc5882dd94246.png) + +Then, configure other nodes according to the logic of the workflow, update orders with the ID of the triggered data and the status "Unpaid" to canceled: + +![Scheduled Task_Trigger Configuration_Collection Time Field Mode_Update Node](https://static-docs.nocobase.com/491dde9df8f773f5b14a4fd8ceac9d3e.png) + +Unlike the custom time mode, there is no need to calculate 30 minutes before, because the triggered data context in the workflow contains the corresponding data record that meet the time conditions, so you can directly update the status of the corresponding orders. diff --git a/docs/fr-FR/handbook/workflow/triggers/webhook.md b/docs/fr-FR/handbook/workflow/triggers/webhook.md new file mode 100644 index 000000000..db35bced1 --- /dev/null +++ b/docs/fr-FR/handbook/workflow/triggers/webhook.md @@ -0,0 +1,3 @@ +# Webhook + + diff --git a/docs/fr-FR/index.md b/docs/fr-FR/index.md new file mode 100644 index 000000000..49a1e7610 --- /dev/null +++ b/docs/fr-FR/index.md @@ -0,0 +1,3 @@ +# Index + + diff --git a/docs/fr-FR/manual/backup-restore/index.md b/docs/fr-FR/manual/backup-restore/index.md new file mode 100644 index 000000000..c469deefd --- /dev/null +++ b/docs/fr-FR/manual/backup-restore/index.md @@ -0,0 +1,3 @@ +# Backup & Restore + + diff --git a/docs/fr-FR/manual/blocks-guide/charts.md b/docs/fr-FR/manual/blocks-guide/charts.md new file mode 100755 index 000000000..5320f273a --- /dev/null +++ b/docs/fr-FR/manual/blocks-guide/charts.md @@ -0,0 +1,208 @@ +# 图表 + +目前,NocoBase 图表区块需要通过配置文件或编写代码来实现。图表库使用的是 [g2plot](https://g2plot.antv.vision/en/examples),理论上支持 https://g2plot.antv.vision/en/examples 上的所有图表。目前可以配置的图表包括: + +- 柱状图 +- 条形图 +- 折线图 +- 饼图 +- 面积图 + +## 添加和编辑图表 + +![chart-edit.gif](https://static-docs.nocobase.com/97c1d74a7ca9d0e8d2971cca2ab8de50.gif) + +## 图表配置 + +初始化的图表配置是静态的 JSON 数据 + +```json +{ + "data": [ + { + "type": "furniture & appliances", + "sales": 38 + }, + { + "type": "食品油副食", + "sales": 52 + }, + { + "type": "Fresh Fruit", + "sales": 61 + }, + { + "type": "美容洗护", + "sales": 145 + }, + { + "type": "Maternity & Baby Products", + "sales": 48 + }, + { + "type": "Imported Food", + "sales": 38 + }, + { + "type": "Food & Beverage", + "sales": 38 + }, + { + "type": "Home Cleaning", + "sales": 38 + } + ], + "xField": "type", + "yField": "sales", + "label": { + "position": "middle", + "style": { + "fill": "#FFFFFF", + "opacity": 0.6 + } + }, + "xAxis": { + "label": { + "autoHide": true, + "autoRotate": false + } + }, + "meta": { + "type": { + "alias": "category" + }, + "sales": { + "alias": "sales" + } + } +} +``` + +data 支持表达式的写法,NocoBase 内置了 `requestChartData(config)` 函数,用于自定义图表数据的请求。Config 参数说明见: [https://github.com/axios/axios#request-config](https://github.com/axios/axios#request-config) + +示例: + +```json +{ + "data": "{{requestChartData({ url: 'collectionName:getColumnChartData' })}}", + "xField": "type", + "yField": "sales", + "label": { + "position": "middle", + "style": { + "fill": "#FFFFFF", + "opacity": 0.6 + } + }, + "xAxis": { + "label": { + "autoHide": true, + "autoRotate": false + } + }, + "meta": { + "type": { + "alias": "category" + }, + "sales": { + "alias": "sales" + } + } +} +``` + +HTTP API 示例: + +```bash +GET /api/collectionName:getColumnChartData + +Response Body +{ + "data": [ + { + "type": "furniture & appliances", + "sales": 38 + }, + { + "type": "食品油副食", + "sales": 52 + }, + { + "type": "Fresh Fruit", + "sales": 61 + }, + { + "type": "美容洗护", + "sales": 145 + }, + { + "type": "Maternity & Baby Products", + "sales": 48 + }, + { + "type": "Imported Food", + "sales": 38 + }, + { + "type": "Food & Beverage", + "sales": 38 + }, + { + "type": "Home Cleaning", + "sales": 38 + } + ] +} + +``` + +## Server 端实现 + +为名为 collectionName 的数据表,添加自定义的 getColumnChartData 方法: + +```js +app.resourcer.registerActionHandlers({ + 'collectionName:getColumnChartData': (ctx, next) => { + // The data to be output + ctx.body = []; + await next(); + }, +}); + +``` + +## 视频 + +### 静态数据 + + + +### 动态数据 + + + +### 更多图表 + +理论上支持 https://g2plot.antv.vision/en/examples 上的所有图表 + + + +## JS 表达式 + +Syntax + +```js +{ + "key1": "{{ js expression }}" +} +``` + + \ No newline at end of file diff --git a/docs/fr-FR/manual/blocks-guide/charts/Chart-Dynamic-1.m4v b/docs/fr-FR/manual/blocks-guide/charts/Chart-Dynamic-1.m4v new file mode 100644 index 000000000..76d8c994b Binary files /dev/null and b/docs/fr-FR/manual/blocks-guide/charts/Chart-Dynamic-1.m4v differ diff --git a/docs/fr-FR/manual/blocks-guide/charts/Chart-Js-1.m4v b/docs/fr-FR/manual/blocks-guide/charts/Chart-Js-1.m4v new file mode 100644 index 000000000..482b078eb Binary files /dev/null and b/docs/fr-FR/manual/blocks-guide/charts/Chart-Js-1.m4v differ diff --git a/docs/fr-FR/manual/blocks-guide/charts/Chart-More-1.m4v b/docs/fr-FR/manual/blocks-guide/charts/Chart-More-1.m4v new file mode 100644 index 000000000..944d8da25 Binary files /dev/null and b/docs/fr-FR/manual/blocks-guide/charts/Chart-More-1.m4v differ diff --git a/docs/fr-FR/manual/blocks-guide/charts/Chart-Static-1.m4v b/docs/fr-FR/manual/blocks-guide/charts/Chart-Static-1.m4v new file mode 100644 index 000000000..8009d7a07 Binary files /dev/null and b/docs/fr-FR/manual/blocks-guide/charts/Chart-Static-1.m4v differ diff --git a/docs/fr-FR/manual/blocks-guide/charts/chart-edit.gif b/docs/fr-FR/manual/blocks-guide/charts/chart-edit.gif new file mode 100755 index 000000000..86a3540a3 Binary files /dev/null and b/docs/fr-FR/manual/blocks-guide/charts/chart-edit.gif differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/enable-federated.md b/docs/fr-FR/manual/collection/collection-fdw/enable-federated.md new file mode 100644 index 000000000..eb828c476 --- /dev/null +++ b/docs/fr-FR/manual/collection/collection-fdw/enable-federated.md @@ -0,0 +1,39 @@ +# MySQL 如何启用 federated 引擎 + +MySQL 数据库默认没有开启 federated 模块,需要修改 my.cnf 配置,如果是 docker 版本,可以通过 volumes 来处理扩展的情况: + +```yml +mysql: + image: mysql:8.1.0 + volumes: + - ./storage/mysql-conf:/etc/mysql/conf.d + environment: + MYSQL_DATABASE: nocobase + MYSQL_USER: nocobase + MYSQL_PASSWORD: nocobase + MYSQL_ROOT_PASSWORD: nocobase + restart: always + networks: + - nocobase +``` + +新建 `./storage/mysql-conf/federated.cnf` 文件 + +```conf +[mysqld] +federated +``` + +重启 mysql + +```bash +docker compose up -d mysql +``` + +查看 federated 是否已经激活 + +```sql +show engines +``` + +![Alt text](https://static-docs.nocobase.com/ac5d97cf902ad164e141633a41a23e46.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/collection/collection-fdw/image-1.png b/docs/fr-FR/manual/collection/collection-fdw/image-1.png new file mode 100644 index 000000000..28ad3aa62 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image-1.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/image-10.png b/docs/fr-FR/manual/collection/collection-fdw/image-10.png new file mode 100644 index 000000000..3fa17d784 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image-10.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/image-2.png b/docs/fr-FR/manual/collection/collection-fdw/image-2.png new file mode 100644 index 000000000..032241693 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image-2.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/image-3.png b/docs/fr-FR/manual/collection/collection-fdw/image-3.png new file mode 100644 index 000000000..93c3e0631 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image-3.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/image-4.png b/docs/fr-FR/manual/collection/collection-fdw/image-4.png new file mode 100644 index 000000000..72f11fdc5 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image-4.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/image-5.png b/docs/fr-FR/manual/collection/collection-fdw/image-5.png new file mode 100644 index 000000000..01b08cd71 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image-5.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/image-6.png b/docs/fr-FR/manual/collection/collection-fdw/image-6.png new file mode 100644 index 000000000..092b33cb6 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image-6.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/image-7.png b/docs/fr-FR/manual/collection/collection-fdw/image-7.png new file mode 100644 index 000000000..793c6aef7 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image-7.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/image-8.png b/docs/fr-FR/manual/collection/collection-fdw/image-8.png new file mode 100644 index 000000000..50a754339 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image-8.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/image-9.png b/docs/fr-FR/manual/collection/collection-fdw/image-9.png new file mode 100644 index 000000000..26e966f7a Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image-9.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/image.png b/docs/fr-FR/manual/collection/collection-fdw/image.png new file mode 100644 index 000000000..332858e2c Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-fdw/image.png differ diff --git a/docs/fr-FR/manual/collection/collection-fdw/index.md b/docs/fr-FR/manual/collection/collection-fdw/index.md new file mode 100644 index 000000000..f15002104 --- /dev/null +++ b/docs/fr-FR/manual/collection/collection-fdw/index.md @@ -0,0 +1,61 @@ +# 连接外部数据表 + +## 介绍 + +基于数据库的 foreign data wrapper 实现的连接远程数据表的功能插件。目前支持 MySQL 和 PostgreSQL 数据库。 + +### MySQL + +MySQL 通过 `federated` 引擎,需要激活,支持连接远程 MySQL 及其协议兼容数据库,如 MariaDB。详情文档参考 [Federated Storage Engine](https://dev.mysql.com/doc/refman/8.0/en/federated-storage-engine.html)。 + +### PostgreSQL + +在 PostgreSQL 中,可通过不同类型的 `fdw` 扩展来支持不同的远程数据类型,目前支持的扩展有: + +- [postgres_fdw](https://www.postgresql.org/docs/current/postgres-fdw.html):在 PostgreSQL 中连接远程 PostgreSQL 数据库。 +- [mysql_fdw(开发中)](https://github.com/EnterpriseDB/mysql_fdw):在 PostgreSQL 中连接远程 MySQL 数据库。 +- 其余类型的 fdw 扩展,可参考 [PostgreSQL Foreign Data Wrappers](https://wiki.postgresql.org/wiki/Foreign_data_wrappers),接入 NocoBase 需要在代码中实现相应的适配接口。 + +## 安装 + +前提条件 + +- 本地 MySQL(NocoBase 使用的数据库)需要激活 `federated`,参考 [MySQL 如何启用 federated 引擎](./enable-federated.md) + +然后通过插件管理器安装并激活插件 + +![安装并激活插件](https://static-docs.nocobase.com/f84276c5712851fb3ff33af3f1ff0f59.png) + +## 使用手册 + +在「数据表管理 > 创建数据表」 下拉中,选择「连接外部数据」 + +![连接外部数据](https://static-docs.nocobase.com/029d946a6d067d1c35a39755219d623c.png) + +在「数据库服务」下拉选项中,选择已存在的数据库服务,或者「创建数据库服务」 + +![数据库服务](https://static-docs.nocobase.com/766271708a911950a5599d60d6be4a4d.png) + +创建数据库服务 + +![创建数据库服务](https://static-docs.nocobase.com/1e357216e04cc4f200bd6212827281c8.png) + +选择数据库服务之后, 在「远程表」的下拉选项中,选择需要连接的数据表。 + +![选择需要连接的数据表](https://static-docs.nocobase.com/e91fd6152b52b4fc01b3808053cc8dc4.png) + +配置字段信息 + +![配置字段信息](https://static-docs.nocobase.com/e618fecc5fe327f6a495e61405e5f040.png) + +如果远程表有结构变化,也可以「从远程表同步」 + +![从远程表同步](https://static-docs.nocobase.com/3751a9a39f933889fb3fcc4d85a6f4ad.png) + +远程表同步 + +![远程表同步](https://static-docs.nocobase.com/13f18200e31ea223fdd8dadaff1e9d28.png) + +最后,在界面里显示 + +![在界面里显示](https://static-docs.nocobase.com/368fca27a99277d9360ca81350949357.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/collection/collection-templates/calender/index.md b/docs/fr-FR/manual/collection/collection-templates/calender/index.md new file mode 100644 index 000000000..9004bee4a --- /dev/null +++ b/docs/fr-FR/manual/collection/collection-templates/calender/index.md @@ -0,0 +1,13 @@ +# 日历表 + +![](https://static-docs.nocobase.com/0077dbdbb296afb00ba055e7bf5e9acc.png) + +日历数据表模板是一种用于管理时间相关数据的数据模板,通常用于存储和管理事件、约会、任务等与日期/时间相关的信息。以下是日历数据表模板的预定义字段: + +1. 创建时间和结束时间:表示事件的开始和结束日期及时间。 +2. 创建者和更新者:列出事件的人员。 +3. 重复频率:定义事件的重复模式,如每天、每周、每月等。 + +通过日历数据表模板,可以方便地创建和管理与时间相关的信息,并支持日程安排、提醒和跟踪任务的进度。这种模板常用于个人日程管理、团队协作、会议安排等应用 + +![](https://static-docs.nocobase.com/e516666868f98162ddf9481109df8aba.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/collection/collection-templates/calender/static/JHaTbG3rCo4L0yxUUYQc1OfTnrd.png b/docs/fr-FR/manual/collection/collection-templates/calender/static/JHaTbG3rCo4L0yxUUYQc1OfTnrd.png new file mode 100644 index 000000000..d82519140 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/calender/static/JHaTbG3rCo4L0yxUUYQc1OfTnrd.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/calender/static/UX2nbqRrdormvlxqQrFcFf3EnCc.png b/docs/fr-FR/manual/collection/collection-templates/calender/static/UX2nbqRrdormvlxqQrFcFf3EnCc.png new file mode 100644 index 000000000..cecffde5c Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/calender/static/UX2nbqRrdormvlxqQrFcFf3EnCc.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/expression/index.md b/docs/fr-FR/manual/collection/collection-templates/expression/index.md new file mode 100644 index 000000000..c838b9086 --- /dev/null +++ b/docs/fr-FR/manual/collection/collection-templates/expression/index.md @@ -0,0 +1,73 @@ +# 表达式表使用 + +## 基本概念 + +区别于数据表中针对全表统一的公式字段,动态表达式的可以针对每行数据进行不同公式的计算。动态表达式计算目前**只在工作流中支持**。 + +表达式模板表用于存储针对同一类数据不同的公式,与需要参与计算的数据表通常为一对多关系(普通数据表 belongsTo 表达式表): + +m:1 只是通常的用法,但实际上普通数据表与表达式表的关系是可以任意建立的,一行数据对多个表达式通常还需要其他区分字段,或者是在循环中对一行数据做多种计算的场景。 + +表达式表三个字段的含义: + +- **数据表**:相当于函数的参数,在表达式中可用的变量字段来源,即只能基于一个数据表的字段进行计算配置; +- **计算引擎**:目前可选 mathjs 和 formulajs,推荐使用 formulajs。 +- **表达式**:相当于函数的内容,计算时将根据配置执行得到一个结果。 + +## 示例 + +以商品下单过程中根据不同商品进行不同优惠规则的最终价格计算举例。 + +1. 建立商品表: + +| 字段名 | 类型 | +| -------- | ----------------------- | +| 商品名 | 文本 | +| 商品原价 | 数字 | +| 优惠规则 | belongsTo(优惠规则表) | + +1. 建立优惠规则表(使用表达式表模板创建): + +| 字段名 | 类型 | +| -------- | ------------------------ | +| 规则名称 | 文本 | +| 数据表 | 单选(数据表) | +| 计算引擎 | 单选(mathjs/formulajs) | +| 表达式 | 文本 | + +1. 创建优惠规则: + +| ID | 名称 | 数据表 | 计算引擎 | 表达式 | +| --- | -------- | ------ | -------- | -------------------- | +| 1 | 八折商品 | 商品 | formula | {{商品.价格}} \* 0.8 | +| 2 | 九折商品 | 商品 | formula | {{商品.价格}} \* 0.9 | + +1. 创建商品,并关联优惠规则: + +| ID | 商品名称 | 价格 | 优惠规则 ID | +| --- | ------------- | ---- | ----------- | +| 1 | iPhone 14 Pro | 7999 | 2 | +| 2 | iPhone 13 Pro | 5999 | 1 | + +1. 创建工作流,订单创建时触发: + +![](https://static-docs.nocobase.com/fda005ee028675b7ac5f11784b5fc437.png) + +1. 创建一个运算节点,配置动态表达式为触发数据/商品/优惠规则: + +![](https://static-docs.nocobase.com/67de28dcda9fc0f662933ea0a6d272d6.png) + +配置变量数据源为触发数据中的商品: + +![](https://static-docs.nocobase.com/c58eeb07213d7fe6bb6c19b84b187e23.png) + +1. 增加一个更新数据节点,配置更新订单总价为计算节点的结果: + ![](https://static-docs.nocobase.com/a1200868b89997ed3caa8332b1ebca4f.png) +2. 创建订单触发工作流,再查看订单列表,核对价格: + +![](https://static-docs.nocobase.com/6e62f43a46f7959d487c4d581a3af3ce.png) + +| 订单商品 | 订单商品 / 原价 | 优惠规则 | 总价 | +| ------------- | --------------- | -------- | -------------------- | +| iPhone 14 Pro | 7999 | 九折 | 7999 \* 0.9 = 7199.1 | +| iPhone 13 Pro | 6999 | 八折 | 6999 \* 0.8 = 5599.2 | \ No newline at end of file diff --git a/docs/fr-FR/manual/collection/collection-templates/expression/static/A6xibwy6ZoyskKxGmdQc7jOcnRe.png b/docs/fr-FR/manual/collection/collection-templates/expression/static/A6xibwy6ZoyskKxGmdQc7jOcnRe.png new file mode 100644 index 000000000..baa8f1c5c Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/expression/static/A6xibwy6ZoyskKxGmdQc7jOcnRe.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/expression/static/OLLTb4M2vocObkxd3bkcxZkLnqh.png b/docs/fr-FR/manual/collection/collection-templates/expression/static/OLLTb4M2vocObkxd3bkcxZkLnqh.png new file mode 100644 index 000000000..e228d75fc Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/expression/static/OLLTb4M2vocObkxd3bkcxZkLnqh.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/expression/static/OTDBbV7ygocjFLxQyt0czIorn5c.png b/docs/fr-FR/manual/collection/collection-templates/expression/static/OTDBbV7ygocjFLxQyt0czIorn5c.png new file mode 100644 index 000000000..949f28f92 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/expression/static/OTDBbV7ygocjFLxQyt0czIorn5c.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/expression/static/V6sCbY59GoZ6g5xlAaJcutx5nUb.png b/docs/fr-FR/manual/collection/collection-templates/expression/static/V6sCbY59GoZ6g5xlAaJcutx5nUb.png new file mode 100644 index 000000000..04441cccf Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/expression/static/V6sCbY59GoZ6g5xlAaJcutx5nUb.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/expression/static/YLhxb1qGxoniCgxB13IcrDiZntf.png b/docs/fr-FR/manual/collection/collection-templates/expression/static/YLhxb1qGxoniCgxB13IcrDiZntf.png new file mode 100644 index 000000000..d3d39470c Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/expression/static/YLhxb1qGxoniCgxB13IcrDiZntf.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/file/index.md b/docs/fr-FR/manual/collection/collection-templates/file/index.md new file mode 100644 index 000000000..ed33f5097 --- /dev/null +++ b/docs/fr-FR/manual/collection/collection-templates/file/index.md @@ -0,0 +1,13 @@ +# 文件表 + +![](https://static-docs.nocobase.com/6b7dd77d7f3b4a77667d75f5991d5e9f.png) + +文件表数据表模板通过 File manager 插件提供 + +![](https://static-docs.nocobase.com/c7893abe6b165c7237327618da7f49e5.png) + +- 支持自定义扩展文件存储类型 + +![](https://static-docs.nocobase.com/f2a5341252a91d2cab8a98b853024966.png) + +![](https://static-docs.nocobase.com/230482a819cb3c05b2302887300582a6.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/collection/collection-templates/file/static/BOlXbQXsOo5ae8xTC6Gc4lAlnRe.png b/docs/fr-FR/manual/collection/collection-templates/file/static/BOlXbQXsOo5ae8xTC6Gc4lAlnRe.png new file mode 100644 index 000000000..e6ab9bcac Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/file/static/BOlXbQXsOo5ae8xTC6Gc4lAlnRe.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/file/static/JRRtb9rtfoNfWOxkEVQcWF0Nndd.png b/docs/fr-FR/manual/collection/collection-templates/file/static/JRRtb9rtfoNfWOxkEVQcWF0Nndd.png new file mode 100644 index 000000000..b5a2bdd98 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/file/static/JRRtb9rtfoNfWOxkEVQcWF0Nndd.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/file/static/PJhDbmWJgo2kBNxtDqIcMmCjnvh.png b/docs/fr-FR/manual/collection/collection-templates/file/static/PJhDbmWJgo2kBNxtDqIcMmCjnvh.png new file mode 100644 index 000000000..0fbb3ed57 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/file/static/PJhDbmWJgo2kBNxtDqIcMmCjnvh.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/file/static/Z3Jgb8N4QosogDxOvBMc33RPnQb.png b/docs/fr-FR/manual/collection/collection-templates/file/static/Z3Jgb8N4QosogDxOvBMc33RPnQb.png new file mode 100644 index 000000000..31695a65c Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/file/static/Z3Jgb8N4QosogDxOvBMc33RPnQb.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/general/index.md b/docs/fr-FR/manual/collection/collection-templates/general/index.md new file mode 100644 index 000000000..a26fd5679 --- /dev/null +++ b/docs/fr-FR/manual/collection/collection-templates/general/index.md @@ -0,0 +1,14 @@ +# 普通表 + +![](https://static-docs.nocobase.com/5a1663c897d5300a65909a904b073395.png) + +普通数据表模板,支持自定义设置数据表的行为: + +- 自动生成 ID 字段 +- 记录创建人 +- 记录最后更新人 +- 记录创建时间 +- 记录最后更新时间 +- 可以对行记录进行排序 + +![](https://static-docs.nocobase.com/43ffcb2de53c610e33f4dd5c440b4324.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/collection/collection-templates/general/static/JM3ab75AroudtGxgvszc7aEznnb.png b/docs/fr-FR/manual/collection/collection-templates/general/static/JM3ab75AroudtGxgvszc7aEznnb.png new file mode 100644 index 000000000..26e81026c Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/general/static/JM3ab75AroudtGxgvszc7aEznnb.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/general/static/NG7NbgZIpolAp8xXy8JcKJDRnGe.png b/docs/fr-FR/manual/collection/collection-templates/general/static/NG7NbgZIpolAp8xXy8JcKJDRnGe.png new file mode 100644 index 000000000..8b15fc361 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/general/static/NG7NbgZIpolAp8xXy8JcKJDRnGe.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/index.md b/docs/fr-FR/manual/collection/collection-templates/index.md new file mode 100644 index 000000000..f139ded6f --- /dev/null +++ b/docs/fr-FR/manual/collection/collection-templates/index.md @@ -0,0 +1 @@ +# 数据表模板 diff --git a/docs/fr-FR/manual/collection/collection-templates/sql/index.md b/docs/fr-FR/manual/collection/collection-templates/sql/index.md new file mode 100644 index 000000000..d0c1062b0 --- /dev/null +++ b/docs/fr-FR/manual/collection/collection-templates/sql/index.md @@ -0,0 +1,47 @@ +# SQL 表 + +## 介绍 + +![](https://static-docs.nocobase.com/c6221758f3aea2f45d0df7b815353697.png) + +SQL collection 提供了一种通过 SQL 语句获取数据的方法。通过 SQL 语句获取数据字段,配置字段元数据之后,用户可以像使用普通表一样,给表格、图表、工作流等使用,适用于关联查询、统计等场景。 + +## 新建 + +![](https://static-docs.nocobase.com/64b3a663285be6377141901c2ff3e1f0.png) + +1. 在 SQL 输入框输入 SQL 语句后,点击执行 (Execute) 后,系统将会尝试解析 SQL 使用了哪些表和字段,从来源表中解析出字段元数据。 + +![](https://static-docs.nocobase.com/513f2161226dd1e705ab0cf0efb2be90.png) + +1. 如果系统自动分析的来源表和字段不对,可以手动选择对应的表和字段,来使用对应字段的元数据。需要先选择来源表,才能在下方的字段来源中选择该表的字段。 + +![](https://static-docs.nocobase.com/966759acf8d6f7380d27feb4edcc15ed.png) + +1. 如果字段没有对应的来源字段,系统会根据数据类型推断字段类型,如果推断结果不对,可以手动选择字段类型。 + +![](https://static-docs.nocobase.com/0e752127ab3e46c0742522891310906b.png) + +1. 在配置字段的同时可以在预览区域看到对应的展示效果。 + +![](https://static-docs.nocobase.com/d741d8b43785e003d35fc0b53fc0e649.png) + +1. 配置完成,确认无误之后,需要点击 SQL 输入框下方的确认 (Confirm) 按钮才能进行最后的提交。 + +## 编辑 + +1. SQL 语句有变化时,可以点击修改 (Edit) 按钮,直接修改 SQL 语句,重新配置字段。 +2. 需要修改字段元数据时,可以通过配置字段 (Configure fields), 像普通表一样修改字段相关配置。 + +## 同步 + +![](https://static-docs.nocobase.com/dd5c0ea1b3def4c8bf4d5fcdb81fac3a.png) + +SQL 语句无变化,但数据库表结构有变化时,可以通过点击配置字段 (Configure fields) - 从数据库同步 (Sync from database) 对字段进行同步和配置。 + +## SQL 表对比连接数据库视图 + +| 模板类型 | 适用场景 | 实现原理 | 增删改支持 | +| -------------- | ---------------------------------------------------------------------- | ---------- | ---------- | +| SQL | 模型比较简单,较轻量场景不方便操作数据库不想维护视图想完全通过 UI 操作 | SQL 子查询 | 不支持 | +| 连接数据库视图 | 模型比较复杂需要和数据库交互需要修改数据需要更良好和稳定的数据库支持 | 数据库视图 | 部分支持 | \ No newline at end of file diff --git a/docs/fr-FR/manual/collection/collection-templates/sql/static/FbR1bpv4DoSq0oxKAFxcKo1tnPh.png b/docs/fr-FR/manual/collection/collection-templates/sql/static/FbR1bpv4DoSq0oxKAFxcKo1tnPh.png new file mode 100644 index 000000000..c646124f5 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/sql/static/FbR1bpv4DoSq0oxKAFxcKo1tnPh.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/sql/static/KjtpbmJvOoTW0VxZIXEcIWVVnkd.png b/docs/fr-FR/manual/collection/collection-templates/sql/static/KjtpbmJvOoTW0VxZIXEcIWVVnkd.png new file mode 100644 index 000000000..c7618a58c Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/sql/static/KjtpbmJvOoTW0VxZIXEcIWVVnkd.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/sql/static/LMe9bH9VTovGZyxFg41cgZwynDd.png b/docs/fr-FR/manual/collection/collection-templates/sql/static/LMe9bH9VTovGZyxFg41cgZwynDd.png new file mode 100644 index 000000000..180f3b999 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/sql/static/LMe9bH9VTovGZyxFg41cgZwynDd.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/sql/static/OVq4bpTpxob4jSx4BaOcFDIfnLg.png b/docs/fr-FR/manual/collection/collection-templates/sql/static/OVq4bpTpxob4jSx4BaOcFDIfnLg.png new file mode 100644 index 000000000..2106af8bd Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/sql/static/OVq4bpTpxob4jSx4BaOcFDIfnLg.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/sql/static/OtJJbUmi0oz1LNx82PPcQkgWnIc.png b/docs/fr-FR/manual/collection/collection-templates/sql/static/OtJJbUmi0oz1LNx82PPcQkgWnIc.png new file mode 100644 index 000000000..e1f7fa582 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/sql/static/OtJJbUmi0oz1LNx82PPcQkgWnIc.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/sql/static/OwJ3b5kQPo6ASNx7uKvc8NAGnYc.png b/docs/fr-FR/manual/collection/collection-templates/sql/static/OwJ3b5kQPo6ASNx7uKvc8NAGnYc.png new file mode 100644 index 000000000..82072da86 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/sql/static/OwJ3b5kQPo6ASNx7uKvc8NAGnYc.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/sql/static/WROObVm7Fojhj5xPq52cmINZn7b.png b/docs/fr-FR/manual/collection/collection-templates/sql/static/WROObVm7Fojhj5xPq52cmINZn7b.png new file mode 100644 index 000000000..f3ce2adb4 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/sql/static/WROObVm7Fojhj5xPq52cmINZn7b.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/tree/index.md b/docs/fr-FR/manual/collection/collection-templates/tree/index.md new file mode 100644 index 000000000..9f77f3e1b --- /dev/null +++ b/docs/fr-FR/manual/collection/collection-templates/tree/index.md @@ -0,0 +1,52 @@ +# 树表 + +![](https://static-docs.nocobase.com/48ea3612a65ba18ea6d898b25a78c4f4.png) + +和普通表一样支持自定义设置数据表的行为 + +![](https://static-docs.nocobase.com/f49bac32396d6fbdbf979de37a2546f7.png) + +树表模板的预定义字段 + +```go +[ + { + interface: 'integer', + name: 'parentId', + type: 'bigInt', + isForeignKey: true, + }, + { + interface: 'm2o', + type: 'belongsTo', + name: 'parent', + foreignKey: 'parentId', + treeParent: true, + onDelete: 'CASCADE', + }, + { + interface: 'o2m', + type: 'hasMany', + name: 'children', + foreignKey: 'parentId', + treeChildren: true, + onDelete: 'CASCADE', + }, + ] +``` + +树表创建后初始化字段 + +![](https://static-docs.nocobase.com/0b06b5a954c8d40567d3dcafa2baff96.png) + +树表数据表模板是通过自关联字段实现树形结构的设计 + +- 父节点关联字段(Many to One):通常称为 "Parent" 字段,它与同一表中的其他记录建立关联,表示每个节点的父节点。 +- 子节点关联字段(One to Many):通常称为 "Children" 字段,它表示每个节点可以有多个子节点 + +## 在区块中使用 + +- 树表格 :默认开启(禁用时,数据将平铺返回) +- 添加子记录:为当前记录添加子记录 + +![](https://static-docs.nocobase.com/97a7ddf0f26c323a2c986d10b43d7174.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/collection/collection-templates/tree/static/MmJhbxcoeo66DqxMDhaclBGPndh.png b/docs/fr-FR/manual/collection/collection-templates/tree/static/MmJhbxcoeo66DqxMDhaclBGPndh.png new file mode 100644 index 000000000..df21bdeb9 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/tree/static/MmJhbxcoeo66DqxMDhaclBGPndh.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/tree/static/MtYebfdtAook0ZxJZkfcrGTAnHh.png b/docs/fr-FR/manual/collection/collection-templates/tree/static/MtYebfdtAook0ZxJZkfcrGTAnHh.png new file mode 100644 index 000000000..8e806ba12 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/tree/static/MtYebfdtAook0ZxJZkfcrGTAnHh.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/tree/static/Q1OgbmzcHowD3fxFylUcGMBbndc.png b/docs/fr-FR/manual/collection/collection-templates/tree/static/Q1OgbmzcHowD3fxFylUcGMBbndc.png new file mode 100644 index 000000000..61f9e288a Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/tree/static/Q1OgbmzcHowD3fxFylUcGMBbndc.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/tree/static/VDg1bTG3noShtXxtU7QcwGMKnch.png b/docs/fr-FR/manual/collection/collection-templates/tree/static/VDg1bTG3noShtXxtU7QcwGMKnch.png new file mode 100644 index 000000000..537b9b848 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/tree/static/VDg1bTG3noShtXxtU7QcwGMKnch.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/view/index.md b/docs/fr-FR/manual/collection/collection-templates/view/index.md new file mode 100644 index 000000000..b8d8b1abc --- /dev/null +++ b/docs/fr-FR/manual/collection/collection-templates/view/index.md @@ -0,0 +1,64 @@ +# 数据库视图 + +![](https://static-docs.nocobase.com/3e33ae5e23399105ab83c7d5ecb32a26.png) + +## 基础概念 + +数据库视图是数据库中的虚拟表,它基于一个或多个数据库表的查询结果生成,具有与表相似的结构,但不存储实际数据。数据库视图允许用户以更简单、更抽象的方式访问和操作数据 + +将数据库中的视图与 Collection 连接是 NocoBase 提供的一种有效建表方式。通过在数据库中创建视图,可以在 Collection 管理中引用并映射为数据表,特别适用于统计场景。这种方式不仅提高了数据表的可维护性,在不同应用场景中还能灵活使用。 + +下面以订单管理系统中常见的统计业务场景为例 + +订单表和客户表有关联关系,统计每个客户的销售金额汇总和销售数量汇总,展示字段:客户名称、客户手机号、销售金额汇总,销售数量汇总 + +在数据库中创建视图: + +```go +SELECT t2.customer_name, + t2.mobile_number , + sum(t1.amount) AS sum_amount, + sum(t1.quantity) AS sum_quantity + FROM Orders t1 + JOIN Customers t2 ON t1.f_6ln1f7tqn9b = t2.id + GROUP BY t2.customer_name, t2.mobile_number; +``` + +数据库中的视图: + +![](https://static-docs.nocobase.com/a5eaaadd358f41b33e036198cf0600ce.png) + +## 创建视图数据表 + +在 NocoBase 中将上面视图映射为数据表(Collection)使用 + +选择目标视图 + +![](https://static-docs.nocobase.com/cf950e4d2851bdde475838a2f040a79e.png) + +- 支持自定义视图的列名(字段名) +- 来源字段:即源表的元字段,当字段未解析出源表来源字段时(聚合的字段无来源字段),可指定字段的 interface +- 视图数据是否支持增删改操作(默认不支持) + +![](https://static-docs.nocobase.com/0d99fc9047f25119dbce0c396a866cf7.png) + +完整的示例配置流程如图 + +![](https://static-docs.nocobase.com/bd0f54c899b4d8740779dd0cb8f1d65f.gif) + +- Sync from database 支持调整视图表配置(若数据库中视图进行了调整,可重新连接视图同步数据) +- 删除:这里删除操作不会将源表字段删除,仅删除视图表中的字段 + +![](https://static-docs.nocobase.com/39e906c75a7f7a3d1c38d8fa0be7d068.png) + +是否支持对视图数据表的增删改操作(默认不启用),启用时,对应区块才支持增加、删除等操作 + +![](https://static-docs.nocobase.com/064ce37acb2f1f61cfe91a5892b34bdb.png) + +## 视图数据表在 UI 中的使用 + +- 作为区块的数据源 + +视图表与其他任意方式创建的数据表一样在所有区块中都能选中作为数据源 + +![](https://static-docs.nocobase.com/1208a826507e9dd210ba63f9bfeaa90d.gif) \ No newline at end of file diff --git a/docs/fr-FR/manual/collection/collection-templates/view/static/AEvTbdf38oXhlnxlS6lcPpV0nVe.png b/docs/fr-FR/manual/collection/collection-templates/view/static/AEvTbdf38oXhlnxlS6lcPpV0nVe.png new file mode 100644 index 000000000..d69740a3a Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/view/static/AEvTbdf38oXhlnxlS6lcPpV0nVe.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/view/static/Ey2Ob9o39oP95Yx2bRIcbamznLd.gif b/docs/fr-FR/manual/collection/collection-templates/view/static/Ey2Ob9o39oP95Yx2bRIcbamznLd.gif new file mode 100644 index 000000000..7410b41f5 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/view/static/Ey2Ob9o39oP95Yx2bRIcbamznLd.gif differ diff --git a/docs/fr-FR/manual/collection/collection-templates/view/static/PGUxb8ur2oylWdxn9wuc99vVnrc.gif b/docs/fr-FR/manual/collection/collection-templates/view/static/PGUxb8ur2oylWdxn9wuc99vVnrc.gif new file mode 100644 index 000000000..ad00d575d Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/view/static/PGUxb8ur2oylWdxn9wuc99vVnrc.gif differ diff --git a/docs/fr-FR/manual/collection/collection-templates/view/static/PguWbMOdAoA5wYxPWopcFGNMn7b.png b/docs/fr-FR/manual/collection/collection-templates/view/static/PguWbMOdAoA5wYxPWopcFGNMn7b.png new file mode 100644 index 000000000..ca4c95f4e Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/view/static/PguWbMOdAoA5wYxPWopcFGNMn7b.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/view/static/PnZ1bBK5OopbXFxkqBfclaTknih.png b/docs/fr-FR/manual/collection/collection-templates/view/static/PnZ1bBK5OopbXFxkqBfclaTknih.png new file mode 100644 index 000000000..001395d8f Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/view/static/PnZ1bBK5OopbXFxkqBfclaTknih.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/view/static/QVhmbkwRso7zrAxP3e8cjoKbndf.png b/docs/fr-FR/manual/collection/collection-templates/view/static/QVhmbkwRso7zrAxP3e8cjoKbndf.png new file mode 100644 index 000000000..26520b545 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/view/static/QVhmbkwRso7zrAxP3e8cjoKbndf.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/view/static/Rh9Vb4rLXorm57xKGaWcQdR1nkh.png b/docs/fr-FR/manual/collection/collection-templates/view/static/Rh9Vb4rLXorm57xKGaWcQdR1nkh.png new file mode 100644 index 000000000..8f74b817f Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/view/static/Rh9Vb4rLXorm57xKGaWcQdR1nkh.png differ diff --git a/docs/fr-FR/manual/collection/collection-templates/view/static/T2qXbDwugovgGJxjmOWcnYQfnYc.png b/docs/fr-FR/manual/collection/collection-templates/view/static/T2qXbDwugovgGJxjmOWcnYQfnYc.png new file mode 100644 index 000000000..69fd8f641 Binary files /dev/null and b/docs/fr-FR/manual/collection/collection-templates/view/static/T2qXbDwugovgGJxjmOWcnYQfnYc.png differ diff --git a/docs/fr-FR/manual/collection/fields/advanced.md b/docs/fr-FR/manual/collection/fields/advanced.md new file mode 100644 index 000000000..231de2e1c --- /dev/null +++ b/docs/fr-FR/manual/collection/fields/advanced.md @@ -0,0 +1,6 @@ +# 高级类型 + +- Formula +- Sequence +- JSON +- Collection diff --git a/docs/fr-FR/manual/collection/fields/basic.md b/docs/fr-FR/manual/collection/fields/basic.md new file mode 100644 index 000000000..15d7eb89e --- /dev/null +++ b/docs/fr-FR/manual/collection/fields/basic.md @@ -0,0 +1,14 @@ +# 基本类型 + +- Single line text +- Username +- Long text +- Phone +- Email +- URL +- Integer +- Number +- Percent +- Password +- Color +- Icon diff --git a/docs/fr-FR/manual/collection/fields/choices.md b/docs/fr-FR/manual/collection/fields/choices.md new file mode 100644 index 000000000..f387b0736 --- /dev/null +++ b/docs/fr-FR/manual/collection/fields/choices.md @@ -0,0 +1,8 @@ +# 选择类型 + +- Checkbox +- Single select +- Multiple select +- Radio group +- Checkbox group +- China region(插件扩展) diff --git a/docs/fr-FR/manual/collection/fields/date.md b/docs/fr-FR/manual/collection/fields/date.md new file mode 100644 index 000000000..d974b135e --- /dev/null +++ b/docs/fr-FR/manual/collection/fields/date.md @@ -0,0 +1,4 @@ +# 日期 & 时间 + +- Datetime +- Time diff --git a/docs/fr-FR/manual/collection/fields/index.md b/docs/fr-FR/manual/collection/fields/index.md new file mode 100644 index 000000000..07dd0c5c7 --- /dev/null +++ b/docs/fr-FR/manual/collection/fields/index.md @@ -0,0 +1 @@ +# Overview diff --git a/docs/fr-FR/manual/collection/fields/map.md b/docs/fr-FR/manual/collection/fields/map.md new file mode 100644 index 000000000..0d8312b3e --- /dev/null +++ b/docs/fr-FR/manual/collection/fields/map.md @@ -0,0 +1 @@ +# 基于地图的几何图形 diff --git a/docs/fr-FR/manual/collection/fields/media.md b/docs/fr-FR/manual/collection/fields/media.md new file mode 100644 index 000000000..1e6d37a28 --- /dev/null +++ b/docs/fr-FR/manual/collection/fields/media.md @@ -0,0 +1,5 @@ +# 多媒体 + +- Markdown +- Rich Text +- Attachment diff --git a/docs/fr-FR/manual/collection/fields/relation.md b/docs/fr-FR/manual/collection/fields/relation.md new file mode 100644 index 000000000..b7acd7fd8 --- /dev/null +++ b/docs/fr-FR/manual/collection/fields/relation.md @@ -0,0 +1,9 @@ +# 关系类型 + +用于建立各种关联关系 + +- One to one (belongs to) +- One to one (has one) +- One to many +- Many to one +- Many to many diff --git a/docs/fr-FR/manual/collection/fields/system.md b/docs/fr-FR/manual/collection/fields/system.md new file mode 100644 index 000000000..3d743314a --- /dev/null +++ b/docs/fr-FR/manual/collection/fields/system.md @@ -0,0 +1,8 @@ +# 系统信息 + +- ID +- Table OID (继承表中使用) +- Created at +- Last updated at +- Created by +- Last updated by diff --git a/docs/fr-FR/manual/collection/index.md b/docs/fr-FR/manual/collection/index.md new file mode 100644 index 000000000..07dd0c5c7 --- /dev/null +++ b/docs/fr-FR/manual/collection/index.md @@ -0,0 +1 @@ +# Overview diff --git a/docs/fr-FR/manual/collection/inherit.md b/docs/fr-FR/manual/collection/inherit.md new file mode 100644 index 000000000..4de486220 --- /dev/null +++ b/docs/fr-FR/manual/collection/inherit.md @@ -0,0 +1,56 @@ +# 数据表继承 + +数据表继承是 PostgreSQL 数据库独有的功能(需要连接 PostgreSQL ),它允许在主表的基础上创建子表,子表继承了主表的结构、字段定义和索引。这个特性主要用于管理大量数据,实现数据分区和性能优化。每个子表可以存储特定条件下的数据,例如按时间分割数据,从而减少查询时的数据扫描量,提高查询性能。此外,主表和子表的查询透明化,用户可以像操作单个表一样查询整个继承表集合,简化了数据操作和查询的复杂性,使数据库更高效地处理大规模数据。 + +## 单继承 + +在单继承模式中,一个表可以继承另一个表,子表继承了父表的结构、字段和约束。这种模式用于表示实体的层次结构,允许子表在保留通用属性的同时添加特定属性。 + +在订单系统中,配置"批发订单表"继承自主表 "订单",用于处理批发订单,配置了批发客户特有的字段,如批发价格、批次号等。 + +![](https://docs-cn.nocobase.com/static/WNA9beotVoYfLqxfBsVcchhvn9y.36308e75.gif) + +商品表的继承关系也可以做如下梳理 + +1. 主表 "商品"(Products):包含通用商品信息,如商品 ID、名称、价格、库存等。 +2. 子表 "电子产品"(ElectronicsProduct):继承自主表 "商品",并添加了特定于电子产品的字段,如屏幕尺寸、操作系统等字段。 +3. 子表 "服装产品"(ApparelProduct):同样继承自主表 "商品",但包含服装产品特有的属性,如尺寸、颜色、材质等字段。 +4. 子表 "食品产品"(FoodProduct):继承自主表 "商品",用于处理食品产品,包括保质期、食品类型等字段。 +5. 子表 "家具产品"(FurnitureProduct):继承自主表 "商品",包含家具产品的特定属性,如尺寸、材料等字段。 + +## 多继承 + +多继承允许一个表同时继承多个父表的结构、字段和约束。这种模式用于具有多个关联的实体建模。 + +以订单、运单和商品进行数据建模为例,在这个系统中,有三个核心实体:订单、运单和商品。一个订单可以包含多个商品,一个订单可以对应多个运单(例如,部分商品运送到不同地点),同时一个运单可能涉及多个订单。这种多重关系可以使用一个子表(联接表)来实现,一个表具有多个父表(多继承)。 + +1. 父表 "订单"(Orders):包含订单的基本信息,如订单 ID。 +2. 父表 "运单"(Shipments):包含运单号、运输方式信息等。 +3. 父表 "商品"(Products):包含商品的属性,如商品 ID、名称、价格等。 +4. 子表"订单商品"(OrderProduct):用于继承订单和商品。每个记录表示一个订单中的一个商品,同时记录了数量等信息。 +5. 子表 "订单运单关联"(OrderShipment):用于继承订单和运单。每个记录表示一个订单与一个运单的关系,同时记录了相关信息 + +![](https://docs-cn.nocobase.com/static/HjXmbyAndo07izxp9AQcA5YSnyd.ac606504.gif) + +## 字段重写 + +继承关系中子表可重新定义或覆盖从父表继承的字段,自定义字段属性以适应特定需求 + +![](https://docs-cn.nocobase.com/static/EUynbO9QPo1iHpxQxwXcYyTLnMf.d3f8cc91.gif) + +### 关系字段重写 + +如 A 多对多 B,A1 继承 A,B1 继承 B +则 A1 也关联 B,这时候 B 有所有(本身及所有子表)的数据,但是 A1 只需要看 B1 的数据,则可以 在 A1 中重写 把 B target 改成 B1。即在关系 A1.B 中,可以修改关联的目标表 B(可选范围为 B 和 B 的子表)为 B1 + +如图:批发订单表中重写商品关系字段(将目标表重写为电子商品表) + +![](https://docs-cn.nocobase.com/static/L6vtbzAUAoxNn6xNwDkcveQenPg.2d4fea1a.gif) + +### 可选项类型字段的重写 + +商品表(主表)中有可选项字段「尺寸」:服装商品可以定义重写为衣服尺寸(S、M、L),电子商品表则可以重写字段为「存储容量」(32GB、64GB、128GB) + +## 关系外键共享 + +关系外键共享是一种策略,允许多个表共享相同的外键字段,以建立表之间的关系。这在多个表需要引用相同实体时非常有用。在数据表继承的情况下,这个共享的外键可以用于确保每个子表与其他表之间的关系或引用,从而构建更复杂的数据模型 diff --git a/docs/fr-FR/manual/collection/management.md b/docs/fr-FR/manual/collection/management.md new file mode 100644 index 000000000..ae84ce35e --- /dev/null +++ b/docs/fr-FR/manual/collection/management.md @@ -0,0 +1,21 @@ +# 数据表管理 + +### 数据表管理 + +数据表的增删改查及拖拽排序 + +![](https://static-docs.nocobase.com/a8ba0e5c00db508225f3858e5b224f7c.gif) + +### 数据表字段管理 + +数据表字段的增删改 + +![](https://static-docs.nocobase.com/c692613fdfa4d3dac895257e0dc42d3c.gif) + +### 数据表分类管理 + +可以将数据表按照不同的标准进行组织,使数据的结构更加清晰降低数据管理的复杂性 + +数据表分类的增删改及排序 + +![](https://static-docs.nocobase.com/665f120f44e1e30b9468db59bf433a59.gif) \ No newline at end of file diff --git a/docs/fr-FR/manual/collection/multiple-databases.md b/docs/fr-FR/manual/collection/multiple-databases.md new file mode 100644 index 000000000..a6d89e94e --- /dev/null +++ b/docs/fr-FR/manual/collection/multiple-databases.md @@ -0,0 +1 @@ +# 多数据库数据源 diff --git a/docs/fr-FR/manual/collection/static/A8yMbUDaSo9zWpxs2Dncrqwjn9e.png b/docs/fr-FR/manual/collection/static/A8yMbUDaSo9zWpxs2Dncrqwjn9e.png new file mode 100644 index 000000000..3d9ba1a44 Binary files /dev/null and b/docs/fr-FR/manual/collection/static/A8yMbUDaSo9zWpxs2Dncrqwjn9e.png differ diff --git a/docs/fr-FR/manual/collection/static/BBPvbjjv0or01vx1SzBcXtN9n9f.png b/docs/fr-FR/manual/collection/static/BBPvbjjv0or01vx1SzBcXtN9n9f.png new file mode 100644 index 000000000..c8a34c5ca Binary files /dev/null and b/docs/fr-FR/manual/collection/static/BBPvbjjv0or01vx1SzBcXtN9n9f.png differ diff --git a/docs/fr-FR/manual/collection/static/Dpmeb5HinokF1Pxfu0BcAmgOnfd.gif b/docs/fr-FR/manual/collection/static/Dpmeb5HinokF1Pxfu0BcAmgOnfd.gif new file mode 100644 index 000000000..f4eab4cfc Binary files /dev/null and b/docs/fr-FR/manual/collection/static/Dpmeb5HinokF1Pxfu0BcAmgOnfd.gif differ diff --git a/docs/fr-FR/manual/collection/static/EUynbO9QPo1iHpxQxwXcYyTLnMf.gif b/docs/fr-FR/manual/collection/static/EUynbO9QPo1iHpxQxwXcYyTLnMf.gif new file mode 100644 index 000000000..01b2c8807 Binary files /dev/null and b/docs/fr-FR/manual/collection/static/EUynbO9QPo1iHpxQxwXcYyTLnMf.gif differ diff --git a/docs/fr-FR/manual/collection/static/HjXmbyAndo07izxp9AQcA5YSnyd.gif b/docs/fr-FR/manual/collection/static/HjXmbyAndo07izxp9AQcA5YSnyd.gif new file mode 100644 index 000000000..0f82a879c Binary files /dev/null and b/docs/fr-FR/manual/collection/static/HjXmbyAndo07izxp9AQcA5YSnyd.gif differ diff --git a/docs/fr-FR/manual/collection/static/JgMZbj7izo2Ugex8vKmc6fTzntb.gif b/docs/fr-FR/manual/collection/static/JgMZbj7izo2Ugex8vKmc6fTzntb.gif new file mode 100644 index 000000000..3393f06c3 Binary files /dev/null and b/docs/fr-FR/manual/collection/static/JgMZbj7izo2Ugex8vKmc6fTzntb.gif differ diff --git a/docs/fr-FR/manual/collection/static/L6vtbzAUAoxNn6xNwDkcveQenPg.gif b/docs/fr-FR/manual/collection/static/L6vtbzAUAoxNn6xNwDkcveQenPg.gif new file mode 100644 index 000000000..6585f48d5 Binary files /dev/null and b/docs/fr-FR/manual/collection/static/L6vtbzAUAoxNn6xNwDkcveQenPg.gif differ diff --git a/docs/fr-FR/manual/collection/static/OYC6b09tEor0E6x5WTXc5FjvnIc.gif b/docs/fr-FR/manual/collection/static/OYC6b09tEor0E6x5WTXc5FjvnIc.gif new file mode 100644 index 000000000..e4747a90c Binary files /dev/null and b/docs/fr-FR/manual/collection/static/OYC6b09tEor0E6x5WTXc5FjvnIc.gif differ diff --git a/docs/fr-FR/manual/collection/static/PM70bxBbDo14KcxYke1cl6GQn9S.gif b/docs/fr-FR/manual/collection/static/PM70bxBbDo14KcxYke1cl6GQn9S.gif new file mode 100644 index 000000000..34cec4d68 Binary files /dev/null and b/docs/fr-FR/manual/collection/static/PM70bxBbDo14KcxYke1cl6GQn9S.gif differ diff --git a/docs/fr-FR/manual/collection/static/PQKrbFbmUoYcX6xS6d7c8Enun4a.gif b/docs/fr-FR/manual/collection/static/PQKrbFbmUoYcX6xS6d7c8Enun4a.gif new file mode 100644 index 000000000..6341cafa3 Binary files /dev/null and b/docs/fr-FR/manual/collection/static/PQKrbFbmUoYcX6xS6d7c8Enun4a.gif differ diff --git a/docs/fr-FR/manual/collection/static/R35gbnMFjolgS9xfO9wczmXmnG0.gif b/docs/fr-FR/manual/collection/static/R35gbnMFjolgS9xfO9wczmXmnG0.gif new file mode 100644 index 000000000..697001106 Binary files /dev/null and b/docs/fr-FR/manual/collection/static/R35gbnMFjolgS9xfO9wczmXmnG0.gif differ diff --git a/docs/fr-FR/manual/collection/static/TkNGb5tLRoY7JVxjlIrc9Ol3njd.png b/docs/fr-FR/manual/collection/static/TkNGb5tLRoY7JVxjlIrc9Ol3njd.png new file mode 100644 index 000000000..b5d957bec Binary files /dev/null and b/docs/fr-FR/manual/collection/static/TkNGb5tLRoY7JVxjlIrc9Ol3njd.png differ diff --git a/docs/fr-FR/manual/collection/static/UPPCbpZb5oU9Frxyc0JcIzbhn1b.gif b/docs/fr-FR/manual/collection/static/UPPCbpZb5oU9Frxyc0JcIzbhn1b.gif new file mode 100644 index 000000000..36fa7f9a8 Binary files /dev/null and b/docs/fr-FR/manual/collection/static/UPPCbpZb5oU9Frxyc0JcIzbhn1b.gif differ diff --git a/docs/fr-FR/manual/collection/static/WNA9beotVoYfLqxfBsVcchhvn9y.gif b/docs/fr-FR/manual/collection/static/WNA9beotVoYfLqxfBsVcchhvn9y.gif new file mode 100644 index 000000000..ad2e4159d Binary files /dev/null and b/docs/fr-FR/manual/collection/static/WNA9beotVoYfLqxfBsVcchhvn9y.gif differ diff --git a/docs/fr-FR/manual/collection/static/WPoJbqedXozxb0xAQP3cKghzn8d.gif b/docs/fr-FR/manual/collection/static/WPoJbqedXozxb0xAQP3cKghzn8d.gif new file mode 100644 index 000000000..15d164275 Binary files /dev/null and b/docs/fr-FR/manual/collection/static/WPoJbqedXozxb0xAQP3cKghzn8d.gif differ diff --git a/docs/fr-FR/manual/collection/static/X8RTbD6FPodn1dxk3OscieZrnie.png b/docs/fr-FR/manual/collection/static/X8RTbD6FPodn1dxk3OscieZrnie.png new file mode 100644 index 000000000..72c863300 Binary files /dev/null and b/docs/fr-FR/manual/collection/static/X8RTbD6FPodn1dxk3OscieZrnie.png differ diff --git a/docs/fr-FR/manual/core-concepts/a-b-c.md b/docs/fr-FR/manual/core-concepts/a-b-c.md new file mode 100755 index 000000000..8ef6daba5 --- /dev/null +++ b/docs/fr-FR/manual/core-concepts/a-b-c.md @@ -0,0 +1,21 @@ +# A·B·C + +在无代码层面,NocoBase 的核心概念可以总结为 `A·B·C`。 + +`A·B·C` 是`Action·Block·Collection` 的缩写,即`操作·区块·数据表`。通过 `Collection` 设计数据结构,通过 `Block` 组织与展示数据,通过 `Action` 交互数据。 + +## 数据与视图分离 + +定义数据时,专注于定义数据;定义视图时,专注于定义视图。 + +通过定义数据,来抽象业务;再通过定义区块去组织内容以你所期望的方式呈现数据。 + +## 一种数据,多种呈现 + +为业务抽象出统一的数据模型,然后通过区块可以为同一个数据表建立各种各样的呈现方式,用于不同的场景、不同的角色、不同的组合。 + +## 操作驱动 + +数据表来定义数据的结构,区块来组织数据的呈现方式。那么,什么驱动数据的交互和变更?答案是操作。 + +区块将数据呈现给用户,操作则是将用户的指令发送给服务器完成数据的交互或变更。 diff --git a/docs/fr-FR/manual/core-concepts/actions.md b/docs/fr-FR/manual/core-concepts/actions.md new file mode 100755 index 000000000..553dc88dc --- /dev/null +++ b/docs/fr-FR/manual/core-concepts/actions.md @@ -0,0 +1,31 @@ +# 操作 + +`操作`是完成某个特定目标的动作集合。在 NocoBase 中通过 `操作`来处理数据或者与服务器通信。 操作通常会通过点击某个按钮触发。 + +## 操作类型 + +NocoBase 目前支持 10 几种操作,未来可以通过插件的方式支持更多种。 + +| 名称 | 描述 | +| ---------- | -------------------------------------------------------- | +| 筛选 | 指定数据的显示范围 | +| 添加 | 打开添加新数据的弹窗,在弹窗里通常包含一个表单区块 | +| 查看 | 打开查看指定数据的弹窗,在弹窗里通常包含一个详情区块 | +| 编辑 | 打开修改指定数据的弹窗,在弹窗里通常包含一个表单区块 | +| 删除 | 打开删除指定数据的对话框,确认后删除 | +| 导出 | 将数据导出为 Excel,常和筛选组合使用 | +| 打印 | 打开浏览器打印窗口,打印指定的数据,常和详情区块组合使用 | +| 提交 | 将指定表单区块的数据提交到服务端 | +| 刷新 | 刷新当前区块内的数据 | +| 导入 | 从 Excel 模板中导入数据 | +| 批量编辑 | 批量编辑数据 | +| 批量更新 | 批量更新数据 | +| 打开弹窗 | 打开弹窗或抽屉,在里面可以放置区块 | +| 更新数据 | 点击后自动更新指定的字段 | +| 自定义请求 | 向第三方发送请求 | + +## 配置操作 + +在界面配置模式下,将鼠标移到操作按钮上,右上角就会出现该操作支持的配置项。比如筛选操作: + +![action-config-5.jpg](https://static-docs.nocobase.com/9562124b304e77e0fc576476781df2bd.jpg) \ No newline at end of file diff --git a/docs/fr-FR/manual/core-concepts/actions/action-config-5.jpg b/docs/fr-FR/manual/core-concepts/actions/action-config-5.jpg new file mode 100755 index 000000000..b9429826f Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/actions/action-config-5.jpg differ diff --git a/docs/fr-FR/manual/core-concepts/blocks.md b/docs/fr-FR/manual/core-concepts/blocks.md new file mode 100755 index 000000000..f8e339298 --- /dev/null +++ b/docs/fr-FR/manual/core-concepts/blocks.md @@ -0,0 +1,87 @@ +# 区块 + +区块是用来展示和操作数据的视图。在 NocoBase 里,将页面、弹窗、抽屉看作是区块的容器,容器就像一张画布,在里面可以放置各种各样的区块。 + +得益于 NocoBase 将数据与视图分离的设计,页面通过区块承载数据,并根据不同的区块类型,以不同的形式组织和管理数据。 + +## 区块结构 + +一个完整的区块由三部分组成: + +1. 内容区:区块的主体 +2. 操作区:可以放置各种操作按钮,用于操作区块数据 +3. 配置区:操作区块配置的按钮 + +![6.block.jpg](https://static-docs.nocobase.com/07ea73c9abcc16846dd5cd0c960d7cb0.jpg) + +## 区块类型 + +![add-block.jpg](https://static-docs.nocobase.com/c105b36b1f61420f2082d8bc5153f3f0.jpg) + +NocoBase 目前内置 10 几种区块,未来可以通过插件的方式支持更多种。 + +- **数据区块**:为组织数据而设计的区块。 + - **表格**:以表格形式展示多条数据的区块,既可以展示一个数据表,也可以展示相互之间有关联关系的多个数据表。 + - **表单**:以各种类型的输入框录入或编辑数据的区块,既可以为某一个数据表进行录入,也可以对相互之间有关联关系的多个数据表统一录入。 + - **详情**:展示一条特定数据的区块,既可以对某一个数据表的某一条数据进行展示,也可以对相互之间有关联关系的多个数据表中的多条数据统一展示。 + - **日历**:以日历的形式展示多条数据的区块,适合某些在日期上具备重要特征的数据。 + - **看板**:以看板的形式展示多条数据的区块,适合用来对生产过程进行管理。 +- **图表区块**:为图形化展示统计数据而设计的区块。目前支持:柱状图、条形图、折线图、饼图、面积图等。 +- **其他区块**:为展示特殊数据而设计的区块。 + - **Markdown**:用 Markdown 书写的文本内容。 + - **操作记录**:展示一个数据表中的所有数据的变更记录,包括新建、编辑和删除。 + +## 添加区块 + +进入界面配置模式,在页面和弹窗内点击 Add block 按钮即可添加区块。选项分为 4 步: + +1. 选择区块类型:目前可用的区块类型包括表格、表单、详情、日历、看板、Markdown +2. 选择 Collection:此处会列出所有的 Collection +3. 选择创建方式:创建空白区块,或者从复制区块模板,或者引用区块模板 +4. 选择模板:若第 3 步选择了从模板创建,则在第 4 步选择模板 + +![6.block-add.jpg](https://static-docs.nocobase.com/4a4dad014fddada53f2d49f5dba681fb.jpg) + +## 配置区块 + +配置区块包括三方面的内容: + +- 配置区块内容 +- 配置区块操作 +- 配置区块属性 + +### 配置区块内容 + +以表格区块为例,区块内容是指表格中要显示的列。点击 Configure columns 即可配置要显示的列: + +![6.block-content.gif](https://static-docs.nocobase.com/4644fe7e4f6a93e58d63219a1ef19633.gif) + +### 配置区块操作 + +以表格区块为例,有筛选、添加、删除、查看、编辑、自定义等操作可选。点击 Configure actions 按钮可以配置操作。其中,每个操作按钮都可以单独配置属性: + +![6.block-content.gif](https://static-docs.nocobase.com/4644fe7e4f6a93e58d63219a1ef19633.gif) + +### 配置区块属性 + +将光标移到区块右上角,会看到区块配置按钮。以表格区块为例,可以配置的属性有: + +- Block title +- Drag & drop sorting +- Set the data scope +- Set default sorting rules +- Records per page + +## 调整布局 + +页面内既可以只放一个区块,也可以放多个区块进行组合。你可以通过拖拽完成区块位置和宽度的调整。 + +![block-drag.gif](https://static-docs.nocobase.com/afa28c9ec8958c0581ec70f6d40891b6.gif) + +## 区块模板 + +你可以将一个区块保存为模板,以后可以复制或引用这个模板。 + +比如,一个数据表的表单,既用于新增数据,又用于编辑数据,那就可以将这个表单保存为模板,在新增数据和编辑数据的界面里引用它。 + +![block-template.jpg](https://static-docs.nocobase.com/d024cfc5dfd96bfc3ed48cd5c9963cde.jpg) \ No newline at end of file diff --git a/docs/fr-FR/manual/core-concepts/blocks/6.block-add.jpg b/docs/fr-FR/manual/core-concepts/blocks/6.block-add.jpg new file mode 100755 index 000000000..cd609413f Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/blocks/6.block-add.jpg differ diff --git a/docs/fr-FR/manual/core-concepts/blocks/6.block-content.gif b/docs/fr-FR/manual/core-concepts/blocks/6.block-content.gif new file mode 100755 index 000000000..8f79be9fa Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/blocks/6.block-content.gif differ diff --git a/docs/fr-FR/manual/core-concepts/blocks/6.block-content1.gif b/docs/fr-FR/manual/core-concepts/blocks/6.block-content1.gif new file mode 100755 index 000000000..8f79be9fa Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/blocks/6.block-content1.gif differ diff --git a/docs/fr-FR/manual/core-concepts/blocks/6.block.jpg b/docs/fr-FR/manual/core-concepts/blocks/6.block.jpg new file mode 100755 index 000000000..b609af5a0 Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/blocks/6.block.jpg differ diff --git a/docs/fr-FR/manual/core-concepts/blocks/6.collection-setting.gif b/docs/fr-FR/manual/core-concepts/blocks/6.collection-setting.gif new file mode 100755 index 000000000..d969e34e8 Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/blocks/6.collection-setting.gif differ diff --git a/docs/fr-FR/manual/core-concepts/blocks/add-block.jpg b/docs/fr-FR/manual/core-concepts/blocks/add-block.jpg new file mode 100755 index 000000000..2b463f2cf Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/blocks/add-block.jpg differ diff --git a/docs/fr-FR/manual/core-concepts/blocks/block-drag.gif b/docs/fr-FR/manual/core-concepts/blocks/block-drag.gif new file mode 100755 index 000000000..69563d0dc Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/blocks/block-drag.gif differ diff --git a/docs/fr-FR/manual/core-concepts/blocks/block-template.jpg b/docs/fr-FR/manual/core-concepts/blocks/block-template.jpg new file mode 100755 index 000000000..86da281e0 Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/blocks/block-template.jpg differ diff --git a/docs/fr-FR/manual/core-concepts/collections.md b/docs/fr-FR/manual/core-concepts/collections.md new file mode 100755 index 000000000..9324ab3fa --- /dev/null +++ b/docs/fr-FR/manual/core-concepts/collections.md @@ -0,0 +1,59 @@ +# 数据表 + +开发一个系统之前,我们通常要对业务进行抽象,建立数据模型。NocoBase 的数据表由字段(列)和记录(行)组成。数据表的概念与关系型数据库的数据表概念相近,但是字段的概念略有不同。 + +例如,在一个描述订单的数据表中,每列包含的是订单某个特定属性的信息,如收件地址;而每行则包含了某个特定订单的所有信息,如订单号、顾客姓名、电话、收件地址等。 + +## 数据与视图分离 + +NocoBase 的`数据`和`视图`是分离的,分别由数据表和区块来管理和呈现。 + +这就意味着: + +- 你可以创建**一个**数据表,并为其设计**一套**界面,实现数据的展示和操作; +- 你也可以创建**一个**数据表,然后为其设计**多套**界面,用于不同的场景或角色下对数据的展示和操作; +- 你还可以创建**多个**数据表,然后为其设计**一套**界面,实现多个数据表的同时展示和操作; +- 你甚至可以创建**多个**数据表,然后为其设计**多套**界面,每套界面都可以操作多个数据表并完成独特的功能; + +简单说,数据与界面的分离使得**数据的组织和管理更加灵活**,如何呈现数据就看你如何配置界面。 + +## 字段类型 + +NocoBase 目前支持以下几十种字段,未来可以通过插件的方式支持更多种。 + +| 名称 | 类型 | +| -------------------- | --------- | +| 单行文本 | 基本类型 | +| 图标 | 基本类型 | +| 多行文本 | 基本类型 | +| 密码 | 基本类型 | +| 手机号码 | 基本类型 | +| 数字 | 基本类型 | +| 整数 | 基本类型 | +| 电子邮箱 | 基本类型 | +| 百分比 | 基本类型 | +| 下拉菜单(单选) | 选择类型 | +| 下拉菜单(多选) | 选择类型 | +| 中国行政区 | 选择类型 | +| 勾选 | 选择类型 | +| 单选框 | 选择类型 | +| 复选框 | 选择类型 | +| 关联 | 关系类型 | +| 一对一(belongs to) | 关系类型 | +| 一对一(has one) | 关系类型 | +| 一对多 | 关系类型 | +| 多对一 | 关系类型 | +| 多对多 | 关系类型 | +| 公式 | 高级类型 | +| 自动编码 | 高级类型 | +| JSON | 高级类型 | +| Markdown | 多媒体 | +| 富文本 | 多媒体 | +| 附件 | 多媒体 | +| 日期 | 日期&时间 | +| 时间 | 日期&时间 | +| ID | 系统信息 | +| 创建人 | 系统信息 | +| 创建日期 | 系统信息 | +| 最后修改人 | 系统信息 | +| 最后修改日期 | 系统信息 | diff --git a/docs/fr-FR/manual/core-concepts/containers.md b/docs/fr-FR/manual/core-concepts/containers.md new file mode 100755 index 000000000..79f665c1f --- /dev/null +++ b/docs/fr-FR/manual/core-concepts/containers.md @@ -0,0 +1,23 @@ +# 容器 + +在 NocoBase 里,将页面、弹窗、抽屉看作是区块的容器,容器就像一张画布,在里面可以放置各种各样的区块 + +## 页面 + +![container-page.jpg](https://static-docs.nocobase.com/0ce51dbad3cd83a23b0d161e6d020bc0.jpg) + +## 弹窗 + +![container-dialog.jpg](https://static-docs.nocobase.com/d7fc5dde40f18e533c6e7fe897e23c0c.jpg) + +## 抽屉 + +![container-drawer.jpg](https://static-docs.nocobase.com/34bc8abcace4343595545ff02629c02a.jpg) + +## 容器内支持标签页 + +在弹窗、抽屉、页面内,可以添加多个标签页。向每个标签页里添加不同的区块,从而显示不同的内容和操作。比如,在一个顾客信息的弹窗里,添加 3 个标签页,分别用来显示顾客的个人信息、订单记录、顾客评价: + +![7.tabs.gif](https://static-docs.nocobase.com/af3574040a0435a1beb47bc8a46f1fde.gif) + +![container-tab-2.jpg](https://static-docs.nocobase.com/5f6e8ea9222ed084e0703e87a42cc696.jpg) \ No newline at end of file diff --git a/docs/fr-FR/manual/core-concepts/containers/7.tabs.gif b/docs/fr-FR/manual/core-concepts/containers/7.tabs.gif new file mode 100755 index 000000000..df7c895aa Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/containers/7.tabs.gif differ diff --git a/docs/fr-FR/manual/core-concepts/containers/container-dialog.jpg b/docs/fr-FR/manual/core-concepts/containers/container-dialog.jpg new file mode 100755 index 000000000..b5984954d Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/containers/container-dialog.jpg differ diff --git a/docs/fr-FR/manual/core-concepts/containers/container-drawer.jpg b/docs/fr-FR/manual/core-concepts/containers/container-drawer.jpg new file mode 100755 index 000000000..b550ea29e Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/containers/container-drawer.jpg differ diff --git a/docs/fr-FR/manual/core-concepts/containers/container-page.jpg b/docs/fr-FR/manual/core-concepts/containers/container-page.jpg new file mode 100755 index 000000000..c765777ea Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/containers/container-page.jpg differ diff --git a/docs/fr-FR/manual/core-concepts/containers/container-tab-2.jpg b/docs/fr-FR/manual/core-concepts/containers/container-tab-2.jpg new file mode 100755 index 000000000..07b1a982b Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/containers/container-tab-2.jpg differ diff --git a/docs/fr-FR/manual/core-concepts/menus.md b/docs/fr-FR/manual/core-concepts/menus.md new file mode 100755 index 000000000..ff8b9e174 --- /dev/null +++ b/docs/fr-FR/manual/core-concepts/menus.md @@ -0,0 +1,43 @@ +# 菜单 + +目前 NocoBase 支持三种类型的菜单项: + +- 页面:跳转至菜单关联的 NocoBase 的页面; +- 分组:对菜单进行分组,将同类菜单放到统一的位置; +- 链接:跳转至指定的 URL; + +以仓储系统为例,如果你的业务里有储位管理,储位管理里又包含出入库日志、库存查询、跳转 ERP 申请储位等功能。那么可以这样设置菜单: + +``` +- 储位管理(分组) + - 库存查询(页面) + - 出入库日志(页面) + - 跳转ERP申请储位(链接) +``` + +## 默认位置 + +在 NocoBase 内置的页面模板中,菜单会出现在顶部和左侧。 + +![menu-position.jpg](https://static-docs.nocobase.com/d4d0a34c74684c988e369abf5a227186.jpg) + +## 添加 + +![5.menu-add.jpg](https://static-docs.nocobase.com/c11557b3bed06be90b98e395c94f7fc7.jpg) + +点击 Add menu item,选择添加的类型。支持无限级子菜单。 + +## 配置和排序 + +将光标移到菜单项上,右上角会出现排序和配置按钮。按住排序按钮,可以拖拽排序。 + +对菜单项可操作的配置: + +- Edit +- Move to +- Insert before +- Insert after +- Insert Inner +- Delete + +![menu-move.gif](https://static-docs.nocobase.com/ffd21aebbbd1b10a5138ada9727d33a8.gif) \ No newline at end of file diff --git a/docs/fr-FR/manual/core-concepts/menus/5.menu-add.jpg b/docs/fr-FR/manual/core-concepts/menus/5.menu-add.jpg new file mode 100755 index 000000000..da89a6f93 Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/menus/5.menu-add.jpg differ diff --git a/docs/fr-FR/manual/core-concepts/menus/menu-move.gif b/docs/fr-FR/manual/core-concepts/menus/menu-move.gif new file mode 100755 index 000000000..1e278d868 Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/menus/menu-move.gif differ diff --git a/docs/fr-FR/manual/core-concepts/menus/menu-position.jpg b/docs/fr-FR/manual/core-concepts/menus/menu-position.jpg new file mode 100755 index 000000000..8e21a0a18 Binary files /dev/null and b/docs/fr-FR/manual/core-concepts/menus/menu-position.jpg differ diff --git a/docs/fr-FR/manual/data-visualization/chart-block.md b/docs/fr-FR/manual/data-visualization/chart-block.md new file mode 100644 index 000000000..ef7614466 --- /dev/null +++ b/docs/fr-FR/manual/data-visualization/chart-block.md @@ -0,0 +1,22 @@ +# 图表区块 + +图表区块是一个用于组织多个图表的面板。 + +## 添加 + +点击“添加区块” (Add block) - “图表” (Charts),可以创建可以空白的图表区块。 + +![](https://static-docs.nocobase.com/790faf0a126e4ffcc3ff976818325cfd.png) + +在图表区块中点击“添加区块” (Add block) - “图表” (Chart),选择对应的数据表 (Collection), 可以创建和配置图表。有查看权限的数据表才可以用于配置图表,否则将会在选项中被隐藏。 + +![](https://static-docs.nocobase.com/93ed2fada2478fba1b243d8705717a34.png) + +## 配置 + +- 图表区块中的图表可以像普通区块一样,在图表区块中,自由拖拽和组织。 +- 点击“配置” (Configure) 按钮,可以对当前图表进行修改。 +- 点击“复制” (Duplicate) 按钮,可以快速复制当前图表。 +- 可以“编辑区块标题” (Edit block title),给当前图表添加标题说明。 + +![](https://static-docs.nocobase.com/76787ede47aa514636dcb100f599740e.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/data-visualization/configure.md b/docs/fr-FR/manual/data-visualization/configure.md new file mode 100644 index 000000000..7ff2a3ac5 --- /dev/null +++ b/docs/fr-FR/manual/data-visualization/configure.md @@ -0,0 +1,63 @@ +# 配置面板 + +图表的配置面板整体上划分为三个部分:数据配置、图表配置和图表预览。 + +![](https://static-docs.nocobase.com/b397cf9ab751b1652ab7d2de81ec0f11.png) + +## 数据配置 + +![](https://static-docs.nocobase.com/801c019fc92c2fe756d622585b214d6e.png) + +- 顶部下拉框代表当前正在配置的数据表 (Collection),通过下拉菜单可以切换。 +- 配置完成后,点击“执行查询” (Run query) 可以通过配置获取数据,“数据” (Data) 面板会展示数据。 + +### 度量 (Measures) + +![](https://static-docs.nocobase.com/35caab4b0dea7c2378e2fe226439aa51.png) + +度量字段,通常是图表需要展示的核心数据。度量数据可以通过聚合函数进行统计,支持常用的数据库统计函数 `求和 (Sum)`,`计数 (Count)`,`平均值 (Avg)`,`最大值 (Max)`,`最小值 (Min)`. 度量字段可以有多个,可以设置别名。 + +### 维度 (Dimesions) + +![](https://static-docs.nocobase.com/7d0568757e6d999d67c316c2ff28d8e7.png) + +维度字段,通常是图表数据分组的依据。对于日期类型字段,支持如图所示的格式化方式,格式化通过数据库函数实现(例如:MySQL 对应 `date_format`),其他类型数据格式化见[数据转换](#数据转换)部分。 + +:::info +**维度格式化 (Dimensions Format) VS 数据转换 (Transform)** + +- 维度格式化发生在获取最终数据之前,数据分组按照维度格式化后的值进行,通常在按时间段筛选数据时有此需求。 +- 数据转换对响应数据做进一步处理,诸如可读性处理,以展现恰当的数据,数据转换在前端进行。 + ::: + +### 筛选 (Filter) + +![](https://static-docs.nocobase.com/42e35ace7a63776f6ba82325975128b5.png) + +筛选配置将对分组前的数据进行过滤。有“当前用户”和“当前日期”变量可供选择,给图表配置动态的筛选范围。 + +### 排序 (Sort) 和限制 (Limit) + +![](https://static-docs.nocobase.com/a49a841116b5c9a42fb79d3431257651.png) + +默认数据集条数上限为 2000. + +### 缓存 + +![](https://static-docs.nocobase.com/3d1e3f3282384d50bd7be3a580a07c4f.png) + +开启缓存后,图表将展示缓存的数据。 + +## 图表配置 + +![](https://static-docs.nocobase.com/4b9b518258613b5a8c8d3e3cd7f6f9a8.png) + +- 图表类型 (Chart Type) - 用于展示的图表类型。NocoBase 使用 [G2Plot](https://g2plot.antv.antgroup.com/) 作为默认的图表库,想扩展使用其他图表库,可以参考[开发指南](../dev/index.md)。 +- 基础配置 - 选择图表后,会出现相应的基础可视化配置,字段配置通常提供了下拉菜单供选择,选项中包含了 Collection 的基础字段和字段别名。 +- JSON 配置 - 当基础配置不满足要求时,可以使用 JSON 配置其他图表属性。参考 [G2Plot 文档](https://g2plot.antv.antgroup.com/api/plot-api)。 + +## 数据转换 + +![](https://static-docs.nocobase.com/86511c44dd3825bdcc3954d4132cd7a0.png) + +使用数据转换可以对接口响应的数据做进一步处理,目前支持转换处理的数据类型为 `number`,`date`,`time`,`datetime`, 对于不属于支持的数据类型的字段,可以手动选择为这几个类型,以使用对应的转换方法。 \ No newline at end of file diff --git a/docs/fr-FR/manual/data-visualization/filter.md b/docs/fr-FR/manual/data-visualization/filter.md new file mode 100644 index 000000000..6e3f68adc --- /dev/null +++ b/docs/fr-FR/manual/data-visualization/filter.md @@ -0,0 +1,60 @@ +# 筛选区块 + +图表区块中的筛选区块,用于对当前图表区块內的多个图表进行动态筛选。 + +## 启用/禁用 + +在图表区块中点击“添加区块” (Add block) - “筛选” (Filter), 可以启用/禁用筛选区块。 + +![](https://static-docs.nocobase.com/d0e6b116952fa6b719acb0f858b432c3.png) + +## 配置筛选字段 + +### 数据表字段 + +对于当前图表区块中的图表所用到的数据表,直接选择数据表对应的字段,即可创建一个筛选表单字段。 + +![](https://static-docs.nocobase.com/e2ef150e9beb8c78004d9049a7536219.png) + +可以对表单字段进行配置: + +![](https://static-docs.nocobase.com/215f0b996e69bf2d5b99746e6d521c3d.png) + +- 配置字段显示标题 +- 配置字段描述 +- 配置该字段在筛选时应用的操作符 + ![](https://static-docs.nocobase.com/d6a593a330d27da4ea78124dfdb8450d.png) + +- 配置字段默认值,可以使用变量。变量的数据类型需与当前字段数据类型相符。 + ![](https://static-docs.nocobase.com/37dee4008f3283db24d491fb8f0404fa.png) + + 例如: + + - 配置默认值为当前用户ID,页面加载后自动筛选出当前用户数据。 + - 配置默认值为当前日期,页面加载后自动筛选出当前日期数据。 + +### 自定义字段 + +某些情况下,可能需要用同一个筛选字段来筛选不同表的不同字段。例如:用一个日期字段来筛选不同表的不同日期字段。这时候可以选择创建自定义字段。 + +![](https://static-docs.nocobase.com/87544594246453d175ef265030c0801a.png) + +添加自定义字段的时候,需要设置字段标题,选择字段组件及进行相应配置,还可以从当前区块使用的数据表中选择一个字段,直接应用该字段的元数据配置,避免重复配置。 + +![](https://static-docs.nocobase.com/ef09136d674d4b7356e819350bcac804.png) + +要使用自定义筛选字段,需要打开对应图表的配置,然后在数据查询的筛选配置中,添加筛选条件并使用“当前筛选” (Current filter) 中的变量。被筛选字段的类型需要和筛选表单自定义字段的类型相符。 + +![](https://static-docs.nocobase.com/f9f2487c4da4b2024af1556743beab6c.png) + +对于自定义字段,同样可以配置标题、描述和默认值。 + +![](https://static-docs.nocobase.com/4a8feb12404f5cc5e74d589263307e5a.png) + +## 配置区块动作 + +- 筛选 (Filter) - 应用筛选条件 +- 重置 (Reset) - 重置筛选表单 +- 折叠/展开 (Collapse / Expand) - 将折叠为一行或展开多行 + +![](https://static-docs.nocobase.com/8619ac90fa045b3a9c6d6610f7be1a81.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/data-visualization/index.md b/docs/fr-FR/manual/data-visualization/index.md new file mode 100644 index 000000000..164494576 --- /dev/null +++ b/docs/fr-FR/manual/data-visualization/index.md @@ -0,0 +1,23 @@ +# 数据可视化 + +## 介绍 + +NocoBase的数据可视化插件提供了可视化的数据检索功能和丰富的图表组件,基于系统Collection数据,用户可以快速建立可视化面板,灵活组织图表,进行业务数据分析。 + +![](https://static-docs.nocobase.com/51be43d5400d6294f6c20d11009f23c4.png) + +## 安装 + +## RoadMap + +- 计划或进行中 + - 对单个图表进行数据下钻,与表格联动 + - 与SQL Collection更好结合 + - 图表交互配置,如链接跳转 +- 在其他区块中添加图表 +- 更方便的数据处理和转换 +- 支持Having +- 在图表区块中添加其他区块,比如Markdown +- 在一个图表中组合多个Query +- 权限控制优化 +- ... \ No newline at end of file diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-14-06-23.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-14-06-23.png new file mode 100644 index 000000000..defc3e8a5 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-14-06-23.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-15-16-21.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-15-16-21.png new file mode 100644 index 000000000..7127e73a7 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-15-16-21.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-15-17-23.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-15-17-23.png new file mode 100644 index 000000000..8a23b77ba Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-15-17-23.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-15-19-16.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-15-19-16.png new file mode 100644 index 000000000..2228432a5 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-15-19-16.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-17-48-11.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-17-48-11.png new file mode 100644 index 000000000..d127ba7a5 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-17-48-11.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-18-03-03.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-18-03-03.png new file mode 100644 index 000000000..030514f64 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-18-03-03.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-23-34.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-23-34.png new file mode 100644 index 000000000..ae3348255 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-23-34.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-27-51.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-27-51.png new file mode 100644 index 000000000..24f15ca77 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-27-51.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-29-44.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-29-44.png new file mode 100644 index 000000000..8e7f90175 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-29-44.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-32-30.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-32-30.png new file mode 100644 index 000000000..e5f02f3df Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-32-30.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-38-59.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-38-59.png new file mode 100644 index 000000000..e9b974b83 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-38-59.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-39-43.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-39-43.png new file mode 100644 index 000000000..4705a6ad2 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-39-43.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-42-32.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-42-32.png new file mode 100644 index 000000000..075874c61 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-42-32.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-45-41.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-45-41.png new file mode 100644 index 000000000..8979f6012 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-45-41.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-49-18.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-49-18.png new file mode 100644 index 000000000..17485590d Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-49-18.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-50-20.png b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-50-20.png new file mode 100644 index 000000000..1318273d2 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/2023-11-28-20-50-20.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/A680brszPoHrB7xFEWucIdjjnSg.png b/docs/fr-FR/manual/data-visualization/static/A680brszPoHrB7xFEWucIdjjnSg.png new file mode 100644 index 000000000..970e3462b Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/A680brszPoHrB7xFEWucIdjjnSg.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/BlkEby9Z7or3CWxvhTCcLXumnHf.png b/docs/fr-FR/manual/data-visualization/static/BlkEby9Z7or3CWxvhTCcLXumnHf.png new file mode 100644 index 000000000..dfef1a101 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/BlkEby9Z7or3CWxvhTCcLXumnHf.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/DEFSbBh6WoujLyxoktHcXEADnom.png b/docs/fr-FR/manual/data-visualization/static/DEFSbBh6WoujLyxoktHcXEADnom.png new file mode 100644 index 000000000..6ae09ac62 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/DEFSbBh6WoujLyxoktHcXEADnom.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/E2pwbBm4BofyHzxut4jcjonJn0s.png b/docs/fr-FR/manual/data-visualization/static/E2pwbBm4BofyHzxut4jcjonJn0s.png new file mode 100644 index 000000000..ee654dd5b Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/E2pwbBm4BofyHzxut4jcjonJn0s.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/K0trbvxhxoVayLx84sUcX5nLnUh.png b/docs/fr-FR/manual/data-visualization/static/K0trbvxhxoVayLx84sUcX5nLnUh.png new file mode 100644 index 000000000..42ec6e996 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/K0trbvxhxoVayLx84sUcX5nLnUh.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/OjTRbDlhHo32npxFBsicKGJinXd.png b/docs/fr-FR/manual/data-visualization/static/OjTRbDlhHo32npxFBsicKGJinXd.png new file mode 100644 index 000000000..68d884f5c Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/OjTRbDlhHo32npxFBsicKGJinXd.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/R0VlbVbkEoVcL1xA2xEcxHQLn1c.png b/docs/fr-FR/manual/data-visualization/static/R0VlbVbkEoVcL1xA2xEcxHQLn1c.png new file mode 100644 index 000000000..a07d41fb0 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/R0VlbVbkEoVcL1xA2xEcxHQLn1c.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/SVYhbc1LNoFSvzxYoOAc78mvn3e.png b/docs/fr-FR/manual/data-visualization/static/SVYhbc1LNoFSvzxYoOAc78mvn3e.png new file mode 100644 index 000000000..53b307c6a Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/SVYhbc1LNoFSvzxYoOAc78mvn3e.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/SdgrbugCjopiffxOrLZcZKhxnEh.png b/docs/fr-FR/manual/data-visualization/static/SdgrbugCjopiffxOrLZcZKhxnEh.png new file mode 100644 index 000000000..7fea06831 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/SdgrbugCjopiffxOrLZcZKhxnEh.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/TUZCbKXHOo6fN6xfxSWcjkhhngg.png b/docs/fr-FR/manual/data-visualization/static/TUZCbKXHOo6fN6xfxSWcjkhhngg.png new file mode 100644 index 000000000..05d7e9a83 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/TUZCbKXHOo6fN6xfxSWcjkhhngg.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/TdsOb1FBfomRaxxSdrHciggGnub.png b/docs/fr-FR/manual/data-visualization/static/TdsOb1FBfomRaxxSdrHciggGnub.png new file mode 100644 index 000000000..5fed0a072 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/TdsOb1FBfomRaxxSdrHciggGnub.png differ diff --git a/docs/fr-FR/manual/data-visualization/static/UrFGbUN1GonqkpxyaUUclAefns3.png b/docs/fr-FR/manual/data-visualization/static/UrFGbUN1GonqkpxyaUUclAefns3.png new file mode 100644 index 000000000..9ff3163b8 Binary files /dev/null and b/docs/fr-FR/manual/data-visualization/static/UrFGbUN1GonqkpxyaUUclAefns3.png differ diff --git a/docs/fr-FR/manual/file-manager/aliyun-oss.md b/docs/fr-FR/manual/file-manager/aliyun-oss.md new file mode 100644 index 000000000..8bcd198a2 --- /dev/null +++ b/docs/fr-FR/manual/file-manager/aliyun-oss.md @@ -0,0 +1 @@ +# Aliyun OSS diff --git a/docs/fr-FR/manual/file-manager/amazon-s3.md b/docs/fr-FR/manual/file-manager/amazon-s3.md new file mode 100644 index 000000000..5f4a3f276 --- /dev/null +++ b/docs/fr-FR/manual/file-manager/amazon-s3.md @@ -0,0 +1 @@ +# Amazon S3 diff --git a/docs/fr-FR/manual/file-manager/index.md b/docs/fr-FR/manual/file-manager/index.md new file mode 100644 index 000000000..501fe48ef --- /dev/null +++ b/docs/fr-FR/manual/file-manager/index.md @@ -0,0 +1,12 @@ +# 文件管理器 + +:::warning +文档待补充 +::: + + diff --git a/docs/fr-FR/manual/file-manager/local.md b/docs/fr-FR/manual/file-manager/local.md new file mode 100644 index 000000000..f4f1f99ad --- /dev/null +++ b/docs/fr-FR/manual/file-manager/local.md @@ -0,0 +1 @@ +# 本地存储 diff --git a/docs/fr-FR/manual/file-manager/tencent-cos.md b/docs/fr-FR/manual/file-manager/tencent-cos.md new file mode 100644 index 000000000..ffadb5185 --- /dev/null +++ b/docs/fr-FR/manual/file-manager/tencent-cos.md @@ -0,0 +1 @@ +# Tencent COS diff --git a/docs/fr-FR/manual/localization-management/index.md b/docs/fr-FR/manual/localization-management/index.md new file mode 100644 index 000000000..5b8a5b4e4 --- /dev/null +++ b/docs/fr-FR/manual/localization-management/index.md @@ -0,0 +1,47 @@ +# 本地化管理 + +## 介绍 + +## 安装 + +## 使用手册 + +### 激活插件 + +![](https://static-docs.nocobase.com/d16f6ecd6bfb8d1e8acff38f23ad37f8.png) + +### 本地化管理 + +![](https://static-docs.nocobase.com/c117b5337941f0afd564152053666480.png) + +### 同步翻译词条 + +![](https://static-docs.nocobase.com/bc380a4ebdb2af075abcab5f16287cf9.png) + +同步之后,会列出所有可翻译词条 + +![](https://static-docs.nocobase.com/cf501e6b4d2f67520ad35b00d1ed3446.png) + +### 发布 + +翻译完成之后,需要点击“发布”按钮,才能使修改结果生效 + +![](https://static-docs.nocobase.com/1f9dc52defb37ac67912011ba31c3160.png) + +### 翻译其他语言 + +启用其他语言,如简体中文 + +![](https://static-docs.nocobase.com/618830967aaeb643c892fce355d59a73.png) + +切换语言 + +![](https://static-docs.nocobase.com/35548a7bf099df4f30d160c72863c6b8.png) + +词条同步 + +![](https://static-docs.nocobase.com/12f39cfcd7d8d9ce3d367426b959af16.png) + +翻译并发布 + +![](https://static-docs.nocobase.com/eb22725dcab6807dc8a410f5e10e9492.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/localization-management/static/BFRcbhE31oEAHOxss5ncRnEvnZb.png b/docs/fr-FR/manual/localization-management/static/BFRcbhE31oEAHOxss5ncRnEvnZb.png new file mode 100644 index 000000000..3e52179dc Binary files /dev/null and b/docs/fr-FR/manual/localization-management/static/BFRcbhE31oEAHOxss5ncRnEvnZb.png differ diff --git a/docs/fr-FR/manual/localization-management/static/DxQ8bDrtsoi8ObxadwZcCYntn9d.png b/docs/fr-FR/manual/localization-management/static/DxQ8bDrtsoi8ObxadwZcCYntn9d.png new file mode 100644 index 000000000..b51c6e242 Binary files /dev/null and b/docs/fr-FR/manual/localization-management/static/DxQ8bDrtsoi8ObxadwZcCYntn9d.png differ diff --git a/docs/fr-FR/manual/localization-management/static/GaqEbrgAdokzgJxqicMcdKxMnQf.png b/docs/fr-FR/manual/localization-management/static/GaqEbrgAdokzgJxqicMcdKxMnQf.png new file mode 100644 index 000000000..ec4c28e92 Binary files /dev/null and b/docs/fr-FR/manual/localization-management/static/GaqEbrgAdokzgJxqicMcdKxMnQf.png differ diff --git a/docs/fr-FR/manual/localization-management/static/IkBhbaqrfodzsMxxueIcUENnnTd.png b/docs/fr-FR/manual/localization-management/static/IkBhbaqrfodzsMxxueIcUENnnTd.png new file mode 100644 index 000000000..ff36c8d38 Binary files /dev/null and b/docs/fr-FR/manual/localization-management/static/IkBhbaqrfodzsMxxueIcUENnnTd.png differ diff --git a/docs/fr-FR/manual/localization-management/static/IkFDbWE8ios6qSxp78scf2BOnQg.png b/docs/fr-FR/manual/localization-management/static/IkFDbWE8ios6qSxp78scf2BOnQg.png new file mode 100644 index 000000000..dd15f11be Binary files /dev/null and b/docs/fr-FR/manual/localization-management/static/IkFDbWE8ios6qSxp78scf2BOnQg.png differ diff --git a/docs/fr-FR/manual/localization-management/static/Pi1nbxvVEoqSIox28FkcYkw7nID.png b/docs/fr-FR/manual/localization-management/static/Pi1nbxvVEoqSIox28FkcYkw7nID.png new file mode 100644 index 000000000..8d3a23243 Binary files /dev/null and b/docs/fr-FR/manual/localization-management/static/Pi1nbxvVEoqSIox28FkcYkw7nID.png differ diff --git a/docs/fr-FR/manual/localization-management/static/S49abMq61oBfMFxRvs7cZTgHnoh.png b/docs/fr-FR/manual/localization-management/static/S49abMq61oBfMFxRvs7cZTgHnoh.png new file mode 100644 index 000000000..a1db38f6a Binary files /dev/null and b/docs/fr-FR/manual/localization-management/static/S49abMq61oBfMFxRvs7cZTgHnoh.png differ diff --git a/docs/fr-FR/manual/localization-management/static/TmD3bXzJ2onTXcxyaWXc2g30n0e.png b/docs/fr-FR/manual/localization-management/static/TmD3bXzJ2onTXcxyaWXc2g30n0e.png new file mode 100644 index 000000000..562afbd77 Binary files /dev/null and b/docs/fr-FR/manual/localization-management/static/TmD3bXzJ2onTXcxyaWXc2g30n0e.png differ diff --git a/docs/fr-FR/manual/localization-management/static/XO9TbVodPo01SrxFPrkcUsVmngg.png b/docs/fr-FR/manual/localization-management/static/XO9TbVodPo01SrxFPrkcUsVmngg.png new file mode 100644 index 000000000..970b990d5 Binary files /dev/null and b/docs/fr-FR/manual/localization-management/static/XO9TbVodPo01SrxFPrkcUsVmngg.png differ diff --git a/docs/fr-FR/manual/mobile-client/index.md b/docs/fr-FR/manual/mobile-client/index.md new file mode 100644 index 000000000..440f20380 --- /dev/null +++ b/docs/fr-FR/manual/mobile-client/index.md @@ -0,0 +1,12 @@ +# 移动端 + +:::warning +文档待补充 +::: + + diff --git a/docs/fr-FR/manual/mobile/development/frontend.md b/docs/fr-FR/manual/mobile/development/frontend.md new file mode 100644 index 000000000..d32eee787 --- /dev/null +++ b/docs/fr-FR/manual/mobile/development/frontend.md @@ -0,0 +1,3 @@ +## Schema Initializer 和 Settings + +![20240712115610](https://static-docs.nocobase.com/20240712115610.png) diff --git a/docs/fr-FR/manual/mobile/index.md b/docs/fr-FR/manual/mobile/index.md new file mode 100644 index 000000000..77341c907 --- /dev/null +++ b/docs/fr-FR/manual/mobile/index.md @@ -0,0 +1,17 @@ +# 移动端 + + + +## 介绍 + +提供移动端页面配置的能力。 + +## 安装 + +预置插件,需要先激活才能使用。 + +![20240712113500](https://static-docs.nocobase.com/20240712113500.png) + +## 用法 + +![20240712113531](https://static-docs.nocobase.com/20240712113531.png) diff --git a/docs/fr-FR/manual/plugin-manager/plugin-manager/index.md b/docs/fr-FR/manual/plugin-manager/plugin-manager/index.md new file mode 100644 index 000000000..4257e00dc --- /dev/null +++ b/docs/fr-FR/manual/plugin-manager/plugin-manager/index.md @@ -0,0 +1,42 @@ +# 插件管理器 + +插件管理器支持通过界面添加插件,以简单、直观,轻量级的使用体验来扩展 NocoBase 的功能。轻松扩展和定制应用功能,包括安装、升级、和卸载插件 + +插件管理器的组成部分 + +1. 本地插件/插件市场 +2. 插件分类(内置、启用、未启用、有问题,支持按插件名称模糊搜索) +3. 添加新插件 +4. 插件配置主体 + +![](https://static-docs.nocobase.com/86fb70757a77ab3654f97faffc2dce78.png) + +#### 查看插件文档 + +点击插件可以快速阅览插件的介绍文档(包括说明文档、依赖兼容性检查、更新日志) + +![](https://static-docs.nocobase.com/a4015bea903d3c6874ca94e6c1085278.png) + +#### 添加插件 + +即插即用,可以直接通过界面添加插件,支持从 npm registry(可以是私有的)下载、本地上传、URL 下载 + +![](https://static-docs.nocobase.com/103baa0ba0dd88e7481c0636147c7a7c.png) + +#### 激活插件 + +![](https://static-docs.nocobase.com/c76b7228678c358ba6f8f68ef05d3cd5.gif) + +#### 禁用插件 + +![](https://static-docs.nocobase.com/86f526669dba0d4f3245d24d9e9d35a9.gif) + +#### 删除插件 + +![](https://static-docs.nocobase.com/b32d6507aaee2b708290311cf1e7ebca.gif) + +#### 更新插件 + +目前仅 storage/plugins 下的插件才有更新操作,如图 + +![](https://static-docs.nocobase.com/7bfaec2785dc6a2e864fee2337fc57ef.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/plugin-manager/plugin-manager/static/DtkpbfloNog6gtxM6RWcqDYwnph.png b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/DtkpbfloNog6gtxM6RWcqDYwnph.png new file mode 100644 index 000000000..cc02c0f8b Binary files /dev/null and b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/DtkpbfloNog6gtxM6RWcqDYwnph.png differ diff --git a/docs/fr-FR/manual/plugin-manager/plugin-manager/static/Ehu2boQ2xowSrnxpMS1ctIprnMd.png b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/Ehu2boQ2xowSrnxpMS1ctIprnMd.png new file mode 100644 index 000000000..ce13dfa7c Binary files /dev/null and b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/Ehu2boQ2xowSrnxpMS1ctIprnMd.png differ diff --git a/docs/fr-FR/manual/plugin-manager/plugin-manager/static/K8JDbo9JCo9iCExVEw4cKHfOnPg.png b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/K8JDbo9JCo9iCExVEw4cKHfOnPg.png new file mode 100644 index 000000000..43c3fe359 Binary files /dev/null and b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/K8JDbo9JCo9iCExVEw4cKHfOnPg.png differ diff --git a/docs/fr-FR/manual/plugin-manager/plugin-manager/static/LcP9b9oVwoN5ZQx2CZScJ7TAn9c.gif b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/LcP9b9oVwoN5ZQx2CZScJ7TAn9c.gif new file mode 100644 index 000000000..5bafff096 Binary files /dev/null and b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/LcP9b9oVwoN5ZQx2CZScJ7TAn9c.gif differ diff --git a/docs/fr-FR/manual/plugin-manager/plugin-manager/static/Mgo0bjYccoNjmNxNT8rcfF0tndd.png b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/Mgo0bjYccoNjmNxNT8rcfF0tndd.png new file mode 100644 index 000000000..c5c349d81 Binary files /dev/null and b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/Mgo0bjYccoNjmNxNT8rcfF0tndd.png differ diff --git a/docs/fr-FR/manual/plugin-manager/plugin-manager/static/NOz2b4To1o1fMbxqnb8cfqacnfT.gif b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/NOz2b4To1o1fMbxqnb8cfqacnfT.gif new file mode 100644 index 000000000..71f3c87a5 Binary files /dev/null and b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/NOz2b4To1o1fMbxqnb8cfqacnfT.gif differ diff --git a/docs/fr-FR/manual/plugin-manager/plugin-manager/static/VehkbE6RqogLlcxoRrVcEvpJn0e.gif b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/VehkbE6RqogLlcxoRrVcEvpJn0e.gif new file mode 100644 index 000000000..68ddab50c Binary files /dev/null and b/docs/fr-FR/manual/plugin-manager/plugin-manager/static/VehkbE6RqogLlcxoRrVcEvpJn0e.gif differ diff --git a/docs/fr-FR/manual/plugin-manager/plugin-settings/index.md b/docs/fr-FR/manual/plugin-manager/plugin-settings/index.md new file mode 100644 index 000000000..c0fb1f908 --- /dev/null +++ b/docs/fr-FR/manual/plugin-manager/plugin-settings/index.md @@ -0,0 +1,12 @@ +# 插件管理中心 + +管理中心为用户提供了一个集中管理和配置系统信息以及与工作相关设置的平台。用户可以根据其特定的业务需求和个人偏好来自定义系统、数据表建模、工作流配置和插件配置 + +插件管理中心的组成 + +1. 置顶的快捷配置项 +2. 所有激活的插件配置列表 +3. 插件的标签页 +4. 正文内容 + +![](https://static-docs.nocobase.com/1c0e3cb111e993232b51aa6233e07478.jpeg) \ No newline at end of file diff --git a/docs/fr-FR/manual/plugin-manager/plugin-settings/static/N50VbOPHpoKvYVxacuUc1i6Cnrd.jpeg b/docs/fr-FR/manual/plugin-manager/plugin-settings/static/N50VbOPHpoKvYVxacuUc1i6Cnrd.jpeg new file mode 100644 index 000000000..0285ff522 Binary files /dev/null and b/docs/fr-FR/manual/plugin-manager/plugin-settings/static/N50VbOPHpoKvYVxacuUc1i6Cnrd.jpeg differ diff --git a/docs/fr-FR/manual/quick-start/functional-zoning.md b/docs/fr-FR/manual/quick-start/functional-zoning.md new file mode 100755 index 000000000..86a824bed --- /dev/null +++ b/docs/fr-FR/manual/quick-start/functional-zoning.md @@ -0,0 +1,9 @@ +# 功能分区 + +NocoBase 默认内置一个布局模板,这个布局模板的界面主要分为三个区域: + +1. 配置入口区。具备系统配置权限的用户,可以在这里看到界面配置、插件管理器、设置中心的入口。 +2. 菜单区。顶部是一级菜单,左侧是二级及以下层级的菜单。每个菜单项都可以配置为菜单分组、页面、外部链接。 +3. 区块容器。这里是页面的区块容器,在里面可以放置各种各样的区块。 + +![3.zone.jpg](https://static-docs.nocobase.com/23ecf224ce92531b8500268220dd2e0c.jpg) \ No newline at end of file diff --git a/docs/fr-FR/manual/quick-start/functional-zoning/3.zone.jpg b/docs/fr-FR/manual/quick-start/functional-zoning/3.zone.jpg new file mode 100755 index 000000000..9507d2c7e Binary files /dev/null and b/docs/fr-FR/manual/quick-start/functional-zoning/3.zone.jpg differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app.md b/docs/fr-FR/manual/quick-start/the-first-app.md new file mode 100755 index 000000000..b79eb959c --- /dev/null +++ b/docs/fr-FR/manual/quick-start/the-first-app.md @@ -0,0 +1,92 @@ +# 第一个应用 + +让我们用 NocoBase 搭建一个订单管理系统。 + +## 1. 创建数据表和字段 + +在这个订单管理系统中,我们需要掌握`Customers`、`Products`、`Orders`的信息,他们彼此之间互相关联。经过分析,我们需要建立 4 个数据表,它们的字段分别为: + +- Customers + - 姓名 + - 地址 + - 性别 + - 电话 + - _订单(购买过的所有订单,数据来自`Orders`,每条顾客数据包含多条订单数据)_ +- Products + - 商品名称 + - 描述 + - 图片 + - 价格 +- Orders + - 订单编号 + - 总价 + - 备注 + - 地址 + - _顾客(该订单所属的顾客,数据来自`Customers`,每条订单数据属于一条顾客数据)_ + - _订单明细(该订单中的商品,数据来自`Order Details`,每条订单数据包含多条订单明细数据)_ +- Order list + - _订单(该明细所属的订单,数据来自`Orders`,每条订单明细数据属于一条订单数据)_ + - _商品(该明细所包含的商品,数据来自`Products`,每条订单明细数据包含一条商品数据)_ + - 数量 + +其中,斜体的字段是关系字段,关联到其他数据表。 + +接下来,点击“数据表配置”按钮,进入数据表配置界面,创建第一个 Collection `Customers`。 + +![create-collection.gif](https://static-docs.nocobase.com/becee29110811c8ceed9b14825e238ad.gif) + +然后点击“字段配置”,为`Customers` 添加 name 字段,它是单行文本类型。 + +![create-field.gif](https://static-docs.nocobase.com/d4c49c55959516fc7e30a379b2eba2b3.gif) + +用同样的方法,为`Customers` 添加 Address、Gender、Phone,它们分别是单行文本、单项选择类型、手机号码类型。 + +![fields-list.jpg](https://static-docs.nocobase.com/887d0173e3f1418f2404f1a9fac77934.jpg) + +用同样的方法,创建 Collection `Products`、`Orders`、`Order list` 以及它们的字段。 + +![collection-list.jpg](https://static-docs.nocobase.com/5d2dabdbdebf0a02bbb81ae65f9f54c5.jpg) + +其中,对于关系字段,如果你不熟悉一对多、多对多等概念,可以直接使用 Link to 类型来建立数据表之间的关联。如果你熟悉这几个概念,请正确使用 One to many, Many to one 等类型来建立数据表之间的关联。比如在这个例子中,我们将 `Orders` 与 `Order list` 关联,关系为 One to many。 + +![collection-list.jpg](https://static-docs.nocobase.com/be7df51a4848342af83f87f623b8fa0f.jpg) + +在图形化的数据表里,可以很直观的看出各个表之间的关系。 + +![graph-collection.jpg](https://static-docs.nocobase.com/f045201f3ecb84d259cb31fe94a4eda4.jpg) + +将数据表和字段创建完成后,我们开始制作界面。 + +## 2. 配置菜单和页面 + +我们需要顾客、订单、商品三个页面展示和管理我们的数据。 + +点击界面配置按钮,进入界面配置模式。在界面配置模式下,我们可以添加菜单项,添加页面,在页面内布置区块。 + +![1.editor.gif](https://static-docs.nocobase.com/d7cd4ec11ba8e6d44f498e4c272de7ba.gif) + +点击添加菜单项,添加菜单分组 “Customers” 和 “Orders & Products” ,然后添加子菜单页面 “All Orders” 和 “Products”。 + +![1.menu.gif](https://static-docs.nocobase.com/22f890a608a95c9a17c325aa51f74d16.gif) + +添加完菜单和页面之后,我们可以在页面内添加和配置区块了。 + +## 3. 添加和配置区块 + +NocoBase 目前支持表格、看板、日历、表单、详情等类型的区块,它们可以将数据表中的数据展示出来,并可以对数据进行操作。显然,顾客、订单、商品 都适合用表格的方式展示和操作。 + +我们在“所有订单”页面,添加一个表格区块,数据源选择 Collection `Orders` ,并为这个表格区块配置需要显示的列。 + +![1.block.gif](https://static-docs.nocobase.com/460d4a1942dcbfc331b4fb46f9ac7bee.gif) + +给这个表格区块配置操作,包括筛选、添加、删除、查看、编辑。 + +![1.action.gif](https://static-docs.nocobase.com/5316605c55379b60b2d448e216b3f4d6.gif) + +为新增、编辑、查看等操作配置表单和详情区块。 + +![1.action-block.gif](https://static-docs.nocobase.com/0d8dfac3b10219bd07439b40681cf0ca.gif) + +然后,用同样的方法,在 Products 和 Customers 页面布置表格区块。完成后,退出界面配置模式,进入使用模式,一个简单的订单管理系统就完成了。 + +![demo-finished.jpg](https://static-docs.nocobase.com/ff6d0662391cb6e2ff879858e4fff698.jpg) \ No newline at end of file diff --git a/docs/fr-FR/manual/quick-start/the-first-app/1.action-block.gif b/docs/fr-FR/manual/quick-start/the-first-app/1.action-block.gif new file mode 100755 index 000000000..db4d312de Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/1.action-block.gif differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/1.action.gif b/docs/fr-FR/manual/quick-start/the-first-app/1.action.gif new file mode 100755 index 000000000..f8a8f2ba6 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/1.action.gif differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/1.block.gif b/docs/fr-FR/manual/quick-start/the-first-app/1.block.gif new file mode 100755 index 000000000..b2cbbcb79 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/1.block.gif differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/1.editor.gif b/docs/fr-FR/manual/quick-start/the-first-app/1.editor.gif new file mode 100755 index 000000000..d5e7a84df Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/1.editor.gif differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/1.menu.gif b/docs/fr-FR/manual/quick-start/the-first-app/1.menu.gif new file mode 100755 index 000000000..d1f43c62a Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/1.menu.gif differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/collection-list.jpg b/docs/fr-FR/manual/quick-start/the-first-app/collection-list.jpg new file mode 100755 index 000000000..b291ed3b8 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/collection-list.jpg differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/create-collection.gif b/docs/fr-FR/manual/quick-start/the-first-app/create-collection.gif new file mode 100755 index 000000000..d8eae060c Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/create-collection.gif differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/create-field.gif b/docs/fr-FR/manual/quick-start/the-first-app/create-field.gif new file mode 100755 index 000000000..ba3f95278 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/create-field.gif differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/demo-finished.jpg b/docs/fr-FR/manual/quick-start/the-first-app/demo-finished.jpg new file mode 100755 index 000000000..b880c89de Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/demo-finished.jpg differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/fields-list.jpg b/docs/fr-FR/manual/quick-start/the-first-app/fields-list.jpg new file mode 100755 index 000000000..13a382880 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/fields-list.jpg differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/graph-collection.jpg b/docs/fr-FR/manual/quick-start/the-first-app/graph-collection.jpg new file mode 100644 index 000000000..682fb9320 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/graph-collection.jpg differ diff --git a/docs/fr-FR/manual/quick-start/the-first-app/order-list-relation.jpg b/docs/fr-FR/manual/quick-start/the-first-app/order-list-relation.jpg new file mode 100644 index 000000000..64c02fdd2 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/the-first-app/order-list-relation.jpg differ diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode.md b/docs/fr-FR/manual/quick-start/ui-editor-mode.md new file mode 100755 index 000000000..e1fe0d107 --- /dev/null +++ b/docs/fr-FR/manual/quick-start/ui-editor-mode.md @@ -0,0 +1,51 @@ +# 界面配置模式 + +NocoBase 采用所见即所得的方式来配置界面。点击右上角的`UI Editor`按钮,即可切换配置模式和使用模式。进入配置模式之后,界面上各处将会出现橙色的配置入口。 + +![ui-editor.gif](https://static-docs.nocobase.com/e582c50f1cf12fee8eb743e1255c550d.gif) + +通常,配置项入口会出现在元素的右上角。 + +## 菜单项配置 + +将鼠标移到菜单项上,在右上角即可以看到拖拽排序按钮、配置项按钮,可以编辑、移动、插入、删除。 + +![menu-config.jpg](https://static-docs.nocobase.com/d5adf5b82a94066ade0e819862bc2be3.jpg) + +## 区块配置 + +将鼠标移到一个区块上,在右上角即可以看到拖拽排序按钮、新增区块按钮、配置项按钮。 + +![block-config.jpg](https://static-docs.nocobase.com/4bdd7a33cabdadd7d6c5e0040d0ef9db.jpg) + +不同的区块还会有一些自己独有的配置项。比如表格区块,将鼠标移到表头上即可以在右上角看到表头的配置项;在表头最右侧还可以看到表格列的配置项。 + +![block-config-2.jpg](https://static-docs.nocobase.com/bdb9976e055fb37214ba31342d389cfa.jpg) + +![block-config-3.jpg](https://static-docs.nocobase.com/999847d0a80f25213d3c6a8ab13514d1.jpg) + +## 操作配置 + +在区块中可以看到操作的配置入口,这些入口在不同的区块里会出现在不同的位置。 + +比如表格区块,在右上方可以看到针对表格数据的操作: + +![action-config-1.jpg](https://static-docs.nocobase.com/99eeb6b2657f96709d12accf60d635d5.jpg) + +在操作列的表头里可以看到针对单行数据的操作: + +![action-config-2.jpg](https://static-docs.nocobase.com/29c5a37149cb8d512897870bf35e7e1f.jpg) + +在详情区块的右上角可以看到针对详情的操作: + +![action-config-3.jpg](https://static-docs.nocobase.com/46155c5f82ede92ddd80539e022f15e9.jpg) + +在表单区块底部可以看到针对表单的操作: + +![action-config-4.jpg](https://static-docs.nocobase.com/a55126785d34fdee2e7510c06dc30886.jpg) + +## 标签页配置 + +在弹窗或抽屉里,可以添加多个标签页,用于承载不同的区块。 + +![tab-config.jpg](https://static-docs.nocobase.com/a91fc4e0c771196c71aea5202ad22b3c.jpg) \ No newline at end of file diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-1.jpg b/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-1.jpg new file mode 100755 index 000000000..c31a20f7a Binary files /dev/null and b/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-1.jpg differ diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-2.jpg b/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-2.jpg new file mode 100755 index 000000000..22b14119f Binary files /dev/null and b/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-2.jpg differ diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-3.jpg b/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-3.jpg new file mode 100755 index 000000000..59e5a2527 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-3.jpg differ diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-4.jpg b/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-4.jpg new file mode 100755 index 000000000..f799395bf Binary files /dev/null and b/docs/fr-FR/manual/quick-start/ui-editor-mode/action-config-4.jpg differ diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode/block-config-2.jpg b/docs/fr-FR/manual/quick-start/ui-editor-mode/block-config-2.jpg new file mode 100755 index 000000000..0e041e35e Binary files /dev/null and b/docs/fr-FR/manual/quick-start/ui-editor-mode/block-config-2.jpg differ diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode/block-config-3.jpg b/docs/fr-FR/manual/quick-start/ui-editor-mode/block-config-3.jpg new file mode 100755 index 000000000..0b1244cc0 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/ui-editor-mode/block-config-3.jpg differ diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode/block-config.jpg b/docs/fr-FR/manual/quick-start/ui-editor-mode/block-config.jpg new file mode 100755 index 000000000..e1a94876c Binary files /dev/null and b/docs/fr-FR/manual/quick-start/ui-editor-mode/block-config.jpg differ diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode/menu-config.jpg b/docs/fr-FR/manual/quick-start/ui-editor-mode/menu-config.jpg new file mode 100755 index 000000000..8765202f0 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/ui-editor-mode/menu-config.jpg differ diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode/tab-config.jpg b/docs/fr-FR/manual/quick-start/ui-editor-mode/tab-config.jpg new file mode 100755 index 000000000..ac46ee284 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/ui-editor-mode/tab-config.jpg differ diff --git a/docs/fr-FR/manual/quick-start/ui-editor-mode/ui-editor.gif b/docs/fr-FR/manual/quick-start/ui-editor-mode/ui-editor.gif new file mode 100755 index 000000000..0ea3bf781 Binary files /dev/null and b/docs/fr-FR/manual/quick-start/ui-editor-mode/ui-editor.gif differ diff --git a/docs/fr-FR/manual/system-settings/index.md b/docs/fr-FR/manual/system-settings/index.md new file mode 100644 index 000000000..f8bd98281 --- /dev/null +++ b/docs/fr-FR/manual/system-settings/index.md @@ -0,0 +1,12 @@ +# 系统设置 + +:::warning +文档待补充 +::: + + diff --git a/docs/fr-FR/manual/theme-editor/index.md b/docs/fr-FR/manual/theme-editor/index.md new file mode 100644 index 000000000..1d4bd28a1 --- /dev/null +++ b/docs/fr-FR/manual/theme-editor/index.md @@ -0,0 +1,12 @@ +# 主题编辑器 + +:::warning +文档待补充 +::: + + diff --git a/docs/fr-FR/manual/ui/actions/add-new.md b/docs/fr-FR/manual/ui/actions/add-new.md new file mode 100644 index 000000000..f705ec4e9 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/add-new.md @@ -0,0 +1 @@ +# 添加 diff --git a/docs/fr-FR/manual/ui/actions/add-record.md b/docs/fr-FR/manual/ui/actions/add-record.md new file mode 100644 index 000000000..0e5ca5f7b --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/add-record.md @@ -0,0 +1,5 @@ +# 添加数据 + +自定义添加数据操作允许用户在操作中为任意数据表中添加数据 + +![](https://static-docs.nocobase.com/70c3982c59d6c7b7f36e225f4c208d2f.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/custom-request.md b/docs/fr-FR/manual/ui/actions/custom-request.md new file mode 100644 index 000000000..a164c397c --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/custom-request.md @@ -0,0 +1,5 @@ +# 自定义请求 + +配置自定义请求操作的请求地址,以满足特定业务需求,详情查看自定义请求插件文档 + +![](https://static-docs.nocobase.com/69d610904dbec87ef719e5345915f5a2.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/delete.md b/docs/fr-FR/manual/ui/actions/delete.md new file mode 100644 index 000000000..d44a37bc2 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/delete.md @@ -0,0 +1,5 @@ +# 删除 + +删除操作用于删除数据记录(行按钮/批量操作按钮),有二次确认弹窗 + +![](https://static-docs.nocobase.com/96272ba867a128004738fce9f5d6d63f.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/duplicate.md b/docs/fr-FR/manual/ui/actions/duplicate.md new file mode 100644 index 000000000..e3382b2fd --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/duplicate.md @@ -0,0 +1,80 @@ +# 复制 + +复制操作允许用户复制一行数据以便于创建新的数据记录,支持直接复制/复制到表单并继续填写两种方式 + +#### 直接复制 + +![](https://static-docs.nocobase.com/2c0ac5d1a539de4b72b49b7d966d8c09.png) + +- 默认以直接复制的方式复制数据 +- 目标数据表:是指复制添加的目标数据表(在继承的场景下,可以复制给子表,直接复制只能复制添加到本表) +- 模版字段:用于指定要复制的字段,可全选,必填 + +完成配置后点击按钮即复制数据 + +#### 复制到表单并继续填写 + +配置的模板字段作为将默认值填充到表单中,可修改后提交 + +可以设置本表或子表为复制添加的目标表 + +![](https://static-docs.nocobase.com/a072aa572fd0a0fe643eadf95471da2a.png) + +配置模板字段:模板字段将作为默认值填充到表单中,只会带出有勾选的字段值 + +![](https://static-docs.nocobase.com/8032fa2025180ade275da55b97774b4d.png) + +「运单」(o2m)是复制的关系,调整其字段组件为子表单,可配置子表单中的字段 + +![](https://static-docs.nocobase.com/b13c9287bae8601646727a2e78b81be7.png) + +同步表单字段:完成表单配置后可点击同步表单字段按钮,会自动解析将表单中已配置的字段均勾选上(每次表单字段配置修改之后需要手动再同步一次),同步表单字段后可自定义调整模板字段 + +![](https://static-docs.nocobase.com/156b6d8d741521e63d12e49092414d58.png) + +点击复制操作会打开弹窗,并按照模板字段带出模板数据作为表单默认值填充,可修改数据后提交完成数据复制 + +![](https://static-docs.nocobase.com/1c0a0ae0c59971f48b2282a68831d44b.png) + +如下图完整示例为订单列表配置复制操作 + +![](https://static-docs.nocobase.com/fa8a89abf0ba136df04b6d0d838eae4e.gif) + +#### 复制、引用、预加载的说明 + +对于不同字段(不同关系类型)有不同的处理逻辑(复制、引用、预加载),其中调整关系字段的字段组件中也会影响处理逻辑(Select 和 Record pikcer 用于处理引用关系,Sub-form 和 Sub-table 用于处理复制关系) + +- 复制 + + - 普通字段是复制 + - hasOne 和 hasMany 的关系字段只能是复制(即该类型的关系字段不能用 Select、Record picker 作为字段组件,应使用 Sub-form、Sub-table 等) + + - hasOne 和 hasMany 字段组件的变更不会改变处理逻辑(复制) + - 复制的关系字段,所有的子字段都可以被选择 + +- 引用 + + - belongsTo 和 belongsToMany 是引用 + - 引用是可能变成复制的,比如字段组件从 select 调整为 sub-form 后,关系就从引用变成了复制(变成复制之后,所有的子字段都是可选的) + +- 预加载:引用字段里的关系字段 + + - 引用的关系字段下的关系字段为预加载 + - 预加载的关系字段在字段组件变更后可能变成引用或者复制 + +#### 关于全选 + +- 所有的复制字段都勾选上 +- 所有的引用字段都勾选上 + +#### 模板数据的处理逻辑 + +- 所有的关系的 fk 都会过滤掉 +- 如果是复制的关系数据 pk 也会过滤掉 +- 引用和预加载有 pk 字段 + +#### 如何理解同步表单字段 + +在大多数场景下,表单配置涉及的字段非常繁多。在处理这种复杂表单场景时,手动配置模板字段通常会变得非常繁琐。为了解决这个问题,引入了一个功能强大的同步表单字段按钮。这个按钮的作用是自动解析表单字段的配置,根据字段类型和关系字段组件的配置来处理字段复制逻辑,包括复制、引用和预加载。在这个过程中,已经配置好的字段会默认被勾选上 + +每当用户修改表单字段配置之后,系统不会自动同步这些变化。因此,用户需要手动点击同步表单字段按钮,以便将最新的配置信息应用到模板配置中。 \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/edit.md b/docs/fr-FR/manual/ui/actions/edit.md new file mode 100644 index 000000000..f94eef69a --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/edit.md @@ -0,0 +1,5 @@ +# 编辑 + +编辑操作允许用户对数据进行修改,通常配置表单区块 + +![](https://static-docs.nocobase.com/9b412840521b7ae6d5c5f0372df2f349.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/export.md b/docs/fr-FR/manual/ui/actions/export.md new file mode 100644 index 000000000..ca4c6ef02 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/export.md @@ -0,0 +1,9 @@ +# 导出 + +导出操作是通过插件扩展实现的,批量导出区块中所绑定的数据表的所有数据,支持配置导出字段的标题 + +![](https://static-docs.nocobase.com/c074c4eb9d67a8408d98ff6299715157.png) + +- 配置可导出字段 + +![](https://static-docs.nocobase.com/903b4c12bcd1b8e59e133d2f9822eb56.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/filter.md b/docs/fr-FR/manual/ui/actions/filter.md new file mode 100644 index 000000000..bb7d7f555 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/filter.md @@ -0,0 +1,13 @@ +# 筛选 + +筛选操作通常出现在数据区块中,可以配置各种条件来过滤数据,需要注意的是如果区块已经配置了数据范围,筛选操作将与数据范围的条件合并作为最终过滤条件。 + +![](https://static-docs.nocobase.com/da548ad1c170bef3d2359ac82764b534.png) + +支持配置可筛选的字段 + +![](https://static-docs.nocobase.com/85815dc40157571ba072cc392fbe43d4.png) + +如下图运单列表配置筛选操作:通过调整条件配置筛选数据 + +![](https://static-docs.nocobase.com/02cabf6201fdf4165747c9fcde687a5e.gif) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/import.md b/docs/fr-FR/manual/ui/actions/import.md new file mode 100644 index 000000000..ffd69f416 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/import.md @@ -0,0 +1,17 @@ +# 导入 + +导入操作是通过插件扩展实现的,目前支持通过导入xlsx文件批量导入数据 + +1. 配置可导入的字段 + +![](https://static-docs.nocobase.com/967a130c06237e0724e5815fc3b16903.png) + +![](https://static-docs.nocobase.com/0046c530677bff984db4d560956da35a.png) + +1. 下载导入的模板,在模板中添加数据后导入 + +![](https://static-docs.nocobase.com/1038ab1b1fcdc7ad6e5346cde27eed49.png) + +详见导入说明 + +[https://github.com/nocobase/nocobase/tree/main/packages/plugins/%40nocobase/plugin-import#%E5%AF%BC%E5%85%A5%E8%AF%B4%E6%98%8E](https://github.com/nocobase/nocobase/tree/main/packages/plugins/%40nocobase/plugin-import#%E5%AF%BC%E5%85%A5%E8%AF%B4%E6%98%8E) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/index.md b/docs/fr-FR/manual/ui/actions/index.md new file mode 100644 index 000000000..15a45ceaa --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/index.md @@ -0,0 +1,45 @@ +# 操作 + +在 UI 里,操作是用来触发一段指令的按钮。可以直接放在页面、对话框、抽屉里,也可以和区块组合使用。目前可动态配置的操作,主要是和区块组合使用 + +## 区块里的操作 + +![](https://static-docs.nocobase.com/3e69f1f2991842ecad640705bc9feda4.png) + +## 操作的设计器(工具栏) + +和区块、字段不太一样,操作的设计器里只有两个图标,分别为: + +- 拖拽 +- 参数配置 + +![](https://static-docs.nocobase.com/007422d42678c54f79668dfafe69b60e.png) + +## 操作的拖拽排序 + +按住按钮设计器里的「拖拽」图标,可以对按钮进行排序 + +```bash +缺少一个动图 +``` + +## 通用的参数配置 + +- 编辑按钮 +- 打开方式:抽屉、对话框 +- 弹窗尺寸:大、中、小 +- 删除 + +![](https://static-docs.nocobase.com/e99916932f6c4d58bcad4d892b5daf15.png) + +## 操作的联动规则 + +有上下文数据的操作,还可以配置「联动规则」 + +![](https://static-docs.nocobase.com/c431434a285278ea00bedf9e4dac4d45.png) + +联动规则配置 + +![](https://static-docs.nocobase.com/149c049bb0c0ce931c6c0333e12b0610.png) + +可以添加多条,条件与筛选用法一致,可以控制按钮的显示、隐藏、启用、禁用 \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/open-popup.md b/docs/fr-FR/manual/ui/actions/open-popup.md new file mode 100644 index 000000000..644ceaa84 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/open-popup.md @@ -0,0 +1,9 @@ +# 打开弹窗 + +打开弹窗操作以弹窗的方式呈现数据,可自定义配置详情区块或表单区块,适用于多种场景。如当数据表中有许多字段,可以将字段拆分到不同的操作区块中,专注于查看或修改某些字段,根据业务需求创建多个定制化数据展示或编辑界面的操作 + +![](https://static-docs.nocobase.com/c859041afb43752431e78c6e81c44c43.png) + +如图订单表格中配置了三个打开弹窗操作,查看主订单(订单主信息),查看商品(订单的关联的商品信息)和查看客户(订单关联的客户信息) + +![](https://static-docs.nocobase.com/110e2eed418c755ef40b7259e5816c73.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/print.md b/docs/fr-FR/manual/ui/actions/print.md new file mode 100644 index 000000000..665a62158 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/print.md @@ -0,0 +1,3 @@ +# 打印 + +![](https://static-docs.nocobase.com/ce71d14cb7889b1e2291fbdb104b00e5.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/refresh.md b/docs/fr-FR/manual/ui/actions/refresh.md new file mode 100644 index 000000000..025a4f046 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/refresh.md @@ -0,0 +1,5 @@ +# 刷新 + +刷新操作用于重新加载数据区块中的数据,支持手动刷新 + +![](https://static-docs.nocobase.com/3488c8c8296e9048f815d89198a51c5a.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/save-record.md b/docs/fr-FR/manual/ui/actions/save-record.md new file mode 100644 index 000000000..390e504b8 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/save-record.md @@ -0,0 +1,14 @@ +# 保存数据 + +自定义保存数据操作是表单区块特有的操作,支持自定义操作的行为: + +- 编辑按钮 +- 字段赋值:点击当前自定义按钮时,当前数据字段赋值中的情况保存。 +- 跳过必填校验 +- 提交成功后的动作 + +![](https://static-docs.nocobase.com/2d35b787114dede3a0f08d7431edb37a.png) + +- 绑定工作流 + +![](https://static-docs.nocobase.com/6d93cd53d45c8408ed78b0289f0f5dae.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/static/ApcrbSF87oD3roxGW80cFkAxn2c.png b/docs/fr-FR/manual/ui/actions/static/ApcrbSF87oD3roxGW80cFkAxn2c.png new file mode 100644 index 000000000..291a8c545 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/ApcrbSF87oD3roxGW80cFkAxn2c.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/BoEEbVUptoQCXOxvFJTc0p8Vnlb.png b/docs/fr-FR/manual/ui/actions/static/BoEEbVUptoQCXOxvFJTc0p8Vnlb.png new file mode 100644 index 000000000..dcad0c620 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/BoEEbVUptoQCXOxvFJTc0p8Vnlb.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/C8RzbI7v5opcUNx7OWzcz1l6nxc.png b/docs/fr-FR/manual/ui/actions/static/C8RzbI7v5opcUNx7OWzcz1l6nxc.png new file mode 100644 index 000000000..bc2264211 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/C8RzbI7v5opcUNx7OWzcz1l6nxc.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/CzfCbLjC3oPItSxoeGAcDh0Rnte.png b/docs/fr-FR/manual/ui/actions/static/CzfCbLjC3oPItSxoeGAcDh0Rnte.png new file mode 100644 index 000000000..b811482e4 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/CzfCbLjC3oPItSxoeGAcDh0Rnte.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/DKwnbW8MfohvHjxplG4cVkcnn8d.png b/docs/fr-FR/manual/ui/actions/static/DKwnbW8MfohvHjxplG4cVkcnn8d.png new file mode 100644 index 000000000..714ab3654 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/DKwnbW8MfohvHjxplG4cVkcnn8d.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/DTzUb0LcPoimfBxvHoHcDD5znAf.png b/docs/fr-FR/manual/ui/actions/static/DTzUb0LcPoimfBxvHoHcDD5znAf.png new file mode 100644 index 000000000..d3520984c Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/DTzUb0LcPoimfBxvHoHcDD5znAf.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/G1bpbybaVoAWKlx4mCmc6HvQn0b.gif b/docs/fr-FR/manual/ui/actions/static/G1bpbybaVoAWKlx4mCmc6HvQn0b.gif new file mode 100644 index 000000000..a304e56a1 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/G1bpbybaVoAWKlx4mCmc6HvQn0b.gif differ diff --git a/docs/fr-FR/manual/ui/actions/static/H1hPbS7CWooWjpxAUfActBgbnsW.png b/docs/fr-FR/manual/ui/actions/static/H1hPbS7CWooWjpxAUfActBgbnsW.png new file mode 100644 index 000000000..8669eaf5a Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/H1hPbS7CWooWjpxAUfActBgbnsW.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/J0udbzu0AoU7sVxJ9xtcvQdLnNc.png b/docs/fr-FR/manual/ui/actions/static/J0udbzu0AoU7sVxJ9xtcvQdLnNc.png new file mode 100644 index 000000000..86939b8ed Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/J0udbzu0AoU7sVxJ9xtcvQdLnNc.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/JzDSbax1BoXxy2xrD6CcYuEKnRp.png b/docs/fr-FR/manual/ui/actions/static/JzDSbax1BoXxy2xrD6CcYuEKnRp.png new file mode 100644 index 000000000..d588f826f Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/JzDSbax1BoXxy2xrD6CcYuEKnRp.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/KR15bOuXoo0u5QxZXmjcNbUJnoe.png b/docs/fr-FR/manual/ui/actions/static/KR15bOuXoo0u5QxZXmjcNbUJnoe.png new file mode 100644 index 000000000..e8f44ef8a Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/KR15bOuXoo0u5QxZXmjcNbUJnoe.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/KsK1b5DOwoKI1qx4Qhscahrrneb.png b/docs/fr-FR/manual/ui/actions/static/KsK1b5DOwoKI1qx4Qhscahrrneb.png new file mode 100644 index 000000000..b7d94bc38 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/KsK1b5DOwoKI1qx4Qhscahrrneb.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/MDtybwjRsoC8qfxrFAecdJpkngc.png b/docs/fr-FR/manual/ui/actions/static/MDtybwjRsoC8qfxrFAecdJpkngc.png new file mode 100644 index 000000000..50d884b2c Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/MDtybwjRsoC8qfxrFAecdJpkngc.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/NRH9bnRw8ogxRkxZ7i3clbW1nRv.png b/docs/fr-FR/manual/ui/actions/static/NRH9bnRw8ogxRkxZ7i3clbW1nRv.png new file mode 100644 index 000000000..7c39abb13 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/NRH9bnRw8ogxRkxZ7i3clbW1nRv.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/Ox76b54eho4fTUxdk67cjcjenCc.png b/docs/fr-FR/manual/ui/actions/static/Ox76b54eho4fTUxdk67cjcjenCc.png new file mode 100644 index 000000000..f8b3c8950 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/Ox76b54eho4fTUxdk67cjcjenCc.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/PAgIbrq5xoMKKfxoG8mcOIOynpf.png b/docs/fr-FR/manual/ui/actions/static/PAgIbrq5xoMKKfxoG8mcOIOynpf.png new file mode 100644 index 000000000..e56108875 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/PAgIbrq5xoMKKfxoG8mcOIOynpf.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/Pkf4bvn30oWEIjxrFmPc3d0lnPd.png b/docs/fr-FR/manual/ui/actions/static/Pkf4bvn30oWEIjxrFmPc3d0lnPd.png new file mode 100644 index 000000000..c237b712b Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/Pkf4bvn30oWEIjxrFmPc3d0lnPd.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/QBHTb3fVBot2lqxdGnhcf29tnrb.png b/docs/fr-FR/manual/ui/actions/static/QBHTb3fVBot2lqxdGnhcf29tnrb.png new file mode 100644 index 000000000..ab9a8a54e Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/QBHTb3fVBot2lqxdGnhcf29tnrb.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/QPq9bd2xaoB6unxVvEPccbJsnRg.png b/docs/fr-FR/manual/ui/actions/static/QPq9bd2xaoB6unxVvEPccbJsnRg.png new file mode 100644 index 000000000..d8a0e40cf Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/QPq9bd2xaoB6unxVvEPccbJsnRg.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/QqICbfLMMozpgBxYBpMcKuOKnmg.png b/docs/fr-FR/manual/ui/actions/static/QqICbfLMMozpgBxYBpMcKuOKnmg.png new file mode 100644 index 000000000..8038a1a90 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/QqICbfLMMozpgBxYBpMcKuOKnmg.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/R3f2biRIdoEm7DxUO6Ec1abXnKc.gif b/docs/fr-FR/manual/ui/actions/static/R3f2biRIdoEm7DxUO6Ec1abXnKc.gif new file mode 100644 index 000000000..c31a4b050 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/R3f2biRIdoEm7DxUO6Ec1abXnKc.gif differ diff --git a/docs/fr-FR/manual/ui/actions/static/R5eGbDbcEoLPrexCEzAcgnWfnjT.png b/docs/fr-FR/manual/ui/actions/static/R5eGbDbcEoLPrexCEzAcgnWfnjT.png new file mode 100644 index 000000000..05ccd6fb2 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/R5eGbDbcEoLPrexCEzAcgnWfnjT.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/RDaibir7Jo6NHzx4IuGcYiKLnGb.gif b/docs/fr-FR/manual/ui/actions/static/RDaibir7Jo6NHzx4IuGcYiKLnGb.gif new file mode 100644 index 000000000..6fe21f650 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/RDaibir7Jo6NHzx4IuGcYiKLnGb.gif differ diff --git a/docs/fr-FR/manual/ui/actions/static/RUsJb4OBFow7zcxSgKocJN6Fnah.png b/docs/fr-FR/manual/ui/actions/static/RUsJb4OBFow7zcxSgKocJN6Fnah.png new file mode 100644 index 000000000..4dbda7393 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/RUsJb4OBFow7zcxSgKocJN6Fnah.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/RZhIbo49lo2vV5xV5hZc0jkfn1d.png b/docs/fr-FR/manual/ui/actions/static/RZhIbo49lo2vV5xV5hZc0jkfn1d.png new file mode 100644 index 000000000..aef3d62f6 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/RZhIbo49lo2vV5xV5hZc0jkfn1d.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/SGMubg0mCoVcbSxmOficmvisnHd.png b/docs/fr-FR/manual/ui/actions/static/SGMubg0mCoVcbSxmOficmvisnHd.png new file mode 100644 index 000000000..7bdf8111c Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/SGMubg0mCoVcbSxmOficmvisnHd.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/SHP3b6s7YoabQ2xFO5pc8ZwDnNg.png b/docs/fr-FR/manual/ui/actions/static/SHP3b6s7YoabQ2xFO5pc8ZwDnNg.png new file mode 100644 index 000000000..7256e94fc Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/SHP3b6s7YoabQ2xFO5pc8ZwDnNg.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/SU3PbOHyDoPT13xt4n2c785Engd.png b/docs/fr-FR/manual/ui/actions/static/SU3PbOHyDoPT13xt4n2c785Engd.png new file mode 100644 index 000000000..701372956 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/SU3PbOHyDoPT13xt4n2c785Engd.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/U9AwbR4ehodjDyxFgdFcjZssn1e.png b/docs/fr-FR/manual/ui/actions/static/U9AwbR4ehodjDyxFgdFcjZssn1e.png new file mode 100644 index 000000000..0c3e802e2 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/U9AwbR4ehodjDyxFgdFcjZssn1e.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/U9VCbG9I6ohTzQxzvPIc6oR3nid.png b/docs/fr-FR/manual/ui/actions/static/U9VCbG9I6ohTzQxzvPIc6oR3nid.png new file mode 100644 index 000000000..889475c16 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/U9VCbG9I6ohTzQxzvPIc6oR3nid.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/Vz3kbrsk4oikc0xdbt6czL0Tn4b.png b/docs/fr-FR/manual/ui/actions/static/Vz3kbrsk4oikc0xdbt6czL0Tn4b.png new file mode 100644 index 000000000..6d31a67d2 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/Vz3kbrsk4oikc0xdbt6czL0Tn4b.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/W7uJbyoy3oyeM1xQKZrc0GxMnhd.png b/docs/fr-FR/manual/ui/actions/static/W7uJbyoy3oyeM1xQKZrc0GxMnhd.png new file mode 100644 index 000000000..c7922508b Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/W7uJbyoy3oyeM1xQKZrc0GxMnhd.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/WQAObL0sUocLRIx1dydcmaOEnQf.png b/docs/fr-FR/manual/ui/actions/static/WQAObL0sUocLRIx1dydcmaOEnQf.png new file mode 100644 index 000000000..5fb62ae25 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/WQAObL0sUocLRIx1dydcmaOEnQf.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/WnChbrBPNoBvbFxZcVVccn5wnlg.png b/docs/fr-FR/manual/ui/actions/static/WnChbrBPNoBvbFxZcVVccn5wnlg.png new file mode 100644 index 000000000..a8e7a0f73 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/WnChbrBPNoBvbFxZcVVccn5wnlg.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/WqjNbus2yozg3LxpRecccPA5nIb.png b/docs/fr-FR/manual/ui/actions/static/WqjNbus2yozg3LxpRecccPA5nIb.png new file mode 100644 index 000000000..db5b0718a Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/WqjNbus2yozg3LxpRecccPA5nIb.png differ diff --git a/docs/fr-FR/manual/ui/actions/static/XbxybS8u3od6TfxiQDYcTMq4n7g.png b/docs/fr-FR/manual/ui/actions/static/XbxybS8u3od6TfxiQDYcTMq4n7g.png new file mode 100644 index 000000000..a5de56bc5 Binary files /dev/null and b/docs/fr-FR/manual/ui/actions/static/XbxybS8u3od6TfxiQDYcTMq4n7g.png differ diff --git a/docs/fr-FR/manual/ui/actions/submit-to-workflow.md b/docs/fr-FR/manual/ui/actions/submit-to-workflow.md new file mode 100644 index 000000000..d1f3eb523 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/submit-to-workflow.md @@ -0,0 +1,9 @@ +# 提交至工作流 + +提交至工作流操作由插件扩展 + +1. 新增、更新表单中支持提交至工作流的配置和触发。 +2. 可在一个按钮点击时触发多个工作流,各自选定不同的工作流和数据上下文(不限制数据,用户自行保证)。 +3. 表单按钮触发仅支持新的工作流类型“表单事件”。 + +详情可查看插件文档 diff --git a/docs/fr-FR/manual/ui/actions/submit.md b/docs/fr-FR/manual/ui/actions/submit.md new file mode 100644 index 000000000..8102e46d3 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/submit.md @@ -0,0 +1,17 @@ +# 提交 + +提交操作用于保存表单数据(表单区块特有) + +![](https://static-docs.nocobase.com/a8dd8cb5a0110c35a1197eb5800a099f.png) + +#### 参数配置 + +- 保存方式:仅针对新建操作中表单区块的提交支持配置保存方式 + +![](https://static-docs.nocobase.com/25fc9b88760248e7015673b29b9487f4.png) + +- 绑定工作流:支持与工作流的绑定配置,提交后自动触发工作流,通过定义触发数据上下文,实现高级的自动化任务,提高数据处理效率和业务流程控制 + +![](https://static-docs.nocobase.com/a77bdff33353fb155b0c919db76e0474.png) + +详情可查看工作流使用文档 \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/update-record.md b/docs/fr-FR/manual/ui/actions/update-record.md new file mode 100644 index 000000000..2bbd65514 --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/update-record.md @@ -0,0 +1,9 @@ +# 更新数据 + +自定义行操作更新数据,通过配置字段赋值确定要修改的内容 + +![](https://static-docs.nocobase.com/03af47524a4b41742cdeb298b02500eb.png) + +如图在运单表格区块中配置更新数据操作用于确认送达 + +![](https://static-docs.nocobase.com/3057b0c6cd176342a15a3892488019fa.gif) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/actions/view.md b/docs/fr-FR/manual/ui/actions/view.md new file mode 100644 index 000000000..d73d8fc1a --- /dev/null +++ b/docs/fr-FR/manual/ui/actions/view.md @@ -0,0 +1,5 @@ +# 查看 + +详情操作用于查看数据的详细信息,通常配置详情区块,详情区块 + +![](https://static-docs.nocobase.com/7252f4916033d26551d22ab3e6b95112.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/blocks/index.md b/docs/fr-FR/manual/ui/blocks/index.md new file mode 100644 index 000000000..4a2dd5f65 --- /dev/null +++ b/docs/fr-FR/manual/ui/blocks/index.md @@ -0,0 +1,90 @@ +# 区块 + +区块是内容的载体,可以放置于页面(Page)、对话框(Modal)或抽屉(Drawer)里,多个区块可以自由拖拽排列。 + +## 添加区块 + +区块可以放置于页面(Page)、对话框(Modal)或抽屉(Drawer)里 + +### 页面里的区块 + +目前页面里的区块类型包括:数据区块、筛选区块、其他区块 + +![](https://static-docs.nocobase.com/dad0a394d33dd26f31c3202a76bb0153.png) + +### 弹窗(对话框或抽屉)里的区块 + +弹窗有对话框和抽屉两种,和页面一样也可以添加区块,区别在于弹窗里的区块通常为单条记录的添加、编辑或查看等,区块类型包括当前数据区块、关系区块、其他区块。 + +#### 抽屉 + +![](https://static-docs.nocobase.com/e18726fb0b52ddab89b9b1a44788f361.png) + +#### 对话框 + +![](https://static-docs.nocobase.com/4763fc5fc008bdf3915f84a7e433c0f8.png) + +## 区块的设计器 + +每个区块右上角都有三个小图标,从左到右分别为: + +1. 拖拽布局 +2. 快捷添加区块 +3. 区块参数配置 + +![](https://static-docs.nocobase.com/b488f3013532a246df59b89c0688a58f.png) + +简单的区块所有的配置项都集中在「区块参数配置」里,如 Markdown + +![](https://static-docs.nocobase.com/f37e277863068b2661f66d4020af806a.png) + +复杂的数据类型区块还会提供独立的内嵌的「配置字段」和「配置操作」 + +![](https://static-docs.nocobase.com/71b550da637d23145a5f62d48ee8521b.png) + +除此之外,也可以自由发挥,提供更多嵌套的可能,如图表区块 + +![](https://static-docs.nocobase.com/07588190b3f41ae3060e71d8b76b4447.png) + +## 区块布局 + +多个区块可以通过拖拽调整布局 + +![](https://static-docs.nocobase.com/f6692295ac0917f3babce9a60ce80879.gif) + +## 区块模板 + +可以将一个数据类型区块保存为模板,以后添加区块时可以直接复制或引用这个模板。比如,一个数据表的表单,既用于新增数据,又用于编辑数据,那就可以将这个表单保存为模板,在新增数据和编辑数据的界面里引用它。 + +### 如何添加和使用模板? + +1. 将数据区块保存为区块模板(只有数据类型的区块才有这个配置项) + +![](https://static-docs.nocobase.com/b7718cea8784587d53524ade3c5b0a82.png) + +1. 添加区块时,选择复制或引用模板 + +![](https://static-docs.nocobase.com/135df7344e0f3080199e4bb1071c2fa6.png) + +### 复制和引用的区别 + +复制是基于区块模板创建的全新区块,区块有调整不影响模块;引用是直接使用区块模板,区块调整会改变模板,所有引用了当前模板的区块都会产生变化。 + +## 区块类型 + +NocoBase 默认将区块分为四种类型: + +- 数据区块:可以将 Collection 的数据展示在区块里 +- 筛选区块:目前只能在页面里添加,可用于数据区块的数据筛选 +- 关系区块:目前只能在弹窗里添加,可用于当前记录的关系数据的增删改查等 +- 其他区块:用于放置独立区块,如 Markdown、审计日志区块、工作流待办区块等 + +### 数据区块 + +### 筛选区块 + +### 关系区块 + +### 其他区块 + +## 筛选联动 \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/blocks/static/BEmxbD2SgoUTDexnYjzcmh7Knhg.png b/docs/fr-FR/manual/ui/blocks/static/BEmxbD2SgoUTDexnYjzcmh7Knhg.png new file mode 100644 index 000000000..a2479759d Binary files /dev/null and b/docs/fr-FR/manual/ui/blocks/static/BEmxbD2SgoUTDexnYjzcmh7Knhg.png differ diff --git a/docs/fr-FR/manual/ui/blocks/static/EicAbMa7Jo2MD9x8FSfcpgTGnHc.png b/docs/fr-FR/manual/ui/blocks/static/EicAbMa7Jo2MD9x8FSfcpgTGnHc.png new file mode 100644 index 000000000..45698aa22 Binary files /dev/null and b/docs/fr-FR/manual/ui/blocks/static/EicAbMa7Jo2MD9x8FSfcpgTGnHc.png differ diff --git a/docs/fr-FR/manual/ui/blocks/static/ImutbF0YDoWldOxrPilcwQFHnSe.png b/docs/fr-FR/manual/ui/blocks/static/ImutbF0YDoWldOxrPilcwQFHnSe.png new file mode 100644 index 000000000..32ab59bd3 Binary files /dev/null and b/docs/fr-FR/manual/ui/blocks/static/ImutbF0YDoWldOxrPilcwQFHnSe.png differ diff --git a/docs/fr-FR/manual/ui/blocks/static/JNiLb7rksoY07ox092ycaarenGd.png b/docs/fr-FR/manual/ui/blocks/static/JNiLb7rksoY07ox092ycaarenGd.png new file mode 100644 index 000000000..d5b5018b2 Binary files /dev/null and b/docs/fr-FR/manual/ui/blocks/static/JNiLb7rksoY07ox092ycaarenGd.png differ diff --git a/docs/fr-FR/manual/ui/blocks/static/L0aJb1V9DoETnNxrr1gcz0g0nDb.png b/docs/fr-FR/manual/ui/blocks/static/L0aJb1V9DoETnNxrr1gcz0g0nDb.png new file mode 100644 index 000000000..cc7603c71 Binary files /dev/null and b/docs/fr-FR/manual/ui/blocks/static/L0aJb1V9DoETnNxrr1gcz0g0nDb.png differ diff --git a/docs/fr-FR/manual/ui/blocks/static/OpBcbf9UlooZ5UxZDwwcHZi8nWf.png b/docs/fr-FR/manual/ui/blocks/static/OpBcbf9UlooZ5UxZDwwcHZi8nWf.png new file mode 100644 index 000000000..717d3ea48 Binary files /dev/null and b/docs/fr-FR/manual/ui/blocks/static/OpBcbf9UlooZ5UxZDwwcHZi8nWf.png differ diff --git a/docs/fr-FR/manual/ui/blocks/static/PSD8bf1fzoZkIUxJW7lc4XuGnee.png b/docs/fr-FR/manual/ui/blocks/static/PSD8bf1fzoZkIUxJW7lc4XuGnee.png new file mode 100644 index 000000000..b8aeaf4f3 Binary files /dev/null and b/docs/fr-FR/manual/ui/blocks/static/PSD8bf1fzoZkIUxJW7lc4XuGnee.png differ diff --git a/docs/fr-FR/manual/ui/blocks/static/Tvjfb4qr4osyzxxPKdRcfn1knsd.png b/docs/fr-FR/manual/ui/blocks/static/Tvjfb4qr4osyzxxPKdRcfn1knsd.png new file mode 100644 index 000000000..77c986e9d Binary files /dev/null and b/docs/fr-FR/manual/ui/blocks/static/Tvjfb4qr4osyzxxPKdRcfn1knsd.png differ diff --git a/docs/fr-FR/manual/ui/blocks/static/Uo6ubaMwFo5bi1xVMU5cshlTn1g.png b/docs/fr-FR/manual/ui/blocks/static/Uo6ubaMwFo5bi1xVMU5cshlTn1g.png new file mode 100644 index 000000000..4abc2a9a8 Binary files /dev/null and b/docs/fr-FR/manual/ui/blocks/static/Uo6ubaMwFo5bi1xVMU5cshlTn1g.png differ diff --git a/docs/fr-FR/manual/ui/blocks/static/XjdHbvC9ZotdQAx8GJoczwoancc.gif b/docs/fr-FR/manual/ui/blocks/static/XjdHbvC9ZotdQAx8GJoczwoancc.gif new file mode 100644 index 000000000..a43b0c671 Binary files /dev/null and b/docs/fr-FR/manual/ui/blocks/static/XjdHbvC9ZotdQAx8GJoczwoancc.gif differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/cascade-select/index.md b/docs/fr-FR/manual/ui/fields/association-components/cascade-select/index.md new file mode 100644 index 000000000..fd9543531 --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/cascade-select/index.md @@ -0,0 +1,15 @@ +# 级联选择器 + +级联选择器用于关系字段目标表为**树表**时,提供的便捷的数据选择方式。按照树表数据的层次结构选择相关数据项。支持子数据的搜索过滤 + +如任务管理应用模型中,任务表中有关系字段「部门」(多对多),「项目」(多对一),部门表和项目表均为树表 + +- 关系为对一,级联为单选 + +![](https://static-docs.nocobase.com/3f8ad42c318ebf6b6c1367da33f4e235.png) + +- 关系为对多,级联为多选,支持拖拽排序 + +![](https://static-docs.nocobase.com/2a4f58986712b073d69a33f17f1d44fc.png) + +![](https://static-docs.nocobase.com/02fec13f436d55108a7328a0716cdfde.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/fields/association-components/cascade-select/static/GjqEbeQ8IoFUFtxeS8cc16Fjnac.png b/docs/fr-FR/manual/ui/fields/association-components/cascade-select/static/GjqEbeQ8IoFUFtxeS8cc16Fjnac.png new file mode 100644 index 000000000..73cce55c6 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/cascade-select/static/GjqEbeQ8IoFUFtxeS8cc16Fjnac.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/cascade-select/static/OHftb05waogIjzxjUgNcfUIan8f.png b/docs/fr-FR/manual/ui/fields/association-components/cascade-select/static/OHftb05waogIjzxjUgNcfUIan8f.png new file mode 100644 index 000000000..118bff0fc Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/cascade-select/static/OHftb05waogIjzxjUgNcfUIan8f.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/cascade-select/static/ZOtzbc1BOoailOxdK41cnJvvnjd.png b/docs/fr-FR/manual/ui/fields/association-components/cascade-select/static/ZOtzbc1BOoailOxdK41cnJvvnjd.png new file mode 100644 index 000000000..7a435aa0f Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/cascade-select/static/ZOtzbc1BOoailOxdK41cnJvvnjd.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/file-manager/index.md b/docs/fr-FR/manual/ui/fields/association-components/file-manager/index.md new file mode 100644 index 000000000..9dcbfbd37 --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/file-manager/index.md @@ -0,0 +1,12 @@ +# 文件管理器 + +文件管理器是专门用于处理关系目标表为文件表的关系字段组件。 + +如在任务管理应用模型中,任务表中有关系字段「附件」(一对一),当关系字段的目标表为文件表时,默认字段组件为文件管理器 + +![](https://static-docs.nocobase.com/96c15ff2a8b13797a6c7b675f2a5ad7a.png) + +可以通过文件管理器组件来管理与当前任务关联的附件文件。 + +- 通过上传按钮将新文件上传添加后关联(快速上传) +- 点击选择从已有的附件列表中选择要关联的附件(选择文件 ) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/fields/association-components/file-manager/static/PmuLburnvoPOwfxXOcNcFYxdnId.png b/docs/fr-FR/manual/ui/fields/association-components/file-manager/static/PmuLburnvoPOwfxXOcNcFYxdnId.png new file mode 100644 index 000000000..263ba3189 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/file-manager/static/PmuLburnvoPOwfxXOcNcFYxdnId.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/index.md b/docs/fr-FR/manual/ui/fields/association-components/index.md new file mode 100644 index 000000000..a91de2307 --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/index.md @@ -0,0 +1,17 @@ +# 关系字段组件 + +NocoBase 的关系字段组件旨在帮助用户更好地展示和处理关联数据。无论关系类型如何,这些组件具有灵活性和通用性,用户能够根据具体需求选择并配置这些组件。 + +#### 使用总结 + +1. 下拉选择器:用于从一个下拉列表中**选择或新建**一个或多个选项。**适用于所有关系类型**,支持设置下拉列表的标题字段。 +2. 数据选择器:用于从相关数据中**选择或新建**一个或多个选项。**适用于所有关系类型**。配置和使用时,可以配置选择器列表的展示信息 +3. 级联选择器:用于目标表为**树表**的关系数据,按树形结构一层一层的往下选取数据。 +4. 子表单/子详情:用于在当前表单或详情页面中展示关联记录的数据。它提供了一种便捷的嵌套方式来查看和编辑关联数据的详细信息,无需跳转到其他页面,提供了更流畅和高效的用户体验,**适用于所有关系类型,**多层的关系数据能以嵌套的形式展示,配置使用时注意布局的调整 +5. 子表格:编辑状态下子表格支持直接**新建/编辑**关系数据,**适用于一对多或多对多的关系类型**,暂不支持选择关联。 +6. 子表单(弹窗):通过将次要或复杂数据字段放在弹窗中,优化了主表单的布局,使界面更简洁、直观。解决了复杂关系层级下表单的冗长问题,提升用户体验。适用于有大量数据字段、关系层级复杂的场景,将次要信息与主要信息分开填写,提高表单的可用性。 +7. 标签:通过为关系字段配置标签组件,实现了数据的分类和标识,能够更直观地展示数据关系,适用于需要将数据按照类别进行分组的场景 +8. 文件管理器:用于直接**上传或选择**与当前记录关联的文件。**适用于目标表为文件表的关系类型**。 +9. 标题:用于在阅读模式下显示关联记录,是所有关系字段阅读状态下的默认字段组件。**适用于所有关系类型**。配置和使用时,默认标题字段为 id,支持自定义设置标题字段。 + +通过使用这些字段组件,可以定制和优化数据展示和操作的界面,提供更好的用户体验。根据具体的业务需求和关系类型,选择合适的字段组件。更多关系字段的功能可在系统中体验并提出反馈。 diff --git a/docs/fr-FR/manual/ui/fields/association-components/record-picker/index.md b/docs/fr-FR/manual/ui/fields/association-components/record-picker/index.md new file mode 100644 index 000000000..ab332186e --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/record-picker/index.md @@ -0,0 +1,15 @@ +# 数据选择器 + +数据选择器用于从相关数据中选择一个或多个选项。它与下拉选择器类似,但提供了更大的灵活性和功能,使用户能够更精确地选择关联数据,可以在数据选择器中配置更多关联信息字段(关系的关系数据),方便用户精准选择数据。 + +- 通过数据选择器选择关联数据 + +![](https://static-docs.nocobase.com/4e21501fb12e3a44405988d2d33e7bd4.png) + +数据选择器以弹窗形式展示关系数据,在表格区块中可以配置更多目标表字段 + +![](https://static-docs.nocobase.com/c4724501b0ad2d5d683782236de13b9d.png) + +- 通过数据选择器,不仅可以选择关联数据,还可对关系目标表进一步管理(新增、删除、导入导出等) + +![](https://static-docs.nocobase.com/ca460a7aa9f0c7ca3bca28cc287979a3.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/fields/association-components/record-picker/static/DVSobGGxuoBncUxwz7Oc6MJfn5C.png b/docs/fr-FR/manual/ui/fields/association-components/record-picker/static/DVSobGGxuoBncUxwz7Oc6MJfn5C.png new file mode 100644 index 000000000..6b7ec4a33 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/record-picker/static/DVSobGGxuoBncUxwz7Oc6MJfn5C.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/record-picker/static/UyHLbOe4YoH5sBxTPFJcBhrxnme.png b/docs/fr-FR/manual/ui/fields/association-components/record-picker/static/UyHLbOe4YoH5sBxTPFJcBhrxnme.png new file mode 100644 index 000000000..b977b8084 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/record-picker/static/UyHLbOe4YoH5sBxTPFJcBhrxnme.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/record-picker/static/VEhzbnCSfooc1jxDr7EcGV4enaf.png b/docs/fr-FR/manual/ui/fields/association-components/record-picker/static/VEhzbnCSfooc1jxDr7EcGV4enaf.png new file mode 100644 index 000000000..4fe56c341 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/record-picker/static/VEhzbnCSfooc1jxDr7EcGV4enaf.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/select/index.md b/docs/fr-FR/manual/ui/fields/association-components/select/index.md new file mode 100644 index 000000000..fd5292100 --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/select/index.md @@ -0,0 +1,27 @@ +# 下拉选择器 + +下拉选择器是关系字段组件的常用组件,除了目标表为文件表的所有关系字段,编辑状态下的默认组件均为下拉选择器,支持从目标表选择已有数据关联或添加新数据后关联。 + +如图在任务管理应用中,任务表有关系字段「负责人」(多对一) + +- 选择关联数据,从目标表的已有数据中选择关联 + +![](https://static-docs.nocobase.com/3b6cca8f0ffefbae76cab9260e3cf991.png) + +- 新增数据后关联 + +直接为目标表新建数据后进行关联,目前有两种新建方式(下拉菜单/弹窗添加) + +下拉菜单添加,创建成功后自动选中创建的数据,需要配置标题字段 + +![](https://static-docs.nocobase.com/67de33d271534826d756593d03d30d7b.png) + +示例如下 + +![](https://static-docs.nocobase.com/697202774f114f60888ed56ba97ae04a.gif) + +弹窗添加:创建成功后会自动选中创建的数据 + +![](https://static-docs.nocobase.com/af5c283ae21e794bf310e9851fef6211.gif) + +在很多场景中,希望通过关系选择器带出关联数据,而下拉选择器只能带出目标表中的简单字段,关系的关系数据则要通过配置数据选择器来带出 \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/fields/association-components/select/static/AWz1bGNV3oTl8UxyXbNcFRXsnDe.png b/docs/fr-FR/manual/ui/fields/association-components/select/static/AWz1bGNV3oTl8UxyXbNcFRXsnDe.png new file mode 100644 index 000000000..d29c261ff Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/select/static/AWz1bGNV3oTl8UxyXbNcFRXsnDe.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/select/static/CZYAbOp1Ho6HxYxwxuyclVDxnBf.gif b/docs/fr-FR/manual/ui/fields/association-components/select/static/CZYAbOp1Ho6HxYxwxuyclVDxnBf.gif new file mode 100644 index 000000000..083904783 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/select/static/CZYAbOp1Ho6HxYxwxuyclVDxnBf.gif differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/select/static/DbUxbR6jFoJ1jWx2BVYc2WkFnQh.gif b/docs/fr-FR/manual/ui/fields/association-components/select/static/DbUxbR6jFoJ1jWx2BVYc2WkFnQh.gif new file mode 100644 index 000000000..601b792dc Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/select/static/DbUxbR6jFoJ1jWx2BVYc2WkFnQh.gif differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/select/static/ZIOdbT8nGoNAqZxqsmAcbAITnAg.png b/docs/fr-FR/manual/ui/fields/association-components/select/static/ZIOdbT8nGoNAqZxqsmAcbAITnAg.png new file mode 100644 index 000000000..7e71a0482 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/select/static/ZIOdbT8nGoNAqZxqsmAcbAITnAg.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-detail/index.md b/docs/fr-FR/manual/ui/fields/association-components/sub-detail/index.md new file mode 100644 index 000000000..11893262e --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/sub-detail/index.md @@ -0,0 +1,5 @@ +# 子详情 + +子详情是子表单在阅读模式下的对应组件,支持多层关系数据嵌套展示 + +![](https://static-docs.nocobase.com/0e7b58c1eebb646530d77d9700b28dcf.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-detail/static/TI2Mbl7dDotd9BxJt6ucXr2OnPc.png b/docs/fr-FR/manual/ui/fields/association-components/sub-detail/static/TI2Mbl7dDotd9BxJt6ucXr2OnPc.png new file mode 100644 index 000000000..555e707db Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-detail/static/TI2Mbl7dDotd9BxJt6ucXr2OnPc.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/index.md b/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/index.md new file mode 100644 index 000000000..ae3a68ec5 --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/index.md @@ -0,0 +1,17 @@ +# 子表单(弹窗) + +子表单(弹窗)是一种用于优化复杂数据输入场景的关系字段组件。在面对关系层级复杂、数据字段众多的情况下,子表单布局可能显得冗长且杂乱,难以有效呈现数据的主次关系。将某些非关键性或不常用的数据字段从主表单中移至独立的弹窗中进行填写,主表单能够更专注地展示最重要的信息,而子表单则用于收纳次要信息或需要复杂关联的数据。用户可以更有针对性地输入相关信息,而无需被主表单的冗长所困扰。 + +子表单(弹窗)不仅简化了表单布局,同时也有效地解决了子表格中关系字段无法直接填写数据的问题。 + +![](https://static-docs.nocobase.com/a386b9333964279e1234e05e53df57ed.gif) + +- 配置标题字段可控制对外的显示字段 + +![](https://static-docs.nocobase.com/e899ff37d80f70c254052441bf7446df.png) + +- 子表格中的关系字段也可以使用子表单(弹窗)填写关系数据 + +![](https://static-docs.nocobase.com/531504bdf10c107cdbc9def08cdccf0c.gif) + +子表单(弹窗)内部也支持多层关系字段的配置,可根据实际情况配置。 \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/static/NEQRbYpxSoy3AyxgiC5cWOSRnFd.png b/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/static/NEQRbYpxSoy3AyxgiC5cWOSRnFd.png new file mode 100644 index 000000000..42199cafd Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/static/NEQRbYpxSoy3AyxgiC5cWOSRnFd.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/static/UTzwbpNczoCK0kxtFPhcGYoKneb.gif b/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/static/UTzwbpNczoCK0kxtFPhcGYoKneb.gif new file mode 100644 index 000000000..05b4dc015 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/static/UTzwbpNczoCK0kxtFPhcGYoKneb.gif differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/static/ZHqsbWKTYoMjZ4xX0rKc5ff2ndk.gif b/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/static/ZHqsbWKTYoMjZ4xX0rKc5ff2ndk.gif new file mode 100644 index 000000000..f0b28ba90 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-form(popover)/static/ZHqsbWKTYoMjZ4xX0rKc5ff2ndk.gif differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-form/index.md b/docs/fr-FR/manual/ui/fields/association-components/sub-form/index.md new file mode 100644 index 000000000..d58f348ce --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/sub-form/index.md @@ -0,0 +1,11 @@ +# 子表单 + +若想处理层级较深的关系数据,通过 select 和数据选择器都不太方便,需要打开弹窗操作,点击次数太多,很繁琐;而子表单就是为了优化这种场景,使用户能够在当前页面上直接维护关联的信息,多层关系以嵌套表单的形式展示 + +支持多层关系字段的嵌套显示 + +![](https://static-docs.nocobase.com/966964d3f3ade50d9af03baed79247cf.png) + +可以配置是否显示标题和调整布局 + +![](https://static-docs.nocobase.com/6b375a39b4b1cba4033f92736c3676f3.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-form/static/U7DXb1zmYo7MOLxASIaciyk6nUc.png b/docs/fr-FR/manual/ui/fields/association-components/sub-form/static/U7DXb1zmYo7MOLxASIaciyk6nUc.png new file mode 100644 index 000000000..08ff68697 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-form/static/U7DXb1zmYo7MOLxASIaciyk6nUc.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-form/static/W0KVbjO2Qo7vDwxHlwpcj6ionhf.png b/docs/fr-FR/manual/ui/fields/association-components/sub-form/static/W0KVbjO2Qo7vDwxHlwpcj6ionhf.png new file mode 100644 index 000000000..b2cfe4b5f Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-form/static/W0KVbjO2Qo7vDwxHlwpcj6ionhf.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-table/index.md b/docs/fr-FR/manual/ui/fields/association-components/sub-table/index.md new file mode 100644 index 000000000..4486ed764 --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/sub-table/index.md @@ -0,0 +1,23 @@ +# 子表格 + +子表格以表格形式展示**一对多或多对多**关系记录。它提供了一种清晰、结构化的方式来展示和管理关联数据,每一行代表一个关联记录,每列代表关联记录的不同字段。 + +![](https://static-docs.nocobase.com/b727c98fea5ca42b2e040aca2ab835f7.png) + +在任务管理应用模型中,任务表中有关系字段「审批纪录」(一对多)。 + +1. 编辑下的子表格 + +![](https://static-docs.nocobase.com/e8bb178a3e6f284823638b6aa150ea0a.png) + +子表格中字段会根据不同字段类型展示不同组件,而大字段(富文本,Json,多行文本等字段)则通过悬浮弹窗编辑 + +![](https://static-docs.nocobase.com/64abfb139e4f00d4bd093f33d57a6849.png) + +子表格中关系字段默认组件是下拉选择器(可调整为数据选择器/子表单(弹窗)) + +![](https://static-docs.nocobase.com/6a6094b3b66cc87f1efc65266fbbb176.png) + +1. 详情下的子表格 + +![](https://static-docs.nocobase.com/9ca7b2a0e2e9d919db668cbf3224eb41.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/AwLMboMECoBBmIxBHcmcuT9xnAe.png b/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/AwLMboMECoBBmIxBHcmcuT9xnAe.png new file mode 100644 index 000000000..31bc5d458 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/AwLMboMECoBBmIxBHcmcuT9xnAe.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/GgBUbe5ZIoT7ojxqV4Pcwz8gn5g.png b/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/GgBUbe5ZIoT7ojxqV4Pcwz8gn5g.png new file mode 100644 index 000000000..79c039e56 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/GgBUbe5ZIoT7ojxqV4Pcwz8gn5g.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/QDq8b1umdokplcxVwjFcmvecntb.png b/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/QDq8b1umdokplcxVwjFcmvecntb.png new file mode 100644 index 000000000..ca86bddcc Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/QDq8b1umdokplcxVwjFcmvecntb.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/WJ45buLjoohisGx7uX2cBOJpnrg.png b/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/WJ45buLjoohisGx7uX2cBOJpnrg.png new file mode 100644 index 000000000..d5fd2d7d7 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/WJ45buLjoohisGx7uX2cBOJpnrg.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/YGLGbcWiJo6tHcxY7jrcfKumnSh.png b/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/YGLGbcWiJo6tHcxY7jrcfKumnSh.png new file mode 100644 index 000000000..1ba6bc59e Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/sub-table/static/YGLGbcWiJo6tHcxY7jrcfKumnSh.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/summary/index.md b/docs/fr-FR/manual/ui/fields/association-components/summary/index.md new file mode 100644 index 000000000..a91de2307 --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/summary/index.md @@ -0,0 +1,17 @@ +# 关系字段组件 + +NocoBase 的关系字段组件旨在帮助用户更好地展示和处理关联数据。无论关系类型如何,这些组件具有灵活性和通用性,用户能够根据具体需求选择并配置这些组件。 + +#### 使用总结 + +1. 下拉选择器:用于从一个下拉列表中**选择或新建**一个或多个选项。**适用于所有关系类型**,支持设置下拉列表的标题字段。 +2. 数据选择器:用于从相关数据中**选择或新建**一个或多个选项。**适用于所有关系类型**。配置和使用时,可以配置选择器列表的展示信息 +3. 级联选择器:用于目标表为**树表**的关系数据,按树形结构一层一层的往下选取数据。 +4. 子表单/子详情:用于在当前表单或详情页面中展示关联记录的数据。它提供了一种便捷的嵌套方式来查看和编辑关联数据的详细信息,无需跳转到其他页面,提供了更流畅和高效的用户体验,**适用于所有关系类型,**多层的关系数据能以嵌套的形式展示,配置使用时注意布局的调整 +5. 子表格:编辑状态下子表格支持直接**新建/编辑**关系数据,**适用于一对多或多对多的关系类型**,暂不支持选择关联。 +6. 子表单(弹窗):通过将次要或复杂数据字段放在弹窗中,优化了主表单的布局,使界面更简洁、直观。解决了复杂关系层级下表单的冗长问题,提升用户体验。适用于有大量数据字段、关系层级复杂的场景,将次要信息与主要信息分开填写,提高表单的可用性。 +7. 标签:通过为关系字段配置标签组件,实现了数据的分类和标识,能够更直观地展示数据关系,适用于需要将数据按照类别进行分组的场景 +8. 文件管理器:用于直接**上传或选择**与当前记录关联的文件。**适用于目标表为文件表的关系类型**。 +9. 标题:用于在阅读模式下显示关联记录,是所有关系字段阅读状态下的默认字段组件。**适用于所有关系类型**。配置和使用时,默认标题字段为 id,支持自定义设置标题字段。 + +通过使用这些字段组件,可以定制和优化数据展示和操作的界面,提供更好的用户体验。根据具体的业务需求和关系类型,选择合适的字段组件。更多关系字段的功能可在系统中体验并提出反馈。 diff --git a/docs/fr-FR/manual/ui/fields/association-components/tag/index.md b/docs/fr-FR/manual/ui/fields/association-components/tag/index.md new file mode 100644 index 000000000..23c529e7d --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/tag/index.md @@ -0,0 +1,9 @@ +# 标签 + +标签是用来在数据展示中更好地分类和标识关系信息的组件。让用户更轻松地识别不同类别的数据,提升浏览效率和数据理解。 在任务管理应用模型中,任务表中有关系字段「任务进度」(一对多) + +- 需要配置标签的颜色字段(从目标表中选择) + +![](https://static-docs.nocobase.com/7f436d6de401aaa13f1d8a876aedac07.png) + +![](https://static-docs.nocobase.com/3f62febe926d5650a587b979a5db8f8f.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/fields/association-components/tag/static/HC7jbnrqNo9vXexyLXecSA30nqd.png b/docs/fr-FR/manual/ui/fields/association-components/tag/static/HC7jbnrqNo9vXexyLXecSA30nqd.png new file mode 100644 index 000000000..b9e823671 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/tag/static/HC7jbnrqNo9vXexyLXecSA30nqd.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/tag/static/HPzlbp2WooC0gix1FUWcmZVfnBf.png b/docs/fr-FR/manual/ui/fields/association-components/tag/static/HPzlbp2WooC0gix1FUWcmZVfnBf.png new file mode 100644 index 000000000..6233b6f63 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/tag/static/HPzlbp2WooC0gix1FUWcmZVfnBf.png differ diff --git a/docs/fr-FR/manual/ui/fields/association-components/title/index.md b/docs/fr-FR/manual/ui/fields/association-components/title/index.md new file mode 100644 index 000000000..c9fdacc9e --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/association-components/title/index.md @@ -0,0 +1,5 @@ +# 标题 + +标题组件是阅读模式下提供的一种清晰明了的方式来显示与当前记录关联的关键信息,详情状态下关系字段的默认组件均为标题,默认标题字段为 id,支持自定义标题字段。 + +![](https://static-docs.nocobase.com/f669435871fe9465680a9200d81d925f.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/fields/association-components/title/static/H97TbGjbwonXIPxctydchPdSnud.png b/docs/fr-FR/manual/ui/fields/association-components/title/static/H97TbGjbwonXIPxctydchPdSnud.png new file mode 100644 index 000000000..cbcb8e240 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/association-components/title/static/H97TbGjbwonXIPxctydchPdSnud.png differ diff --git a/docs/fr-FR/manual/ui/fields/index.md b/docs/fr-FR/manual/ui/fields/index.md new file mode 100644 index 000000000..0b76311a4 --- /dev/null +++ b/docs/fr-FR/manual/ui/fields/index.md @@ -0,0 +1,67 @@ +# Overview + +在 UI 里,字段即字段组件,是单元数据的载体,不同类型数据以不同字段组件呈现。字段只能附属于区块,不能独立使用。 + +## 区块里的字段 + +字段一般不单独使用,而是作为数据类型区块的子元素存在。数据类型的区块通常都有「配置字段」,字段列表由当前数据表提供。 + +![](https://static-docs.nocobase.com/c5ea18ad1847332fe78075413f23de46.png) + +## 字段的设计器(工具栏) + +和区块一样,字段组件的右上角也有三个图标,分别为: + +- 拖拽布局 +- 快捷添加字段 +- 字段参数配置 + +![](https://static-docs.nocobase.com/30cc5fcaeeb171862f79449a72a7fcf9.png) + +## 字段的布局 + +通过拖拽移动可以自定义调整字段在区块中的布局 + +![](https://static-docs.nocobase.com/0825ea8c014c9073f505e74f707ded66.gif) + +## 通用的参数配置 + +- 编辑字段标题 +- 显示标题 +- 编辑描述 +- 必填 +- 验证规则 +- 默认值 +- 显示模式 + +![](https://static-docs.nocobase.com/cbb838c9e167f51636d6a0ad3b287b59.png) + +重要参数配置说明: + +### 验证规则 + +待补充 + +### 默认值 + +待补充 + +### 显示模式 + +和区块不同的是字段组件有三种显示模式: + +- 可编辑 - editable +- 只读(不可编辑)- readonly +- 只读(阅读模式)- read friendly + +### 字段组件 + +部分字段支持切换为其他组件,例如:`URL` 组件可以切换为 `Preview` 组件。 + +![20240806164801](https://static-docs.nocobase.com/20240806164801.png) + +如果你需要扩展更多的组件,可以参考 [扩展有值字段组件组件](/plugin-samples/field/value)。 + +## 字段的类型 + +区块的字段由数据表提供,更多字段类型的配置参考 [数据表字段类型](https://nocobase.feishu.cn/wiki/BJKYw1xpHiVxFHkmgT3cKrKznkd) diff --git a/docs/fr-FR/manual/ui/fields/static/BpmibJbEgoijTgxHkqdcjodanVc.gif b/docs/fr-FR/manual/ui/fields/static/BpmibJbEgoijTgxHkqdcjodanVc.gif new file mode 100644 index 000000000..3205df33b Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/static/BpmibJbEgoijTgxHkqdcjodanVc.gif differ diff --git a/docs/fr-FR/manual/ui/fields/static/MIcrb5RbUoGYoZxWazPcGMWInjc.png b/docs/fr-FR/manual/ui/fields/static/MIcrb5RbUoGYoZxWazPcGMWInjc.png new file mode 100644 index 000000000..270657578 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/static/MIcrb5RbUoGYoZxWazPcGMWInjc.png differ diff --git a/docs/fr-FR/manual/ui/fields/static/P82Kbwh5moSEL5x5UeYcn6kIn3Y.png b/docs/fr-FR/manual/ui/fields/static/P82Kbwh5moSEL5x5UeYcn6kIn3Y.png new file mode 100644 index 000000000..2f16eb6e6 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/static/P82Kbwh5moSEL5x5UeYcn6kIn3Y.png differ diff --git a/docs/fr-FR/manual/ui/fields/static/WBkubBX4QoUQ3HxPUHPcht2VnnK.png b/docs/fr-FR/manual/ui/fields/static/WBkubBX4QoUQ3HxPUHPcht2VnnK.png new file mode 100644 index 000000000..abb66a1a3 Binary files /dev/null and b/docs/fr-FR/manual/ui/fields/static/WBkubBX4QoUQ3HxPUHPcht2VnnK.png differ diff --git a/docs/fr-FR/manual/ui/index.md b/docs/fr-FR/manual/ui/index.md new file mode 100644 index 000000000..d145abd6d --- /dev/null +++ b/docs/fr-FR/manual/ui/index.md @@ -0,0 +1,45 @@ +# UI Editor + +## What you see is what you get + +NocoBase utilizes a WYSIWYG interface configuration mode. You can switch between configuration mode and usage mode by clicking the UI Editor button. + +![2024-01-20_11-42-20](https://static-docs.nocobase.com/2024-01-20_11-42-20.jpg) + +Usage Mode: + +![2024-01-20_11-28-46](https://static-docs.nocobase.com/2024-01-20_11-28-46.jpg) + +Configuration mode: + +![2024-01-20_11-29-50](https://static-docs.nocobase.com/2024-01-20_11-29-50.jpg) + +## Layout Templates + +NocoBase has a built-in layout template, with the navigation area on the top and left, and the content area on the right. + +![2024-01-20_11-36-38](https://static-docs.nocobase.com/2024-01-20_11-36-38.jpg) + +## Configuration items + +Once you enter the UI Editor mode, orange configurable items will appear on the interface. Typically, the configuration item entry for each configurable element is located in the upper right corner of the element. Almost all elements can be configured and viewed in effect in real time on the interface, here are a few examples: + +Configurable items for menu items: + +![2024-01-20_11-30-29](https://static-docs.nocobase.com/2024-01-20_11-30-29.jpg) + +Configuration item for pages: + +![2024-01-20_11-30-52](https://static-docs.nocobase.com/2024-01-20_11-30-52.jpg) + +Configuration items for blocks: + +![2024-01-20_11-31-20](https://static-docs.nocobase.com/2024-01-20_11-31-20.jpg) + +Configuration item for actions: + +![2024-01-20_11-31-50](https://static-docs.nocobase.com/2024-01-20_11-31-50.jpg) + +Configuration items for table columns: + +![2024-01-20_11-32-08](https://static-docs.nocobase.com/2024-01-20_11-32-08.jpg) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/inherit.md b/docs/fr-FR/manual/ui/inherit.md new file mode 100644 index 000000000..85947525e --- /dev/null +++ b/docs/fr-FR/manual/ui/inherit.md @@ -0,0 +1,47 @@ +# 继承 + +## 配置字段包括继承的父表字段 + +子表在区块中使用时除了本表字段还有所有父表的字段供配置 + +![](https://static-docs.nocobase.com/33921f1e2367b3b4edac9450d2c1fef2.png) + +## 添加操作可以启用子表 + +父表配置 TableOID(记录是由哪个表创建的数据) + +![](https://static-docs.nocobase.com/9bfaa4d261fd482e2473469a2f4c3250.png) + +![](https://static-docs.nocobase.com/ce4d4ca099600e4a38058369a6dc38c7.gif) + +子表的数据汇聚在父表中 + +![](https://static-docs.nocobase.com/fc4b50175aa9b7b7404895f636db8d8f.gif) + +在父表中为子表配置添加操作 + +![](https://static-docs.nocobase.com/81ab8e1d14a0d84620e4a0b214edef5a.gif) + +可选项为当前表的所有子表 + +![](https://static-docs.nocobase.com/c5944d8b2ac4dd5b938bf31667d34516.png) + +## 继承表数据的查看与编辑(按 \_\_collection 显示) + +UI 配置状态下可以为子表配置区块(表单/详情区块) + +![](https://static-docs.nocobase.com/fbadc32ae1931c711707ad5bd9a6c603.png) + +非 UI 配置状态下,按 \_\_collection 只显示对应数据表记录的区块 + +![](https://static-docs.nocobase.com/07dc8529f7b33deb0e4aaf1a004be213.gif) + +## 关系数据的弹窗(按 \_\_collection 显示) + +关系数据的详情在非 UI 配置状态下按 \_\_collection 仅显示对应数据的区块 + +![](https://static-docs.nocobase.com/101753398b9fd5a1013fcee833cbeec0.gif) + +## 继承下的筛选联动 + +B 可以连接 A,B 的子表 B1 也可以连接 A \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/linkage.md b/docs/fr-FR/manual/ui/linkage.md new file mode 100644 index 000000000..a62d3e8aa --- /dev/null +++ b/docs/fr-FR/manual/ui/linkage.md @@ -0,0 +1 @@ +# Linkage rules \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/menus/index.md b/docs/fr-FR/manual/ui/menus/index.md new file mode 100644 index 000000000..c2898929e --- /dev/null +++ b/docs/fr-FR/manual/ui/menus/index.md @@ -0,0 +1,51 @@ +# Menus + +Menus are used to organize pages and external links. In NocoBase's default page layout template, menus are located on the top and left side. In this case, the top side is the first level menu, and the left side is the second level and infinite levels of submenus. + +## Menu Item Types + +NocoBase has three built-in menu item types: + +- Group +- Page +- Link + +![](https://static-docs.nocobase.com/ccf6f42d3cc2677d440f9e33b9488d1c.png) + +### Group + +"Group" is used to group menu items, which can be on the top or left side. Within a group, you can continue to create groups, i.e. the menu can be infinitely hierarchical. + +![](https://static-docs.nocobase.com/e59b2088fd68666cd240a26566616a3e.png) + +### Page + +Page can be used as container for blocks, holding a wide variety of blocks. (See [pages and popups](. /pages/index.md) ) + +![](https://static-docs.nocobase.com/4cd259f6b79f6792df72ccc291da2af9.png) + +### Link + +Can be used to jump to third-party URLs + +![](https://static-docs.nocobase.com/80a6e6a875c565425224d9325332a1ad.png) + +## Configure Menu + +Once you switch into UI Editor mode, there are two icons in the upper right corner of the menu item: + +- Drag and drop to move +- Menu Item Configuration + +![](https://static-docs.nocobase.com/963ba10e36d04fd258fea0e996231f68.png) + +### Menu Item Configuration + +![](https://static-docs.nocobase.com/0a9a05bd88d8bad9d711102a730f351d.png) + +- Edit: includes menu item title, icon, etc. +- Move to: besides drag and drop move, you can also move the menu item quickly by "Move to", you can move the menu item in front of, behind or inside of other menu items. +- Insert before +- Insert after +- Insert inner (group type only) +- Delete \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/menus/static/Jp3NbdeVBojspWxvcWhcuDTlnOe.png b/docs/fr-FR/manual/ui/menus/static/Jp3NbdeVBojspWxvcWhcuDTlnOe.png new file mode 100644 index 000000000..a2751410c Binary files /dev/null and b/docs/fr-FR/manual/ui/menus/static/Jp3NbdeVBojspWxvcWhcuDTlnOe.png differ diff --git a/docs/fr-FR/manual/ui/menus/static/LTdGbCxxHopt9ix1Nuncj73VnQb.png b/docs/fr-FR/manual/ui/menus/static/LTdGbCxxHopt9ix1Nuncj73VnQb.png new file mode 100644 index 000000000..f686eb3de Binary files /dev/null and b/docs/fr-FR/manual/ui/menus/static/LTdGbCxxHopt9ix1Nuncj73VnQb.png differ diff --git a/docs/fr-FR/manual/ui/menus/static/OpdHbIbJ8oZX75x777ycylHxn1Q.png b/docs/fr-FR/manual/ui/menus/static/OpdHbIbJ8oZX75x777ycylHxn1Q.png new file mode 100644 index 000000000..4a609a506 Binary files /dev/null and b/docs/fr-FR/manual/ui/menus/static/OpdHbIbJ8oZX75x777ycylHxn1Q.png differ diff --git a/docs/fr-FR/manual/ui/menus/static/SYzbbocHfoNFtsxomWJcUno7nog.png b/docs/fr-FR/manual/ui/menus/static/SYzbbocHfoNFtsxomWJcUno7nog.png new file mode 100644 index 000000000..dc01db58a Binary files /dev/null and b/docs/fr-FR/manual/ui/menus/static/SYzbbocHfoNFtsxomWJcUno7nog.png differ diff --git a/docs/fr-FR/manual/ui/menus/static/T0LTbjTBEo24UaxU9Btc6xgbnMf.png b/docs/fr-FR/manual/ui/menus/static/T0LTbjTBEo24UaxU9Btc6xgbnMf.png new file mode 100644 index 000000000..197266e57 Binary files /dev/null and b/docs/fr-FR/manual/ui/menus/static/T0LTbjTBEo24UaxU9Btc6xgbnMf.png differ diff --git a/docs/fr-FR/manual/ui/menus/static/ZLYibDXwToMdqRxMTy4cyTion1f.png b/docs/fr-FR/manual/ui/menus/static/ZLYibDXwToMdqRxMTy4cyTion1f.png new file mode 100644 index 000000000..a89a582a6 Binary files /dev/null and b/docs/fr-FR/manual/ui/menus/static/ZLYibDXwToMdqRxMTy4cyTion1f.png differ diff --git a/docs/fr-FR/manual/ui/pages/index.md b/docs/fr-FR/manual/ui/pages/index.md new file mode 100644 index 000000000..77303f23b --- /dev/null +++ b/docs/fr-FR/manual/ui/pages/index.md @@ -0,0 +1,53 @@ +# Page & pupup + +NocoBase's pages and popups (dialog, drawer) can be used as containers for blocks; they are like a canvas on which various blocks can be freely placed. + +## Pages +After creating a page by [menu](. /menus/index.md) , you can see that an empty page consists of the following two parts: +1. header + 1. page title + 2. tab +2. block container + +![2024-01-20_08-23-10](https://static-docs.nocobase.com/2024-01-20_08-23-10.jpg) + +Hover your mouse over the configuration item icon at the top right of the page to see the page configuration item: + +![2024-01-20_08-24-27](https://static-docs.nocobase.com/2024-01-20_08-24-27.jpg) + +Configurable items include: +- Enable page header: used to control whether to display the header or not; +- Display page title: whether to show the page title in the header; +- Edit page title: the default page title is the menu item title, which can be customized; +- Enable page tabs: off by default, you can add multiple tabs when enabled. + +### Header +Usually, we need to enable the header area for displaying page title, tabs. There are also cases where you don't want to enable it, for example, when we create a Dashbodrd page and the first level menu is a good representation of the content of that page, in this case we can disable the header and only show the blocks within the page. + +![20240120084618](https://static-docs.nocobase.com/20240120084618.png) + +#### Page Title +The default page title is the name of the menu item, which can be changed by clicking "Edit page title". As with the header, there are times when we don't need to show the page title, but only the tabs, in which case the title can be turned off. + +![2024-01-20_08-28-43](https://static-docs.nocobase.com/2024-01-20_08-28-43.jpg) + +#### Tabs +When there is too much content in a page, or when it is suitable to organize it into several separate parts, we can enable tabs, each tab is a separate block container. In the image below, we have added 3 tabs to the orders page to display all orders, completed orders, and refunded orders. Hover your mouse over the tab titles and you can see the Drag and Configure Items buttons in the upper right corner. + +![2024-01-20_08-47-15](https://static-docs.nocobase.com/2024-01-20_08-47-15.jpg) + +### Block Container +You can add an unlimited number of blocks to your page by clicking "Add block" (see [Blocks](. /blocks/index.md)). + +![2024-01-20_08-48-36](https://static-docs.nocobase.com/2024-01-20_08-48-36.jpg) + +After adding multiple blocks, you can drag and drop any layout of the blocks to adjust the layout to achieve the most suitable effect by using the dragbutton at the upper right corner of the block. + +![page-block](https://static-docs.nocobase.com/page-block.gif) + +## Popup +Currently, there are two kinds of popup windows in NocoBase: dialogs and drawers. Like pages, dialogs and drawers can be used as containers for blocks, and multiple tabs can be added to them. They are opened by actions such as Add, Edit, View, etc. + +![2024-01-20_08-52-00](https://static-docs.nocobase.com/2024-01-20_08-52-00.jpg) + +![2024-01-20_08-52-24](https://static-docs.nocobase.com/2024-01-20_08-52-24.jpg) \ No newline at end of file diff --git a/docs/fr-FR/manual/ui/pages/static/C3xvb09t4oGOlhxxI5jcy2B7ncc.png b/docs/fr-FR/manual/ui/pages/static/C3xvb09t4oGOlhxxI5jcy2B7ncc.png new file mode 100644 index 000000000..ff6e6bf2c Binary files /dev/null and b/docs/fr-FR/manual/ui/pages/static/C3xvb09t4oGOlhxxI5jcy2B7ncc.png differ diff --git a/docs/fr-FR/manual/ui/pages/static/U0kXblh2Yo5S5hx91c2cYggrnYf.gif b/docs/fr-FR/manual/ui/pages/static/U0kXblh2Yo5S5hx91c2cYggrnYf.gif new file mode 100644 index 000000000..a43b0c671 Binary files /dev/null and b/docs/fr-FR/manual/ui/pages/static/U0kXblh2Yo5S5hx91c2cYggrnYf.gif differ diff --git a/docs/fr-FR/manual/ui/pages/static/VpP2bTwhooaxrqxy5gYc4KJFnUc.png b/docs/fr-FR/manual/ui/pages/static/VpP2bTwhooaxrqxy5gYc4KJFnUc.png new file mode 100644 index 000000000..3a1725bca Binary files /dev/null and b/docs/fr-FR/manual/ui/pages/static/VpP2bTwhooaxrqxy5gYc4KJFnUc.png differ diff --git a/docs/fr-FR/manual/ui/pages/static/YPqEb1UEMoNzszxAHeDcNrsjnie.png b/docs/fr-FR/manual/ui/pages/static/YPqEb1UEMoNzszxAHeDcNrsjnie.png new file mode 100644 index 000000000..933e11052 Binary files /dev/null and b/docs/fr-FR/manual/ui/pages/static/YPqEb1UEMoNzszxAHeDcNrsjnie.png differ diff --git a/docs/fr-FR/manual/ui/static/A8yMbUDaSo9zWpxs2Dncrqwjn9e.png b/docs/fr-FR/manual/ui/static/A8yMbUDaSo9zWpxs2Dncrqwjn9e.png new file mode 100644 index 000000000..3d9ba1a44 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/A8yMbUDaSo9zWpxs2Dncrqwjn9e.png differ diff --git a/docs/fr-FR/manual/ui/static/BBPvbjjv0or01vx1SzBcXtN9n9f.png b/docs/fr-FR/manual/ui/static/BBPvbjjv0or01vx1SzBcXtN9n9f.png new file mode 100644 index 000000000..c8a34c5ca Binary files /dev/null and b/docs/fr-FR/manual/ui/static/BBPvbjjv0or01vx1SzBcXtN9n9f.png differ diff --git a/docs/fr-FR/manual/ui/static/Dpmeb5HinokF1Pxfu0BcAmgOnfd.gif b/docs/fr-FR/manual/ui/static/Dpmeb5HinokF1Pxfu0BcAmgOnfd.gif new file mode 100644 index 000000000..f4eab4cfc Binary files /dev/null and b/docs/fr-FR/manual/ui/static/Dpmeb5HinokF1Pxfu0BcAmgOnfd.gif differ diff --git a/docs/fr-FR/manual/ui/static/EUynbO9QPo1iHpxQxwXcYyTLnMf.gif b/docs/fr-FR/manual/ui/static/EUynbO9QPo1iHpxQxwXcYyTLnMf.gif new file mode 100644 index 000000000..01b2c8807 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/EUynbO9QPo1iHpxQxwXcYyTLnMf.gif differ diff --git a/docs/fr-FR/manual/ui/static/HjXmbyAndo07izxp9AQcA5YSnyd.gif b/docs/fr-FR/manual/ui/static/HjXmbyAndo07izxp9AQcA5YSnyd.gif new file mode 100644 index 000000000..0f82a879c Binary files /dev/null and b/docs/fr-FR/manual/ui/static/HjXmbyAndo07izxp9AQcA5YSnyd.gif differ diff --git a/docs/fr-FR/manual/ui/static/JgMZbj7izo2Ugex8vKmc6fTzntb.gif b/docs/fr-FR/manual/ui/static/JgMZbj7izo2Ugex8vKmc6fTzntb.gif new file mode 100644 index 000000000..3393f06c3 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/JgMZbj7izo2Ugex8vKmc6fTzntb.gif differ diff --git a/docs/fr-FR/manual/ui/static/L6vtbzAUAoxNn6xNwDkcveQenPg.gif b/docs/fr-FR/manual/ui/static/L6vtbzAUAoxNn6xNwDkcveQenPg.gif new file mode 100644 index 000000000..6585f48d5 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/L6vtbzAUAoxNn6xNwDkcveQenPg.gif differ diff --git a/docs/fr-FR/manual/ui/static/OYC6b09tEor0E6x5WTXc5FjvnIc.gif b/docs/fr-FR/manual/ui/static/OYC6b09tEor0E6x5WTXc5FjvnIc.gif new file mode 100644 index 000000000..e4747a90c Binary files /dev/null and b/docs/fr-FR/manual/ui/static/OYC6b09tEor0E6x5WTXc5FjvnIc.gif differ diff --git a/docs/fr-FR/manual/ui/static/PM70bxBbDo14KcxYke1cl6GQn9S.gif b/docs/fr-FR/manual/ui/static/PM70bxBbDo14KcxYke1cl6GQn9S.gif new file mode 100644 index 000000000..34cec4d68 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/PM70bxBbDo14KcxYke1cl6GQn9S.gif differ diff --git a/docs/fr-FR/manual/ui/static/PQKrbFbmUoYcX6xS6d7c8Enun4a.gif b/docs/fr-FR/manual/ui/static/PQKrbFbmUoYcX6xS6d7c8Enun4a.gif new file mode 100644 index 000000000..6341cafa3 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/PQKrbFbmUoYcX6xS6d7c8Enun4a.gif differ diff --git a/docs/fr-FR/manual/ui/static/R35gbnMFjolgS9xfO9wczmXmnG0.gif b/docs/fr-FR/manual/ui/static/R35gbnMFjolgS9xfO9wczmXmnG0.gif new file mode 100644 index 000000000..697001106 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/R35gbnMFjolgS9xfO9wczmXmnG0.gif differ diff --git a/docs/fr-FR/manual/ui/static/TkNGb5tLRoY7JVxjlIrc9Ol3njd.png b/docs/fr-FR/manual/ui/static/TkNGb5tLRoY7JVxjlIrc9Ol3njd.png new file mode 100644 index 000000000..b5d957bec Binary files /dev/null and b/docs/fr-FR/manual/ui/static/TkNGb5tLRoY7JVxjlIrc9Ol3njd.png differ diff --git a/docs/fr-FR/manual/ui/static/UPPCbpZb5oU9Frxyc0JcIzbhn1b.gif b/docs/fr-FR/manual/ui/static/UPPCbpZb5oU9Frxyc0JcIzbhn1b.gif new file mode 100644 index 000000000..36fa7f9a8 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/UPPCbpZb5oU9Frxyc0JcIzbhn1b.gif differ diff --git a/docs/fr-FR/manual/ui/static/WNA9beotVoYfLqxfBsVcchhvn9y.gif b/docs/fr-FR/manual/ui/static/WNA9beotVoYfLqxfBsVcchhvn9y.gif new file mode 100644 index 000000000..ad2e4159d Binary files /dev/null and b/docs/fr-FR/manual/ui/static/WNA9beotVoYfLqxfBsVcchhvn9y.gif differ diff --git a/docs/fr-FR/manual/ui/static/WPoJbqedXozxb0xAQP3cKghzn8d.gif b/docs/fr-FR/manual/ui/static/WPoJbqedXozxb0xAQP3cKghzn8d.gif new file mode 100644 index 000000000..15d164275 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/WPoJbqedXozxb0xAQP3cKghzn8d.gif differ diff --git a/docs/fr-FR/manual/ui/static/X8RTbD6FPodn1dxk3OscieZrnie.png b/docs/fr-FR/manual/ui/static/X8RTbD6FPodn1dxk3OscieZrnie.png new file mode 100644 index 000000000..72c863300 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/X8RTbD6FPodn1dxk3OscieZrnie.png differ diff --git a/docs/fr-FR/manual/ui/static/X8u0b5QJFomar7xbFTKceqIPngb.jpg b/docs/fr-FR/manual/ui/static/X8u0b5QJFomar7xbFTKceqIPngb.jpg new file mode 100644 index 000000000..23e19ebe1 Binary files /dev/null and b/docs/fr-FR/manual/ui/static/X8u0b5QJFomar7xbFTKceqIPngb.jpg differ diff --git a/docs/fr-FR/manual/user/user-center/index.md b/docs/fr-FR/manual/user/user-center/index.md new file mode 100644 index 000000000..a5e60cc79 --- /dev/null +++ b/docs/fr-FR/manual/user/user-center/index.md @@ -0,0 +1,15 @@ +# 个人中心 + +个人中心为用户提供了一系列管理和系统维护功能,包括查看系统版本号、查看和编辑个人资料等快捷操作。当系统权限开启了相应权限时,个人中心还会提供清除缓存和重启应用的按钮,个人中心的快捷操作可由插件扩展提供。 + +目前提供的个人中心快捷操作: + +- Edit profile:编辑用户个人信息,由用户认证插件提供 +- Change password:修改密码,由用户认证插件实现提供 +- Switch role:切换角色,由用户认证插件实现提供 +- Sign out:登出系统,由用户认证插件实现提供 +- Theme :用于切换主题,由主题插件实现提供 +- Clear cache: 清除缓存,由用户认证插件实现提供(有权限控制) +- Restart application:重启应用,由用户认证插件实现提供(有权限控制) + +![](https://static-docs.nocobase.com/9db96c7432f9c1cfbc0429589f58674f.png) \ No newline at end of file diff --git a/docs/fr-FR/manual/user/user-center/static/FNtmbksNrorQ4xxbXEMcRHx7ndb.png b/docs/fr-FR/manual/user/user-center/static/FNtmbksNrorQ4xxbXEMcRHx7ndb.png new file mode 100644 index 000000000..69e0178af Binary files /dev/null and b/docs/fr-FR/manual/user/user-center/static/FNtmbksNrorQ4xxbXEMcRHx7ndb.png differ diff --git a/docs/fr-FR/manual/workflow/advanced.md b/docs/fr-FR/manual/workflow/advanced.md new file mode 100644 index 000000000..eb7c036f8 --- /dev/null +++ b/docs/fr-FR/manual/workflow/advanced.md @@ -0,0 +1 @@ + diff --git a/docs/fr-FR/manual/workflow/image.png b/docs/fr-FR/manual/workflow/image.png new file mode 100644 index 000000000..4e03c288d Binary files /dev/null and b/docs/fr-FR/manual/workflow/image.png differ diff --git a/docs/fr-FR/manual/workflow/index.md b/docs/fr-FR/manual/workflow/index.md new file mode 100644 index 000000000..16c6d602f --- /dev/null +++ b/docs/fr-FR/manual/workflow/index.md @@ -0,0 +1 @@ + diff --git a/docs/fr-FR/manual/workflow/nodes/aggregate.md b/docs/fr-FR/manual/workflow/nodes/aggregate.md new file mode 100644 index 000000000..ba6ffb13a --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/aggregate.md @@ -0,0 +1,55 @@ +# 聚合查询 + +用于对某个数据表的满足条件的数据进行聚合函数查询,并返回对应的统计结果。常用于处理报表相关的统计数据。 + +节点的实现上基于数据库的聚合函数,目前仅支持对一个数据表的单字段进行统计,统计结果的数值会保存在节点的结果中供后续其他节点使用。 + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“聚合查询”节点: + +![创建聚合查询节点](https://github.com/nocobase/nocobase/assets/525658/0e7c1609-a30b-4071-8f71-ee863bade0d3) + +## 节点配置 + +![聚合查询节点_节点配置](https://github.com/nocobase/nocobase/assets/525658/26bd7262-7f98-4651-a8c3-b2a6eb1c7c69) + +### 聚合函数 + +支持 SQL 中的 `COUNT`、`SUM`、`AVG`、`MIN` 和 `MAX` 共 5 种聚合函数,选择其中一种对数据进行聚合查询。 + +### 目标类型 + +聚合查询的目标可以通过两种模式选择,一种是直接选择目标数据表和其中的一个字段,另一种是通过流程上下文已有的数据对象,选择其对多的关系数据表及字段,进行聚合查询。 + +### 去重 + +即 SQL 中的 `DISTINCT`,去重的字段与选择的数据表字段相同,暂时不支持两者选不同的字段。 + +### 筛选条件 + +与普通的数据表查询时的筛选条件类似,可以使用流程的上下文变量。 + +## 示例 + +聚合目标为“数据表数据”比较容易理解,这里以“统计新增文章后该文章分类的总文章数”为例,介绍聚合目标为“关联数据表数据”的用法。 + +首先,创建两张数据表:“文章”和“分类”,其中文章有一个多对一关系字段指向分类表,同时创建反向关系字段分类一对多文章: + +| 字段名 | 类型 | +| -------- | -------------- | +| 标题 | 单行文本 | +| 所属分类 | 多对一(分类) | + +| 字段名 | 类型 | +| -------- | -------------- | +| 分类名称 | 单行文本 | +| 包含文章 | 一对多(文章) | + +接下来创建一个数据表事件触发的工作流,选择文章表新增数据后触发。 + +之后增加一个聚合查询节点,配置如下: + +![聚合查询节点_示例_节点配置](https://github.com/nocobase/nocobase/assets/525658/6c3e8dde-dbfe-4042-91c7-0c2993bbba82) + +这样在工作流被触发后,聚合查询节点中将会统计新增文章的分类下所有文章的数量,并保存为节点的结果。 diff --git a/docs/fr-FR/manual/workflow/nodes/calculation.md b/docs/fr-FR/manual/workflow/nodes/calculation.md new file mode 100644 index 000000000..a5c8aae31 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/calculation.md @@ -0,0 +1,39 @@ +# 运算 + +运算节点虽然不对流程进行控制,但是流程中一种重要的功能,运算节点可以对一个表达式进行计算,运算结果会保存在对应节点的结果中,以供后续其他节点使用。是一种用于计算、处理和转换数据的工具,一定程度上,可以代替编程语言中对一个值计算函数调用并赋值给变量的功能。 + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“运算”节点: + +![运算节点_添加](https://static-docs.nocobase.com/58a455540d26945251cd143eb4b16579.png) + +## 节点配置 + +![运算节点_节点配置](https://static-docs.nocobase.com/6a155de3f6a883d8cd1881b2d9c33874.png) + +### 运算引擎 + +运算引擎规定了表达式支持的语法,目前支持的运算引擎有 [Math.js](https://mathjs.org/) 和 [Formula.js](https://formulajs.info/),引擎各自都内置了大量的常用函数和数据操作的方法,具体的用法可以参考其官方文档。 + +:::info{title=提示} +需要注意的是,两者在数组下标访问上有所区别,Math.js 的索引是从 `1` 开始,而 Formula.js 是从 `0` 开始。 +::: + +另外如果是需要简单的字符串拼接,可以直接使用“字符串模板”,该引擎会将表达式中的变量替换为对应的值,然后返回拼接后的字符串。 + +### 表达式 + +表达式即一个运算公式的字符串表达,可以由变量、常量、运算符和支持的函数等组成。可以使用流程上下文的变量,例如运算节点的前置节点的结果,或者是循环的局部变量等。 + +表达式输入不符合语法时会在节点配置中提示错误,如果在具体执行时变量不存在或者类型不匹配,又或者使用了不存在的函数,运算节点会以出错的状态提前终止。 + +## 示例 + +### 计算订单总价 + +通常一个订单内可能有多个商品,每个商品的价格和数量都不同,订单的总价需要计算所有商品的价格和数量的乘积之和。可以在加载订单明细列表(对多关系数据集)之后使用运算节点来计算订单的总价: + +![运算节点_示例_节点配置](https://static-docs.nocobase.com/85966b0116afb49aa966eeaa85e78dae.png) + +其中 Formula.js 的 `SUMPRODUCT` 函数可以计算两个相同长度数组每行的乘积之和,加总就可以得到订单的总价。 \ No newline at end of file diff --git a/docs/fr-FR/manual/workflow/nodes/condition.md b/docs/fr-FR/manual/workflow/nodes/condition.md new file mode 100644 index 000000000..dc26aba19 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/condition.md @@ -0,0 +1,43 @@ +# 条件判断 + +类型于编程语言中的 `if` 语句,根据配置条件判断的结果,决定后续流程的走向。 + +## 创建节点 + +条件判断有两种模式,分别是“‘是’则继续”和“‘是’和‘否’分别继续”,在创建节点时需要选择其中一种模式,之后在节点的配置中不能修改。 + +![条件判断_模式选择](https://github.com/nocobase/nocobase/assets/525658/dac253b8-4b45-414c-abd5-e3f6908a60cd) + +“‘是’则继续”的模式下,当条件判断的结果为“是”时,流程将继续执行后续节点,否则流程将终止,并以失败的状态提前退出。 + +![“是”则继续模式](https://github.com/nocobase/nocobase/assets/525658/d4046c6c-d44c-4d31-8b94-6231459a1415) + +这种模式适合于不满足条件的情况下,流程不再继续的场景,例如使用“提交至工作流”表单按钮配置了提交订单的表单,但在订单对应商品库存不足的情况下,不继续生成订单,而是失败退出。 + +“‘是’和‘否’分别继续”的模式下,条件节点后续会产生两条分支流程,分别对应条件判断的结果为“是”和“否”时的流程,两条分支流程可以分别配置后续节点,在任意分支执行完毕后,再自动汇合到条件节点所在的上级分支,继续执行之后的节点。 + +![“是”和“否”分别继续模式](https://github.com/nocobase/nocobase/assets/525658/2b791162-bfcc-4079-be41-4dfdf18cf782) + +这种模式适合于满足条件和不满足条件的情况下,流程需要分别执行不同的操作的场景,例如查询某条数据是否存在,不存在的时候新增,存在的时候更新。 + +## 节点配置 + +### 运算引擎 + +目前支持三种引擎: + +- **基础**:通过简单的双目计算和“与”、“或”分组,得到逻辑结果。 +- **Math.js**:计算 [Math.js](https://mathjs.org/) 引擎支持的表达式得到逻辑结果。 +- **Formula.js**:计算 [Formula.js](https://formulajs.info/) 引擎支持的表达式得到逻辑结果。 + +三种计算中均可以使用流程上下文的变量,用作计算的操作数。 + +## 示例 + +### “‘是’则继续”模式 + + + +### “‘是’和‘否’分别继续”模式 + + diff --git a/docs/fr-FR/manual/workflow/nodes/create.md b/docs/fr-FR/manual/workflow/nodes/create.md new file mode 100644 index 000000000..72a6271ac --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/create.md @@ -0,0 +1,39 @@ +# 新增数据 + +用于对某个数据表新增一行数据。 + +新增数据行的字段值可以使用流程上下文的变量,对关系字段的赋值可以直接引用上下文中的对应数据变量,可以是对象,也可以是外键的值。如果不使用变量,则需要手动填写外键的值,对多关系的多个外键值需要使用英文逗号分隔的形式。 + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“新增数据”节点: + +![创建新增数据节点](https://github.com/nocobase/nocobase/assets/525658/81b1aa3a-3001-480d-a6a2-5c15cdb2c92f) + +## 节点配置 + +![新增节点_示例_节点配置](https://github.com/nocobase/nocobase/assets/525658/00acac15-8a4a-426e-96d8-f45c0bf57634) + +### 数据表 + +选择要新增数据的数据表。 + +### 字段值 + +针对数据表的字段进行赋值,可以使用流程上下文的变量,也可以手动填写静态值。 + +注:工作流中新增节点新增的数据不会自动处理“创建人”、“最后修改人”等用户数据,需要根据情况自行配置这两个字段的值。 + +### 预加载关系数据 + +如果新增数据的字段中包含关系字段,且希望后续流程中使用相应的关系数据时,可以在预加载配置中勾选相应的关系字段,这样在新增数据完成后,会自动加载相应的关系数据一并储存在节点的结果数据中。 + +## 示例 + +例如当“文章”表的数据新增或更新后,需要自动新增一条“文章版本”数据,记录文章的一次变更历史,可以使用新增节点来实现: + +![新增节点_示例_流程配置](https://github.com/nocobase/nocobase/assets/525658/c29fb9e2-cc2e-4ef9-892c-c42bcef53d94) + +![新增节点_示例_节点配置](https://github.com/nocobase/nocobase/assets/525658/6c751857-6973-4fb8-b59b-d3ce39423539) + +按此配置启用工作流后,当“文章”表的数据变更时,会自动新增一条“文章版本”数据,记录文章的变更历史。 diff --git a/docs/fr-FR/manual/workflow/nodes/delay.md b/docs/fr-FR/manual/workflow/nodes/delay.md new file mode 100644 index 000000000..258d86936 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/delay.md @@ -0,0 +1,29 @@ +# 延时 + +延时节点可以在流程中增加一个延时,延时结束后,可根据配置是继续执行延时结束后的节点或是提前终止流程。 + +通常配合并行分支节点一起使用,可以在其中一个分支中增加延时节点,以达到超时后相关处理的目的。例如并行分支中其中一个分支包含人工处理,另一个分支包含延时节点,当人工处理超时后,如果设置的是超时失败,则代表人工处理必须在限定时间内完成,如果设置的是超时继续,则代表到时间后可以忽略该人工处理。 + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“延时”节点: + +![创建延时节点](https://github.com/nocobase/nocobase/assets/525658/c6c46d94-e03b-45b6-aa20-f4c1bd2c2f0e) + +## 节点配置 + +![延时节点_节点配置](https://github.com/nocobase/nocobase/assets/525658/5f46759c-6796-44c6-a135-84c76c7d5af7) + +### 延时时间 + +延时时间可以填写一个数字,并选择时间单位,支持的时间单位有:秒、分钟、小时、天和周。 + +### 到时状态 + +到时状态可以选择“通过并继续”和“失败并退出”,前者代表延时结束后,流程会继续执行延时结束后的节点,后者代表延时结束后,流程会以失败状态提前终止。 + +## 示例 + +以工单发起后需要在限时内答复的场景为例,我们需要在并行的两个分支中其一添加一个人工节点,另一个分支添加延时节点,如果人工处理未在 10 分钟内答复,则更新工单状态为超时未处理。 + +![延时节点_示例_流程组织](https://github.com/nocobase/nocobase/assets/525658/a2f1001b-c19c-4aa4-a4a5-84311f9705ec) diff --git a/docs/fr-FR/manual/workflow/nodes/destroy.md b/docs/fr-FR/manual/workflow/nodes/destroy.md new file mode 100644 index 000000000..f737e9b36 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/destroy.md @@ -0,0 +1,35 @@ +# 删除数据 + +用于对某个数据表的满足条件的数据进行删除。 + +删除节点的基本使用与更新节点类似,只是删除节点不需要字段赋值,只需要选择数据表和筛选条件即可。删除节点的结果会返回删除成功数据的行数,只在执行历史里可查看,不可作为变量在后续节点使用。 + +:::info{title=注意} +目前删除节点不支持逐条删除,均为批量删除,因此不会触发每条数据删除的其他事件。 +::: + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“删除数据”节点: + +![创建删除数据节点](https://github.com/nocobase/nocobase/assets/525658/ca9d34fb-df6b-4b8a-bd14-9b4473e546c8) + +## 节点配置 + +![删除节点_节点配置](https://github.com/nocobase/nocobase/assets/525658/6cdd0036-3188-43f5-b956-916af6afcb01) + +### 数据表 + +选择要删除数据的数据表。 + +### 筛选条件 + +与普通的数据表查询时的筛选条件类似,可以使用流程的上下文变量。 + +## 示例 + +例如定时清理已取消的无效历史订单数据,可以使用删除节点来实现: + +![删除节点_示例_节点配置](https://github.com/nocobase/nocobase/assets/525658/ec0e0802-eae1-4201-ac8c-471f3458ee93) + +工作流将定时触发,并执行删除所有已取消的无效历史订单数据。 diff --git a/docs/fr-FR/manual/workflow/nodes/dynamic-calculation.md b/docs/fr-FR/manual/workflow/nodes/dynamic-calculation.md new file mode 100644 index 000000000..bb1fda994 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/dynamic-calculation.md @@ -0,0 +1,108 @@ +# 动态表达式运算 + +区别于普通的运算节点只执行固定的表达式计算,动态表达式节点可以基于数据关联的表达式进行不同的计算。其解决的核心问题是由于普通的公式字段针对数据表所有数据行都只能使用同一个固定公式进行计算,而动态表达式可以针对数据行不同计算方式时,在工作流中进行处理以达成动态计算的目标。 + +例如订单数据在所属不同产品分类下使用不同的统计公式来计算特定的报表数据。 + +## 准备 + +动态表达式节点的使用与工作流其他较为简单的节点不同,有几个需要前置完成的步骤: + +1. 创建“表达式”模板表。 +2. 录入表达式数据。 +3. 将业务数据与表达式数据建立关联。 +4. 通过查询节点或者数据触发时的预加载关系数据加载特定业务数据关联的表达式数据。 + +以上步骤完成后,再对工作流配置动态表达式节点。 + +### 创建“表达式”模板表 + +在工作流内使用动态表达式运算节点之前,需要先在数据表管理工具中创建一张“表达式”模板表,用于存放不同的表达式: + +![创建表达式模板表](https://github.com/nocobase/nocobase/assets/525658/9964baff-d53d-4f2c-8906-c76e65fe4fe1) + +### 录入表达式数据 + +然后创建一个表格区块对该模板表添加几条公式数据,“表达式”模板表中每行数据都可以被理解为针对特定表数据模型的一个计算规则。每行公式数据可使用不同数据表的数据模型中的字段值作为变量,编写不同的表达式作为计算规则,当然,也可以使用不同的计算引擎。 + +### 将业务数据与表达式数据建立关联 + +创建好公式以后还需要将业务数据与公式进行关联,将每行业务数据直接关联公式数据行会比较繁琐,所以通常我们会使用类似分类的元数据表与公式表进行多对一(或一对一)关联,再将业务数据与分类元数据进行多对一的关联,那么在创建业务数据时只需指定特定的分类元数据,即可在后续使用中通过这个关联路径找到对应的公式数据进行使用。 + +### 流程中加载相应的数据 + +## 创建节点 + +## 节点配置 + +最后我们需要在特定业务的工作流中加入动态表达式节点,其将在流程触发时执行对应的计算。 + +
    + 运算节点_节点配置 +
    + +### 动态表达式 + +与普通运算节点的表达式选项不同,动态表达式需要根据已经查询出来的数据进行选择,而不是直接录入表达式。 + +### 变量数据源 + +同时还需要选择表达式中变量所需要使用的数据表数据行对象,可以从流程的上下文中选择已经提前加载(或查询)出来的结果对象。 + +## 示例 + +以商品下单过程中根据不同商品进行不同优惠规则的最终价格计算举例。 + +1. 建立商品表: + + | 字段名 | 类型 | + | -------- | ------------------------- | + | 商品名 | 文本 | + | 商品原价 | 数字 | + | 优惠规则 | `belongsTo`(优惠规则表) | + +2. 建立优惠规则表(使用表达式表模板创建): + + | 字段名 | 类型 | + | -------- | ------------------------ | + | 规则名称 | 文本 | + | 数据表 | 单选(数据表) | + | 计算引擎 | 单选(mathjs/formulajs) | + | 表达式 | 文本 | + +3. 录入优惠规则: + + | ID | 名称 | 数据表 | 计算引擎 | 表达式 | + | --- | -------- | ------ | ---------- | --------------------- | + | 1 | 八折商品 | 商品 | formula.js | `{{商品.价格}} * 0.8` | + | 2 | 九折商品 | 商品 | formula.js | `{{商品.价格}} * 0.9` | + +4. 创建商品,并关联优惠规则: + + | ID | 商品名称 | 价格 | 优惠规则 | + | --- | ------------- | ---- | -------- | + | 1 | iPhone 14 Pro | 7999 | 2 | + | 2 | iPhone 13 Pro | 6999 | 1 | + +5. 创建工作流,订单创建时触发: + + ![]() + +6. 创建一个运算节点,配置动态表达式为触发数据/商品/优惠规则: + + 配置变量数据源为触发数据中的商品: + + ![]() + +7. 增加一个更新数据节点,配置更新订单总价为计算节点的结果: + + ![]() + +8. 创建订单触发工作流,再查看订单列表,核对价格: + + ![]() + + | 订单商品 | 订单商品 / 原价 | 优惠规则 | 总价 | + | ------------- | --------------- | -------- | -------------------- | + | iPhone 14 Pro | 7999 | 九折 | 7999 \* 0.9 = 7199.1 | + | iPhone 13 Pro | 6999 | 八折 | 6999 \* 0.8 = 5599.2 | diff --git a/docs/fr-FR/manual/workflow/nodes/index.md b/docs/fr-FR/manual/workflow/nodes/index.md new file mode 100644 index 000000000..6cfc98571 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/index.md @@ -0,0 +1,28 @@ +# 概述 + +节点是工作流中逻辑编排的基本单元,一个工作流可以配置任意多个节点,每个节点的类型代表一个指令,决定了节点的行为。节点的配置即对应指令的参数,参数决定其行为的操作数据对象或其他内容。 + +:::info{title=提示} +工作流的触发器不属于节点,只是以入口节点的形式展示在流程图中,但与节点是不同的概念,详情请参考[触发器](../triggers/index.md)的内容。 +::: + +从功能角度,目前已实现的节点可以分为四大类(共 14 种节点): + +- 流程控制类 + - [条件判断](./condition.md) + - [运算](./calculation.md) + - [动态表达式运算](./dynamic-calculation.md) + - [循环](./loop.md) + - [并行分支](./parallel.md) + - [延时](./delay.md) +- 数据表操作 + - [新增数据](./create.md) + - [更新数据](./update.md) + - [删除数据](./destroy.md) + - [查询数据](./query.md) + - [聚合查询](./aggregate.md) + - [SQL 操作](./sql.md) +- 人工处理 + - [人工处理](./manual.md) +- 外部调用 + - [HTTP 请求](./request.md) diff --git a/docs/fr-FR/manual/workflow/nodes/loop.md b/docs/fr-FR/manual/workflow/nodes/loop.md new file mode 100644 index 000000000..84f0c8915 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/loop.md @@ -0,0 +1,77 @@ +# 循环 + +循环相当编程语言中的 `for`/`while`/`forEach` 等语法结构,当需要一定次数或针对某个数据集合(数组)重复执行一些操作时,可以使用循环节点。 + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“循环”节点: + +![创建循环节点](https://github.com/nocobase/nocobase/assets/525658/ca5002e1-75fc-4efd-8b6b-2284d7c2fe8a) + +创建循环节点后,会生成一个循环内部的分支,可以在分支中增加任意多个节点,这些节点除了可以使用流程上下文的变量,还可以使用循环上下文的局部变量,例如循环集合中每次循环到的数据对象,或者是循环次数的索引(索引从 `0` 开始计数)。局部变量的作用域仅限于循环内部,如果有多层循环嵌套,可以按层使用具体循环的局部变量。 + +## 节点配置 + +### 循环对象 + +循环会以循环对象不同数据类型做不同的处理: + +1. **数组**:最常见的情况,通常是可以选择流程上下文的变量,比如查询节点的多条数据结果,或者预加载的对多关系数据。如果选择的是数组,循环节点会遍历数组中的每个元素,每次循环都会将当前元素赋值给循环上下文的局部变量。 + +2. **数字**:当选择的变量是一个数字是,会以该数字为循环次数,局域变量中的循环次数的索引也即循环对象的值。 + +3. **字符串**:当选择的变量是一个字符串时,会以该字符串的长度为循环次数,每次按索引处理字符串中的每一个字符。 + +4. **其他**:其他类型的值(包括对象类型)都仅作为单次处理的循环对象,也只会循环一次,通常这种情况不需要使用循环。 + +除了选择变量,针对数字和字符串类型也可以直接输入常量,例如输入 `5`(数字类型),循环节点会循环 5 次,输入 `abc`(字符串类型),循环节点会循环 3 次,分别处理 `a`、`b`、`c` 三个字符。在选择变量的工具中选择希望使用常量的类型。 + +## 示例 + +例如在订单下单时,需要对订单中的每个商品进行库存检查,如果库存充足则扣减库存,否则订单明细内的商品更新为无效。 + +1. 创建三张表,商品表 <-(1:m)-- 订单明细表 --(m:1)-> 订单表,数据模型如下: + + | 字段名称 | 字段类型 | + | ------------ | -------------- | + | 订单商品明细 | 多对一(明细) | + | 订单总价 | 数字 | + + | 字段名称 | 字段类型 | + | -------- | -------------- | + | 商品 | 一对多(商品) | + | 数量 | 数字 | + + | 字段名称 | 字段类型 | + | -------- | -------- | + | 商品名称 | 单行文本 | + | 价格 | 数字 | + | 库存 | 整数 | + +2. 创建工作流,触发器选择“数据表事件”,选择“订单”表“新增数据时”触发,并且需要配置上预加载“订单明细”表和明细下的商品表的关系数据: + + ![循环节点_示例_触发器配置](https://github.com/nocobase/nocobase/assets/525658/76c97498-bfd6-46f4-99da-9734cb10e400) + +3. 创建循环节点,选择循环对象为“触发数据 / 订单明细”,即对订单明细表中的每一条数据: + + ![循环节点_示例_循环节点配置](https://github.com/nocobase/nocobase/assets/525658/961c20bb-f1c8-4bba-96b3-79ea74dcc66c) + +4. 循环节点内部创建一个“条件判断”节点,判断商品的库存是否充足: + + ![循环节点_示例_条件判断节点配置](https://github.com/nocobase/nocobase/assets/525658/85085520-9287-4353-b978-b47c859972fc) + +5. 如果充足则在“是”的分支中创建一个“计算节点”和一个“更新数据”节点,将计算完扣减的库存更新至对应商品的记录: + + ![循环节点_示例_计算节点配置](https://github.com/nocobase/nocobase/assets/525658/5ec4ff91-e3ff-4ee2-91d7-4602b13d605f) + + ![循环节点_示例_更新库存节点配置](https://github.com/nocobase/nocobase/assets/525658/85c59e6d-90bb-47bd-b36a-7ecf1744a630) + +6. 否则在“否”的分支中创建一个“更新数据”节点,更新订单明细的状态为“无效”: + + ![循环节点_示例_更新订单明细节点配置](https://github.com/nocobase/nocobase/assets/525658/856f8c35-d35b-4879-81d0-3d334e6d9a42) + +总的流程结构如下图: + +![循环节点_示例_流程结构](https://github.com/nocobase/nocobase/assets/525658/7cd2dfe7-6a43-43b8-90d7-9c9c323f888e) + +配置完成并激活该流程后,当创建新订单时,会自动检查订单明细中的商品库存,如果库存充足则扣减库存,否则订单明细内的商品更新为无效(以便计算有效的订单总价)。 diff --git a/docs/fr-FR/manual/workflow/nodes/manual.md b/docs/fr-FR/manual/workflow/nodes/manual.md new file mode 100644 index 000000000..9b8e8e16a --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/manual.md @@ -0,0 +1,183 @@ +# 人工处理 + +当业务流程不能完全自动化决策时,可以通过人工节点,将部分决策权交给人工处理。 + +人工节点在执行到时会先中断整个流程的执行,生成对应用户的待办任务,在用户提交后根据所选的状态决定继续流程、继续等待还是终止流程。在需要进行流程审批等场景会非常有用。 + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“人工处理”节点: + +![创建人工节点](https://github.com/nocobase/nocobase/assets/525658/6a08d124-7bef-4064-9f9a-f37db40c3927) + +## 配置节点 + +### 负责人 + +人工节点需要指定一个用户,作为待办任务的执行者。待办任务的列表可以在页面添加区块时添加,每个节点的任务弹窗内容需要在节点中进行界面配置。 + +选定一个用户,或者通过变量选择上下文中的用户数据的主键或外键。 + +![人工节点_配置_负责人_选择变量](https://github.com/nocobase/nocobase/assets/525658/9d241c64-243c-4da3-89b0-3c4a5538ad5d) + +:::info{title=提示} +目前人工节点的负责人选项暂不支持针对多人处理,会在未来的版本中支持。 +::: + +### 配置用户界面 + +待办事项的界面配置是人工节点的核心内容,可以通过点击“配置用户界面”按钮弹窗打开独立配置,和普通页面一样,可以所见即所得地配置: + +![人工节点_节点配置_界面配置](https://github.com/nocobase/nocobase/assets/525658/45ff0236-c4bb-4379-af78-a40c782cae6c) + +#### 标签页 + +标签页可以用于区分不同的内容,例如一个标签页用于通过的表单提交,另一个标签页用于拒绝的表单提交,或者用于展示相关数据的详情等,可自由配置。 + +#### 区块 + +支持的区块类型主要有两大类,数据区块和表单区块,另外的 Markdown 主要用于提示信息等静态内容。 + +##### 数据区块 + +数据区块可选择触发器数据或任意的节点处理结果,用于提供给待办负责人相关的上下文信息。例如工作流是表单事件触发的,即可以创建一个触发数据的详情区块,与普通页面的详情配置一致,可任选触发数据内有的字段进行数据展示: + +![人工节点_节点配置_界面配置_数据区块_触发器](https://github.com/nocobase/nocobase/assets/525658/2aca45ec-7e4f-448f-aeec-7e6e80f28a3b) + +节点数据区块类似,可以选择上游节点中的数据结果作为详情展示。例如上游一个计算节点的结果,作为负责人待办的上下文参考信息: + +![人工节点_节点配置_界面配置_数据区块_节点数据](https://github.com/nocobase/nocobase/assets/525658/f861a680-995c-47d5-ad9e-403902eec974) + +:::info{title=提示} +由于配置界面时工作流都处于未执行的状态,所以数据区块中都是没有具体数据显示的,只有当工作流被触发执行后,在待办弹窗界面中才可看到具体流程的相关数据。 +::: + +##### 表单区块 + +待办界面中至少需要配置一个表单区块,作为工作流是否继续执行的最终决策处理,不配置表单会导致流程中断后无法继续。表单区块有三种类型,分别是: + +- 自定义表单 +- 新增数据表单 +- 更新数据表单 + +![人工节点_节点配置_界面配置_表单类型](https://github.com/nocobase/nocobase/assets/525658/2e4c8b58-ea55-48f6-9c4c-1ebbc07cc940) + +新增数据表单和更新数据表单需要选择基于的数据表,待办用户提交后会使用表单内的值新增或更新特定数据表的数据。自定义表单则可以自由定义一个数据表无关的临时表单,待办用户提交后的字段值可以在后续节点中使用。 + +表单的提交按钮可以配置三种类型,分别是: + +- 提交后继续流程 +- 提交后终止流程 +- 仅暂存表单值 + +![人工节点_节点配置_界面配置_表单按钮](https://github.com/nocobase/nocobase/assets/525658/8d3f4852-3ad7-4a10-9e41-3f78e0835d8a) + +三个按钮代表流程处理中三种节点状态,提交后该节点的状态修改为“完成”、“拒绝”或继续处于“等待”的状态,一个表单至少要配置前两者之一,以决定整个流程的后续处理流向。 + +在“继续流程”按钮上可以配置对表单字段的赋值: + +![人工节点_节点配置_界面配置_表单按钮_设置表单值](https://github.com/nocobase/nocobase/assets/525658/e62e86fe-39c3-4bbc-b7b6-6bb5d69c3212) + +![人工节点_节点配置_界面配置_表单按钮_设置表单值弹窗](https://github.com/nocobase/nocobase/assets/525658/ba5bc9b6-d8ac-4588-9381-399e247b7efb) + +打开弹窗后可以对表单任意字段进行赋值,表单提交后将会以该值作为字段的终值。通常在对一些数据进行审核时比较有用,可以在表单中使用多个不同的“继续流程”按钮,每个按钮对类似状态的字段设置不同的枚举值,以达到继续后续流程执行且使用不同数据值的效果。 + +## 配置待办区块 + +对于人工处理来说,还需要在页面中添加待办列表,用于展示待办任务,相关人员才可以通过该列表进入人工节点的具体任务处理。可以从页面中的区块中选择“工作流待办”,添加待办列表的区块: + +![人工节点_添加待办区块](https://github.com/nocobase/nocobase/assets/525658/d88cc678-a2ff-4a48-a353-484177886b7a) + +待办列表区块示例: + +![人工节点_待办列表](https://github.com/nocobase/nocobase/assets/525658/b4f15922-0e63-4668-aa94-dda84fba4a6b) + +之后相关人员可以点击对应的待办任务,进入待办弹窗,进行人工处理: + +![人工节点_待办详情](https://github.com/nocobase/nocobase/assets/525658/7eebb3f9-042a-46a1-8924-b30f157a6044) + +## 示例 + +### 文章审核 + +假设普通用户提交的文章,需要管理员审核通过后才能更新为已发布状态,否则如果拒绝该流程,文章将保持草稿状态(不公开),这一流程可以使用人工节点中的更新表单来实现。 + +创建一个由“新增文章”触发的工作流,并增加一个人工节点: + +
    + 人工节点_示例_文章审核_流程编排 +
    + +在人工节点中配置负责人为管理员,配置界面中增加一个基于触发数据的区块,用于展示新增文章的详情: + +
    + 人工节点_示例_文章审核_节点配置_详情区块 +
    + +在配置界面中增加一个基于更新数据表单的区块,选择文章表,用于管理员决定是否通过审核,通过审核后会根据后面的其他配置更新对应文章。添加表单后,默认会有一个“继续流程”的按钮,可以将其视为点击后通过,再增加一个“终止流程”的按钮,用作审核不通过的情况: + +
    + 人工节点_示例_文章审核_节点配置_表单和操作 +
    + +针对继续流程时,我们需要更新文章的状态,这里有两种配置方式,一种是直接在表单中展示文章状态的字段,供操作者选择,这种方式更适合于一些需要主动填写表单的情况,例如反馈意见等: + +
    + 人工节点_示例_文章审核_节点配置_表单字段 +
    + +为了简化操作者的操作,另一种方式是在“继续流程”按钮上配置表单赋值,赋值中增加一个“状态”字段,值为“已发布”,则代表操作者点击按钮后,文章将会更新为已发布状态: + +
    + 人工节点_示例_文章审核_节点配置_表单赋值 +
    + +然后从表单区块的右上角配置菜单中选择要更新的数据的筛选条件,这里选择“文章”表,筛选条件为“ID `等于` 触发器变量 / 触发数据 / ID”: + +
    + 人工节点_示例_文章审核_节点配置_表单条件 +
    + +最后,可以修改各个区块的标题和相关按钮的文本,以及表单字段的提示文本,使界面更加友好: + +
    + 人工节点_示例_文章审核_节点配置_最终表单 +
    + +关闭配置面板,点击提交按钮保存节点配置后,工作流就配置完成了。启用该工作流以后,在新增文章时,会自动触发该工作流,管理员可以从待办任务列表中看到该工作流需要处理,点击查看后可以看到待办任务的详情: + +
    + 人工节点_示例_文章审核_待办列表 +
    + +
    + 人工节点_示例_文章审核_待办详情 +
    + +管理员可以根据文章详情进行人工判断,该文章是否可以发布,如果可以的话,点击“通过”按钮,文章将会更新为已发布状态,如果不可以的话,点击“拒绝”按钮,文章将会保持草稿状态。 + +### 请假审批 + +假设员工需要请假,需要经过主管审批通过后才能生效,并核销对应员工的假期数据。而且不管通过或拒绝,都将会通过请求节点调用短信接口,发送相关的的通知短信给员工(见 [HTTP 请求](#_HTTP_请求) 部分)。这个场景可以使用人工节点中的自定义表单来实现。 + +创建一个由“新增请假”触发的工作流,并增加一个人工节点,与之前的文章审核流程类似,只是这里的负责人是主管,配置界面中增加一个基于触发数据的区块,用于展示新增请假的详情,再增加一个基于自定义表单的区块,用于主管决定是否通过审核,自定义表单中增加一个是否通过的字段,以及一个拒绝理由的字段: + +
    + 人工节点_示例_请假审批_节点配置 +
    + +与文章审核流程不同,由于我们需要根据主管审批的结果继续后续的流程,所以这里我们只配置一个“继续流程”按钮,作为提交使用,而不使用“终止流程”按钮。 + +同时在人工节点之后,我们可以通过一个条件判断节点来判断主管是否通过了该请假申请,通过的分支中增加核销假期的数据处理,并在分支结束后增加一个请求节点,用于发送短信通知员工,就得到以下完整的流程: + +
    + 人工节点_示例_请假审批_流程编排 +
    + +其中条件判断节点的中的条件配置为“人工节点 / 自定义表单数据 / 是否通过字段的值是否为‘通过’”: + +
    + 人工节点_示例_请假审批_条件判断 +
    + +发送请求节点里的数据也可以使用人工节点中相应的表单变量,以区分通过和拒绝的短信内容。这样就完成了整个流程的配置,在开启工作流后,当员工提交请假申请的表单后,主管即可在待办任务中进行审批处理,操作基本与文章审核流程类似。 diff --git a/docs/fr-FR/manual/workflow/nodes/parallel.md b/docs/fr-FR/manual/workflow/nodes/parallel.md new file mode 100644 index 000000000..b88584645 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/parallel.md @@ -0,0 +1,29 @@ +# 并行分支 + +并行分支节点可以将流程分为多个分支,每个分支可以配置不同的节点,根据分支的模式不同,分支的执行方式也不同。在需要在同时执行多个操作的场景下,可以使用并行分支节点。 + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“并行分支”节点: + +![并行分支_添加](https://github.com/nocobase/nocobase/assets/525658/a0f9c6e9-3f6b-441e-a714-fa0f82f46859) + +在流程中增加并行分支节点后,会默认增加两个子分支,同时也可以点击增加分支的按钮增加任意多个分支,每个分支都可以增加任意的节点,不需要的分支可以点击分支开始处的删除按钮删除。 + +![并行分支_分支管理](https://github.com/nocobase/nocobase/assets/525658/db1a4bf9-774e-459a-8354-b93d99ed868a) + +## 节点配置 + +### 分支模式 + +并行分支节点有以下三种模式: + +- **全部成功**:所有分支都执行成功,流程才会继续执行分支结束后的节点。否则任意分支提前终止,无论是失败、出错还是其他非成功状态,都导致整个并行分支节点以该状态提前终止,也称作“All 模式”。 +- **任意成功**:任意分支执行成功,流程就会继续执行分支结束后的节点。除非所有分支都提前终止,无论是失败、出错还是其他非成功状态,才会导致整个并行分支节点以该状态提前终止,也称作“Any 模式”。 +- **任意成功和失败**:任意分支执行成功后流程就会继续执行分支结束后的节点,但任意节点失败后,会导致整个并行以该状态提前终止,也称作“Race 模式”。 + +不论哪种模式,都会从左到右依次尝试执行每个分支,直到满足分支预设模式的相关条件后,继续执行后续节点或提前退出。 + +## 示例 + +参考 [延时节点](./delay#示例) 中的例子。 diff --git a/docs/fr-FR/manual/workflow/nodes/query.md b/docs/fr-FR/manual/workflow/nodes/query.md new file mode 100644 index 000000000..48bfa9446 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/query.md @@ -0,0 +1,43 @@ +# 查询数据 + +用于对某个数据表的满足条件的数据进行查询并获取数据记录。 + +可以配置查询单条数据或多条数据,查询结果可以作为变量在后续节点使用。当查询多条数据时,查询结果为一个数组。当查询结果为空时,可以选择是否继续执行后续节点。 + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“查询数据”节点: + +![查询数据_添加](https://github.com/nocobase/nocobase/assets/525658/40d07623-b1c9-43ce-9513-0d42ac4a5b87) + +## 节点配置 + +![查询节点_节点配置](https://github.com/nocobase/nocobase/assets/525658/90d21bdb-426a-4f41-8bbe-2d095a6f9d3e) + +### 数据表 + +选择要查询数据的数据表。 + +### 查询模式 + +勾选“允许结果是多条数据”后,将会查询出满足条件的所有数据,否则只会查询出满足条件的第一条数据。如果勾选了“允许结果是多条数据”,则查询节点的结果会是一个数组类型。 + +### 筛选条件 + +与普通的数据表查询时的筛选条件类似,可以使用流程的上下文变量。 + +### 排序 + +查询一条或多条数据时均可通过排序规则来控制需要的结果。例如查询最新的一条数据,可以通过“创建时间”字段降序排序。 + +### 分页 + +当结果集可能会很大时,可以使用分页来控制查询结果的数量。例如查询最新的 10 条数据,可以通过“创建时间”字段降序排序,然后设置分页为 1 页 10 条数据。 + +### 结果为空的处理 + +在单条结果模式下,没有符合条件的数据的话查询结果会是 `null`,多条结果的模式下是空数组(`[]`)。可以根据需要是否勾选“查询结果为空是,退出流程”,勾选后,如果查询结果为空,则不会执行后续节点,以失败的状态提前退出。 + +## 示例 + +TODO diff --git a/docs/fr-FR/manual/workflow/nodes/request.md b/docs/fr-FR/manual/workflow/nodes/request.md new file mode 100644 index 000000000..39a5ff403 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/request.md @@ -0,0 +1,63 @@ +# HTTP 请求 + +当需要与另一个 web 系统进行交互时,可以使用 HTTP 请求节点。该节点在执行时会根据配置向对应的地址发出一个 HTTP 请求,可以携带 JSON 格式的数据,完成与外部系统的数据交互。 + +如果对 Postman 这类请求发送工具比较熟悉,那么可以很快掌握 HTTP 请求节点的用法。与这些工具不同的是,HTTP 请求节点中各项参数均可使用当前流程中的上下文变量,可以与当前系统的业务处理有机结合起来。 + +:::info{title=提示} +HTTP 请求节点暂不支持请求响应的结果进行使用,可能会在未来支持。 +::: + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“HTTP 请求”节点: + +![HTTP 请求_添加](https://github.com/nocobase/nocobase/assets/525658/d1d73f4d-5a24-4fcc-8fdc-6ee5bb700dd6) + +## 节点配置 + +![HTTP请求节点_节点配置](https://github.com/nocobase/nocobase/assets/525658/0bed2560-fe5d-4726-b918-45594248d60b) + +### 请求方法 + +可选的 HTTP 请求方法:`GET`、`POST`、`PUT`、`PATCH` 和 `DELETE`。 + +### 请求地址 + +HTTP 服务的 URL,需要包含协议部分(`http://` 或 `https://`),推荐使用 `https://`。 + +### 请求头配置 + +请求 Header 部分的键值对,相关值可以使用流程上下文的变量。 + +:::info{title=提示} +对 `Content-Type` 请求头,目前仅支持 `application/json` 的格式,且已默认内置,无需填写,覆盖无效。 +::: + +### 请求参数 + +请求 query 部分的键值对,相关值可以使用流程上下文的变量。 + +### 请求体 + +请求的 Body 部分,目前仅支持标准的 JSON 格式,可以通过文本编辑框右上角的变量按钮插入流程上下文中的变量。 + +:::info{title=提示} +注:变量必须在 JSON 的字符串中使用,例如:`"a": "{{$context.data.a}}"`。 +::: + +### 超时设置 + +当请求长时间未响应时,通过超时设置取消该请求的执行。请求超时后会以失败状态提前终止当前流程。 + +### 忽略失败 + +请求节点会以标准 HTTP 状态码的 `200`~`299` 之间(含)的状态认为是成功状态,其他的均认为是失败。如勾选了“忽略失败的请求并继续工作流”选项,则当请求失败后仍继续执行后续的其他流程节点。 + +## 示例 + +例如我们可以使用请求节点来对接云平台发送通知短信,以阿里云发送短信接口为例配置如下(相关参数需自行查阅文档适配): + +![HTTP请求节点_节点配置](https://github.com/nocobase/nocobase/assets/525658/0bed2560-fe5d-4726-b918-45594248d60b) + +工作流触发该节点执行时会以配置的内容调用阿里云的短信接口,请求成功的话将通过短信云服务发送一条短信。 diff --git a/docs/fr-FR/manual/workflow/nodes/sql.md b/docs/fr-FR/manual/workflow/nodes/sql.md new file mode 100644 index 000000000..192388164 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/sql.md @@ -0,0 +1,21 @@ +# SQL 操作 + +在一些特殊场景里,上面简单的数据表操作节点可能无法复杂的操作,则可以直接使用 SQL 节点,使数据库直接执行复杂的 SQL 语句进行数据操作。 + +与在应用外部直接连接数据库进行 SQL 操作的区别是,在工作流内可以使用流程上下文的变量,作为 SQL 语句中的部分参数。 + +:::info{title=提示} +目前 SQL 节点还不支持 `SELECT` 语句的结果作为节点结果使用,可能会在未来支持。 +::: + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“SQL 操作”节点: + +![SQL 操作_添加](https://github.com/nocobase/nocobase/assets/525658/1d3f21b3-d3f4-4f97-9195-e6a98ccb5289) + +## 节点配置 + +通过编辑框右上角的变量按钮插入需要的变量,会在执行前通过文本替换为对应变量的值: + +![SQL节点_节点配置](https://github.com/nocobase/nocobase/assets/525658/dd4e2f21-acd3-4c14-bbc9-0c28554e2fda) diff --git a/docs/fr-FR/manual/workflow/nodes/update.md b/docs/fr-FR/manual/workflow/nodes/update.md new file mode 100644 index 000000000..fd281e3a0 --- /dev/null +++ b/docs/fr-FR/manual/workflow/nodes/update.md @@ -0,0 +1,41 @@ +# 更新数据 + +用于对某个数据表的满足条件的数据进行更新。 + +数据表和字段赋值部分与新增节点相同,更新节点的区别主要是增加了筛选条件,而且需要选择更新模式。另外,更新节点的结果会返回更新成功数据的行数,只在执行历史里可查看,不可作为变量在后续节点使用。 + +## 创建节点 + +在工作流配置界面中,点击流程中的加号(“+”)按钮,添加“更新数据”节点: + +![更新数据_添加](https://github.com/nocobase/nocobase/assets/525658/9d29da49-3950-45af-854d-0347eee07d41) + +## 节点配置 + +![更新节点_节点配置](https://github.com/nocobase/nocobase/assets/525658/e4bf1fea-d343-4976-99d4-26724221ca16) + +### 数据表 + +选择要更新数据的数据表。 + +### 更新模式 + +更新模式有“批量”和“逐条”的模式,批量模式下,不会再触发每条更新数据的数据表事件,而逐条更新的话会触发每条更新数据的数据表事件,但在大数据量下会有性能问题,需要谨慎使用。通常根据更新的目标数据和是否要触发其他工作流事件来选择,如果是根据主键更新单条数据的,建议使用逐条更新,如果是根据条件更新多条数据的,建议使用批量更新。 + +### 筛选条件 + +与普通的数据表查询时的筛选条件类似,可以使用流程的上下文变量。 + +### 字段值 + +与新增节点的字段赋值类似,可以使用流程上下文的变量,也可以手动填写静态值。 + +注:工作流中更新节点更新的数据不会自动处理“最后修改人”数据,需要根据情况自行配置这个字段的值。 + +## 示例 + +例如当新增“文章”时,需要自动更新“文章分类”表的“文章数量”字段,可以使用更新节点来实现: + +![更新节点_示例_节点配置](https://github.com/nocobase/nocobase/assets/525658/e4bf1fea-d343-4976-99d4-26724221ca16) + +当工作流触发后,会自动更新“文章分类”表的“文章数量”字段为当前文章数量 +1。 diff --git a/docs/fr-FR/manual/workflow/start.md b/docs/fr-FR/manual/workflow/start.md new file mode 100644 index 000000000..d9db90334 --- /dev/null +++ b/docs/fr-FR/manual/workflow/start.md @@ -0,0 +1 @@ + diff --git a/docs/fr-FR/manual/workflow/triggers/collection.md b/docs/fr-FR/manual/workflow/triggers/collection.md new file mode 100644 index 000000000..a7c2e87e9 --- /dev/null +++ b/docs/fr-FR/manual/workflow/triggers/collection.md @@ -0,0 +1,92 @@ +# 数据表事件 + +数据表事件类型的触发器将监听数据表的增删改查事件,当发生对该表的数据操作且满足配置的条件时,触发对应工作流。例如新增订单后扣减商品的库存,新增一条评论后等待人工审核等场景。 + +## 基本使用 + +数据表的变动有几种情况: + +1. 新增数据后。 +2. 更新数据后。 +3. 新增或更新数据后。 +4. 删除数据后。 + +
    + 数据表事件_触发时机选择 +
    + +可以根据业务的不同需要选择触发的时机。当选择变动情况中包含更新数据表的情况时,还可以对发生变动的字段进行限定,只有选中字段发生变动时,才满足触发条件,不选择则代表所有字段发生变动都可以触发。 + +
    + 数据表事件_发生变动的字段选择 +
    + +更细节地,可以对触发的数据行的各个字段配置条件规则,当其中的字段满足相应条件,才进行触发。 + +
    + 数据表事件_配置数据满足的条件 +
    + +数据表事件触发后会在执行计划中注入产生事件的数据行作为触发上下文数据,以供后续流程中的节点作为变量调用。但当后续节点中希望使用该数据的关系字段时,需要先配置对关系数据的预加载,选中的关系数据将会在触发后一并注入到上下文中,且可被按层级进行选择使用。 + +## 相关提示 + +### 暂不支持批量数据操作触发 + +数据表事件事件暂不支持批量数据操作的触发,例如新增文章数据时同时新增的该文章的多个标签数据(对多关系数据),将仅能触发对文章新增的工作流,而同时新增的多个标签将不会触发新增标签的工作流。多对多关系数据的关联和新增时,也不会触发中间表的工作流。 + +### 非应用内的数据操作不会触发 + +另外,通过 HTTP API 调用应用接口对数据表的操作也可以触发相应事件,但如果不通过 NodoBase 应用,而是直接通过数据库操作产生的数据变动,就无法触发相应事件。比如数据库中本身的触发器不会与应用中的工作流产生关联。 + +## 示例 + +以新增一个订单后计算总价并扣减库存的场景举例。 + +首先,我们创建商品表和订单表,数据模型如下: + +| 字段名称 | 字段类型 | +| -------- | -------- | +| 商品名称 | 单行文本 | +| 价格 | 数字 | +| 库存 | 整数 | + +| 字段名称 | 字段类型 | +| -------- | -------------- | +| 订单号 | 自动编号 | +| 订单商品 | 多对一(商品) | +| 订单总价 | 数字 | + +并添加基础的商品数据: + +| 商品名称 | 价格 | 库存 | +| ------------- | ---- | ---- | +| iPhone 14 Pro | 7999 | 10 | +| iPhone 13 Pro | 5999 | 0 | + +然后创建一个基于订单数据表事件的工作流: + +
    + 数据表事件_示例_新增订单触发 +
    + +其中的几个配置项: + +- 数据表:选择“订单”表。 +- 触发时机:选择“新增数据后”触发。 +- 触发条件:留空。 +- 预加载关系数据:勾选“商品”。 + +之后根据流程的逻辑配置其他节点,检查商品库存是否大于 0,大于 0 的扣减库存,否则订单无效删除订单: + +
    + 数据表事件_示例_新增订单流程编排 +
    + +节点的配置会在具体类型的介绍文档中详细说明。 + +启用该工作流,并通过界面新增订单来测试。对“iPhone 14 Pro”下单后,对应商品的库存会扣减为 9,而如果对“iPhone 13 Pro”下单,由于库存不足,订单将被删除。 + +
    + 数据表事件_示例_新增订单执行结果 +
    diff --git a/docs/fr-FR/manual/workflow/triggers/form.md b/docs/fr-FR/manual/workflow/triggers/form.md new file mode 100644 index 000000000..e38a5a2ca --- /dev/null +++ b/docs/fr-FR/manual/workflow/triggers/form.md @@ -0,0 +1,82 @@ +# 表单事件 + +表单提交事件针对 UI 界面中新增和更新数据的表单操作按钮,在表单中点击对应已绑定工作流的按钮后,将触发对应绑定的工作流执行。例如对某个活动发起报名的表单,报名(表单提交)成功后触发相应的流程处理。 + +## 基本使用 + +针对“提交”按钮(含“保存数据”按钮)配置的工作流,将在用户提交对应表单且数据操作完成后被触发。 + +
    + 表单事件_提交按钮 +
    + +针对自定义的“提交至工作流”按钮配置的工作流,将在用户点击对应按钮时,直接将已配置的表单数据提交到对应工作流进行处理。 + +
    + 表单事件_提交至工作流按钮 +
    + +从按钮配置的菜单中选择“绑定工作流”,即可打开绑定配置弹窗。弹窗中可以配置任意多个要触发的工作流,如果一个都不配置,则代表无需触发。针对每一个工作流,需要先限定触发的数据是整个表单的数据还是表单中的某个关系字段的数据,之后再根据所选的数据模型对应的数据表,选择已配置了匹配该表模型的表单工作流。 + +
    + 表单事件_绑定工作流配置_上下文选择 +
    + +
    + 表单事件_绑定工作流配置_工作流选择 +
    + +## 相关提示 + +### 与数据表事件的区别 + +表单提交事件与数据表事件不同的地方在于,表单事件只在配置了绑定工作流的按钮点击后才触发,而如果针对一个数据表有多个不同的新增或更新表单(如针对不同角色的不同界面上),未配置绑定工作流按钮的表单提交时,不会触发。而如果配置了针对数据表事件的工作流,则在任意对应表单提交后,都会触发该工作流。 + +### “提交至工作流”按钮的区别 + +而且针对“提交至工作流”的自定义按钮点击时,提交的数据不会被直接保存到数据表中,而是交给对应的工作流作为上下文数据,由已定义的流程进行特定的处理。上下文中除了表单数据,还会包含提交表单的“当前用户”对象,可以在后续流程中使用。后续处理过程中可以根据提交数据的条件,选择保存到对应数据表,也可以不保存。这种直接交给工作流的表单提交事件,在一定程度上,可以配置为提交申请和审批场景中的流程。 + + + +## 示例 + +普通的“提交”触发与数据表事件类似,这里主要针对“提交至工作流”的方式进行演示。 + +假设一个“报销申请”的场景,我们需要在员工提交费用报销后,进行额度的自动审核和超出额度的人工审核,审核成功的才通过申请,并在之后交由财务处理。 + +首先,我们可以先创建一张“费用报销”数据表,有以下字段: + +- 项目名称:单行文本 +- 申请人:多对一(用户) +- 金额:数字 +- 状态:单选(“审核通过”、“处理完成”) + +之后先创建一个“表单事件”类型的工作流,并且把触发器中的数据表模型配置为“费用报销”表: + +
    + 配置表单事件工作流的数据模型 +
    + +将工作流设置为启用状态后,流程的具体处理节点稍后再回来配置。 + +然后我们在界面上创建“费用报销”数据表的表格区块,并且在工具栏增加一个“添加”按钮,配置对应的表单字段。这里我们不使用默认的“提交”按钮,而是移除后重新添加一个“提交至工作流”的按钮: + +
    + 配置提交表单 +
    + +并打开按钮的“绑定工作流”配置对话框,选择整个表单数据作为上下文,以及工作流为我们之前创建的工作流: + +
    + 配置绑定工作流 +
    + +表单配置完成后,再回到工作流的逻辑编排。比如我们需要金额大于 500 元时要求管理员进行人工审核,否则直接通过,审核通过后才创建报销记录,并由财务进一步处理(略)。 + +
    + 配置绑定工作流 +
    + +忽略后续财务的处理的话,这样就完成了申请报销流程的配置,当员工填写报销申请并提交后,会触发对应的工作流,如果费用金额小于 500,会自动创建记录并等待财务进一步处理,否则会由主管审核,审核通过后也是一样创建记录并交给财务处理。 + +该示例的流程也可以配置在普通“提交”按钮上,可以根据具体的业务场景决定是否需要先创建记录再执行后续的流程。 diff --git a/docs/fr-FR/manual/workflow/triggers/index.md b/docs/fr-FR/manual/workflow/triggers/index.md new file mode 100644 index 000000000..f078bf527 --- /dev/null +++ b/docs/fr-FR/manual/workflow/triggers/index.md @@ -0,0 +1,17 @@ +# 概述 + +触发器是工作流的执行入口,当应用运行过程中满足触发器条件的事件产生时,工作流将会被触发执行。触发器的类型也就是工作流的类型,在创建工作流时选择,创建后不可修改。目前内置的触发器类型如下: + +- 表单事件 +- 数据表事件 +- 定时任务 + +比如用户提交一个表单,或者数据表中的数据由于用户操作或程序调用发生变化,或者定时任务到达执行时间,都会触发对应的工作流执行。 + +与数据有关的触发器(如表单、数据表事件)通常会携带触发上下文数据,这些数据可以在工作流的节点中被引用,用以实现数据的自动化处理。例如当用户提交一个绑定了工作流的表单时,表单提交的数据会被注入到执行计划的上下文环境中,以供后续节点作为变量使用。 + +创建工作流以后,在工作流查看页面中,触发器会以入口节点的样式显示在流程的开始位置,点击该卡片即可打开配置弹窗。根据触发器的类型不同,可以配置触发器的相关条件。 + +
    + 触发器_入口节点 +
    diff --git a/docs/fr-FR/manual/workflow/triggers/schedule.md b/docs/fr-FR/manual/workflow/triggers/schedule.md new file mode 100644 index 000000000..ca6138b0e --- /dev/null +++ b/docs/fr-FR/manual/workflow/triggers/schedule.md @@ -0,0 +1,75 @@ +# 定时任务 + +定时任务是以时间为触发条件的事件,分为两种模式: + +- 自定义时间:常规类似 cron 的按系统时间计划触发 +- 数据表时间字段:按数据表中时间字段的值到时触发 + +系统运行到满足所配置的触发条件的时间点(精度到秒)时,会触发相应的工作流。 + +## 基本使用 + +### 自定义时间模式 + +针对常规的模式,首先需要配置开始时间为任意时间点(精度到秒)。开始时间可以配置为未来的时间,也可以配置为过去的时间。当配置为过去的时间时,会根据配置的重复条件检查是否到时,如果没有配置重复条件,开始时间如果是过去的时间,则工作流不再会被触发。 + +重复规则有两种配置方式: + +- 按间隔时间:开始时间后每固定间隔时间触发,如每一小时,每 30 分钟等。 +- 高级模式:即按 cron 规则,可配置为到达固定规则日期时间的周期。 + +配置了重复规则后,还可以配置结束条件,可以通过固定时间点结束,也可以通过已执行过的次数限制。 + +### 数据表时间字段模式 + +通过数据表的时间字段来确定开始时间,是一种将普通定时任务和数据表时间字段结合的触发模式,使用这个模式可以简化一些特定流程的中的节点,从配置上也更加直观。例如,需要将超时未支付的订单修改为已取消的状态,可以仅配置一个数据表时间字段模式的定时任务,选择开始时间为订单创建后 30 分钟, + +## 相关提示 + +### 未启动或停机状态下的定时任务 + +如果配置的时间条件满足时,但整个 NocoBase 应用服务处在未启动或停机状态,则对应时间点应该触发的定时任务会被错过,且在服务重新启动后,已经错过的任务不会再被触发。所以在使用时可能需要考虑对应情况的处理,或候补措施。 + +### 重复次数 + +配置了结束条件中的按重复次数时,计算的是同一个工作流所有版本执行过的总次数,例如一个定时任务在版本 1 的时候执行过 10 次,如果重复次数也设置了 10 次,该工作流将不再会被触发,即使复制到新版本,也不会被触发,除非将重复次数修改为大于 10 的数字。但如果是复制为新的工作流,已执行的次数将会重新从 0 开始计算,不修改相关配置的情况下,新的工作流将可以再被触发 10 次。 + +### 重复规则中间隔时间与高级模式的区别 + +重复规则中的间隔时间是相对于上一次触发(开始时间)的时间点,而高级模式是按固定的时间点触发,例如,配置了每 30 分钟触发一次,如果上一次触发是 2021-09-01 12:01:23,那么下一次触发时间是 2021-09-01 12:31:23。而高级模式即 cron 模式,配置的规则均为固定的时间点触发,例如,可以配置在每小时的 01 分和 31 分触发。 + +## 示例 + +假设每分钟检查创建后超过 30 分钟未完成支付的订单,并自动修改为已取消状态。分别使用两种模式来实现。 + +### 自定义时间模式 + +创建一个基于定时任务的工作流,触发器配置中选择“自定义时间”模式,开始时间选择任意不晚于当前时间的时间点,重复规则选择“每分钟”,结束条件留空: + +
    + 定时任务_触发器配置_自定义时间模式 +
    + +之后根据流程的逻辑配置其他节点,计算出 30 分钟,如果超时未支付则修改为已取消状态: + +
    + 定时任务_触发器配置_自定义时间模式 +
    + +工作流启用后,从开始时间起每分钟会触发一次,计算 30 分钟前的时间,用于更新创建时间早于该时间点的订单状态为取消。 + +### 数据表时间字段模式 + +创建一个基于定时任务的工作流,触发器配置中选择“数据表时间字段”模式,数据表选择“订单”表,开始时间选择订单的创建时间之后 30 分钟,重复规则选择“不重复”: + +
    + 定时任务_触发器配置_数据表时间字段模式_触发器 +
    + +之后根据流程的逻辑配置其他节点,更新 ID 为触发数据 ID 且状态是“未支付”的订单为取消状态: + +
    + 定时任务_触发器配置_数据表时间字段模式_更新节点 +
    + +与自定义时间模式不同的是,这里不需要计算 30 分钟前的时间,因为工作流触发数据上下文中即包含对应符合时间条件的数据行,所以可以直接更新对应订单的状态。 diff --git a/docs/fr-FR/plugin-samples/block/block-carousel.md b/docs/fr-FR/plugin-samples/block/block-carousel.md new file mode 100644 index 000000000..c3fbec3bb --- /dev/null +++ b/docs/fr-FR/plugin-samples/block/block-carousel.md @@ -0,0 +1,1127 @@ +# `Carousel` 区块 + +## 场景说明 + +NocoBase 有很多 `Add block` 按钮用于向界面添加区块,但是目前已有的区块类型不一定满足我们的需求,我们就需要根据需求自定开发一些区块。 + +其中有些和数据表有关系的被成为数据区块 `Data Block`,有些和数据表无关的被称为简单区块 `Simple Block`,本篇文章就是针对简单区块 `Simple Block` 举例说明。 + +## 示例说明 + +本实例会基于 ant-design 的 [Carousel](https://ant.design/components/carousel) 组件创建 `Carousel` 区块,并将其添加到 `Page`、`Table` 以及移动端的 `Add block` 中。 + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-block-carousel) 中查看。 + + + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-block-carousel +yarn pm enable @nocobase-sample/plugin-block-carousel +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/locale/](http://localhost:13000/admin/pm/list/locale/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +在实现本示例之前,我们需要先了解一些基础知识: + +- [ant-design Carousel](https://ant.design/components/carousel) +- [SchemaInitializer 教程](/development/client/ui-schema/initializer):用于向界面内添加各种区块、字段、操作等 +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于向界面内添加各种区块、字段、操作等 +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 +- [Designable 设计器](/development/client/ui-schema/designable):用于修改 Schema + +```bash +. +├── client # 客户端插件 +│ ├── initializer # 初始化器 +│ ├── component # 区块组件 +│ ├── index.tsx # 客户端插件入口 +│ ├── locale.ts # 多语言工具函数 +│ ├── constants.ts # 常量 +│ ├── schema # Schema +│ └── settings # Schema Settings +├── locale # 多语言文件 +│ ├── en-US.json # 英语 +│ └── zh-CN.json # 中文 +├── index.ts # 服务端插件入口 +└── server # 服务端插件 +``` + +### 1. 定义名称 + +我们首先需要定义区块名称,它将会使用在各个地方。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/constants.ts`: + +```ts +export const BlockName = 'Carousel'; +export const BlockNameLowercase = BlockName.toLowerCase(); +``` + +### 2. 实现区块组件 + +#### 2.1 定义区块组件 + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/component/Carousel.tsx` 文件,其内容如下: + +```tsx | pure +import React, { FC } from 'react'; +import { Carousel as AntdCarousel, Result, CarouselProps as AntdCarouselProps } from 'antd'; +import { withDynamicSchemaProps } from '@nocobase/client'; +import { BlockName } from './constants'; + +export interface CarouselProps extends AntdCarouselProps { + images?: { url: string; title?: string }[]; + /** + * @default 300 + */ + height?: number; + /** + * @default 'cover' + */ + objectFit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'; +} + +export const Carousel: FC = withDynamicSchemaProps((props) => { + const { images, height = 300, objectFit = 'cover', ...carouselProps } = props; + return (images && images.length) ? ( + + {images.map((image) => ( +
    + {image.title} +
    + ))} +
    + ) : +}, { displayName: BlockName }) + +``` + +`Carousel` 组件整体来说是一个被 `withDynamicSchemaProps` 包裹的函数组件,[withDynamicSchemaProps](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) 是一个高阶组件,用于处理 Schema 中的的动态属性。 + +如果不看 `withDynamicSchemaProps` 的话,`Carousel` 组件就是一个简单的函数组件。 + +然后将其在 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/component/index.ts` 中导出: + +```tsx | pure +export * from './Carousel'; +``` + +#### 2.2 注册区块组件 + +我们需要将 `Carousel` 通过插件注册到系统中。 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Carousel } from './component'; + +export class PluginBlockCarouselClient extends Plugin { + async load() { + this.app.addComponents({ Carousel }) + } +} + +export default PluginBlockCarouselClient; +``` + +#### 2.3 验证区块组件 + +组件验证方式有 2 种: + +- 临时页面验证:我们可以临时建一个页面,然后渲染 `Carousel` 组件,查看是否符合需求 +- 文档示例验证:可以启动文档 `yarn doc plugins/@nocobase-sample/plugin-block-carousel`,通过写文档示例的方式验证是否符合需求(TODO) + +我们以 `临时页面验证` 为例,我们新建一个页面,根据属性参数添加一个或者多个 `Carousel` 组件,查看是否符合需求。 + +```tsx | pure +import React from 'react'; +import { Plugin } from '@nocobase/client'; +import { Carousel } from './component'; + +export class PluginBlockCarouselClient extends Plugin { + async load() { + this.app.addComponents({ Carousel }) + + this.app.router.add('admin.carousel-component', { + path: '/admin/carousel-component', + Component: () => { + const images = [{ url: 'https://picsum.photos/id/1/1200/300' }, { url: 'https://picsum.photos/id/2/1200/300' }]; + return <> +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + +
    + +
    + + } + }); + } +} + +export default PluginBlockCarouselClient; +``` + +然后访问 `http://localhost:13000/admin/carousel-component` 就可以看到对应测试页面的内容了。 + + + +验证完毕后需要删除测试页面。 + +### 3. 定义区块 Schema + +#### 3.1 定义区块 Schema + +NocoBase 的动态页面都是通过 Schema 来渲染,所以我们需要定义一个 Schema,后续用于在界面中添加 `Carousel` 区块。在实现本小节之前,我们需要先了解一些基础知识: + +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/schema/index.ts` 文件: + +```tsx | pure +import { ISchema } from '@nocobase/client'; +import { useFieldSchema } from '@formily/react' + +import { BlockName, BlockNameLowercase } from '../constants'; + +export function useCarouselBlockProps() { + const fieldSchema = useFieldSchema(); + return fieldSchema.parent?.['x-decorator-props']?.[BlockNameLowercase] +} + +export const carouselSchema: ISchema = { + type: 'void', + 'x-component': 'CardItem', + 'x-decorator-props': { + [BlockNameLowercase]: {}, + }, + properties: { + carousel: { + type: 'void', + 'x-component': BlockName, + 'x-use-component-props': 'useCarouselBlockProps' + } + } +}; +``` + +`carouselSchema`: + +- `type`:类型,这里是 `void`,表示纯 UI 节点,没有数据 +- `'x-component': 'CardItem'`:[CardItem 组件](https://client.docs.nocobase.com/components/card-item),目前的区块都是被包裹在卡片中的,用于提供样式、布局和拖拽等功能 +- `x-decorator-props`:用于存储 `Carousel` 组件的属性 +- `properties`:子节点 + - `carousel`: + - `'x-component': BlockName`:`Carousel` 组件 + - `'x-use-component-props': 'useCarouselBlockProps'`:用于动态获取 `Carousel` 组件的属性 + +上述 Schema 转为 React 组件后相当于: + +```tsx | pure + + + +``` + +#### 3.2 注册 scope + +我们需要将 `useCarouselBlockProps` 注册到系统中,这样 [x-use-component-props](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) 才能找到对应的 scope。 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Carousel } from './component'; +import { useCarouselBlockProps } from './schema'; + +export class PluginBlockCarouselClient extends Plugin { + async load() { + this.app.addComponents({ Carousel }) + this.app.addScopes({ useCarouselBlockProps }); + } +} + +export default PluginBlockCarouselClient; +``` + +更多关于 Scope 的说明可以查看 [全局注册 Component 和 Scope](/plugin-samples/component-and-scope/global) + +#### 3.3 验证区块 Schema + +同验证组件一样,我们可以通过临时页面验证或者文档示例验证的方式来验证 Schema 是否符合需求。我们这里以临时页面验证为例: + +```tsx | pure +import React from 'react'; +import { Plugin, SchemaComponent } from '@nocobase/client'; +import { Carousel } from './component'; +import { carouselSchema } from './schema'; + +export class PluginBlockCarouselClient extends Plugin { + async load() { + this.app.addComponents({ Carousel }) + this.app.addScopes({ useCarouselBlockProps }); + + this.app.router.add('admin.carousel-schema', { + path: '/admin/carousel-schema', + Component: () => { + const images = [{ url: 'https://picsum.photos/id/1/1200/300' }, { url: 'https://picsum.photos/id/2/1200/300' }]; + return <> +
    + +
    +
    + +
    +
    + +
    +
    + +
    + + } + }); + } +} + +export default PluginBlockCarouselClient; +``` + +关于 `SchemaComponent` 的详细说明可以查看 [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) 文档。 + +我们访问 [http://localhost:13000/admin/carousel-schema](http://localhost:13000/admin/carousel-schema) 就可以看到对应测试页面的内容了。 + + + +验证完毕后需要删除测试页面。 + +### 4. 定义 Schema Initializer Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/initializer/index.ts` 文件: + +```ts +import { SchemaInitializerItemType, useSchemaInitializer } from '@nocobase/client'; + +import { carouselSchema } from '../schema'; +import { BlockName, BlockNameLowercase } from '../constants'; +import { useT } from '../locale'; + +export const carouselInitializerItem: SchemaInitializerItemType = { + type: 'item', + name: BlockNameLowercase, + icon: 'PlayCircleOutlined', + useComponentProps() { + const { insert } = useSchemaInitializer(); + const t = useT(); + return { + title: t(BlockName), + onClick: () => { + insert(carouselSchema); + }, + }; + }, +} +``` + +- `type`:类型,这里是 `item`,表示是一个文本,其有点击事件,点击后可以插入一个新的 Schema +- `name`:唯一标识符,用于区分不同的 Schema Item 和增删改查操作 +- `icon`:图标,更多 icon 可以参考 [Ant Design Icons](https://ant.design/components/icon) +- `useComponentProps`:返回一个对象,包含 `title` 和 `onClick` 两个属性,`title` 是显示的文本,`onClick` 是点击后的回调函数 +- [useSchemaInitializer()](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#useschemainitializer):用于获取 `SchemaInitializerContext` 上下文 + - `insert`:插入一个新的 Schema +- `useT()`:用于获取多语言工具函数 + +更多关于 Schema Item 的定义可以参考 [Schema Initializer Item](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#built-in-components-and-types) 文档。 + +### 5. 添加到 Add block 中 + +系统中有很多个 `Add block` 按钮,但他们的 **name 是不同的**。 + +![img_v3_02b4_049b0a62-8e3b-420f-adaf-a6350d84840g](https://static-docs.nocobase.com/img_v3_02b4_049b0a62-8e3b-420f-adaf-a6350d84840g.jpg) + +#### 5.1 添加到页面级别 Add block 中 + +如果我们需要添加到页面级别的 `Add block` 中,我们需要知道对应的 `name`,我们可以通过 TODO 方式查看对应的 `name`。 + +TODO + +通过上图可以看到页面级别的 `Add block` 对应的 name 为 `page:addBlock`,`Other Blocks` 对应的 name 为 `otherBlocks`。 + +然后我们修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/index.tsx` 文件: + +```tsx | pure +import { Plugin } from '@nocobase/client'; + +import { Carousel } from './component'; +import { carouselSchema, useCarouselBlockProps } from './schema'; +import { carouselSettings } from './settings'; +import { carouselInitializerItem } from './initializer'; + +export class PluginBlockCarouselClient extends Plugin { + async load() { + this.app.addComponents({ Carousel }) + this.app.schemaSettingsManager.add(carouselSettings); + this.app.addScopes({ useCarouselBlockProps }); + + this.app.schemaInitializerManager.addItem('page:addBlock', `otherBlocks.${carouselInitializerItem.name}`, carouselInitializerItem) + } +} + +export default PluginBlockCarouselClient; +``` + +上述代码首先将 `Carousel` 组件注册到系统中,这样前面 `carouselSchema` 定义的 `x-component: 'Carousel'` 才能找到对应的组件,更多详细解释可以查看 [全局注册 Component 和 Scope](/plugin-samples/component-and-scope/global)。 + +然后将 `carouselSettings` 通过 [app.schemaSettingsManager.add](https://client.docs.nocobase.com/core/ui-schema/schema-settings-manager#schemasettingsmanageradd) 添加到系统中。 + +然后使用 [app.schemaInitializerManager.addItem](https://client.docs.nocobase.com/core/ui-schema/schema-initializer-manager#schemainitializermanageradditem) 将 `carouselInitializerItem` 添加对应 Initializer 子项中,其中 `page:addBlock` 是页面上 `Add block` 的 name,`otherBlocks` 是其父级的 name。 + +然后我们 hover `Add block` 按钮,就可以看到 `Image` 这个新的区块类型了,点击 `Image`,就可以添加一个新的 `Carousel` 区块了。 + +![20240603161730](https://static-docs.nocobase.com/20240603161730.png) + +#### 5.2 添加到弹窗 Add block 中 + +我们不仅需要将其添加到页面级别的 `Add block` 中,还需要将其添加到 `Table` 区块 `Add new` 弹窗的 `Add block` 中。 + +![img_v3_02b4_fc47fe3a-35a1-4186-999c-0b48e6e001dg](https://static-docs.nocobase.com/img_v3_02b4_fc47fe3a-35a1-4186-999c-0b48e6e001dg.jpg) + +我们按照页面级别获取 `name` 的方式获取到 `Table` 区块的 `Add block` 的 `name` 为 `popup:addNew:addBlock`,`Other Blocks` 对应的 name 为 `otherBlocks`。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/index.tsx` 文件: + +```diff +export class PluginBlockCarouselClient extends Plugin { + async load() { + // ... ++ this.app.schemaInitializerManager.addItem('popup:addNew:addBlock', `otherBlocks.${carouselInitializerItem.name}`, carouselInitializerItem) + } +} +``` + +![20240603161814](https://static-docs.nocobase.com/20240603161814.png) + +#### 5.3 添加到移动端 Add block 中 + +> 首先要激活移动端插件,参考 [激活插件](/welcome/getting-started/plugin#3-activate-the-plugin) 文档。 + +我们可以将其添加到移动端的 `Add block` 中,获取 `name` 的方法这里就不再赘述了。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/index.tsx` 文件: + +```diff +export class PluginBlockCarouselClient extends Plugin { + async load() { + // ... ++ this.app.schemaInitializerManager.addItem('mobilePage:addBlock', `otherBlocks.${carouselInitializerItem.name}`, carouselInitializerItem) + } +} +``` + +![20240603161913](https://static-docs.nocobase.com/20240603161913.png) + +如果需要更多的 `Add block`,可以继续添加,只需要知道对应的 `name` 即可。 + +### 6. 实现 Schema Settings + +#### 6.1 定义 Schema Settings + +一个完整的 Block 还需要有 Schema Settings,用于配置一些属性和操作。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/index.ts` 文件: + +```ts | pure +import { SchemaSettings } from "@nocobase/client"; +import { BlockNameLowercase } from '../constants'; + +export const carouselSettings = new SchemaSettings({ + name: `blockSettings:${BlockNameLowercase}`, + items: [ + // TODO + ] +}); +``` + +#### 6.2 注册 Schema Settings + +```ts +import { Plugin } from '@nocobase/client'; +import { carouselSettings } from './settings'; + +export class PluginBlockCarouselClient extends Plugin { + async load() { + // ... + this.app.schemaSettingsManager.add(carouselSettings) + } +} + +export default PluginBlockCarouselClient; +``` + +#### 6.3 使用 Schema Settings + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/schema/index.ts` 中的 `carouselSchema`: + +```diff ++ import { carouselSettings } from "../settings"; + +const carouselSchema: ISchema = { + type: 'void', + 'x-decorator': 'CardItem', ++ 'x-settings': carouselSettings.name, + // ... +}; +``` + +![20240603162037](https://static-docs.nocobase.com/20240603162037.png) + +### 7. 实现 Schema Settings items + +目前我们只实现了 `Schema Settings`,但是没有实现任何操作,我们需要根据需求实现各个操作。 + +目前 Schema Settings 支持的内置操作类型请参考 [Schema Settings - Built-in Components and Types](https://client.docs.nocobase.com/core/ui-schema/schema-settings#built-in-components-and-types) 文档。 + +#### 7.1 实现 `remove` 操作 + +目前通过 initializers 添加的区块是无法删除的,我们需要实现 `remove` 操作。 + +[NocoBase] 内置了 [remove](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsremove-1) 操作类型,我们修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/index.ts` 文件: + +```diff +import { SchemaSettings } from '@nocobase/client'; +import { BlockNameLowercase } from '../constants'; + +export const carouselSettings = new SchemaSettings({ + name: `blockSettings:${BlockNameLowercase}`, + items: [ ++ { ++ type: 'remove', ++ name: 'remove', ++ componentProps: { ++ removeParentsIfNoChildren: true, ++ breakRemoveOn: { ++ 'x-component': 'Grid', ++ }, ++ } ++ } + ] +}); +``` + +- componentProps + - `removeParentsIfNoChildren`:如果没有子节点,是否删除父节点 + - `breakRemoveOn`:删除时的中断条件。因为 `Add Block` 会自动将子项的包裹在 `Grid` 中,所以这里设置 `breakRemoveOn: { 'x-component': 'Grid' }`,当删除 `Grid` 时,不再向上删除。 + + + +#### 7.2 实现 `Edit Block title` 操作 + +我们可以实现一个 `Edit Block title` 操作,用于修改区块的标题。 + +因为编辑区块标题是一个通用的逻辑,所以 NocoBase 提供了 SchemaSettingsBlockTitleItem(文档 TODO) 组件,我们可以直接使用。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/index.ts`: + +```diff +- import { SchemaSettingsBlockTitleItem } from "@nocobase/client"; ++ import { SchemaSettings, SchemaSettingsBlockTitleItem } from "@nocobase/client"; + +import { SchemaSettings, SchemaSettingsBlockTitleItem } from '@nocobase/client'; +import { BlockNameLowercase } from '../constants'; +import { heightSchemaSettingsItem } from './items/height'; +import { objectFitSchemaSettingsItem } from './items/objectFit'; +import { imagesSchemaSettingsItem } from './items/images'; +import { autoplaySchemaSettingsItem } from './items/autoplay'; + +export const carouselSettings = new SchemaSettings({ + name: `blockSettings:${BlockNameLowercase}`, + items: [ ++ { ++ name: 'editBlockTitle', ++ Component: SchemaSettingsBlockTitleItem, ++ }, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + + + +更多可以复用的 SchemaSettings items 可以查看 TODO。 + +#### 7.3 实现 `Edit Images` 操作 + +我们可以实现一个 `Edit Images` 操作,用于修改轮播的的图片。 + +##### 7.3.1 定义 Schema Settings item + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/items/images.ts` 文件: + +```ts +import { SchemaSettingsItemType, useDesignable, } from "@nocobase/client"; +import { useFieldSchema } from '@formily/react'; + +import { BlockNameLowercase } from "../../constants"; +import { useT } from "../../locale"; + +export const imagesSchemaSettingsItem: SchemaSettingsItemType = { + name: 'images', + type: 'actionModal', + useComponentProps() { + const filedSchema = useFieldSchema(); + const { deepMerge } = useDesignable(); + const t = useT(); + + return { + title: t('Edit Images'), + schema: { + type: 'object', + title: t('Edit Images'), + properties: { + src: { + title: t('Images'), + type: 'string', + default: filedSchema['x-decorator-props'][BlockNameLowercase]?.images ?? [], + 'x-decorator': 'FormItem', + 'x-component': 'Upload.Attachment', + 'x-component-props': { + action: 'attachments:create', + multiple: true + }, + }, + }, + }, + onSubmit({ src: images }: any) { + deepMerge({ + 'x-uid': filedSchema['x-uid'], + 'x-decorator-props': { + ...filedSchema['x-decorator-props'], + [BlockNameLowercase]: { + ...filedSchema['x-decorator-props']?.[BlockNameLowercase], + images, + }, + }, + }) + } + }; + }, +}; +``` + +关于 SchemaSettings Item 的定义可以查看 [SchemaSettingsItem](https://client.docs.nocobase.com/core/ui-schema/schema-settings#optionsitems)。 + +- `type`:内置类型。[actionModal](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsactionmodalitem) 为弹窗类型 +- `name`:唯一标识,用于增删改查 +- `useComponentProps`:返回 `actionModal` 对应组件 `SchemaSettingsActionModalItem` 的属性 + +`useComponentProps`: + +- Hooks + - `useFieldSchema`:获取当前节点 schema + - `useDesignable`:获取当前 Designable 实例,deepMerge 用于合并 schema + - `x-uid`:当前节点的唯一标识 + - `x-decorator-props`:当前节点的属性,存储了 `carousel` 的属性 + +- Props + - `title`:弹窗标题 + - `schema`:弹窗表单 schema + - [Upload.Attachment](https://client.docs.nocobase.com/components/upload):上传组件 + - [FormItem](https://client.docs.nocobase.com/components/form-item):表单项 + - `onSubmit`:表单提交事件 + +##### 7.3.2 使用 SchemaSettings Item + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/index.ts`: + +```diff +// ... ++ import { imagesSchemaSettingsItem } from "./items/images"; + +export const carouselSettings = new SchemaSettings({ + name: `blockSettings:${BlockNameLowercase}`, + items: [ + { + name: 'editBlockTitle', + Component: SchemaSettingsBlockTitleItem, + }, ++ imagesSchemaSettingsItem, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + + + +#### 7.4 实现 Edit Height + +##### 7.4.1 实现 SchemaSettings Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/items/height.ts` 文件: + +```ts +import { SchemaSettingsItemType, useDesignable, } from "@nocobase/client"; +import { useFieldSchema } from '@formily/react'; + +import { BlockNameLowercase } from "../../constants"; +import { useT } from "../../locale"; + +export const heightSchemaSettingsItem: SchemaSettingsItemType = { + name: 'height', + type: 'actionModal', + useComponentProps() { + const filedSchema = useFieldSchema(); + const { deepMerge } = useDesignable(); + const t = useT(); + + return { + title: t('Edit Height'), + schema: { + type: 'object', + title: t('Edit Height'), + properties: { + height: { + title: t('Height'), + type: 'number', + default: filedSchema['x-decorator-props']?.[BlockNameLowercase]?.height, + 'x-decorator': 'FormItem', + 'x-component': 'InputNumber', + }, + }, + }, + onSubmit({ height }: any) { + deepMerge({ + 'x-uid': filedSchema['x-uid'], + 'x-decorator-props': { + ...filedSchema['x-decorator-props'], + [BlockNameLowercase]: { + ...filedSchema['x-decorator-props']?.[BlockNameLowercase], + height, + }, + }, + }) + } + }; + }, +}; +``` + +关于 SchemaSettings Item 的定义可以查看 [SchemaSettingsItem](https://client.docs.nocobase.com/core/ui-schema/schema-settings#optionsitems)。 + +- `type`:内置类型。[actionModal](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsactionmodalitem) 为弹窗类型 +- `name`:唯一标识,用于增删改查 +- `useComponentProps`:返回 `actionModal` 对应组件 `SchemaSettingsActionModalItem` 的属性 + +`useComponentProps`: + +- Hooks + - `useFieldSchema`:获取当前节点 schema + - `useDesignable`:获取当前 Designable 实例,deepMerge 用于合并 schema + - `x-uid`:当前节点的唯一标识 + - `x-decorator-props`:当前节点的属性,存储了 `carousel` 的属性 + +- Props + - `title`:弹窗标题 + - `schema`:弹窗表单 schema + - [InputNumber](https://client.docs.nocobase.com/components/input-number):数字输入框 + - [FormItem](https://client.docs.nocobase.com/components/form-item):表单项 + - `onSubmit`:表单提交事件 + +##### 7.4.2 使用 SchemaSettings Item + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/index.ts`: + +```diff +// ... ++ import { heightSchemaSettingsItem } from "./items/height"; + +export const carouselSettings = new SchemaSettings({ + name: `blockSettings:${BlockNameLowercase}`, + items: [ + { + name: 'editBlockTitle', + Component: SchemaSettingsBlockTitleItem, + }, + imagesSchemaSettingsItem, ++ heightSchemaSettingsItem, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + + +#### 7.5 实现 ObjectFit + +##### 7.5.1 实现 SchemaSettings Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/items/objectFit.ts` 文件: + +```ts +import { SchemaSettingsItemType, useDesignable, } from "@nocobase/client"; +import { useFieldSchema } from '@formily/react'; +import { BlockNameLowercase } from "../../constants"; +import { useT } from "../../locale"; + +export const objectFitSchemaSettingsItem: SchemaSettingsItemType = { + name: 'objectFit', + type: 'select', + useComponentProps() { + const filedSchema = useFieldSchema(); + const { deepMerge } = useDesignable(); + const t = useT(); + + return { + title: t('Object Fit'), + options: [ + { label: 'Cover', value: 'cover' }, + { label: 'Contain', value: 'contain' }, + { label: 'Fill', value: 'fill' }, + { label: 'None', value: 'none' }, + { label: 'Scale Down', value: 'scale-down' }, + ], + value: filedSchema['x-decorator-props']?.[BlockNameLowercase]?.objectFit || 'cover', + onChange(v) { + deepMerge({ + 'x-uid': filedSchema['x-uid'], + 'x-decorator-props': { + ...filedSchema['x-decorator-props'], + [BlockNameLowercase]: { + ...filedSchema['x-decorator-props']?.[BlockNameLowercase], + objectFit: v, + }, + }, + }) + }, + }; + }, +}; +``` + +关于 SchemaSettings Item 的定义可以查看 [SchemaSettingsItem](https://client.docs.nocobase.com/core/ui-schema/schema-settings#optionsitems)。 + +- `type`:内置类型。[select](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsselectitem) 为选择类型 +- `name`:唯一标识,用于增删改查 +- `useComponentProps`:返回 `select` 对应组件 `SchemaSettingsSelectItem` 的属性 + +`useComponentProps`: + +- Hooks + - `useFieldSchema`:获取当前节点 schema + - `useDesignable`:获取当前 Designable 实例,deepMerge 用于合并 schema + - `x-uid`:当前节点的唯一标识 + - `x-decorator-props`:当前节点的属性,存储了 `carousel` 的属性 + +- Props + - `title`:弹窗标题 + - `options`:选择项 + - `value`:默认值 + - `onChange`:选择事件 + +##### 7.5.2 使用 SchemaSettings Item + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/index.ts`: + +```diff +// ... ++ import { objectFitSchemaSettingsItem } from "./items/objectFit"; + +export const carouselSettings = new SchemaSettings({ + name: `blockSettings:${BlockNameLowercase}`, + items: [ + { + name: 'editBlockTitle', + Component: SchemaSettingsBlockTitleItem, + }, + imagesSchemaSettingsItem, + heightSchemaSettingsItem, ++ objectFitSchemaSettingsItem, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + + + +#### 7.6 实现 Autoplay + +##### 7.6.1 实现 SchemaSettings Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/items/autoplay.ts` 文件: + +```ts +import { SchemaSettingsItemType, useDesignable, } from "@nocobase/client"; +import { useFieldSchema } from '@formily/react'; + +import { BlockNameLowercase } from "../../constants"; +import { useT } from "../../locale"; + +export const autoplaySchemaSettingsItem: SchemaSettingsItemType = { + name: 'autoplay', + type: 'switch', + useComponentProps() { + const filedSchema = useFieldSchema(); + const { deepMerge } = useDesignable(); + const t = useT(); + + return { + title: t('Autoplay'), + checked: !!filedSchema['x-decorator-props']?.[BlockNameLowercase]?.autoplay, + onChange(v) { + deepMerge({ + 'x-uid': filedSchema['x-uid'], + 'x-decorator-props': { + ...filedSchema['x-decorator-props'], + [BlockNameLowercase]: { + ...filedSchema['x-decorator-props']?.[BlockNameLowercase], + autoplay: v, + }, + }, + }) + }, + }; + }, +}; +``` + +关于 SchemaSettings Item 的定义可以查看 [SchemaSettingsItem](https://client.docs.nocobase.com/core/ui-schema/schema-settings#optionsitems)。 + +- `type`:内置类型。[switch](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsswitchitem) 为开关类型 +- `name`:唯一标识,用于增删改查 +- `useComponentProps`:返回 `switch` 对应组件 `SchemaSettingsSwitchItem` 的属性 + +`useComponentProps`: + +- Hooks + - `useFieldSchema`:获取当前节点 schema + - `useDesignable`:获取当前 Designable 实例,deepMerge 用于合并 schema + - `x-uid`:当前节点的唯一标识 + - `x-decorator-props`:当前节点的属性,存储了 `carousel` 的属性 + +- Props + - `title`:弹窗标题 + - `checked`:默认值 + - `onChange`:开关事件 + + +##### 7.6.2 使用 SchemaSettings Item + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/index.ts`: + +```diff +// ... ++ import { autoplaySchemaSettingsItem } from "./items/autoplay"; + +export const carouselSettings = new SchemaSettings({ + name: `blockSettings:${BlockNameLowercase}`, + items: [ + { + name: 'editBlockTitle', + Component: SchemaSettingsBlockTitleItem, + }, + imagesSchemaSettingsItem, + heightSchemaSettingsItem, + objectFitSchemaSettingsItem, ++ autoplaySchemaSettingsItem, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + + + +#### 7.7 增加 divider + +`editBlockTitle` 和 `remove` 是一个通用的逻辑,而 `src`、`height`、`objectFit`、`autoplay` 是针对 `Image` 的配置,我们可以通过 `divider` 来区分。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/client/settings/index.ts`: + +```diff +// ... +export const carouselSettings = new SchemaSettings({ + name: `blockSettings:${BlockNameLowercase}`, + items: [ + { + name: 'editBlockTitle', + Component: SchemaSettingsBlockTitleItem, + }, ++ { ++ name: 'divider1', ++ type: 'divider' ++ }, + imagesSchemaSettingsItem, + heightSchemaSettingsItem, + objectFitSchemaSettingsItem, + autoplaySchemaSettingsItem, ++ { ++ name: 'divider2', ++ type: 'divider' ++ }, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + +![20240603162933](https://static-docs.nocobase.com/20240603162933.png) + +### 8. 权限 + +TODO + +### 9. 多语言 + +#### 9.1 英文 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/locale/en-US.json` 文件: + +```json +{ + "Carousel": "Carousel", + "Edit Images": "Edit Images", + "Images": "Images", + "Autoplay": "Autoplay", + "Edit Height": "Edit Height", + "Height": "Height" +} +``` + +#### 9.2 中文 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-block-carousel/src/locale/zh-CN.json` 文件: + +```json +{ + "Carousel": "走马灯", + "Edit Images": "编辑图片", + "Images": "图片", + "Autoplay": "自动播放", + "Edit Height": "编辑高度", + "Height": "高度" +} +``` + +我们可以通过 [http://localhost:13000/admin/settings/system-settings](http://localhost:13000/admin/settings/system-settings) 添加多个语言,并且在右上角切换语言。 + +![20240611113758](https://static-docs.nocobase.com/20240611113758.png) + +![20240611114018](https://static-docs.nocobase.com/20240611114018.png) + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-block-carousel --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-block-carousel.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugin-samples/block/block-form.md b/docs/fr-FR/plugin-samples/block/block-form.md new file mode 100644 index 000000000..666711159 --- /dev/null +++ b/docs/fr-FR/plugin-samples/block/block-form.md @@ -0,0 +1,1172 @@ +# `Form` 区块 + +## 场景说明 + +`Form` 区块是 NocoBase 中最重要的区块之一,它用于展示和编辑数据表的数据。文本会详细介绍 `Form` 区块实现。 + + + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-block-form +yarn pm enable @nocobase-sample/plugin-block-form +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/locale/](http://localhost:13000/admin/pm/list/locale/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +在实现本示例之前,我们需要先了解一些基础知识: + +- [ant-design Form](https://ant.design/components/form) +- [@formily/antd-v5 Form](https://antd5.formilyjs.org/components/form) +- [SchemaInitializer 教程](/development/client/ui-schema/initializer):用于向界面内添加各种区块、字段、操作等 +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于向界面内添加各种区块、字段、操作等 +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 +- [Designable 设计器](/development/client/ui-schema/designable):用于修改 Schema + +```bash +. +├── client # 客户端插件 +│ ├── FormV3.configActions # 配置初始化器 +│ ├── index.ts +│ └── items +│ └── submit # 提交操作 +│ ├── index.ts +│ ├── initializer.tsx +│ ├── schema.ts +│ └── settings.ts +│ ├── FormV3.configFields # 字段初始化器 +│ ├── FormV3.settings # 设置 +│ ├── FormV3.initializer.ts # 初始化器 +│ ├── FormV3.schema.ts # Schema +│ ├── FormV3.tsx # Component +│ ├── index.tsx # 客户端插件入口 +│ └── locale.ts # 多语言工具函数 +├── locale # 多语言文件 +│ ├── en-US.json # 英语 +│ └── zh-CN.json # 中文 +├── index.ts # 服务端插件入口 +└── server # 服务端插件 +``` + +### 1. 定义名称 + +我们首先需要定义区块名称,它将会使用在各个地方。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/constants.ts`: + +```ts +export const FormV3BlockName = 'FormV3'; +export const FormV3BlockNameLowercase = 'form-v3'; +``` + +> 为了不与已有的 `Form` 组件冲突,我们这里将其命名为 `FormV3` + +### 2. 实现区块组件 + +#### 2.1 定义区块组件 + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.tsx` 文件,其内容如下: + +```tsx | pure +import React, { FC } from 'react'; +import { Form, FormProps } from '@formily/antd-v5'; +import { withDynamicSchemaProps } from '@nocobase/client'; +import { FormV3BlockName } from './constants' + +export interface FormV3Props extends FormProps { + children?: React.ReactNode; +} + +export const FormV3: FC = withDynamicSchemaProps((props) => { + return
    +}, { displayName: FormV3BlockName }); +``` + +`Form` 组件整体来说是一个被 `withDynamicSchemaProps` 包裹的函数组件,[withDynamicSchemaProps](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) 是一个高阶组件,用于处理 Schema 中的的动态属性。 + +如果不看 `withDynamicSchemaProps` 的话,`Form` 组件就是一个简单的函数组件。 + +#### 2.2 注册区块组件 + +我们需要将 `FormV3` 通过插件注册到系统中。 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { FormV3 } from './FormV3'; + +export class PluginBlockFormClient extends Plugin { + async load() { + this.app.addComponents({ FormV3 }) + } +} + +export default PluginBlockFormClient; +``` + +#### 2.3 验证区块组件 + +组件验证方式有 2 种: + +- 临时页面验证:我们可以临时建一个页面,然后渲染 `Form` 组件,查看是否符合需求 +- 文档示例验证:可以启动文档 `yarn doc plugins/@nocobase-sample/plugin-block-form`,通过写文档示例的方式验证是否符合需求(TODO) + +我们以 `临时页面验证` 为例,我们新建一个页面,根据属性参数添加一个或者多个 `Form` 组件,查看是否符合需求。 + +```tsx | pure +import React from 'react'; +import { Plugin, SchemaComponent } from '@nocobase/client'; +import { FormV3 } from './FormV3'; + +export class PluginBlockFormClient extends Plugin { + async load() { + this.app.addComponents({ FormV3 }) + + this.app.router.add('admin.block-form-component', { + path: '/admin/block-form-component', + Component: () => { + return + + + } + }); + } +} + +export default PluginBlockFormClient; +``` + +然后访问 `http://localhost:13000/admin/form-component` 就可以看到对应测试页面的内容了。 + +![20240718175735](https://static-docs.nocobase.com/20240718175735.png) + +验证完毕后需要删除测试页面。 + +### 3. 定义区块 Schema + +#### 3.1 定义区块 Schema + +NocoBase 的动态页面都是通过 Schema 来渲染,所以我们需要定义一个 Schema,后续用于在界面中添加 `Form` 区块。在实现本小节之前,我们需要先了解一些基础知识: + +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.schema.ts` 文件: + +```tsx | pure +import { ISchema, useDataBlockProps } from "@nocobase/client"; + +import { FormV3BlockName, FormV3BlockNameLowercase } from "./constants"; +import { FormV3Props } from "./FormV3"; + +export function useFormV3Props(): FormV3Props { + const blockProps = useDataBlockProps(); + return blockProps[FormV3BlockNameLowercase]; +} + +interface GetFormV3SchemaOptions { + dataSource?: string; + collection: string; + properties?: ISchema['properties']; +} + +export function getFormV3Schema(options: GetFormV3SchemaOptions): ISchema { + const { dataSource, collection, properties = {} } = options; + return { + type: 'void', + 'x-component': 'CardItem', + 'x-decorator': 'DataBlockProvider', + 'x-decorator-props': { + dataSource, + collection, + [FormV3BlockNameLowercase]: {}, + }, + properties: { + [FormV3BlockNameLowercase]: { + type: 'void', + 'x-component': FormV3BlockName, + 'x-use-component-props': 'useFormV3Props', + properties: { + ...properties, + } + }, + } + } +} +``` + +`getFormV3Schema`: + - `type`:类型,这里是 `void`,表示纯 UI 节点,没有数据 + - `'x-component': 'CardItem'`:[CardItem 组件](https://client.docs.nocobase.com/components/card-item),目前的区块都是被包裹在卡片中的,用于提供样式、布局和拖拽等功能 + - `x-decorator: 'DataBlockProvider'`:数据区块提供者,用于提供数据,更多关于 DataBlockProvider 可以查看 [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider) + - `x-decorator-props`:`DataBlockProvider` 的属性 + - `dataSource`:数据源 + - `collection`:数据表 + - `[FormV3BlockNameLowercase]: {}`:`FormV3` 组件的属性 + - `properties: { [FormV3BlockNameLowercase]: { ... } }`:子节点 + - `[FormV3BlockNameLowercase]`:`FormV3` 组件的属性 + - `'x-component': FormV3BlockName`:`FormV3` 组件 + - `'x-use-component-props': 'useFormV3Props'`:使用 [x-use-component-props](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) 获取 `FormV3` 组件的属性 + - `"x-toolbar": "BlockSchemaToolbar"`:`BlockSchemaToolbar` 用于左上角显示当前数据表,一般和 `DataBlockProvider` 搭配使用 + +`useFormV3Props`:Hooks,用于获取 `FormV3` 组件的属性 + - [useDataBlockProps](https://client.docs.nocobase.com/core/data-block/data-block-provider#usedatablockprops):获取 [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider) 的 props 属性,也就是 `x-decorator-props` 的值 + - `blockProps[FormV3BlockNameLowercase]`:对应 `FormV3` 组件的属性 + +上述 Schema 转为 React 组件后相当于: + +```tsx | pure + + + + {children} + + + +``` + +#### 3.2 注册 scope + +我们需要将 `useFormV3Props` 注册到系统中,这样 [x-use-component-props](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) 才能找到对应的 scope。 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { FormV3 } from './FormV3'; +import { useFormV3Props } from './FormV3.schema'; + +export class PluginBlockFormClient extends Plugin { + async load() { + this.app.addComponents({ FormV3 }) + this.app.addScopes({ useFormV3Props }); + } +} + +export default PluginBlockFormClient; +``` + +更多关于 Scope 的说明可以查看 [全局注册 Component 和 Scope](/plugin-samples/component-and-scope/global) + +#### 3.3 验证区块 Schema + +同验证组件一样,我们可以通过临时页面验证或者文档示例验证的方式来验证 Schema 是否符合需求。我们这里以临时页面验证为例: + +```tsx | pure +import React from 'react'; +import { Plugin, SchemaComponent } from '@nocobase/client'; +import { FormV3 } from './FormV3'; +import { useFormV3Props, getFormV3Schema } from './FormV3.schema'; + +import { useForm } from '@formily/react'; +function useSubmitActionProps(): ActionProps { + const form = useForm(); + + return { + type: 'primary', + htmlType: 'submit', + async onClick() { + await form.submit(); + const values = form.values; + + console.log('values', values); + }, + }; +} + +export class PluginBlockFormClient extends Plugin { + async load() { + this.app.addComponents({ FormV3 }) + this.app.addScopes({ useFormV3Props }); + + this.app.router.add('admin.block-form-schema', { + path: '/admin/block-form-schema', + Component: () => { + return <> +
    + +
    + + } + }) + } +} + +export default PluginBlockFormClient; +``` + +关于 `SchemaComponent` 的详细说明可以查看 [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) 文档。 + +我们访问 [http://localhost:13000/admin/block-form-schema](http://localhost:13000/admin/block-form-schema) 就可以看到对应测试页面的内容了。 + +![20240718180826](https://static-docs.nocobase.com/20240718180826.png) + +验证完毕后需要删除测试页面。 + +### 4. 定义 Schema Initializer Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.initializer.tsx` 文件: + +```ts +import React from 'react'; +import { SchemaInitializerItemType, useSchemaInitializer } from '@nocobase/client' +import { FormOutlined } from '@ant-design/icons'; + +import { getFormV3Schema } from './FormV3.schema' +import { FormV3BlockName } from './constants'; +import { useT } from './locale'; + +export const formV3InitializerItem: SchemaInitializerItemType = { + name: FormV3BlockName, + Component: 'DataBlockInitializer', + useComponentProps() { + const { insert } = useSchemaInitializer(); + const t = useT(); + + return { + title: t(FormV3BlockName), + icon: , + componentType: FormV3BlockName, + onCreateBlockSchema({ item }) { + insert(getFormV3Schema({ dataSource: item.dataSource, collection: item.name })) + }, + }; + }, +} +``` + +`formV3InitializerItem`: + +- `Component`:与 [添加简单区块 Simple Block](/plugin-samples/schema-initializer/block-simple) 中使用的是 `type`,这里使用的是 `Component`,[2 种定义方式](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#two-ways-to-define-component-and-type) 都是可以的 +- `useComponentProps`:`DataBlockInitializer` 组件的属性 + - `title`:标题 + - `icon`:图标,更多图标可以查看 [Ant Design Icons](https://ant.design/components/icon/) + - `componentType`:组件类型,这里是 `Info` + - `onCreateBlockSchema`:当点击数据表后的回调 + - `item`:点击的数据表信息 + - `item.name`:数据表名称 + - `item.dataSource`:数据表所属的数据源 + - [useSchemaInitializer](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#useschemainitializer):提供了插入 Schema 的方法 + +更多关于 Schema Initializer 的定义可以参考 [Schema Initializer](https://client.docs.nocobase.com/core/ui-schema/schema-initializer) 文档。 + +### 5. 添加到 Add block 中 + +系统中有很多个 `Add block` 按钮,但他们的 **name 是不同的**。 + +![img_v3_02b4_049b0a62-8e3b-420f-adaf-a6350d84840g](https://static-docs.nocobase.com/img_v3_02b4_049b0a62-8e3b-420f-adaf-a6350d84840g.jpg) + +如果我们需要添加到页面级别的 `Add block` 中,我们需要知道对应的 `name`,我们可以通过 TODO 方式查看对应的 `name`。 + +TODO + +通过上图可以看到页面级别的 `Add block` 对应的 name 为 `page:addBlock`,`Data Blocks` 对应的 name 为 `dataBlocks`。 + +然后我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/index.tsx` 文件: + +```tsx | pure +import { Plugin } from '@nocobase/client'; + +import { FormV3 } from './FormV3'; +import { useFormV3Props } from './FormV3.schema'; +import { formV3InitializerItem } from './FormV3.initializer'; + +export class PluginBlockFormClient extends Plugin { + async load() { + this.app.addComponents({ FormV3 }) + this.app.addScopes({ useFormV3Props }); + + this.app.schemaInitializerManager.addItem('page:addBlock', `dataBlocks.${formV3InitializerItem.name}`, formV3InitializerItem); + } +} + +export default PluginBlockFormClient; +``` + +这里使用 [app.schemaInitializerManager.addItem](https://client.docs.nocobase.com/core/ui-schema/schema-initializer-manager#schemainitializermanageradditem) 将 `formV3InitializerItem` 添加对应 Initializer 子项中,其中 `page:addBlock` 是页面上 `Add block` 的 name,`dataBlocks` 是其父级的 name。 + +然后我们 hover `Add block` 按钮,就可以看到 `FormV3` 这个新的区块类型。 + +![20240719112105](https://static-docs.nocobase.com/20240719112105.png) + +点击 `Users` 表,就可以添加一个新的 `FormV3` 区块了,但是目前子节点是空的。 + +![20240719112149](https://static-docs.nocobase.com/20240719112149.png) + +### 6. 实现 Schema Settings + +目前的区块只能添加,但是无法删除,我们需要实现 `Schema Settings`,用于配置一些属性和操作。 + +#### 6.1 定义 Schema Settings + +一个完整的 Block 还需要有 Schema Settings,用于配置一些属性和操作。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.settings/index.ts` 文件: + +```ts | pure +import { SchemaSettings } from "@nocobase/client"; +import { FormV3BlockNameLowercase } from "../constants"; + +export const formV3Settings = new SchemaSettings({ + name: `blockSettings:${FormV3BlockNameLowercase}`, + items: [ + // TODO + ] +}) +``` + +#### 6.2 注册 Schema Settings + +```ts +import { Plugin } from '@nocobase/client'; +import { formV3Settings } from './FormV3.settings'; + +export class PluginBlockFormClient extends Plugin { + async load() { + // ... + this.app.schemaSettingsManager.add(formV3Settings) + } +} + +export default PluginBlockFormClient; +``` + +#### 6.3 使用 Schema Settings + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/schema/index.ts` 中的 `getFormV3Schema`: + +```diff ++ import { formV3Settings } from "./FormV3.settings"; + +export function getFormV3Schema(options: GetFormV3SchemaOptions): ISchema { + const { dataSource, collection, properties = {} } = options; + return { + type: 'void', + 'x-decorator': 'CardItem', ++ 'x-settings': formV3Settings.name, + // ... + } +}; +``` + + +### 7. 实现 Schema Settings items + +目前我们只实现了 `Schema Settings`,但是没有实现任何操作,我们需要根据需求实现各个操作。 + +目前 Schema Settings 支持的内置操作类型请参考 [Schema Settings - Built-in Components and Types](https://client.docs.nocobase.com/core/ui-schema/schema-settings#built-in-components-and-types) 文档。 + +#### 7.1 实现 `remove` 操作 + +目前通过 initializers 添加的区块是无法删除的,我们需要实现 `remove` 操作。 + +[NocoBase] 内置了 [remove](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsremove-1) 操作类型,我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/settings/index.ts` 文件: + +```diff +import { SchemaSettings } from '@nocobase/client'; +import { BlockNameLowercase } from '../constants'; + +export const formV3Settings = new SchemaSettings({ + name: `blockSettings:${FormV3BlockNameLowercase}`, + items: [ ++ { ++ type: 'remove', ++ name: 'remove', ++ componentProps: { ++ removeParentsIfNoChildren: true, ++ breakRemoveOn: { ++ 'x-component': 'Grid', ++ }, ++ } ++ } + ] +}); +``` + +- componentProps + - `removeParentsIfNoChildren`:如果没有子节点,是否删除父节点 + - `breakRemoveOn`:删除时的中断条件。因为 `Add Block` 会自动将子项的包裹在 `Grid` 中,所以这里设置 `breakRemoveOn: { 'x-component': 'Grid' }`,当删除 `Grid` 时,不再向上删除。 + +:::warning +schema 的变更不会影响之前添加的区块,只有新添加的区块会才能有最新的 schema,我们这里需要新添加一个区块来查看效果。 +::: + +![20240719145202](https://static-docs.nocobase.com/20240719145202.png) + +#### 7.2 实现 `Edit block title` 操作 + +`Edit block title` 也是一个常见的操作,`@nocobase/client` 内置了 `SchemaSettingsBlockTitleItem` 组件,我们可以直接使用。 + +```diff +- import { SchemaSettings } from "@nocobase/client"; ++ import { SchemaSettings, SchemaSettingsBlockTitleItem } from "@nocobase/client"; + +export const formV3Settings = new SchemaSettings({ + name: `blockSettings:${FormV3BlockNameLowercase}`, + items: [ ++ { ++ name: 'blockTitle', ++ Component: SchemaSettingsBlockTitleItem, ++ }, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + }, + ] +}) +``` + +![20240719145326](https://static-docs.nocobase.com/20240719145326.png) + + +### 8. 实现 `Configure actions` + +`Configure actions` 用于添加一些操作,比如 `Submit`、`Custom request` 等。 + +关于 `Configure actions` 的详细说明可以查看 [区块内嵌的 Initializer - 配置操作](/plugin-samples/schema-initializer/configure-actions) 文档。 + +#### 8.1 定义 initializer + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configFields/index.ts` 文件: + +```ts +import { SchemaInitializer } from "@nocobase/client"; +import { FormV3BlockNameLowercase } from "../constants"; + +export const formV3ConfigureActionsInitializer = new SchemaInitializer({ + name: `${FormV3BlockNameLowercase}:configureActions`, + icon: 'SettingOutlined', + title: tStr('Configure actions'), + style: { + marginLeft: 8, + }, + items: [ + // TODO + ] +}); +``` + +我们通过上述代码定义了一个新的 `SchemaInitializer`,其子项暂时为空。 + +- [SchemaInitializer](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于创建一个 Schema Initializer 实例 +- `icon`:图标,更多图标可参考 Ant Design [Icons](https://ant.design/components/icon/) +- `title`:按钮标题 +- [items](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#built-in-components-and-types):按钮下的子项 + +#### 8.2 注册 initializer + +然后修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/index.tsx` 文件,导入并注册这个 initializer: + +```tsx | pure +// ... +import { formV3ConfigureActionsInitializer } from './FormV3.configActions'; + +export class PluginBlockFormClient extends Plugin { + async load() { + this.app.schemaInitializerManager.add(formV3ConfigureActionsInitializer); + + // ... + } +} +``` + +#### 8.3 使用 initializer + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.schema.ts` 文件,新增 `actionBar` 子节点: + +```diff +// ... ++ import { formV3ConfigureActionsInitializer } from "./FormV3.configActions"; + +export function getFormV3Schema(options: GetFormV3SchemaOptions): ISchema { + const { dataSource, collection, properties = {} } = options; + return { + type: 'void', + 'x-component': 'CardItem', + 'x-decorator': 'DataBlockProvider', + 'x-decorator-props': { + dataSource, + collection, + action, + params, + [FormV3BlockNameLowercase]: {}, + }, + 'x-settings': formV3Settings.name, + "x-toolbar": "BlockSchemaToolbar", + properties: { + [FormV3BlockNameLowercase]: { + type: 'void', + 'x-component': FormV3BlockName, + 'x-use-component-props': 'useFormV3Props', + properties: { + ...properties as any, ++ actionBar: { ++ type: 'void', ++ "x-initializer": formV3ConfigureActionsInitializer.name, ++ "x-component": "ActionBar", ++ "x-component-props": { ++ "layout": "one-column", ++ "style": { ++ "marginTop": 24 ++ } ++ }, ++ }, + } + } + } + } +} +``` + +`configure actions` 一般与 [ActionBar](https://client.docs.nocobase.com/components/action#actionbar) 组件搭配使用。 + +我们在 `FormV3` 的子节点中添加了一个 `actionBar` 节点: + +- `type: 'void'`:类型为 `void`,表示这是一个容器 +- `x-component: 'ActionBar'`:使用 [ActionBar](https://client.docs.nocobase.com/components/action#actionbar) 组件,用于展示按钮 +- `x-initializer: formV3ConfigureActionsInitializer.name`:使用我们刚创建的 Initializer +- `x-component-props.layout: 'one-column'`:左侧布局,具体示例可参考 [ActionBar one-column](https://client.docs.nocobase.com/components/action#one-column) + +![20240719152528](https://static-docs.nocobase.com/20240719152528.png) + +### 9. 实现 `Configure actions` items + +```bash +. +├── FormV3.configActions +├── index.ts +└── items + └── submit # 提交操作 + ├── index.ts + ├── initializer.tsx + ├── schema.ts + └── settings.ts +``` + +#### 9.1 实现 `Submit` 操作 + +##### 9.1.1 定义 Schema + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configActions/items/submit/schema.ts` 文件: + +```ts +import { useForm } from '@formily/react'; +import { App } from 'antd'; +import { ActionProps, useDataBlockResource } from "@nocobase/client"; +import { tStr } from '../../../locale' + +export const useFormV3SubmitActionProps = (): ActionProps => { + const resource = useDataBlockResource(); + const form = useForm(); + const { message } = App.useApp(); + return { + type: 'primary', + htmlType: 'submit', + async onClick() { + await form.submit(); + const values = form.values; + await resource.create({ values }) + await form.reset(); + message.success('Created successfully'); + }, + } +} + +export const submitActionSchema = { + type: 'void', + title: tStr('Submit'), + 'x-component': 'Action', + 'x-use-component-props': 'useFormV3SubmitActionProps', + 'x-toolbar': 'ActionSchemaToolbar' +}; +``` + +`submitActionSchema`: + - `type: 'void'`:类型为 `void`,表示普通 UI,不包含数据 + - `x-component: 'Action'`:使用 [Action](https://client.docs.nocobase.com/components/action) 组件,用于展示按钮 + - `title: 'Submit'`:按钮标题 + - `x-use-component-props: 'useFormV3SubmitActionProps'`:使用 `useFormV3SubmitActionProps` 这个 Hooks 返回的属性。因为 Schema 会保存到服务器,所以这里需要使用字符串的方式。 + - `'x-toolbar': 'ActionSchemaToolbar'`:一般于 `Action` 组件搭配使用,与默认的 ToolBar 不同的是,其将 Action 右上角的 `Initializer` 隐藏,仅保留 Drag 和 Settings。 + +`useFormV3SubmitActionProps`:这个是 React Hooks,需要返回 Action 组件的属性。 + - [useDataBlockResource()](https://client.docs.nocobase.com/core/data-block/data-block-request-provider):数据区块的请求对象,由 `DataBlockProvider` 内部提供,用于自动获取数据区块的数据 + - `resource.create`:用于创建数据 + - `useForm`:获取 Formily 的 form 对象 + - `form.submit()`:提交表单,触发校验 + - `form.values`:获取表单数据 + - `form.reset()`:重置表单 + - `type: 'primary'`:按钮类型为 `primary` + - `onClick`:点击事件。 + + +然后将其在 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configActions/items/submit/index.ts` 中导出: + +```ts +export * from './schema'; +``` + +##### 9.1.2 注册 Scope + +我们还需要将 `useFormV3SubmitActionProps` 注册到上下文中。我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/index.tsx` 文件: + +```diff +// ... ++ import { useFormV3SubmitActionProps } from './FormV3.configActions/items/submit'; + +export class PluginBlockFormClient extends Plugin { + async load() { + // ... +- this.app.addScopes({ useFormV3Props }); ++ this.app.addScopes({ useFormV3Props, useFormV3SubmitActionProps }); + } +} +``` + +关于 `SchemaComponentOptions` 的使用可以参考 [SchemaComponentOptions](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponentoptions) 文档以及 [全局注册 Component 和 Scope](/plugin-samples/component-and-scope/global)。 + +##### 9.1.3 定义 SchemaInitializer item + +我们新增 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configActions/items/submit/initializer.tsx` 文件: + +```tsx | pure +import { SchemaInitializerItemType, useSchemaInitializer } from "@nocobase/client"; +import { submitActionSchema } from "./schema"; +import { tStr } from '../../../locale'; + +export const submitActionInitializerItem: SchemaInitializerItemType = { + type: 'item', + name: 'submit', + title: tStr('Submit'), + useComponentProps() { + const { insert } = useSchemaInitializer(); + return { + onClick() { + insert(submitActionSchema) + }, + }; + }, +}; +``` + +- `type: 'item'`:类型为 `item`,表示文本,当点击后会触发 `onClick` 事件 +- `name: 'submit'`:唯一标识符,用于区分不同的 Schema Item 和增删改查操作 +- `title: 'Submit'`:按钮标题 + +更多关于 Schema Item 的定义可以参考 [Schema Initializer Item](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#built-in-components-and-types) 文档。 + + +然后修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configActions/items/submit/index.ts` 将其导出: + +```tsx | pure +export * from './initializer'; +``` + +###### 10.1.4 使用 SchemaInitializer item + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configActions/index.ts` 文件,将 `submitActionInitializerItem` 添加到 `items` 中: + +```diff +// ... ++ import { submitActionInitializerItem } from "./items/submit"; + +export const formV3ConfigureActionsInitializer = new SchemaInitializer({ + name: `${FormV3BlockNameLowercase}:configureActions`, + icon: 'SettingOutlined', + title: 'Configure actions', + style: { + marginLeft: 8, + }, + items: [ ++ submitActionInitializerItem, + ] +}); +``` + +##### 9.1.4 定义 settings + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configActions/items/submit/settings.ts` + +```tsx | pure +import { ButtonEditor, SchemaSettings, useSchemaToolbar } from "@nocobase/client"; + +export const formV3SubmitActionSettings = new SchemaSettings({ + name: `actionSettings:formV3Submit`, + items: [ + { + name: 'editButton', + Component: ButtonEditor, + useComponentProps() { + const { buttonEditorProps } = useSchemaToolbar(); + return buttonEditorProps; + }, + }, + { + name: 'remove', + type: 'remove', + } + ] +}) +``` + +`formV3SubmitActionSettings`: + - `editButton`:用于编辑按钮的样式。 + - `remove`:用于删除 + +更多关于 Schema Settings 的定义可以参考 [Schema Settings](https://client.docs.nocobase.com/core/ui-schema/schema-settings) 文档。 + +修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configActions/items/submit/index.ts` 将其导出: + +```tsx | pure +export * from './settings'; +``` + +##### 9.1.5 注册 settings + +然后将 `formV3SubmitActionSettings` 注册到系统中。我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/index.tsx` 文件: + +```diff +- import { useFormV3SubmitActionProps } from './FormV3.configActions/items/submit'; ++ import { formV3SubmitActionSettings, useFormV3SubmitActionProps } from './FormV3.configActions/items/submit'; + +export class PluginBlockFormClient extends Plugin { + async load() { ++ this.app.schemaSettingsManager.add(formV3SubmitActionSettings); + } +} +``` + +##### 9.1.6 使用 settings + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configActions/items/submit/schema.ts` 文件的 `submitActionSchema` 方法,将 `x-settings` 设置为 `formV3SubmitActionSettings.name`。 + +```diff ++ import { formV3SubmitActionSettings } from './settings'; + +export const submitActionSchema = { + type: 'void', + title: tStr('Submit'), + 'x-component': 'Action', ++ 'x-settings': formV3SubmitActionSettings.name, + 'x-use-component-props': 'useFormV3SubmitActionProps', + 'x-toolbar': 'ActionSchemaToolbar' +}; +``` + + + +#### 9.2 实现 `Custom request` + +`Custom request` 是一个常见的操作,NocoBase 内置了 `CustomRequest` 组件,我们可以直接使用。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configActions/index.ts`: + +```diff + +import { SchemaInitializer } from "@nocobase/client"; +import { FormV3BlockNameLowercase } from "../constants"; +import { submitActionInitializerItem } from "./items/submit"; ++ import { tStr } from '../locale' + +export const formV3ConfigureActionsInitializer = new SchemaInitializer({ + name: `${FormV3BlockNameLowercase}:configureActions`, + icon: 'SettingOutlined', + title: 'Configure actions', + style: { + marginLeft: 8, + }, + items: [ + submitActionInitializerItem, ++ { ++ name: 'customRequest', ++ title: tStr('Custom request'), ++ Component: 'CustomRequestInitializer', ++ }, + ] +}); +``` + +![20240719165222](https://static-docs.nocobase.com/20240719165222.png) + +### 10. 实现 `Configure fields` + +`Configure fields` 的作用是向 FormV3 区块添加数据字段。 + +#### 10.1 定义 initializer + +我们新建 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configFields/index.ts` 文件: + +```ts +import { gridRowColWrap, SchemaInitializer } from "@nocobase/client"; +import { FormV3BlockNameLowercase } from '../constants'; + +export const formV3ConfigureFieldsInitializer = new SchemaInitializer({ + name: `${FormV3BlockNameLowercase}:configureFields`, + icon: 'SettingOutlined', + wrap: gridRowColWrap, + title: tStr('Configure fields'), + items: [ + // TODO + ] +}); +``` + +`formV3ConfigureFieldsInitializer`: + - `name`:唯一标识符 + - `icon`:图标 + - `wrap`:我们将每个字段包裹在 `Grid` 中,这样可以方便布局和拖拽 + - `title`:标题 + - `items`:子项 + +更多关于 Schema Item 的定义可以参考 [Schema Initializer Item](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#built-in-components-and-types) 文档。 + +#### 10.2 注册 initializer + +然后修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/index.tsx` 文件,导入并注册这个 initializer: + +```diff ++ import { formV3ConfigureFieldsInitializer } from './FormV3.configFields'; + +export class PluginBlockFormClient extends Plugin { + async load() { +- this.app.schemaInitializerManager.add(formV3ConfigureActionsInitializer); ++ this.app.schemaInitializerManager.add(formV3ConfigureActionsInitializer, formV3ConfigureFieldsInitializer); + // ... + } +} +``` + +#### 10.3 使用 initializer + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.schema.ts` 文件,新增 `fields` 子节点: + +```diff +// ... ++ import { formV3ConfigureFieldsInitializer } from "./FormV3.configFields"; + +export function getFormV3Schema(options: GetFormV3SchemaOptions): ISchema { + const { dataSource, collection, properties = {} } = options; + return { + type: 'void', + 'x-component': 'CardItem', + 'x-decorator': 'DataBlockProvider', + 'x-decorator-props': { + dataSource, + collection, + [FormV3BlockNameLowercase]: {}, + }, + 'x-settings': formV3Settings.name, + "x-toolbar": "BlockSchemaToolbar", + properties: { + [FormV3BlockNameLowercase]: { + type: 'void', + 'x-component': FormV3BlockName, + 'x-use-component-props': 'useFormV3Props', + properties: { + ...properties as any, ++ fields: { ++ "type": "void", ++ "x-component": "Grid", ++ "x-initializer": formV3ConfigureFieldsInitializer.name ++ }, + actionBar: { + type: 'void', + "x-initializer": formV3ConfigureActionsInitializer.name, + "x-component": "ActionBar", + "x-component-props": { + "layout": "one-column", + "style": { + "marginTop": 24 + } + }, + }, + } + } + } + } +} +``` + +为了方便布局,我们将其包裹在 `Grid` 中,这样可以方便布局和拖拽。 + +![20240719171211](https://static-docs.nocobase.com/20240719171211.png) + +### 11. 实现 `Configure fields` items + +#### 11.1 实现 `Collection Fields` + +`Configure fields` 主要是基于 [CollectionFieldsToInitializerItems](https://client.docs-en.nocobase.com/core/data-source/collection-fields-to-initializer-items#collectionfieldstoinitializeritems) 实现。 + +我们这里可以直接内核提供的 `CollectionFieldsToFormInitializerItems`,它的作用就是将数据表的字段转换为 `Initializer` 的子项。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configFields/index.ts` 文件: + +```diff +- import { gridRowColWrap, SchemaInitializer } from "@nocobase/client"; ++ import { gridRowColWrap, SchemaInitializer, CollectionFieldsToFormInitializerItems } from "@nocobase/client"; + +export const formV3ConfigureFieldsInitializer = new SchemaInitializer({ + name: `${FormV3BlockNameLowercase}:configureFields`, + icon: 'SettingOutlined', + wrap: gridRowColWrap, + title: 'Configure fields', + items: [ ++ { ++ name: 'collectionFields', ++ Component: CollectionFieldsToFormInitializerItems, ++ }, + ] +}); +``` + +- `name: 'collectionFields'`:唯一标识符 +- `Component: CollectionFieldsToFormInitializerItems`:内核提供的组件,用于将数据表的字段转换 FormItem 类型的 Initializer 子项 + + + +#### 11.2 实现 `Add text` + +向界面添加文本,这是一个常见的需求。因此,NocoBase 在 `@nocobase/client` 中提供了 `MarkdownFormItemInitializer` 来实现此功能。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-block-form/src/client/FormV3.configFields/index.ts` 文件: + +```diff +// ... ++ import { tStr } from '../locale' + +export const formV3ConfigureFieldsInitializer = new SchemaInitializer({ + name: `${FormV3BlockNameLowercase}:configureFields`, + icon: 'SettingOutlined', + wrap: gridRowColWrap, + title: 'Configure fields', + items: [ + { + name: 'collectionFields', + Component: CollectionFieldsToFormInitializerItems, + }, ++ { ++ name: 'divider', ++ type: 'divider', ++ }, ++ { ++ name: 'addText', ++ title: tStr('Add text'), ++ Component: 'MarkdownFormItemInitializer', ++ }, + ] +}); +``` + + + +### 12. 权限 + +TODO + +### 13. 多语言 + +我们可以通过 [http://localhost:13000/admin/settings/system-settings](http://localhost:13000/admin/settings/system-settings) 添加多个语言,并且在右上角切换语言。 + +![20240611113758](https://static-docs.nocobase.com/20240611113758.png) + +由于 FormV3 所使用的文案和 FormV2 相同,已经做了多语言处理,所以这里并没有什么需要更改的。 + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-block-form --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-block-form.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugin-samples/block/block-table.md b/docs/fr-FR/plugin-samples/block/block-table.md new file mode 100644 index 000000000..eeeb039e2 --- /dev/null +++ b/docs/fr-FR/plugin-samples/block/block-table.md @@ -0,0 +1,3 @@ +# `Table` 区块 + +TODO diff --git a/docs/fr-FR/plugin-samples/block/index.md b/docs/fr-FR/plugin-samples/block/index.md new file mode 100644 index 000000000..b0df560f7 --- /dev/null +++ b/docs/fr-FR/plugin-samples/block/index.md @@ -0,0 +1,13 @@ +# 区块 + +NocoBase 支持多种类型的区块。 + +![20240603155329](https://static-docs.nocobase.com/20240603155329.png) + +但是目前已有的区块不一定满足需求,我们可以扩展区块。 + +根据区块类型和复杂度,我们提供了如下示例: + +- [`Carousel` 区块](/plugin-samples/block/block-carousel) +- [`Form` 区块](/plugin-samples/block/block-form) +- [`Table` 区块](/plugin-samples/block/block-table) diff --git a/docs/fr-FR/plugin-samples/component-and-scope/global.md b/docs/fr-FR/plugin-samples/component-and-scope/global.md new file mode 100644 index 000000000..990901c21 --- /dev/null +++ b/docs/fr-FR/plugin-samples/component-and-scope/global.md @@ -0,0 +1,176 @@ +# Global Registration of Component and Scope + +## Example Explanation + +Create a new page and use the [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) to render some content. The route component and the components within the `SchemaComponent` are globally registered. + +You can view the complete example code for this documentation in the [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-component-and-scope-global) repository. + +## Initializing the Plugin + +Following the instructions from [Creating Your First Plugin](/development/your-first-plugin), if you don’t already have a project, you can create one. If you have a project or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Next, initialize a plugin and add it to the system: + +```bash +yarn pm create @nocobase-sample/plugin-component-and-scope-global +yarn pm enable @nocobase-sample/plugin-component-and-scope-global +``` + +Then, start the project: + +```bash +yarn dev +``` + +After logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to check that the plugin has been installed and enabled. + +## Function Implementation + +### 1. Creating a Custom Page + +Create the `packages/plugins/@nocobase-sample/plugin-component-and-scope-global/src/client/CustomPage.tsx` file with the following content: + +```tsx | pure +import React from "react" + +export const SamplesCustomPage = () => { + return
    TODO
    +} +``` + +### 2. Global Registration of Components and Routes + +For detailed instructions on creating a custom page, refer to the [Add Page](/plugin-samples/router/add-page) documentation. + +Modify the `packages/plugins/@nocobase-sample/plugin-component-and-scope-global/src/index.ts` file as follows: + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { SamplesCustomPage } from './CustomPage' + +export class PluginComponentAndScopeGlobalClient extends Plugin { + async load() { + this.app.router.add('admin.custom-page1', { + path: '/admin/custom-page1', + Component: 'SamplesCustomPage', + }) + + this.app.addComponents({ SamplesCustomPage }) + } +} + +export default PluginComponentAndScopeGlobalClient; +``` + +We register the `SamplesCustomPage` component globally using the `app.addComponents()` method, then register a route using the `app.router.add()` method. The `Component` field, being a string type, will automatically search for the globally registered component. + +Afterward, visit [http://localhost:13000/admin/custom-page1](http://localhost:13000/admin/custom-page1) to see the content of the `SamplesCustomPage` component. + +![img_v3_02av_55c3115b-f4b6-4c24-8ea2-914869d498bg](https://static-docs.nocobase.com/img_v3_02av_55c3115b-f4b6-4c24-8ea2-914869d498bg.jpg) + +### 3. Using `SchemaComponent` to Render a Schema + +We first need to understand the following concepts: + +- [Schema Protocol](/development/client/ui-schema/what-is-ui-schema) +- [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) +- [withDynamicSchemaProps](/development/client/ui-schema/what-is-ui-schema#x-component-props-and-x-use-component-props) +- [useFieldSchema()](https://client.docs.nocobase.com/core/ui-schema/designable#usefieldschema) + +Modify the `packages/plugins/@nocobase-sample/plugin-component-and-scope-global/src/client/CustomPage.tsx` file as follows: + +```tsx | pure +import { ISchema, SchemaComponent, withDynamicSchemaProps } from "@nocobase/client" +import { uid } from '@formily/shared' +import { useFieldSchema } from '@formily/react' +import React, { FC } from "react" + +export const SamplesHello: FC<{ name: string }> = withDynamicSchemaProps(({ name }) => { + return
    hello {name}
    +}) + +export const useSamplesHelloProps = () => { + const schema = useFieldSchema(); + return { name: schema.name } +} + +const schema: ISchema = { + type: 'void', + name: uid(), + properties: { + demo1: { + type: 'void', + 'x-component': 'SamplesHello', + 'x-component-props': { + name: 'demo1', + }, + }, + demo2: { + type: 'void', + 'x-component': 'SamplesHello', + 'x-use-component-props': 'useSamplesHelloProps', + }, + } +} + +export const SamplesCustomPage = () => { + return +} +``` + +- We defined and exported the `SamplesHello` and `useSamplesHelloProps` components. +- We defined a `schema` object that contains `'x-component': 'SamplesHello'` and `'x-use-component-props': 'useSamplesHelloProps'`, both of which are string types. +- We used the [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) component to render the `schema` object. + +Next, we need to register `SamplesHello` and `useSamplesHelloProps` globally. Modify the `packages/plugins/@nocobase-sample/plugin-component-and-scope-global/src/index.ts` file as follows: + +```diff +import { Plugin } from '@nocobase/client'; +- import { SamplesCustomPage } from './CustomPage' ++ import { SamplesCustomPage, SamplesHello, useSamplesHelloProps } from './CustomPage' + +export class PluginComponentAndScopeGlobalClient extends Plugin { + async load() { + this.app.router.add('admin.custom-page1', { + path: '/admin/custom-page1', + Component: 'SamplesCustomPage', + }) + +- this.app.addComponents({ SamplesCustomPage }) ++ this.app.addComponents({ SamplesCustomPage, SamplesHello }) ++ this.app.addScopes({ useSamplesHelloProps }) + } +} + +export default PluginComponentAndScopeGlobalClient; +``` + +Afterward, visit [http://localhost:13000/admin/custom-page1](http://localhost:13000/admin/custom-page1) to see the content of the `CustomPage` component. + +![img_v3_02av_79e76ad8-d697-4e3b-aaa9-46ed90e2bb9g](https://static-docs.nocobase.com/img_v3_02av_79e76ad8-d697-4e3b-aaa9-46ed90e2bb9g.jpg) + +## Packaging and Uploading to Production + +Following the instructions in [Building and Packaging the Plugin](/development/your-first-plugin#building-and-packaging-the-plugin), you can package the plugin and upload it to the production environment. + +If you have cloned the source code, first perform a full build to include plugin dependencies. + +```bash +yarn build +``` + +If the project was created using `create-nocobase-app`, simply run: + +```bash +yarn build @nocobase-sample/plugin-component-and-scope-global --tar +``` + +After this, you’ll find the `storage/tar/@nocobase-sample/plugin-component-and-scope-global.tar.gz` file, which can be installed using the [upload method](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/component-and-scope/index.md b/docs/fr-FR/plugin-samples/component-and-scope/index.md new file mode 100644 index 000000000..f0996664a --- /dev/null +++ b/docs/fr-FR/plugin-samples/component-and-scope/index.md @@ -0,0 +1,99 @@ +# Registration and Usage of Component and Scope + +## Scenario Explanation + +There are two main reasons why Components and Scopes need to be registered: + +### Reason 1: UI Schema Needs to Be Stored on the Server + +NocoBase’s front-end pages are rendered based on the [UI Schema](/development/client/ui-schema/what-is-ui-schema), which must be stored in the database. Since the UI Schema cannot have reference-type properties, we can only store the values of properties like `x-component`, `x-decorator`, `x-use-component-props`, and `x-use-decorator-props` as strings. Then, we register the corresponding Component and Scope in NocoBase so that during page rendering, the system can match the stored strings to the appropriate Component and Scope. + +In contrast, for UI Schemas that do not need to be stored in the database, we can directly use reference-type properties. For example, in the locally developed [plugin configuration page](/plugin-samples/plugin-settings/form), properties like `x-component` and `x-use-component-props` can use reference-type values directly. + +```ts +const schema: ISchema = { + type: 'void', + name: uid(), + 'x-component': MyComponent, + 'x-use-component-props': useMyComponentProps, +} +``` + +### Reason 2: Extensibility Needs + +Components can be used both in the UI Schema and in routing. In both cases, it may be necessary to override certain components to achieve customization. For example: + +```ts +class AuthPlugin extends Plugin { + async load() { + this.app.addComponents({ LoginPage }) + this.app.router.add('auth.signin', { + path: '/signin', + Component: 'SignInPage', + }) + } +} +``` + +If someone needs to replace the login page, there are two options: + +#### Option 1: Replace the Route + +```ts +class CustomPlugin extends Plugin { + async load() { + this.app.router.add('auth.login', { + path: '/login', + Component: CustomLoginPage, + }) + } +} +``` + +#### Option 2: Directly Replace the Component + +```ts +class CustomPlugin extends Plugin { + async load() { + this.app.addComponent({ LoginPage: CustomLoginPage }) + } +} +``` + +In summary, if it's not one of these two scenarios, there's no need to register the Component and Scope, and you can directly use reference-type properties instead. + +## Global Registration and Local Registration + +Components and Scopes can be registered globally or locally. + +### Global Registration + +For global registration, use the methods [app.addComponents()](https://client.docs.nocobase.com/core/application/application#appaddcomponents) and [app.addScopes()](https://client.docs.nocobase.com/core/application/application#appaddscopes). For example: + +```ts +class MyPlugin extends Plugin { + async load() { + this.app.addComponents({ MyComponent }) + this.app.addScopes({ MyScope }) + } +} +``` + +### Local Registration + +For local registration, use the `components` and `scope` properties of the [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) and [SchemaComponentOptions](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponentoptions) components. For example: + +```tsx | pure + + + +``` + +`SchemaComponentProvider` can be nested multiple layers deep, and inner `SchemaComponent` elements will inherit the `components` and `scope` from outer layers. + +For the scenarios mentioned, we provide the following examples: + +- [Global Registration of Component and Scope](/plugin-samples/component-and-scope/global) +- [Local Registration of Component and Scope](/plugin-samples/component-and-scope/local) + +For the customization scenario, refer to the routing example [Replace Page](/plugin-samples/router/replace-page). diff --git a/docs/fr-FR/plugin-samples/component-and-scope/local.md b/docs/fr-FR/plugin-samples/component-and-scope/local.md new file mode 100644 index 000000000..593bf7339 --- /dev/null +++ b/docs/fr-FR/plugin-samples/component-and-scope/local.md @@ -0,0 +1,163 @@ +# 局部注册 Component 和 Scope + +## 示例说明 + +需要实现的功能和 [全局注册 Component 和 Scope](/plugin-samples/component-and-scope/global) 示例一样,只是这次我们将组件和 scope 注册到插件内部,而不是全局注册。 + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-component-and-scope-local) 中查看。 + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-component-and-scope-local +yarn pm enable @nocobase-sample/plugin-component-and-scope-local +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +### 1. 创建自定义页面 + +我们新建 `packages/plugins/@nocobase-sample/plugin-component-and-scope-local/src/client/CustomPage.tsx` 文件,内容如下: + +```tsx | pure +import React from "react" + +export const SamplesCustomPage = () => { + return
    TODO
    +} +``` + +### 2. 直接使用 `Component` 渲染内容 + +关于自定义页面的创建,可以参考 [新增页面](/plugin-samples/router/add-page) 文档。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-component-and-scope-local/src/index.ts` 文件,内容如下: + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { SamplesCustomPage } from './CustomPage' + +export class PluginComponentAndScopeLocalClient extends Plugin { + async load() { + this.app.router.add('admin.custom-page2', { + path: '/admin/custom-page2', + Component: SamplesCustomPage, + }) + } +} + +export default PluginComponentAndScopeLocalClient; +``` + +与全局注册不同的是,这里直接使用了 `Component: SamplesCustomPage` 组件,而不是字符串类型。 + +然后我们访问 [http://localhost:13000/admin/custom-page2](http://localhost:13000/admin/custom-page2) 就可以看到 `SamplesCustomPage` 组件的内容了。 + +![img_v3_02av_46e020ae-41d2-4bc3-a047-e28d97c20bdg](https://static-docs.nocobase.com/img_v3_02av_46e020ae-41d2-4bc3-a047-e28d97c20bdg.jpg) + +### 3. 使用 `SchemaComponent` 渲染内容 + +我们需要先了解以下知识: + +- [Schema 协议](/development/client/ui-schema/what-is-ui-schema) +- [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) +- [withDynamicSchemaProps](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) +- [useFieldSchema()](https://client.docs.nocobase.com/core/ui-schema/designable#usefieldschema) + +我们修改 `packages/plugins/@nocobase-sample/plugin-component-and-scope-local/src/client/CustomPage.tsx` 文件,内容如下: + +```tsx | pure +import { ISchema, SchemaComponent, withDynamicSchemaProps } from "@nocobase/client" +import { uid } from '@formily/shared' +import { useFieldSchema } from '@formily/react' +import React, { FC } from "react" + +const SamplesHello: FC<{ name: string }> = withDynamicSchemaProps(({ name }) => { + return
    hello {name}
    +}) + +const useSamplesHelloProps = () => { + const schema = useFieldSchema(); + return { name: schema.name } +} + +const schema: ISchema = { + type: 'void', + name: uid(), + properties: { + demo1: { + type: 'void', + 'x-component': SamplesHello, + 'x-component-props': { + name: 'demo1', + }, + }, + demo2: { + type: 'void', + 'x-component': SamplesHello, + 'x-use-component-props': useSamplesHelloProps, + }, + demo3: { + type: 'void', + 'x-component': 'SamplesHello', + 'x-component-props': { + name: 'demo3', + }, + }, + demo4: { + type: 'void', + 'x-component': 'SamplesHello', + 'x-use-component-props': 'useSamplesHelloProps', + }, + } +} + +export const SamplesCustomPage = () => { + return +} +``` + +- 我们定义了 `SamplesHello` 和 `useSamplesHelloProps` 组件 +- 然后定义了一个 `schema` 对象,`demo1` 和 `demo2` 字段使用对应的组件和 scope,而 `demo3` 和 `demo4` 字段使用字符串类型的组件和 scope +- 最后我们使用 `SchemaComponent` 的 `components` 和 `scope` 属性局部注册 `SamplesHello` 和 `useSamplesHelloProps` + +然后我们访问 [http://localhost:13000/admin/custom-page2](http://localhost:13000/admin/custom-page2) 就可以看到 `CustomPage` 组件的内容了。 + +![img_v3_02av_e8d4d0c7-7a59-4f9e-a120-a2551e719ebg](https://static-docs.nocobase.com/img_v3_02av_e8d4d0c7-7a59-4f9e-a120-a2551e719ebg.jpg) + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-component-and-scope-local --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-component-and-scope-local.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugin-samples/field/index.md b/docs/fr-FR/plugin-samples/field/index.md new file mode 100644 index 000000000..b8e085fed --- /dev/null +++ b/docs/fr-FR/plugin-samples/field/index.md @@ -0,0 +1,5 @@ +# 字段 + +- [无值字段组件](/plugin-samples/field/without-value) +- [有值字段组件](/plugin-samples/field/value) +- [Field interface](/plugin-samples/field/interface) diff --git a/docs/fr-FR/plugin-samples/field/interface.md b/docs/fr-FR/plugin-samples/field/interface.md new file mode 100644 index 000000000..1d3fcaac2 --- /dev/null +++ b/docs/fr-FR/plugin-samples/field/interface.md @@ -0,0 +1,429 @@ +# Field Interface + +前面已经介绍了基于已有的 `Field interface` 增加组件类型的方式实现字段组件的替换,但是某些场景下新增的组件不属于已有的 `Field interface`,这时候我们就需要自定义 `Field interface`。 + +## 示例说明 + +本文会新增一个 `Encryption` interface 类型即加解密字段。具体需求如下: + +- 使用对称加密算法对字段进行加密和解密 +- 加密后,以密文的方式被存储至数据库中,在查看数据时进行解密明文显示 +- 加密后的字段不支持模糊搜索,只支持等于、不等于、为空、不为空等操作 + +此功能需要前后端配合实现,前端需要实现加密和解密的 Field interface,后端需要实现加密和解密的逻辑。 + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-field-interface) 中查看。 + + + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-field-interface +yarn pm enable @nocobase-sample/plugin-field-interface +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/locale/](http://localhost:13000/admin/pm/list/locale/) 就可以看到插件已经安装并启用了。 + +## 文档知识和目录结构 + +在实现本示例之前,我们需要先了解一些基础知识: + +- [NodeJS crypto 模块](https://nodejs.org/api/crypto.html) +- [Database]( /api/database):用于管理数据、字段、模型、操作等 +- [CollectionFieldInterface](https://client.docs.nocobase.com/core/data-source/collection-field-interface):前端数据字段类 +- [CollectionFieldInterfaceManager](https://client.docs.nocobase.com/core/data-source/collection-field-interface-manager):前端用来管理 `CollectionFieldInterface` 的类 + +```bash +. +├── client # 客户端插件 +│ ├── EncryptionFieldInterface.tsx # 前端 Field Interface +│ ├── locale.ts # 多语言工具函数 +│ └── index.ts # 前端入口文件 +├── locale +│ ├── en-US.json # 英语 +│ └── zh-CN.json # 中文 +├── index.ts # 服务端插件入口 +└── server + ├── encryption-field.ts # 加解密字段 + ├── index.ts # 服务端入口文件 + ├── operators # 查询操作符 + │ ├── eq.ts # 等于 + │ ├── ne.ts # 不等于 + │ └── utils.ts # 工具函数 + ├── plugin.ts # 服务端插件 + └── utils.ts # 工具函数 +``` + +## 前端实现 + +### 1. 组件 + +由于加解密用的是字符串,所以我们可以使用 `Input` 组件,并不需要自定义组件。 + +如果其他需求需要自定义组件,可以参考 [有值字段组件](/plugin-samples/field/value) 文档。 + +### 2. Field Interface + +#### 2.1 定义 + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-interface/src/client/EncryptionFieldInterface.tsx` 文件: + +```tsx | pure +import { CollectionFieldInterface, defaultProps } from '@nocobase/client'; +import { uid } from '@nocobase/utils/client'; +import { tStr } from './locale'; + +export class EncryptionFieldInterface extends CollectionFieldInterface { + name = 'encryption'; + type = 'object'; + group = 'advanced'; + order = 10; + title = tStr('Encryption'); + default = { + type: 'encryption', + iv: uid(16), + uiSchema: { + type: 'string', + 'x-component': 'Input', + }, + }; + availableTypes = ['string']; + hasDefaultValue = true; + properties = { + ...defaultProps, + }; + filterable = { + operators: [ + { label: '{{t("is")}}', value: '$encryptionEq', selected: true }, + { label: '{{t("is not")}}', value: '$encryptionNe' }, + { label: '{{t("exists")}}', value: '$exists', noValue: true }, + { label: '{{t("not exists")}}', value: '$notExists', noValue: true }, + ], + }; +} +``` + +所有的 Field interface 都需要继承 `CollectionFieldInterface` 类,然后实现 `name`、`type`、`group`、`order`、`title`、`default`、`availableTypes`、`hasDefaultValue`、`properties`、`filterable` 等属性,具体每个属性的含义为: + +- `tStr`:生成多语言字符串模板 + +- `name`:Field interface 的唯一标识,用于区分不同的 Field interface +- `type`:? +- `group`:分组,用于在字段设置中分组显示,这里我们设置为 `advanced` +- `order`:排序,用于在字段设置中排序显示 +- `title`:标题,用于在字段设置中显示 +- `default`:字段配置,插入到数据库中的默认值 + - `iv`:初始化向量,随机字符串,用于加密 + - `uiSchema`:字段的 UI 配置,这里我们使用 `Input` 组件 +- `availableTypes`:可用的字段类型 +- `hasDefaultValue`:是否有默认值配置 +- `properties`:属性配置,其中 `defaultProps` 包含 + - `name`:字段名 + - `displayName`:字段显示名 +- `filterable`:可过滤的操作符。 + + +其中关于 `filterable` 有 2 点注意: + +- 因为存储到数据库中是密文,所以仅支持 **相等、不等、存在、不存在** 操作符 +- 搜索字符串的时候,需要将字符串解密后再进行搜索,所以这里不能使用默认的 `$eq`、`$ne` 操作符,需要自定义操作符为 `$encryptionEq`、`$encryptionNe`。 + +更多关于 CollectionFieldInterface 的属性和方法可以查看 [CollectionFieldInterface](https://client.docs.nocobase.com/core/data-source/collection-field-interface) 文档。 + +#### 2.2 注册 + +我们修改 `packages/plugins/@nocobase-sample/plugin-field-interface/src/client/index.ts` 文件: + +```ts +import { Plugin } from '@nocobase/client'; +import { EncryptionFieldInterface } from './EncryptionFieldInterface'; + +export class PluginFieldInterfaceClient extends Plugin { + async load() { + this.app.dataSourceManager.collectionFieldInterfaceManager.addFieldInterfaces([EncryptionFieldInterface]); + } +} + +export default PluginFieldInterfaceClient; +``` + +我们通过 `collectionFieldInterfaceManager.addFieldInterfaces()` 将 `EncryptionFieldInterface` 注册到系统中。 + +更多关于 `CollectionFieldInterfaceManager` 的属性和方法可以查看 [文档](https://client.docs.nocobase.com/core/data-source/collection-field-interface-manager)。 + +![20240726193638](https://static-docs.nocobase.com/20240726193638.png) + +此时界面上就可以看到 `Encryption` 字段了,但是后端还没有实现加解密逻辑,所以还**不能创建字段**。 + +## 后端实现 + +### 1. 实现加解密 + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-interface/src/server/utils.ts` 文件: + +```ts +import crypto from 'crypto'; +const algorithm = 'aes-256-cbc'; + +const keyString = process.env.ENCRYPTION_KEY || '12345678901234567890123456789012';; + +const key = Buffer.from(keyString, 'utf8'); + +export function encryptSync(text: string, ivString: string) { + const iv = Buffer.from(ivString, 'utf8'); + const cipher = crypto.createCipheriv(algorithm, key, iv); + let encrypted = cipher.update(text, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + return encrypted; +} + +export function decryptSync(encrypted: string, ivString: string) { + const iv = Buffer.from(ivString, 'utf8'); + const decipher = crypto.createDecipheriv(algorithm, key, iv); + let decrypted = decipher.update(encrypted, 'hex', 'utf8'); + decrypted += decipher.final('utf8'); + return decrypted; +} +``` + +我们使用 `crypto` 模块实现加解密,其中 `encryptSync` 方法用于加密,`decryptSync` 方法用于解密。具体的加密算法是 `aes-256-cbc`,密钥是 `ENCRYPTION_KEY` 环境变量,如果没有设置则使用默认值 `12345678901234567890123456789012`。 + +关于 `crypto` 模块的更多信息可以查看 [NodeJS crypto 模块](https://nodejs.org/api/crypto.html) 文档。 + +### 2. 实现 Field + +#### 2.1 定义 + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-interface/src/server/encryption-field.ts` 文件: + +```ts +import { BaseColumnFieldOptions, Field, FieldContext } from '@nocobase/database'; +import { DataTypes } from 'sequelize'; +import { decryptSync, encryptSync } from './utils'; + +export interface EncryptionFieldOptions extends BaseColumnFieldOptions { + type: 'encryption'; +} + +export class EncryptionField extends Field { + get dataType() { + return DataTypes.STRING; + } + + constructor(options?: any, context?: FieldContext) { + const { name, iv } = options; + super( + { + get() { + const value = this.getDataValue(name); + if (!value) return null; + return decryptSync(value, iv); + }, + set(value) { + if (!value?.length) value = null; + else { + value = encryptSync(value, iv); + } + this.setDataValue(name, value); + }, + ...options, + }, + context, + ); + } +} +``` + +- dataType:加解密对应到数据库中是字符串,所以我们使用 `DataTypes.STRING` 类型 +- get:获取字段值时,解密 +- set:设置字段值时,加密 + +#### 2.2 注册 + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-interface/src/server/plugin.ts` 文件: + +```ts +import { Plugin } from '@nocobase/server'; +import { EncryptionField } from './encryption-field'; +import { $encryptionEq } from './operators/eq'; +import { $encryptionNe } from './operators/ne'; + +export class PluginFieldInterfaceServer extends Plugin { + async load() { + this.db.registerFieldTypes({ + encryption: EncryptionField, + }); + } +} + +export default PluginFieldInterfaceServer; +``` + +我们通过 `db.registerFieldTypes()` 将 `EncryptionField` 注册到系统中,具体可以查看 [registerFieldTypes()](/api/database#registerfieldtypes) 文档。 + +![20240726192559](https://static-docs.nocobase.com/20240726192559.png) + +此时我们已经完成了前后端的实现,可以创建字段了,但是还需要实现查询操作符。 + +### 3. 实现操作符 + +#### 3.1 定义 + +我们要做的就是在查询时,将字符串加密后再进行查询。 + +##### 3.1.1 封装公共方法 + +因为 `$encryptionEq`、`$encryptionNe` 都是需要在加密后再进行查询,所以我们可以将这两个操作符的逻辑抽离出来,所以我们新建 `packages/plugins/@nocobase-sample/plugin-field-interface/src/server/operators/utils.ts` 文件: + +```ts +import { encryptSync } from '../utils'; + +export function getFieldOptions(ctx: any) { + const fieldPathArr = ctx.fieldPath.split('.'); + const collectionName = fieldPathArr[fieldPathArr.length - 2]; + const fieldName = ctx.fieldName; + + return ctx.db.collections.get(collectionName).fields.get(fieldName).options; +} + +export function encryptSearchValueSync(str: any, ctx: any) { + const { iv } = getFieldOptions(ctx); + let encrypted; + if (Array.isArray(str)) { + encrypted = str.map((item) => encryptSync(item, iv)); + } else { + encrypted = encryptSync(str, iv); + } + return encrypted; +} +``` + +我们定义了 2 个方法: + +- `getFieldOptions`:获取字段配置 +- `encryptSearchValueSync`:加密搜索值 + +##### 3.1.2 实现 `$encryptionEq` + +然后我们新建 `packages/plugins/@nocobase-sample/plugin-field-interface/src/server/operators/eq.ts` 文件: + +```ts +import { encryptSearchValueSync } from './utils'; + +export const $encryptionEq = (str, ctx) => { + const eq = ctx.db.operators.get('$eq'); + if (!str) return eq(str, ctx); + const encrypted = encryptSearchValueSync(str, ctx); + return eq(encrypted, ctx); +}; +``` + +我们定义了 `$encryptionEq` 操作符,将搜索值加密后再进行查询。 + +##### 3.1.3 实现 `$encryptionNe` + +然后我们新建 `packages/plugins/@nocobase-sample/plugin-field-interface/src/server/operators/ne.ts` 文件: + +```ts +import { encryptSearchValueSync } from './utils'; + +export const $encryptionNe = (str, ctx) => { + const eq = ctx.db.operators.get('$ne'); + if (!str) return eq(str, ctx); + const encrypted = encryptSearchValueSync(str, ctx); + return eq(encrypted, ctx); +}; +``` + +我们定义了 `$encryptionNe` 操作符,将搜索值加密后再进行查询。 + +#### 3.2 注册操作符 + +我们修改 `packages/plugins/@nocobase-sample/plugin-field-interface/src/server/plugin.ts` 文件: + +```ts +// ... +import { $encryptionEq } from './operators/eq'; +import { $encryptionNe } from './operators/ne'; + +export class PluginFieldInterfaceServer extends Plugin { + async load() { + // ... + + this.db.registerOperators({ + $encryptionEq, + $encryptionNe, + }); + } +} + +export default PluginFieldInterfaceServer; +``` + +![20240726192832](https://static-docs.nocobase.com/20240726192832.png) + +## 多语言 + +我们可以通过 [http://localhost:13000/admin/settings/system-settings](http://localhost:13000/admin/settings/system-settings) 添加多个语言,并且在右上角切换语言。 + +![20240611113758](https://static-docs.nocobase.com/20240611113758.png) + +### 英语 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-field-interface/src/locale/zh-CN.json` 文件: + +```diff +{ + "Encryption": "Encryption" +} +``` + +### 中文 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-field-interface/src/locale/zh-CN.json` 文件: + +```diff +{ + "Encryption": "加密" +} +``` + +![20240726193259](https://static-docs.nocobase.com/20240726193259.png) + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-field-interface --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-field-interface.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugin-samples/field/sub-field.md b/docs/fr-FR/plugin-samples/field/sub-field.md new file mode 100644 index 000000000..7effc77d3 --- /dev/null +++ b/docs/fr-FR/plugin-samples/field/sub-field.md @@ -0,0 +1 @@ +# 子节点组件 diff --git a/docs/fr-FR/plugin-samples/field/value.md b/docs/fr-FR/plugin-samples/field/value.md new file mode 100644 index 000000000..49718ce98 --- /dev/null +++ b/docs/fr-FR/plugin-samples/field/value.md @@ -0,0 +1,404 @@ +# 有值字段组件 + +有值字段组件是组件有 `value` 属性的字段组件,用于展示字段的值。举例来说,`Input`、`Select`、`Checkbox`、`Radio`、`Switch` 等组件都是有值字段组件。 + +## 示例说明 + +本实例会新增 `QRCode` 组件,用于 URL 字段的值展示,并支持 `尺寸`、`颜色`、`边框` 的配置。 + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-field-value) 中查看。 + + + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-field-value +yarn pm enable @nocobase-sample/plugin-field-value +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/locale/](http://localhost:13000/admin/pm/list/locale/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +在实现本示例之前,我们需要先了解一些基础知识: + +- [ant-design QRCode](https://ant.design/components/qr-code) +- [SchemaInitializer 教程](/development/client/ui-schema/initializer):用于向界面内添加各种区块、字段、操作等 +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于向界面内添加各种区块、字段、操作等 +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 +- [Designable 设计器](/development/client/ui-schema/designable):用于修改 Schema + + +```bash +. +├── client # 客户端插件 +│ ├── QRCode.tsx # 组件 +│ ├── settings.tsx # Schema Settings +│ ├── locale.ts # 多语言工具函数 +│ └── index.ts # 客户端入口文件 +├── locale # 多语言文件 +│ ├── en-US.json # 英语 +│ └── zh-CN.json # 中文 +├── index.ts # 服务端插件入口 +└── server # 服务端插件 +``` + +### 1. 组件 + +![20240723211323](https://static-docs.nocobase.com/20240723211323.png) + +对于组件而言我们需要适配三种模式: + +- Editable:编辑模式 +- ReadOnly:只读模式(禁止编辑) +- Easy-reading:阅览模式 + +其中 `ReadOnly` 模式属于编辑模式的 `disabled` 属性,所以我们只需要适配 `Editable` 和 `Easy-reading` 两种模式。 + +#### 1.1 编辑模式组件 + +在编辑模式下,组件会自动注入 `onChange`、`value`、`disabled` 以及 `schema` 中的 [x-component-props](/development/client/ui-schema/what-is-ui-schema#x-component-props-and-x-use-component-props) 属性。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-value/src/client/QRCode.tsx` 文件: + +```tsx | pure +import React, { FC } from 'react'; +import { Input } from '@nocobase/client'; +import { QRCode as AntdQRCode, Space, QRCodeProps as AntdQRCodeProps } from 'antd'; + +interface QRCodeProps extends AntdQRCodeProps { + onChange: (value: string) => void; + disabled?: boolean; +} + +const QRCodeEditable: FC = ({ value, disabled, onChange, ...otherProps }) => { + return + + onChange(e.target.value)} + /> + ; +} +``` + +编辑模式下,我们使用 `Space` 组件将 `QRCode` 和 `Input.URL` 组件放在一起,`QRCode` 组件用于展示 URL 字段的值,`Input.URL` 用于编辑 URL 字段的值。 + +其中 `value`、`disabled`、`onChange` 是 `Editable` 模式下自动注入的属性。 + +#### 1.2 预览模式组件 + +在预览模式下,组件会自动注入 `value` 以及 `schema` 中的 [x-component-props](/development/client/ui-schema/what-is-ui-schema#x-component-props-and-x-use-component-props) 属性。 + +我们继续修改 `packages/plugins/@nocobase-sample/plugin-field-value/src/client/QRCode.tsx` 文件: + +```tsx | pure +const QRCodeReadPretty: FC = ({ value, ...otherProps }) => { + if (!value) return null; + return ; +} +``` + +#### 1.3 连接组件 + +我们需要将 `QRCodeEditable` 和 `QRCodeReadPretty` 组件连接起来,这样在 Schema 中就能够通过 [x-pattern](https://docs.nocobase.com/development/client/ui-schema/what-is-ui-schema#x-pattern) 自动切换组件。 + +我们继续修改 `packages/plugins/@nocobase-sample/plugin-field-value/src/client/QRCode.tsx` 文件: + +```tsx | pure +import { connect, mapReadPretty } from '@formily/react'; + +export const QRCode: FC = connect(QRCodeEditable, mapReadPretty(QRCodeReadPretty); + +QRCode.displayName = 'QRCode'; +``` + +我们使用 [connect](https://react.formilyjs.org/api/shared/connect) 函数能将 `QRCodeEditable` 和 `QRCodeReadPretty` 组件连接起来。 + +#### 1.4 注册组件 + +我们需要将 `QRCode` 通过插件注册到系统中。 + +```ts +import { Plugin } from '@nocobase/client'; + +import { QRCode } from './QRCode'; + +export class PluginFieldComponentValueClient extends Plugin { + async load() { + this.app.addComponents({ QRCode }); + } +} + +export default PluginFieldComponentValueClient; +``` + +这样就可以在 Schema 中以字符串的方式使用 `QRCode` 组件了。 + +```json +{ + "type": "string", + "x-component": "QRCode", +} +``` + +#### 1.5 添加到 field interface 的 `componentOptions` 中 + +我们还需要将 `QRCode` 组件添加到 `url` interface 字段的 `componentOptions` 中,这样就可以通过界面自由切换组件了。 + +```ts +import { Plugin } from '@nocobase/client'; + +import { QRCode } from './QRCode'; +import { qrCodeComponentFieldSettings } from './settings'; +import { tStr } from './locale'; + +export class PluginFieldComponentValueClient extends Plugin { + async load() { + this.app.addComponents({ QRCode }); + this.schemaSettingsManager.add(qrCodeComponentFieldSettings); + this.app.addFieldInterfaceComponentOption('url', { + label: tStr('QRCode'), + value: 'QRCode', + }); + } +} + +export default PluginFieldComponentValueClient; +``` + +其中关于 `app.addFieldInterfaceComponentOption` 的使用可以参考 [文档](https://client.docs.nocobase.com/core/data-source/collection-field-interface-manager#addfieldinterfacecomponentoption)。 + +![编辑模式](https://static-docs.nocobase.com/20240724111012.png) + +![ReadOnly 模式](https://static-docs.nocobase.com/20240724111116.png) + +![预览模式](https://static-docs.nocobase.com/20240724111231.png) + +### 2. 实现 Schema Settings + +我们需要通过 Schema Settings 来配置 `QRCode` 组件的属性。 + +#### 2.1 定义 Schema Settings + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-value/src/client/settings.tsx` 文件: + +```ts +import { createModalSettingsItem, createSelectSchemaSettingsItem, createSwitchSettingsItem, SchemaSettings } from "@nocobase/client"; + +import { tStr, useT } from './locale'; + +export const qrCodeComponentFieldSettings = new SchemaSettings({ + name: 'fieldSettings:component:QRCode', + items: [ + // TODO + ] +}); +``` + +其中 `name` 的命名规则为 `fieldSettings:component:${componentName}`,`componentName` 为组件的名字。 + +#### 2.2 注册 Schema Settings + +我们将 `qrCodeComponentFieldSettings` 注册到系统中。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-field-component-value/src/client/index.tsx` 文件: + +```ts +// ... +import { qrCodeComponentFieldSettings } from './settings'; + +export class PluginFieldComponentValueClient extends Plugin { + async load() { + // ... + this.schemaSettingsManager.add(qrCodeComponentFieldSettings); + } +} +``` + +### 3. 实现 Schema Settings items + +#### 3.1 实现 `Size` + +`Size` 我们使用 `select` 选择框来选择 `small`、`middle`、`large`。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-field-component-value/src/client/settings.ts`: + +```ts +// ... +export const qrCodeComponentFieldSettings = new SchemaSettings({ + name: 'fieldSettings:component:QRCode', + items: [ + createSelectSchemaSettingsItem({ + name: 'size', + title: tStr('Size'), + schemaKey: 'x-component-props.size', + defaultValue: 160, + useOptions() { + const t = useT(); + return [ + { + label: t('Small'), + value: 100, + }, + { + label: t('Middle'), + value: 160, + }, + { + label: t('Large'), + value: 200, + } + ] + } + }), + ], +}); +``` + +- `name`:唯一标识 +- `title`:标题 +- `schemaKey`:Schema 的 key,我们这里将其存储在 `x-component-props.size` 中 +- `defaultValue`:默认值 +- `useOptions`:选项 + +![20240724111505](https://static-docs.nocobase.com/20240724111505.png) + +#### 3.2 实现 `Bordered` + +`Border` 我们使用 `switch` 开关来选择是否显示边框。 + +```ts +export const qrCodeComponentFieldSettings = new SchemaSettings({ + name: 'fieldSettings:component:QRCode', + items: [ + // ... + createSwitchSettingsItem({ + name: 'bordered', + schemaKey: 'x-component-props.bordered', + title: tStr('Bordered'), + defaultValue: true, + }), + ], +}); +``` + +- `name`:唯一标识 +- `schemaKey`:Schema 的 key,我们这里将其存储在 `x-component-props.bordered` 中 +- `defaultValue`:默认值 + +![20240724111935](https://static-docs.nocobase.com/20240724111935.png) + +#### 3.3 实现 `Color` + +`Color` 我们使用 `Modal` 弹窗来选择颜色。 + +```ts +export const qrCodeComponentFieldSettings = new SchemaSettings({ + name: 'fieldSettings:component:QRCode', + items: [ + // ... + createModalSettingsItem({ + name: 'color', + title: tStr('Color'), + parentSchemaKey: 'x-component-props', + schema({ color }) { + return { + type: 'object', + title: tStr('Color'), + properties: { + color: { + type: 'string', + title: tStr('Color'), + default: color, + 'x-component': 'ColorPicker', + } + } + } + }, + }), + ], +}); +``` + +![20240724112041](https://static-docs.nocobase.com/20240724112041.png) + +### 4. 多语言 + +我们可以通过 [http://localhost:13000/admin/settings/system-settings](http://localhost:13000/admin/settings/system-settings) 添加多个语言,并且在右上角切换语言。 + +![20240611113758](https://static-docs.nocobase.com/20240611113758.png) + +#### 4.1 英语 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-field-value/src/locale/zh-CN.json` 文件: + +```diff +{ + "QRCode": "QRCode", + "Size": "Size", + "Bordered": "Bordered", + "Color": "Color", + "Small": "Small", + "Middle": "Middle", + "Large": "Large" +} +``` + +#### 4.1 中文 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-field-value/src/locale/zh-CN.json` 文件: + +```diff +{ + "QRCode": "二维码", + "Size": "尺寸", + "Bordered": "边框", + "Color": "颜色", + "Small": "小", + "Middle": "中", + "Large": "大" +} +``` + +![TODO:截图](https://static-docs.nocobase.com/TODO:截图.png) + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-field-value --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-field-value.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugin-samples/field/without-value.md b/docs/fr-FR/plugin-samples/field/without-value.md new file mode 100644 index 000000000..026268035 --- /dev/null +++ b/docs/fr-FR/plugin-samples/field/without-value.md @@ -0,0 +1,619 @@ +# 无值字段组件 + +## 场景说明 + +某些表单字段由于特殊需求,它并不与字段直接关联,可能是独立的一个字段或者读取其他字段的值,做一些特殊处理后展示在界面上。 + +## 示例说明 + +本示例会演示一个通过实时检测订单号字段变化,查询订单详情并展示的场景。 + + + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-field-component-without-value) 中查看。 + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-field-component-without-value +yarn pm enable @nocobase-sample/plugin-field-component-without-value +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/locale/](http://localhost:13000/admin/pm/list/locale/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +在实现本示例之前,我们需要先了解一些基础知识: + +- [SchemaInitializer 教程](/development/client/ui-schema/initializer):用于向界面内添加各种区块、字段、操作等 +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于向界面内添加各种区块、字段、操作等 +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 +- [Designable 设计器](/development/client/ui-schema/designable):用于修改 Schema +- [FormV2](https://client.docs.nocobase.com/components/form-v2):表单组件 +- [FormItem](https://client.docs.nocobase.com/components/form-item):表单项组件 + +```bash +. +├── client # 客户端插件 +│ ├── initializer # 初始化器 +│ ├── component # 字段组件 +│ ├── index.tsx # 客户端插件入口 +│ ├── locale.ts # 多语言工具函数 +│ ├── constants.ts # 常量 +│ ├── schema # Schema +│ └── settings # Schema Settings +├── locale # 多语言文件 +│ ├── en-US.json # 英语 +│ └── zh-CN.json # 中文 +├── index.ts # 服务端插件入口 +└── server # 服务端插件 +``` + +### 1. 定义名称 + +我们首先需要定义字段名称,它将会使用在各个地方。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/constants.ts`: + +```ts +export const FiledComponentName = 'OrderDetails'; +export const FieldTitle = 'Order Details'; +export const FieldNameLowercase = 'orderDetails'; +``` + +### 2. 实现字段组件 + +#### 2.1 定义字段组件 + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/component/OrderDetails.tsx` 文件,其内容如下: + +```tsx | pure +import { observer } from '@formily/react' +import { Spin, Empty } from 'antd'; +import React, { FC } from 'react'; +import { useForm } from '@formily/react'; +import { FiledComponentName } from '../constants'; +import { useRequest } from '@nocobase/client'; + +export interface OrderDetailsProps { + orderField?: string; +} + +export const OrderDetails: FC = observer(({ orderField }) => { + const form = useForm(); + const value = orderField ? form.values[orderField] : undefined; + + const { data, loading } = useRequest<{ data: any[] }>({ url: `https://jsonplaceholder.typicode.com/todos/${value}` }, { + ready: !!value, + refreshDeps: [orderField, value], + }) + + if (!orderField) return
    Please select order Field
    + + if (loading) { + return
    + } + + if (!data?.data) return ; + + return
    {JSON.stringify(data?.data, null, 2)}
    ; +}, { displayName: FiledComponentName }); +``` + +- [observer](https://react.formilyjs.org/api/shared/observer):用于将函数组件转换为响应式组件,当表单数据变化时,组件会自动更新 +- [useForm()](https://react.formilyjs.org/api/hooks/use-form):用于获取当前表单实例 + - `values`:表单数据 +- [useRequest()](https://client.docs.nocobase.com/core/request):用于请求数据 + +默认情况下,系统只有 `users` 和 `roles` 表,为了简单说明,我们这里根据通过传入的 `orderField` 获取对应的 `users` 表的数据,然后展示在界面上。 + +然后将其在 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/component/index.ts` 中导出: + +```tsx | pure +export * from './OrderDetails' +``` + +#### 2.2 注册字段组件 + +我们需要将 `OrderDetails` 通过插件注册到系统中。 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { OrderDetails } from './component'; +import { FieldComponentName } from './constants'; + +export class PluginFieldComponentWithoutValueClient extends Plugin { + async load() { + this.app.addComponents({ [FieldComponentName]: OrderDetails }) + } +} + +export default PluginFieldComponentWithoutValueClient; +``` + +#### 2.3 验证字段组件 + +组件验证方式有 2 种: + +- 临时页面验证:我们可以临时建一个页面,然后渲染 `OrderDetails` 组件,查看是否符合需求 +- 文档示例验证:可以启动文档 `yarn doc plugins/@nocobase-sample/plugin-field-component-without-value`,通过写文档示例的方式验证是否符合需求(TODO) + +我们以 `临时页面验证` 为例,我们新建一个页面,根据属性参数添加一个或者多个 `OrderDetails` 组件,查看是否符合需求。 + +```tsx | pure +import React from 'react'; +import { Plugin, SchemaComponent } from '@nocobase/client'; + +import { OrderDetails } from './component'; +import { FieldComponentName } from './constants'; + +export class PluginFieldOrderDetailsClient extends Plugin { + async load() { + this.app.addComponents({ [FiledComponentName]: OrderDetails }) + + function Demo() { + const schema = { + type: 'void', + name: 'root', + properties: { + test: { + type: 'void', + 'x-component': 'FormV2', + properties: { + username: { + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'Input', + title: 'Username', + required: true, + }, + orderDetails: { + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': OrderDetails, + title: 'Order Details', + 'x-component-props': { + orderField: 'username', + }, + } + }, + }, + }, + }; + + return ; + } + + this.app.router.add('admin.order-details-component', { + path: '/admin/order-details-component', + Component: Demo + }) + } +} + +export default PluginFieldOrderDetailsClient; +``` + +我们参考 [Form 组件](https://client.docs.nocobase.com/components/form-v2#basic-usage) 示例,新建一个 `Demo` 组件,然后在 `orderDetails` 字段中添加 `OrderDetails` 组件,然后将 `orderField` 设置为 `username`,这样就可以根据 `username` 字段的值获取对应的 `users` 表的数据。 + +关于 `SchemaComponent` 的详细说明可以查看 [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) 文档。 + +然后访问 `http://localhost:13000/admin/order-details-component` 就可以看到对应测试页面的内容了。 + + + +验证完毕后需要删除测试页面。 + +### 3. 定义字段 Schema + +NocoBase 的动态页面都是通过 Schema 来渲染,所以我们需要定义一个 Schema,后续用于在界面中添加 `Carousel` 区块。在实现本小节之前,我们需要先了解一些基础知识: + +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 + +#### 3.1 定义字段 Schema + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/schema/index.ts` 文件: + +```tsx | pure +import { ISchema } from "@nocobase/client" +import { FieldComponentName } from '../constants'; + +export const getOrderDetailsSchema = (orderField: string): ISchema => ({ + type: 'void', + 'x-decorator': 'FormItem', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-component': FieldComponentName, + 'x-component-props': { + 'orderField': orderField, + } +}) +``` + +`getOrderDetailsSchema`: + +- `type`:类型,这里是 `void`,表示纯 UI 节点 +- `'x-decorator': 'FormItem'`:[FormItem 组件](https://client.docs.nocobase.com/components/form-item),用于包裹字段组件。 +- `'x-toolbar': 'FormItemSchemaToolbar'`:与 `x-decorator` 配合使用,用于显示右上角的操作和设置 +- `'x-component': FiledComponentName`:就是我们上面定义的 `OrderDetails` 组件 +- `x-component-props`:`OrderDetails` 组件的属性,会自动传入到组件中 + - `orderField`:订单字段 + +上述 Schema 转为 React 组件后相当于: + +```tsx | pure + + + +``` + +#### 3.2 验证字段 Schema + +同验证组件一样,我们可以通过临时页面验证或者文档示例验证的方式来验证 Schema 是否符合需求。我们这里以临时页面验证为例: + + +```tsx | pure +import { Plugin, SchemaComponent } from '@nocobase/client'; +import { OrderDetails } from './component'; +import { FieldComponentName } from './constants'; + +import React from 'react'; + +export class PluginFieldOrderDetailsClient extends Plugin { + async load() { + this.app.addComponents({ [FiledComponentName]: OrderDetails }) + + function Demo() { + const schema = { + type: 'void', + name: 'root', + properties: { + test: { + type: 'void', + 'x-component': 'FormV2', + properties: { + username: { + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'Input', + title: 'Username', + required: true, + }, + orderDetails: getOrderDetailsSchema('username') + }, + }, + }, + }; + + return ; + } + + this.app.router.add('admin.order-details-schema', { + path: '/admin/order-details-schema', + Component: Demo + }) + } +} + +export default PluginFieldOrderDetailsClient; +``` + +我们访问 [http://localhost:13000/admin/order-details-schema](http://localhost:13000/admin/order-details-schema) 就可以看到对应测试页面的内容了。 + + + +### 4. 定义 Schema Initializer Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/initializer/index.tsx` 文件: + +```ts +import React from "react"; +import { SchemaInitializerActionModal, SchemaInitializerItemType, SelectProps, useCollection, useCompile, useSchemaInitializer } from "@nocobase/client" +import { MenuOutlined } from "@ant-design/icons"; + +import { FieldNameLowercase } from "../constants"; +import { useT } from "../locale"; +import { getOrderDetailsSchema } from '../schema' + +export function useFieldOptions(): SelectProps['options'] { + const collection = useCollection(); + + const compile = useCompile(); + return collection + .getFields() + .map(field => ({ label: field.uiSchema?.title ? compile(field.uiSchema.title) : field.name, value: field.name })); +} + +const OrderDetailsSchemaInitializer = () => { + const t = useT(); + const { insert } = useSchemaInitializer(); + const options = useFieldOptions(); + return } + isItem + onSubmit={({ orderField }) => { + insert(getOrderDetailsSchema(orderField)); + }} + schema={{ + orderField: { + type: 'string', + title: 'orderField', + required: true, + 'x-component': 'Select', + 'x-decorator': 'FormItem', + enum: options + }, + }} + > +} + +export const orderDetailsInitializerItem: SchemaInitializerItemType = { + name: FieldNameLowercase, + Component: OrderDetailsSchemaInitializer +}; +``` + +`orderDetailsInitializerItem`: + - `name`:唯一标识符,用于区分不同的 Schema Item 和增删改查操作 + - `Component`:Schema Initializer Item 对应的组件 + +`OrderDetailsSchemaInitializer`: + - [SchemaInitializerActionModal](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#type-actionmodal---schemainitializeractionmodal):带弹窗的 Schema Initializer Item + - `buttonText`:按钮文本 + - `title`:弹窗标题 + - `isItem`:是否是 Item,这里必须为 true + - `schema`:弹窗内的表单 schema + - `onSubmit`:表单提交事件 + - `useFieldOptions`:获取字段选项 + - `useT`:获取多语言工具函数 + - [useSchemaInitializer()](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#useschemainitializer):获取 Schema Initializer 上下文 + - `insert`:插入 Schema Item + +`useFieldOptions`: + - [useCollection](https://client.docs.nocobase.com/core/data-source/collection-provider#usecollection):获取当前表的集合 + - `useCompile`:编译函数 + +更多关于 Schema Item 的定义可以参考 [Schema Initializer Item](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#built-in-components-and-types) 文档。 + +### 5. 添加到 Form Block `Configure fields` 中 + +表单区块的 `Configure fields` 对应的 name 为 `form:configureFields`。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/index.tsx` 文件: + +```diff +// ... ++ import { orderDetailsInitializerItem } from './initializer'; + +export class PluginFieldComponentWithoutValueClient extends Plugin { + async load() { + // ... ++ this.app.schemaInitializerManager.addItem('form:configureFields', orderDetailsInitializerItem.name, orderDetailsInitializerItem); + } +} + +export default PluginFieldComponentWithoutValueClient; +``` + +我们使用 [app.schemaInitializerManager.addItem](https://client.docs.nocobase.com/core/ui-schema/schema-initializer-manager#schemainitializermanageradditem) 将 `orderDetailsInitializerItem` 添加对应 Initializer 子项中。 + +![20240723161400](https://static-docs.nocobase.com/20240723161400.png) + +### 6. 实现 Schema Settings + +#### 6.1 定义 Schema Settings + +一个完整的 Block 还需要有 Schema Settings,用于配置一些属性和操作。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/settings/index.ts` 文件: + +```ts | pure +import { SchemaSettings } from "@nocobase/client"; +import { FieldNameLowercase } from '../constants'; +import { orderFieldSchemaSettingsItem } from "./items/orderField"; + +export const orderDetailsSettings = new SchemaSettings({ + name: `blockSettings:${FieldNameLowercase}`, + items: [ + // TODO + ] +}); +``` + +#### 6.2 注册 Schema Settings + +```ts +import { Plugin } from '@nocobase/client'; +import { orderDetailsSettings } from './settings'; + +export class PluginFieldComponentWithoutValueClient extends Plugin { + async load() { + // ... + this.app.schemaSettingsManager.add(orderDetailsSettings) + } +} + +export default PluginFieldComponentWithoutValueClient; +``` + +#### 6.3 使用 Schema Settings + +我们修改 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/schema/index.ts` 中的 `carouselSchema`: + +```diff ++ import { orderDetailsSettings } from "../settings"; + +export const getOrderDetailsSchema = (orderField: string): ISchema => ({ + type: 'void', + 'x-decorator': 'FormItem', ++ 'x-settings': orderDetailsSettings.name, + // ... +}; +``` + +### 7. 实现 Schema Settings items + +目前我们只实现了 `Schema Settings`,但是没有实现任何操作,我们需要根据需求实现各个操作。 + +目前 Schema Settings 支持的内置操作类型请参考 [Schema Settings - Built-in Components and Types](https://client.docs.nocobase.com/core/ui-schema/schema-settings#built-in-components-and-types) 文档。 + +#### 7.1 实现 `remove` 操作 + +目前通过 initializers 添加的字段是无法删除的,我们需要实现 `remove` 操作。 + +[NocoBase] 内置了 [remove](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsremove-1) 操作类型,我们修改 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/settings/index.ts` 文件: + +```diff +export const orderDetailsSettings = new SchemaSettings({ + name: `blockSettings:${FieldNameLowercase}`, + items: [ ++ { ++ type: 'remove', ++ name: 'remove', ++ componentProps: { ++ removeParentsIfNoChildren: true, ++ breakRemoveOn: { ++ 'x-component': 'Grid', ++ }, ++ } ++ } + ] +}); +``` + +- componentProps + - `removeParentsIfNoChildren`:如果没有子节点,是否删除父节点 + - `breakRemoveOn`:删除时的中断条件。因为 `Configure fields` 会自动将子项的包裹在 `Grid` 中,所以这里设置 `breakRemoveOn: { 'x-component': 'Grid' }`,当删除 `Grid` 时,不再向上删除。 + +![20240613183852](https://static-docs.nocobase.com/20240613183852.png) + +#### 7.2 实现 `Order field` 选择 + +我们除了在添加字段的时候选择了 `Order field`,还可以在 `Schema Settings` 中选择 `Order field`。 + +##### 7.2.1 定义 Schema Settings item + +我们新建 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/settings/items/orderField.ts` 文件: + +```ts +import { createSelectSchemaSettingsItem } from "@nocobase/client"; +import { generateNTemplate } from "../../locale"; +import { useFieldOptions } from '../../initializer' + +export const orderFieldSchemaSettingsItem = createSelectSchemaSettingsItem({ + name: 'orderField', + title: generateNTemplate('Order field'), + useOptions: useFieldOptions, + schemaKey: `x-component-props.orderField`, +}); +``` + +关于 SchemaSettings Item 的定义可以查看 [SchemaSettingsItem](https://client.docs.nocobase.com/core/ui-schema/schema-settings#optionsitems)。 + +`createSelectSchemaSettingsItem`:用于快速创建选择类型的 SchemaSettings Item。 + +- `name`:唯一标识,用于增删改查 +- `title`:标题 +- `useOptions`:获取选项 +- `schemaKey`:对应 schema 的 key + +##### 7.3.2 使用 SchemaSettings Item + +我们修改 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/client/settings/index.ts`: + +```diff +import { SchemaSettings } from "@nocobase/client"; +import { FieldNameLowercase } from '../constants'; ++ import { orderFieldSchemaSettingsItem } from "./items/orderField"; + +export const orderDetailsSettings = new SchemaSettings({ + name: `blockSettings:${FieldNameLowercase}`, + items: [ ++ orderFieldSchemaSettingsItem, + { + name: 'remove', + type: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + }, + ] +}); +``` + +![20240723161525](https://static-docs.nocobase.com/20240723161525.png) + +你可以根据需要实现更多的 Settings 配置。 + +### 8. 多语言 + +#### 8.1 英文 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/locale/en-US.json` 文件: + +```ts +{ + "Order Details": "Order Details", + "Order field": "Order field" +} +``` + +#### 8.2 中文 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-field-component-without-value/src/locale/zh-CN.json` 文件: + +```ts +{ + "Order Details": "订单详情", + "Order field": "订单字段" +} +``` + +我们可以通过 [http://localhost:13000/admin/settings/system-settings](http://localhost:13000/admin/settings/system-settings) 添加多个语言,并且在右上角切换语言。 + +![20240611113758](https://static-docs.nocobase.com/20240611113758.png) + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-field-component-without-value --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-field-component-without-value.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugin-samples/index.md b/docs/fr-FR/plugin-samples/index.md new file mode 100644 index 000000000..18369167a --- /dev/null +++ b/docs/fr-FR/plugin-samples/index.md @@ -0,0 +1,82 @@ +# Overview + +- **Creating the First Plugin** + - @my-project/plugin-hello +- **Tables and Fields** + - sample-collection-define + - sample-collection-extend + - sample-collection-model + - sample-collection-repository + - sample-collection-template + - sample-collection-field-type + - sample-collection-field-interface +- **Resources and Actions** + - sample-resource-manager-register-action-handlers + - sample-resource-manager-define + - sample-resource-manager-actions +- **Database Usage** + - sample-db-registerFieldTypes + - sample-db-registerModels + - sample-db-registerRepositories + - sample-db-registerOperators + - sample-db-repository +- **Custom Command Line** + - sample-cli-create-command +- **Migration Scripts** + - sample-migration-create-migration +- **Caching** + - sample-cache-register-store + - sample-cache-create-cache +- **Server Middleware** + - sample-middleware-ratelimit +- **Data Source Extensions** + - sample-data-source-nocobase-api +- **Chart Extensions** + - sample-dv-echarts +- **Internationalization** + - sample-i18n-zh-cn +- **Frontend Routing Extensions** + - Add a New Page + - Replace an Existing Page + - Plugin Configuration Page (Single Route) + - Plugin Configuration Page (Tabbed Layout) + - Plugin Configuration Page (Different Layouts) +- **Plugin Configuration Pages** + - Form Configuration Page + - Table Configuration Page + - Polymorphic Table Configuration Page +- **Provider Components** + - Global Announcement Bar +- **Component Extensions** +- **Schema Initializer** + - Add initialization items to existing Add blocks + - Add initialization items to existing Configure actions + - Add initialization items to existing Configure fields + - Reuse existing SchemaInitializerItem + - Directly add a block + - Add after configuring a pop-up (such as a calendar) + - Create new initializers + - Simple button and dropdown menu +- **Schema Settings** + - Add initialization items to existing Settings + - Reuse existing SchemaSettingsItem + - Create new settings +- **Block Extensions** + - Simple Block Example - Gallery Image Carousel Block + - Block component development + - Initializer item + - Block Settings + - Embedded Block Initializer + - Configure operations + - Configure fields + - Custom initializer +- **Operation Extensions** + - Command-based operations + - Pop-up-based operations +- **Field Extensions** + - Custom Field Interface Type + - Custom Field Data Type + - Field Component Development + - connect + mapReadPretty + - observer + mapReadPretty + - Provide Setters for Fields diff --git a/docs/fr-FR/plugin-samples/plugin-settings/form.md b/docs/fr-FR/plugin-samples/plugin-settings/form.md new file mode 100644 index 000000000..f9d8945e1 --- /dev/null +++ b/docs/fr-FR/plugin-samples/plugin-settings/form.md @@ -0,0 +1,455 @@ +# Form Configuration Page + +## Scenario Description + +The configuration interface is composed of a form. + +## Example Description + +Suppose we need to connect to a third-party map service and configure the map's `key` and `secret`. We can add a configuration page via a plugin to fill in this information. + +The complete example code in this document can be found in [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-settings-form). + +## Initialize the Plugin + +Following the [Writing Your First Plugin](/development/your-fisrt-plugin) document, if you don’t have a project yet, you can create one first. If you already have one or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Then, initialize a plugin and add it to the system: + +```bash +yarn pm create @nocobase-sample/plugin-settings-form +yarn pm enable @nocobase-sample/plugin-settings-form +``` + +Now, start the project: + +```bash +yarn dev +``` + +After logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to see that the plugin has been installed and enabled. + +## Backend Implementation + +### 1. Create the Database Table + +The backend mainly involves creating a database table to store configuration information. For creating database tables, we need to be familiar with the following: + +- [Tables and Fields](/development/server/collections) +- [Creating Tables](/development/server/collections/configure#在插件代码里定义) +- [Field Type](/development/server/collections/options#field-type) +- [defineCollection() API](/api/database#definecollection) +- [Collection API](/api/database/collection) + +In this example, we create the `packages/plugins/@nocobase-sample/plugin-settings-form/src/server/collections/map-configuration.ts` file with the following content: + +```ts +import { defineCollection } from '@nocobase/database'; + +export default defineCollection({ + name: 'SamplesMapConfiguration', + fields: [ + { + type: 'string', + name: 'key', + }, + { + type: 'string', + name: 'secret', + }, + ], +}); +``` + +As needed, we created a `SamplesMapConfiguration` database table containing two fields: `key` and `secret`, both of string type. + +### 2. Execute the Update + +We need to update the database with the defined table, which can be done with the following command: + +```bash +yarn nocobase upgrade +``` + +![img_v3_02av_db5e9985-eb20-4420-a0b2-8a809ff05a5g](https://static-docs.nocobase.com/img_v3_02av_db5e9985-eb20-4420-a0b2-8a809ff05a5g.jpg) + +## Frontend Implementation + +### 1. Create the Plugin Configuration Page + +We've already introduced the detailed steps for [Adding a Plugin Configuration Page (Single Route)](/plugin-samples/router/add-setting-page-single-route), so we won’t repeat them here. + +We modify the `packages/plugins/@nocobase-sample/plugin-settings-form/src/client/index.tsx` file as follows: + +```tsx | pure +import { Plugin } from '@nocobase/client'; +// @ts-ignore +import { name } from '../../package.json'; + +export class PluginSettingsFormClient extends Plugin { + async load() { + this.app.pluginSettingsManager.add(name, { + title: 'Plugin Settings Form', + icon: 'FormOutlined', + Component: () => 'TODO', + }); + } +} + +export default PluginSettingsFormClient; +``` + +Then, visit [http://localhost:13000/admin/settings/@nocobase-sample/plugin-settings-form](http://localhost:13000/admin/settings/@nocobase-sample/plugin-settings-form) to see the configuration page. + +![img_v3_02av_c90b5767-97dd-4fef-8dd0-c7ff9a136a9g](https://static-docs.nocobase.com/img_v3_02av_c90b5767-97dd-4fef-8dd0-c7ff9a136a9g.jpg) + +### 2. Define the Data Table Structure + +Based on the Schema definition method, we first need to define the structure of the data table. To define the data table structure on the frontend, we need to understand the following concepts: + +- [Tables and Fields](/development/server/collections#field-component) +- [Field Type](/development/server/collections/options#field-type) +- [Field Interface](/development/server/collections/options#field-interface) +- [UI Schema Protocol](/development/client/ui-schema/what-is-ui-schema) +- [Field Components](https://client.docs.nocobase.com/components) + +We then create the `packages/plugins/@nocobase-sample/plugin-settings-form/src/client/PluginSettingsForm.tsx` file with the following content: + +```ts +const mapConfigurationCollection = { + name: 'SamplesMapConfiguration', + filterTargetKey: 'id', + fields: [ + { + type: 'string', + name: 'key', + interface: 'input', + uiSchema: { + title: 'Title', + required: true, + 'x-component': 'Input', + }, + }, + { + type: 'string', + name: 'secret', + interface: 'input', + uiSchema: { + title: 'Secret', + required: true, + 'x-component': 'Input', + }, + }, + ], +}; +``` + +We've defined a `SamplesMapConfiguration` data table with two fields: `key` and `secret`. The `fields` are explained as follows: + +- `type`: Since the values are strings, it is set to `string` and must match the backend field type. +- `name`: The field's name, which must match the backend field name. +- `interface`: Corresponding to the string value, it is set to `input`. +- `uiSchema`: Refers to the rendering of the frontend form components. + - `title`: The title of the form field. + - `required`: As it is mandatory, it is set to `true`. + - `x-component`: The [Input component](https://client.docs.nocobase.com/components/input) is chosen for single-line text input. + +### 3. Create Form Schema + +For writing form schemas, the following concepts are important: + +- [Form Component](https://client.docs.nocobase.com/components/form-v2) +- [CollectionField Component](https://client.docs.nocobase.com/core/data-source/collection-field) +- [CardItem Component](https://client.docs.nocobase.com/components/card-item) +- [Schema Protocol](/development/client/ui-schema/what-is-ui-schema) +- [DataBlockProvider Component](https://client.docs.nocobase.com/core/data-block/data-block-provider) +- [Action Component](https://client.docs.nocobase.com/components/action) + +We continue to write the following in `packages/plugins/@nocobase-sample/plugin-settings-form/src/client/PluginSettingsForm.tsx`: + +```ts +import { useMemo } from 'react'; +import { App as AntdApp } from 'antd'; +import { createForm } from '@formily/core'; +import { useForm } from '@formily/react'; +import { uid } from '@formily/shared'; +import { ActionProps, ISchema, useCollection, useCollectionRecordData, useDataBlockResource } from '@nocobase/client'; + +const schema: ISchema = { + type: 'void', + name: uid(), + 'x-component': 'CardItem', + 'x-decorator': 'DataBlockProvider', + 'x-decorator-props': { + collection: mapConfigurationCollection.name, + action: 'get', + }, + properties: { + form: { + type: 'void', + 'x-component': 'FormV2', + 'x-use-component-props': 'useFormBlockProps', + properties: { + key: { + title: 'Key', + 'x-decorator': 'FormItem', + 'x-component': 'CollectionField', + }, + secret: { + title: 'Secret', + 'x-decorator': 'FormItem', + 'x-component': 'CollectionField', + }, + footer: { + type: 'void', + 'x-component': 'Action', + title: 'Submit', + 'x-use-component-props': 'useSubmitActionProps', + }, + }, + }, + }, +}; + +const useFormBlockProps = () => { + const recordData = useCollectionRecordData(); + const form = useMemo( + () => createForm({ + initialValues: recordData, + }), + [recordData], + ); + return { + form, + }; +}; + +const useSubmitActionProps = (): ActionProps => { + const form = useForm(); + const { message } = AntdApp.useApp(); + const collection = useCollection(); + const resource = useDataBlockResource(); + return { + type: 'primary', + htmlType: 'submit', + async onClick() { + await form.submit(); + const values = form.values; + await resource.updateOrCreate({ + values, + filterKeys: [collection.filterTargetKey], + }); + message.success('Saved successfully!'); + }, + }; +}; +``` + +- [CardItem](https://client + +.docs.nocobase.com/components/card-item): A card component that provides card-style layouts. +- [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider): A component that provides data to child nodes, with the `collection` and `action` attributes since the form fetches single-row data. +- [FormV2](https://client.docs.nocobase.com/components/form-v2): A form component used to render the form. +- `useFormBlockProps`: Used to get the data block's attributes and pass them to the FormV2 component. For detailed examples, see FormV2 [Default values](https://client.docs.nocobase.com/components/form-v2#default-values). +- [CollectionField](https://client.docs.nocobase.com/core/data-source/collection-field): A data table field component used to read the UI Schema of the Collection and render it. +- [Action](https://client.docs.nocobase.com/components/action): An action button component used to submit the form. +- `useSubmitActionProps`: Used to get the attributes of the submit button. + - [useCollection](/core/data-source/collection-provider): Used to get information about the data table. + - [useDataBlockResource](/core/data-block/data-block-resource-provider): A hook provided by DataBlockProvider to access the data block's resources for CRUD operations. + +### 4. Create the Form Component + +To render the schema into a component, we need to understand the following concepts: + +- [ExtendCollectionsProvider](https://client.docs.nocobase.com/core/data-source/extend-collections-provider) component to extend data tables. +- [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component) component to render forms. + +We continue writing in `packages/plugins/@nocobase-sample/plugin-settings-form/src/client/PluginSettingsForm.tsx`: + +```tsx | pure +import React from 'react'; +import { ExtendCollectionsProvider, SchemaComponent } from '@nocobase/client'; +export const PluginSettingsForm = () => { + return ( + + + + ); +}; +``` + +### 5. Register the Plugin Configuration Page + +We modify the `packages/plugins/@nocobase-sample/plugin-settings-form/src/client/index.tsx` file as follows: + +```diff +import { Plugin } from '@nocobase/client'; +// @ts-ignore +import { name } from '../../package.json'; ++ import { PluginSettingsForm } from './PluginSettingsForm' + +export class PluginSettingFormClient extends Plugin { + async load() { + this.app.pluginSettingsManager.add(name, { + title: 'Plugin Settings Form', + icon: 'FormOutlined', +- Component: () => 'TODO', ++ Component: PluginSettingsForm, + }); + } +} + +export default PluginSettingFormClient; +``` + +Now, visit [http://localhost:13000/admin/settings/@nocobase-sample/plugin-settings-form](http://localhost:13000/admin/settings/@nocobase-sample/plugin-settings-form) to see the configuration page. + + + +### 6. Use Configuration Data Inside the Page + +When using form data, there are two scenarios: using the data inside the page and using it globally. The difference is: + +- Global usage: After updating the form data, it needs to be synchronized to the global state for real-time updates. +- Page-specific usage: Since the page will be automatically destroyed and created upon switching, there’s no need to synchronize the data. + +In this step, we'll demonstrate using form data inside a page. + +We create the `packages/plugins/@nocobase-sample/plugin-settings-form/src/client/PluginSettingsFormPage.tsx` file with the following content: + +```tsx | pure +import { useRequest } from '@nocobase/client'; +import React from 'react'; + +export const PluginSettingsFormPage = () => { + const { data, loading } = useRequest<{ data?: { key: string; secret: string } }>({ + url: 'SamplesMapConfiguration:get', + }); + + if (loading) return null; + + return
    {JSON.stringify(data?.data, null, 2)}
    +} +``` + +Then we introduce the `PluginSettingsFormPage` component in the `PluginSettingsForm` component: + +```tsx | pure +import { PluginSettingsFormPage } from './PluginSettingsFormPage' +// ... + +export class PluginSettingFormClient extends Plugin { + async load() { + // ... + + this.app.router.add(`admin.${name}-page`, { + path: '/admin/plugin-settings-form-page', + Component: PluginSettingsFormPage, + }) + } +} +``` + +Now, visit [http://localhost:13000/admin/plugin-settings-form-page](http://localhost:13000/admin/plugin-settings-form-page) to see the form data. + +![img_v3_02av_70ade722-7069-4fc7-a2c3-c080f85ff30g](https://static-docs.nocobase.com/img_v3_02av_70ade722-7069-4fc7-a2c3-c080f85ff30g.jpg) + +### 7. Use Configuration Data Globally + +To use the data globally and ensure real-time updates, we need to use `Context` and NocoBase's [Provider](/development/client/providers) capabilities. + +We create the `packages/plugins/@nocobase-sample/plugin-settings-form/src/client/PluginSettingsFormProvider.tsx` file with the following content: + +```tsx | pure +import React, { createContext, FC } from 'react'; +import { useRequest, UseRequestResult } from '@nocobase/client'; + +const PluginSettingsFormContext = createContext>(null as any); + +export const PluginSettingsFormProvider: FC<{ children: React.ReactNode }> = ({children}) => { + const request = useRequest<{ data?: { key: string; secret: string } }>({ + url: 'SamplesMapConfiguration:get', + }); + + console.log('PluginSettingsFormProvider', request.data?.data); + + return {children}; +} + +export const usePluginSettingsFormRequest = () => { + return React.useContext(PluginSettingsFormContext); +}; +``` + +Then we modify the `packages/plugins/@nocobase-sample/plugin-settings-form/src/client/index.tsx` file to register it globally: + +```ts +import { PluginSettingsFormProvider } from './PluginSettingsFormProvider' +// ... + +export class PluginSettingFormClient extends Plugin { + async load() { + // ... + this.app.addProvider(PluginSettingsFormProvider) + } +} +``` + +After updating the form, we need to re-fetch the global data. We modify the `packages/plugins/@nocobase-sample/plugin-settings-form/src/client/PluginSettingsForm.tsx` file: + +```diff ++ import { usePluginSettingsFormRequest } from './PluginSettingsFormProvider'; + +const useSubmitActionProps = (): ActionProps => { + const form = useForm(); + const { message } = AntdApp.useApp(); + const collection = useCollection(); + const resource = useDataBlockResource(); ++ const globalSettingsFormRequest = usePluginSettingsFormRequest(); + return { + type: 'primary', + htmlType: 'submit', + async onClick() { + await form.submit(); + const values = form.values; + await resource.updateOrCreate({ + values, + filterKeys: [collection.filterTargetKey], + }); ++ await globalSettingsFormRequest.runAsync(); + message.success('Saved successfully!'); + }, + }; +}; +``` + + + +## Packaging and Uploading to Production Environment + +Following the [Build and Package Plugin](/development/your-fisrt-plugin#构建并打包插件) document, we can package the plugin and upload it to the production environment. + +If you've cloned the source code, you need to perform a full build first to package the plugin's dependencies. + +```bash +yarn build +``` + +If you used the `create-nocobase-app` to create the project, you can directly execute: + +```bash +yarn build @nocobase-sample/plugin-settings-form --tar +``` + +Then you’ll see the `storage/tar/@nocobase-sample/plugin-settings-form.tar.gz` file, which can be installed by following the [uploading instructions](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/plugin-settings/index.md b/docs/fr-FR/plugin-samples/plugin-settings/index.md new file mode 100644 index 000000000..8cf7b96c1 --- /dev/null +++ b/docs/fr-FR/plugin-samples/plugin-settings/index.md @@ -0,0 +1,59 @@ +# Plugin Configuration Page Overview + +## Scenario Introduction + +When developing plugins, it is often necessary to provide a configuration page where users can set various parameters for the plugin. + +There are four common types of plugin configuration pages: + +### Form Configuration Page + +Users can fill in certain parameters in a form and save them. These parameters will be stored in a database and retrieved by the plugin during its operation. For example, see the [Custom Brand Plugin](/handbook/custom-brand#user-guide). + +![img_v3_02av_cc1d4351-3a24-4cd9-b5a6-98fb3b8dae6g](https://static-docs.nocobase.com/img_v3_02av_cc1d4351-3a24-4cd9-b5a6-98fb3b8dae6g.jpg) + +As shown above, this configuration page is a form where users can input parameters such as `Brand` and `About`, and then click the `Submit` button to save them. + +### Table Configuration Page + +The plugin's configuration consists of a dataset that users can add, delete, or modify within a table. For example, see the [Users & Permissions Plugin](/handbook/users). + +![img_v3_02av_11e5f726-f716-4c0f-a244-2b6543b1b5dg](https://static-docs.nocobase.com/img_v3_02av_11e5f726-f716-4c0f-a244-2b6543b1b5dg.jpg) + +As seen above, this configuration page is a table where users can add, delete, and modify user information. + +### Table Configuration Page (Multiple New Entry Forms) + +The plugin's configuration consists of a dataset, but multiple forms are available for adding new entries. For example, see the [File Manager Plugin](/handbook/file-manager). + +![img_v3_02av_1d023074-402a-4586-848a-b4abd0ee5d4g](https://static-docs.nocobase.com/img_v3_02av_1d023074-402a-4586-848a-b4abd0ee5d4g.jpg) + +As shown above, there are multiple forms for adding new entries, allowing users to choose different forms for data input. + +### Other Cases + +There are also other special cases, such as the [Theme Editor Plugin](/handbook/theme-editor#navigate-to-theme-configuration-page). + +![img_v3_02av_ec2fa97f-2d1a-415c-8106-e3d979740fcg](https://static-docs.nocobase.com/img_v3_02av_ec2fa97f-2d1a-415c-8106-e3d979740fcg.jpg) + +As seen above, this image displays the corresponding theme editor interface. + +## Examples + +For the above scenarios, we provide the following examples: + +- [Form Configuration Page](/plugin-samples/plugin-settings/form) +- [Table Configuration Page](/plugin-samples/plugin-settings/table) +- [Table Configuration Page (Multiple New Entry Forms)](/plugin-samples/plugin-settings/table-multiple-forms.md) + +For special cases, you can develop according to your specific needs. + +## Configuration Page Routes + +For plugin routing, refer to: + +- [Plugin Configuration Page (Single Route)](/plugin-samples/router/add-setting-page-single-route) +- [Plugin Configuration Page (Tabs Route)](/plugin-samples/router/add-setting-page-tabs-routes) +- [Plugin Configuration Page (Different Layouts)](/plugin-samples/router/add-setting-page-layout-routes) + +This set of plugin examples does not go into detail on routing. Those interested can consult the relevant documentation. diff --git a/docs/fr-FR/plugin-samples/plugin-settings/table-multiple-add-forms.md b/docs/fr-FR/plugin-samples/plugin-settings/table-multiple-add-forms.md new file mode 100644 index 000000000..5fb24866d --- /dev/null +++ b/docs/fr-FR/plugin-samples/plugin-settings/table-multiple-add-forms.md @@ -0,0 +1,3 @@ +# 表格配置页面(多种新增表单) + +TODO diff --git a/docs/fr-FR/plugin-samples/plugin-settings/table.md b/docs/fr-FR/plugin-samples/plugin-settings/table.md new file mode 100644 index 000000000..3bf9219a8 --- /dev/null +++ b/docs/fr-FR/plugin-samples/plugin-settings/table.md @@ -0,0 +1,884 @@ +# Table Configuration Page + +## Scenario Description + +The configuration interface consists of a table that allows you to add, edit, and delete data. + +## Example Description + +Let’s assume we need to create an email notification plugin. This plugin can have multiple templates, and each template contains information such as the email subject and content. We need a configuration interface to manage these templates. + +The complete example code for this document can be found in [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-settings-table). + +## Initialize the Plugin + +Following the instructions in [Writing Your First Plugin](/development/your-first-plugin), if you don't have a project yet, you can create one first. If you already have a project or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Next, initialize a plugin and add it to the system: + +```bash +yarn pm create @nocobase-sample/plugin-settings-table +yarn pm enable @nocobase-sample/plugin-settings-table +``` + +Then, start the project: + +```bash +yarn dev +``` + +After logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to see the plugin installed and enabled. + +## Backend Implementation + +### 1. Create a Data Table + +The backend mainly involves creating a data table to store configuration information. To create the data table, you'll need to familiarize yourself with the following concepts: + +- [Tables and Fields](/development/server/collections) +- [Creating Tables](/development/server/collections/configure#defining-tables-in-plugin-code) +- [Field Type](/development/server/collections/options#field-type) +- [defineCollection() API](/api/database#definecollection) +- [Collection API](/api/database/collection) + +For this example, we create the file `packages/plugins/@nocobase-sample/plugin-settings-table/src/server/collections/email-templates.ts` with the following content: + +```ts +import { defineCollection } from '@nocobase/database'; + +export default defineCollection({ + name: 'samplesEmailTemplates', + fields: [ + { + type: 'string', + name: 'subject', + }, + { + type: 'text', + name: 'content', + }, + ], +}); +``` + +We created a `samplesEmailTemplates` data table with two fields: `subject` and `content`. Based on our needs, we used a single-line text field for `subject` and a rich text field for `content`. + +- The `subject` field is of the single-line text type, so its type is set to `string`. +- The `content` field is of the long text type, so its type is set to `text`. + +### 2. Apply the Update + +We need to update the database with the new table definition. You can run the following command to apply the update: + +```bash +yarn nocobase upgrade +``` + +![img_v3_02av_eb156d0e-9f25-4702-a5de-2bfa5cde84bg](https://static-docs.nocobase.com/img_v3_02av_eb156d0e-9f25-4702-a5de-2bfa5cde84bg.jpg) + +## Frontend Implementation + +### 1. Create the Plugin Configuration Page + +In the previous [Adding a Plugin Configuration Page (Single Route)](/plugin-samples/router/add-setting-page-single-route) section, we explained this in detail. Here, we won’t repeat those instructions. + +Modify the file `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/index.tsx` with the following content: + +```tsx | pure +import { Plugin } from '@nocobase/client'; +// @ts-ignore +import { name } from '../../package.json'; + +export class PluginSettingsTableClient extends Plugin { + async load() { + this.app.pluginSettingsManager.add(name, { + title: 'Plugin Settings Table', + icon: 'TableOutlined', + Component: () => 'TODO', + }); + } +} + +export default PluginSettingsTableClient; +``` + +Then, visit [http://localhost:13000/admin/settings/@nocobase-sample/plugin-settings-table](http://localhost:13000/admin/settings/@nocobase-sample/plugin-settings-table) to view the configuration page. + +![img_v3_02av_c610403d-95d8-466a-a3d1-cfcab232057g](https://static-docs.nocobase.com/img_v3_02av_c610403d-95d8-466a-a3d1-cfcab232057g.jpg) + +## Backend Functionality Implementation + +### 1. Create a Data Table + +The backend primarily involves creating a data table to store configuration information. For creating data tables, the following concepts need to be understood: + +- [Data Tables and Fields](/development/server/collections) +- [Data Table Creation](/development/server/collections/configure#defining-in-plugin-code) +- [Field Type](/development/server/collections/options#field-type) +- [defineCollection() API](/api/database#definecollection) +- [Collection API](/api/database/collection) + +In this example, we create a `packages/plugins/@nocobase-sample/plugin-settings-table/src/server/collections/email-templates.ts` file with the following content: + +```ts +import { defineCollection } from '@nocobase/database'; + +export default defineCollection({ + name: 'samplesEmailTemplates', + fields: [ + { + type: 'string', + name: 'subject', + }, + { + type: 'text', + name: 'content', + }, + ], +}); +``` + +We create a `samplesEmailTemplates` data table with two fields: `subject` and `content`. The `subject` field is stored as single-line text, and the `content` field is stored as rich text, depending on the requirement. + +- The `subject` field is of single-line text type, so the type is set to `string`. +- The `content` field is of rich text type, so the type is set to `text`. + +### 2. Execute the Update + +We also need to update the data table definition in the database. This can be done using the following command: + +```bash +yarn nocobase upgrade +``` + +![img_v3_02av_eb156d0e-9f25-4702-a5de-2bfa5cde84bg](https://static-docs.nocobase.com/img_v3_02av_eb156d0e-9f25-4702-a5de-2bfa5cde84bg.jpg) + +--- + +## Frontend Functionality Implementation + +### 1. Create Plugin Configuration Page + +We have already covered how to create a [Plugin Configuration Page (Single Route)](/plugin-samples/router/add-setting-page-single-route) in detail, so we won’t repeat it here. + +We modify the `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/index.tsx` file as follows: + +```tsx | pure +import { Plugin } from '@nocobase/client'; +// @ts-ignore +import { name } from '../../package.json'; + +export class PluginSettingsTableClient extends Plugin { + async load() { + this.app.pluginSettingsManager.add(name, { + title: 'Plugin Settings Table', + icon: 'TableOutlined', + Component: () => 'TODO', + }); + } +} + +export default PluginSettingsTableClient; +``` + +Then, you can visit [http://localhost:13000/admin/settings/@nocobase-sample/plugin-settings-table](http://localhost:13000/admin/settings/@nocobase-sample/plugin-settings-table) to view the configuration page. + +![img_v3_02av_c610403d-95d8-466a-a3d1-cfcab232057g](https://static-docs.nocobase.com/img_v3_02av_c610403d-95d8-466a-a3d1-cfcab232057g.jpg) + +### 2. Define Data Table Structure + +Using Schema-based writing, we first need to define the structure of the data table. To define the data table structure on the frontend, we need to understand the following concepts: + +- [Data Tables and Fields](/development/server/collections#field-component) +- [Field Type](/development/server/collections/options#field-type) +- [Field Interface](/development/server/collections/options#field-interface) +- [UI Schema Protocol](/development/client/ui-schema/what-is-ui-schema) +- [Field Components](https://client.docs.nocobase.com/components) + +Next, we create a `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/PluginSettingsTable.tsx` file with the following content: + +```ts +const emailTemplatesCollection = { + name: 'samplesEmailTemplates', + filterTargetKey: 'id', + fields: [ + { + type: 'string', + name: 'subject', + interface: 'input', + uiSchema: { + title: 'Subject', + required: true, + 'x-component': 'Input', + }, + }, + { + type: 'text', + name: 'content', + interface: 'richText', + uiSchema: { + title: 'Content', + required: true, + 'x-component': 'RichText', + }, + }, + ], +}; +``` + +We define a `samplesEmailTemplates` data table with two fields: `subject` and `content`. The following are explanations of the `fields`: + +- `type`: The value needs to match the type of the data table field in the backend. +- `name`: The field name, which should match the name of the corresponding field in the backend. +- `interface` + - `subject` field: Single-line text, so the value is `input`. + - `content` field: Rich text, so the value is `richText`. +- `uiSchema`: Corresponds to the rendering of frontend form items. + - `type`: Both single-line and rich text fields are of string type, so the value is `string`. + - `title`: The title of the form item. + - `required`: This is a required field, so the value is `true`. + - `x-component`: + - `subject` field: Uses the [Input Component](https://client.docs.nocobase.com/components/input). + - `content` field: Uses the [RichText Component](https://client.docs.nocobase.com/components/rich-text). + +### 3. Create Table Schema + +For creating form Schema, the following knowledge is needed: + +- [Table Component](https://client.docs.nocobase.com/components/table-v2) +- [CollectionField Component](https://client.docs.nocobase.com/core/data-source/collection-field) +- [CardItem Component](https://client.docs.nocobase.com/components/card-item) +- [Schema Protocol](/development/client/ui-schema/what-is-ui-schema) +- [DataBlockProvider Component](https://client.docs.nocobase.com/core/data-block/data-block-provider) + +We refer to the [Extends Collection Table Example](https://client.docs.nocobase.com/components/table-v2#extends-collection) and continue to modify the `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/PluginSettingsTable.tsx` file as follows: + +```tsx | pure +import { ISchema } from '@nocobase/client'; +import { uid } from '@formily/shared' + +const schema: ISchema = { + type: 'void', + name: uid(), + 'x-component': 'CardItem', + 'x-decorator': 'TableBlockProvider', + 'x-decorator-props': { + collection: emailTemplatesCollection.name, + action: 'list', + showIndex: true, + dragSort: false, + }, + properties: { + table: { + type: 'array', + 'x-component': 'TableV2', + 'x-use-component-props': 'useTableBlockProps', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + }, + properties: { + subject: { + type: 'void', + title: 'Subject', + 'x-component': 'TableV2.Column', + properties: { + subject: { + type: 'string', + 'x-component': 'CollectionField', + 'x-pattern': 'readPretty', + }, + }, + }, + content: { + type: 'void', + title: 'Content', + 'x-component': 'TableV2.Column', + properties: { + content: { + type: 'string', + 'x-component': 'CollectionField', + 'x-pattern': 'readPretty', + }, + }, + }, + }, + }, + }, +} +``` + +- [CardItem](https://client.docs.nocobase.com/components/card-item): A card component that provides card-style display. +- [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider): A data block component used to provide data to child nodes. Since this is a form that fetches single-line data, we provide `collection` and `action` properties. +- [TableV2](https://client.docs.nocobase.com/components/table-v2): A table component used to render forms. +- `useTableBlockProps`: Used to get the properties of the data block and pass them to the TableV2 component, usually without modification. +- `TableV2.Column`: A Table column component for rendering table columns. +- [CollectionField](https://client.docs.nocobase.com/core/data-source/collection-field): A data table field component used to read the `UI Schema` from the Collection and render it. + +### 4. Create Table Component + +To render the Schema as a component, we need to understand the following: + +- [ExtendCollectionsProvider](https://client.docs.nocobase.com/core/data-source/extend-collections-provider) component for extending data tables. +- [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component) component for rendering forms. + +We continue writing in the `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/PluginSettingsTable.tsx` file: + + + +```tsx | pure +import React from 'react'; +import { ExtendCollectionsProvider, SchemaComponent } from '@nocobase/client'; +export const PluginSettingsTable = () => { + return ( + + + + ); +}; +``` + +### 5. Register Plugin Configuration Page + +We modify the `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/index.tsx` file as follows: + +```diff +import { Plugin } from '@nocobase/client'; +// @ts-ignore +import { name } from '../../package.json'; ++ import { PluginSettingsTable } from './PluginSettingsTable' + +export class PluginSettingFormClient extends Plugin { + async load() { + this.app.pluginSettingsManager.add(name, { + title: 'Plugin Settings Form', + icon: 'FormOutlined', +- Component: () => 'TODO', ++ Component: PluginSettingsTable, + }); + } +} + +export default PluginSettingFormClient; +``` + +Then, you can visit [http://localhost:13000/admin/settings/@nocobase-sample/plugin-settings-table](http://localhost:13000/admin/settings/@nocobase-sample/plugin-settings-table) to view the configuration page. + +![img_v3_02av_97fd272d-1333-4faf-9ce1-6363c6a049dg](https://static-docs.nocobase.com/img_v3_02av_97fd272d-1333-4faf-9ce1-6363c6a049dg.jpg) + +### 6. Implementing the "Add New" Feature + +Currently, our Table lacks any data, so we need to add the "Add New" functionality. To achieve this, please refer to the following documentation: + +- Table component [With ActionToolbar Example](https://client.docs.nocobase.com/components/table-v2) +- [Form Component](https://client.docs.nocobase.com/components/form-v2) +- [Action Component](https://client.docs.nocobase.com/components/action) + +We will continue editing the file `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/PluginSettingsTable.tsx`: + +```tsx | pure +import React from 'react'; +import { ISchema, useActionContext, useDataBlockRequest, useDataBlockResource } from '@nocobase/client'; +import { App as AntdApp } from 'antd'; +import { useForm } from '@formily/react'; + +const schema: ISchema = { + // ... + properties: { + actions: { + type: 'void', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 20, + }, + }, + properties: { + add: { + type: 'void', + 'x-component': 'Action', + title: 'Add New', + 'x-align': 'right', + 'x-component-props': { + type: 'primary', + }, + properties: { + drawer: { + type: 'void', + 'x-component': 'Action.Drawer', + title: 'Add new', + properties: { + form: { + type: 'void', + 'x-component': 'FormV2', + properties: { + subject: { + 'x-decorator': 'FormItem', + 'x-component': 'CollectionField', + }, + content: { + 'x-decorator': 'FormItem', + 'x-component': 'CollectionField', + }, + footer: { + type: 'void', + 'x-component': 'Action.Drawer.Footer', + properties: { + submit: { + title: 'Submit', + 'x-component': 'Action', + 'x-use-component-props': 'useSubmitActionProps', + }, + } + } + }, + }, + }, + }, + }, + }, + } + }, + + table: { + // ... + } + } +} + + +const useSubmitActionProps = () => { + const { setVisible } = useActionContext(); + const { message } = AntdApp.useApp(); + const form = useForm(); + const resource = useDataBlockResource(); + const { runAsync } = useDataBlockRequest(); + + return { + type: 'primary', + async onClick() { + await form.submit(); + const values = form.values; + await resource.create({ values }) + await runAsync() + message.success('Saved successfully'); + setVisible(false); + }, + }; +}; +``` + +In this context: + +- [ActionBar](https://client.docs.nocobase.com/components/action#actionbar): Provides the layout for action buttons. +- [Action](https://client.docs.nocobase.com/components/action): The "Add New" button. +- [Action.Drawer](https://client.docs.nocobase.com/components/action#actiondrawer): Opens a modal window when clicked. +- [FormV2](https://client.docs.nocobase.com/components/form-v2): The form component. +- [FormItem](https://client.docs.nocobase.com/components/form-v2#formitem): The form item component. +- [Action.Drawer.Footer](https://client.docs.nocobase.com/components/action#actiondrawerfooter): The footer of the modal window. +- [useSubmitActionProps](https://client.docs.nocobase.com/core/data-block/use-data-block-request#use-submit-action-props): Used for submitting the form. + - `useActionContext()`: Retrieves the Action context. + - [useDataBlockResource()](https://client.docs.nocobase.com/core/data-block/data-block-resource-provider): Obtains the `resource` provided by `TableBlockProvider`, used for CRUD operations on data. + - [useDataBlockRequest()](https://client.docs.nocobase.com/core/data-block/data-block-request-provider): The request object for the Table block; calling `runAsync` will re-fetch data, thus refreshing the Table. + +Next, we need to add `useSubmitActionProps` to the context: + +```diff +export const PluginSettingsTable = () => { + return ( + +- ++ + + ); +}; +``` + + + +### 7. Implementing the Edit Feature + +The edit feature is similar to the "Add New" functionality, except we need to add an edit button within the Table and modify data through a modal window. To implement the edit feature, please refer to the following documentation: + +- Table component [View Or Edit Record](https://client.docs.nocobase.com/components/table-v2#view-or-edit-record) +- Form component [Default Values](https://client.docs.nocobase.com/components/form-v2#default-values) +- [useCollectionRecord()](https://client.docs.nocobase.com/core/data-block/collection-record-provider): Used to retrieve data of the current row + +We will continue editing the file `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/PluginSettingsTable.tsx`: + +```tsx | pure +import { useCollectionRecordData } from '@nocobase/client'; +import { useMemo } from 'react'; + +const useEditFormProps = () => { + const recordData = useCollectionRecordData(); + const form = useMemo( + () => + createForm({ + values: recordData, + }), + [], + ); + + return { + form, + }; +} + +const schema: ISchema = { + // ... + properties: { + // ... + table: { + // ... + properties: { + // ... + actions: { + type: 'void', + title: 'Actions', + 'x-component': 'TableV2.Column', + properties: { + actions: { + type: 'void', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + properties: { + edit: { + type: 'void', + title: 'Edit', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + icon: 'EditOutlined', + }, + properties: { + drawer: { + type: 'void', + title: 'Edit', + 'x-component': 'Action.Drawer', + properties: { + form: { + type: 'void', + 'x-component': 'FormV2', + 'x-use-component-props': 'useEditFormProps', + properties: { + subject: { + 'x-decorator': 'FormItem', + 'x-component': 'CollectionField', + }, + content: { + 'x-decorator': 'FormItem', + 'x-component': 'CollectionField', + }, + footer: { + type: 'void', + 'x-component': 'Action.Drawer.Footer', + properties: { + submit: { + title: 'Submit', + 'x-component': 'Action', + 'x-use-component-props': 'useSubmitActionProps', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + }, + } + } + } + } +} +``` + +`Table` passes each row's data to child nodes via the [CollectionRecordProvider](https://client.docs.nocobase.com/core/data-block/collection-record-provider). + +In our `useEditFormProps`, we use `useCollectionRecordData()` to fetch the current row's data, then create a form using `createForm`, passing the current row's data as the default values. + +Next, we modify the logic of `useSubmitActionProps()` to support both creation and editing: + +```diff +const useSubmitActionProps = () => { + // ... ++ const collection = useCollection(); + return { + type: 'primary', + async onClick() { + await form.submit(); + const values = form.values; +- await resource.create({ values }) ++ if (values[collection.filterTargetKey]) { ++ await resource.update({ ++ values, ++ filterByTk: values[collection.filterTargetKey], ++ }); ++ } else { ++ await resource.create({ ++ values, ++ }); ++ } + // ... + }, + }; +}; +``` + +- [useCollection](https://client.docs.nocobase.com/core/data-source/collection-provider#usecollection): The data table object provided by DataBlockProvider. + +Finally, register `useEditFormProps` into the context: + +```diff +export const PluginSettingsTable = () => { + return ( + +- ++ + + ); +}; +``` + + + +### 8. Implementing the Delete Functionality + +The delete functionality is relatively simple. We just need to add a `Delete` button in the Action column, and upon clicking it, call `resource.destroy()` followed by refreshing the Table data. + +- Action [Confirm](https://client.docs.nocobase.com/components/action#confirm) + +We continue by writing the following in the `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/PluginSettingsTable.tsx` file: + +```ts +import { ActionProps } from '@nocobase/client'; + +function useDeleteActionProps(): ActionProps { + const { message } = AntdApp.useApp(); + const record = useCollectionRecordData(); + const resource = useDataBlockResource(); + const collection = useCollection(); + const { runAsync } = useDataBlockRequest(); + return { + confirm: { + title: 'Delete', + content: 'Are you sure you want to delete it?', + }, + async onClick() { + await resource.destroy({ + filterByTk: record[collection.filterTargetKey] + }); + await runAsync(); + message.success('Deleted!'); + }, + }; +} + +const schema: ISchema = { + // ... + properties: { + // ... + table: { + // ... + properties: { + // ... + actions: { + // ... + properties: { + // ... + delete: { + type: 'void', + title: 'Delete', + 'x-component': 'Action.Link', + 'x-use-component-props': 'useDeleteActionProps', + } + } + } + } + } + } +} +``` + +Then, we register `useDeleteActionProps` into the context. + + +```diff +export const PluginSettingsTable = () => { + return ( + +- ++ + + ); +}; +``` + + + +### 9. Using Configuration Data Within a Page + +There are two scenarios for using form data: one is using it within the page, and the other is using it globally. The difference between the two is: + +- **Global Usage**: When form data is updated, it needs to be synchronized to the global state to achieve real-time updates. +- **Page-Specific Usage**: Since the page will automatically be destroyed and recreated during navigation, there's no need to synchronize the data. + +In this step, we will focus on using form data within a page. + +We create the `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/PluginSettingsTablePage.tsx` file with the following content: + +```tsx | pure +import { useRequest } from '@nocobase/client'; +import React from 'react'; + +export const PluginSettingsTablePage = () => { + const { data, loading } = useRequest<{ data?: any[] }>({ + url: 'samplesEmailTemplates:list', + }); + + if (loading) return null; + + return
    {JSON.stringify(data?.data, null, 2)}
    +} +``` + +Then, we import the `PluginSettingsTablePage` component into the `PluginSettingsTable` component: + +```tsx | pure +import { PluginSettingsTablePage } from './PluginSettingsTablePage' +// ... + +export class PluginSettingFormClient extends Plugin { + async load() { + // ... + + this.app.router.add(`admin.${name}-page`, { + path: '/admin/plugin-settings-table-page', + Component: PluginSettingsTablePage, + }) + } +} +``` + +Afterward, we can visit [http://localhost:13000/admin/plugin-settings-table-page](http://localhost:13000/admin/plugin-settings-table-page) to see our form data. + +![img_v3_02av_753dd9f1-9e8c-43c5-a1c6-1fb217844cag](https://static-docs.nocobase.com/img_v3_02av_753dd9f1-9e8c-43c5-a1c6-1fb217844cag.jpg) + +### 10. Global Usage of Configuration Data + +To ensure global use and real-time refresh, you will need to use `Context` along with NocoBase [Provider](/development/client/providers) capabilities. + +We create the file `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/PluginSettingsTableProvider.tsx` with the following content: + +```tsx | pure +import React, { createContext, FC } from 'react'; +import { useRequest, UseRequestResult } from '@nocobase/client'; + +const PluginSettingsTableContext = createContext>(null as any); + +export const PluginSettingsTableProvider: FC<{ children: React.ReactNode }> = ({children}) => { + const request = useRequest<{ data?: any[] }>({ + url: 'samplesEmailTemplates:list', + }); + + console.log('PluginSettingsTableProvider', request.data?.data); + + return {children}; +} + +export const usePluginSettingsTableRequest = () => { + return React.useContext(PluginSettingsTableContext); +}; +``` + +Next, modify the `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/index.tsx` file to register it globally: + +```ts +import { PluginSettingsTableProvider } from './PluginSettingsTableProvider' +// ... + +export class PluginSettingFormClient extends Plugin { + async load() { + // ... + this.app.addProvider(PluginSettingsTableProvider) + } +} +``` + +After updating the form, we need to retrieve the global data again. Modify `packages/plugins/@nocobase-sample/plugin-settings-table/src/client/PluginSettingsTable.tsx`: + +```diff +import { usePluginSettingsTableRequest } from './PluginSettingsTableProvider'; + +// ... + +const useSubmitActionProps = (): ActionProps => { + // ... ++ const globalSettingsTableRequest = usePluginSettingsTableRequest(); + return { + type: 'primary', + htmlType: 'submit', + async onClick() { + // ... ++ await globalSettingsTableRequest.runAsync(); + message.success('Saved successfully!'); + }, + }; +}; + +function useDeleteActionProps(): ActionProps { ++ const globalSettingsTableRequest = usePluginSettingsTableRequest(); + + return { + // ... + async onClick() { + // ... ++ await globalSettingsTableRequest.runAsync(); + message.success('Deleted!'); + } + } +} +``` + + + +### Packaging and Uploading to Production Environment + +Following the [Build and Package Plugin](/development/your-fisrt-plugin#build-and-package-plugin) documentation, we can package the plugin and upload it to the production environment. + +If you cloned the source code, you need to perform a full build first to ensure the plugin dependencies are built properly. + +```bash +yarn build +``` + +If your project was created using `create-nocobase-app`, you can directly run: + +```bash +yarn build @nocobase-sample/plugin-settings-table --tar +``` + +This will generate the file `storage/tar/@nocobase-sample/plugin-settings-table.tar.gz`, which can be installed via the [upload method](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/provider/content.md b/docs/fr-FR/plugin-samples/provider/content.md new file mode 100644 index 000000000..4b6adbe44 --- /dev/null +++ b/docs/fr-FR/plugin-samples/provider/content.md @@ -0,0 +1,126 @@ +# Global Content Display + +We can display global content using the `Provider` component. + +## Example Description + +We want to implement an announcement feature. If the backend returns announcement information, it will be displayed at the top of the page. + +You can view the complete example code in the [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-provider-content) repository. + +![img_v3_02av_cd3c7f37-0c5b-4c9c-b10e-e413af409ccg](https://static-docs.nocobase.com/img_v3_02av_cd3c7f37-0c5b-4c9c-b10e-e413af409ccg.jpg) + +## Initializing the Plugin + +Follow the instructions in the [Writing Your First Plugin](/development/your-fisrt-plugin) guide. If you don't already have a project, you can create one. If you already have a project or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Next, initialize a plugin and add it to the system: + +```bash +yarn pm create @nocobase-sample/plugin-provider-content +yarn pm enable @nocobase-sample/plugin-provider-content +``` + +Now, start the project: + +```bash +yarn dev +``` + +After logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to verify that the plugin has been installed and enabled. + +## Feature Implementation + +### 1. Adding the `Provider` Component + +The `Provider` component is a regular React component, but it is important to remember to render the `children` as part of it. + +Create a new file at `packages/plugins/@nocobase-sample/plugin-provider-content/src/client/TopAnnouncement.tsx`: + +```tsx | pure +import React, { FC, ReactNode } from 'react'; +import { Alert, Affix, AlertProps } from 'antd'; +import { useRequest } from '@nocobase/client'; + +const mockRequest = () => new Promise((resolve) => { + Math.random() > 0.5 ? + resolve({ data: { message: 'This is an important message.', type: 'info' } }) : + resolve({ data: undefined }) +}) + +export const TopAnnouncement: FC<{ children: ReactNode }> = ({ children }) => { + const { data, loading } = useRequest<{ data: { message: string; type: AlertProps['type'] } }>(mockRequest) + + const onClose = () => { + console.log('onClose') + } + + return ( + <> + { + !loading && !!data.data && + + + } + {children} + + ); +}; +``` + +For the announcement configuration and data, you can refer to the [Plugin Form Configuration Page](/plugin-samples/plugin-settings/form). In this example, mock data is used. + +Remember to render `children` within the component. + +### 2. Registering It in the System + +Modify the `packages/plugins/@nocobase-sample/plugin-provider-content/src/index.ts` file to register the `TopAnnouncement` component within the system. + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { TopAnnouncement } from './TopAnnouncement'; + +export class PluginProviderContentClient extends Plugin { + async load() { + this.app.addProvider(TopAnnouncement) + } +} + +export default PluginProviderContentClient; +``` + +Now, visit [http://localhost:13000](http://localhost:13000), and you will see the announcement displayed at the top of the page. + +![img_v3_02av_cd3c7f37-0c5b-4c9c-b10e-e413af409ccg](https://static-docs.nocobase.com/img_v3_02av_cd3c7f37-0c5b-4c9c-b10e-e413af409ccg.jpg) + +## Packaging and Deploying to Production + +Follow the instructions in the [Build and Package Plugin](/development/your-fisrt-plugin#构建并打包插件) document to package the plugin and upload it to the production environment. + +If you cloned the source code, run a full build first to package the plugin’s dependencies as well: + +```bash +yarn build +``` + +If you used `create-nocobase-app` to create the project, you can directly run: + +```bash +yarn build @nocobase-sample/plugin-provider-content --tar +``` + +You will now see the `storage/tar/@nocobase-sample/plugin-provider-content.tar.gz` file. You can then install it by [uploading it](/welcome/getting-started/plugin). +]() diff --git a/docs/fr-FR/plugin-samples/provider/context.md b/docs/fr-FR/plugin-samples/provider/context.md new file mode 100644 index 000000000..d1ae01c6f --- /dev/null +++ b/docs/fr-FR/plugin-samples/provider/context.md @@ -0,0 +1,171 @@ +# Global Context + +In many situations, we need to store data in a global context so that it can be accessed anywhere, such as themes, permissions, and more. + +## Example Overview + +We need to implement a feature toggle plugin to control the activation or deactivation of certain functions. + +The full sample code for this document can be viewed in the [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-provider-context) repository. + +## Plugin Initialization + +Following the instructions in [Writing Your First Plugin](/development/your-first-plugin), if you don’t already have a project, you can create one. If you already have a project or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Next, initialize a plugin and add it to the system: + +```bash +yarn pm create @nocobase-sample/plugin-provider-context +yarn pm enable @nocobase-sample/plugin-provider-context +``` + +Then, start the project: + +```bash +yarn dev +``` + +After logging in, you can visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to verify that the plugin has been installed and enabled. + +## Feature Implementation + +The implementation of the global context requires utilizing React’s `Context` API. + +### 1. Creating the Context + +```tsx | pure +import { useRequest } from '@nocobase/client'; +import { Spin } from 'antd'; +import React, { FC, createContext, ReactNode } from 'react'; + +const FeaturesContext = createContext>({}); + +const mockRequest = () => new Promise((resolve) => { + resolve({ data: { feature1: true, feature2: false } }) +}) + +export const FeaturesProvider: FC<{ children: ReactNode }> = ({ children }) => { + const { loading, data } = useRequest<{ data: Record }>(mockRequest); + + if (loading) return ; + + return {children}; +}; + +export const useFeatures = () => React.useContext(FeaturesContext); + +export const useFeature = (feature: string) => { + const features = useFeatures(); + return features[feature]; +} +``` + +Don’t forget to render the `children` component. + +For configuration and data related to `features`, refer to the [Plugin Form Configuration Page](/plugin-samples/plugin-settings/form) for example usage. In this case, we're using mock data. + +### 2. Registering the Plugin into the System + +Modify the `packages/plugins/@nocobase-sample/plugin-provider-context/src/index.ts` file to register the `FeaturesProvider` component into the system. + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { FeaturesProvider } from './FeaturesProvider'; + +export class PluginProviderContextClient extends Plugin { + async load() { + this.app.addProvider(FeaturesProvider) + } +} + +export default PluginProviderContextClient; +``` + +### 3. Accessing Context Data + +To access the context data, you can use the `useFeatures` and `useFeature` methods. + +There are two cases: using it within this plugin or in other plugins. + +#### 3.1 Using it Within This Plugin + +Modify the `packages/plugins/@nocobase-sample/plugin-provider-context/src/index.ts` file to add a test page for checking the context data. + +```tsx | pure +import React from 'react'; +import { Plugin } from '@nocobase/client'; + +import { FeaturesProvider, useFeature } from './FeaturesProvider'; + +const TestPage = () => { + const feature1 = useFeature('feature1'); + const feature2 = useFeature('feature2'); + + return ( +
    +

    Feature1: {feature1 ? 'Enabled' : 'Disabled'}

    +

    Feature2: {feature2 ? 'Enabled' : 'Disabled'}

    +
    + ); +}; + +export class PluginProviderContextClient extends Plugin { + async load() { + this.app.addProvider(FeaturesProvider) + + this.app.router.add(`admin.features-test`, { + path: '/admin/features-test', + Component: TestPage, + }) + } +} + +export default PluginProviderContextClient; +``` + +Now, visit [http://localhost:13000/admin/features-test](http://localhost:13000/admin/features-test) to see the context data. + +![img_v3_02av_51b7cb08-1b42-42f4-b553-49b4e3f217bg](https://static-docs.nocobase.com/img_v3_02av_51b7cb08-1b42-42f4-b553-49b4e3f217bg.jpg) + +#### 3.2 Using it in Other Plugins + +If you need to use the context in other plugins, you should export the `useFeatures` and `useFeature` methods. + +Modify the `packages/plugins/@nocobase-sample/plugin-provider-context/src/index.ts` file: + +```tsx | pure +export { useFeatures, useFeature } from './FeaturesProvider'; +``` + +Then, you can use the `useFeatures` and `useFeature` methods as shown below: + +```tsx | pure +import { useFeature } from '@nocobase-sample/plugin-provider-context/client'; +``` + +Note that the import path should be `'@nocobase-sample/plugin-provider-context/client'` rather than `'@nocobase-sample/plugin-provider-context'`. + +## Packaging and Deploying to Production + +Following the [Build and Package Plugin](/development/your-first-plugin#build-and-package-plugin) guide, you can package the plugin and upload it to the production environment. + +If you cloned the source code, you’ll need to perform a full build to include the plugin's dependencies. + +```bash +yarn build +``` + +If the project was created using `create-nocobase-app`, simply run: + +```bash +yarn build @nocobase-sample/plugin-provider-context --tar +``` + +This will generate the `storage/tar/@nocobase-sample/plugin-provider-context.tar.gz` file, which can then be installed by following the [upload process](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/provider/index.md b/docs/fr-FR/plugin-samples/provider/index.md new file mode 100644 index 000000000..7a4034ef6 --- /dev/null +++ b/docs/fr-FR/plugin-samples/provider/index.md @@ -0,0 +1,12 @@ +## Provider + +According to the [Provider Tutorial](/development/client/providers), the Provider has three main functions: + +- Providing a globally shared context +- Displaying global content +- Intercepting and rendering based on conditions + +For these functions, we offer the following examples: + +- [Global Content Display](/plugin-samples/provider/content) +- [Global Context](/plugin-samples/provider/context) diff --git a/docs/fr-FR/plugin-samples/router/add-page/index.md b/docs/fr-FR/plugin-samples/router/add-page/index.md new file mode 100644 index 000000000..cb9644dc1 --- /dev/null +++ b/docs/fr-FR/plugin-samples/router/add-page/index.md @@ -0,0 +1,222 @@ +# Add Page + +## Description + +Add some pages for personalized display. + +## Example Description + +This example will add 4 pages: + +- `/about`: About page, used to display system-related information, accessible without logging in. +- `/admin/data-view`: Data dashboard page, requires login to access. +- `/admin/material-manage`: Material management center, including image and video management, is a parent route page. + - `/admin/material-manage/image`: Image management. + - `/admin/material-manage/video`: Video management. + +However, the content development will not be extensive, only for demonstration purposes. + +You can find the complete example code in the [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-add-page) repository. + +## Initialize the Plugin + +Following the instructions in the [Writing Your First Plugin](/development/your-fisrt-plugin) documentation, if you don't have a project yet, you can create one. If you already have one or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Then initialize a plugin and add it to the application: + +```bash +yarn pm create @nocobase-sample/plugin-add-page +yarn pm enable @nocobase-sample/plugin-add-page +``` + +Then start the project: + +```bash +yarn dev +``` + +Then, after logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to see that the plugin has been installed and enabled. + +## Function Implementation + +### 1. Add `/about` page + +According to the [Page Routing and Extension](/development/client/router) documentation in the plugin development tutorial, we need to modify the `packages/plugins/@nocobase-sample/plugin-add-page/src/client/index.tsx` file of the plugin: + +```ts +import React, { useEffect } from 'react'; +import { Plugin, useDocumentTitle } from '@nocobase/client'; + +const AboutPage = () => { + const { setTitle } = useDocumentTitle(); + + useEffect(() => { + setTitle('About'); + }, []) + + return
    About Page
    ; +} + +export class PluginAddPageClient extends Plugin { + async load() { + this.app.router.add('about', { + path: '/about', + Component: AboutPage, + }) + } +} + +export default PluginAddPageClient; +``` + +The `router.add()` function takes two parameters. The first parameter is the name of the page, which is used for CRUD operations and hierarchical nesting. The second parameter is the configuration of the page, where `path` is the path of the page and `Component` is the component of the page. + +`useDocumentTitle()` is used to modify the title of the page. + +Then, when we visit [http://localhost:13000/about](http://localhost:13000/about), we can see that the page displays "About Page". + +![20240512200508](https://static-docs.nocobase.com/20240512200508.png) + +### 2. Add `/admin/data-view` page + +According to the [Existing Page Routes](/development/client/router#existing-page-routes) documentation, we know that `/admin/*` corresponds to the `name` `admin`. If we want to add a new page under it, we can use the `admin.` prefix, for example `admin.dataView`. + +```tsx | pure +// ... +const DataViewPage = () => { + const { setTitle } = useDocumentTitle(); + + useEffect(() => { + setTitle('DataView'); + }, []) + + return
    DataView
    +}; + +export class PluginAddPageClient extends Plugin { + async load() { + // ... + this.app.router.add('admin.dataView', { + path: '/admin/data-view', + Component: DataViewPage, + }) + } +} + +export default PluginAddPageClient; +``` + +Then we visit [http://localhost:13000/admin/data-view](http://localhost:13000/admin/data-view), we can see that the page displays "DataView", and if we visit it again after logging out, it will redirect to the login page. + +![20240512200555](https://static-docs.nocobase.com/20240512200555.png) + +### 3. Add `/admin/material-manage` and its sub-pages + +We can create a `packages/plugins/@nocobase-sample/plugin-add-page/src/client/MaterialPage.tsx` file with the following content: + +```tsx | pure +import React, { useEffect } from 'react'; +import { Outlet, Link } from 'react-router-dom'; +import { useDocumentTitle } from '@nocobase/client'; + +export const MaterialPage = () => { + return
    +

    Material Page

    +
      +
    • + Video +
    • +
    • + Img +
    • +
    + +
    +} + +export const MaterialVideo = () => { + const { setTitle } = useDocumentTitle(); + + useEffect(() => { + setTitle('Material Video'); + }, []) + + return
    Material Video
    +} +export const MaterialImg = () => { + const { setTitle } = useDocumentTitle(); + + useEffect(() => { + setTitle('Material Img'); + }, []) + + return
    Material Img
    ; +} +``` + +Then in `packages/plugins/@nocobase-sample/plugin-add-page/src/client/index.tsx` import and use: + +```ts +// ... +import { MaterialImg, MaterialPage, MaterialVideo } from './MaterialPage'; + +export class PluginAddPageClient extends Plugin { + async load() { + // ... + + this.app.router.add('admin.material', { + path: '/admin/material', + Component: MaterialPage, + }) + + this.app.router.add('admin.material.video', { + path: '/admin/material/video', + Component: MaterialVideo, + }) + + this.app.router.add('admin.material.img', { + path: '/admin/material/img', + Component: MaterialImg, + }) + } +} +``` + +If `MaterialPage` is used as a parent page and does not need a custom layout, the `Component` property can be omitted. + +```ts +this.app.router.add('admin.material', { + path: '/admin/material', +}) +``` + +Then we visit [http://localhost:13000/admin/material](http://localhost:13000/admin/material) and we can see that the `Material Page` is already displayed on the page, and clicking on the `Video` and `Img` links can switch to the corresponding pages. + + + +## Packaging and Uploading to Production Environment + +According to the documentation on [Building and Packaging Plugins](/development/your-fisrt-plugin#building-and-packaging-plugins), we can package the plugin and upload it to the production environment. + +If you have cloned the source code, you need to perform a full build first to build the dependencies of the plugin as well. + +```bash +yarn build +``` + +If you are using `create-nocobase-app` to create your project, you can directly execute: + +```bash +yarn build @nocobase-sample/plugin-add-page --tar +``` + +This way you can see the `storage/tar/@nocobase-sample/plugin-add-page.tar.gz` file, and then install it through the [upload method](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/router/add-setting-page-layout-routes/index.md b/docs/fr-FR/plugin-samples/router/add-setting-page-layout-routes/index.md new file mode 100644 index 000000000..285ec2f24 --- /dev/null +++ b/docs/fr-FR/plugin-samples/router/add-setting-page-layout-routes/index.md @@ -0,0 +1,131 @@ +# Add Plugin Setting Page (Different Layout) + +## Description + +The plugin requires multiple configuration pages, and some pages are not under [AdminSettingsLayout](/development/client/router#existing-page-routes), usually for detail pages, such as the `@nocobase/plugin-mobile-client` plugin or the `@nocobase/plugin-workflow`. + +## Example Description + +This example will have a configuration page, and inside the configuration page, there will be a detail link that, when clicked, will navigate to a new page. + +This document will not go into much detail about the content development. It is only used to demonstrate how to add a plugin configuration page. For specific content and logic of the configuration page, please refer to the [Plugin Settings plugin example](/plugin-samples/plugin-settings) documentation. + +You can find the complete example code for this document in the [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-add-setting-page-layout-routes) repository. + + + +## Initialize the Plugin + +Following the instructions in the [Writing Your First Plugin](/development/your-fisrt-plugin) documentation, if you don't have a project yet, you can create one. If you already have one or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Then initialize a plugin and add it to the application: + +```bash +yarn pm create @nocobase-sample/plugin-add-setting-page-layout-routes +yarn pm enable @nocobase-sample/plugin-add-setting-page-layout-routes +``` + +Then start the project: + +```bash +yarn dev +``` + +Then, after logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to see that the plugin has been installed and enabled. + +## Function Implementation + +### 1. Register the Plugin Setting Page + +Following the instructions in the [Plugin Setting Page Extension](/development/client/router#plugin-setting-page-extension) section of the plugin development tutorial, we need to modify the `packages/plugins/@nocobase-sample/plugin-add-setting-page-layout-routes/src/client/index.tsx` file: + +```tsx | pure +import React from 'react'; +import { Plugin } from '@nocobase/client'; + +// @ts-ignore +import { name } from '../../package.json'; + +const PluginSettingPage = () =>
    + details +
    + +export class PluginAddSettingPageLayoutRoutesClient extends Plugin { + async load() { + this.app.pluginSettingsManager.add(name, { + title: 'Different Layout', + icon: 'ApiOutlined', + Component: PluginSettingPage, + }); + } +} + +export default PluginAddSettingPageLayoutRoutesClient; +``` + +Then we can visit [http://localhost:13000/admin/settings/@nocobase-sample/plugin-add-setting-page-layout-routes](http://localhost:13000/admin/settings/@nocobase-sample/plugin-add-setting-page-layout-routes) to view the plugin configuration page. + + +### 2. Add Detail Page + +我们准备在 `AdminLayout` 下面新增一个详情页面,我们继续修改 `packages/plugins/@nocobase-sample/plugin-add-setting-page-layout-routes/src/client/index.tsx`: + +```diff ++ import { Link } from 'react-router-dom' + +const PluginSettingPage = () =>
    +- details ++ details +
    + +export class PluginAddSettingPageLayoutRoutesClient extends Plugin { + async load() { + // ... ++ this.app.router.add(`admin.${name}-details`, { ++ path: `/admin/${name}-detail`, ++ Component: () =>
    detail
    , ++ }); + } +} +``` + +When we click on the `details` link, it will navigate to the `/admin/@nocobase-sample/plugin-add-setting-page-layout-routes-detail` page. + + + +## Permission Configuration + +By default, the plugin configuration page does not have any permissions. Anyone can access and configure it. To configure permissions for the plugin, we need to configure them in the plugin settings. + +We can visit [http://localhost:13000/admin/settings/users-permissions/roles](http://localhost:13000/admin/settings/users-permissions/roles) to see all the roles. We can configure permissions in the plugin settings. + +![20240512201624](https://static-docs.nocobase.com/20240512201624.png) + +## Packaging and Uploading to Production Environment + +According to the documentation on [Building and Packaging Plugins](/development/your-fisrt-plugin#building-and-packaging-plugins), we can package the plugin and upload it to the production environment. + +If you have cloned the source code, you need to perform a full build first to build the dependencies of the plugin as well. + +```bash +yarn build +``` + +If you are using `create-nocobase-app` to create your project, you can directly execute: + +```bash +yarn build @nocobase-sample/plugin-add-setting-page-layout-routes --tar +``` + +This way you can see the `storage/tar/@nocobase-sample/plugin-add-setting-page-layout-routes.tar.gz` file, and then install it through the [upload method](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/router/add-setting-page-single-route/index.md b/docs/fr-FR/plugin-samples/router/add-setting-page-single-route/index.md new file mode 100644 index 000000000..6cf35bba9 --- /dev/null +++ b/docs/fr-FR/plugin-samples/router/add-setting-page-single-route/index.md @@ -0,0 +1,102 @@ +# Add Plugin Configuration Page (Single Route) + +## Description + +The plugin requires a simple configuration page with only one route. + +## Example Description + +Assuming we integrate with a third-party email service and need to configure the email service token, we need a configuration page. + +This document will not go into too much development detail, but only demonstrate how to add a plugin configuration page. For specific configuration page content and logic, please refer to the [Plugin Settings plugin example](/plugin-samples/plugin-settings) documentation. + +You can view the complete example code for this document in the [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-add-setting-page-single-route) repository. + +![20240512201126](https://static-docs.nocobase.com/20240512201126.png) + +## Initialize the Plugin + +Following the instructions in the [Writing Your First Plugin](/development/your-fisrt-plugin) documentation, if you don't have a project yet, you can create one. If you already have one or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Then initialize a plugin and add it to the application: + +```bash +yarn pm create @nocobase-sample/plugin-add-setting-page-single-route +yarn pm enable @nocobase-sample/plugin-add-setting-page-single-route +``` + +Then start the project: + +```bash +yarn dev +``` + +Then, after logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to see that the plugin has been installed and enabled. + +## Function Implementation + +According to the tutorial on [Extending Plugin Settings Page](/development/client/router#extending-plugin-settings-page) in the plugin development documentation, we need to modify the `packages/plugins/@nocobase-sample/plugin-add-setting-page-single-route/src/client/index.tsx` file of the plugin: + +```ts +import React from 'react'; +import { Plugin } from '@nocobase/client'; + +// @ts-ignore +import { name } from '../../package.json'; + +const MySettingPage = () =>
    Hello Setting page
    ; + +export class PluginAddSettingPageSingleRouteClient extends Plugin { + async load() { + this.app.pluginSettingsManager.add(name, { + title: 'Single Route', + icon: 'ApiOutlined', + Component: MySettingPage, + }); + } +} + +export default PluginAddSettingPageSingleRouteClient; +``` + +- `name`: The name of the plugin, used to uniquely identify the plugin. +- `title`: The title of the plugin configuration management page menu. +- `icon`: The icon of the plugin configuration management page menu. For more icons, you can refer to the [Ant Design Icons](https://ant.design/components/icon/). +- `Component`: The content of the setting page. + +Then we can visit [http://localhost:13000/admin/settings/@nocobase-sample/plugin-add-setting-page-single-route](http://localhost:13000/admin/settings/@nocobase-sample/plugin-add-setting-page-single-route) to view the plugin configuration page. + +![20240512201126](https://static-docs.nocobase.com/20240512201126.png) + +## Permission Configuration + +By default, the plugin configuration page does not have any permissions. Anyone can access and configure it. To configure permissions for the plugin, we need to configure them in the plugin settings. + +We can visit [http://localhost:13000/admin/settings/users-permissions/roles](http://localhost:13000/admin/settings/users-permissions/roles) to see all the roles. We can configure permissions in the plugin settings. + +![20240512201234](https://static-docs.nocobase.com/20240512201234.png) + +## Packaging and Uploading to Production Environment + +According to the documentation on [Building and Packaging Plugins](/development/your-fisrt-plugin#building-and-packaging-plugins), we can package the plugin and upload it to the production environment. + +If you have cloned the source code, you need to perform a full build first to build the dependencies of the plugin as well. + +```bash +yarn build +``` + +If you are using `create-nocobase-app` to create your project, you can directly execute: + +```bash +yarn build @nocobase-sample/plugin-add-setting-page-single-route --tar +``` + +This way you can see the `storage/tar/@nocobase-sample/plugin-add-setting-page-single-route.tar.gz` file, and then install it by [uploading](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/router/add-setting-page-tabs-routes/index.md b/docs/fr-FR/plugin-samples/router/add-setting-page-tabs-routes/index.md new file mode 100644 index 000000000..8a90904a6 --- /dev/null +++ b/docs/fr-FR/plugin-samples/router/add-setting-page-tabs-routes/index.md @@ -0,0 +1,134 @@ +# Add Plugin Configuration Pages (Multiple Tabs) + +## Description + +The plugin requires multiple configuration pages, with each page corresponding to a tab. + +## Example Description + +Assuming we integrate with a third-party email service and need to configure the email service token. At the same time, we also need a configuration page to set up email service templates. In this case, we need a configuration page with two tabs. + +This document does not go into much detail about the content development. It is only used to demonstrate how to add a plugin configuration page. For specific configuration page content and logic, please refer to the [Plugin Settings plugin example](/plugin-samples/plugin-settings) documentation. + +You can find the complete example code for this document in the [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-add-setting-page-tabs-routes) repository. + + + +## Initialize the Plugin + +Following the instructions in the [Writing Your First Plugin](/development/your-fisrt-plugin) documentation, if you don't have a project yet, you can create one. If you already have one or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Then initialize a plugin and add it to the application: + +```bash +yarn pm create @nocobase-sample/plugin-add-setting-page-tabs-routes +yarn pm enable @nocobase-sample/plugin-add-setting-page-tabs-routes +``` + +Then start the project: + +```bash +yarn dev +``` + +Then, after logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to see that the plugin has been installed and enabled. + +## Function Implementation + +According to the tutorial on plugin development [Extending Plugin Settings Page](/development/client/router#extending-plugin-settings-page), we need to modify the `packages/plugins/@nocobase-sample/plugin-add-setting-page-tabs-routes/src/client/index.tsx` file of the plugin: + +```tsx | pure +import React from 'react'; +import { Outlet } from 'react-router-dom'; +import { Plugin } from '@nocobase/client'; + +// @ts-ignore +import { name } from '../../package.json'; + +const TokenPage = () =>
    Token Page
    + +const TemplatePage = () =>
    Template Page
    + +export class PluginAddSettingPageTabsRoutesClient extends Plugin { + async load() { + this.app.pluginSettingsManager.add(name, { + title: 'Tabs Routes', + icon: 'ApiOutlined', + Component: Outlet, // Can be omitted or use a custom component + }); + + this.app.pluginSettingsManager.add(`${name}.token`, { + title: 'Token Page', + Component: TokenPage, + sort: 1, + }); + + this.app.pluginSettingsManager.add(`${name}.template`, { + title: 'Template Page', + Component: TemplatePage, + sort: 2, + }); + + this.app.pluginSettingsManager.add(`${name}.nestedRoute`, { + title: 'Test', + Component: Outlet, // Can be omitted or use a custom component + sort: 3, + }); + + this.app.pluginSettingsManager.add(`${name}.nestedRoute.a`, { + title: 'Test A', + Component: () =>
    Test A page
    + }); + + this.app.pluginSettingsManager.add(`${name}.nestedRoute.b`, { + title: 'Test B', + Component: () =>
    Test B page
    + }); + } +} + +export default PluginAddSettingPageTabsRoutesClient; +``` + +In scenarios where there are multiple configuration pages, the `name` attribute of `pluginSettingsManager.add()` needs to be separated by `.`. For example, `pluginName.pageName` can be used to achieve multiple configuration pages as tabs. + +Then we can visit [http://localhost:13000/admin/settings/@nocobase-sample/plugin-add-setting-page-tabs-routes](http://localhost:13000/admin/settings/@nocobase-sample/plugin-add-setting-page-tabs-routes) to view the plugin configuration page. + + + +## Permission Configuration + +By default, the plugin configuration page does not have any permissions. Anyone can access and configure it. To configure permissions for the plugin, we need to configure them in the plugin settings. + +We can visit [http://localhost:13000/admin/settings/users-permissions/roles](http://localhost:13000/admin/settings/users-permissions/roles) to see all the roles. We can configure permissions in the plugin settings. + +![20240512201446](https://static-docs.nocobase.com/20240512201446.png) + +## Packaging and Uploading to Production Environment + +According to the documentation on [Building and Packaging Plugins](/development/your-fisrt-plugin#building-and-packaging-plugins), we can package the plugin and upload it to the production environment. + +If you have cloned the source code, you need to perform a full build first to build the dependencies of the plugin as well. + +```bash +yarn build +``` + +If you are using `create-nocobase-app` to create your project, you can directly execute: + +```bash +yarn build @nocobase-sample/plugin-add-setting-page-tabs-routes --tar +``` + +This way you can see the `storage/tar/@nocobase-sample/plugin-add-setting-page-tabs-routes.tar.gz` file, and then install it through the [upload method](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/router/index.md b/docs/fr-FR/plugin-samples/router/index.md new file mode 100644 index 000000000..336950f3d --- /dev/null +++ b/docs/fr-FR/plugin-samples/router/index.md @@ -0,0 +1,35 @@ +# Explanation + +NocoBase's frontend pages currently include the following [page routes](/development/client/router#existing-page-routes): + +| Name | Path | Component | Description | +| -------------- | ------------------ | ------------------- |-------------| +| admin | /admin/\* | AdminLayout | Backend management page | +| admin.page | /admin/:name | AdminDynamicPage | Dynamically created page | +| admin.settings | /admin/settings/\* | AdminSettingsLayout | Plugin configuration page | +| admin.pm.list | /admin/pm/list/\* | PluginManager | Plugin management page | + +However, these pages may not meet all requirements, for example: + +**add** + +- Add a new page for frontend display only, such as `/about`, to show information about the website. +- Extend a new page under `/admin/*`, which requires login to access. +- Add a configuration page for a newly added plugin. + +**change** + +- Completely replace an existing page, for example, customize the login page instead of using the default one. +- Modify the layout of an existing page, for example, modify the layout of `/admin/*` without the top menu bar. + +**delete** + +- For example, if we no longer need a registered page, we can delete it. + +To address the above scenarios, we can use NocoBase's frontend router extension feature. We provide the following examples: + +- [Add Page](/plugin-samples/router/add-page) (Add a new page) +- [Replace Page](/plugin-samples/router/replace-page) (Modify a page) +- [Add Plugin Setting Page (Single Route)](/plugin-samples/router/add-setting-page-single-route) (Plugin configuration page - single route) +- [Add Plugin Setting Page (Tabs Routes)](/plugin-samples/router/add-setting-page-tabs-routes) (Plugin configuration page - tabs routes) +- [Add Plugin Setting Page (different Routes)](/plugin-samples/router/add-setting-page-layout-routes) (Plugin configuration page - different layouts) diff --git a/docs/fr-FR/plugin-samples/router/replace-page/index.md b/docs/fr-FR/plugin-samples/router/replace-page/index.md new file mode 100644 index 000000000..1203964f9 --- /dev/null +++ b/docs/fr-FR/plugin-samples/router/replace-page/index.md @@ -0,0 +1,239 @@ +# Replace Page + +## Description + +Scene where the layout of an existing page needs to be changed or the entire content of the page needs to be replaced. + +## Example Description + +We need to customize the layout of the login and registration pages. Currently, there is only a form, but we want to change it to a left-right layout, with an image on the left and the form on the right. + +You can find the complete example code for this documentation in the [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-replace-page) repository. + +![20240512200917](https://static-docs.nocobase.com/20240512200917.png) + +## Initialize the Plugin + +Following the instructions in the [Writing Your First Plugin](/development/your-fisrt-plugin) documentation, if you don't have a project yet, you can create one. If you already have one or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Then initialize a plugin and add it to the application: + +```bash +yarn pm create @nocobase-sample/plugin-replace-page +yarn pm enable @nocobase-sample/plugin-replace-page +``` + +Then start the project: + +```bash +yarn dev +``` + +Then, after logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to see that the plugin has been installed and enabled. + +## Function Implementation + +### 1. Analyzing Requirements and Source Code + +The login and registration pages are registered by the [Auth plugin](/handbook/auth/dev/api#route), which registers the following routes: + +- Auth layout + - name: `auth` + - path: `-` + - component: `AuthLayout` + +- Sign-in page + - name: `auth.signin` + - path: `/signin` + - component: `SignInPage` + +- Sign-up page + - name: `auth.signup` + - path: `/signup` + - component: `SignUpPage` + +The `AuthLayout` is the layout for the entire login and registration pages. We can achieve custom layout by replacing the `AuthLayout`. + +To understand how to implement this, we need to refer to the source code of the original [AuthLayout](https://github.com/nocobase/nocobase/blob/main/packages/plugins/%40nocobase/plugin-auth/src/client/pages/AuthLayout.tsx). + +```tsx | pure +export function AuthLayout() { + const { data } = useSystemSettings(); + + return ( +
    +

    {data?.data?.title}

    + + + +
    + +
    +
    + ); +} +``` + +The overall source code is relatively simple. What we need to implement is a layout with a left and right side. The left side will contain an image, and the right side will contain the login and registration forms. We can either copy the existing `AuthLayout` and place it on the right side, or directly import the original `AuthLayout` and place an image on the left side. + +### 2. Implementing Custom AuthLayout Component + +We create `packages/plugins/@nocobase-sample/plugin-replace-page/src/client/AuthLayout.tsx` with the following content: + +```tsx | pure +import React from 'react'; +import { Col, Row } from 'antd'; +import { Outlet } from 'react-router-dom'; +import { PoweredBy, css, useSystemSettings } from '@nocobase/client'; +import { AuthenticatorsContextProvider } from '@nocobase/plugin-auth/client' + +import authImg from './auth-image.jpg' + +export function CustomAuthLayout() { + const { data } = useSystemSettings(); + + return +
    + + + +
    +

    {data?.data?.title}

    + + + +
    + +
    +
    + + +} +``` + +Then place the left background image [auth-image.jpg](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-replace-page/src/client/auth-image.jpg) in the `packages/plugins/@nocobase-sample/plugin-replace-page/src/client` directory. + +This completes the implementation of a login page with a left and right layout. + +### 3. Replacing `AuthLayout` with `CustomAuthLayout` + +Next, we need to import and use `CustomAuthLayout` in `packages/plugins/@nocobase-sample/plugin-replace-page/src/client/index.tsx`. + +There are two ways to replace `AuthLayout`: through route override and component override. + +#### Route Override + +As mentioned earlier, the route name for `AuthLayout` is `auth`. We can override it using routes: + +```ts +import { Plugin } from '@nocobase/client'; +import { CustomAuthLayout } from './AuthLayout'; + +export class PluginReplacePageClient extends Plugin { + async load() { + this.app.router.add('auth', { + Component: CustomAuthLayout, + }) + } +} + +export default PluginReplacePageClient; +``` + +The first parameter of the `router.add()` method is the name of the route. If it is added repeatedly, it will override the existing route. + +#### Component Override Method + +```ts +import { Plugin } from '@nocobase/client'; +import { CustomAuthLayout } from './AuthLayout'; + +export class PluginChangePageClient extends Plugin { + async load() { + this.app.addComponents({ AuthLayout: CustomAuthLayout }) + } +} +``` + +It should be noted that this method of overriding must be done using *string Component* to register the route. For example, the source code of the [auth plugin](https://github.com/nocobase/nocobase/blob/cff530acac45cc615291c344b4a26c7bc7f410dc/packages/plugins/%40nocobase/plugin-auth/src/client/index.tsx#L47) is as follows: + +```ts +this.app.router.add('auth', { + Component: 'AuthLayout', +}) + +this.app.addComponents({ AuthLayout }) +``` + +If the source code of the `auth` plugin is registered in the following way, it cannot be overridden: + +```ts +this.app.router.add('auth', { + Component: AuthLayout, +}) +``` + +Then we log out and visit [http://localhost:13000/signin](http://localhost:13000/signin) to see that the layout of the login page has been changed. + +![20240512200917](https://static-docs.nocobase.com/20240512200917.png) + +## Packaging and Uploading to Production Environment + +According to the documentation on [Building and Packaging Plugins](/development/your-fisrt-plugin#building-and-packaging-plugins), we can package the plugin and upload it to the production environment. + +If you have cloned the source code, you need to perform a full build first to build the dependencies of the plugin as well. + +```bash +yarn build +``` + +If you are using `create-nocobase-app` to create your project, you can directly execute: + +```bash +yarn build @nocobase-sample/plugin-replace-page --tar +``` + +This way, you can see the `storage/tar/@nocobase-sample/plugin-replace-page.tar.gz` file, and then install it using the [upload method](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/schema-initailizer/add-item-to-block.md b/docs/fr-FR/plugin-samples/schema-initailizer/add-item-to-block.md new file mode 100644 index 000000000..80c31cb0b --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initailizer/add-item-to-block.md @@ -0,0 +1,167 @@ +# Partial Registration of Component and Scope + +## Example Description + +The functionality to be implemented is similar to the [Global Registration of Component and Scope](/plugin-samples/component-and-scope/global) example, but this time, the component and scope will be registered within the plugin itself, instead of globally. + +You can view the complete sample code for this document in [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-component-and-scope-local). + +## Initialize the Plugin + +Following the guide on [Writing Your First Plugin](/development/your-first-plugin), if you do not yet have a project, you can create one first. If you already have a project or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Next, initialize a plugin and add it to the system: + +```bash +yarn pm create @nocobase-sample/plugin-component-and-scope-local +yarn pm enable @nocobase-sample/plugin-component-and-scope-local +``` + +Then, start the project: + +```bash +yarn dev +``` + +After logging in, go to [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to confirm that the plugin has been installed and enabled. + +--- + +# Functionality Implementation + +## 1. Creating a Custom Page + +Create a new file `packages/plugins/@nocobase-sample/plugin-component-and-scope-local/src/client/CustomPage.tsx` with the following content: + +```tsx | pure +import React from "react" + +export const SamplesCustomPage = () => { + return
    TODO
    +} +``` + +## 2. Rendering Content Directly with `Component` + +For more details on custom page creation, refer to the [Add New Page](/plugin-samples/router/add-page) guide. + +Next, modify the file `packages/plugins/@nocobase-sample/plugin-component-and-scope-local/src/index.ts` as follows: + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { SamplesCustomPage } from './CustomPage' + +export class PluginComponentAndScopeLocalClient extends Plugin { + async load() { + this.app.router.add('admin.custom-page2', { + path: '/admin/custom-page2', + Component: SamplesCustomPage, + }) + } +} + +export default PluginComponentAndScopeLocalClient; +``` + +Unlike global registration, here we directly use the `Component: SamplesCustomPage` instead of passing a string as the component type. + +Next, go to [http://localhost:13000/admin/custom-page2](http://localhost:13000/admin/custom-page2) to see the content of the `SamplesCustomPage` component. + +![img_v3_02av_46e020ae-41d2-4bc3-a047-e28d97c20bdg](https://static-docs.nocobase.com/img_v3_02av_46e020ae-41d2-4bc3-a047-e28d97c20bdg.jpg) + +## 3. Rendering Content with `SchemaComponent` + +You’ll need to understand the following concepts: + +- [Schema Protocol](/development/client/ui-schema/what-is-ui-schema) +- [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) +- [withDynamicSchemaProps](/development/client/ui-schema/what-is-ui-schema#x-component-props-and-x-use-component-props) +- [useFieldSchema()](https://client.docs.nocobase.com/core/ui-schema/designable#usefieldschema) + +Now, modify the file `packages/plugins/@nocobase-sample/plugin-component-and-scope-local/src/client/CustomPage.tsx` as follows: + +```tsx | pure +import { ISchema, SchemaComponent, withDynamicSchemaProps } from "@nocobase/client" +import { uid } from '@formily/shared' +import { useFieldSchema } from '@formily/react' +import React, { FC } from "react" + +const SamplesHello: FC<{ name: string }> = withDynamicSchemaProps(({ name }) => { + return
    hello {name}
    +}) + +const useSamplesHelloProps = () => { + const schema = useFieldSchema(); + return { name: schema.name } +} + +const schema: ISchema = { + type: 'void', + name: uid(), + properties: { + demo1: { + type: 'void', + 'x-component': SamplesHello, + 'x-component-props': { + name: 'demo1', + }, + }, + demo2: { + type: 'void', + 'x-component': SamplesHello, + 'x-use-component-props': useSamplesHelloProps, + }, + demo3: { + type: 'void', + 'x-component': 'SamplesHello', + 'x-component-props': { + name: 'demo3', + }, + }, + demo4: { + type: 'void', + 'x-component': 'SamplesHello', + 'x-use-component-props': 'useSamplesHelloProps', + }, + } +} + +export const SamplesCustomPage = () => { + return +} +``` + +- We defined the `SamplesHello` and `useSamplesHelloProps` components. +- Then, we created a `schema` object where the `demo1` and `demo2` fields use corresponding components and scope, while the `demo3` and `demo4` fields use string-type components and scope. +- Finally, we used the `SchemaComponent`'s `components` and `scope` attributes to locally register `SamplesHello` and `useSamplesHelloProps`. + +Visit [http://localhost:13000/admin/custom-page2](http://localhost:13000/admin/custom-page2) to see the content of the `CustomPage` component. + +![img_v3_02av_e8d4d0c7-7a59-4f9e-a120-a2551e719ebg](https://static-docs.nocobase.com/img_v3_02av_e8d4d0c7-7a59-4f9e-a120-a2551e719ebg.jpg) + +--- + +# Packaging and Uploading to Production + +Following the guide on [Building and Packaging Plugins](/development/your-first-plugin#building-and-packaging-plugins), you can package the plugin and upload it to the production environment. + +If you cloned the source code, you need to perform a full build to package the plugin's dependencies: + +```bash +yarn build +``` + +If you used `create-nocobase-app` to create the project, simply run: + +```bash +yarn build @nocobase-sample/plugin-component-and-scope-local --tar +``` + +This will generate the file `storage/tar/@nocobase-sample/plugin-component-and-scope-local.tar.gz`, which you can then upload using the [plugin upload method](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/schema-initailizer/index.md b/docs/fr-FR/plugin-samples/schema-initailizer/index.md new file mode 100644 index 000000000..84c9d0ca3 --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initailizer/index.md @@ -0,0 +1,15 @@ +# SchemaInitializer + +[SchemaInitializer](/development/client/ui-schema/initializer) 用于向界面内添加各种区块、字段、操作等。 + +根据需求不同可能有以下扩展场景: + +- 向已有的 Initializer 中添加子项 +- 创建新的 Initializer + +根据以上场景,我们提供了如下示例: + +- [向已有的 Add block 里添加新子项](/plugin-samples/schema-initializer/add-item-to-block) +- [向已有的 Configure actions 里添加新子项](/plugin-samples/schema-initializer/add-item-to-actions) +- [复用已有的 Initializer 子项](/plugin-samples/schema-initializer/reuse-existing-item) +- [创建并使用新的 Initializer](/plugin-samples/schema-initializer/create-new) diff --git a/docs/fr-FR/plugin-samples/schema-initializer/action-modal.md b/docs/fr-FR/plugin-samples/schema-initializer/action-modal.md new file mode 100644 index 000000000..983139e16 --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initializer/action-modal.md @@ -0,0 +1,356 @@ +# Adding a Popup Action + +## Scenario Description + +In NocoBase, there are many `Configure actions` used to add operation buttons to the interface. + +![img_v3_02b4_51f4918f-d344-43b2-b19e-48dca709467g](https://static-docs.nocobase.com/img_v3_02b4_51f4918f-d344-43b2-b19e-48dca709467g.jpg) + +If the existing action buttons do not fully meet our needs, we can add sub-items to the current `Configure actions` to create new action buttons. + +## Example Description + +In this example, we will create a button that, when clicked, opens a popup. The popup contains a document embedded in an iframe. This button will be added to the `Table`, `Details`, and `Form` blocks within the `Configure actions`. + +The complete example code can be found in [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-initializer-action-modal). + + + +## Initializing the Plugin + +Follow the instructions in [Creating Your First Plugin](/development/your-fisrt-plugin). If you don’t already have a project, you can create one. If you already have one or have cloned the source code, you can skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Next, initialize a plugin and add it to the system: + +```bash +yarn pm create @nocobase-sample/plugin-initializer-action-modal +yarn pm enable @nocobase-sample/plugin-initializer-action-modal +``` + +Then, start the project: + +```bash +yarn dev +``` + +After logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to verify that the plugin is installed and enabled. + +## Functionality Implementation + +Before implementing this example, we need to understand some foundational knowledge: + +- [Action Component](https://client.docs.nocobase.com/components/action) +- [SchemaInitializer Tutorial](/development/client/ui-schema/initializer): Used to add blocks, fields, actions, etc., to the interface +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer): Also for adding blocks, fields, actions, etc., to the interface +- [UI Schema](/development/client/ui-schema/what-is-ui-schema): Defines the structure and style of the interface +- [Designable Designer](/development/client/ui-schema/designable): Used to modify the schema + +```bash +. +├── client # Client-side plugin +│ ├── initializer # Initializer +│ ├── index.tsx # Client-side plugin entry point +│ ├── locale.ts # Localization utility functions +│ ├── constants.ts # Constants +│ ├── schema # Schema +│ └── settings # Schema Settings +├── locale # Localization files +│ ├── en-US.json # English +│ └── zh-CN.json # Chinese +├── index.ts # Server-side plugin entry point +└── server # Server-side plugin +``` + +## 1. Define the Name + +First, we need to define the action name, which will be used in several places. + +Create the file `packages/plugins/@nocobase-sample/plugin-initializer-action-modal/src/client/constants.ts`: + +```ts +export const ActionName = 'Open Document'; +export const ActionNameLowercase = 'open-document'; +``` + +## 2. Define the Schema + +### 2.1 Define the Schema + +NocoBase’s dynamic pages are rendered using schemas, so we need to define a schema for later use to add elements to the interface. Before proceeding, we need to understand the following concepts: + +- [Action Component](https://client.docs.nocobase.com/components/action) +- [Action.Drawer Component](https://client.docs.nocobase.com/components/action#actiondrawer) +- [UI Schema Protocol](/development/client/ui-schema/what-is-ui-schema): This document explains the structure of the schema and the purpose of each attribute + +We will create a new file, `packages/plugins/@nocobase-sample/plugin-initializer-action-modal/src/client/schema/index.ts`, with the following content: + +```ts +import { ISchema } from "@nocobase/client" +import { tStr } from "../locale"; +import { ActionName } from "../constants"; + +export const createDocumentActionModalSchema = (blockComponent: string): ISchema => { + return { + type: 'void', + 'x-component': 'Action', + title: tStr(ActionName), + 'x-component-props': { + type: 'primary' + }, + properties: { + drawer: { + type: 'void', + 'x-component': 'Action.Drawer', + 'x-component-props': { + size: 'large' + }, + properties: { + iframe: { + type: 'void', + 'x-component': 'iframe', + 'x-component-props': { + src: `https://client.docs.nocobase.com/components/${blockComponent}`, + style: { + border: 'none', + width: '100%', + height: '100%' + } + }, + } + } + }, + }, + } +} +``` + +The `createDocumentActionModalSchema` component accepts a `blockComponent` parameter and returns a schema. This schema adds a button to the interface that, when clicked, opens a popup. The popup contains an iframe with the block's document as its source. + +`createDocumentActionModalSchema`: +- `type`: Specifies the type of component. Here, it’s `void`, meaning it’s a purely UI component +- `x-component: 'Action'`: [Action Component](https://client.docs.nocobase.com/components/action), used to generate a button +- `title: 'Open Document'`: The title of the button +- `properties`: Child nodes + - ['x-component': 'Action.Drawer'](https://client.docs.nocobase.com/components/action#actiondrawer): Refers to the Action.Drawer component + +For more details on the schema, refer to the [UI Schema](/development/client/ui-schema/what-is-ui-schema) documentation. + +### 2.2 Validate the Schema + +There are two methods for validating the schema: + +- Temporary page validation: You can create a temporary page, render the schema, and check if it meets the requirements +- Documentation example validation: Start the documentation by running `yarn doc plugins/@nocobase-sample/plugin-initializer-action-modal`, and validate by creating a documentation example (TODO) + +We’ll use the `Temporary Page Validation` method. Create a new page, add one or more examples based on the attribute parameters, and check if they meet the requirements. + +```tsx | pure +import React from 'react'; +import { Plugin, SchemaComponent } from '@nocobase/client'; +import { createDocumentActionModalSchema } from './schema'; + +export class PluginInitializerActionModalClient extends Plugin { + async load() { + this.app.router.add('admin.open-document-schema', { + path: '/admin/open-document-schema', + Component: () => { + return <> +
    + +
    +
    + +
    + + } + }) + } +} + +export default PluginInitializerActionModalClient; +``` + +Afterward, visit [http://localhost:13000/admin/open-document-schema](http://localhost:13000/admin/open-document-schema) to view the temporary page we’ve added. + +For detailed information on `SchemaComponent`, refer to the [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) documentation. + + + +Once validation is complete, be sure to remove the test page. + +# 3. Define Schema Initializer Item + +We will add a new file `packages/plugins/@nocobase-sample/plugin-initializer-action-modal/src/client/initializer/index.ts`: + +```ts +import { SchemaInitializerItemType, useSchemaInitializer } from "@nocobase/client" + +import { useT } from "../locale"; +import { createDocumentActionModalSchema } from '../schema'; +import { ActionName, ActionNameLowercase } from "../constants"; + +export const createDocumentActionModalInitializerItem = (blockComponent: string): SchemaInitializerItemType => ({ + type: 'item', + title: ActionName, + name: ActionNameLowercase, + useComponentProps() { + const { insert } = useSchemaInitializer(); + const t = useT(); + return { + title: t(ActionName), + onClick: () => { + insert(createDocumentActionModalSchema(blockComponent)); + }, + }; + }, +}) +``` + +Since we need to generate different `DocumentActionModal` instances based on various `blockComponent` values, we define the `createDocumentActionModalInitializerItem` function to generate the corresponding Schema Initializer Item. + +- `type`: This is set as `item`, indicating a text element that triggers an event upon clicking, inserting a new Schema. +- `name`: A unique identifier that helps distinguish between different Schema Items and operations, such as creating, reading, updating, and deleting. +- `useComponentProps`: Returns an object that includes the `title` and `onClick` properties. The `title` is the displayed text, and `onClick` is the callback function executed when clicked. +- [useSchemaInitializer](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#useschemainitializer): Retrieves the `SchemaInitializerContext`, which provides methods for operational tasks. + +For further details on defining Schema Items, refer to the [Schema Initializer Item](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#built-in-components-and-types) documentation. + +# 4. Implement Schema Settings + +## 4.1 Define Schema Settings + +At the moment, once added via `createDocumentActionInitializerItem()`, items cannot be removed. We can address this by using [Schema Settings](https://client.docs.nocobase.com/core/ui-schema/schema-settings). + +We will add a new file: `packages/plugins/@nocobase-sample/plugin-initializer-action-modal/src/client/settings/index.ts`: + +```ts +import { SchemaSettings } from "@nocobase/client"; +import { ActionNameLowercase } from "../constants"; + +export const documentActionModalSettings = new SchemaSettings({ + name: `actionSettings:${ActionNameLowercase}`, + items: [ + { + name: 'remove', + type: 'remove', + } + ] +}); +``` + +## 4.2 Register Schema Settings + +```ts +import { Plugin } from '@nocobase/client'; +import { documentActionModalSettings } from './settings'; + +export class PluginInitializerActionModalClient extends Plugin { + async load() { + this.app.schemaSettingsManager.add(documentActionModalSettings); + } +} + +export default PluginInitializerActionModalClient; +``` + +## 4.3 Use Schema Settings + +We will modify the `createDocumentActionModalSchema` function in `packages/plugins/@nocobase-sample/plugin-initializer-action-modal/src/client/schema/index.ts`, adding `documentActionModalSettings` to `x-settings`. + +```diff +export const createDocumentActionModalSchema = (blockComponent: string): ISchema => { + return { + type: 'void', + 'x-component': 'Action', ++ 'x-settings': documentActionModalSettings.name, + // .. + } +} +``` + +# 5. Add to Configure Actions in the Page + +There are several `Configure actions` buttons in the system, but their **names differ**. We will add the necessary items to the `Table`, `Details`, and `Form` sections' `Configure actions`. + +First, we will identify the appropriate names: + +TODO + +Then, modify the `packages/plugins/@nocobase-sample/plugin-initializer-action-modal/src/client/index.tsx` file: + +```diff +import { Plugin } from '@nocobase/client'; +import { documentActionModalSettings } from './documentActionModalSettings'; +import { createDocumentActionModalInitializerItem } from './documentActionModalInitializerItem'; + +export class PluginInitializerActionModalClient extends Plugin { + async load() { + this.app.schemaSettingsManager.add(documentActionModalSettings); ++ this.app.schemaInitializerManager.addItem('table:configureActions', 'open-document', createDocumentActionModalInitializerItem('table-v2')); ++ this.app.schemaInitializerManager.addItem('details:configureActions', 'open-document', createDocumentActionModalInitializerItem('details')); ++ this.app.schemaInitializerManager.addItem('createForm:configureActions', 'open-document', createDocumentActionModalInitializerItem('form-v2')); + } +} + +export default PluginInitializerActionModalClient; +``` + + + +# 6. Multi-language Support + +:::warning +Changes to the language files will take effect only after restarting the service. +::: + +### 6.1 English + +We will edit the file `packages/plugins/@nocobase-sample/plugin-initializer-action-simple/src/locale/en-US.json`: + +```json +{ + "Document": "Document" +} +``` + +### 6.2 Chinese + +We will edit the file `packages/plugins/@nocobase-sample/plugin-initializer-action-simple/src/locale/zh-CN.json`: + +```json +{ + "Document": "文档" +} +``` + +If additional language support is required, more languages can be added. + +You can manage multiple languages and switch between them through the UI at [http://localhost:13000/admin/settings/system-settings](http://localhost:13000/admin/settings/system-settings). + +![20240611113758](https://static-docs.nocobase.com/20240611113758.png) + +## Packaging and Uploading to Production + +Following the guidelines outlined in the [Build and Package Plugins](/development/your-fisrt-plugin#build-and-package-plugins) documentation, we can package the plugin and deploy it to the production environment. + +For cloned source code, ensure a full build is executed first to compile plugin dependencies: + +```bash +yarn build +``` + +For projects created using `create-nocobase-app`, execute the following: + +```bash +yarn build @nocobase-sample/plugin-initializer-action-modal --tar +``` + +This will generate the file `storage/tar/@nocobase-sample/plugin-initializer-action-modal.tar.gz`, which can then be installed by following the [upload process](/welcome/getting-started/plugin). + diff --git a/docs/fr-FR/plugin-samples/schema-initializer/action-simple.md b/docs/fr-FR/plugin-samples/schema-initializer/action-simple.md new file mode 100644 index 000000000..43a92ee19 --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initializer/action-simple.md @@ -0,0 +1,280 @@ +# Adding a Simple Action + +## Scenario Description + +NocoBase provides various `Configure actions` for adding action buttons to the interface. + +![img_v3_02b4_51f4918f-d344-43b2-b19e-48dca709467g](https://static-docs.nocobase.com/img_v3_02b4_51f4918f-d344-43b2-b19e-48dca709467g.jpg) + +If the existing action buttons do not fully meet our needs, we can add new buttons by creating sub-items within the `Configure actions`. + +The term "simple action" in the title refers to actions that do not require a popup. For details on how to add a popup action, refer to [Adding a Popup Action](/plugin-samples/schema-initializer/action-modal). + +## Example Explanation + +This example creates a button that opens the corresponding block's documentation when clicked. This button will be added to the `Table`, `Details`, and `Form` blocks within the `Configure actions`. + +You can view the complete sample code in [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-initializer-action-simple). + + + +## Initializing the Plugin + +Following the instructions in the [Writing Your First Plugin](/development/your-first-plugin) document, you can create a project if one does not already exist. If you have an existing project or cloned the source code, skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Next, initialize a plugin and add it to the system: + +```bash +yarn pm create @nocobase-sample/plugin-initializer-action-simple +yarn pm enable @nocobase-sample/plugin-initializer-action-simple +``` + +Then, start the project: + +```bash +yarn dev +``` + +Once logged in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to confirm that the plugin is installed and enabled. + +## Functionality Implementation + +Before implementing this example, we need to understand some basic concepts: + +- [Action Component](https://client.docs.nocobase.com/components/action) +- [SchemaInitializer Tutorial](/development/client/ui-schema/initializer): Used for adding various blocks, fields, and actions to the interface. +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer): Used for adding various blocks, fields, and actions to the interface. +- [UI Schema](/development/client/ui-schema/what-is-ui-schema): Defines the structure and style of the interface. +- [Designable Designer](/development/client/ui-schema/designable): Used for modifying the schema. + +```bash +. +├── client # Client-side plugin +│ ├── initializer # Initializer +│ ├── index.tsx # Client-side plugin entry +│ ├── locale.ts # Multilingual utility functions +│ ├── constants.ts # Constants +│ ├── schema # Schema +│ └── settings # Schema Settings +├── locale # Multilingual files +│ ├── en-US.json # English +│ └── zh-CN.json # Chinese +├── index.ts # Server-side plugin entry +└── server # Server-side plugin +``` + +### 1. Define the Name + +First, we need to define the action name, which will be used in various places. + +Create the file `packages/plugins/@nocobase-sample/plugin-initializer-action-simple/src/client/constants.ts`: + +```ts +export const ActionName = 'Document'; +export const ActionNameLowercase = ActionName.toLowerCase(); +``` + +### 2. Define the Schema + +#### 2.1 Define the Schema + +NocoBase’s dynamic pages are rendered through schemas, so we need to define a schema that will be used to add the button to the interface. Before proceeding, it's important to understand some basic concepts: + +- [Action Component](https://client.docs.nocobase.com/components/action) +- [UI Schema Protocol](/development/client/ui-schema/what-is-ui-schema): Detailed introduction to the structure and functionality of schema attributes. + +Create the file `packages/plugins/@nocobase-sample/plugin-initializer-action-simple/src/client/schema/index.ts` with the following content: + +```ts +import { useFieldSchema } from '@formily/react'; +import { ISchema } from "@nocobase/client" +import { useT } from '../locale'; +import { ActionName } from '../constants'; + +export function useDocumentActionProps() { + const fieldSchema = useFieldSchema(); + const t = useT(); + return { + title: t(ActionName), + type: 'primary', + onClick() { + window.open(fieldSchema['x-doc-url']) + } + } +} + +export const createDocumentActionSchema = (blockComponent: string): ISchema & { 'x-doc-url': string } => { + return { + type: 'void', + 'x-component': 'Action', + 'x-doc-url': `https://client.docs.nocobase.com/components/${blockComponent}`, + 'x-use-component-props': 'useDocumentActionProps', + } +} +``` + +The `createDocumentActionSchema` component takes a `blockComponent` parameter and returns a schema that adds a button to the interface, which opens the corresponding block’s documentation when clicked. + +`createDocumentActionSchema`: +- `type`: Type, here it's `void`, meaning a pure UI component. +- `x-component: 'Action'`: [Action Component](https://client.docs.nocobase.com/components/action) used to create a button. +- `title: 'Document'`: Button title. +- `x-doc-url`: A custom schema property representing the documentation URL. +- `x-use-component-props: 'useDocumentActionProps'`: Dynamic properties, more details can be found in [the documentation](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props). + +`useDocumentActionProps()`: +- [useFieldSchema()](https://client.docs.nocobase.com/core/ui-schema/designable#usefieldschema): Retrieves the schema of the current node. +- `type: 'primary'`: Button type. +- `onClick`: Click event, opens the corresponding block’s documentation. + +For more details on schemas, refer to the [UI Schema](/development/client/ui-schema/what-is-ui-schema) documentation. + +### 4. Implement Schema Settings + +#### 4.1 Define Schema Settings + +Currently, after adding through `createDocumentActionInitializerItem()`, items cannot be deleted. We can use [Schema Settings](https://client.docs.nocobase.com/core/ui-schema/schema-settings) for configuration. + +We add a new file `packages/plugins/@nocobase-sample/plugin-initializer-action-simple/src/client/settings/index.ts`: + +```ts +import { SchemaSettings } from "@nocobase/client"; + +import { ActionNameLowercase } from "../constants"; + +export const documentActionSettings = new SchemaSettings({ + name: `actionSettings:${ActionNameLowercase}`, + items: [ + { + name: 'remove', + type: 'remove', + } + ] +}); +``` + +#### 4.2 Register Schema Settings + +```diff +import { Plugin } from '@nocobase/client'; +import { useDocumentActionProps } from './schema'; ++ import { documentActionSettings } from './settings'; + +export class PluginInitializerActionSimpleClient extends Plugin { + async load() { + this.app.addScopes({ useDocumentActionProps }); ++ this.app.schemaSettingsManager.add(documentActionSettings); + } +} + +export default PluginInitializerActionSimpleClient; +``` + +#### 4.3 Use Schema Settings + +We modify the `createDocumentActionSchema` in `packages/plugins/@nocobase-sample/plugin-initializer-action-simple/src/client/schema/index.ts`: + +```diff ++ import { documentActionSettings } from '../settings'; + +export const createDocumentActionSchema = (blockComponent: string): ISchema & { 'x-doc-url': string } => { + return { + type: 'void', + 'x-component': 'Action', ++ 'x-settings': documentActionSettings.name, + // ... + } +} +``` + +### 5. Add to the Configure Actions Page + +There are many `Configure actions` buttons in the system, but their **names are different**. We need to add them to the `Table`, `Details`, and `Form` blocks based on specific requirements. + +First, let's find the corresponding names: + +TODO + +Next, we modify the `packages/plugins/@nocobase-sample/plugin-initializer-action-simple/src/client/index.tsx` file: + +```diff +import { Plugin } from '@nocobase/client'; +import { useDocumentActionProps } from './schema'; +import { documentActionSettings } from './settings'; ++ import { createDocumentActionInitializerItem } from './initializer'; + +export class PluginInitializerActionSimpleClient extends Plugin { + async load() { + this.app.addScopes({ useDocumentActionProps }); + this.app.schemaSettingsManager.add(documentActionSettings); ++ this.app.schemaInitializerManager.addItem('table:configureActions', 'document', createDocumentActionInitializerItem('table-v2')); ++ this.app.schemaInitializerManager.addItem('details:configureActions', 'document', createDocumentActionInitializerItem('details')); ++ this.app.schemaInitializerManager.addItem('createForm:configureActions', 'document', createDocumentActionInitializerItem('form-v2')); + } +} + +export default PluginInitializerActionSimpleClient; +``` + + + +### 6. Multi-language Support + +:::warning +After modifying the multi-language files, you need to restart the service for the changes to take effect. +::: + +#### 6.1 English + +We edit the `packages/plugins/@nocobase-sample/plugin-initializer-action-simple/src/locale/en-US.json` file: + +```json +{ + "Document": "Document" +} +``` + +#### 6.2 Chinese + +We edit the `packages/plugins/@nocobase-sample/plugin-initializer-action-simple/src/locale/zh-CN.json` file: + +```json +{ + "Document": "文档" +} +``` + +If more language support is needed, additional entries can be added. + +You can add multiple languages via [http://localhost:13000/admin/settings/system-settings](http://localhost:13000/admin/settings/system-settings) and switch languages in the upper right corner. + +![20240611113758](https://static-docs.nocobase.com/20240611113758.png) + +### Packaging and Uploading to the Production Environment + +Following the [Build and Package Plugin](/development/your-fisrt-plugin#构建并打包插件) guide, we can package the plugin and upload it to the production environment. + +If the source code was cloned, a full build is needed first to construct the plugin dependencies. + +```bash +yarn build +``` + +If the project was created using `create-nocobase-app`, simply run: + +```bash +yarn build @nocobase-sample/plugin-initializer-action-simple --tar +``` + +Afterward, you will see the file `storage/tar/@nocobase-sample/plugin-initializer-action-simple.tar.gz`, which can be uploaded for installation following the [upload guide](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/plugin-samples/schema-initializer/block-data-modal.md b/docs/fr-FR/plugin-samples/schema-initializer/block-data-modal.md new file mode 100644 index 000000000..49fdb9db7 --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initializer/block-data-modal.md @@ -0,0 +1,843 @@ +# 添加带弹窗的数据区块 Data Block Modal + +## 场景说明 + +很多情况下在点击创建区块之前,我们需要先选择配置信息。例如: +- `Kanban` 区块点击后需要先选择 `Grouping field` 和 `Sorting field` +- `Calendar` 区块需要先选择 `Title field`、`Start date field`、`End date field` +- `Chart` 区块需要先配置图标相关信息 + +
    + + + +## 示例说明 + +本实例会基于 ant-design [Timeline 组件](https://ant.design/components/timeline) 创建一个 `Timeline` 区块,并且在区块创建前选择 `Time Field` 和 `Title Field`。 + +本实例主要为了演示 initializer 的使用,更多关于区块扩展可以查看 [区块扩展](/plugin-samples/block) 文档。 + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-initializer-block-data-modal) 中查看。 + + + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-initializer-block-data-modal +yarn pm enable @nocobase-sample/plugin-initializer-block-data-modal +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +在实现本示例之前,我们需要先了解一些基础知识: + +- ant-design [Timeline 组件](https://ant.design/components/timeline) +- [SchemaInitializer 教程](/development/client/ui-schema/initializer):用于向界面内添加各种区块、字段、操作等 +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于向界面内添加各种区块、字段、操作等 +- [UI Schema](/development/client/ui-schema/what-is-ui-schema):用于定义界面的结构和样式 +- [Designable 设计器](/development/client/ui-schema/designable):用于修改 Schema + +```bash +. +├── client # 客户端插件 +│ ├── initializer # 初始化器 +│ ├── component # 区块组件 +│ ├── index.tsx # 客户端插件入口 +│ ├── locale.ts # 多语言工具函数 +│ ├── constants.ts # 常量 +│ ├── schema # Schema +│ └── settings # Schema Settings +├── locale # 多语言文件 +│ ├── en-US.json # 英语 +│ └── zh-CN.json # 中文 +├── index.ts # 服务端插件入口 +└── server # 服务端插件 +``` + +### 1. 定义名称 + +我们首先需要定义区块名称,它将会使用在各个地方。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/constants.ts`: + +```ts +export const BlockName = 'Timeline'; +export const BlockNameLowercase = BlockName.toLowerCase(); +``` + +### 2. 实现区块组件 + +#### 2.1 定义区块组件 + +本示例要做的是一个 `Timeline` 区块组件,其具体的需求是: + +首先我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/component/Timeline.tsx` 文件,其内容如下: + +```tsx | pure +import React, { FC } from 'react'; +import { Timeline as AntdTimeline, TimelineProps as AntdTimelineProps, Spin } from 'antd'; +import { withDynamicSchemaProps } from "@nocobase/client"; +import { BlockName } from '../constants'; + +export interface TimelineProps { + data?: AntdTimelineProps['items']; + loading?: boolean; +} + +export const Timeline: FC = withDynamicSchemaProps((props) => { + const { data, loading } = props; + if (loading) return
    + return +}, { displayName: BlockName }); +``` + +`Timeline` 组件整体来说是一个被 `withDynamicSchemaProps` 包裹的组件,其接受 2 个参数: + +- `loading`:数据加载状态 +- `data`:`Timeline` 组件的 `items` 属性 + +[withDynamicSchemaProps](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) 是一个高阶组件,用于处理 Schema 中的的动态属性。 + +#### 2.2 注册区块组件 + +我们需要将 `Timeline` 通过插件注册到系统中。 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Timeline } from './component'; + +export class PluginInitializerBlockDataModalClient extends Plugin { + async load() { + this.app.addComponents({ Timeline }) + } +} + +export default PluginInitializerBlockDataModalClient; +``` + +#### 2.3 验证区块组件 + +组件验证方式有 2 种: + +- 临时页面验证:我们可以临时建一个页面,然后渲染 `Timeline` 组件,查看是否符合需求 +- 文档示例验证:可以启动文档 `yarn doc plugins/@nocobase-sample/plugin-initializer-block-data-modal`,通过写文档示例的方式验证是否符合需求(TODO) + +我们以 `临时页面验证` 为例,我们新建一个页面,根据属性参数添加一个或者多个 `Timeline` 组件,查看是否符合需求。 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Timeline } from './component'; +import React from 'react'; + +export class PluginInitializerBlockDataModalClient extends Plugin { + async load() { + this.app.addComponents({ Timeline }) + + this.app.router.add('admin.timeline-block-component', { + path: '/admin/timeline-block-component', + Component: () => { + return <> +
    + +
    +
    + +
    + + } + }) + } +} + +export default PluginInitializerBlockDataModalClient; +``` + +然后访问 `http://localhost:13000/admin/timeline-block-component` 就可以看到对应测试页面的内容了。 + +![20240529210122](https://static-docs.nocobase.com/20240529210122.png) + +验证完毕后需要删除测试页面。 + +### 3. 定义配置表单 + +根据需求,我们需要在选择数据表后配置 `Time Field` 和 `Title Field`,所以我们需要定义一个配置表单,取名为 `TimelineInitializerConfigForm`。 + +#### 3.1 定义配置表单组件 + +我们需要先了解以下知识: + +- [Action](https://client.docs.nocobase.com/components/action) +- [Action.Modal](https://client.docs.nocobase.com/components/action#actionmodal):弹窗 +- [ActionContextProvider](https://client.docs.nocobase.com/components/action#actioncontext):`Action` 上下文 +- [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1):用于渲染 Schema + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/initializer/ConfigForm.tsx` 文件,其内容如下: + +```tsx | pure +import React, { FC, useMemo } from "react"; +import { ISchema } from '@formily/react'; +import { ActionContextProvider, SchemaComponent, useApp, CollectionFieldOptions } from '@nocobase/client'; +import { useT } from "../locale"; + +const createSchema = (fields: CollectionFieldOptions, t: ReturnType): ISchema => { + // TODO +} + +interface TimelineConfigFormValues { + timeField: string; + titleField: string; +} + +export interface TimelineConfigFormProps { + collection: string; + dataSource?: string; + onSubmit: (values: TimelineConfigFormValues) => void; + visible: boolean; + setVisible: (visible: boolean) => void; +} + +export const TimelineInitializerConfigForm: FC = ({ visible, setVisible, collection, dataSource, onSubmit }) => { + const app = useApp(); + const fields = useMemo(() => app.getCollectionManager(dataSource).getCollection(collection).getFields(), [collection, dataSource]) + const t = useT(); + const schema = useMemo(() => createSchema(fields, t), [fields]); + + return + + +} +``` + +`TimelineInitializerConfigForm` 组件接受 4 个参数: + +- `visible`:是否显示 +- `setVisible`:设置是否显示 +- `collection`:数据表名称 +- `dataSource`:数据源名称 +- `onSubmit`:表单提交回调 + +其中 `collection` 和 `dataSource` 是通过点击数据表后获取的,所以这里是动态的。 + +- [app](https://client.docs.nocobase.com/core/application/application):通过 [useApp()](https://client.docs.nocobase.com/core/application/application#useapp) 获取应用实例 +- [app.getCollectionManager](https://client.docs.nocobase.com/core/application/application##appgetcollectionmanager):获取 [CollectionManager](https://client.docs.nocobase.com/core/data-source/collection-manager) 实例 +- [getCollection](https://client.docs.nocobase.com/core/data-source/collection-manager#getcollectionpath):获取数据表 +- [getFields](https://client.docs.nocobase.com/core/data-source/collection#collectiongetfieldspredicate):获取数据表字段 + +[ActionContextProvider](https://client.docs.nocobase.com/components/action#actioncontext) 用于传递 `visible` 和 `setVisible` 给子节点,`SchemaComponent` 用于渲染 Schema。 + +#### 3.2 实现配置表单 Schema + +我们需要先了解以下知识: + +- [FormV2](https://client.docs.nocobase.com/components/form-v2):表单组件 +- [Select](https://client.docs.nocobase.com/components/action#select):选择器 + +```tsx | pure +const useCloseActionProps = () => { + const { setVisible } = useActionContext(); + return { + type: 'default', + onClick() { + setVisible(false); + }, + }; +}; + +const useSubmitActionProps = (onSubmit: (values: TimelineConfigFormValues) => void) => { + const { setVisible } = useActionContext(); + const form = useForm(); + + return { + type: 'primary', + async onClick() { + await form.submit(); + const values = form.values; + onSubmit(values); + setVisible(false); + }, + }; +}; + +const createSchema = (fields: CollectionFieldOptions[]): ISchema => { + return { + type: 'void', + name: uid(), + 'x-component': 'Action.Modal', + 'x-component-props': { + width: 600, + }, + 'x-decorator': 'FormV2', + properties: { + titleField: { + type: 'string', + title: 'Title Field', + required: true, + enum: fields.map(item => ({ label: item.uiSchema?.title || item.name, value: item.name })), + 'x-decorator': 'FormItem', + 'x-component': 'Select', + }, + timeField: { + type: 'string', + title: 'Time Field', + required: true, + enum: fields.filter(item => item.type === 'date').map(item => ({ label: item.uiSchema?.title || item.name, value: item.name })), + 'x-decorator': 'FormItem', + 'x-component': 'Select', + }, + footer: { + type: 'void', + 'x-component': 'Action.Modal.Footer', + properties: { + close: { + title: 'Close', + 'x-component': 'Action', + 'x-component-props': { + type: 'default', + }, + 'x-use-component-props': 'useCloseActionProps', + }, + submit: { + title: 'Submit', + 'x-component': 'Action', + 'x-use-component-props': 'useSubmitActionProps', + }, + }, + }, + } + }; +} +``` + +我们定义了一个 `createSchema` 函数,用于生成配置表单的 Schema,其接受一个 `fields` 参数,这个参数是数据表的字段。 + +上述的效果是弹窗内有一个表单,表单内有 2 个选择器,一个是 `Title Field`,一个是 `Time Field`,并且有一个 `Close` 和 `Submit` 按钮。 + +- `Close` 和 `Submit` 按钮因为要使用 Hooks,所以我们使用了 [x-use-component-props](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) +- `Title Field`:所有字段都可以选择 +- `Time Field`:只有 `date` 类型的字段可以选择 + +然后我们还需要修改 `TimelineInitializerConfigForm`,将 `useSubmitActionProps` 和 `useCloseActionProps` 注册到 [scope](/plugin-samples/component-and-scope/local) 中。 + +```diff +- ++ +``` + +#### 3.3 验证配置表单 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Timeline } from './component'; +import React, { useState } from 'react'; +import { TimelineInitializerConfigForm } from './initializer/ConfigForm'; + +export class PluginInitializerBlockDataModalClient extends Plugin { + async load() { + this.app.addComponents({ Timeline }) + + this.app.router.add('admin.timeline-config-form', { + path: '/admin/timeline-config-form', + Component: () => { + const [visible, setVisible] = useState(true); + function onSubmit(values) { + console.log(values); + } + return <> +
    + +
    + + } + }) + } +} + +export default PluginInitializerBlockDataModalClient; +``` + +然后访问 `http://localhost:13000/admin/timeline-config-form` 就可以看到对应测试页面的内容了。 + + + +验证完毕后需要删除测试页面。 + +### 4. 定义区块 Schema + +#### 4.1 定义区块 Schema + +NocoBase 的动态页面都是通过 Schema 来渲染,所以我们需要定义一个 Schema,后续用于在界面中添加 `Timeline` 区块。在实现本小节之前,我们需要先了解一些基础知识: + +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 +- [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider):数据区块 + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/schema/index.tsx` 文件: + +```ts +import { useDataBlockProps, useDataBlockRequest } from "@nocobase/client"; +import { TimelineProps } from '../component'; +import { BlockName, BlockNameLowercase } from "../constants"; + +interface GetTimelineSchemaOptions { + dataSource?: string; + collection: string; + titleField: string; + timeField: string; +} + +export function getTimelineSchema(options: GetTimelineSchemaOptions) { + return { + type: 'void', + "x-toolbar": "BlockSchemaToolbar", + 'x-decorator': 'DataBlockProvider', + 'x-decorator-props': { + dataSource, + collection, + action: 'list', + params: { + sort: `-${timeField}` + }, + [BlockNameLowercase]: { + titleField, + timeField, + } + }, + 'x-component': 'CardItem', + properties: { + [BlockNameLowercase]: { + type: 'void', + 'x-component': BlockName, + 'x-use-component-props': 'useTimelineProps', + } + } + } +} + +export function useTimelineProps(): TimelineProps { + const dataProps = useDataBlockProps(); + const props = dataProps[BlockNameLowercase]; + const { loading, data } = useDataBlockRequest(); + return { + loading, + data: data?.data?.map((item) => ({ + label: item[props.timeField], + children: item[props.titleField], + })) + } +} +``` + +这里有 2 个点需要说明: + +`getTimelineSchema()` 接收 `dataSource`、`collection`、`titleField`、`timeField` 并返回一个 Schema,这个 Schema 用于渲染 `Timeline` 区块: + - `type: 'void'`:表示没有任何数据 + - `x-decorator: 'DataBlockProvider'`:数据区块提供者,用于提供数据,更多关于 DataBlockProvider 可以查看 [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider) + - `x-decorator-props`:`DataBlockProvider` 的属性 + - `dataSource`:数据源 + - `collection`:数据表 + - `action: 'list'`:操作类型,这里是 `list`,获取数据列表 + - `params: { sort }`:请求参数,这里我们将 `timeField` 倒叙,更多关于请求参数请参考 [useRequest](https://client.docs.nocobase.com/core/request#userequest) + - `x-component: 'CardItem'`:[CardItem 组件](https://client.docs.nocobase.com/components/card-item),目前的区块都是被包裹在卡片中的,用于提供样式、布局和拖拽等功能 + - `'x-component': 'Timeline'`:区块组件,就是我们定义的 `Timeline` 组件 + - `'x-use-component-props': 'useTimelineProps'`:用于处理 `Timeline` 组件的动态属性,并且因为要存到数据库,所以这里的值类型为 string 类型。 + +`useTimelineProps()`:Timeline 组件的动态属性 + - [useDataBlockProps](https://client.docs.nocobase.com/core/data-block/data-block-provider#usedatablockprops):获取 [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider) 的 props 属性,也就是 `x-decorator-props` 的值 + - [useDataBlockRequest](https://client.docs.nocobase.com/core/data-block/data-block-request-provider#usedatablockrequest) 获取数据区块请求,由 [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider) 提供 + +上述 Schema 转为 React 组件后相当于: + +```tsx | pure + + + + + +``` + +#### 4.2 注册 scope + +我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/index.tsx` 文件,将 `useTimelineProps` 注册到系统中,这样 `x-use-component-props` 才能找到对应的 scope。 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Timeline } from './component'; +import { useTimelineProps } from './schema'; + +export class PluginInitializerBlockDataModalClient extends Plugin { + async load() { + this.app.addComponents({ Timeline }) + this.app.addScopes({ useTimelineProps }); + } +} + +export default PluginInitializerBlockDataModalClient; +``` + +更多关于 Scope 的说明可以查看 [全局注册 Component 和 Scope](/plugin-samples/component-and-scope/global) + +#### 4.3 验证区块 Schema + +同验证组件一样,我们可以通过临时页面验证或者文档示例验证的方式来验证 Schema 是否符合需求。我们这里以临时页面验证为例: + +```tsx | pure +import { Plugin, SchemaComponent } from '@nocobase/client'; +import { Timeline, getTimelineSchema, useTimelineProps } from './component'; +import React from 'react'; + +export class PluginInitializerBlockDataModalClient extends Plugin { + async load() { + // ... + + this.app.router.add('admin.timeline-schema', { + path: '/admin/timeline-schema', + Component: () => { + return <> +
    + +
    + + } + }) + } +} + +export default PluginInitializerBlockDataModalClient; + +``` + +- [SchemaComponentOptions](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponentoptions):用于传递 Schema 中所需的 `components` 和 `scope`,具体的可查看 [局部注册 Component 和 Scope](/plugin-samples/component-and-scope/local) +- [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1):用于渲染 Schema + +我们访问 `http://localhost:13000/admin/timeline-schema` 就可以看到对应测试页面的内容了。 + + + +验证完毕后需要删除测试页面。 + +### 5. 定义 Schema Initializer Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/initializer/index.tsx` 文件,定义 Schema Initializer Item: + +```tsx | pure +import React, { useCallback, useState } from 'react'; +import { FieldTimeOutlined } from '@ant-design/icons'; +import { DataBlockInitializer, SchemaInitializerItemType, useSchemaInitializer } from "@nocobase/client"; + +import { getTimelineSchema } from '../schema'; +import { useT } from '../locale'; +import { TimelineConfigFormProps, TimelineInitializerConfigForm } from './ConfigForm'; +import { BlockName, BlockNameLowercase } from '../constants'; + +export const TimelineInitializerComponent = () => { + const { insert } = useSchemaInitializer(); + const [collection, setCollection] = useState(); + const [dataSource, setDataSource] = useState(); + const [showConfigForm, setShowConfigForm] = useState(false); + const t = useT() + + const onSubmit: TimelineConfigFormProps['onSubmit'] = useCallback((values) => { + const schema = getTimelineSchema({ collection, dataSource, timeField: values.timeField, titleField: values.titleField }); + insert(schema); + }, [collection, dataSource]) + + return <> + {showConfigForm && } + } + componentType={BlockName} + onCreateBlockSchema={({ item }) => { + const { name: collection, dataSource } = item; + setCollection(collection); + setDataSource(dataSource); + setShowConfigForm(true); + }}> + + + +} + +export const timelineInitializerItem: SchemaInitializerItemType = { + name: 'Timeline', + Component: TimelineInitializerComponent, +} +``` + +操作流程是,先点击数据表获取 `collection` 和 `dataSource` 的值,然后通过配置表单 `TimelineInitializerConfigForm` 获取 `timeField` 和 `titleField` 字段,当表单提交时,根据数据创建 schema 并插入到页面。 + +实现数据区块的效果核心是 DataBlockInitializer(文档 TODO)。 + +`timelineInitializerItem`: + - `name`:唯一标识,用于增删改查 + - `Component`:与 [添加简单区块 Simple Block](/plugin-samples/schema-initializer/block-simple) 中使用的是 `type`,这里使用的是 `Component`,[2 种定义方式](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#two-ways-to-define-component-and-type) 都是可以的 + +`TimelineInitializerComponent`: + - `DataBlockInitializer` + - `title`:标题 + - `icon`:图标,更多图标可以查看 [Ant Design Icons](https://ant.design/components/icon/) + - `componentType`:组件类型,这里是 `Timeline` + - `onCreateBlockSchema`:当点击数据表后的回调 + - `item`:点击的数据表信息 + - `item.name`:数据表名称 + - `item.dataSource`:数据表所属的数据源 + - [useSchemaInitializer](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#useschemainitializer):提供了插入 Schema 的方法 + +更多关于 Schema Initializer 的定义可以参考 [Schema Initializer](https://client.docs.nocobase.com/core/ui-schema/schema-initializer) 文档。 + +### 6. 实现 Schema Settings + +#### 6.1 定义 Schema Settings + +一个完整的 Block 还需要有 Schema Settings,用于配置一些属性和操作,但 Schema Settings 不是本示例的重点,所以我们这里仅有一个 `remove` 操作。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/settings/index.ts` 文件,其内容如下: + +```ts +import { SchemaSettings } from "@nocobase/client"; + +export const timelineSettings = new SchemaSettings({ + name: 'blockSettings:info', + items: [ + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}) +``` + +- componentProps + - `removeParentsIfNoChildren`:如果没有子节点,是否删除父节点 + - `breakRemoveOn`:删除时的中断条件。因为 `Add Block` 会自动将子项的包裹在 `Grid` 中,所以这里设置 `breakRemoveOn: { 'x-component': 'Grid' }`,当删除 `Grid` 时,不再向上删除。 + +#### 6.2 注册 Schema Settings + +```ts +import { Plugin } from '@nocobase/client'; +import { timelineSettings } from './settings'; + +export class PluginInitializerBlockDataModalClient extends Plugin { + async load() { + // ... + this.app.schemaSettingsManager.add(timelineSettings) + } +} + +export default PluginInitializerBlockDataModalClient; +``` + +#### 6.3 使用 Schema Settings + +我们需要修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/schema/index.tsx` 的 `getTimelineSchema()` 为: + +```diff ++ import { timelineSettings } from '../settings'; + +export function getTimelineSchema(options: GetTimelineSchemaOptions) { + const { dataSource, collection, titleField, timeField } = options; + return { + type: 'void', + 'x-decorator': 'DataBlockProvider', ++ 'x-settings': timelineSettings.name, + // ... + } +} +``` + +### 7. 添加到 Add block 中 + +系统中有很多个 `Add block` 按钮,但他们的 **name 是不同的**。 + +![img_v3_02b4_049b0a62-8e3b-420f-adaf-a6350d84840g](https://static-docs.nocobase.com/img_v3_02b4_049b0a62-8e3b-420f-adaf-a6350d84840g.jpg) + +#### 7.1 添加到页面级别 Add block 中 + +如果我们需要添加到页面级别的 `Add block` 中,我们需要知道对应的 `name`,我们可以通过 TODO 方式查看对应的 `name`。 + +TODO + +通过上图可以看到页面级别的 `Add block` 对应的 name 为 `page:addBlock`,`Data Blocks` 对应的 name 为 `dataBlocks`。 + +然后我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/index.tsx` 文件: + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Timeline } from './component'; +import { useTimelineProps } from './schema'; +import { timelineSettings } from './settings'; +import { timelineInitializerItem } from './timelineInitializerItem'; + +export class PluginInitializerBlockDataModalClient extends Plugin { + async load() { + this.app.addComponents({ Timeline }) + this.app.addScopes({ useTimelineProps }); + this.app.schemaSettingsManager.add(timelineSettings) + + this.app.schemaInitializerManager.addItem('page:addBlock', `dataBlocks.${timelineInitializerItem.name}`, timelineInitializerItem) + } +} + +export default PluginInitializerBlockDataModalClient; +``` + + + +#### 7.2 添加到弹窗 Add block 中 + +我们不仅需要将其添加到页面级别的 `Add block` 中,还需要将其添加到 `Table` 区块 `Add new` 弹窗的 `Add block` 中。 + +![img_v3_02b4_fc47fe3a-35a1-4186-999c-0b48e6e001dg](https://static-docs.nocobase.com/img_v3_02b4_fc47fe3a-35a1-4186-999c-0b48e6e001dg.jpg) + +我们按照页面级别获取 `name` 的方式获取到 `Table` 区块的 `Add block` 的 `name` 为 `popup:addNew:addBlock`,`Data Blocks` 对应的 name 为 `dataBlocks`。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/index.tsx` 文件: + +```diff +import { Plugin } from '@nocobase/client'; +import { Timeline } from './component'; +import { useTimelineProps } from './schema'; +import { timelineSettings } from './settings'; +import { timelineInitializerItem } from './timelineInitializerItem'; + +export class PluginInitializerBlockDataModalClient extends Plugin { + async load() { + this.app.addComponents({ Timeline }) + this.app.addScopes({ useTimelineProps }); + this.app.schemaSettingsManager.add(timelineSettings) + this.app.schemaInitializerManager.addItem('page:addBlock', `dataBlocks.${timelineInitializerItem.name}`, timelineInitializerItem) ++ this.app.schemaInitializerManager.addItem('popup:addNew:addBlock', `dataBlocks.${timelineInitializerItem.name}`, timelineInitializerItem); + } +} + +export default PluginInitializerBlockDataModalClient; +``` + +![20240529223046](https://static-docs.nocobase.com/20240529223046.png) + +#### 7.3 添加到移动端 Add block 中 + +> 首先要激活移动端插件,参考 [激活插件](/welcome/getting-started/plugin#3-activate-the-plugin) 文档。 + +我们可以将其添加到移动端的 `Add block` 中,获取 `name` 的方法这里就不再赘述了。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/client/index.tsx` 文件: + +```ts +// ... + +export class PluginInitializerBlockDataModalClient extends Plugin { + async load() { + // ... + this.app.schemaInitializerManager.addItem('mobilePage:addBlock', `dataBlocks.${timelineInitializerItem.name}`, timelineInitializerItem); + } +} + +export default PluginInitializerBlockDataModalClient; +``` + +![20240529223307](https://static-docs.nocobase.com/20240529223307.png) + +如果需要更多的 `Add block`,可以继续添加,只需要知道对应的 `name` 即可。 + +### 8. 多语言 + +#### 8.1 英文 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/locale/en-US.json` 文件: + +```diff +{ + "Timeline": "Timeline", + "Title Field": "Title Field", + "Time Field": "Time Field" +} +``` + +#### 8.2 中文 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-initializer-block-data-modal/src/locale/zh-CN.json` 文件: + +```diff +{ + "Timeline": "时间线", + "Title Field": "标题字段", + "Time Field": "时间字段" +} +``` + +我们可以通过 [http://localhost:13000/admin/settings/system-settings](http://localhost:13000/admin/settings/system-settings) 添加多个语言,并且在右上角切换语言。 + +![20240611113758](https://static-docs.nocobase.com/20240611113758.png) + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-initializer-block-data-modal --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-initializer-block-data-modal.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugin-samples/schema-initializer/block-data.md b/docs/fr-FR/plugin-samples/schema-initializer/block-data.md new file mode 100644 index 000000000..2ad7cf801 --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initializer/block-data.md @@ -0,0 +1,605 @@ +# Adding Data Blocks + +## Scenario Description + +NocoBase has many `Add block` buttons used to add blocks to the interface. Some of these blocks are related to data tables and are referred to as Data Blocks, while others that are not related to data tables are called Simple Blocks. + +![img_v3_02b4_170eddb5-d3b4-461e-b74b-f83250941e5g](https://static-docs.nocobase.com/img_v3_02b4_170eddb5-d3b4-461e-b74b-f83250941e5g.jpg) + +However, the existing block types may not fully meet our needs, so we may need to custom-develop some blocks according to our requirements. This article specifically explains how to create Data Blocks. + +## Example Explanation + +In this example, we will create an `Info` block and add it to the `Page`, `Table`, and the mobile `Add block` sections. + +This example mainly demonstrates the usage of the initializer. For more information on block extensions, refer to the [Block Extension](/plugin-samples/block) documentation. + +The complete sample code for this document can be found in the [plugin-samples repository](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-initializer-block-data). + + + +## Initializing the Plugin + +Following the instructions in the [Creating Your First Plugin](/development/your-fisrt-plugin) document, if you don't have a project yet, you can create one first. If you already have a project or have cloned the source code, skip this step. + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +Next, initialize a plugin and add it to the system: + +```bash +yarn pm create @nocobase-sample/plugin-initializer-block-data +yarn pm enable @nocobase-sample/plugin-initializer-block-data +``` + +Then, start the project: + +```bash +yarn dev +``` + +After logging in, visit [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) to see that the plugin has been installed and enabled. + +## Feature Implementation + +Before implementing this example, we need to understand some basic concepts: + +- [SchemaInitializer Tutorial](/development/client/ui-schema/initializer): Used to add various blocks, fields, operations, etc., to the interface. +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer): Provides an API for adding various blocks, fields, operations, etc., to the interface. +- [UI Schema](/development/client/ui-schema/what-is-ui-schema): Used for defining the structure and style of the interface. +- [Designable](/development/client/ui-schema/designable): A designer tool used for modifying schemas. + +```bash +. +├── client # Client-side plugin +│ ├── initializer # Initializer +│ ├── component # Block components +│ ├── index.tsx # Entry point for the client-side plugin +│ ├── locale.ts # Multi-language utility functions +│ ├── constants.ts # Constants +│ ├── schema # Schema +│ └── settings # Schema settings +├── locale # Multi-language files +│ ├── en-US.json # English +│ └── zh-CN.json # Chinese +├── index.ts # Server-side plugin entry point +└── server # Server-side plugin +``` + +### 1. Defining Names + +First, we need to define the block's name, which will be used in various places. + +Create `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client/constants.ts`: + +```ts +export const BlockName = 'Info'; +export const BlockNameLowercase = BlockName.toLowerCase(); +``` + +### 2. Implementing Block Components + +#### 2.1 Defining the Block Component + +In this example, we need to create an `Info` block component with the following requirements: + +- Display the name of the current block's data table. +- Display the current block's data list. + +First, create `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client/component/Info.tsx` with the following content: + +```tsx | pure +import React, { FC } from 'react'; +import { withDynamicSchemaProps } from '@nocobase/client' +import { BlockName } from '../constants'; + +export interface InfoProps { + collectionName: string; + data?: any[]; + loading?: boolean; +} + +export const Info: FC = withDynamicSchemaProps(({ collectionName, data }) => { + return
    +
    Collection: {collectionName}
    +
    Data list:
    {JSON.stringify(data, null, 2)}
    +
    +}, { displayName: BlockName }) +``` + +The `Info` component is essentially a functional component wrapped by `withDynamicSchemaProps`. The [withDynamicSchemaProps](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) is a higher-order component used to handle dynamic properties in schemas. + +Without considering `withDynamicSchemaProps`, the `Info` component is a simple functional component. + +Next, export it in `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client/component/index.ts`: + +```tsx | pure +export * from './Info'; +``` + +#### 2.2 Registering the Block Component + +We need to register the `Info` component in the system via the plugin. + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Info } from './component'; + +export class PluginInitializerBlockDataClient extends Plugin { + async load() { + this.app.addComponents({ Info }) + } +} + +export default PluginInitializerBlockDataClient; +``` + +#### 2.3 Verifying the Block Component + +There are two ways to verify the component: + +- Temporary page verification: You can create a temporary page, render the `Info` component, and check if it meets the requirements. +- Documentation example verification: You can start the documentation with `yarn doc plugins/@nocobase-sample/plugin-initializer-block-data` and verify the component through a documentation example (TODO). + +For this example, we'll use **Temporary Page Verification**. Create a page and add one or more `Info` components based on the parameters, then check if it meets the requirements. + +```tsx | pure +import React from 'react'; +import { Plugin } from '@nocobase/client'; +import { Info } from './component'; + +export class PluginInitializerBlockDataClient extends Plugin { + async load() { + this.app.addComponents({ Info }) + + this.app.router.add('admin.info-component', { + path: '/admin/info-component', + Component: () => { + return <> +
    + +
    + + } + }) + } +} + +export default PluginInitializerBlockDataClient; +``` + +Then, visit `http://localhost:13000/admin/info-component` to see the corresponding content on the test page. + +![20240526165834](https://static-docs.nocobase.com/20240526165834.png) + +After verification, delete the test page. + + + + + + + + + + + + + + + + + + +### 3. 定义区块 Schema + +#### 3.1 定义区块 Schema + +NocoBase 的动态页面都是通过 Schema 来渲染,所以我们需要定义一个 Schema,后续用于在界面中添加 `Info` 区块。在实现本小节之前,我们需要先了解一些基础知识: + +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 +- [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider):数据区块 + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client/schema/index.ts` 文件: + +```ts +import { useCollection, useDataBlockRequest } from "@nocobase/client"; + +import { InfoProps } from "../component"; +import { BlockName, BlockNameLowercase } from "../constants"; + +export function useInfoProps(): InfoProps { + const collection = useCollection(); + const { data, loading } = useDataBlockRequest(); + + return { + collectionName: collection.name, + data: data?.data, + loading: loading + } +} + +export function getInfoSchema({ dataSource = 'main', collection }) { + return { + type: 'void', + 'x-decorator': 'DataBlockProvider', + 'x-decorator-props': { + dataSource, + collection, + action: 'list', + }, + 'x-component': 'CardItem', + "x-toolbar": "BlockSchemaToolbar", + properties: { + [BlockNameLowercase]: { + type: 'void', + 'x-component': BlockName, + 'x-use-component-props': 'useInfoProps', + } + } + } +} +``` + +这里有 2 个点需要说明: + +- `getInfoSchema()`:之所以定义为函数,因为 `dataSource` 和 `collection` 是动态的,由点击的数据表决定 +- `useInfoProps()`:用于处理 `Info` 组件的动态属性,并且因为要存到数据库,所以这里的值类型为 string 类型。 + +`getInfoSchema()`:返回 Info 的 Schema + - `type: 'void'`:表示没有任何数据 + - `x-decorator: 'DataBlockProvider'`:数据区块提供者,用于提供数据,更多关于 DataBlockProvider 可以查看 [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider) + - `x-decorator-props`:`DataBlockProvider` 的属性 + - `dataSource`:数据源 + - `collection`:数据表 + - `action: 'list'`:操作类型,这里是 `list`,获取数据列表 + - `x-component: 'CardItem'`:[CardItem 组件](https://client.docs.nocobase.com/components/card-item),目前的区块都是被包裹在卡片中的,用于提供样式、布局和拖拽等功能 + - `properties`:子节点 + - `info`:信息区块 + +`useInfoProps()`:Info 组件的动态属性 + - [useCollection](https://client.docs.nocobase.com/core/data-source/collection-provider#usecollection):获取当前数据表,由 [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider) 提供 + - [useDataBlockRequest](https://client.docs.nocobase.com/core/data-block/data-block-request-provider#usedatablockrequest) 获取数据区块请求,由 [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider) 提供 + +上述 Schema 转为 React 组件后相当于: + +```tsx | pure + + + + + +``` + +#### 3.2 注册 scope + +我们需要将 `useInfoProps` 注册到系统中,这样 [x-use-component-props](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) 才能找到对应的 scope。 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Info } from './component'; +import { useInfoProps } from './schema'; + +export class PluginInitializerBlockDataClient extends Plugin { + async load() { + this.app.addComponents({ Info }) + this.app.addScopes({ useInfoProps }); + } +} + +export default PluginInitializerBlockDataClient; +``` + +更多关于 Scope 的说明可以查看 [全局注册 Component 和 Scope](/plugin-samples/component-and-scope/global) + +#### 3.3 验证区块 Schema + +同验证组件一样,我们可以通过临时页面验证或者文档示例验证的方式来验证 Schema 是否符合需求。我们这里以临时页面验证为例: + +```tsx | pure +import React from 'react'; +import { Plugin, SchemaComponent, SchemaComponentOptions } from '@nocobase/client'; +import { Info } from './component'; +import { getInfoSchema, useInfoProps } from './schema'; + +export class PluginInitializerBlockDataClient extends Plugin { + async load() { + // ... + this.app.router.add('admin.info-schema', { + path: '/admin/info-schema', + Component: () => { + return <> +
    + +
    + +
    + +
    + + } + }) + } +} + +export default PluginInitializerBlockDataClient; +``` + +- [SchemaComponentOptions](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponentoptions):用于传递 Schema 中所需的 `components` 和 `scope`,具体的可查看 [局部注册 Component 和 Scope](/plugin-samples/component-and-scope/local) +- [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1):用于渲染 Schema + +我们访问 [http://localhost:13000/admin/info-schema](http://localhost:13000/admin/info-schema) 就可以看到对应测试页面的内容了。 + +![20240526170053](https://static-docs.nocobase.com/20240526170053.png) + +验证完毕后需要删除测试页面。 + +### 4. 定义 Schema Initializer Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client/initializer/index.tsx` 文件: + +```tsx | pure +import React from 'react'; +import { SchemaInitializerItemType, useSchemaInitializer } from '@nocobase/client' +import { CodeOutlined } from '@ant-design/icons'; + +import { getInfoSchema } from '../schema' +import { useT } from '../locale'; +import { BlockName, BlockNameLowercase } from '../constants'; + +export const infoInitializerItem: SchemaInitializerItemType = { + name: BlockNameLowercase, + Component: 'DataBlockInitializer', + useComponentProps() { + const { insert } = useSchemaInitializer(); + const t = useT(); + return { + title: t(BlockName), + icon: , + componentType: BlockName, + useTranslationHooks: useT, + onCreateBlockSchema({ item }) { + insert(getInfoSchema({ dataSource: item.dataSource, collection: item.name })) + }, + }; + }, +} +``` + +实现数据区块的效果核心是 DataBlockInitializer(文档 TODO)。 + +`infoInitializerItem`: + - `Component`:与 [添加简单区块 Simple Block](/plugin-samples/schema-initializer/block-simple) 中使用的是 `type`,这里使用的是 `Component`,[2 种定义方式](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#two-ways-to-define-component-and-type) 都是可以的 + - `useComponentProps`:`DataBlockInitializer` 组件的属性 + - `title`:标题 + - `icon`:图标,更多图标可以查看 [Ant Design Icons](https://ant.design/components/icon/) + - `componentType`:组件类型,这里是 `Info` + - `onCreateBlockSchema`:当点击数据表后的回调 + - `item`:点击的数据表信息 + - `item.name`:数据表名称 + - `item.dataSource`:数据表所属的数据源 + - [useSchemaInitializer](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#useschemainitializer):提供了插入 Schema 的方法 + - `"x-toolbar": "BlockSchemaToolbar"`:`BlockSchemaToolbar` 用于左上角显示当前数据表,一般和 `DataBlockProvider` 搭配使用 + +更多关于 Schema Initializer 的定义可以参考 [Schema Initializer](https://client.docs.nocobase.com/core/ui-schema/schema-initializer) 文档。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +### 5. 实现 Schema Settings + +#### 5.1 定义 Schema Settings + +一个完整的 Block 还需要有 Schema Settings,用于配置一些属性和操作,但 Schema Settings 不是本示例的重点,所以我们这里仅有一个 `remove` 操作。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client/settings/index.ts` 文件: + +```ts +import { SchemaSettings } from "@nocobase/client"; +import { BlockNameLowercase } from "../constants"; + +export const infoSettings = new SchemaSettings({ + name: `blockSettings:${BlockNameLowercase}`, + items: [ + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}) +``` + +#### 5.2 注册 Schema Settings + +```ts +import { Plugin } from '@nocobase/client'; +import { infoSettings } from './settings'; + +export class PluginInitializerBlockDataClient extends Plugin { + async load() { + // ... + this.app.schemaSettingsManager.add(infoSettings) + } +} + +export default PluginInitializerBlockDataClient; +``` + +#### 5.3 使用 Schema Settings + +我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client/schema/index.ts` 文件的 `getInfoSchema` 方法,将 `x-settings` 设置为 `infoSettings.name`。 + +```diff ++ import { infoSettings } from "../settings"; + +export function getInfoSchema({ dataSource = 'main', collection }) { + return { + type: 'void', + 'x-decorator': 'DataBlockProvider', ++ 'x-settings': infoSettings.name, + // ... + } +} +``` + +### 6. 添加到 Add block 中 + +系统中有很多个 `Add block` 按钮,但他们的 **name 是不同的**。 + +![img_v3_02b4_049b0a62-8e3b-420f-adaf-a6350d84840g](https://static-docs.nocobase.com/img_v3_02b4_049b0a62-8e3b-420f-adaf-a6350d84840g.jpg) + +#### 6.1 添加到页面级别 Add block 中 + +如果我们需要添加到页面级别的 `Add block` 中,我们需要知道对应的 `name`,我们可以通过 TODO 方式查看对应的 `name`。 + +TODO + +通过上图可以看到页面级别的 `Add block` 对应的 name 为 `page:addBlock`,`Data Blocks` 对应的 name 为 `dataBlocks`。 + +然后我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client/index.tsx` 文件: + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Info } from './component'; +import { useInfoProps } from './schema'; +import { infoSettings } from './settings'; +import { infoInitializerItem } from './initializer'; + +export class PluginDataBlockInitializerClient extends Plugin { + async load() { + this.app.addComponents({ Info }); + this.app.addScopes({ useInfoProps }); + + this.app.schemaSettingsManager.add(infoSettings); + + this.app.schemaInitializerManager.addItem('page:addBlock', `dataBlocks.${infoInitializerItem.name}`, infoInitializerItem) + } +} + +export default PluginDataBlockInitializerClient; +``` + + + +#### 6.2 添加到弹窗 Add block 中 + +我们不仅需要将其添加到页面级别的 `Add block` 中,还需要将其添加到 `Table` 区块 `Add new` 弹窗的 `Add block` 中。 + +![img_v3_02b4_fc47fe3a-35a1-4186-999c-0b48e6e001dg](https://static-docs.nocobase.com/img_v3_02b4_fc47fe3a-35a1-4186-999c-0b48e6e001dg.jpg) + +我们按照页面级别获取 `name` 的方式获取到 `Table` 区块的 `Add block` 的 `name` 为 `popup:addNew:addBlock`,`Data Blocks` 对应的 name 为 `dataBlocks`。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client/index.tsx` 文件: + +```diff +import { Plugin } from '@nocobase/client'; +import { Plugin } from '@nocobase/client'; +import { Info } from './component'; +import { useInfoProps } from './schema'; +import { infoSettings } from './settings'; +import { infoInitializerItem } from './initializer'; + +export class PluginDataBlockInitializerClient extends Plugin { + async load() { + this.app.addComponents({ Info }); + this.app.addScopes({ useInfoProps }); + + this.app.schemaSettingsManager.add(infoSettings); + + this.app.schemaInitializerManager.addItem('page:addBlock', `dataBlocks.${infoInitializerItem.name}`, infoInitializerItem) ++ this.app.schemaInitializerManager.addItem('popup:addNew:addBlock', `dataBlocks.${infoInitializerItem.name}`, infoInitializerItem) + } +} + +export default PluginDataBlockInitializerClient; + +``` + +![img_v3_02b4_7062bfab-5a7b-439c-b385-92c5704b6b3g](https://static-docs.nocobase.com/img_v3_02b4_7062bfab-5a7b-439c-b385-92c5704b6b3g.jpg) + +#### 6.3 添加到移动端 Add block 中 + +> 首先要激活移动端插件,参考 [激活插件](/welcome/getting-started/plugin#3-activate-the-plugin) 文档。 + +我们可以将其添加到移动端的 `Add block` 中,获取 `name` 的方法这里就不再赘述了。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client/index.tsx` 文件: + +```diff +import { Plugin } from '@nocobase/client'; +import { Info } from './component'; +import { useInfoProps } from './schema'; +import { infoSettings } from './settings'; +import { infoInitializerItem } from './initializer'; + +export class PluginDataBlockInitializerClient extends Plugin { + async load() { + this.app.addComponents({ Info }); + this.app.addScopes({ useInfoProps }); + + this.app.schemaSettingsManager.add(infoSettings); + + this.app.schemaInitializerManager.addItem('page:addBlock', `dataBlocks.${infoInitializerItem.name}`, infoInitializerItem) + this.app.schemaInitializerManager.addItem('popup:addNew:addBlock', `dataBlocks.${infoInitializerItem.name}`, infoInitializerItem) ++ this.app.schemaInitializerManager.addItem('mobilePage:addBlock', `dataBlocks.${infoInitializerItem.name}`, infoInitializerItem) + } +} + +export default PluginDataBlockInitializerClient; +``` + +如果需要更多的 `Add block`,可以继续添加,只需要知道对应的 `name` 即可。 + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-initializer-block-data --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-initializer-block-data.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugin-samples/schema-initializer/block-simple.md b/docs/fr-FR/plugin-samples/schema-initializer/block-simple.md new file mode 100644 index 000000000..3383a94c4 --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initializer/block-simple.md @@ -0,0 +1,467 @@ +# 添加新的简单区块 Simple Block + +## 场景说明 + +NocoBase 有很多 `Add block` 按钮用于向界面添加区块。其中有些和数据表有关系的被成为数据区块 `Data Block`,有些和数据表无关的被称为简单区块 `Simple Block`。 + +![img_v3_02b4_a4529308-62e3-4fa7-be4d-5dcae332c49g](https://static-docs.nocobase.com/img_v3_02b4_a4529308-62e3-4fa7-be4d-5dcae332c49g.jpg) + +但是目前已有的区块类型不一定满足我们的需求,我们就需要根据需求自定开发一些区块,本篇文章就是针对简单区块 `Simple Block` 进行说明。 + +## 示例说明 + +本实例会创建一个图片区块类型,并将其添加到 `Page`、`Table` 以及移动端的 `Add block` 中。 + +本实例主要为了演示 initializer 的使用,更多关于区块扩展可以查看 [区块扩展](/plugin-samples/block) 文档。 + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-initializer-block-simple) 中查看。 + + + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-initializer-block-simple +yarn pm enable @nocobase-sample/plugin-initializer-block-simple +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +在实现本示例之前,我们需要先了解一些基础知识: + +- [SchemaInitializer 教程](/development/client/ui-schema/initializer):用于向界面内添加各种区块、字段、操作等 +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于向界面内添加各种区块、字段、操作等 +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 +- [Designable 设计器](/development/client/ui-schema/designable):用于修改 Schema + +```bash +. +├── client # 客户端插件 +│ ├── initializer # 初始化器 +│ ├── component # 区块组件 +│ ├── index.tsx # 客户端插件入口 +│ ├── locale.ts # 多语言工具函数 +│ ├── constants.ts # 常量 +│ ├── schema # Schema +│ └── settings # Schema Settings +├── locale # 多语言文件 +│ ├── en-US.json # 英语 +│ └── zh-CN.json # 中文 +├── index.ts # 服务端插件入口 +└── server # 服务端插件 +``` + +### 1. 定义名称 + +我们首先需要定义区块名称,它将会使用在各个地方。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client/constants.ts`: + +```ts +export const BlockName = 'Image'; +export const BlockNameLowercase = BlockName.toLowerCase(); +``` + +### 2. 实现区块组件 + +#### 2.1 定义区块组件 + +本示例要做的是一个图片区块组件,我们取名为 `Image`。 + +所以我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client/component/Image.tsx` 文件,其内容如下: + +```tsx | pure +import React, { FC } from 'react'; +import { withDynamicSchemaProps } from '@nocobase/client'; +import { BlockName } from '../constants'; + +export const Image: FC<{ height?: number }> = withDynamicSchemaProps(({ height = 500 }) => { + return
    + +
    +}, { displayName: BlockName }) +``` + +`Image` 组件整体来说是一个被 `withDynamicSchemaProps` 包裹的函数组件,[withDynamicSchemaProps](/development/client/ui-schema/what-is-ui-schema#x-component-props-和-x-use-component-props) 是一个高阶组件,用于处理 Schema 中的的动态属性。 + +如果不看 `withDynamicSchemaProps` 的话,`Image` 组件就是一个简单的函数组件。 + +然后将其在 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client/component/index.ts` 中导出: + +```tsx | pure +export * from './Image'; +``` + +#### 2.2 注册区块组件 + +我们需要将 `Image` 通过插件注册到系统中。 + +```tsx | pure +import { Plugin } from '@nocobase/client'; +import { Image } from './component' + +export class PluginInitializerBlockSimpleClient extends Plugin { + async load() { + this.app.addComponents({ Image }) + } +} + +export default PluginInitializerBlockSimpleClient; +``` + +#### 2.3 验证区块组件 + +组件验证方式有 2 种: + +- 临时页面验证:我们可以临时建一个页面,然后渲染 `Image` 组件,查看是否符合需求 +- 文档示例验证:可以启动文档 `yarn doc plugins/@nocobase-sample/plugin-initializer-block-simple`,通过写文档示例的方式验证是否符合需求(TODO) + +我们以 `临时页面验证` 为例,我们新建一个页面,根据属性参数添加一个或者多个 `Image` 组件,查看是否符合需求。 + +```tsx | pure +import React from 'react'; +import { Plugin } from '@nocobase/client'; +import { Image } from './component' + +export class PluginInitializerBlockSimpleClient extends Plugin { + async load() { + this.app.addComponents({ Image }) + + this.app.router.add('admin.image-component', { + path: '/admin/image-component', + Component: () => { + return <> +
    + +
    + +
    + +
    + + } + }) + } +} + +export default PluginInitializerBlockSimpleClient; +``` + +然后访问 `http://localhost:13000/admin/image-component` 就可以看到对应测试页面的内容了。 + +![20240526165057](https://static-docs.nocobase.com/20240526165057.png) + +验证完毕后需要删除测试页面。 + +### 3. 定义区块 Schema + +#### 3.1 定义区块 Schema + +NocoBase 的动态页面都是通过 Schema 来渲染,所以我们需要定义一个 Schema,后续用于在界面中添加 `Image` 区块。在实现本小节之前,我们需要先了解一些基础知识: + +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client/schema/index.ts` 文件: + +```tsx | pure +import { ISchema } from "@nocobase/client"; +import { BlockName, BlockNameLowercase } from "../constants"; + +export const imageSchema: ISchema = { + type: 'void', + 'x-component': 'CardItem', + properties: { + [BlockNameLowercase]: { + 'x-component': BlockName, + } + } +}; +``` + +关于 `imageSchema` 的详细说明: + +- `type`:类型,这里是 `void`,表示纯 UI 节点,没有数据 +- `x-decorator`:装饰器,这里是 [CardItem 组件](https://client.docs.nocobase.com/components/card-item),目前的区块都是被包裹在卡片中的,用于提供样式、布局和拖拽等功能 +- `x-component`:组件,这里是 `Image`,就是我们刚定义的组件 + +上述 Schema 转为 React 组件后相当于: + +```tsx | pure + + + +``` + +#### 3.2 验证区块 Schema + +同验证组件一样,我们可以通过临时页面验证或者文档示例验证的方式来验证 Schema 是否符合需求。我们这里以临时页面验证为例: + +```tsx | pure +import React from 'react'; +import { Plugin, SchemaComponent } from '@nocobase/client'; +import { Image } from './component' +import { imageSchema } from './schema' + +export class PluginInitializerBlockSimpleClient extends Plugin { + async load() { + this.app.addComponents({ Image }) + + this.app.router.add('admin.image-schema', { + path: '/admin/image-schema', + Component: () => { + return
    + +
    + } + }) + } +} + +export default PluginInitializerBlockSimpleClient; +``` + +关于 `SchemaComponent` 的详细说明可以查看 [SchemaComponent](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponent-1) 文档。 + +我们访问 [http://localhost:13000/admin/image-schema](http://localhost:13000/admin/image-schema) 就可以看到对应测试页面的内容了。 + +![20240526165408](https://static-docs.nocobase.com/20240526165408.png) + +验证完毕后需要删除测试页面。 + +### 4. 定义 Schema Initializer Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client/initializer/index.ts` 文件: + +```ts +import { SchemaInitializerItemType, useSchemaInitializer } from '@nocobase/client'; + +import { useT } from '../locale'; +import { imageSchema } from '../schema'; +import { BlockName, BlockNameLowercase } from '../constants'; + +export const imageInitializerItem: SchemaInitializerItemType = { + type: 'item', + name: BlockNameLowercase, + icon: 'FileImageOutlined', + useComponentProps() { + const { insert } = useSchemaInitializer(); + const t = useT() + return { + title: t(BlockName), + onClick: () => { + insert(imageSchema); + }, + }; + }, +} +``` + +- `type`:类型,这里是 `item`,表示是一个文本,其有点击事件,点击后可以插入一个新的 Schema +- `name`:唯一标识符,用于区分不同的 Schema Item 和增删改查操作 +- `icon`:图标,更多 icon 可以参考 [Ant Design Icons](https://ant.design/components/icon) +- `useComponentProps`:返回一个对象,包含 `title` 和 `onClick` 两个属性,`title` 是显示的文本,`onClick` 是点击后的回调函数 +- [useSchemaInitializer()](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#useschemainitializer):用于获取 `SchemaInitializerContext` 上下文 + - `insert`:插入一个新的 Schema + +更多关于 Schema Item 的定义可以参考 [Schema Initializer Item](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#built-in-components-and-types) 文档。 + +### 5. 实现 Schema Settings + +#### 5.1 定义 Schema Settings + +一个完整的 Block 还需要有 Schema Settings,用于配置一些属性和操作,但 Schema Settings 不是本示例的重点,所以我们这里仅有一个 `remove` 操作。 + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client/settings/index.ts` 文件: + +```ts | pure +import { SchemaSettings } from "@nocobase/client"; +import { BlockNameLowercase } from "../constants"; + +export const imageSettings = new SchemaSettings({ + name: `blockSettings:${BlockNameLowercase}`, + items: [ + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + +- componentProps + - `removeParentsIfNoChildren`:如果没有子节点,是否删除父节点 + - `breakRemoveOn`:删除时的中断条件。因为 `Add Block` 会自动将子项的包裹在 `Grid` 中,所以这里设置 `breakRemoveOn: { 'x-component': 'Grid' }`,当删除 `Grid` 时,不再向上删除。 + +#### 5.2 注册 Schema Settings + +```ts +import { Plugin } from '@nocobase/client'; +import { imageSettings } from './settings'; + +export class PluginInitializerBlockSimpleClient extends Plugin { + async load() { + // ... + this.app.schemaSettingsManager.add(imageSettings) + } +} + +export default PluginInitializerBlockSimpleClient; +``` + +#### 5.3 使用 Schema Settings + +我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client/schema/index.ts` 中的 `imageSchema`: + +```diff ++ import { imageSettings } from "../settings"; + +const imageSchema: ISchema = { + type: 'void', + 'x-decorator': 'CardItem', ++ 'x-settings': imageSettings.name, + // ... +}; +``` + +### 6. 添加到 Add block 中 + +系统中有很多个 `Add block` 按钮,但他们的 **name 是不同的**。 + +![img_v3_02b4_049b0a62-8e3b-420f-adaf-a6350d84840g](https://static-docs.nocobase.com/img_v3_02b4_049b0a62-8e3b-420f-adaf-a6350d84840g.jpg) + +#### 6.1 添加到页面级别 Add block 中 + +如果我们需要添加到页面级别的 `Add block` 中,我们需要知道对应的 `name`,我们可以通过 TODO 方式查看对应的 `name`。 + +TODO + +通过上图可以看到页面级别的 `Add block` 对应的 name 为 `page:addBlock`,`Other Blocks` 对应的 name 为 `otherBlocks`。 + +然后我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client/index.tsx` 文件: + +```tsx | pure +import { Plugin } from '@nocobase/client'; + +import { Image } from './component' +import { imageSettings } from './settings'; +import { imageInitializerItem } from './initializer'; + +export class PluginInitializerBlockSimpleClient extends Plugin { + async load() { + this.app.addComponents({ Image }) + this.app.schemaSettingsManager.add(imageSettings) + this.app.schemaInitializerManager.addItem('page:addBlock', `otherBlocks.${imageInitializerItem.name}`, imageInitializerItem) + } +} + +export default PluginInitializerBlockSimpleClient; +``` + +上述代码首先将 `Image` 组件注册到系统中,这样前面 `imageSchema` 定义的 `x-component: 'Image'` 才能找到对应的组件,更多详细解释可以查看 [全局注册 Component 和 Scope](/plugin-samples/component-and-scope/global)。 + +然后将 `imageSettings` 通过 [app.schemaSettingsManager.add](https://client.docs.nocobase.com/core/ui-schema/schema-settings-manager#schemasettingsmanageradd) 添加到系统中。 + +然后使用 [app.schemaInitializerManager.addItem](https://client.docs.nocobase.com/core/ui-schema/schema-initializer-manager#schemainitializermanageradditem) 将 `imageInitializerItem` 添加对应 Initializer 子项中,其中 `page:addBlock` 是页面上 `Add block` 的 name,`otherBlocks` 是其父级的 name。 + +然后我们 hover `Add block` 按钮,就可以看到 `Image` 这个新的区块类型了,点击 `Image`,就可以添加一个新的 `Image` 区块了。 + + + +#### 6.2 添加到弹窗 Add block 中 + +我们不仅需要将其添加到页面级别的 `Add block` 中,还需要将其添加到 `Table` 区块 `Add new` 弹窗的 `Add block` 中。 + +![img_v3_02b4_fc47fe3a-35a1-4186-999c-0b48e6e001dg](https://static-docs.nocobase.com/img_v3_02b4_fc47fe3a-35a1-4186-999c-0b48e6e001dg.jpg) + +我们按照页面级别获取 `name` 的方式获取到 `Table` 区块的 `Add block` 的 `name` 为 `popup:addNew:addBlock`,`Other Blocks` 对应的 name 为 `otherBlocks`。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client/index.tsx` 文件: + +```diff +export class PluginInitializerBlockSimpleClient extends Plugin { + async load() { + this.app.addComponents({ Image }) + this.app.schemaSettingsManager.add(imageSettings) + + this.app.schemaInitializerManager.addItem('page:addBlock', `otherBlocks.${imageInitializerItem.name}`, imageInitializerItem) ++ this.app.schemaInitializerManager.addItem('popup:addNew:addBlock', `otherBlocks.${imageInitializerItem.name}`, imageInitializerItem) + } +} +``` + +![img_v3_02b4_7062bfab-5a7b-439c-b385-92c5704b6b3g](https://static-docs.nocobase.com/img_v3_02b4_7062bfab-5a7b-439c-b385-92c5704b6b3g.jpg) + +#### 6.3 添加到移动端 Add block 中 + +> 首先要激活移动端插件,参考 [激活插件](/welcome/getting-started/plugin#3-activate-the-plugin) 文档。 + +我们可以将其添加到移动端的 `Add block` 中,获取 `name` 的方法这里就不再赘述了。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client/index.tsx` 文件: + +```diff +export class PluginInitializerBlockSimpleClient extends Plugin { + async load() { + this.app.addComponents({ Image }) + this.app.schemaSettingsManager.add(imageSettings) + + this.app.schemaInitializerManager.addItem('page:addBlock', `otherBlocks.${imageInitializerItem.name}`, imageInitializerItem) + this.app.schemaInitializerManager.addItem('popup:addNew:addBlock', `otherBlocks.${imageInitializerItem.name}`, imageInitializerItem) ++ this.app.schemaInitializerManager.addItem('mobilePage:addBlock', `otherBlocks.${imageInitializerItem.name}`, imageInitializerItem) + } +} +``` + +![img_v3_02b4_ec873b25-5a09-4f3a-883f-1d722035799g](https://static-docs.nocobase.com/img_v3_02b4_ec873b25-5a09-4f3a-883f-1d722035799g.jpg) + +如果需要更多的 `Add block`,可以继续添加,只需要知道对应的 `name` 即可。 + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-initializer-block-simple --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-initializer-block-simple.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugin-samples/schema-initializer/configure-actions.md b/docs/fr-FR/plugin-samples/schema-initializer/configure-actions.md new file mode 100644 index 000000000..fbb806daa --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initializer/configure-actions.md @@ -0,0 +1,490 @@ +# 区块内嵌的 Initializer - 配置操作 + +## 场景说明 + +如果新创建的区块是一个复杂的数据区块,那么它内部可能包含多个动态添加的部分,其中 `Configure actions` 对应的 initializer 主要是负责动态添加一些按钮实现各种操作。例如 `Details` 区块,我们可以通过 `Configure actions` 添加 `Edit`、`Print` 等按钮。 + +![img_v3_02b4_9b80a4a0-6d9b-4e53-a544-f92c17d81d2g](https://static-docs.nocobase.com/img_v3_02b4_9b80a4a0-6d9b-4e53-a544-f92c17d81d2g.jpg) + +## 示例说明 + +本实例会在 [添加数据区块 Data Block](/plugin-samples/schema-initializer/data-block) 基础上继续实现类似 `Details` 区块的效果,通过 `Configure actions` 来配置按钮。 + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-initializer-configure-actions) 中查看。 + + + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-initializer-configure-actions +yarn pm enable @nocobase-sample/plugin-initializer-configure-actions +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +在实现本示例之前,我们需要先了解一些基础知识: + +- [SchemaInitializer 教程](/development/client/ui-schema/initializer):用于向界面内添加各种区块、字段、操作等 +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于向界面内添加各种区块、字段、操作等 +- [UI Schema](/development/client/ui-schema/what-is-ui-schema):用于定义界面的结构和样式 +- [Designable 设计器](/development/client/ui-schema/designable):用于修改 Schema + +### 1. 创建区块 + +前面已经说明本示例会在 [添加数据区块 Data Block](/plugin-samples/schema-initializer/data-block) 基础上继续实现,所以我们可以复制 `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client` 目录覆盖 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client`。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/index.tsx`: + +```diff +import { Plugin } from '@nocobase/client'; +- import { Info } from './component'; ++ import { InfoV2 } from './component'; + +- export class PluginInitializerBlockDataClient extends Plugin { ++ export class PluginInitializerConfigureActionsClient extends Plugin { + async load() { +- this.app.addComponents({ Info }) ++ this.app.addComponents({ InfoV2 }) + // ... + } +} + +- export default PluginInitializerBlockDataClient; ++ export default PluginInitializerConfigureActionsClient; +``` + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/constants.ts`: + +```ts +export const BlockName = 'InfoV2'; +export const BlockNameLowercase = 'info-v2'; +``` + +### 2. 实现 initializer + +#### 2.1 定义 initializer + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/configureActionsInitializer.ts` 文件: + +```tsx | pure +import { SchemaInitializer } from "@nocobase/client"; +import { BlockNameLowercase } from "../../constants"; + +export const configureActionsInitializer = new SchemaInitializer({ + name: `${BlockNameLowercase}:configureActions`, + icon: 'SettingOutlined', + title: 'Configure actions', + style: { + marginLeft: 8, + }, + items: [ + + ] +}); +``` + +我们通过上述代码定义了一个新的 `SchemaInitializer`,其子项暂时为空。 + +- [SchemaInitializer](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于创建一个 Schema Initializer 实例 +- `icon`:图标,更多图标可参考 Ant Design [Icons](https://ant.design/components/icon/) +- `title`:按钮标题 +- [items](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#built-in-components-and-types):按钮下的子项 + +然后将其在 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/index.ts` 中导出: + +```tsx | pure +export * from './configureActionsInitializer'; +``` + +并且修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/index.tsx` 将 `configureActions` 导出: + +```diff +import React from 'react'; +import { SchemaInitializerItemType, useSchemaInitializer } from '@nocobase/client' +import { CodeOutlined } from '@ant-design/icons'; + ++ export * from './configureActions' +// ... +``` + +#### 2.2 注册 initializer + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/index.tsx` 文件,导入并注册这个 initializer: + +```tsx | pure +// ... +import { infoInitializerItem, configureActionsInitializer } from './initializer'; + +export class PluginInitializerConfigureActionsClient extends Plugin { + async load() { + this.app.schemaInitializerManager.add(configureActionsInitializer) + + // ... + } +} +``` + +#### 2.3 使用 initializer + +我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/schema/index.ts` 文件,新增 `actions` 子节点: + +```diff +// ... ++ import { configureActionsInitializer } from "../initializer"; + +function getInfoBlockSchema({ dataSource, collection }) { + return { + // ... + properties: { + info: { + 'x-component': BlockName, + 'x-use-component-props': 'useInfoProps', ++ properties: { ++ actions: { ++ type: 'void', ++ 'x-component': 'ActionBar', ++ 'x-component-props': { ++ layout: 'two-column', ++ style: { marginBottom: 20 } ++ }, ++ 'x-initializer': configureActionsInitializer.name, ++ } ++ } + } + } + } +} +``` + +`configure actions` 一般与 [ActionBar](https://client.docs.nocobase.com/components/action#actionbar) 组件搭配使用。 + + +我们在 `Info` 的子节点中添加了一个 `actions` 字段: + +- `type: 'void'`:类型为 `void`,表示这是一个容器 +- `x-component: 'ActionBar'`:使用 [ActionBar](https://client.docs.nocobase.com/components/action#actionbar) 组件,用于展示按钮 +- `x-initializer: configureActionsInitializer.name`:使用我们刚创建的 Schema Initializer +- `x-component-props.layout: 'two-column'`:左右布局,具体示例可参考 [ActionBar two-column](https://client.docs.nocobase.com/components/action#two-column) + +#### 2.4 区块渲染子节点 + +我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/component/Info.tsx` 文件,将 `Info` 组件修改为: + +```diff +import React, { FC } from 'react'; +import { withDynamicSchemaProps } from '@nocobase/client' + +export interface InfoV2Props { + collectionName: string; + data?: any[]; + loading?: boolean; ++ children?: React.ReactNode; +} + +export const InfoV2: FC = withDynamicSchemaProps(({ children, collectionName, data }) => { + return
    ++ {children} +-
    collection: {collectionName}
    +-
    data list:
    {JSON.stringify(data, null, 2)}
    ++
    data length: {data?.length}
    +
    +}, { displayName: BlockName }) +``` + +- `children`: `properties` 的内容会被传入到 `InfoV2` 组件的 `children` 中,所以我们直接将 `children` 渲染出来即可。 + +![img_v3_02b4_4c6cb675-789e-48d5-99ce-072984dcfc9g](https://static-docs.nocobase.com/img_v3_02b4_4c6cb675-789e-48d5-99ce-072984dcfc9g.jpg) + +### 3. 实现 initializer items + +#### 3.1 复用:`Custom request` Action + +我们继续修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/configureActionsInitializer.ts` 文件: + +```diff +export const configureActions = new SchemaInitializer({ + name: 'info:configureActions', + title: 'Configure actions', + icon: 'SettingOutlined', + items: [ ++ { ++ name: 'customRequest', ++ title: '{{t("Custom request")}}', ++ Component: 'CustomRequestInitializer', ++ }, + ] +}); +``` + +因为 `Custom request` 我们这里直接复用了 `CustomRequestInitializer` 组件,更多可复用的 Initializer Item 可参考 *TODO*。 + +![img_v3_02b4_0d439087-cfe1-4681-bfab-4e4bc3e34cbg](https://static-docs.nocobase.com/img_v3_02b4_0d439087-cfe1-4681-bfab-4e4bc3e34cbg.jpg) + +#### 3.2 自定义:`Custom Refresh` Action + +除了复用已有的 Initializer Item,我们也可以自定义 Action。关于自定义 Action 的详细步骤可以参考 [添加简单 Action](/plugin-samples/schema-initializer/action-simple) 和 [添加弹窗 Action](/plugin-samples/schema-initializer/action-modal)。 + +这里我们实现一个 `Custom Refresh` Action。 + +#### 3.2.1 定义名称 + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/items/customRefresh/constants.ts`: + +```ts +export const ActionName = 'Custom Request'; +export const ActionNameLowercase = 'customRequest'; +``` + +#### 3.2.2 定义 Schema + +##### 3.2.2.1 定义 Schema + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/items/customRefresh/schema.ts` 文件: + +```ts +import { ActionProps, useDataBlockRequest, ISchema } from "@nocobase/client"; +import { useT } from "../../../../locale"; + +export const useCustomRefreshActionProps = (): ActionProps => { + const { runAsync } = useDataBlockRequest(); + const t = useT(); + return { + type: 'primary', + title: t('Custom Refresh'), + async onClick() { + await runAsync(); + }, + } +} + +export const customRefreshActionSchema: ISchema = { + type: 'void', + 'x-component': 'Action', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-use-component-props': 'useCustomRefreshActionProps' +} +``` + +我们定义了 `customRefreshActionSchema` 以及动态属性 `useCustomRefreshActionProps`。 + +`customRefreshActionSchema`: + - `type: 'void'`:类型为 `void`,表示普通 UI,不包含数据 + - `x-component: 'Action'`:使用 [Action](https://client.docs.nocobase.com/components/action) 组件,用于展示按钮 + - `title: 'Custom Refresh'`:按钮标题 + - `x-use-component-props: 'useCustomRefreshActionProps'`:使用 `useCustomRefreshActionProps` 这个 Hooks 返回的属性。因为 Schema 会保存到服务器,所以这里需要使用字符串的方式。 + - `'x-toolbar': 'ActionSchemaToolbar'`:一般于 `Action` 组件搭配使用,与默认的 ToolBar 不同的是,其将 Action 右上角的 `Initializer` 隐藏,仅保留 Drag 和 Settings。 + +`useCustomRefreshActionProps`:这个是 React Hooks,需要返回 Action 组件的属性。 + - [useDataBlockRequest()](https://client.docs.nocobase.com/core/data-block/data-block-request-provider):数据区块的请求对象,由 `DataBlockProvider` 内部提供,用于自动获取数据区块的数据 + - `runAsync`:一个异步请求方法,用于刷新数据区块的数据 + - `type: 'primary'`:按钮类型为 `primary` + - `onClick`:点击事件。 + +然后将其在 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/items/customRefresh/index.ts` 中导出: + +```ts +export * from './initializer'; +``` + +并修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/index.ts` 将 `customRefresh` 导出: + +```diff +export * from './configureActionsInitializer'; ++ export * from './items/customRefresh'; +``` + +##### 3.2.2.2 注册上下文 + +我们还需要将 `useCustomRefreshActionProps` 注册到上下文中。我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/index.tsx` 文件: + +```diff +// ... +- import { infoInitializerItem } from './initializer'; ++ import { infoInitializerItem, useCustomRefreshActionProps } from './initializer'; + +export class PluginInitializerConfigureActionsClient extends Plugin { + async load() { + // ... +- this.app.addScopes({ useInfoProps }); ++ this.app.addScopes({ useInfoProps, useCustomRefreshActionProps }); + } +} +``` + +关于 `SchemaComponentOptions` 的使用可以参考 [SchemaComponentOptions](https://client.docs.nocobase.com/core/ui-schema/schema-component#schemacomponentoptions) 文档以及 [全局注册 Component 和 Scope](/plugin-samples/component-and-scope/global)。 + +#### 3.3.2 实现 settings + +##### 3.3.2.1 定义 settings + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/items/customRefresh/settings.ts` + +```tsx | pure +import { SchemaSettings } from "@nocobase/client"; +import { ActionNameLowercase } from "./constants"; + +export const customRefreshActionSettings = new SchemaSettings({ + name: `actionSettings:${ActionNameLowercase}`, + items: [ + { + name: 'remove', + type: 'remove', + } + ] +}) +``` + +`customRefreshActionSettings`:这里只简单定义了一个 `remove` 操作,更多关于 Schema Settings 的定义可以参考 [Schema Settings](https://client.docs.nocobase.com/core/ui-schema/schema-settings) 文档。 + + +修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/items/customRefresh/index.ts` 将其导出: + +```tsx | pure +export * from './settings'; +``` + +##### 3.3.2.2 注册 settings + +然后将 `customRefreshActionSettings` 注册到系统中。我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/index.tsx` 文件: + +```diff +- import { infoInitializerItem, useCustomRefreshActionProps } from './initializer'; ++ import { infoInitializerItem, useCustomRefreshActionProps, customRefreshActionSettings } from './initializer'; + +export class PluginInitializerConfigureActionsClient extends Plugin { + async load() { ++ this.app.schemaSettingsManager.add(customRefreshActionSettings); + } +} +``` + +##### 3.3.2.2 使用 settings + +我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/items/customRefresh/schema.ts` 文件的 `customRefreshActionSchema` 方法,将 `x-settings` 设置为 `customRefreshActionSettings.name`。 + +```diff ++ import { customRefreshActionSettings } from "./settings"; + +export const customRefreshActionSchema: ISchema = { + type: 'void', + 'x-component': 'Action', ++ "x-settings": customRefreshActionSettings.name, + title: 'Custom Refresh', + 'x-use-component-props': 'useCustomRefreshActionProps' +} +``` + +##### 3.3.3 定义 SchemaInitializer item + +###### 3.3.3.1 定义 SchemaInitializer item + +我们继续修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/items/customRefresh/initializer.ts` 文件: + +```tsx | pure +import { SchemaInitializerItemType, useSchemaInitializer } from "@nocobase/client"; +import { customRefreshActionSchema } from "./schema"; +import { ActionName } from "./constants"; +import { useT } from "../../../../locale"; + +export const customRefreshActionInitializerItem: SchemaInitializerItemType = { + type: 'item', + name: ActionName, + useComponentProps() { + const { insert } = useSchemaInitializer(); + const t = useT(); + return { + title: t(ActionName), + onClick() { + insert(customRefreshActionSchema) + }, + }; + }, +}; +``` + +- `type: 'item'`:类型为 `item`,表示文本,当点击后会触发 `onClick` 事件 +- `name: 'custom refresh'`:唯一标识符,用于区分不同的 Schema Item 和增删改查操作 +- `title: 'Custom Refresh'`:按钮标题 + +更多关于 Schema Item 的定义可以参考 [Schema Initializer Item](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#built-in-components-and-types) 文档。 + + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/index.ts` 将其导出: + +```tsx | pure +export * from './initializer'; +``` + +###### 3.3.3.2 使用 SchemaInitializer item + +我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-actions/src/client/initializer/configureActions/configureActionsInitializer.ts` 文件,将 `customRefreshActionInitializerItem` 添加到 `items` 中: + +```diff +import { SchemaInitializer } from "@nocobase/client"; ++ import { customRefreshActionInitializerItem } from "./items/customRefresh"; + +export const configureActionsInitializer = new SchemaInitializer({ + name: 'info:configureActions', + title: 'Configure actions', + icon: 'SettingOutlined', + style: { + marginLeft: 8, + }, + items: [ + { + name: 'customRequest', + title: '{{t("Custom request")}}', + Component: 'CustomRequestInitializer', + 'x-align': 'right', + }, ++ customRefreshActionInitializerItem + ] +}); +``` + + + +你可以根据需要实现更多的 `Action`。 + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-initializer-configure-actions --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-initializer-configure-actions.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 + diff --git a/docs/fr-FR/plugin-samples/schema-initializer/configure-fields-bk.md b/docs/fr-FR/plugin-samples/schema-initializer/configure-fields-bk.md new file mode 100644 index 000000000..04e677a01 --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initializer/configure-fields-bk.md @@ -0,0 +1,396 @@ +# 实现数据字段 Initializer + +## 场景说明 + +如果新创建的区块是一个复杂的数据区块,那么它内部可能包含多个动态添加的部分,其中重点就是通过 `Configure fields` 对应的 initializer 动态添加字段。例如 `Form` 区块,我们可以通过 `Configure fields` 来配置显示的字段。 + +![img_v3_02b4_111734a2-755f-4100-949d-96803ad1912g](https://static-docs.nocobase.com/img_v3_02b4_111734a2-755f-4100-949d-96803ad1912g.jpg) + +## 示例说明 + +本实例会在 [添加数据区块 Data Block](/plugin-samples/schema-initializer/data-block) 基础上继续实现类似 `Form` 区块的效果,通过 `Configure fields` 来配置显示的字段。 + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-initializer-configure-fields) 中查看。 + + + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-initializer-configure-fields +yarn pm enable @nocobase-sample/plugin-initializer-configure-fields +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +在实现本示例之前,我们需要先了解一些基础知识: + +- [SchemaInitializer 教程](/development/client/ui-schema/initializer):用于向界面内添加各种区块、字段、操作等 +- [SchemaInitializer API](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于向界面内添加各种区块、字段、操作等 +- [UI Schema](/development/client/ui-schema/what-is-ui-schema):用于定义界面的结构和样式 +- [Designable 设计器](/development/client/ui-schema/designable):用于修改 Schema + +### 1. Copy 代码并修改插件名称 + +前面已经说明本示例会在 [添加数据区块 Data Block](/plugin-samples/schema-initializer/data-block) 基础上继续实现,所以我们可以复制 `packages/plugins/@nocobase-sample/plugin-initializer-block-data/src/client` 目录覆盖 `packages/plugins/@nocobase-sample/plugin-initializer-configure-fields/src/client`。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-fields/src/client/index.tsx`: + +```diff +import { Plugin } from '@nocobase/client'; +import { InfoBlock, infoBlockSettings, infoBlockInitializerItem } from './InfoBlock'; + +- export class PluginInitializerBlockDataClient extends Plugin { ++ export class PluginInitializerConfigureFieldsClient extends Plugin { + async load() { + // ... + } +} + +- export default PluginInitializerBlockDataClient; ++ export default PluginInitializerConfigureFieldsClient; +``` + +为了避免和其他示例冲突,把所有 `InfoBlock` 改为了 `InfoBlock2`,但是本示例文档中仍然按照 `InfoBlock` 来说明。 + +### 2. 创建 `Configure fields` 对应的 initializer + +我们新建 `packages/plugins/@nocobase-sample/plugin-initializer-configure-fields/src/client/configureFields.tsx` 文件: + +```tsx | pure +import { Grid, SchemaInitializer, useSchemaInitializer } from "@nocobase/client"; + +export const configureFields = new SchemaInitializer({ + name: 'info:configureFields', + icon: 'SettingOutlined', + title: 'Configure fields', + items: [ + { + type: 'itemGroup', + name: 'fields', + title: 'Display fields', + useChildren() { + const { insert } = useSchemaInitializer(); + + return [] + }, + } + ] +}); +``` + +- [SchemaInitializer](https://client.docs.nocobase.com/core/ui-schema/schema-initializer):用于创建一个 Schema Initializer 实例 +- `icon`:图标,更多图标可参考 Ant Design [Icons](https://ant.design/components/icon/) +- `title`:按钮标题 +- [items](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#built-in-components-and-types):按钮下的子项 + - `type: 'itemGroup'`:子项类型,用于包装多个子项 + - `name: 'fields'`:子项名称 + - `title: 'Display fields'`:子项标题 + - `useChildren`:子项的子项,返回一个数组,数组中的每一项都是一个子项 + +### 3. 注册 `Configure fields` initializer + +然后修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-fields/src/client/index.tsx` 文件,导入并注册这个 initializer: + +```tsx | pure +import { configureFields } from './configureFields' + +export class PluginInitializerConfigureFieldsClient extends Plugin { + async load() { + this.app.schemaInitializerManager.add(configureFields) + } +} +``` + +### 4. 修改 `getInfoBlockSchema()` 区块 + +我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-fields/src/client/InfoBlock.tsx` 文件,将 `getInfoBlockSchema()` 区块修改为: + +```diff +function getInfoBlockSchema({ dataSource, collection }) { + return { + // ... + properties: { + info: { + type: 'void', + 'x-component': 'InfoBlock', ++ properties: { ++ fields: { ++ type: 'void', ++ 'x-component': 'Grid', ++ 'x-initializer': 'info:configureFields', ++ } ++ } + } + } + } +} +``` + +我们在 `InfoBlock` 的子节点中添加了一个 `fields` 字段,为了更好的布局,我们使用 `Grid` 组件包裹了一下,并且指定了 `x-initializer` 为 `info:configureFields`,因为 `Grid` 内置了 [useSchemaInitializerRender()](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#useschemainitializerrender) 的渲染逻辑,所以我们可以直接使用,如果是一个自定义的组件,需要自己通过 `useSchemaInitializerRender()` 实现渲染逻辑。 + +### 5. 修改 `InfoBlock` 组件 + +我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-fields/src/client/InfoBlock.tsx` 文件,将 `InfoBlock` 组件修改为: + +```tsx | pure +export const InfoBlock = ({ children }) => { + return
    {children}
    +} +``` + +`properties` 的内容会被传入到 `InfoBlock` 组件的 `children` 中,所以我们直接将 `children` 渲染出来即可。 + + + +### 6. 读取数据表字段作为 `Configure fields` 的子项 + +我们继续修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-fields/src/client/configureFields.tsx` 文件: + +```tsx | pure +interface GetFieldInitializerItemOptions { + collectionField: CollectionFieldOptions; +} + +function getFieldInitializerItem(options: GetFieldInitializerItemOptions) { + const { collectionField } = options; + const title = collectionField.uiSchema?.title || collectionField.name; + const name = collectionField.name; + return { + name: collectionField.name, + title: collectionField.uiSchema?.title || collectionField.name, + type: 'switch', + onClick() { + // TODO + } + } as SchemaInitializerItemType; +} + +export const configureFields = new SchemaInitializer({ + name: 'info:configureFields', + icon: 'SettingOutlined', + title: 'Configure fields', + items: [ + { + type: 'itemGroup', + name: 'fields', + title: 'Display fields', + useChildren() { + const collection = useCollection(); + + const schemaItems = collection + .getFields() + .map(getFieldInitializerItem({ + collectionField, + })) + + return schemaItems; + }, + } + ] +}); +``` + +- [useCollection()](https://client.docs.nocobase.com/core/data-source/collection-provider#usecollection):用于获取当前数据表的实例。在 `getInfoBlockSchema()` 中我们使用了 [DataBlockProvider](https://client.docs.nocobase.com/core/data-block/data-block-provider) ,其内部包含了 [CollectionProvider](https://client.docs.nocobase.com/core/data-source/collection-provider) ,所以我们可以直接使用。 + - `collection.getFields()`:获取数据表的字段 + +- getFieldInitializerItem:用于获取字段的 Schema Initializer Item + - `name`:子项名称,用于唯一标识 + - `title`:子项标题,用于显示,如果字段有 `uiSchema.title` 则使用 `uiSchema.title`,否则使用字段名称,关于 `field.uiSchema` 的数据结构可以参考 [CollectionField](https://client.docs.nocobase.com/core/data-source/collection-field) + - `type: 'switch'`:子项类型,[Switch 类型](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#type-switch--schemainitializerswitch),其核心是要实现 `onClick` 方法,当点击后如果已经存在则删除,如果不存在则添加。 + - `onClick`:点击事件,我们这里暂时不实现,后续会实现。 + +![img_v3_02b4_7d5c145e-cb15-4d93-9004-bde406e42a5g](https://static-docs.nocobase.com/img_v3_02b4_7d5c145e-cb15-4d93-9004-bde406e42a5g.jpg) + +### 7. 实现 `switch` 的添加和删除 + +我们修改 `packages/plugins/@nocobase-sample/plugin-initializer-configure-fields/src/client/configureFields.tsx` 文件: + +```diff ++ import { CollectionFieldOptions, ISchema, SchemaInitializer, SchemaInitializerItemType, SchemaSettings, useCollection, useDesignable, useSchemaInitializer } from "@nocobase/client"; + +export const configureFields = new SchemaInitializer({ + name: 'info:configureFields', + icon: 'SettingOutlined', + title: 'Configure fields', + items: [ + { + type: 'itemGroup', + name: 'fields', + title: 'Display fields', + useChildren() { ++ const { insert } = useSchemaInitializer(); ++ const { remove } = useDesignable(); ++ const schema = useFieldSchema(); + const collection = useCollection(); + + const schemaItems = collection + .getFields() + .map((collectionField) => getFieldInitializerItem({ + collectionField, ++ schema, ++ remove, ++ insert ++ })) + + return schemaItems; + }, + } + ] +}); +``` + +- [useDesignable()](https://client.docs.nocobase.com/core/ui-schema/designable#usedesignable):可以增删改查 Schema 的方法 +- [useSchemaInitializer()](https://client.docs.nocobase.com/core/ui-schema/schema-initializer#useschemainitializer):用于提供 SchemaInitializer 上下文 + - `insert`:用于插入 Schema。这里之所以使用 `useSchemaInitializer()` 所提供的 insert 方法,而不是 `useDesignable()` 提供的 insert 方法,是因为 Schema 是有层级的,`useSchemaInitializer()` 获取的是 `SchemaInitializer` 所在层级,而 `useDesignable()` 获取的是当前 Schema 所在层级,我们需要插入到 `SchemaInitializer` 所在层级的兄弟层,所以应该使用 `useSchemaInitializer()` 提供的 insert 方法。 + +```tsx | pure +function getInfoItemSchema(collectionFieldName: string) { + return { + type: 'void', + 'x-collection-field': collectionFieldName, + // TODO + } +} + +interface GetFieldInitializerItemOptions { + collectionField: CollectionFieldOptions; + schema: ISchema; + remove: (schema: ISchema) => void; + insert: (schema: ISchema) => void; +} + +function getFieldInitializerItem(options: GetFieldInitializerItemOptions) { + const { collectionField, schema, remove, insert } = options; + const title = collectionField.uiSchema?.title || collectionField.name; + const name = collectionField.name; + const collectionFieldSchema = Object.values(schema.properties || {}).find((item) => item['x-collection-field'] === name); + return { + name, + type: 'switch', + title, + checked: !!collectionFieldSchema, + onClick() { + if (collectionFieldSchema) { + remove(collectionFieldSchema) + return; + } + insert(getInfoItemSchema(name)) + } + } as SchemaInitializerItemType; +} +``` + +首先 `getInfoItemSchema` 用于返回一个字段的 Schema,其中一个关键点是 `x-collection-field` 字段,用于标识这个 Schema 是哪个字段的。 + +然后我们通过读取 `schema.properties` 中的数据,找到对应的字段的 Schema,如果存在则删除,如果不存在则插入。 + +### 8. 完善子节点 Schema 和组件 + +```ts +export const infoItemSettings = new SchemaSettings({ + name: 'fieldSettings:info', + items: [ + { + name: 'remove', + type: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn(s) { + return s['x-component'] === 'Grid'; + }, + }, + } + ] +}) + +export const InfoItem = () => { + const fieldSchema = useFieldSchema(); + const collection = useCollection(); + const collectionFieldName = fieldSchema.name; + return
    {JSON.stringify(collection.getField(collectionFieldName), null, 2)}
    +} + +function getInfoItemSchema(collectionFieldName: string) { + return { + type: 'void', + 'x-collection-field': collectionFieldName, + 'x-component': 'Grid.Row', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + [collectionFieldName]: { + type: 'void', + 'x-component': 'InfoItem', + 'x-decorator': 'CardItem', + 'x-settings': infoItemSettings.name, + }, + }, + }, + }, + } as ISchema; +} +``` + +我们在 `getInfoBlockSchema()` 中使用 `Grid` 组件作为父级,那么子节点就需要使用 `Grid.Row` 和 `Grid.Col` 组件,然后在 `Grid.Col` 中使用 `InfoItem` 组件。 + +`InfoItem` 就是具体的字段信息展示组件,我们这里做的事情很简单,首先读取当前字段的 Schema,其中 `schema.name` 对应 `collectionFieldName`,然后通过 [collection.getField(collectionFieldName)](https://client.docs.nocobase.com/core/data-source/collection#collectiongetfieldname) 获取字段的详细信息,然后展示出来。 + +然后我们将 `InfoItem` 和 `infoItemSettings` 组件注册到系统中: + +```ts +export class PluginInitializerComplexDataBlockClient extends Plugin { + async load() { + this.app.addComponents({ InfoBlock, InfoItem }); + this.app.schemaSettingsManager.add(infoBlockSettings, infoItemSettings); + } +} +``` + + + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-initializer-configure-fields --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-initializer-configure-fields.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 + diff --git a/docs/fr-FR/plugin-samples/schema-initializer/configure-fields.md b/docs/fr-FR/plugin-samples/schema-initializer/configure-fields.md new file mode 100644 index 000000000..4e452588a --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initializer/configure-fields.md @@ -0,0 +1,3 @@ +# 区块内嵌的 Initializer - 配置字段 + +TODO diff --git a/docs/fr-FR/plugin-samples/schema-initializer/index.md b/docs/fr-FR/plugin-samples/schema-initializer/index.md new file mode 100644 index 000000000..dbf0a396e --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-initializer/index.md @@ -0,0 +1,24 @@ +# SchemaInitializer + +[SchemaInitializer](/development/client/ui-schema/initializer) 用于向界面内添加各种区块、字段、操作等。 + +根据需求不同可能有以下扩展场景: + +- 向已有的 Initializer 中添加子项 +- 创建新的 Initializer + +根据以上场景,我们提供了如下示例: + +**向已有的 Initializer 中添加子项** + +- [添加简单区块 Simple Block](/plugin-samples/schema-initializer/block-simple) +- [添加数据区块 Data Block](/plugin-samples/schema-initializer/data-block) +- [添加带弹窗的数据区块 Data Block Modal](/plugin-samples/schema-initializer/data-block-modal) +- [添加简单 Action](/plugin-samples/schema-initializer/action-simple) +- [添加弹窗 Action](/plugin-samples/schema-initializer/action-modal) + +**创建新的 Initializer** + +- [区块内嵌的 Initializer - 配置字段](/plugin-samples/schema-initializer/configure-fields) +- [区块内嵌的 Initializer - 配置操作](/plugin-samples/schema-initializer/configure-actions) + diff --git a/docs/fr-FR/plugin-samples/schema-settings/add-item.md b/docs/fr-FR/plugin-samples/schema-settings/add-item.md new file mode 100644 index 000000000..ad213efa0 --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-settings/add-item.md @@ -0,0 +1,174 @@ +# 添加子项到已有的 SchemaSettings + +## 场景说明 + +在实际开发中,我们区块、操作、字段都需要配置一些属性,但是已有的配置不一定满足我们的需求,我们就需要根据需求添加一些新的配置项。 + +## 示例说明 + +目前 Table 区块的配置项中没有 `showIndex` 属性,我们需要添加一个 `showIndex` 属性,用于控制是否显示序号。 + +本实例主要为了演示 SchemaSettings 的使用,更多关于区块扩展可以查看 [区块扩展](/plugin-samples/block) 文档。 + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-schema-settings-add-item) 中查看。 + + + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-schema-settings-add-item +yarn pm enable @nocobase-sample/plugin-schema-settings-add-item +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +在实现本示例之前,我们需要先了解一些基础知识: + +- [SchemaSettings 教程](/development/client/ui-schema/settings):用于配置区块、字段、操作等的属性 +- [SchemaSettings API](https://client.docs.nocobase.com/core/ui-schema/schema-settings):用于配置区块、字段、操作等的属性 +- [UI Schema 协议](/development/client/ui-schema/what-is-ui-schema):详细介绍 Schema 的结构和每个属性的作用 +- [Designable 设计器](/development/client/ui-schema/designable):用于修改 Schema +- [TableV2](https://client.docs.nocobase.com/components/table-v2):Table 区块的文档 + +想要实现向已有的区块、字段、操作等添加新的配置项,需要有 3 个前提: + +- 组件需要支持新的配置 +- 需要正确设置 Schema +- Schema 的属性需要到传递到组件中 + +以本示例为例,我们需要在 Table 区块中添加 `showIndex` 属性,用于控制是否显示序号。 + +- 首先需要确认 [TableV2](https://client.docs.nocobase.com/components/table-v2) 区块是否支持 `showIndex` 属性:我们通过 [文档](https://client.docs.nocobase.com/components/table-v2) 可以得知 Table 区块支持 `showIndex` 属性 +- 然后需要确认 [Table Block Schema](https://client.docs.nocobase.com/ui-schema/blocks/data/table) 中 `TableV2` 组件的属性存储位置: 我们通过 [文档](https://client.docs.nocobase.com/ui-schema/blocks/data/table) 在 `x-decorator-props` 中 +- 最后需要确认 `showIndex` 属性的值是否传递到 `TableV2` 组件中:我们通过 [文档](https://client.docs.nocobase.com/ui-schema/blocks/data/table) 可以得知 `showIndex` 属性是通过 `useTableBlockProps` 传递到 `TableV2` 组件中 + +### 1. 定义 SchemaSettingsItem + +我们新建 `packages/plugins/@nocobase-sample/plugin-schema-settings-add-item/src/client/tableShowIndexSettingsItem.tsx` 文件: + +```ts +import { SchemaSettingsItemType, useDesignable } from '@nocobase/client'; +import { useFieldSchema } from '@formily/react'; + +export const tableShowIndexSettingsItem: SchemaSettingsItemType = { + name: 'showIndex', + type: 'switch', + useComponentProps() { + return {}; + }, +}; +``` + +我们定义了一个 `showIndex` 的配置项,类型为 `switch`。 + +- `name`:配置项的名称,用于增删改查 +- `type`:配置项的类型,用于渲染不同的组件,更多类型可以查看 [SchemaSettings API](https://client.docs.nocobase.com/core/ui-schema/schema-settings#built-in-components-and-types) +- `useComponentProps`:用于配置组件的属性 + +### 2. 修改 Schema + +```diff +import { SchemaSettingsItemType, useDesignable } from '@nocobase/client'; +import { useFieldSchema } from '@formily/react'; + +export const tableShowIndexSettingsItem: SchemaSettingsItemType = { + name: 'showIndex', + type: 'switch', + useComponentProps() { ++ const fieldSchema = useFieldSchema(); ++ const dn = useDesignable(); ++ return { ++ title: 'Show Index', ++ checked: !!fieldSchema['x-decorator-props'].showIndex, ++ onChange(v: boolean) { ++ dn.deepMerge({ ++ 'x-uid': fieldSchema['x-uid'], ++ 'x-decorator-props': { ++ ...fieldSchema['x-decorator-props'], ++ showIndex: v, ++ }, ++ }); ++ }, ++ }; + }, +}; +``` + +Hooks: + +- [useFieldSchema](https://client.docs.nocobase.com/core/ui-schema/designable#usefieldschema):用于获取当前字段的 Schema +- [useDesignable](https://client.docs.nocobase.com/core/ui-schema/designable#usedesignable):用于修改 Schema + +Props: + +- `title`:Switch 组件的标题 +- `checked`:Switch 组件的选中状态,通过 `fieldSchema['x-decorator-props'].showIndex` 获取,具体可以查看 [Table Block Schema](https://client.docs.nocobase.com/ui-schema/blocks/data/table) +- `onChange`:Switch 组件的值改变事件,通过 `dn.deepMerge` 修改 Schema + +`dn.deepMerge`:用于修改 Schema + +- `x-uid`:字段的唯一标识,用于服务端的查询和修改 +- `x-decorator-props`:字段的属性,用于配置组件的属性 + +### 3. 注册 SchemaSettingsItem + +我们修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-add-item/src/client/index.ts` 文件: + +```ts +import { Plugin } from '@nocobase/client'; +import { tableShowIndexSettingsItem } from './tableShowIndexSettingsItem' + +export class PluginSchemaSettingsAddItemClient extends Plugin { + async load() { + this.schemaSettingsManager.addItem('blockSettings:table', tableShowIndexSettingsItem.name, tableShowIndexSettingsItem) + } +} + +export default PluginSchemaSettingsAddItemClient; +``` + +然后我们就可以看到 Table 区块的配置项中多了一个 `Show Index` 的配置项。 + + + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build nocobase-sample/plugin-schema-settings-add-item --tar +``` + +这样就可以看到 `storage/tar/nocobase-sample/plugin-schema-settings-add-item.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugin-samples/schema-settings/index.md b/docs/fr-FR/plugin-samples/schema-settings/index.md new file mode 100644 index 000000000..109f1c5f8 --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-settings/index.md @@ -0,0 +1,13 @@ +# SchemaSettings + +[SchemaSettings](/development/client/ui-schema/settings) 通过修改 Schema 动态配置区块、字段、操作的属性。 + +根据需求不同可能有以下扩展场景: + +- 向已有的 SchemaSettings 中添加子项 +- 创建新的 SchemaSettings + +根据以上场景,我们提供了如下示例: + +- [创建新的 SchemaSettings](/plugin-samples/schema-settings/new) +- [添加子项到已有的 SchemaSettings](/plugin-samples/schema-settings/add-item) diff --git a/docs/fr-FR/plugin-samples/schema-settings/new.md b/docs/fr-FR/plugin-samples/schema-settings/new.md new file mode 100644 index 000000000..6d7312b04 --- /dev/null +++ b/docs/fr-FR/plugin-samples/schema-settings/new.md @@ -0,0 +1,854 @@ +# 创建新的 SchemaSettings + +## 场景说明 + +当我们新增一个区块、字段或者操作时,我们可能需要新增一些配置项,用于其展示、行为等,这时我们就需要新增一个 `SchemaSettings`。 + +## 示例说明 + +本示例会在 [简单区块](/plugin-samples/schema-initializer/block-simple) 例子的基础上完善,当时只是创建了一个只有 `remove` 的 SchemaSettings,本示例会增加如下配置项: + +- `Edit block title`:编辑区块标题 +- `Edit Image`:编辑图片 +- `Edit height`:编辑图片的高度 +- `objectFit`:选择 img 的 `object-fit` 属性 +- `Lazy`:是否懒加载 + +
    + + + +本实例主要为了演示 initializer 的使用,更多关于区块扩展可以查看 [区块扩展](/plugin-samples/block) 文档。 + +本文档完整的示例代码可以在 [plugin-samples](https://github.com/nocobase/plugin-samples/tree/main/packages/plugins/%40nocobase-sample/plugin-schema-settings-new) 中查看。 + + +## 初始化插件 + +我们按照 [编写第一个插件](/development/your-fisrt-plugin) 文档说明,如果没有一个项目,可以先创建一个项目,如果已经有了或者是 clone 的源码,则跳过这一步。 + +```bash +yarn create nocobase-app my-nocobase-app -d sqlite +cd my-nocobase-app +yarn install +yarn nocobase install +``` + +然后初始化一个插件,并添加到系统中: + +```bash +yarn pm create @nocobase-sample/plugin-schema-settings-new +yarn pm enable @nocobase-sample/plugin-schema-settings-new +``` + +然后启动项目即可: + +```bash +yarn dev +``` + +然后登录后访问 [http://localhost:13000/admin/pm/list/local/](http://localhost:13000/admin/pm/list/local/) 就可以看到插件已经安装并启用了。 + +## 功能实现 + +### 1. 创建区块/字段/操作 + +前面已经说明本示例会在 [简单区块](/plugin-samples/schema-initializer/simple-block) 基础上继续实现,所以我们可以复制 `packages/plugins/@nocobase-sample/plugin-initializer-block-simple/src/client` 目录覆盖 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client`。 + +然后修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/index.tsx`: + +```diff +// ... +- import { Image } from './component'; ++ import { ImageV2 } from './component'; + +- export class PluginInitializerBlockSimpleClient extends Plugin { ++ export class PluginSchemaSettingsNewClient extends Plugin { + async load() { +- this.app.addComponents({ Image }) ++ this.app.addComponents({ ImageV2 }) + // ... + } +} + +- export default PluginInitializerBlockSimpleClient; ++ export default PluginSchemaSettingsNewClient; +``` + +然后修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/component/Image.tsx` 的 `Image` 组件: + +```diff +- export const Image: FC<{ height?: number }> = withDynamicSchemaProps(({ height = 500 }) => { ++ export const ImageV2: FC<{ height?: number }> = withDynamicSchemaProps(({ height = 500 }) => { +``` + +然后修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/constants.ts`: + +```ts +export const BlockName = 'ImageV2'; +export const BlockNameLowercase = 'image-v2'; +``` + +### 2. 组件属性 + +#### 2.1 实现组件 + +我们需要先让组件支持需求中的属性。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/component/Image.tsx` 文件: + +```tsx | pure +import React, { FC } from 'react'; +import { withDynamicSchemaProps } from '@nocobase/client'; +import { BlockName } from '../constants'; + +export interface ImageV2Props { + src?: { url: string; title?: string }; + /** + * @default 500 + */ + height?: number; + /** + * @default 'cover' + */ + objectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'; + /** + * @default false + */ + lazy?: boolean; +} + +export const ImageV2: FC = withDynamicSchemaProps((props) => { + const { src, height = 500, objectFit = 'cover', lazy = false } = props; + return
    + { + src ? {src.title} : null + } +
    +}, { displayName: BlockName }) +``` + +#### 2.2 验证组件 + +组件验证方式有 2 种: + +- 临时页面验证:我们可以临时建一个页面,然后渲染 `ImageV2` 组件,查看是否符合需求 +- 文档示例验证:可以启动文档 `yarn doc plugins/@@nocobase-sample/plugin-schema-settings-new`,通过写文档示例的方式验证是否符合需求(TODO) + +我们以 `临时页面验证` 为例,我们新建一个页面,根据属性参数添加一个或者多个 `Image` 组件,查看是否符合需求。 + +```tsx | pure +// ... +export class PluginSchemaSettingsNewClient extends Plugin { + async load() { + // ... + this.app.router.add('admin.image-component', { + path: '/admin/image-component', + Component: () => { + return <> +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + } + }) + } +} +``` + +我们访问 [http://localhost:3000/admin/image-component](http://localhost:3000/admin/image-component),查看是否符合需求。 + + + +验证完毕后需要删除测试页面。 + +### 3. 实现 Schema + +#### 3.1 定义 Schema + +我们修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/schema/index.ts`: + +```diff +import { ISchema } from "@nocobase/client"; +import { useFieldSchema } from '@formily/react'; +import { imageSettings } from "../settings"; +import { BlockName, BlockNameLowercase } from "../constants"; + ++ import { ImageV2Props } from "../component"; + ++ export function useImageV2Props(): ImageV2Props { ++ const fieldSchema = useFieldSchema(); ++ return fieldSchema.parent?.['x-decorator-props']?.[BlockNameLowercase]; ++ } + +export const imageSchema: ISchema = { + type: 'void', + 'x-component': 'CardItem', ++ 'x-decorator-props': { ++ [BlockNameLowercase]: {} ++ }, + properties: { + [BlockNameLowercase]: { + 'x-component': BlockName, ++ 'x-use-component-props': 'useImageV2Props' + } + }, + 'x-settings': imageSettings.name +}; +``` + +我们将 `Image` 的属性存储在 `x-decorator-props` 的 `image` 属性中,然后通过 `x-use-component-props` 来获取。 + +`useImageV2Props()`:返回 `Image` 组件对应的属性 + +- `useFieldSchema()`:获取当前字段的 schema,并通过 `parent` 获取父级 schema。如果是数据区块则可以通过 [useDataBlockProps](https://client.docs.nocobase.com/core/data-block/data-block-provider#usedatablockprops) 获取属性。 + +#### 3.2 验证 Schema + +```tsx | pure +// ... +export class PluginSchemaSettingsNewClient extends Plugin { + async load() { + // ... + this.app.router.add('admin.image-schema', { + path: '/admin/image-schema', + Component: () => { + return <> +
    + +
    +
    + +
    +
    + +
    +
    + +
    + + } + }) + } +} +``` + +我们访问 [http://localhost:3000/admin/image-component](http://localhost:3000/admin/image-component),查看是否符合需求。 + + + +验证完毕后需要删除测试页面。 + +### 4. 实现 SchemaSettings + +[简单区块文档](/plugin-samples/schema-initializer/block-simple#4-实现-schema-settings) 中已经说明了如何实现 `SchemaSettings`。 + +### 5. 实现 SchemaSettings items + +#### 5.1 实现 Edit block title + +因为编辑区块标题是一个通用的逻辑,所以 NocoBase 提供了 SchemaSettingsBlockTitleItem(文档 TODO) 组件,我们可以直接使用。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/InfoBlock.tsx`: + +```diff +- import { SchemaSettingsBlockTitleItem } from "@nocobase/client"; ++ import { SchemaSettings, SchemaSettingsBlockTitleItem } from "@nocobase/client"; + +export const imageSettings = new SchemaSettings({ + name: 'blockSettings:image', + items: [ ++ { ++ name: 'editBlockTitle', ++ Component: SchemaSettingsBlockTitleItem, ++ }, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + + + +更多可以复用的 SchemaSettings items 可以查看 TODO。 + +#### 5.2 实现 Edit Image + +##### 5.2.1 实现 SchemaSettings Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/settings/items/image.ts` 文件: + +```ts +import { SchemaSettingsItemType, useDesignable, } from "@nocobase/client"; +import { useFieldSchema } from '@formily/react'; +import { useT } from "../../locale"; +import { BlockNameLowercase } from "../../constants"; + +export const imageSchemaSettingsItem: SchemaSettingsItemType = { + name: 'src', + type: 'actionModal', + useComponentProps() { + const filedSchema = useFieldSchema(); + const { deepMerge } = useDesignable(); + const t = useT(); + + return { + title: t('Edit Image'), + schema: { + type: 'object', + title: t('Edit Image'), + properties: { + src: { + title: t('Image'), + type: 'string', + default: filedSchema['x-decorator-props']?.[BlockNameLowercase]?.src, + 'x-decorator': 'FormItem', + 'x-component': 'Upload.Attachment', + 'x-component-props': { + action: 'attachments:create', + }, + }, + }, + }, + onSubmit(image: any) { + deepMerge({ + 'x-uid': filedSchema['x-uid'], + 'x-decorator-props': { + ...filedSchema['x-decorator-props'], + [BlockNameLowercase]: { + ...filedSchema['x-decorator-props']?.[BlockNameLowercase], + src: image.src, + }, + }, + }) + } + }; + }, +}; +``` + +关于 SchemaSettings Item 的定义可以查看 [SchemaSettingsItem](https://client.docs.nocobase.com/core/ui-schema/schema-settings#optionsitems)。 + +- `type`:内置类型。[actionModal](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsactionmodalitem) 为弹窗类型 +- `name`:唯一标识,用于增删改查 +- `useComponentProps`:返回 `actionModal` 对应组件 `SchemaSettingsActionModalItem` 的属性 + +`useComponentProps`: + +- Hooks + - `useFieldSchema`:获取当前节点 schema + - `useDesignable`:获取当前 Designable 实例,deepMerge 用于合并 schema + - `x-uid`:当前节点的唯一标识 + - `x-decorator-props`:当前节点的属性,存储了 `image` 的属性 + +- Props + - `title`:弹窗标题 + - `schema`:弹窗表单 schema + - [Upload.Attachment](https://client.docs.nocobase.com/components/upload):上传组件 + - [FormItem](https://client.docs.nocobase.com/components/form-item):表单项 + - `onSubmit`:表单提交事件 + +##### 5.2.2 使用 SchemaSettings Item + +我们修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/settings/index.ts`: + +```diff +// ... ++ import { imageSchemaSettingsItem } from "./items/image"; + +export const imageSettings = new SchemaSettings({ + name: 'blockSettings:image', + items: [ + { + name: 'editBlockTitle', + Component: SchemaSettingsBlockTitleItem, + }, ++ imageSchemaSettingsItem, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + + + +#### 5.3 实现 Edit Height + +##### 5.3.1 实现 SchemaSettings Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/settings/items/height.ts` 文件: + +```ts +import { SchemaSettingsItemType, useDesignable, } from "@nocobase/client"; +import { useFieldSchema } from '@formily/react'; +import { useT } from '../../locale' +import { BlockNameLowercase } from "../../constants"; + +export const heightSchemaSettingsItem: SchemaSettingsItemType = { + name: 'height', + type: 'actionModal', + useComponentProps() { + const filedSchema = useFieldSchema(); + const { deepMerge } = useDesignable(); + const t = useT(); + + return { + title: t('Edit height'), + schema: { + type: 'object', + title: t('Edit height'), + properties: { + height: { + title: t('Height'), + type: 'number', + default: filedSchema['x-decorator-props']?.[BlockNameLowercase]?.height, + 'x-decorator': 'FormItem', + 'x-component': 'InputNumber', + }, + }, + }, + onSubmit({ height }: any) { + deepMerge({ + 'x-uid': filedSchema['x-uid'], + 'x-decorator-props': { + ...filedSchema['x-decorator-props'], + [BlockNameLowercase]: { + ...filedSchema['x-decorator-props']?.[BlockNameLowercase], + height, + }, + }, + }) + } + }; + }, +}; +``` + +关于 SchemaSettings Item 的定义可以查看 [SchemaSettingsItem](https://client.docs.nocobase.com/core/ui-schema/schema-settings#optionsitems)。 + +- `type`:内置类型。[actionModal](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsactionmodalitem) 为弹窗类型 +- `name`:唯一标识,用于增删改查 +- `useComponentProps`:返回 `actionModal` 对应组件 `SchemaSettingsActionModalItem` 的属性 + +`useComponentProps`: + +- Hooks + - `useFieldSchema`:获取当前节点 schema + - `useDesignable`:获取当前 Designable 实例,deepMerge 用于合并 schema + - `x-uid`:当前节点的唯一标识 + - `x-decorator-props`:当前节点的属性,存储了 `image` 的属性 + +- Props + - `title`:弹窗标题 + - `schema`:弹窗表单 schema + - [InputNumber](https://client.docs.nocobase.com/components/input-number):数字输入框 + - [FormItem](https://client.docs.nocobase.com/components/form-item):表单项 + - `onSubmit`:表单提交事件 + +##### 5.3.2 使用 SchemaSettings Item + +我们修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/settings/index.ts`: + +```diff +// ... ++ import { heightSchemaSettingsItem } from "./items/height"; + +export const imageSettings = new SchemaSettings({ + name: 'blockSettings:image', + items: [ + { + name: 'editBlockTitle', + Component: SchemaSettingsBlockTitleItem, + }, + imageSchemaSettingsItem, ++ heightSchemaSettingsItem, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + + + + +#### 5.4 实现 ObjectFit + +##### 5.4.1 实现 SchemaSettings Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/items/objectFit.ts` 文件: + +```ts +import { SchemaSettingsItemType, useDesignable, } from "@nocobase/client"; +import { useFieldSchema } from '@formily/react'; +import { useT } from "../../locale"; +import { BlockNameLowercase } from "../../constants"; + +export const objectFitSchemaSettingsItem: SchemaSettingsItemType = { + name: 'objectFit', + type: 'select', + useComponentProps() { + const filedSchema = useFieldSchema(); + const { deepMerge } = useDesignable(); + const t = useT(); + + return { + title: t('Object Fit'), + options: [ + { label: 'Cover', value: 'cover' }, + { label: 'Contain', value: 'contain' }, + { label: 'Fill', value: 'fill' }, + { label: 'None', value: 'none' }, + { label: 'Scale Down', value: 'scale-down' }, + ], + value: filedSchema['x-decorator-props']?.[BlockNameLowercase]?.objectFit || 'cover', + onChange(v) { + deepMerge({ + 'x-uid': filedSchema['x-uid'], + 'x-decorator-props': { + ...filedSchema['x-decorator-props'], + [BlockNameLowercase]: { + ...filedSchema['x-decorator-props']?.[BlockNameLowercase], + objectFit: v, + }, + }, + }) + }, + }; + }, +}; +``` + +关于 SchemaSettings Item 的定义可以查看 [SchemaSettingsItem](https://client.docs.nocobase.com/core/ui-schema/schema-settings#optionsitems)。 + +- `type`:内置类型。[select](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsselectitem) 为选择类型 +- `name`:唯一标识,用于增删改查 +- `useComponentProps`:返回 `select` 对应组件 `SchemaSettingsSelectItem` 的属性 + +`useComponentProps`: + +- Hooks + - `useFieldSchema`:获取当前节点 schema + - `useDesignable`:获取当前 Designable 实例,deepMerge 用于合并 schema + - `x-uid`:当前节点的唯一标识 + - `x-decorator-props`:当前节点的属性,存储了 `image` 的属性 + +- Props + - `title`:弹窗标题 + - `options`:选择项 + - `value`:默认值 + - `onChange`:选择事件 + + +##### 5.4.2 使用 SchemaSettings Item + +我们修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/settings/index.ts`: + +```diff +// ... ++ import { objectFitSchemaSettingsItem } from "./items/objectFit"; + +export const imageSettings = new SchemaSettings({ + name: 'blockSettings:image', + items: [ + { + name: 'editBlockTitle', + Component: SchemaSettingsBlockTitleItem, + }, + imageSchemaSettingsItem, + heightSchemaSettingsItem, ++ objectFitSchemaSettingsItem, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + + + +#### 5.5 实现 Lazy + +##### 5.5.1 实现 SchemaSettings Item + +我们新建 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/items/lazy.ts` 文件: + +```ts +import { SchemaSettingsItemType, useDesignable, } from "@nocobase/client"; +import { useFieldSchema } from '@formily/react'; +import { useT } from "../../locale"; +import { BlockNameLowercase } from "../../constants"; + +export const lazySchemaSettingsItem: SchemaSettingsItemType = { + name: 'lazy', + type: 'switch', + useComponentProps() { + const filedSchema = useFieldSchema(); + const { deepMerge } = useDesignable(); + const t = useT(); + + return { + title: t('Lazy'), + checked: !!filedSchema['x-decorator-props']?.[BlockNameLowercase]?.lazy, + onChange(v) { + deepMerge({ + 'x-uid': filedSchema['x-uid'], + 'x-decorator-props': { + ...filedSchema['x-decorator-props'], + [BlockNameLowercase]: { + ...filedSchema['x-decorator-props']?.[BlockNameLowercase], + lazy: v, + }, + }, + }) + }, + }; + }, +}; +``` + +关于 SchemaSettings Item 的定义可以查看 [SchemaSettingsItem](https://client.docs.nocobase.com/core/ui-schema/schema-settings#optionsitems)。 + +- `type`:内置类型。[switch](https://client.docs.nocobase.com/core/ui-schema/schema-settings#schemasettingsswitchitem) 为开关类型 +- `name`:唯一标识,用于增删改查 +- `useComponentProps`:返回 `switch` 对应组件 `SchemaSettingsSwitchItem` 的属性 + +`useComponentProps`: + +- Hooks + - `useFieldSchema`:获取当前节点 schema + - `useDesignable`:获取当前 Designable 实例,deepMerge 用于合并 schema + - `x-uid`:当前节点的唯一标识 + - `x-decorator-props`:当前节点的属性,存储了 `image` 的属性 + +- Props + - `title`:弹窗标题 + - `checked`:默认值 + - `onChange`:开关事件 + + +##### 5.5.2 使用 SchemaSettings Item + +我们修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/settings/index.ts`: + +```diff +// ... ++ import { lazySchemaSettingsItem } from "./items/lazy"; + +export const imageSettings = new SchemaSettings({ + name: 'blockSettings:image', + items: [ + { + name: 'editBlockTitle', + Component: SchemaSettingsBlockTitleItem, + }, + imageSchemaSettingsItem, + heightSchemaSettingsItem, + objectFitSchemaSettingsItem, ++ lazySchemaSettingsItem, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + + + +#### 5.6 增加 divider + +`editBlockTitle` 和 `remove` 是一个通用的逻辑,而 `src`、`height`、`objectFit`、`lazy` 是针对 `Image` 的配置,我们可以通过 `divider` 来区分。 + +我们修改 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/client/settings/index.ts`: + +```diff +// ... +export const imageSettings = new SchemaSettings({ + name: 'blockSettings:image', + items: [ + { + name: 'editBlockTitle', + Component: SchemaSettingsBlockTitleItem, + }, ++ { ++ name: 'divider1', ++ type: 'divider' ++ }, + imageSchemaSettingsItem, + heightSchemaSettingsItem, + objectFitSchemaSettingsItem, + lazySchemaSettingsItem, ++ { ++ name: 'divider2', ++ type: 'divider' ++ }, + { + type: 'remove', + name: 'remove', + componentProps: { + removeParentsIfNoChildren: true, + breakRemoveOn: { + 'x-component': 'Grid', + }, + } + } + ] +}); +``` + +![20240602112229](https://static-docs.nocobase.com/20240602112229.png) + + +### 6. 多语言 + +:::warning +多语言文件变更后,需要重启服务才能生效 +::: + +#### 6.1 英文 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/locale/en-US.json` 文件: + +```json +{ + "Image": "Image", + "Edit Image": "Edit Image", + "Images": "Images", + "Autoplay": "Autoplay", + "Edit height": "Edit Height", + "Height": "Height", + "Lazy": "Lazy" +} +``` + +#### 6.2 中文 + +我们编辑 `packages/plugins/@nocobase-sample/plugin-schema-settings-new/src/locale/zh-CN.json` 文件: + +```json +{ + "Image": "图片", + "Edit Image": "编辑图片", + "Images": "图片", + "Edit height": "编辑高度", + "Height": "高度", + "Lazy": "懒加载" +} +``` +如果需要更多的多语言支持,可以继续添加。 + +## 打包和上传到生产环境 + +按照 [构建并打包插件](/development/your-fisrt-plugin#构建并打包插件) 文档说明,我们可以打包插件并上传到生产环境。 + +如果是 clone 的源码,需要先执行一次全量 build,将插件的依赖也构建好。 + +```bash +yarn build +``` + +如果是使用的 `create-nocobase-app` 创建的项目,可以直接执行: + +```bash +yarn build @nocobase-sample/plugin-schema-settings-new --tar +``` + +这样就可以看到 `storage/tar/@nocobase-sample/plugin-schema-settings-new.tar.gz` 文件了,然后通过[上传的方式](/welcome/getting-started/plugin)进行安装。 diff --git a/docs/fr-FR/plugins/acl/index.md b/docs/fr-FR/plugins/acl/index.md new file mode 100644 index 000000000..12904f942 --- /dev/null +++ b/docs/fr-FR/plugins/acl/index.md @@ -0,0 +1,12 @@ +# 权限控制 + +## 介绍 + +NocoBase 的 ACL 模块主要由两部分组成: + +- 内核中的 `@nocobase/acl`,提供核心功能 +- 插件中的 `@nocobase/plugin-acl`,提供动态配置能力 + +## 安装 + +内置插件,无需单独安装。 diff --git a/docs/fr-FR/plugins/acl/user/index.md b/docs/fr-FR/plugins/acl/user/index.md new file mode 100755 index 000000000..1ebac6586 --- /dev/null +++ b/docs/fr-FR/plugins/acl/user/index.md @@ -0,0 +1,265 @@ +# 使用手册 + +## 管理中心 + +### 角色的管理 + +![](https://static-docs.nocobase.com/da7083c67d794e23dc6eb0f85b1de86c.png) + +初始化安装的应用内置了两个角色,分别是 "Admin" 和 "Member",它们具有不同的默认权限设置。 + +### 角色的增删改 + +角色标识(系统唯一标识),可以自定义默认角色,不可将系统默认角色删除 + +![](https://static-docs.nocobase.com/35f323b346db4f9f12f9bee4dea63302.png) + +### 设置默认角色 + +这里的默认角色是指当新建的用户没有配角色时,默认用哪个角色 + +![](https://static-docs.nocobase.com/f41bba7ff55ca28715c486dc45bc1708.png) + +### 配置权限 + +#### 通用权限配置 + +![](https://static-docs.nocobase.com/119a9650259f9be71210121d0d3a435d.png) + +##### 配置权限 + +1. 允许配置界面:该权限控制是否允许用户配置界面。激活此权限后,出现 UI 配置按钮。"admin" 角色默认启用此权限。 +2. 允许安装、激活、禁用插件:该权限控制是否允许用户启用或禁用插件。激活此权限后,用户可以访问插件管理器界面。"admin" 角色默认启用此权限。 +3. 允许配置插件:该权限控制是否允许用户配置插件参数或管理插件后台数据。"admin" 角色默认启用此权限。 +4. 允许清除缓存,重启应用:该权限控制的是用户的系统运维权限: 清空缓存和重启应用。激活后,相关操作按钮将出现在个人中心,默认不启用。 +5. 新增菜单项默认允许访问:默认新建的菜单允许访问,默认开启 + +##### 全局操作权限 + +全局操作权限对全局生效(所有数据表)按照操作类型划分,支持根据数据范围维度配置:所有数据和自己的数据。前者允许对整个数据表执行操作,而后者限制仅能处理自己相关的数据。 + +#### 数据表操作权限 + +![](https://static-docs.nocobase.com/6a6e0281391cecdea5b5218e6173c5d7.png) + +![](https://static-docs.nocobase.com/9814140434ff9e1bf028a6c282a5a165.png) + +数据表操作权限进一步细化了全局操作权限,可以针对每个数据表的资源访问进行个别的权限配置。这些权限分为两个方面: + +1. 操作权限:操作权限包括添加、查看、编辑、删除、导出和导入操作。这些权限根据数据范围的维度进行配置: + + - 所有数据:允许用户对数据表中的所有记录执行操作。 + - 自己的数据:限制用户仅对自己创建的数据记录执行操作。 + +2. 字段权限:字段权限允许对每个字段在不同操作中进行权限配置。例如,某些字段可以配置为只允许查看而不允许编辑。 + +#### 菜单访问权限 + +菜单访问权限以菜单为维度控制访问权限 + +![](https://static-docs.nocobase.com/28eddfc843d27641162d9129e3b6e33f.png) + +#### 插件配置权限 + +插件配置权限用于控制对特定插件参数的配置权限,当插件配置权限勾选后管理中心将出现对应的插件管理界面 + +![](https://static-docs.nocobase.com/5a742ae20a9de93dc2722468b9fd7475.png) + +## 个人中心 + +### 角色切换 + +可以为一个用户分配多个角色,当用户拥有多个角色时,可在个人中心切换角色 + +![](https://static-docs.nocobase.com/e331d11ec1ca3b8b7e0472105b167819.png) + +用户进入系统的的默认角色优先级为:上一次切换的角色(每次切换角色时会更新默认角色值)> 第一个角色(系统默认角色) + +## 在 UI 中的应用 + +### 数据区块的权限 + +数据表数据区块是否可见由查看操作权限控制(单独配置的优先级高于全局) + +如下图:全局权限下 admin 拥有所有权限,订单表配置单独权限(不可见) + +全局权限配置如下: + +![](https://static-docs.nocobase.com/3d026311739c7cf5fdcd03f710d09bc4.png) + +订单表单独权限配置如下: + +![](https://static-docs.nocobase.com/a88caba1cad47001c1610bf402a4a2c1.png) + +在 UI 上的表现为订单表的所有区块均不显示 + +完整配置流程如下 + +![](https://static-docs.nocobase.com/b283c004ffe0b746fddbffcf4f27b1df.gif) + +### 字段权限 + +查看: 控制字段字段级别是否可见,例如控制某个角色对订单表的某些字段可见 + +![](https://static-docs.nocobase.com/30dea84d984d95039e6f7b180955a6cf.png) + +在 UI 上表现为订单表的区块中只显示有配置权限的字段,系统字段(Id,CreateAt ,Last updated at)即使不配置也有查看权限 + +![](https://static-docs.nocobase.com/40cc49b517efe701147fd2e799e79dcc.png) + +- 编辑:控制字段是否可以编辑保存(更新) + +如图配置订单表字段的编辑权限(数量和关联的商品有编辑权限) + +![](https://static-docs.nocobase.com/6531ca4122f0887547b5719e2146ba93.png) + +在 UI 上的表现为订单表区块的编辑操作表单区块只显示有编辑权限的字段 + +![](https://static-docs.nocobase.com/12982450c311ec1bf87eb9dc5fb04650.png) + +完整配置流程如下: + +![](https://static-docs.nocobase.com/1dbe559a9579c2e052e194e50edc74a7.gif) + +- 添加:控制字段是否可以添加(创建) + +如图配置订单表字段的添加权限(订单编号、数量、商品、运单有添加权限) + +![](https://static-docs.nocobase.com/3ab1bbe41e61915e920fd257f2e0da7e.png) + +在 UI 中表现为订单表区块的添加操作表单区块中只显示有添加权限的字段 + +![](https://static-docs.nocobase.com/8d0c07893b63771c428974f9e126bf35.png) + +- 导出:控制字段是否可以导出 +- 导入:控制字段是否支持导入 + +### 操作权限 + +单独配置的优先级最高,有单独配置按单独配置权限没有则走全局配置的权限 + +- 添加,控制区块中添加操作按钮是否显示 + +如图订单表单独配置操作权限,允许添加 + +![](https://static-docs.nocobase.com/2e3123b5dbc72ae78942481360626629.png) + +在 UI 中表现为订单表区块中操作区域中添加按钮显示 + +![](https://static-docs.nocobase.com/f0458980d450544d94c73160d75ba96c.png) + +- 查看 + +控制数据区块是否显示 + +如图全局权限配置如下(没有查看权限) + +![](https://static-docs.nocobase.com/6e4a1e6ea92f50bf84959dedbf1d5683.png) + +订单表单独配置权限如下 + +![](https://static-docs.nocobase.com/f2dd142a40fe19fb657071fd901b2291.png) + +在 UI 中表现为:其他所有数据表的区块均不显示,订单表的区块显示。 + +完整示例配置流程如下 + +![](https://static-docs.nocobase.com/b92f0edc51a27b52e85cdeb76271b936.gif) + +- 编辑 + +控制区块内的编辑操作按钮是否显示 + +![](https://static-docs.nocobase.com/fb1c0290e2a833f1c2b415c761e54c45.gif) + +通过设置数据范围可以进一步控制操作的权限 + +如图设置订单数据表中用户只能编辑数据自己的数据 + +![](https://static-docs.nocobase.com/b082308f62a3a9084cab78a370c14a9f.gif) + +- 删除 + +控制区块中删除操作按钮的显示 + +![](https://static-docs.nocobase.com/021c9e79bcc1ad221b606a9555ff5644.gif) + +- 导出 + +控制区块中导出操作按钮的显示 + +- 导入 + +控制区块中导入操作按钮的显示 + +### 关系权限 + +#### 作为字段时 + +- 关系字段的权限由源表的字段权限控制,控制整个关系字段组件是否显示 + +如图订单表中关系字段客户只有查看和导入导出权限 + +![](https://static-docs.nocobase.com/d0dc797aae73feeabc436af285dd4f59.png) + +在 UI 中表现为订单表区块中添加和编辑操作区块中客户关系字段不会显示 + +完整示例配置流程如下 + +![](https://static-docs.nocobase.com/372f8a4f414feea097c23b2ba326c0ef.gif) + +- 关系字段组件内(如子表格/子表单)字段的权限由目标数据表权限决定 + +关系字段组件为子表单时: + +如下图订单表中关系字段「客户」,订单中的关系字段「客户」有所有权限,而客户表设置单独权限为只读 + +订单表单独配置权限如下,「客户」关系字段有所有字段权限 + +![](https://static-docs.nocobase.com/3a3ab9722f14a7b3a35361219d67fa40.png) + +客户表单独配置权限如下,客户表中字段只有查看权限 + +![](https://static-docs.nocobase.com/46704d179b931006a9a22852e6c5089e.png) + +在 UI 中表现为:在订单表区块中客户关系字段可见,而当切换为子表单时(子表单内的字段在详情中可见,在新建和编辑操作中不显示) + +完整示例配置流程如下 + +![](https://static-docs.nocobase.com/932dbf6ac46e36ee357ff3e8b9ea1423.gif) + +进一步控制子表单内字段权限:个别字段拥有权限 + +如图客户表单独配置字段权限(客户名称不可见不可编辑) + +![](https://static-docs.nocobase.com/e7b875521cbc4e28640f027f36d0413c.png) + +完整示例配置流程如下 + +![](https://static-docs.nocobase.com/7a07e68c2fe2a13f0c2cef19be489264.gif) + +关系字段组件为子表格时情况和子表单一致: + +如图订单表中有关系字段「运单」,订单中的关系字段「运单」有所有权限,而运单表设置单独权限为只读 + +在 UI 中表现为:该关系字段可见,而当切换为子表格时(子表格内的字段在查看操作中可见,在新建和编辑操作中不可见) + +![](https://static-docs.nocobase.com/fd4b7d81cdd765db789d9c85cf9dc324.gif) + +进一步控制子表格内字段权限:个别字段拥有权限 + +![](https://static-docs.nocobase.com/51d70a624cb2b0366e421bcdc8abb7fd.gif) + +#### 作为区块时 + +- 关系区块的由对应关系字段目标表权限控制,和关系字段权限无关 + +如图「客户」关系区块是否显示由客户表权限控制 + +![](https://static-docs.nocobase.com/633ebb301767430b740ecfce11df47b3.gif) + +- 关系区块内的字段由目标表中的字段权限控制 + +如图为客户表设置个别字段拥有查看权限 + +![](https://static-docs.nocobase.com/35af9426c20911323b17f67f81bac8fc.gif) \ No newline at end of file diff --git a/docs/fr-FR/plugins/acl/user/static/ApOObW9lGoRGE0xcFcscpDZ5nid.png b/docs/fr-FR/plugins/acl/user/static/ApOObW9lGoRGE0xcFcscpDZ5nid.png new file mode 100755 index 000000000..db526bc48 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/ApOObW9lGoRGE0xcFcscpDZ5nid.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/AtS4bAdLCojw2Ex4FvjcEn1tngx.gif b/docs/fr-FR/plugins/acl/user/static/AtS4bAdLCojw2Ex4FvjcEn1tngx.gif new file mode 100755 index 000000000..7fee988d6 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/AtS4bAdLCojw2Ex4FvjcEn1tngx.gif differ diff --git a/docs/fr-FR/plugins/acl/user/static/CIZCbruUtoFZe1xIHUWcS2HwnEh.png b/docs/fr-FR/plugins/acl/user/static/CIZCbruUtoFZe1xIHUWcS2HwnEh.png new file mode 100755 index 000000000..dab9413b2 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/CIZCbruUtoFZe1xIHUWcS2HwnEh.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/DAICbLqwLo6nLzx9LcpcRFj5nAf.png b/docs/fr-FR/plugins/acl/user/static/DAICbLqwLo6nLzx9LcpcRFj5nAf.png new file mode 100755 index 000000000..afa7b374f Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/DAICbLqwLo6nLzx9LcpcRFj5nAf.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/DYmDbQ2AGoZzCGxgQrcccDgNnVg.gif b/docs/fr-FR/plugins/acl/user/static/DYmDbQ2AGoZzCGxgQrcccDgNnVg.gif new file mode 100755 index 000000000..8dac8e660 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/DYmDbQ2AGoZzCGxgQrcccDgNnVg.gif differ diff --git a/docs/fr-FR/plugins/acl/user/static/E5P7bepyPobSYhxIFH3c1T1onRg.png b/docs/fr-FR/plugins/acl/user/static/E5P7bepyPobSYhxIFH3c1T1onRg.png new file mode 100755 index 000000000..f06b7366d Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/E5P7bepyPobSYhxIFH3c1T1onRg.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/EB0gbEm3bo7zXfxzcxocAh1snth.gif b/docs/fr-FR/plugins/acl/user/static/EB0gbEm3bo7zXfxzcxocAh1snth.gif new file mode 100755 index 000000000..b07b60867 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/EB0gbEm3bo7zXfxzcxocAh1snth.gif differ diff --git a/docs/fr-FR/plugins/acl/user/static/EIvgbZPupooY9IxeH5Gc0Vxan0g.png b/docs/fr-FR/plugins/acl/user/static/EIvgbZPupooY9IxeH5Gc0Vxan0g.png new file mode 100755 index 000000000..145e06603 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/EIvgbZPupooY9IxeH5Gc0Vxan0g.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/EiCSbyvcToilFqxngPlcabEnnog.gif b/docs/fr-FR/plugins/acl/user/static/EiCSbyvcToilFqxngPlcabEnnog.gif new file mode 100755 index 000000000..b396b58eb Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/EiCSbyvcToilFqxngPlcabEnnog.gif differ diff --git a/docs/fr-FR/plugins/acl/user/static/FoykbYbvNorP1axz1DKcdQ66nrh.png b/docs/fr-FR/plugins/acl/user/static/FoykbYbvNorP1axz1DKcdQ66nrh.png new file mode 100755 index 000000000..ace81a4ad Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/FoykbYbvNorP1axz1DKcdQ66nrh.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/FpqdbZ04noXYClxvvPBcYsPFnNf.png b/docs/fr-FR/plugins/acl/user/static/FpqdbZ04noXYClxvvPBcYsPFnNf.png new file mode 100755 index 000000000..16bfebd24 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/FpqdbZ04noXYClxvvPBcYsPFnNf.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/FshmbDt5connlpxtExrc73orn1b.png b/docs/fr-FR/plugins/acl/user/static/FshmbDt5connlpxtExrc73orn1b.png new file mode 100755 index 000000000..1d2f3dafb Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/FshmbDt5connlpxtExrc73orn1b.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/GR9jb8gPso3LRjxFIb9cndOBnub.gif b/docs/fr-FR/plugins/acl/user/static/GR9jb8gPso3LRjxFIb9cndOBnub.gif new file mode 100755 index 000000000..92d4a71db Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/GR9jb8gPso3LRjxFIb9cndOBnub.gif differ diff --git a/docs/fr-FR/plugins/acl/user/static/GYWIbViYxo2peYxT0xMcyZO2n5c.png b/docs/fr-FR/plugins/acl/user/static/GYWIbViYxo2peYxT0xMcyZO2n5c.png new file mode 100755 index 000000000..89d8a8a82 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/GYWIbViYxo2peYxT0xMcyZO2n5c.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/I5uKbd4NXoUBL0x3jpIc6UXrnCb.png b/docs/fr-FR/plugins/acl/user/static/I5uKbd4NXoUBL0x3jpIc6UXrnCb.png new file mode 100755 index 000000000..7205e40ce Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/I5uKbd4NXoUBL0x3jpIc6UXrnCb.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/IHmhbshM8oDxxJx3VYyc6A7rn1c.png b/docs/fr-FR/plugins/acl/user/static/IHmhbshM8oDxxJx3VYyc6A7rn1c.png new file mode 100755 index 000000000..67163711d Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/IHmhbshM8oDxxJx3VYyc6A7rn1c.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/JVxSbTW1soiPz3xDqiPcTR4Znbe.png b/docs/fr-FR/plugins/acl/user/static/JVxSbTW1soiPz3xDqiPcTR4Znbe.png new file mode 100755 index 000000000..c45934d82 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/JVxSbTW1soiPz3xDqiPcTR4Znbe.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/KHgXbk4oRo7qWQxlP2pc5Otnnsd.gif b/docs/fr-FR/plugins/acl/user/static/KHgXbk4oRo7qWQxlP2pc5Otnnsd.gif new file mode 100755 index 000000000..39af67150 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/KHgXbk4oRo7qWQxlP2pc5Otnnsd.gif differ diff --git a/docs/fr-FR/plugins/acl/user/static/KNeebcJghocQbVxLltycetuMnTb.gif b/docs/fr-FR/plugins/acl/user/static/KNeebcJghocQbVxLltycetuMnTb.gif new file mode 100755 index 000000000..9dc5738d9 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/KNeebcJghocQbVxLltycetuMnTb.gif differ diff --git a/docs/fr-FR/plugins/acl/user/static/MolVbOe3GozpHYx3efAcg5ZLnzg.png b/docs/fr-FR/plugins/acl/user/static/MolVbOe3GozpHYx3efAcg5ZLnzg.png new file mode 100755 index 000000000..c92bf6db6 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/MolVbOe3GozpHYx3efAcg5ZLnzg.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/OtZab2PZEomdf5xvZIhcosLAnGc.gif b/docs/fr-FR/plugins/acl/user/static/OtZab2PZEomdf5xvZIhcosLAnGc.gif new file mode 100755 index 000000000..e52399755 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/OtZab2PZEomdf5xvZIhcosLAnGc.gif differ diff --git a/docs/fr-FR/plugins/acl/user/static/PFYqbxqCvoAxVUx29UYctS8KnRf.png b/docs/fr-FR/plugins/acl/user/static/PFYqbxqCvoAxVUx29UYctS8KnRf.png new file mode 100755 index 000000000..dbf809de4 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/PFYqbxqCvoAxVUx29UYctS8KnRf.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/ROF6b4SkboxFezxftsjczo9GnOb.png b/docs/fr-FR/plugins/acl/user/static/ROF6b4SkboxFezxftsjczo9GnOb.png new file mode 100755 index 000000000..6493eec90 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/ROF6b4SkboxFezxftsjczo9GnOb.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/RXwSbzriCorfatxFtbXceEYynrL.png b/docs/fr-FR/plugins/acl/user/static/RXwSbzriCorfatxFtbXceEYynrL.png new file mode 100755 index 000000000..c7ee54d5f Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/RXwSbzriCorfatxFtbXceEYynrL.png differ diff --git a/docs/fr-FR/plugins/acl/user/static/RgAIbdr1QofBorxbiYjcG7lun3e.gif b/docs/fr-FR/plugins/acl/user/static/RgAIbdr1QofBorxbiYjcG7lun3e.gif new file mode 100644 index 000000000..35ef5e034 Binary files /dev/null and b/docs/fr-FR/plugins/acl/user/static/RgAIbdr1QofBorxbiYjcG7lun3e.gif differ diff --git a/docs/fr-FR/welcome/changelog/0-template.md b/docs/fr-FR/welcome/changelog/0-template.md new file mode 100644 index 000000000..1687ccb59 --- /dev/null +++ b/docs/fr-FR/welcome/changelog/0-template.md @@ -0,0 +1,84 @@ +# <版本号>:<日期> + +版本号: + +- Release Version:x.y.z +- Pre-release Version:1.x.y-alpha.z + +相关说明: + +- 兼容性变更:x + 1 +- 新插件、新功能发布:y + 1 +- 缺陷修复:z + 1 +- alpha -> beta -> rc + +更新日志每周一篇,文件名格式: + +```bash +- docs/zh-CN/welcome/changelog/.md +- docs/eh-US/welcome/changelog/.md +``` + +标题格式为: + +```md +# <版本号>:<日期> + +# v1.0.0-alpha.15:2024-05-19 +``` + +分为新增、改进、修复三块内容,内容格式: + +```md +## (<a href="pr-url" target="_blank">#<pr-number></a>) +<!-- title 必填,scope 没有可以不写,pr 没有也可以不写 --> + +<description> <!-- 没有描述可以不写 --> + +![](<img-url>) <!-- 截图必须有,尺寸为 1440x900 --> +``` + +## 新增 - Added + +### 新增功能 XXX ([#4260](https://github.com/nocobase/nocobase/pull/4260)) + +一句话概括,然后后面放一张截图、动图或视频说明,在这里内容不要写太多了,更多内容应该放到使用手册里介绍。 + +![](https://static-docs.nocobase.com/202405191513995.png) + +### 插件:LDAP 认证 ([#4260](https://github.com/nocobase/nocobase/pull/4260)) + +支持用户使用 LDAP 服务器账号密码登录 NocoBase,详情参考 [认证:LDAP](/handbook/auth-ldap) 文档。 + +![](https://static-docs.nocobase.com/202405191513995.png) + +## 改进 - Improved + +### 改进或优化了某个功能 ([#4260](https://github.com/nocobase/nocobase/pull/4260)) + +一句话概括,然后后面放一张截图、动图或视频说明,在这里内容不要写太多了,如果内容较多可以概括性总结,例如: + +- 事项1 +- 事项2 + +![](https://static-docs.nocobase.com/202405191513995.png) + +### 改进「配置操作」交互 ([#4260](https://github.com/nocobase/nocobase/pull/4260)) + +下拉菜单里所有操作统一显示在一个列表中,不再区分“启用操作”和“自定义”。 + +- 只能添加一次的操作:这些操作保留 Switch 效果,用户只能启用或禁用。 +- 可以重复添加的操作:这些操作不再使用 Switch 交互,可以多次添加。 +- 合并功能相似的操作 + - “Add new” 和 “Add record” + - “Submit” 和 “Save record” + +![20240520153033](https://static-docs.nocobase.com/20240520153033.png) + +## 修复 - Fixed + +### 修复某个缺陷 XXX ([#4260](https://github.com/nocobase/nocobase/pull/4260)) + +一句话概括,然后后面放一张截图、动图或视频说明。 + +![](https://static-docs.nocobase.com/202405191513995.png) diff --git a/docs/fr-FR/welcome/changelog/20240519.md b/docs/fr-FR/welcome/changelog/20240519.md new file mode 100644 index 000000000..d34ccaace --- /dev/null +++ b/docs/fr-FR/welcome/changelog/20240519.md @@ -0,0 +1,100 @@ +# v1.0.0-alpha.15: 2024-05-19 + +## New features + +### Auth plugin: LDAP authentication + +Supports users logging in to NocoBase using their LDAP server credentials. For more information, refer to the [Authentication: LDAP](/handbook/auth-ldap) documentation. + +![](https://static-docs.nocobase.com/202405191513995.png) + +### Workflow plugin: custom action trigger + +When CRUD actions cannot satisfy your needs, you can use the custom action trigger of the workflow to orchestrate your own data processing logic. For more information, refer to the [Workflow / Custom action trigger](/handbook/workflow-custom-action-trigger) documentation. + +![](https://static-docs.nocobase.com/202405191515770.png) + +### Table block supports fixed columns + +![](https://static-docs.nocobase.com/202405191512587.png) + +### Supports adding Gantt and Kanban in pop-up windows + +![](https://static-docs.nocobase.com/202405191512280.png) + +### The details block supports linkage rules + +Allows configuring the visible and hidden properties of fields. + +![](https://static-docs.nocobase.com/202405191513781.png) + +### Workflow HTTP request node supports `application/www-x-form-urlencoded` format data + +![](https://static-docs.nocobase.com/202405191514472.png) + +### Workflow HTTP request node input boxes supports string templates + +![](https://static-docs.nocobase.com/202405191514748.png) + +### Plugin samples for development + +View the documentation for [plugin examples](/plugin-samples). + +![20240521105056](https://static-docs.nocobase.com/20240521105056.png) + +## Improvements + +### Improved "Configure actions" interaction + +All actions are displayed in a single list in the dropdown menu, no longer distinguishing between "Enable actions" and "Customize". + +- Actions that can only be added once: These actions retain the switch effect. +- Actions that can be added repeatedly: These actions no longer use the switch interaction and can be added multiple times. +- Merged similar actions + - “Add new” and “Add record” + - “Submit” and “Save record” + +![20240520153033](https://static-docs.nocobase.com/20240520153033.png) + +### Unified data format for workflow HTTP request node result: + +```js +{ + config: {}, + headers: {}, + status: 500, + statusText: 'xxx', + data: {} +} +``` + +### Reorganize workflow handbook + +![20240521104934](https://static-docs.nocobase.com/20240521104934.png) + +## Fixes + +### Log plugin now only shows logs of the current application + +When there are multiple applications: + +- The log plugin only displays the log file list for the current application. +- Workflow and custom request folders are placed within the application folder. + +![20240520152448](https://static-docs.nocobase.com/20240520152448.png) + +Other major fixes include: + +- Charts did not convert date fields to client time zone when querying aggregated data by date field. <a href="https://github.com/nocobase/nocobase/pull/4366" target="_blank">fix(data-vi): should use local timezone when formatting date #4366</a> +- View refresh issue, where the view needed to be exited and re-entered after syncing with the database. <a href="https://github.com/nocobase/nocobase/pull/4224" target="_blank">fix: collection fields should be refreshed after editing sync from database #4224</a> +- Tree table block did not collapse all nodes when adding a child node. <a href="https://github.com/nocobase/nocobase/pull/4289" target="_blank">fix: do not collapse all nodes when adding a child node in the tree table block #4289</a> +- Data table title field settings were invalid. <a href="https://github.com/nocobase/nocobase/pull/4358" target="_blank">fix: collection title field setting is invalid #4358</a> +- Bigint field lost precision in read-only mode. <a href="https://github.com/nocobase/nocobase/pull/4360" target="_blank">fix: bigint field loses precision in read pretty mode #4360</a> +- Open log files were not closed after stopping a sub-application. <a href="https://github.com/nocobase/nocobase/pull/4380" target="_blank">fix(logger): should close log stream after destroying app #4380</a> +- Workflow aggregate node relationship data model selection bug. <a href="https://github.com/nocobase/nocobase/pull/4315" target="_blank">fix(plugin-workflow-aggregate): fix association field select #4315</a> +- Ignoring errors option was ineffective in synchronous mode for workflow HTTP request node. <a href="https://github.com/nocobase/nocobase/pull/4334" target="_blank">fix(plugin-workflow-request): fix ignoreFail in sync mode #4334</a> +- Workflow HTTP request node value input box overflowed. <a href="https://github.com/nocobase/nocobase/pull/4353" target="_blank">fix(plugin-workflow-request): fix value fields overflowing #4354</a> +- Special characters caused workflow HTTP request node to hang. <a href="https://github.com/nocobase/nocobase/pull/4376" target="_blank">fix(plugin-workflow-request): fix request hanging when invalid header value #4376</a> +- Fixed issue where setting marginBlock in the theme editor affected form field spacing. <a href="https://github.com/nocobase/nocobase/pull/4374" target="_blank">fix(theme-editor): form field spacing should not be affected by token.marginBlock #4374</a> +- Fixed issue where clicking the "License" option in the top right corner of the page redirected incorrectly. [PR #4415](https://github.com/nocobase/nocobase/pull/4415) +- Fixed issue where the field operator was invalid when saving a filter form as a block template. [PR #4390](https://github.com/nocobase/nocobase/pull/4390) diff --git a/docs/fr-FR/welcome/changelog/20240607.md b/docs/fr-FR/welcome/changelog/20240607.md new file mode 100644 index 000000000..f6bd14f6d --- /dev/null +++ b/docs/fr-FR/welcome/changelog/20240607.md @@ -0,0 +1,144 @@ +# v1.0.1-alpha.1: 2024-06-07 + +## New features + +### Blocks support height settings (<a href="https://github.com/nocobase/nocobase/pull/4441" target="_blank">#4441</a>) + +![20240603115253](https://static-docs.nocobase.com/20240603115253.gif) + +Reference document: + +- [set block height](/handbook/ui/blocks/block-settings/block-height) + +### Link action: navigate to the specified URL (<a href="https://github.com/nocobase/nocobase/pull/4506" target="_blank">#4506</a>) + +Support configuring variables in the URL or search params. + +<video width="100%" height="440" controls> + + <source src="https://static-docs.nocobase.com/20240603224044.mp4" type="video/mp4"> + +</video> + +Reference document: + +- [Link action](/handbook/ui/actions/types/link) + +### Add a new variable called "URL search params" (<a href="https://github.com/nocobase/nocobase/pull/4506" target="_blank">#4506</a>) + +The variable is only available when there is a query string in the page URL, making it more convenient to use in conjunction with [link action](/handbook/ui/actions/types/link). + +![20240603170651](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240603170651.png) + +Reference document: + +- [URL search params](/handbook/ui/variables#url-search-params) +- [Link action](/handbook/ui/actions/types/link) + +### Iframe support variables (<a href="https://github.com/nocobase/nocobase/pull/4512" target="_blank">#4512</a>) + +![20240603114711](https://static-docs.nocobase.com/20240603114711.png) + +![20240603114750](https://static-docs.nocobase.com/20240603114750.png) + +Reference document: + +- [iframe block](/handbook/block-iframe) + +### File storages support configuring file size and file type (<a href="https://github.com/nocobase/nocobase/pull/4118" target="_blank">#4118</a>) + +![20240603115303](https://static-docs.nocobase.com/20240603115303.png) + +Reference document: + +- [File Storage](/handbook/file-manager/storage) + +### Workflow: variable nodes support selecting partial path of data objects as the value of variables + +![20240531211727](https://static-docs.nocobase.com/20240531211727.png) + +### URL fields support preview (<a href="https://github.com/nocobase/nocobase/pull/4559" target="_blank">#4559</a>) + +Currently only support image preview. + +![337101796-916a6c97-bc08-4560-9526-53e482e2ac6c](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/337101796-916a6c97-bc08-4560-9526-53e482e2ac6c.gif) + +### Data visualization: Support for "URL query parameters" and "current role" variables (<a href="https://github.com/nocobase/nocobase/pull/4586" target="_blank">#4586</a>) + +![data-visualization-filter-block](https://static-docs.nocobase.com/202406071148997.png) + +![data-visualization-filter](https://static-docs.nocobase.com/202406071149567.png) + +## Improvements + +### Import and export function optimization (<a href="https://github.com/nocobase/nocobase/pull/4468" target="_blank">#4468</a>) + +Improved the stability of import and export function, increased the limit of import and export to 2000 records. Supports extended import and export logic of custom field types. + +![20240611112948](https://static-docs.nocobase.com/20240611112948.png) + +### Avoid misoperation by disabling the date variable option (<a href="https://github.com/nocobase/nocobase/pull/4452" target="_blank">#4452</a>) + +Except for the "current time", the variables representing dates are intervals (arrays) rather than moments (strings). They can be used for filtering, but cannot be directly used as default values. + +![20240527150429](https://static-docs.nocobase.com/20240527150429.png) + +### Linkage rule assignment interaction optimization (<a href="https://github.com/nocobase/nocobase/pull/4492" target="_blank">#4492</a>) + +Multi-select fields do not show assignment options. If a single-select field is selected and assigned, then switching to a multi-select field will clear the configuration + +![20240603143309](https://static-docs.nocobase.com/20240603143309.png) + +### Adjust the top-right icon of the action column in the table block (<a href="https://github.com/nocobase/nocobase/pull/4538" target="_blank">#4538</a>) + +![20240603115131](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240603115131.png) + +### ErrorFallback (<a href="https://github.com/nocobase/nocobase/pull/4459" target="_blank">#4459</a>) + +Refining error fallback for different components in the frontend to prevent the entrie page from becoming unusable due to a frontend error. + +![error-fallback](https://static-docs.nocobase.com/20240604122043_rec_.gif) + +### Collect debug information and quickly download logs when a frontend error occurs(<a href="https://github.com/nocobase/nocobase/pull/4524" target="_blank">#4524</a>) + +![error-fallback-log](https://static-docs.nocobase.com/202406041224009.png) + +### Others + +- Modify character length limit of username to 1-50 (<a href="https://github.com/nocobase/nocobase/pull/4502" target="_blank">#4502</a>) +- Do not hide foreign key fields(<a href="https://github.com/nocobase/nocobase/pull/4499" target="_blank">#4499</a>) + +## Bug fixes + +### The data scope in the permission configuration dialog should not support the "Current form" and "Current popup record" variables (<a href="https://github.com/nocobase/nocobase/pull/4484" target="_blank">#4484</a>) + +![20240527145519](https://static-docs.nocobase.com/20240527145519.png) + +### Support selecting the value of a variable directly as the default value for a association field (<a href="https://github.com/nocobase/nocobase/pull/4439" target="_blank">#4439</a>) + +![20240603121447](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240603121447.png) + +### Fix the issue of error when adding "Custom request" action multiple times (<a href="https://github.com/nocobase/nocobase/pull/4458" target="_blank">#4458</a>) + +![20240603115234](https://nocobase-docs.oss-cn-beijing.aliyuncs.com/20240603115234.png) + +### Others + +- Fix the issue of content in the sub-table not being cleared after form submission. (<a href="https://github.com/nocobase/nocobase/pull/4475" target="_blank">#4475</a>) +- Fix the issue of abnormal use of the "Current object" variable in the sub-table. (<a href="https://github.com/nocobase/nocobase/pull/4521" target="_blank">#4521</a>) +- add 'Set default zoom level' option for map fields. (<a href="https://github.com/nocobase/nocobase/pull/4527" target="_blank">#4527</a>) +- Fix the issue of block not being displayed when adding a block using block templates in a popup window. (<a href="https://github.com/nocobase/nocobase/pull/4531" target="_blank">#4531</a>) +- Fix the style issue of form data templates. (<a href="https://github.com/nocobase/nocobase/pull/4536" target="_blank">#4536</a>) +- Workflow: expression box style disappeared in calculation node. (<a href="https://github.com/nocobase/nocobase/pull/4513" target="_blank">#4513</a>) +- Workflow: field type incorrect when created in custom form of manual node. (<a href="https://github.com/nocobase/nocobase/pull/4519" target="_blank">#4519</a>) +- Workflow: permission issue of triggering custom action event. (<a href="https://github.com/nocobase/nocobase/pull/4522" target="_blank">#4522</a>) +- Workflow: incorrect depth configuration of preloading assoacition for multiple data source. (<a href="https://github.com/nocobase/nocobase/pull/4526" target="_blank">#4526</a>) +- `json-templates` library bug. (<a href="https://github.com/nocobase/nocobase/pull/4525" target="_blank">#4525</a>) +- File manager: error when uploading or deleting file on COS. (<a href="https://github.com/nocobase/nocobase/pull/4529" target="_blank">#4529</a>, <a href="https://github.com/nocobase/nocobase/pull/4537" target="_blank">#4537</a>) +- Form linkage rule displays [object Object] when assigning a value of 0.00 to a numeric field. (<a href="https://github.com/nocobase/nocobase/pull/4482" target="_blank">#4482</a>) +- Subtable is missing the control setting item for the add new button. (<a href="https://github.com/nocobase/nocobase/pull/4498" target="_blank">#4498</a>) +- Submit button in the table edit form is missing the linkage rule setting item. (<a href="https://github.com/nocobase/nocobase/pull/4515" target="_blank">#4515</a>) +- Data-visualization: fix the issue of field components invisible when setting default values for chart filter fields (<a href="https://github.com/nocobase/nocobase/pull/4509" target="_blank">#4509</a>) +- Authentication: fix the issue where the sign up page is not found for newly created basic authenticator. (<a href="https://github.com/nocobase/nocobase/pull/4556" target="_blank">#4556</a>) +- Localization: fix the issue where the page titles is not translated when translating the menu texts. (<a href="https://github.com/nocobase/nocobase/pull/4557" target="_blank">#4557</a>) +- Map: fix the issue where AMap shows a key error despite correct configuration. (<a href="https://github.com/nocobase/nocobase/pull/4574" target="_blank">#4574</a>) diff --git a/docs/fr-FR/welcome/community/contributing.md b/docs/fr-FR/welcome/community/contributing.md new file mode 100644 index 000000000..f83ef09f5 --- /dev/null +++ b/docs/fr-FR/welcome/community/contributing.md @@ -0,0 +1,51 @@ +# Contribuer + +- Forker le code source dans votre repository +- Modifier le code source +- Soummetre une pull request +- Signer la CLA + +## Télécharger + +```bash +# Remplacer l'adresse git suivante par votre repo +git clone https://github.com/nocobase/nocobase.git +cd nocobase +yarn install +``` + +## Développer et tester + +```bash +# Installer et démarrer l'application +yarn dev +# Lancer tous les tests +yarn test +# Lancer tous les fichiers test du dossier +yarn test <dir> +# Lancer un fichier test +yarn test <file> +``` + +## Aperçu de la documentation + +```bash +# Démarrer la documentation +yarn doc --lang=zh-CN +yarn doc --lang=en-US +``` + +La documentation se trouve dans le répertoire docs et suit la syntaxe Markdown + +```bash +|- /docs/ + |- en-US + |- fr-FR + |- zh-CN +``` + +## Autres + +Pour plus d'instructions CLI, veuillez vous reporter au chapitre [NocoBase CLI](https://docs.nocobase.com/api/cli). + + diff --git a/docs/fr-FR/welcome/community/faq.md b/docs/fr-FR/welcome/community/faq.md new file mode 100644 index 000000000..4514b4c10 --- /dev/null +++ b/docs/fr-FR/welcome/community/faq.md @@ -0,0 +1 @@ +# FAQ diff --git a/docs/fr-FR/welcome/community/thanks.md b/docs/fr-FR/welcome/community/thanks.md new file mode 100644 index 000000000..8e388c564 --- /dev/null +++ b/docs/fr-FR/welcome/community/thanks.md @@ -0,0 +1,12 @@ +# Remerciements + +NocoBase utilise des produits open source excellents et éprouvés, à qui nous exprimons notre sincère gratitude. + +- [Ant Design](https://ant.design/) +- [Dnd Kit](https://dndkit.com/) +- [Formily](https://github.com/alibaba/formily) +- [I18next](https://www.i18next.com/) +- [Koa](https://koajs.com/) +- [React](https://reactjs.org/) +- [Sequelize](https://sequelize.org/) +- [UmiJS](https://umijs.org/) diff --git a/docs/fr-FR/welcome/community/translations.md b/docs/fr-FR/welcome/community/translations.md new file mode 100644 index 000000000..5e5987d12 --- /dev/null +++ b/docs/fr-FR/welcome/community/translations.md @@ -0,0 +1,159 @@ +# Traductions + +Le langage par défaut de NocoBase est l'anglais. Actuellement l'anglais, le chinois simplifié, le japonnais, le russe et le turque sont supportés. Vous pouvez aider à traduire Nocobase dans votre langue. + +Les fichiers de langue NocoBase sont situés dans les emplacements suivants: + +```shell +packages/core/**/src/locale +packages/plugins/**/src/locale +``` + +La traduction du noyau NocoBase se trouve principalement ici: + +https://github.com/nocobase/nocobase/tree/main/packages/core/client/src/locale + +Veuillez copier le fichier en_US.ts, nommez-le avec le nom de la langue que vous souhaitez ajouter, puis traduisez les chaînes qu'il contient. Une fois la traduction terminée, veuillez la soumettre à NocoBase via pull request et nous l'ajouterons à la liste des langues. Ensuite, vous verrez les nouvelles langues dans la configuration du système, où vous pourrez configurer les langues que vous souhaitez afficher pour que les utilisateurs puissent choisir. + +<img src="./translations/enabled-languages.jpg" style="max-width: 800px;"/> + +Le tableau suivant répertorie le nom de la culture linguistique, le nom du fichier de paramètres régionaux et le nom d'affichage. + +| Nom de la langue | Nom du fichier | Nom d'affichage | +| :-------------------- | :--------------- | :---------------------------- | +| af-ZA | af_ZA.ts | Afrikaans - South Africa | +| sq-AL | sq_AL.ts | Albanian - Albania | +| ar-DZ | ar_DZ.ts | Arabic - Algeria | +| ar-BH | ar_BH.ts | Arabic - Bahrain | +| ar-EG | ar_EG.ts | Arabic - Egypt | +| ar-IQ | ar_IQ.ts | Arabic - Iraq | +| ar-JO | ar_JO.ts | Arabic - Jordan | +| ar-KW | ar_KW.ts | Arabic - Kuwait | +| ar-LB | ar_LB.ts | Arabic - Lebanon | +| ar-LY | ar_LY.ts | Arabic - Libya | +| ar-MA | ar_MA.ts | Arabic - Morocco | +| ar-OM | ar_OM.ts | Arabic - Oman | +| ar-QA | ar_QA.ts | Arabic - Qatar | +| ar-SA | ar_SA.ts | Arabic - Saudi Arabia | +| ar-SY | ar_SY.ts | Arabic - Syria | +| ar-TN | ar_TN.ts | Arabic - Tunisia | +| ar-AE | ar_AE.ts | Arabic - United Arab Emirates | +| ar-YE | ar_YE.ts | Arabic - Yemen | +| hy-AM | hy_AM.ts | Armenian - Armenia | +| Cy-az-AZ | Cy_az_AZ.ts | Azeri (Cyrillic) - Azerbaijan | +| Lt-az-AZ | Lt_az_AZ.ts | Azeri (Latin) - Azerbaijan | +| eu-ES | eu_ES.ts | Basque - Basque | +| be-BY | be_BY.ts | Belarusian - Belarus | +| bg-BG | bg_BG.ts | Bulgarian - Bulgaria | +| ca-ES | ca_ES.ts | Catalan - Catalan | +| zh-CN | zh_CN.ts | Chinese - China | +| zh-HK | zh_HK.ts | Chinese - Hong Kong SAR | +| zh-MO | zh_MO.ts | Chinese - Macau SAR | +| zh-SG | zh_SG.ts | Chinese - Singapore | +| zh-TW | zh_TW.ts | Chinese - Taiwan | +| zh-CHS | zh_CHS.ts | Chinese (Simplified) | +| zh-CHT | zh_CHT.ts | Chinese (Traditional) | +| hr-HR | hr_HR.ts | Croatian - Croatia | +| cs-CZ | cs_CZ.ts | Czech - Czech Republic | +| da-DK | da_DK.ts | Danish - Denmark | +| div-MV | div_MV.ts | Dhivehi - Maldives | +| nl-BE | nl_BE.ts | Dutch - Belgium | +| nl-NL | nl_NL.ts | Dutch - The Netherlands | +| en-AU | en_AU.ts | English - Australia | +| en-BZ | en_BZ.ts | English - Belize | +| en-CA | en_CA.ts | English - Canada | +| en-CB | en_CB.ts | English - Caribbean | +| en-IE | en_IE.ts | English - Ireland | +| en-JM | en_JM.ts | English - Jamaica | +| en-NZ | en_NZ.ts | English - New Zealand | +| en-PH | en_PH.ts | English - Philippines | +| en-ZA | en_ZA.ts | English - South Africa | +| en-TT | en_TT.ts | English - Trinidad and Tobago | +| en-GB | en_GB.ts | English - United Kingdom | +| en-US | en_US.ts | English - United States | +| en-ZW | en_ZW.ts | English - Zimbabwe | +| et-EE | et_EE.ts | Estonian - Estonia | +| fo-FO | fo_FO.ts | Faroese - Faroe Islands | +| fa-IR | fa_IR.ts | Farsi - Iran | +| fi-FI | fi_FI.ts | Finnish - Finland | +| fr-BE | fr_BE.ts | French - Belgium | +| fr-CA | fr_CA.ts | French - Canada | +| fr-FR | fr_FR.ts | French - France | +| fr-LU | fr_LU.ts | French - Luxembourg | +| fr-MC | fr_MC.ts | French - Monaco | +| fr-CH | fr_CH.ts | French - Switzerland | +| gl-ES | gl_ES.ts | Galician - Galician | +| ka-GE | ka_GE.ts | Georgian - Georgia | +| de-AT | de_AT.ts | German - Austria | +| de-DE | de_DE.ts | German - Germany | +| de-LI | de_LI.ts | German - Liechtenstein | +| de-LU | de_LU.ts | German - Luxembourg | +| de-CH | de_CH.ts | German - Switzerland | +| el-GR | el_GR.ts | Greek - Greece | +| gu-IN | gu_IN.ts | Gujarati - India | +| he-IL | he_IL.ts | Hebrew - Israel | +| hi-IN | hi_IN.ts | Hindi - India | +| hu-HU | hu_HU.ts | Hungarian - Hungary | +| is-IS | is_IS.ts | Icelandic - Iceland | +| id-ID | id_ID.ts | Indonesian - Indonesia | +| it-IT | it_IT.ts | Italian - Italy | +| it-CH | it_CH.ts | Italian - Switzerland | +| ja-JP | ja_JP.ts | Japanese - Japan | +| kn-IN | kn_IN.ts | Kannada - India | +| kk-KZ | kk_KZ.ts | Kazakh - Kazakhstan | +| kok-IN | kok_IN.ts | Konkani - India | +| ko-KR | ko_KR.ts | Korean - Korea | +| ky-KZ | ky_KZ.ts | Kyrgyz - Kazakhstan | +| lv-LV | lv_LV.ts | Latvian - Latvia | +| lt-LT | lt_LT.ts | Lithuanian - Lithuania | +| mk-MK | mk_MK.ts | Macedonian (FYROM) | +| ms-BN | ms_BN.ts | Malay - Brunei | +| ms-MY | ms_MY.ts | Malay - Malaysia | +| mr-IN | mr_IN.ts | Marathi - India | +| mn-MN | mn_MN.ts | Mongolian - Mongolia | +| nb-NO | nb_NO.ts | Norwegian (BokmÃ¥l) - Norway | +| nn-NO | nn_NO.ts | Norwegian (Nynorsk) - Norway | +| pl-PL | pl_PL.ts | Polish - Poland | +| pt-BR | pt_BR.ts | Portuguese - Brazil | +| pt-PT | pt_PT.ts | Portuguese - Portugal | +| pa-IN | pa_IN.ts | Punjabi - India | +| ro-RO | ro_RO.ts | Romanian - Romania | +| ru-RU | ru_RU.ts | Russian - Russia | +| sa-IN | sa_IN.ts | Sanskrit - India | +| Cy-sr-SP | Cy_sr_SP.ts | Serbian (Cyrillic) - Serbia | +| Lt-sr-SP | Lt_sr_SP.ts | Serbian (Latin) - Serbia | +| sk-SK | sk_SK.ts | Slovak - Slovakia | +| sl-SI | sl_SI.ts | Slovenian - Slovenia | +| es-AR | es_AR.ts | Spanish - Argentina | +| es-BO | es_BO.ts | Spanish - Bolivia | +| es-CL | es_CL.ts | Spanish - Chile | +| es-CO | es_CO.ts | Spanish - Colombia | +| es-CR | es_CR.ts | Spanish - Costa Rica | +| es-DO | es_DO.ts | Spanish - Dominican Republic | +| es-EC | es_EC.ts | Spanish - Ecuador | +| es-SV | es_SV.ts | Spanish - El Salvador | +| es-GT | es_GT.ts | Spanish - Guatemala | +| es-HN | es_HN.ts | Spanish - Honduras | +| es-MX | es_MX.ts | Spanish - Mexico | +| es-NI | es_NI.ts | Spanish - Nicaragua | +| es-PA | es_PA.ts | Spanish - Panama | +| es-PY | es_PY.ts | Spanish - Paraguay | +| es-PE | es_PE.ts | Spanish - Peru | +| es-PR | es_PR.ts | Spanish - Puerto Rico | +| es-ES | es_ES.ts | Spanish - Spain | +| es-UY | es_UY.ts | Spanish - Uruguay | +| es-VE | es_VE.ts | Spanish - Venezuela | +| sw-KE | sw_KE.ts | Swahili - Kenya | +| sv-FI | sv_FI.ts | Swedish - Finland | +| sv-SE | sv_SE.ts | Swedish - Sweden | +| syr-SY | syr_SY.ts | Syriac - Syria | +| ta-IN | ta_IN.ts | Tamil - India | +| tt-RU | tt_RU.ts | Tatar - Russia | +| te-IN | te_IN.ts | Telugu - India | +| th-TH | th_TH.ts | Thai - Thailand | +| tr-TR | tr_TR.ts | Turkish - Turkey | +| uk-UA | uk_UA.ts | Ukrainian - Ukraine | +| ur-PK | ur_PK.ts | Urdu - Pakistan | +| Cy-uz-UZ | Cy_uz_UZ.ts | Uzbek (Cyrillic) - Uzbekistan | +| Lt-uz-UZ | Lt_uz_UZ.ts | Uzbek (Latin) - Uzbekistan | +| vi-VN | vi_VN.ts | Vietnamese - Vietnam | diff --git a/docs/fr-FR/welcome/community/translations/enabled-languages.jpg b/docs/fr-FR/welcome/community/translations/enabled-languages.jpg new file mode 100644 index 000000000..fcf326305 Binary files /dev/null and b/docs/fr-FR/welcome/community/translations/enabled-languages.jpg differ diff --git a/docs/fr-FR/welcome/community/translations/language-settings-1.jpg b/docs/fr-FR/welcome/community/translations/language-settings-1.jpg new file mode 100644 index 000000000..eb352a0f8 Binary files /dev/null and b/docs/fr-FR/welcome/community/translations/language-settings-1.jpg differ diff --git a/docs/fr-FR/welcome/community/translations/language-settings-2.jpg b/docs/fr-FR/welcome/community/translations/language-settings-2.jpg new file mode 100644 index 000000000..3e9f7b08e Binary files /dev/null and b/docs/fr-FR/welcome/community/translations/language-settings-2.jpg differ diff --git a/docs/fr-FR/welcome/getting-started/deployment/create-nocobase-app.md b/docs/fr-FR/welcome/getting-started/deployment/create-nocobase-app.md new file mode 100644 index 000000000..c34c65165 --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/deployment/create-nocobase-app.md @@ -0,0 +1,59 @@ +# create-nocobase-app + +Les autres processus ne sont pas différents de [create-nocobase-app](/welcome/getting-started/installation/create-nocobase-app). + +<embed src="./env-note.md"></embed> +- Lors d'un déploiement dans un environnement de production, pour réduire le volume, vous pouvez installer uniquement les dépendances nécessaires avec `yarn install --production` + +<br /> + +[>>> Pour plus d'informations, consultez les « Variables d'environnement » complètes. <<<](/welcome/getting-started/env) + +## Gérer les processus d'application + +NocoBase a déjà intégré [PM2](https://pm2.keymetrics.io/) pour gérer les processus. Dans un environnement de production, vous pouvez directement utiliser `yarn start`. Si vous avez besoin qu'il s'exécute en arrière-plan, ajoutez simplement le paramètre `-d`, par exemple : + +```bash +# Exécuter en arrière-plan +yarn start -d +``` + +Redémarrer + +```bash +yarn nocobase pm2-restart +``` + +Arrêter + +```bash +yarn nocobase pm2-stop +``` + +Plus de commandes PM2 + +```bash +yarn nocobase pm2 -h +``` + +## Configurer Nginx + +Dans un environnement de production, vous pouvez envisager de demander à Nginx de "proxifier" les fichiers statiques. NocoBase fournit la commande `create-nginx-conf` pour générer les fichiers de configuration Nginx. + +```bash +yarn nocobase create-nginx-conf +``` + +Le chemin du fichier est `./storage/nocobase.conf`. Ajustez-le en fonction de la situation réelle, et enfin ajoutez-le à `/etc/nginx/sites-enabled`, par exemple : + +```bash +ln -s /app/nocobase/storage/nocobase.conf /etc/nginx/sites-enabled/nocobase.conf +``` + +**Remarques** + +- Lors du déploiement dans un sous-chemin, vous devez configurer la variable d'environnement `APP_PUBLIC_PATH`. Après la configuration, vous devez réexécuter la commande `create-nginx-conf` ; +- Modifier le fichier généré `nocobase.conf` en fonction de la situation réelle, comme la configuration du nom de domaine, etc. ; +- `/app/nocobase/` est le répertoire où se trouve l'exemple d'application, et il doit être ajusté en fonction de la situation réelle ; +- `/etc/nginx/sites-enabled` est le chemin de configuration par défaut de Nginx, la situation réelle peut varier, vous pouvez le vérifier avec `nginx -V` ; +- Si vous n'utilisez pas Nginx, vous pouvez effectuer quelques ajustements en vous référant à la configuration de Nginx. diff --git a/docs/fr-FR/welcome/getting-started/deployment/docker-compose.md b/docs/fr-FR/welcome/getting-started/deployment/docker-compose.md new file mode 100644 index 000000000..1d3d10ee6 --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/deployment/docker-compose.md @@ -0,0 +1,60 @@ +# Docker + +Les autres processus ne sont pas différents de l'installation[Docker](/welcome/getting-started/installation/docker-compose). + +<embed src="./env-note.md"></embed> + +<br /> + +[>>> Pour plus d'informations, consultez les « Variables d'environnement » complètes. <<<](/welcome/getting-started/env) + +## Domaine Binding + +En prenant nginx comme exemple, proxy via nginx http://127.0.0.1:13000/ + +```bash +server { + listen 80; + server_name votre_domaine.com; # Remplacer votre_domaine.com avec votre domaine + + location / { + proxy_pass http://127.0.0.1:13000/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_buffering off; + } +} +``` + +## Déployer dans un sous-chemin + +Pour déployer dans un sous-chemin, vous devez configurer la variable d'environnement `APP_PUBLIC_PATH`: + +```diff +services: + app: + image: nocobase/nocobase:latest + environment: ++ - APP_PUBLIC_PATH=/nocobase/ +``` + +L'URL de l'application est http://127.0.0.1:13000/nocobase/ et la configuration Nginx est: + +```bash +server { + listen 80; + server_name votre_domaine.com; # Remplacer votre_domaine.com avec votre domaine + + location /nocobase/ { + proxy_pass http://127.0.0.1:13000/nocobase/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + } +} +``` + +Enfin, vous pouvez y accéder via http://votre_domaine.com/nocobase/ diff --git a/docs/fr-FR/welcome/getting-started/deployment/env-note.md b/docs/fr-FR/welcome/getting-started/deployment/env-note.md new file mode 100644 index 000000000..b1d0934ad --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/deployment/env-note.md @@ -0,0 +1,7 @@ +**Points à noter :** + +- `TZ` est utilisé pour définir le fuseau horaire de l'application, la valeur par défaut étant le fuseau horaire du système ; +- `APP_KEY` est la clé secrète de l'application, utilisée pour générer des jetons utilisateur, etc. (si APP_KEY est modifié, les anciens jetons deviendront également invalides). Il peut s'agir de n'importe quelle chaîne aléatoire. Veuillez la remplacer par votre propre clé secrète et assurez-vous qu'elle ne soit pas divulguée au public. +- `DB_*` est lié à la base de données. S'il ne s'agit pas du service de base de données par défaut dans l'exemple, veuillez le modifier en fonction de la situation réelle ; +- Lors d'un déploiement dans un environnement de production, `APP_ENV=production` ; +- Lors du déploiement dans un sous-chemin, vous devez configurer `APP_PUBLIC_PATH`, tel que `APP_PUBLIC_PATH=/nocobase/`. diff --git a/docs/fr-FR/welcome/getting-started/deployment/git-clone.md b/docs/fr-FR/welcome/getting-started/deployment/git-clone.md new file mode 100644 index 000000000..7f8e7792b --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/deployment/git-clone.md @@ -0,0 +1,5 @@ +# Code source Git + +Les autres processus ne sont pas différents du [Code source Git](/welcome/getting-started/installation/git-clone). + +<embed src="./create-nocobase-app.md#L4-L1000"></embed> diff --git a/docs/fr-FR/welcome/getting-started/deployment/index.md b/docs/fr-FR/welcome/getting-started/deployment/index.md new file mode 100644 index 000000000..12bc34abc --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/deployment/index.md @@ -0,0 +1,7 @@ +# Vue d'ensemble + +NocoBase prend en charge trois méthodes d'installation différentes, chacune avec des procédures de déploiement légèrement différentes. + +- [Docker](./docker-compose.md) +- [create-nocobase-app](./create-nocobase-app.md) +- [Code source Git](./git-clone.md) diff --git a/docs/fr-FR/welcome/getting-started/env.md b/docs/fr-FR/welcome/getting-started/env.md new file mode 100644 index 000000000..5c99b9f36 --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/env.md @@ -0,0 +1,440 @@ +# Variables d'environnement + +## Comment définir les variables d'environnement? + +### Méthode d'installation `Code source Git` ou `create-nocobase-app` + +Définissez les variables d'environnement dans le fichier `.env` dans le répertoire racine du projet. Après avoir modifié les variables d'environnement, arrêtez le processus d'application et redémarrez-le. + +### Méthode d'installation `Docker` + +Modifiez la configuration `docker-compose.yml` et définissez les variables d'environnement dans le paramètre `environment`. Exemple: + +```yml +services: + app: + image: nocobase/nocobase:latest + environment: + - APP_ENV=production +``` + +Vous pouvez également utiliser `env_file` pour définir les variables d'environnement dans le fichier `.env`. Exemple: + +```yml +services: + app: + image: nocobase/nocobase:latest + env_file: .env +``` + +Après avoir modifié les variables d'environnement, reconstruisez le conteneur d'application : + +```yml +docker-compose up -d app +``` + +## Variables d'environnement globales + +Enregistré dans le fichier `.env` + +### TZ + +Utilisé pour définir le fuseau horaire de l'application, la valeur par défaut étant le fuseau horaire du système. + +https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +:::warning +Les opérations liées au temps seront traitées en fonction de ce fuseau horaire. La modification de TZ peut affecter les valeurs de date dans la base de données. Pour plus de détails, reportez-vous à [Aperçu de la date et de l'heure](/handbook/data-modeling/collection-fields/datetime). +::: + +### APP_ENV + +Environnement d'application, la valeur par défaut est « développement », les options incluent + +- `production` environnement de production +- `development` environnement de développement + +```bash +APP_ENV=production +``` + +### APP_KEY + +Clé secrète, pour des scénarios tels que jwt + +```bash +APP_KEY=app-key-test +``` + +### APP_PORT + +Port d'application, la valeur par défaut est `13000` + +```bash +APP_PORT=13000 +``` + +### API_BASE_PATH + +Préfixe d'adresse API NocoBase, la valeur par défaut est `/api/` + +```bash +API_BASE_PATH=/api/ +``` + +<!-- will be open in 1.5 +### CLUSTER_MODE + +The multi-core (cluster) mode for starting app. If this variable is configured, will be passed to the pm2 start command as the `-i <instances>` parameter. The options are consistent with the pm2 `-i` parameter (refer to [PM2: Cluster Mode](https://pm2.keymetrics.io/docs/usage/cluster-mode/)), including: + +- `max`: Use the maximum number of CPU cores +- `-1`: Use the maximum number of CPU cores minus one +- `<number>`: Specify the number of cores + +The default value is empty, meaning it is not enabled. + +:::warning{title="Attention"} +This mode requires the use of plugins related to cluster mode, such as `@nocobase/plugin-sync-adapter-redis`. Otherwise, the functionality of applicaiton may encounter unexpected issues. +::: +--> + +### PLUGIN_PACKAGE_PREFIX + +Préfixe du package de plugin, la valeur par défaut est `@nocobase/plugin-,@nocobase/preset-` + +Par exemple, ajoutez le plugin `hello` dans le projet `my-nocobase-app`, le nom du package du plugin est `@my-nocobase-app/plugin-hello`. + +PLUGIN_PACKAGE_PREFIX est configuré comme suit : + +```bash +PLUGIN_PACKAGE_PREFIX=@nocobase/plugin-,@nocobase-preset-,@my-nocobase-app/plugin- +``` + +La correspondance entre le nom du plugin et le nom du package est : + +- Le nom du package du plugin `users` est `@nocobase/plugin-users` +- Le nom du package du plugin`nocobase` est `@nocobase/preset-nocobase` +- Le nom du package du plugin`hello` est `@my-nocobase-app/plugin-hello` + +### DB_DIALECT + +Type de base de données, la valeur par défaut est `sqlite`, les options incluent + +- `sqlite` +- `mysql` +- `postgres` + +```bash +DB_DIALECT=mysql +``` + +### DB_STORAGE + +Chemin du fichier de base de données (obligatoire lors de l'utilisation d'une base de données SQLite) + +```bash +### Chemin relatif +DB_STORAGE=storage/db/nocobase.db +# Chemin absolu +DB_STORAGE=/your/path/nocobase.db +``` + +### DB_HOST + +Hôte de base de données (obligatoire lors de l'utilisation de bases de données MySQL ou PostgreSQL) + +La valeur par défaut est `localhost` + +```bash +DB_HOST=localhost +``` + +### DB_PORT + +Port de base de données (obligatoire lors de l'utilisation de bases de données MySQL ou PostgreSQL) + +- Le port par défaut de MySQL est 3306 +- Le port par défaut de PostgreSQL est 5432 + +```bash +DB_PORT=3306 +``` + +### DB_DATABASE + +Nom de la base de données (obligatoire lors de l'utilisation de bases de données MySQL ou PostgreSQL) + +```bash +DB_DATABASE=nocobase +``` + +### DB_USER + +Utilisateur de la base de données (obligatoire lors de l'utilisation de bases de données MySQL ou PostgreSQL) + +```bash +DB_USER=nocobase +``` + +### DB_PASSWORD + +Mot de passe de la base de données (obligatoire lors de l'utilisation de bases de données MySQL ou PostgreSQL) + +```bash +DB_PASSWORD=nocobase +``` + +### DB_TABLE_PREFIX + +Préfixe des tables de la base de données + +```bash +DB_TABLE_PREFIX=nocobase_ +``` + +### DB_LOGGING + +Commutateur de journal de base de données, la valeur par défaut est `off`, les options incluent + +- `on` activer +- `off` désactiver + +```bash +DB_LOGGING=on +``` + +### NOCOBASE_PKG_USERNAME + +Nom d'utilisateur de la plateforme de services, utilisé pour télécharger et mettre à jour automatiquement les plugins. + +### NOCOBASE_PKG_PASSWORD + +Mot de passe de la plateforme de service, utilisé pour télécharger et mettre à jour automatiquement les plugins. + +### LOGGER_TRANSPORT + +Mode de sortie du journal, séparez plusieurs entrées par `,`. La valeur par défaut pour l'environnement de développement est `console` et la valeur par défaut pour l'environnement de production est `console,dailyRotateFile`. +Possibilités : + +- `console` - `console.log` +- `file` - `Fichier` +- `dailyRotateFile` - `Rotation de fichier quotidien` + +```bash +LOGGER_TRANSPORT=console,dailyRotateFile +``` + +### LOGGER_BASE_PATH + +Chemin de stockage des journaux basés sur des fichiers, la valeur par défaut est `storage/logs`. + +```bash +LOGGER_BASE_PATH=storage/logs +``` + +### LOGGER_LEVEL + +Au niveau du journal de sortie, la valeur par défaut pour l'environnement de développement est « debug » et la valeur par défaut pour l'environnement de production est « info ». Options facultatives : + +- `error` +- `warn` +- `info` +- `debug` +- `trace` + +```bash +LOGGER_LEVEL=info +``` + +Le niveau de sortie du journal de la base de données est `debug`, qui est contrôlé par `DB_LOGGING` et n'est pas affecté par `LOGGER_LEVEL`. + +### LOGGER_MAX_FILES + +Le nombre maximum de fichiers journaux à conserver. + +- Lorsque `LOGGER_TRANSPORT` est `file`, la valeur par défaut est `10`. +- Lorsque `LOGGER_TRANSPORT` est `dailyRotateFile`, utilisez `[n]d` pour représenter le nombre de jours. La valeur par défaut est `14d`. + +```bash +LOGGER_MAX_FILES=14d +``` + +### LOGGER_MAX_SIZE + +Rotation du journal par taille. + +- Lorsque `LOGGER_TRANSPORT` est `file`, l'unité est `byte` et la valeur par défaut est `20971520` (20 * 1024 * 1024). +- Lorsque `LOGGER_TRANSPORT` est `dailyRotateFile`, vous pouvez utiliser `[n]k`, `[n]m`, `[n]g`. Non configuré par défaut. + +```bash +LOGGER_MAX_SIZE=20971520 +``` + +### LOGGER_FORMAT + +日志打印格式,开发环境默认 `console`, 生产环境默认 `json`. 可选项: +Format d'impression du journal, la valeur par défaut est `console` pour l'environnement de développement et `json` pour l'environnement de production. Options facultatives : + +- `console` +- `json` +- `logfmt` +- `delimiter` + +```bash +LOGGER_FORMAT=json +``` + +Voir:[Format du log](../plugins/logger/index.md#logformat) + +### CACHE_DEFAULT_STORE + +Specify the default cache method using the unique name,default is `memory`, options inlcude: +spécifiez la méthode de cache par défaut en utilisant le nom unique, la valeur par défaut est `memory`, options possibles : + +- `memory` +- `redis` + +```bash +CACHE_DEFAULT_STORE=memory +``` + +### CACHE_MEMORY_MAX + +Nombre maximum d'éléments dans le cache mémoire, la valeur par défaut est `2000`. + +```bash +CACHE_MEMORY_MAX=2000 +``` + +### CACHE_REDIS_URL + +URL Redis, optionnel. Exemple : `Redis://localhost:6379`. + +```bash +CACHE_REDIS_URL=redis://localhost:6379 +``` + +### TELEMETRY_ENABLED + +Activer la collecte de données de télémétrie, la valeur par défaut est `off`. + +- `on` activer +- `off` désactiver + +```bash +TELEMETRY_ENABLED=on +``` + +### TELEMETRY_METRIC_READER + +Le collecteur d'indicateurs de surveillance activé, la valeur par défaut est `console`. Les autres valeurs doivent faire référence au nom enregistré du plug-in de collecteur correspondant, tel que `prometheus`. Utilisez `,` pour en séparer plusieurs. + +```bash +TELEMETRY_METRIC_READER=console,prometheus +``` + +### TELEMETRY_TRACE_PROCESSOR + +Le processeur de données de lien activé est par défaut `console`. Les autres valeurs doivent faire référence au nom enregistré du plug-in du processeur correspondant. Utilisez `,` pour en séparer plusieurs. + +```bash +TELEMETRY_TRACE_PROCESSOR=console +``` + +## variables d'environnement expérimental + +### APPEND_PRESET_LOCAL_PLUGINS + +Utilisé pour ajouter des plugins locaux prédéfinis, avec la valeur du nom du package (le paramètre `name` dans `package.JSON`), séparés par des virgules pour plusieurs plugins. + +:::info +Ceux-ci n'apparaîtront que dans la page du gestionnaire de plugin après l'initialisation de l'installation avec `nocobase install` ou la mise à niveau avec `nocobase upgrade`. +::: + +```bash +APPEND_PRESET_LOCAL_PLUGINS=@my-project/plugin-foo,@my-project/plugin-bar +``` + +### APPEND_PRESET_BUILT_IN_PLUGINS + +Utilisé pour ajouter des plugins intégrés qui sont automatiquement installés par défaut, la valeur étant le nom du package (le paramètre `name` dans `package.json`), séparé par des virgules pour plusieurs plugins. + +:::info +Ces plugins seront automatiquement installés ou mis à niveau lors de l'initialisation avec `nocobase install` ou `nocobase update`. +::: + +```bash +APPEND_PRESET_LOCAL_PLUGINS=@my-project/plugin-foo,@my-project/plugin-bar +``` + +## Variables d'environnement temporaires + +L'installation de NocoBase peut être facilitée en définissant des variables d'environnement temporaires, telles que : + +```bash +yarn cross-env \ + INIT_APP_LANG=zh-CN \ + INIT_ROOT_EMAIL=demo@nocobase.com \ + INIT_ROOT_PASSWORD=admin123 \ + INIT_ROOT_NICKNAME="Super Admin" \ + nocobase install + +# Equivalent à +yarn nocobase install \ + --lang=zh-CN \ + --root-email=demo@nocobase.com \ + --root-password=admin123 \ + --root-nickname="Super Admin" + +# Equivalent à +yarn nocobase install -l zh-CN -e demo@nocobase.com -p admin123 -n "Super Admin" +``` + +### INIT_APP_LANG + +Langue au moment de l'installation, la valeur par défaut est « en-US », les options incluent + +- `en-US` Anglais +- `zh-CN` Chinois (Simplifié) + +```bash +yarn cross-env \ + INIT_APP_LANG=zh-CN \ + nocobase install +``` + +### INIT_ROOT_EMAIL + +Email de l'utilisateur root + +```bash +yarn cross-env \ + INIT_APP_LANG=zh-CN \ + INIT_ROOT_EMAIL=demo@nocobase.com \ + nocobase install +``` + +### INIT_ROOT_PASSWORD + +Mot de passe root + +```bash +yarn cross-env \ + INIT_APP_LANG=zh-CN \ + INIT_ROOT_EMAIL=demo@nocobase.com \ + INIT_ROOT_PASSWORD=admin123 \ + nocobase install +``` + +### INIT_ROOT_NICKNAME + +Surnom root + +```bash +yarn cross-env \ + INIT_APP_LANG=zh-CN \ + INIT_ROOT_EMAIL=demo@nocobase.com \ + INIT_ROOT_PASSWORD=admin123 \ + INIT_ROOT_NICKNAME="Super Admin" \ + nocobase install +``` diff --git a/docs/fr-FR/welcome/getting-started/installation/create-nocobase-app.md b/docs/fr-FR/welcome/getting-started/installation/create-nocobase-app.md new file mode 100644 index 000000000..575142412 --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/installation/create-nocobase-app.md @@ -0,0 +1,237 @@ +# create-nocobase-app + +## 0. Prerequisites + +Make sure you have: + +- Installed Node.js 20+, Yarn 1.22.x +- Configured and started one of the required database MySQL 8.x, MariaDB 10.9+, PostgreSQL 10+ + +You can download and install the latest LTS version from the official website. It is recommended to use nvm (or nvm-windows for Win systems) to manage Node.js versions if you plan to work with Node.js for a long time. + +```bash +$ node -v + +v20.10.0 +``` + +Install yarn package manager + +```bash +$ npm install --global yarn +$ yarn -v + +1.22.21 +``` + +## 1. Create a NocoBase project + +### Latest version + +Stable and well-tested version and only bug fixed will be made. This version is recommended. + +<Tabs> +<div label="PostgreSQL" name="postgres"> + +```bash +yarn create nocobase-app my-nocobase-app -d postgres \ + -e DB_HOST=localhost \ + -e DB_PORT=5432 \ + -e DB_DATABASE=nocobase \ + -e DB_USER=nocobase \ + -e DB_PASSWORD=nocobase \ + -e TZ=Asia/Shanghai \ + -e NOCOBASE_PKG_USERNAME= \ + -e NOCOBASE_PKG_PASSWORD= +``` + +</div> + +<div label="MySQL" name="mysql"> + +```bash +yarn create nocobase-app my-nocobase-app -d mysql \ + -e DB_HOST=localhost \ + -e DB_PORT=3306 \ + -e DB_DATABASE=nocobase \ + -e DB_USER=nocobase \ + -e DB_PASSWORD=nocobase \ + -e TZ=Asia/Shanghai \ + -e NOCOBASE_PKG_USERNAME= \ + -e NOCOBASE_PKG_PASSWORD= +``` + +</div> + +<div label="MariaDB" name="mariadb"> + +```bash +yarn create nocobase-app my-nocobase-app -d mariadb \ + -e DB_HOST=localhost \ + -e DB_PORT=3306 \ + -e DB_DATABASE=nocobase \ + -e DB_USER=nocobase \ + -e DB_PASSWORD=nocobase \ + -e TZ=Asia/Shanghai \ + -e NOCOBASE_PKG_USERNAME= \ + -e NOCOBASE_PKG_PASSWORD= +``` + +</div> +</Tabs> + +### Beta version + +This version includes new features that are about to be released and it has been preliminarily tested, but still have known or unknown issues. + +<Tabs> +<div label="PostgreSQL" name="postgres"> + +```bash +npx create-nocobase-app@beta my-nocobase-app -d postgres \ + -e DB_HOST=localhost \ + -e DB_PORT=5432 \ + -e DB_DATABASE=nocobase \ + -e DB_USER=nocobase \ + -e DB_PASSWORD=nocobase \ + -e TZ=Asia/Shanghai \ + -e NOCOBASE_PKG_USERNAME= \ + -e NOCOBASE_PKG_PASSWORD= +``` + +</div> + +<div label="MySQL" name="mysql"> + +```bash +npx create-nocobase-app@beta my-nocobase-app -d mysql \ + -e DB_HOST=localhost \ + -e DB_PORT=3306 \ + -e DB_DATABASE=nocobase \ + -e DB_USER=nocobase \ + -e DB_PASSWORD=nocobase \ + -e TZ=Asia/Shanghai \ + -e NOCOBASE_PKG_USERNAME= \ + -e NOCOBASE_PKG_PASSWORD= +``` + +</div> + +<div label="MariaDB" name="mariadb"> + +```bash +npx create-nocobase-app@beta my-nocobase-app -d mariadb \ + -e DB_HOST=localhost \ + -e DB_PORT=3306 \ + -e DB_DATABASE=nocobase \ + -e DB_USER=nocobase \ + -e DB_PASSWORD=nocobase \ + -e TZ=Asia/Shanghai \ + -e NOCOBASE_PKG_USERNAME= \ + -e NOCOBASE_PKG_PASSWORD= +``` + +</div> +</Tabs> + +### Alpha version + +A development version containing the latest features, which may be incomplete or unstable. + +<Tabs> +<div label="PostgreSQL" name="postgres"> + +```bash +npx create-nocobase-app@alpha my-nocobase-app -d postgres \ + -e DB_HOST=localhost \ + -e DB_PORT=5432 \ + -e DB_DATABASE=nocobase \ + -e DB_USER=nocobase \ + -e DB_PASSWORD=nocobase \ + -e TZ=Asia/Shanghai \ + -e NOCOBASE_PKG_USERNAME= \ + -e NOCOBASE_PKG_PASSWORD= +``` + +</div> + +<div label="MySQL" name="mysql"> + +```bash +npx create-nocobase-app@alpha my-nocobase-app -d mysql \ + -e DB_HOST=localhost \ + -e DB_PORT=3306 \ + -e DB_DATABASE=nocobase \ + -e DB_USER=nocobase \ + -e DB_PASSWORD=nocobase \ + -e TZ=Asia/Shanghai \ + -e NOCOBASE_PKG_USERNAME= \ + -e NOCOBASE_PKG_PASSWORD= +``` + +</div> + +<div label="MariaDB" name="mariadb"> + +```bash +npx create-nocobase-app@alpha my-nocobase-app -d mariadb \ + -e DB_HOST=localhost \ + -e DB_PORT=3306 \ + -e DB_DATABASE=nocobase \ + -e DB_USER=nocobase \ + -e DB_PASSWORD=nocobase \ + -e TZ=Asia/Shanghai \ + -e NOCOBASE_PKG_USERNAME= \ + -e NOCOBASE_PKG_PASSWORD= +``` + +</div> +</Tabs> + +:::warning + +- **Version 1.4 and above**: By setting the environment variables [`NOCOBASE_PKG_USERNAME`](/welcome/getting-started/env#nocobase_pkg_username) and [`NOCOBASE_PKG_PASSWORD`](/welcome/getting-started/env#nocobase_pkg_password), you can automatically download commercial plugins during application installation or upgrade; +- `TZ` is used to set the application's time zone, with the default being the system's time zone; +- `APP_KEY` is the application's secret key, used for generating user tokens and so on (if APP_KEY is changed, the old tokens will also become invalid). It can be any random string. Please change it to your own secret key and ensure it is not disclosed to the public. +- `DB_*` is related to the database. If it is not the default database service in the example, please modify it according to the actual situation. + ::: + +## 2. Switch to the project directory + +```bash +cd my-nocobase-app +``` + +## 3. Install dependencies + +📢 This next step may take more than ten minutes due to network environment, system configuration, and other factors. + +```bash +yarn install +``` + +## 4. Install NocoBase + +```bash +yarn nocobase install --lang=en-US +``` + +## 5. Start NocoBase + +Development + +```bash +yarn dev +``` + +Production + +```bash +yarn start +``` + +Note: For production, if the code has been modified, you need to execute `yarn build` and restart NocoBase. + +## 6. Log in to NocoBase + +Open [http://localhost:13000](http://localhost:13000) in a web browser. The initial account and password are `admin@nocobase.com` and `admin123`. diff --git a/docs/fr-FR/welcome/getting-started/installation/docker-compose.md b/docs/fr-FR/welcome/getting-started/installation/docker-compose.md new file mode 100644 index 000000000..2cadcc9ae --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/installation/docker-compose.md @@ -0,0 +1,265 @@ +# Docker (👍 Recommended) + +## 0. Prerequisites + +⚡⚡ Please make sure you have installed [Docker](https://docs.docker.com/get-docker/) + +## 1. Create a `docker-compose.yml` file + +```bash +# Create a folder named my-project (or any other name) to store the system files generated by NocoBase +mkdir my-project && cd my-project + +# Create an empty docker-compose.yml file +vi docker-compose.yml +``` + +## 2. Configure `docker-compose.yml` + +The configuration parameters vary slightly depending on the database. Choose the appropriate database configuration and copy it into the `docker-compose.yml`. + +<Tabs> + +<div label="PostgreSQL" name="postgres"> + +```yml +version: '3' + +networks: + nocobase: + driver: bridge + +services: + app: + image: nocobase/nocobase:latest + networks: + - nocobase + depends_on: + - postgres + environment: + # The application's secret key, used to generate user tokens, etc. + # If APP_KEY is changed, old tokens will also become invalid. + # It can be any random string, and make sure it is not exposed. + - APP_KEY=your-secret-key + # Database type, supports postgres, mysql, mariadb + - DB_DIALECT=postgres + # Database host, can be replaced with the IP of an existing database server + - DB_HOST=postgres + # Database name + - DB_DATABASE=nocobase + # Database user + - DB_USER=nocobase + # Database password + - DB_PASSWORD=nocobase + # Timezone + - TZ=Asia/Shanghai + # Service platform username and password, + # used for automatically downloading and updating plugins. + - NOCOBASE_PKG_USERNAME= + - NOCOBASE_PKG_PASSWORD= + volumes: + - ./storage:/app/nocobase/storage + ports: + - '13000:80' + # init: true + + # If using an existing database server, postgres service can be omitted + postgres: + image: postgres:16 + restart: always + command: postgres -c wal_level=logical + environment: + POSTGRES_USER: nocobase + POSTGRES_DB: nocobase + POSTGRES_PASSWORD: nocobase + volumes: + - ./storage/db/postgres:/var/lib/postgresql/data + networks: + - nocobase +``` + +</div> + +<div label="MySQL" name="mysql"> + +```yml +version: '3' + +networks: + nocobase: + driver: bridge + +services: + app: + image: nocobase/nocobase:latest + networks: + - nocobase + depends_on: + - mysql + environment: + # The application's secret key, used to generate user tokens, etc. + # If APP_KEY is changed, old tokens will also become invalid. + # It can be any random string, and make sure it is not exposed. + - APP_KEY=your-secret-key + # Database type, supports postgres, mysql, mariadb + - DB_DIALECT=mysql + # Database host, can be replaced with the IP of an existing database server + - DB_HOST=mysql + # Database name + - DB_DATABASE=nocobase + # Database user + - DB_USER=root + # Database password + - DB_PASSWORD=nocobase + # Whether to convert table and field names to snake case + - DB_UNDERSCORED=true + # Timezone + - TZ=Asia/Shanghai + # Service platform username and password, + # used for automatically downloading and updating plugins. + - NOCOBASE_PKG_USERNAME= + - NOCOBASE_PKG_PASSWORD= + volumes: + - ./storage:/app/nocobase/storage + ports: + - '13000:80' + # init: true + + # If using an existing database server, mysql service can be omitted + mysql: + image: mysql:8 + environment: + MYSQL_DATABASE: nocobase + MYSQL_USER: nocobase + MYSQL_PASSWORD: nocobase + MYSQL_ROOT_PASSWORD: nocobase + restart: always + volumes: + - ./storage/db/mysql:/var/lib/mysql + networks: + - nocobase +``` + +</div> + +<div label="MariaDB" name="mariadb"> + +```yml +version: '3' + +networks: + nocobase: + driver: bridge + +services: + app: + image: nocobase/nocobase:latest + networks: + - nocobase + depends_on: + - mariadb + environment: + # The application's secret key, used to generate user tokens, etc. + # If APP_KEY is changed, old tokens will also become invalid. + # It can be any random string, and make sure it is not exposed. + - APP_KEY=your-secret-key + # Database type, supports postgres, mysql, mariadb + - DB_DIALECT=mariadb + # Database host, can be replaced with the IP of an existing database server + - DB_HOST=mariadb + # Database name + - DB_DATABASE=nocobase + # Database user + - DB_USER=root + # Database password + - DB_PASSWORD=nocobase + # Whether to convert table and field names to snake case + - DB_UNDERSCORED=true + # Timezone + - TZ=Asia/Shanghai + # Service platform username and password, + # used for automatically downloading and updating plugins. + - NOCOBASE_PKG_USERNAME= + - NOCOBASE_PKG_PASSWORD= + volumes: + - ./storage:/app/nocobase/storage + ports: + - '13000:80' + # init: true + + # If using an existing database server, mariadb service can be omitted + mariadb: + image: mariadb:11 + environment: + MYSQL_DATABASE: nocobase + MYSQL_USER: nocobase + MYSQL_PASSWORD: nocobase + MYSQL_ROOT_PASSWORD: nocobase + restart: always + volumes: + - ./storage/db/mariadb:/var/lib/mysql + networks: + - nocobase +``` + +</div> +</Tabs> + +Choose the appropriate NocoBase version, refer to [versions](./index.md#which-version-to-install) + +- `latest`: Stable and well-tested version and only bug fixed will be made. This version is recommended. +- `beta`: This version includes new features that are about to be released and it has been preliminarily tested, but still have known or unknown issues. +- `alpha`: A development version containing the latest features, which may be incomplete or unstable. +- `1.3.51`: Specify the version number. To check the latest version, see the [list of released versions](https://hub.docker.com/r/nocobase/nocobase/tags). + +:::warning +**Version 1.4 and above**: By setting the environment variables [`NOCOBASE_PKG_USERNAME`](/welcome/getting-started/env#nocobase_pkg_username) and [`NOCOBASE_PKG_PASSWORD`](/welcome/getting-started/env#nocobase_pkg_password), you can automatically download commercial plugins during application installation or upgrade. +::: + +Example: + +```yml +#... +services: + app: + # Domestic users suggest using Ali Cloud image + image: registry.cn-shanghai.aliyuncs.com/nocobase/nocobase:latest + image: registry.cn-shanghai.aliyuncs.com/nocobase/nocobase:beta + image: registry.cn-shanghai.aliyuncs.com/nocobase/nocobase:alpha + Image: registry.cn-shanghai.aliyuncs.com/nocobase/nocobase:1.3.51 + + # Docker Hub image (Domestic users cannot download) + image: nocobase/nocobase:latest + image: nocobase/nocobase:beta + image: nocobase/nocobase:alpha + image: nocobase/nocobase:1.3.51 +# ... +` ` ` + +## 3. Install and start NocoBase + +It may take a few minutes + +```bash +# pull service images +$ docker-compose pull +# run in the background +$ docker-compose up -d +# view app process +$ docker-compose logs app + +app-postgres-app-1 | nginx started +app-postgres-app-1 | yarn run v1.22.15 +app-postgres-app-1 | $ cross-env DOTENV_CONFIG_PATH=.env node -r dotenv/config packages/app/server/lib/index.js install -s +app-postgres-app-1 | Done in 2.72s. +app-postgres-app-1 | yarn run v1.22.15 +app-postgres-app-1 | $ pm2-runtime start --node-args="-r dotenv/config" packages/app/server/lib/index.js -- start +app-postgres-app-1 | 2022-04-28T15:45:38: PM2 log: Launching in no daemon mode +app-postgres-app-1 | 2022-04-28T15:45:38: PM2 log: App [index:0] starting in -fork mode- +app-postgres-app-1 | 2022-04-28T15:45:38: PM2 log: App [index:0] online +app-postgres-app-1 | 🚀 NocoBase server running at: http://localhost:13000/ +``` + +## 4. Log in to NocoBase + +Open [http://localhost:13000](http://localhost:13000) in a web browser. The initial account and password are `admin@nocobase.com` and `admin123`. diff --git a/docs/fr-FR/welcome/getting-started/installation/git-clone.md b/docs/fr-FR/welcome/getting-started/installation/git-clone.md new file mode 100644 index 000000000..d0178a682 --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/installation/git-clone.md @@ -0,0 +1,97 @@ +# Git source code + +## 0. Prerequisites + +Make sure you have: + +- Git, Node.js 20+, Yarn 1.22.x installed +- Configured and started the required database — MySQL 8.x, MariaDB 10.9+, PostgreSQL 10+ — choose any one. + +## 1. Download with Git + +### Latest version (`main`) + +Stable and well-tested version and only bug fixed will be made. This version is recommended. + +```bash +git clone https://github.com/nocobase/nocobase.git -b main --depth=1 my-nocobase +``` + +### Beta version (`next`) + +This version includes new features that are about to be released and it has been preliminarily tested, but still have known or unknown issues. + +```bash +git clone https://github.com/nocobase/nocobase.git -b next --depth=1 my-nocobase +``` + +### Alpha version (`develop`) + +A development version containing the latest features, which may be incomplete or unstable. + +```bash +git clone https://github.com/nocobase/nocobase.git -b develop --depth=1 my-nocobase +``` + +## 2. Switch to the project directory + +```bash +cd my-nocobase +``` + +## 3. Install dependencies + +```bash +yarn install --frozen-lockfile +``` + +## 4. Set environment variables + +The environment variables required by NocoBase are stored in the root `.env` file, modify the environment variables according to the actual situation, if you don't know how to change them, [click here for environment variables description](../env.md), or you can leave it as default. + +```bash +TZ=Asia/Shanghai +APP_KEY=your-secret-key +DB_HOST=localhost +DB_PORT=5432 +DB_DATABASE=postgres +DB_USER=nocobase +DB_PASSWORD=nocobase +NOCOBASE_PKG_USERNAME=your-username +NOCOBASE_PKG_PASSWORD=your-password +``` + +:::warning + +- **Version 1.4 and above**: By setting the environment variables [`NOCOBASE_PKG_USERNAME`](/welcome/getting-started/env#nocobase_pkg_username) and [`NOCOBASE_PKG_PASSWORD`](/welcome/getting-started/env#nocobase_pkg_password), you can automatically download commercial plugins during application installation or upgrade; +- `TZ` is used to set the application's time zone, with the default being the system's time zone; +- `APP_KEY` is the application's secret key, used for generating user tokens and so on (if APP_KEY is changed, the old tokens will also become invalid). It can be any random string. Please change it to your own secret key and ensure it is not disclosed to the public. +- `DB_*` is related to the database. If it is not the default database service in the example, please modify it according to the actual situation. + ::: + +## 5. Install NocoBase + +```bash +yarn nocobase install --lang=en-US +``` + +## 6. Start NocoBase + +Development + +```bash +yarn dev +``` + +Production + +```bash +# Build (make sure you have executed `yarn install --frozen-lockfile`, note that it does not include `--production`) +yarn build +# Start +yarn start +``` + +## 7. Log in to NocoBase + +Open [http://localhost:13000](http://localhost:13000) in a web browser. The initial account and password are `admin@nocobase.com` and `admin123`. diff --git a/docs/fr-FR/welcome/getting-started/installation/index.md b/docs/fr-FR/welcome/getting-started/installation/index.md new file mode 100644 index 000000000..91f036c2f --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/installation/index.md @@ -0,0 +1,43 @@ +# Overview + +## Installation Methods + +NocoBase supports three installation methods. + +- [Docker (recommended)](./docker-compose.md) +- [create-nocobase-app](./create-nocobase-app.md) +- [Git source code](./git-clone.md) + +## How to choose the Installation method? + +### Docker (recommended) + +Suitable for no-code scenarios, no code to write. When upgrading, just download the latest image and reboot. + +### create-nocobase-app + +The business code of the project is completely independent and supports low-code development. + +### Git source code + +If you want to experience the latest unreleased version, or want to participate in the contribution, you need to make changes and debug on the source code, it is recommended to choose this installation method, which requires a high level of development skills, and if the code has been updated, you can git pull the latest code. + +## Which version to install? + +### Latest version + +This is a stable and well-tested version and only bug fixed will be made. This version is recommended. + +### Beta version + +This version includes new features that are about to be released and it has been preliminarily tested, but still have known or unknown issues, primarily for testing and feedback. Ideal for early testers willing to try new features and provide feedback. + +### Alpha version + +A development version containing the latest features, which may be incomplete or unstable. Suitable for technical users interested in cutting-edge features. Not recommended for production use. + +| Version | Source code branch | Docker images version | create-nocobase-app version | Specific version | +| -------- | ------------------ | -------------------------- | ---------------------------- | -------------------------------------------- | +| `Latest` | `main` | `nocobase/nocobase:latest` | `create-nocobase-app@latest` | `1.3.51`<br />`1.3.52`<br />... | +| `Beta` | `next` | `nocobase/nocobase:beta` | `create-nocobase-app@beta` | `1.4.0-beta.1`<br/>`1.4.0-beta.2`<br />... | +| `Alpha` | `develop` | `nocobase/nocobase:alpha` | `create-nocobase-app@alpha` | `1.5.0-alpha.1`<br/>`1.5.0-alpha.2`<br />... | diff --git a/docs/fr-FR/welcome/getting-started/plugin.md b/docs/fr-FR/welcome/getting-started/plugin.md new file mode 100644 index 000000000..82796c490 --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/plugin.md @@ -0,0 +1,162 @@ +# Installation et mise à jour des plugins + +## Installation et mise à niveau de plugins commerciaux (v1.4 et supérieur) + +### Configurer les variables d'environnement + +Définissez les variables d'environnement [`NOCOBASE_PKG_USERNAME`](/welcome/getting-started/env#nocobase_pkg_username) et [`NOCOBASE_PKG_PASSWORD`](/welcome/getting-started/env#nocobase_pkg_password)(Nom d'utilisateur et mot de passe NocoBase Service Platform) pour télécharger automatiquement les plugins commerciaux lors de l’installation ou de la mise à niveau de l’application. + +```bash +NOCOBASE_PKG_USERNAME=your-username +NOCOBASE_PKG_PASSWORD=your-password +``` + +[Comment définir les variables d'environnement ?](/welcome/getting-started/env) + +### Exécuter les commandes d'installation ou de mise à niveau de l'application + +Une fois l'application installée ou mise à niveau, tous les plugins commerciaux autorisés apparaîtront dans le gestionnaire de plugins. Les plugins seront automatiquement téléchargés et mis à jour. + +#### Installation + +- [Docker (recommendé)](./installation/docker-compose.md) +- [create-nocobase-app](./installation/create-nocobase-app.md) +- [Code source Git](./installation/git-clone.md) + +#### Mise à niveau + +- [Mise à niveau pour Docker compose](./upgrading/docker-compose.md) +- [Mise à niveau pour create-nocobase-app](./upgrading/create-nocobase-app.md) +- [Mise à niveau pour Code source Git](./upgrading/git-clone.md) + +### Activer les plugins + +Sélectionnez les plugins que vous souhaitez activer dans le gestionnaire de plugins. + +![Activation de Plugin](https://static-docs.nocobase.com/20241204000230.png) + +--- + +## Installation et mise à jour des plugins via l'interface + +:::warning +L'ajout ou la mise à jour de plugins via l'interface redémarrera l'application. Pour les opérations par lots, envisagez des méthodes alternatives. +::: + +### Uploader des packages de plugins via Plugin Manager + +Les plugins commerciaux et tiers peuvent être directement uploadé via l'interface. + +![Upload de Plugins](https://static-docs.nocobase.com/20241204000127.png) + +Notes: + +- Pour créer des packages de plugins, reportez-vous à [Ecrire votre premier Plugin](/development/your-first-plugin) pour garantir une construction et un packaging appropriés. + +### Activer les Plugins + +Sélectionnez les plugins que vous souhaitez activer dans le gestionnaire de plugins. + +![Activation de Plugin](https://static-docs.nocobase.com/20241204000230.png) + +--- + +## Installation et mise à jour des plugins via la ligne de commande + +:::warning +- Prend en charge les opérations par lots. +- Cette méthode est recommandée si les mises à jour de l'application entraînent une incompatibilité du plugin ou un échec de démarrage. + ::: + +### 0. Pour les versions Docker, entrez dans le conteneur + +```bash +docker-compose exec app bash +``` + +### 1. Connectez-vous au registre NPM + +Configurez le registre en fonction de votre configuration. + +```bash +npm login --registry=https://pkg.nocobase.com/ +``` + +### 2. Ajouter ou mettre à jour des plugins + +```bash +yarn pm add @nocobase/plugin-data-source-external-mysql @nocobase/plugin-embed --registry=https://pkg.nocobase.com/ +``` + +### 3. Activer les plugins + +```bash +yarn pm enable @nocobase/plugin-data-source-external-mysql @nocobase/plugin-embed +``` + +--- + +## Installation et mise à jour des plugins via l'upload du répertoire de plugins + +:::warning +- Prend en charge les opérations par lots et est pratique pour la migration. +- Convient aux serveurs dans un environnement intranet. +- Recommandé pour la mise à jour des plugins incompatibles provoqués par les mises à jour d'applications. + ::: + +### Ajouter ou mettre à jour des plugins + +Stockez les plugins commerciaux et tiers dans le répertoire `./storage/plugins/`. Vous pouvez télécharger des plugins dans un environnement de développement et les télécharger dans le répertoire `./storage/plugins/` sur le serveur. Vous pouvez également extraire directement le package du plugin dans le répertoire. Par exemple: + +```bash +mkdir -p /my-nocobase/storage/plugins/@nocobase/plugin-auth-cas && \ + tar -xvzf /downloads/plugin-auth-cas-1.4.0.tgz \ + -C /my-nocobase/storage/plugins/@nocobase/plugin-auth-cas \ + --strip-components=1 +``` + +Cette commande garantit que le plugin est extrait dans `/my-nocobase/storage/plugins/@nocobase/plugin-auth-cas` sans le répertoire `package`. La structure correcte des répertoires est la suivante : + +```plaintext +./plugin-auth-cas/dist/server/migrations/20240425200816-change-locale-module.js +./plugin-auth-cas/dist/server/auth.js +./plugin-auth-cas/client.js +./plugin-auth-cas/dist/constants.js +./plugin-auth-cas/dist/externalVersion.js +./plugin-auth-cas/dist/client/index.js +./plugin-auth-cas/dist/index.js +./plugin-auth-cas/dist/server/index.js +./plugin-auth-cas/dist/server/actions/login.js +./plugin-auth-cas/dist/server/plugin.js +./plugin-auth-cas/server.js +./plugin-auth-cas/dist/server/actions/service.js +./plugin-auth-cas/dist/locale/en-US.json +./plugin-auth-cas/dist/locale/ko_KR.json +./plugin-auth-cas/package.json +./plugin-auth-cas/dist/locale/zh-CN.json +./plugin-auth-cas/README.md +./plugin-auth-cas/README.zh-CN.md +./plugin-auth-cas/dist/server/migrations/20240425200816-change-locale-module.d.ts +./plugin-auth-cas/dist/server/auth.d.ts +./plugin-auth-cas/client.d.ts +./plugin-auth-cas/dist/constants.d.ts +./plugin-auth-cas/dist/client/index.d.ts +./plugin-auth-cas/dist/client/locale/index.d.ts +./plugin-auth-cas/dist/index.d.ts +./plugin-auth-cas/dist/server/index.d.ts +./plugin-auth-cas/dist/server/actions/login.d.ts +./plugin-auth-cas/dist/client/Options.d.ts +./plugin-auth-cas/dist/server/plugin.d.ts +./plugin-auth-cas/server.d.ts +./plugin-auth-cas/dist/server/actions/service.d.ts +./plugin-auth-cas/dist/client/SigninPage.d.ts +./plugin-auth-cas/LICENSE.txt +``` + +### Exécutez la commande Upgrade pour mettre à jour les plugins + +Après avoir uploadé les plugins dans le répertoire des plugins, exécutez la commande « nocobase update » pour terminer la mise à jour. + +```bash +yarn nocobase upgrade +``` diff --git a/docs/fr-FR/welcome/getting-started/upgrading/create-nocobase-app.md b/docs/fr-FR/welcome/getting-started/upgrading/create-nocobase-app.md new file mode 100644 index 000000000..e76ccce08 --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/upgrading/create-nocobase-app.md @@ -0,0 +1,27 @@ +# Mise à niveau pour `create-nocobase-app` + +## 0. Préparation de la mise à niveau + +:::warning +- Assurez-vous de sauvegarder la base de données avant la mise à niveau !!! +- **Version 1.4 et supérieure** : En définissant les variables d'environnement [`NOCOBASE_PKG_USERNAME`](/welcome/getting-started/env#nocobase_pkg_username) et [`NOCOBASE_PKG_PASSWORD`](/welcome/getting-started/env#nocobase_pkg_password), vous pouvez télécharger automatiquement des plugins commerciaux lors de l'installation ou de la mise à niveau de l'application. +::: + +## 1. Mise à niveau + +Mettez à niveau l'application en exécutant la commande `yarn nocobase upgrade`. + +```bash +# Basculer vers le répertoire correspondant +cd mon-nocobase-app +# Exécutez la commande de mise à jour +yarn nocobase upgrade +# Démarrer +yarn dev +``` + +Si vous rencontrez des problèmes avec la mise à niveau, vous pouvez également [recréer une nouvelle application](/welcome/getting-started/installation/create-nocobase-app) et vous référer à l'ancienne version de .env pour modifier les variables d'environnement. Les informations de la base de données doivent être configurées correctement. Lorsque vous utilisez une base de données SQLite, vous devez copier les fichiers de la base de données dans le répertoire `./storage/db/`. Enfin, exécutez `yarn nocobase update` pour effectuer la mise à niveau. + +## 2. Mise à niveau des plugins indépendants + +Après la mise à niveau de NocoBase, les plugins indépendants installés via l'interface devront peut-être également être mis à niveau. Veuillez vous référer à la documentation [Installation et mise à niveau des plugins](/welcome/getting-started/plugin) diff --git a/docs/fr-FR/welcome/getting-started/upgrading/docker-compose.md b/docs/fr-FR/welcome/getting-started/upgrading/docker-compose.md new file mode 100644 index 000000000..35d347be6 --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/upgrading/docker-compose.md @@ -0,0 +1,55 @@ +# Mise à niveau pour Docker Compose + +## 0. Préparation à la mise à niveau + +:::warning +- Assurez-vous de sauvegarder la base de données avant de procéder à la mise à niveau !!! +- **Version 1.4 et supérieure** : En définissant les variables d'environnement [`NOCOBASE_PKG_USERNAME`](/welcome/getting-started/env#nocobase_pkg_username) et [`NOCOBASE_PKG_PASSWORD`](/welcome/getting-started/env#nocobase_pkg_password), vous pouvez télécharger automatiquement les plugins commerciaux lors de l'installation ou de la mise à niveau de l'application. +::: + +## 1. Naviguer vers le répertoire contenant `docker-compose.yml` + +Exemple + +```bash +# MacOS, Linux... +cd /votre/chemin/mon-projet/ +# Windows +cd C:\votre\chemin\mon-projet +``` + +## 2. Mettre à jour la version de l'image + +- 'latest' : Stabilité fonctionnelle, version testée de manière plus complète, avec uniquement des corrections de bugs. Il est recommandé d'installer cette version. +- 'beta' : Contient une nouvelle fonctionnalité prête à être publiée, version préalablement testée qui peut contenir des problèmes connus ou inconnus. +- 'alpha' : Version en développement qui contient le dernier code des fonctionnalités, peut être incomplète ou instable, utilisée principalement pour le développement interne et l'itération rapide. +- `1.3.51` : Spécifiez un numéro de version, vous pouvez consulter la liste des versions précédentes [ici](https://hub.docker.com/r/nocobase/nocobase/tags). + +:::warning +Les images peuvent uniquement être mises à niveau, elles ne peuvent pas être rétrogradées. La prochaine version ne peut pas être rétrogradée vers la version "latest". +::: + +```yml +# ... +services: + app: + image: nocobase/nocobase:main + image: nocobase/nocobase:latest + image: nocobase/nocobase:1.2.4-alpha +# ... +``` + +## 3. Redémarrer le conteneur + +```bash +# Récupérer la dernière image +docker-compose pull +# Démarrer +docker-compose up -d app +# Voir les logs de l'application +docker-compose logs app +``` + +## 4. Mise à niveau des plugins indépendants + +Après la mise à niveau de NocoBase, les plugins indépendants installés via l'interface peuvent aussi nécessiter une mise à niveau. Veuillez consulter la documentation [Installation et Mise à niveau des Plugins](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/welcome/getting-started/upgrading/git-clone.md b/docs/fr-FR/welcome/getting-started/upgrading/git-clone.md new file mode 100644 index 000000000..a4241839a --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/upgrading/git-clone.md @@ -0,0 +1,131 @@ +# Upgrading for Git source code + +## 0. Preparing for the upgrade + +:::warning +- Make sure to backup the database before upgrading!!! +- **Version 1.4 and above**: By setting the environment variables [`NOCOBASE_PKG_USERNAME`](/welcome/getting-started/env#nocobase_pkg_username) and [`NOCOBASE_PKG_PASSWORD`](/welcome/getting-started/env#nocobase_pkg_password), you can automatically download commercial plugins during application installation or upgrade. +::: + +## 1. switch to the NocoBase project directory + +```bash +cd my-nocobase-app +``` + +## 2. Pull the latest code + +```bash +git pull +``` + +## 3. Delete cache and dependencies (optional) + +If the normal upgrade process fails, try emptying the cache and dependencies and re-downloading it. + +```bash +# delete nocobase cache +yarn nocobase clean +# delete dependencies +yarn rimraf -rf node_modules +``` + +## 4. Update dependencies + +```bash +yarn install +``` + +## 5. Execute the update command + +```bash +yarn nocobase upgrade +``` + +## 6. Start NocoBase + +development environment + +```bash +yarn dev +``` + +Production environment + +```bash +# compile +yarn build + +# Start +yarn start +``` + +## 7. Upgrading independent plugins + +After upgrading NocoBase, independent plugins installed through the interface might also need to be upgraded. Please refer to documentation [Installation and Upgrade of Plugins](/welcome/getting-started/plugin) + +# Mise à niveau pour le code source Git + +## 0. Préparation à la mise à niveau + +:::warning +- Assurez-vous de sauvegarder la base de données avant de procéder à la mise à niveau !!! +- **Version 1.4 et supérieure** : En définissant les variables d'environnement [`NOCOBASE_PKG_USERNAME`](/welcome/getting-started/env#nocobase_pkg_username) et [`NOCOBASE_PKG_PASSWORD`](/welcome/getting-started/env#nocobase_pkg_password), vous pouvez télécharger automatiquement les plugins commerciaux lors de l'installation ou de la mise à niveau de l'application. +::: + +## 1. Passer au répertoire du projet NocoBase + +```bash +cd mon-app-nocobase +``` + +## 2. Récupérer le dernier code + +```bash +git pull +``` + +## 3. Supprimer le cache et les dépendances (facultatif) + +Si le processus de mise à niveau standard échoue, essayez de vider le cache et les dépendances, puis de les télécharger à nouveau. + +```bash +# supprimer le cache nocobase +yarn nocobase clean +# supprimer les dépendances +yarn rimraf -rf node_modules +``` + +## 4. Mettre à jour les dépendances + +```bash +yarn install +``` + +## 5. Exécuter la commande de mise à niveau + +```bash +yarn nocobase upgrade +``` + +## 6. Démarrer NocoBase + +Environnement de développement + +```bash +yarn dev +``` + +Environnement de production + +```bash +# compiler +yarn build + +# Démarrer +yarn start +``` + +## 7. Mise à niveau des plugins indépendants + +Après la mise à niveau de NocoBase, les plugins indépendants installés via l'interface peuvent également nécessiter une mise à niveau. Veuillez consulter la documentation [Installation et Mise à niveau des Plugins](/welcome/getting-started/plugin). diff --git a/docs/fr-FR/welcome/getting-started/upgrading/index.md b/docs/fr-FR/welcome/getting-started/upgrading/index.md new file mode 100644 index 000000000..adfee9c65 --- /dev/null +++ b/docs/fr-FR/welcome/getting-started/upgrading/index.md @@ -0,0 +1,7 @@ +# Vue d'ensemble + +NocoBase prend en charge trois types d'installation, avec de légères différences lors des mises à niveau. + +- [Mise à niveau pour Docker compose](./docker-compose.md) +- [Mise à niveau pour create-nocobase-app](./create-nocobase-app.md) +- [Mise à niveau pour le code source Git](./git-clone.md) diff --git a/docs/fr-FR/welcome/how.md b/docs/fr-FR/welcome/how.md new file mode 100644 index 000000000..8b2eb9643 --- /dev/null +++ b/docs/fr-FR/welcome/how.md @@ -0,0 +1,31 @@ +# Fonctionnement de NocoBase + +NocoBase prend en charge toutes ses fonctionnalités grâce à une architecture basée sur un microkernel et des plugins. + +## Microkernel + +Le noyau de NocoBase est similaire à un framework de développement qui définit le cycle de vie de l'application et standardise les protocoles d'interface de chaque couche. La structure de base de NocoBase est illustrée dans le diagramme suivant : + +![how-micro-core](https://static-docs.nocobase.com/how-micro-core.png) + +Le modèle de données est utilisé comme moteur sous-jacent, l'interface basée sur des blocs est utilisée comme couche utilisateur, et la couche de logique métier sert de pont reliant les deux et portant toutes sortes de règles métier, permettant ainsi aux données de circuler de manière cyclique à travers les opérations de l'utilisateur. + +NocoBase définit des protocoles standard à trois niveaux principaux : +1. **Modèle de données** : basé sur l'encapsulation d'ORM de base de données relationnelle pour la couche supérieure, avec une description normalisée de la modélisation des données (voir [Collections et Champs](/development/server/collections)). +2. **Routage HTTP** : interface de type RESTful basée sur des définitions de ressources et d'actions (voir [Ressources et Actions](/development/server/resources-actions)). +3. **Interface côté client** : JSON Schema basé sur Formily 2.0 pour décrire la disposition personnalisée des pages et des blocs (voir [UI Schema](/development/client/ui-schema/quick-start)). + +Sur la base de ces protocoles, cela rend également le développement d'autres modules plus standardisé et plus facile. + +### Pluginisation + +NocoBase ouvre des interfaces extensibles à tous les aspects du cycle de vie de l'application, y compris les types de champs, les types de collections, les sources de données tierces dans le modèle de données, l'insertion de middleware dans la couche de logique métier, les composants d'interface, les blocs, etc. Ces interfaces couvrent tout le cycle de vie de l'application (démarrage, arrêt, et chargement des plugins), et de nombreux plugins offrent même des interfaces extensibles secondaires. Cette conception offre une multitude de possibilités d'extension pour le développement d'applications, et toutes les fonctionnalités intégrées de NocoBase sont également composées à travers cette approche : + +![how-plugins-en](https://static-docs.nocobase.com/how-plugins-en.png) + +Les plugins peuvent être utilisés pour étendre les fonctionnalités requises à n'importe quelle étape du cycle de vie de l'application, comme le plugin **Permissions**, qui inclut des tables de données personnalisées, des traitements métier pour le middleware des requêtes, et des interfaces pour l'administration front-end. +Grâce à cette conception, NocoBase ne se contente pas de réaliser des fonctionnalités no-code riches, mais prend également en charge des extensions libres lorsque les fonctionnalités intégrées ne peuvent pas satisfaire les besoins. + +### En savoir plus + +Veuillez consulter la section [Développement de plugins](/development) pour commencer à étendre NocoBase en développant des plugins. diff --git a/docs/fr-FR/welcome/introduction/features.md b/docs/fr-FR/welcome/introduction/features.md new file mode 100644 index 000000000..8e7d3228e --- /dev/null +++ b/docs/fr-FR/welcome/introduction/features.md @@ -0,0 +1,21 @@ +# Caractéristiques distinctives + +## 1. Model-driven, séparation de l'« interface utilisateur » et de la « structure des données » + +La plupart des produits no-code basés sur des formulaires, des tableaux ou des processus créent des structures de données directement dans l'interface utilisateur, comme Airtable, où l'ajout d'une nouvelle colonne dans un tableau correspond à l'ajout d'un nouveau champ. Cela présente l'avantage de la simplicité d'utilisation, mais l'inconvénient d'une fonctionnalité et d'une flexibilité limitées pour répondre aux besoins de scénarios plus complexes. + +NocoBase adopte l'idée de conception consistant à séparer la structure des données de l'interface utilisateur, vous permettant de créer un nombre quelconque de blocs (vues de données) pour les collections de données, avec des types, des styles, du contenu et des actions différents dans chaque bloc. Cela équilibre la simplicité de l'opération no-code avec la flexibilité du développement natif. + +![model](https://nocobase-file.oss-cn-beijing.aliyuncs.com/model-l.png) + +## 2. Ce que vous voyez est ce que vous obtenez + +NocoBase permet le développement de systèmes métier complexes et distinctifs, mais cela ne signifie pas que des opérations complexes et spécialisées sont nécessaires. En un seul clic, les options de configuration sont affichées sur l'interface d'utilisation, et les administrateurs disposant de privilèges de configuration du système peuvent configurer directement l'interface utilisateur de manière WYSIWYG (What You See Is What You Get). + +![wysiwyg](https://nocobase-file.oss-cn-beijing.aliyuncs.com/wysiwyg.gif) + +## 3. Fonctionne sous forme de plugins + +NocoBase adopte une architecture de plugins, toutes les nouvelles fonctionnalités peuvent être réalisées en développant et en installant des plugins, et l'extension des fonctionnalités est aussi simple que d'installer une application sur votre téléphone. + +![plugins](https://nocobase-file.oss-cn-beijing.aliyuncs.com/plugins-l.png) diff --git a/docs/fr-FR/welcome/introduction/features/2.collection-block.png b/docs/fr-FR/welcome/introduction/features/2.collection-block.png new file mode 100755 index 000000000..7389064cb Binary files /dev/null and b/docs/fr-FR/welcome/introduction/features/2.collection-block.png differ diff --git a/docs/fr-FR/welcome/introduction/features/2.user-root.gif b/docs/fr-FR/welcome/introduction/features/2.user-root.gif new file mode 100755 index 000000000..92d668c14 Binary files /dev/null and b/docs/fr-FR/welcome/introduction/features/2.user-root.gif differ diff --git a/docs/fr-FR/welcome/introduction/index.md b/docs/fr-FR/welcome/introduction/index.md new file mode 100644 index 000000000..8209098d8 --- /dev/null +++ b/docs/fr-FR/welcome/introduction/index.md @@ -0,0 +1,61 @@ +# Introduction + +<video width="100%" controls> + <source src="https://static-docs.nocobase.com/NocoBase0510.mp4" type="video/mp4"> +</video> + + +## What is NocoBase + +NocoBase is a extensibility-first, open-source no-code development platform. +Instead of investing years of time and millions of dollars in research and development, deploy NocoBase in a few minutes and you'll have a private, controllable, and extremely extensible no-code development platform! + +Homepage: +https://www.nocobase.com/ + +Online Demo: +https://demo.nocobase.com/new + +Documents: +https://docs.nocobase.com/ + +Commericial license & plugins: +https://www.nocobase.com/en/commercial + +License agreement: +https://www.nocobase.com/en/agreement + + +## Contact Us: +hello@nocobase.com + + +----- +# Introduction + +<video width="100%" controls> + <source src="https://static-docs.nocobase.com/NocoBase0510.mp4" type="video/mp4"> +</video> + +## Qu'est-ce que NocoBase + +NocoBase est une plateforme de développement no-code open-source, conçue en priorité pour l'extensibilité. +Au lieu d'investir des années de travail et des millions de dollars en recherche et développement, déployez NocoBase en quelques minutes et vous disposerez d'une plateforme de développement no-code privée, contrôlable et extrêmement extensible ! + +Page d'accueil : +[https://www.nocobase.com/](https://www.nocobase.com/) + +Démo en ligne : +[https://demo.nocobase.com/new](https://demo.nocobase.com/new) + +Documentation : +[https://docs.nocobase.com/](https://docs.nocobase.com/) + +Licence commerciale & plugins : +[https://www.nocobase.com/en/commercial](https://www.nocobase.com/en/commercial) + +Accord de licence : +[https://www.nocobase.com/en/agreement](https://www.nocobase.com/en/agreement) + +## Contactez-nous : +hello@nocobase.com diff --git a/docs/fr-FR/welcome/introduction/why.md b/docs/fr-FR/welcome/introduction/why.md new file mode 100644 index 000000000..8800961f9 --- /dev/null +++ b/docs/fr-FR/welcome/introduction/why.md @@ -0,0 +1,52 @@ +# Why NocoBase + +## Open source, autonomous and controllable + +NocoBase is open source under the AGPL-3.0 license, and can be used free of charge as long as you follow the license. Advanced features are provided through the commercial version, which also provides full source code and is privately deployed to keep data private and secure. + +## Strong no-code capability + +NocoBase has three core concepts: collection, block, and action. By defining the data collections, to abstract the business; through the block to present the data; through the action to send the user's instructions to the server to complete the data interaction or change. + +## High extensibility + +In the actual business, the ideal situation is to use no-code to meet 80% of the needs, the rest usually need to extend the development. NocoBase adopts the microkernel architecture, with a sound plugin system, all kinds of functions are extended in the form of plugins. NocoBase is based on Node.js and uses mainstream frameworks and technologies, including Koa, Sequelize, React and so on, which makes it extremely easy to expand. + +## Integrate with existing systems + +Organizations usually have various systems and databases already in place, and NocoBase supports using third-party databases or APIs as data sources, as well as embedding NocoBase into third-party systems or embedding third-party systems into NocoBase. + +## Extremely simple and lightweight + +NocoBase uses JavaScript/TypeScript technology stack, one person can complete the front-end and back-end development. It has low server requirements and can be deployed on a single low-configuration server. + +## Pay once, use forever + +NocoBase only charges for premium features. On top of the open source version, we offer commercial licenses, commercial services, and commercial plugins. Pay once and get lifetime licenses, as well as full source code for commercial plugins. + +---- +# Pourquoi NocoBase + +## Open source, autonome et contrôlable + +NocoBase est open source sous la licence AGPL-3.0, et peut être utilisé gratuitement tant que vous respectez la licence. Les fonctionnalités avancées sont proposées via la version commerciale, qui fournit également le code source complet et peut être déployée de manière privée pour garder les données sécurisées et confidentielles. + +## Forte capacité no-code + +NocoBase repose sur trois concepts fondamentaux : collection, bloc et action. En définissant les collections de données, on peut abstraire les processus métier ; à travers les blocs, les données sont présentées ; et grâce aux actions, les instructions de l'utilisateur sont envoyées au serveur pour effectuer des interactions ou modifications de données. + +## Grande extensibilité + +Dans le cadre des besoins métier réels, la situation idéale consiste à utiliser le no-code pour couvrir 80 % des besoins, le reste nécessitant généralement un développement supplémentaire. NocoBase adopte une architecture microkernel, avec un système de plugins solide, permettant d'étendre toutes les fonctionnalités sous forme de plugins. NocoBase est basé sur Node.js et utilise des frameworks et technologies populaires, tels que Koa, Sequelize, React, ce qui facilite grandement son extensibilité. + +## Intégration avec les systèmes existants + +Les organisations disposent souvent de divers systèmes et bases de données déjà en place. NocoBase prend en charge l'utilisation de bases de données ou d'API tierces comme sources de données, ainsi que l'intégration de NocoBase dans des systèmes tiers ou l'intégration de systèmes tiers dans NocoBase. + +## Extrêmement simple et léger + +NocoBase utilise une pile technologique JavaScript/TypeScript, ce qui permet à une seule personne de réaliser le développement front-end et back-end. Il a des exigences serveur faibles et peut être déployé sur un serveur à faible ressource. + +## Payez une fois, utilisez à vie + +NocoBase ne facture que les fonctionnalités premium. En plus de la version open source, nous proposons des licences commerciales, des services commerciaux et des plugins commerciaux. Payez une fois et obtenez des licences à vie, ainsi que le code source complet des plugins commerciaux. diff --git a/docs/fr-FR/welcome/release/20240519-changelog.md b/docs/fr-FR/welcome/release/20240519-changelog.md new file mode 100644 index 000000000..ebbb8de34 --- /dev/null +++ b/docs/fr-FR/welcome/release/20240519-changelog.md @@ -0,0 +1,185 @@ +# v1.0.0-alpha.15 : 2024.05.19 + +## Nouvelles fonctionnalités + +### Colonnes fixes dans les tableaux + +Référez-vous à [Colonnes fixes dans les tableaux](https://docs-cn.nocobase.com/handbook/ui/fields/generic/table-column#%E5%9B%BA%E5%AE%9A%E5%88%97) + +<img src="https://static-docs.nocobase.com/202405191512587.png"/> + +### Prise en charge de l'ajout de blocs Gantt et Kanban dans les fenêtres modales/volets + +Référez-vous à [Ajout de blocs dans les fenêtres modales](https://docs-cn.nocobase.com/handbook/ui/pop-up) + +<img src="https://static-docs.nocobase.com/202405191512280.png"/> + +### Prise en charge de l'ajout de règles de liaison dans les blocs de détails + +Les règles de liaison dans les blocs de détails prennent désormais en charge la définition dynamique des champs à afficher/masquer. Référez-vous à [Règles de liaison dans les blocs de détails](https://docs-cn.nocobase.com/handbook/ui/blocks/data-blocks/details#%E8%81%94%E5%8A%A8%E8%A7%84%E5%88%99) + +<img src="https://static-docs.nocobase.com/202405191513781.png"/> + +### Authentification : LDAP + +Ajout du plugin "Auth : LDAP" (plugin commercial), qui permet aux utilisateurs de se connecter à NocoBase en utilisant les identifiants du serveur LDAP. Référez-vous au [Manuel utilisateur](https://docs-cn.nocobase.com/handbook/auth-ldap) + +<img src="https://static-docs.nocobase.com/202405191513995.png"/> + +### Noeud de requête HTTP dans les workflows + +#### Prise en charge du format de données `application/www-x-form-urlencoded` + +Auparavant, le noeud de requête ne prenait en charge que le format JSON (`application/json`) pour la partie du corps de `Content-Type`. Après la mise à jour, il prend également en charge la configuration des données au format formulaire sous forme de paires clé-valeur. + +<img src="https://static-docs.nocobase.com/202405191514472.png"/> + +#### Prise en charge des modèles de chaînes pour les champs de saisie des valeurs + +Auparavant, les champs de saisie des valeurs dans les sections "En-têtes" et "Paramètres" du noeud de requête ne prenaient en charge que l'entrée pure ou la sélection de variables. Après la mise à jour, vous pouvez directement saisir une chaîne avec des variables intégrées. Celle-ci sera automatiquement analysée comme la valeur finale avant l'envoi de la requête. + +<img src="https://static-docs.nocobase.com/202405191514748.png"/> + +### Événement d'action personnalisé dans le workflow + +Le bouton d'action "Soumettre au Workflow", qui était initialement lié pour déclencher directement les événements de type "Post-action", a été séparé et créé indépendamment en tant que bouton d'action "Déclencher le Workflow" pour les "Événements d'action personnalisés" (plugin commercial). Les boutons d'action ajoutés précédemment dans la version open-source peuvent toujours être utilisés, mais ils ne seront plus pris en charge pour les nouveaux ajouts. Veuillez utiliser le nouvel "Événement d'action personnalisé". Consultez le [Manuel d'utilisation](https://docs-cn.nocobase.com/handbook/workflow-custom-action-trigger) pour plus d'informations. + +<img src="https://static-docs.nocobase.com/202405191515770.png"/> + +## Améliorations + +### Ajustements dans la configuration des actions + +#### Ajustements de l'interface utilisateur + +1. Hiérarchie du menu aplatie et suppression de certaines opérations de basculement, prise en charge de l'ajout répété. + +Avant : + +<img src="https://static-docs.nocobase.com/202405191516585.png"/> + +Après : + +<img src="https://static-docs.nocobase.com/202405191516026.png"/> + +2. Fusion des actions similaires + +2.1. Fusion des options "Ajouter nouveau" et "Ajouter un enregistrement" + +Avant : + +<img src="https://static-docs.nocobase.com/202405191516874.png"/> + +Après : + +<img src="https://static-docs.nocobase.com/202405191516737.png"/> + +2.2 Fusion des options "Soumettre" et "Enregistrer l'enregistrement" + +Avant : + +<img src="https://static-docs.nocobase.com/202405191517966.png"/> + +Après : + +<img src="https://static-docs.nocobase.com/202405191517078.png"/> + +#### Impact pour les développeurs + +Voir PR : <a href="https://github.com/nocobase/nocobase/pull/4336" target="_blank">refactor: flatten and merge Actions #4336</a> + +### Journaux + +#### Liste des fichiers du plugin de journalisation + +Avant : Dans un environnement multi-applications, le plugin de journalisation affichait la liste de tous les fichiers journaux des applications. + +Après : Dans un environnement multi-applications, le plugin de journalisation affiche uniquement la liste des fichiers journaux de l'application en cours. + +#### Chemins des dossiers de workflow et des requêtes personnalisées + +Avant : Le chemin du dossier pour les journaux de workflow et les requêtes personnalisées était au même niveau que le dossier des journaux de l'application. + +Après : Le chemin du dossier pour les journaux de workflow et les requêtes personnalisées appartient désormais au dossier des journaux de l'application correspondante. + +### Workflow + +#### Données du noeud de requête HTTP + +Auparavant, la structure des données de résultat après une requête HTTP réussie ou échouée était incohérente. + +```js +// Seules les données de réponse étaient renvoyées en cas de succès +{ + // Contenu JSON quelconque +} + +// L'échec renvoyait le résultat de la fonction Axios's error.toJSON(). +{ + config: {}, + headers: {}, + status: 500, + statusText: 'xxx', +} +``` + +Maintenant, la réponse pour le succès et l'échec sera stockée de manière cohérente dans le résultat du noeud. + +```js +// Succès +{ + config: {}, + headers: {}, + status: 200, + statusText: 'ok', + data: {} +} + +// Échec +{ + config: {}, + headers: {}, + status: 500, + statusText: 'xxx', + data: {} +} +``` + +D'autres exceptions, comme l'absence de réponse du serveur (`status` égal à `null`) ou une initialisation échouée, peuvent être observées dans les journaux du serveur pour le traitement des erreurs. Consultez plus de détails dans <a href="https://github.com/nocobase/nocobase/issues/4373" target="_blank">[Workflow : Nœuds de requête HTTP] Type de résultat de noeud non fixé #4373</a> + +## Corrections de bugs + +- Les champs de date dans les graphiques n'étaient pas convertis selon le fuseau horaire du client lors de l'agrégation des données avec une dimension de champ de date. <a href="https://github.com/nocobase/nocobase/pull/4366" target="_blank">fix(data-vi): should use local timezone when formatting date #4366</a> + +- Mauvaise actualisation des vues ; les vues de base de données doivent être fermées et rouvertes pour se rafraîchir. <a href="https://github.com/nocobase/nocobase/pull/4224" target="_blank">fix: collection fields should refreshed after editing sync from database #4224</a> + +- Les blocs de tableau d'arbre ne pliaient pas tous les nœuds lors de l'ajout d'un nœud enfant. <a href="https://github.com/nocobase/nocobase/pull/4289" target="_blank">fix: do not collapse all nodes when adding a child node in the tree table block #4289</a> + +- Le paramètre de titre de collection n'était pas valide. <a href="https://github.com/nocobase/nocobase/pull/4358" target="_blank">fix: collection title field setting is invalid #4358</a> + +- Le champ bigint perdait de la précision en mode "read pretty". <a href="https://github.com/nocobase/nocobase/pull/4360" target="_blank">fix: bigint field loses precision in read pretty mode #4360</a> + +- Les fichiers journaux restaient ouverts après l'arrêt des sous-applications. <a href="https://github.com/nocobase/nocobase/pull/4380" target="_blank">fix(logger): should close log stream after destroying app #4380</a> + +- Bug de sélection du champ d'association dans le noeud d'agrégation du workflow. <a href="https://github.com/nocobase/nocobase/pull/4315" target="_blank">fix(plugin-workflow-aggregate): fix association field select #4315</a> + +- L'option "Ignorer l'erreur" était invalide dans le mode de synchronisation du noeud de requête HTTP. < + +a href="https://github.com/nocobase/nocobase/pull/4334" target="_blank">fix(plugin-workflow-request): fix ignoreFail in sync mode #4334</a> + +- Les champs de saisie de valeur dans le noeud de requête HTTP du workflow débordaient. <a href="https://github.com/nocobase/nocobase/pull/4353" target="_blank">fix(plugin-workflow-request): fix value fields overflowing #4354</a> + +- Les caractères spéciaux entraînaient le blocage du noeud de requête HTTP du workflow. <a href="https://github.com/nocobase/nocobase/pull/4376" target="_blank">fix(plugin-workflow-request): fix request hanging when invalid header value #4376</a> + +- Le paramètre `marginBlock` dans l'éditeur de thème affectait l'espacement entre les champs de formulaire. <a href="https://github.com/nocobase/nocobase/pull/4374" target="_blank">fix(theme-editor): form field spacing should not be affected by token.marginBlock #4374</a> + +- Problème de redirection incorrecte lors du clic sur l'option "Licence" dans le coin supérieur droit de la page. [PR #4415](https://github.com/nocobase/nocobase/pull/4415) + +- Problème où l'opérateur du champ devenait invalide après avoir enregistré le formulaire de filtre en tant que modèle de bloc. [PR #4390](https://github.com/nocobase/nocobase/pull/4390) + +## Documentation + +- Documentation ajoutée pour les exemples de plugins : https://docs-cn.nocobase.com/plugin-samples + +- Mise à jour de la structure de la documentation pour le manuel d'utilisation des workflows : https://docs-cn.nocobase.com/handbook/workflow + diff --git a/docs/fr-FR/welcome/release/6de7c906518b6c6643570292523b06c8.png b/docs/fr-FR/welcome/release/6de7c906518b6c6643570292523b06c8.png new file mode 100644 index 000000000..b16f60154 Binary files /dev/null and b/docs/fr-FR/welcome/release/6de7c906518b6c6643570292523b06c8.png differ diff --git a/docs/fr-FR/welcome/release/703809b8cd74cc95e1ab2ab766980817.gif b/docs/fr-FR/welcome/release/703809b8cd74cc95e1ab2ab766980817.gif new file mode 100644 index 000000000..9ae9417be Binary files /dev/null and b/docs/fr-FR/welcome/release/703809b8cd74cc95e1ab2ab766980817.gif differ diff --git a/docs/fr-FR/welcome/release/collection-templates.md b/docs/fr-FR/welcome/release/collection-templates.md new file mode 100644 index 000000000..b0daf6f88 --- /dev/null +++ b/docs/fr-FR/welcome/release/collection-templates.md @@ -0,0 +1,93 @@ +# v0.9.0 : **Modèles de Collection** + +<img src="./v08-1-collection-templates/v08-1-collection-templates.jpg"> + +## Pourquoi avons-nous besoin de modèles de collection ? + +Les modèles de collection offrent une manière standardisée et réutilisable de définir et configurer différents types de collections de données. Grâce aux modèles de collection, vous pouvez simplifier et unifier le processus de création et de configuration des collections, ce qui rend la gestion et la construction des données sur NocoBase plus efficace et cohérente. Les modèles prennent en charge la personnalisation des types de champs, des configurations de champs et des paramètres optionnels, ce qui améliore la flexibilité et l'extensibilité du système. + +## Explication des paramètres de configuration + +L'interface `ICollectionTemplate` est la structure principale de configuration pour les modèles de collection, vous permettant de définir les propriétés du modèle, les champs configurables et les types de champs disponibles. Voici une explication détaillée de l'interface `ICollectionTemplate` : + +```ts +interface ICollectionTemplate { + name: string; // Nom du modèle, requis + title?: string; // Titre du modèle, généralement utilisé pour l'affichage dans l'UI + /** Tri */ + order?: number; // Ordre d'affichage du modèle + /** Configuration par défaut */ + default?: CollectionOptions; // Paramètres par défaut + /** Paramètres de CollectionOptions configurables via l'UI (champs du formulaire de création ou d'édition de Collection) */ + configurableProperties?: Record<string, ISchema>; // Définition des champs configurables + /** Types de champs disponibles pour ce modèle */ + availableFieldInterfaces?: + | AvailableFieldInterfacesInclude // Champs inclus + | AvailableFieldInterfacesExclude; // Champs exclus +} + +interface AvailableFieldInterfacesInclude { + include?: any[]; // Types de champs à afficher +} + +interface AvailableFieldInterfacesExclude { + exclude?: any[]; // Types de champs à exclure +} + +interface CollectionOptions { + /** + * Génération automatique de l'id + * @default true + * */ + autoGenId?: boolean; // Si true, l'ID est généré automatiquement (par défaut true) + /** Créé par */ + createdBy?: boolean; // Si true, l'auteur de la création est enregistré + /** Dernière mise à jour par */ + updatedBy?: boolean; // Si true, l'auteur de la dernière mise à jour est enregistré + /** Date de création */ + createdAt?: boolean; // Si true, la date de création est enregistrée + /** Date de mise à jour */ + updatedAt?: boolean; // Si true, la date de la dernière mise à jour est enregistrée + /** Tri activé */ + sortable?: boolean; // Si true, le tri est activé pour la collection + /* Structure d'arbre */ + tree?: string; // Support pour les structures de type arbre + /* Journalisation */ + logging?: boolean; // Si true, l'enregistrement des logs est activé + /** Héritage */ + inherits: string | string[]; // Hérite des champs d'autres collections + /* Liste des champs */ + fields?: FieldOptions[]; // Configuration des champs +} +``` + +### Explication des principaux champs + +- **name** : Identifiant unique du modèle. +- **title** : Titre du modèle, utilisé pour l'affichage dans l'interface utilisateur, non requis. +- **order** : Paramètre de tri, permet de contrôler l'ordre d'affichage du modèle dans l'interface. +- **default** : Configuration par défaut du modèle, incluant la génération automatique de l'ID, les valeurs par défaut des champs, etc. +- **configurableProperties** : Paramètres configurables via l'interface utilisateur. Ces champs permettent à l'utilisateur de personnaliser les configurations du modèle. +- **availableFieldInterfaces** : Configuration des types de champs disponibles pour ce modèle, en incluant ou excluant certains types de champs. + +## Exemple + +Imaginons que nous souhaitons créer un modèle sans génération automatique de l'ID, avec seulement les champs `title` et `name` configurables. + +```ts +import { collectionConfigurableProperties } from '@nocobase/client'; + +{ + default: { + autoGenId: false, // Désactiver la génération automatique de l'ID + fields: [], // Aucun champ par défaut + }, + configurableProperties: { + ...collectionConfigurableProperties('name', 'title'), // Configurer uniquement 'name' et 'title' + }, +} +``` + +### Exemple complet du plugin + +Vous pouvez consulter l'exemple complet d'un plugin personnalisé pour les modèles de collection à l'adresse suivante : [samples/custom-collection-template](https://github.com/nocobase/nocobase/tree/feat/collection-templates/packages/samples/custom-collection-template). diff --git a/docs/fr-FR/welcome/release/formulas.md b/docs/fr-FR/welcome/release/formulas.md new file mode 100644 index 000000000..4e2f5ff49 --- /dev/null +++ b/docs/fr-FR/welcome/release/formulas.md @@ -0,0 +1,40 @@ +# v0.9.0 : Plugin de Formules de Champ + +NocoBase propose actuellement deux plugins pour la gestion des formules de calculs dans les champs de données : + +- `@nocobase/plugin-math-formula-field` : Formules Mathématiques +- `@nocobase/plugin-excel-formula-field` : Formules Excel (merci à [azriel46d](https://github.com/nocobase/nocobase/pull/906) pour cette contribution) + +## Formule Mathématique + +Le plugin **Math Formula** est basé sur [Math.js](https://mathjs.org/), un puissant moteur de calcul qui prend en charge des expressions mathématiques complexes, incluant des calculs symboliques, une large gamme de fonctions et de constantes intégrées, ainsi que des solutions pour gérer différents types de données comme les nombres, grands nombres, nombres complexes, fractions, unités et matrices. + +### Exemple d'utilisation + +```ts +import { evaluate } from 'mathjs'; + +// Expressions de test +evaluate('1.2 * (2 + 4.5)'); // 7.8 +evaluate('12.7 cm to inch'); // 5 inch +evaluate('sin(45 deg) ^ 2'); // 0.5 +evaluate('9 / 3 + 2i'); // 3 + 2i +evaluate('det([-1, 2; 3, 1])'); // -7 +``` + +**Capture d'écran :** Formule mathématique dans NocoBase +<img src="./formulas/math-form.jpg" /> + +## Formule Excel + +Le plugin **Excel Formula** est basé sur [Formula.js](https://formulajs.info/), une bibliothèque JavaScript qui émule les formules d'Excel. Il permet l’utilisation de fonctions similaires à celles que l’on trouve dans une feuille de calcul Excel, offrant ainsi une flexibilité pour effectuer des calculs et manipulations de données de manière simple. + +### Exemple d'utilisation + +```ts +SUM(-5, 15, 32); // 42 +IF(true, 'Hello!', 'Goodbye!'); // Hello! +``` + +**Capture d'écran :** Formule Excel dans NocoBase +<img src="./formulas/excel-form.jpg" /> diff --git a/docs/fr-FR/welcome/release/formulas/excel-form.jpg b/docs/fr-FR/welcome/release/formulas/excel-form.jpg new file mode 100644 index 000000000..41413a0c4 Binary files /dev/null and b/docs/fr-FR/welcome/release/formulas/excel-form.jpg differ diff --git a/docs/fr-FR/welcome/release/formulas/math-form.jpg b/docs/fr-FR/welcome/release/formulas/math-form.jpg new file mode 100644 index 000000000..ecf54c476 Binary files /dev/null and b/docs/fr-FR/welcome/release/formulas/math-form.jpg differ diff --git a/docs/fr-FR/welcome/release/gantt/introduction.md b/docs/fr-FR/welcome/release/gantt/introduction.md new file mode 100644 index 000000000..8396c1be7 --- /dev/null +++ b/docs/fr-FR/welcome/release/gantt/introduction.md @@ -0,0 +1,21 @@ +# Bloc Gantt + +## Créer un bloc Gantt + +![](https://static-docs.nocobase.com/c87178922308143656bc444c57bac45d.png) + +## Bloc Gantt (Aucune donnée) + +![](https://static-docs.nocobase.com/1b439225f12b7a09aaab9d3a6dc11215.png) + +## Paramètres du bloc + +![](https://static-docs.nocobase.com/e3b1950ca356fd58b4e1b644067337e4.png) + +## Tâches générales + +![](https://static-docs.nocobase.com/4bb22d6c98dc5f4e0a27aecd67a0e586.png) + +## Tâches en arbre + +![](https://static-docs.nocobase.com/672625d0238dbd685f3e1c1ef810024f.png) diff --git a/docs/fr-FR/welcome/release/gantt/static/IwJzb9PsFovXwZxNqJnc6HaFnyg.png b/docs/fr-FR/welcome/release/gantt/static/IwJzb9PsFovXwZxNqJnc6HaFnyg.png new file mode 100644 index 000000000..a8893aa82 Binary files /dev/null and b/docs/fr-FR/welcome/release/gantt/static/IwJzb9PsFovXwZxNqJnc6HaFnyg.png differ diff --git a/docs/fr-FR/welcome/release/gantt/static/UxT7b8mVCo1isIxrsjtcZ8hpnlf.png b/docs/fr-FR/welcome/release/gantt/static/UxT7b8mVCo1isIxrsjtcZ8hpnlf.png new file mode 100644 index 000000000..2d309ad42 Binary files /dev/null and b/docs/fr-FR/welcome/release/gantt/static/UxT7b8mVCo1isIxrsjtcZ8hpnlf.png differ diff --git a/docs/fr-FR/welcome/release/gantt/static/V9w1b43YsoIRYpxtFdscpf2MnQf.png b/docs/fr-FR/welcome/release/gantt/static/V9w1b43YsoIRYpxtFdscpf2MnQf.png new file mode 100644 index 000000000..c454d0c43 Binary files /dev/null and b/docs/fr-FR/welcome/release/gantt/static/V9w1b43YsoIRYpxtFdscpf2MnQf.png differ diff --git a/docs/fr-FR/welcome/release/gantt/static/VGTZbOs38obgyqxm5YfcGS1Vnhb.png b/docs/fr-FR/welcome/release/gantt/static/VGTZbOs38obgyqxm5YfcGS1Vnhb.png new file mode 100644 index 000000000..4e93257fd Binary files /dev/null and b/docs/fr-FR/welcome/release/gantt/static/VGTZbOs38obgyqxm5YfcGS1Vnhb.png differ diff --git a/docs/fr-FR/welcome/release/gantt/static/VM3qbBhLeoEcKwxwAZkcRHBynOd.png b/docs/fr-FR/welcome/release/gantt/static/VM3qbBhLeoEcKwxwAZkcRHBynOd.png new file mode 100644 index 000000000..901010eff Binary files /dev/null and b/docs/fr-FR/welcome/release/gantt/static/VM3qbBhLeoEcKwxwAZkcRHBynOd.png differ diff --git a/docs/fr-FR/welcome/release/gantt/static/YJZZb0aO3oG9n6x4aZwcAB07nng.png b/docs/fr-FR/welcome/release/gantt/static/YJZZb0aO3oG9n6x4aZwcAB07nng.png new file mode 100644 index 000000000..a603d847c Binary files /dev/null and b/docs/fr-FR/welcome/release/gantt/static/YJZZb0aO3oG9n6x4aZwcAB07nng.png differ diff --git a/docs/fr-FR/welcome/release/index.md b/docs/fr-FR/welcome/release/index.md new file mode 100644 index 000000000..5bd13f9f1 --- /dev/null +++ b/docs/fr-FR/welcome/release/index.md @@ -0,0 +1 @@ +<Release></Release> \ No newline at end of file diff --git a/docs/fr-FR/welcome/release/inherits.md b/docs/fr-FR/welcome/release/inherits.md new file mode 100644 index 000000000..861611cb1 --- /dev/null +++ b/docs/fr-FR/welcome/release/inherits.md @@ -0,0 +1,75 @@ +# v0.9.0 : Héritage des tables de données + +L'héritage des tables de données est basé sur la syntaxe [INHERITS de PostgreSQL](https://www.postgresql.org/docs/current/tutorial-inheritance.html) et n'est disponible que lorsque NocoBase est installé avec une base de données PostgreSQL. + +## Exemple + +Commençons par un exemple. Supposons que nous devions créer un système de gestion scolaire avec trois types d'utilisateurs : étudiants, parents et enseignants. + +Sans l'héritage, nous devrions créer une table pour chaque type d'utilisateur : + +- Étudiant : Nom, Âge, Sexe, Numéro de carte d'identité +- Parent : Nom, Âge, Sexe, Profession, Niveau d'études +- Enseignant : Nom, Âge, Sexe, Ancienneté, Marié + +Avec l'héritage des tables de données, nous pouvons extraire les informations communes : + +- Utilisateur : Nom, Âge, Sexe +- Étudiant : Numéro de carte d'identité +- Parent : Profession, Niveau d'études +- Enseignant : Ancienneté, Marié + +Voici le diagramme ER (Entité-Relation) : + +<img src="./inherits/er.svg" style="max-width: 700px;" /> + +**Note** : Les ID des tables enfants et des tables parentes partagent la même séquence. + +## Configurer l'héritage des tables de données + +Le champ `Inherits` permet de sélectionner la table parent à hériter. + +<img src="./inherits/inherit.jpg" /> + +Exemple de configuration via le code : + +```ts +db.collection({ + name: 'users', +}); + +db.collection({ + name: 'students', + inherits: 'users', +}); +``` + +### Points importants : + +- La table héritée ne peut pas être choisie de manière arbitraire. La clé primaire doit être une séquence unique, par exemple un UUID ou une séquence auto-incrémentée partagée par toutes les tables de l'héritage. +- Le paramètre `Inherits` ne peut pas être modifié après sa configuration. +- Si une relation d'héritage existe, la table parent ne peut pas être supprimée. + +## Liste des champs des tables de données + +La liste des champs des tables de données affichera les champs hérités de la table parent. Ces champs parent ne peuvent pas être modifiés, mais peuvent être réécrits (Override). + +<img src="./inherits/inherit-fields.jpg" /> + +### Points à retenir lors de la réécriture des champs parent : + +- Un champ dans la table enfant avec le même nom que le champ parent est considéré comme une réécriture. +- Le type du champ réécrit doit être cohérent avec le type du champ parent. +- Les paramètres des champs de relation, à l'exception de la collection cible, doivent rester identiques. + +## Bloc des sous-tableaux de la table parent + +Dans le bloc de la table parent, il est possible de configurer des blocs pour les tables enfants. + +<img src="./inherits/inherited-blocks.jpg" /> + +## Nouvelle configuration des champs hérités de la table parent + +Lorsqu'une table héritée est présente, les champs hérités de la table parent seront configurables. + +<img src="./inherits/configure-fields.jpg" /> diff --git a/docs/fr-FR/welcome/release/inherits/configure-fields.jpg b/docs/fr-FR/welcome/release/inherits/configure-fields.jpg new file mode 100644 index 000000000..adf256da3 Binary files /dev/null and b/docs/fr-FR/welcome/release/inherits/configure-fields.jpg differ diff --git a/docs/fr-FR/welcome/release/inherits/er.svg b/docs/fr-FR/welcome/release/inherits/er.svg new file mode 100644 index 000000000..f1ba5c251 --- /dev/null +++ b/docs/fr-FR/welcome/release/inherits/er.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than diagrams.net --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="866px" height="541px" viewBox="-0.5 -0.5 866 541" content="<mxfile host="app.diagrams.net" modified="2022-11-16T02:45:35.466Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" version="20.5.3" etag="r3dIv0wwxGSoXKs5LQh3" type="device"><diagram id="sQ-S40tc_4f1Dr5c1EA7" name="Page-1">7V1db6M4FP01eewIAiTp4yZtd6VtV1UzszP7tHKDm1hDcGScNplfvzbY4cMlAW0SnNhSpOKLuRjfYx98D9CeN1lufidgtXjCIYx6fSfc9Ly7Xr/v+v0B+8Mt28xy4w08YZoTFIpquWGKfkFhdIR1jUKYlCpSjCOKVmXjDMcxnNGSDRCCP8rV3nBUPusKzKFimM5ApFq/o5AuMusocHL7HxDNF/LMriP2LIGsLAzJAoT4o2Dy7nvehGBMs63lZgIj3n2yX7LjHmr27hpGYEybHPD6+HOBh+F7/9/k29P44Wa2Hfx94/qZm3cQrcUVf0sgSUST6Vb2A2v9im9S8MpN44QCQkW4PIcZWAAoQDEkzOCm5SgCqwSl1TPLAkXhI9jiNZWOZGn8hjYwfMmixeuywD0yZ7zInb8x51PRGL4bRGges+0Zu3Z+xjGBCWvLI0jozsE6DmEoSru+586Sn5DOFmIP9/wAlijiCJ3gJZqx656CmPWA8zRlFUT/QELhprbn3V082VCAeAkp2bIq4oC+H2SHiFHg3w4EJj5ySLkjYVsU4SQrAgHj+c757nwvDPYgnrO+yU84dEondG9d9YSfnc+rnA5ErHtjQOGYd2dSxBfbKFxrbkpR1waBgYLA/eB74YEcLzBBvzjkIhnVAiDT8gdaRiBmoxOEFdMYp/NRCiwURRMcYY7aGMdQAS6vFBK8+grIHFJhWGEU07SLgjH7sU6bOF+CXsDaOmFlNy+zH69O6ATHCSVsgHAfkOH0A3KsjileCacRfJP+iYgI337FlOJlU7SWsN0IunumBRXQ2zJMDsG3Cqcieks4ag2agQKa5z9rYcMulyIQ5QMlna04XYA8yJ8g4dPY7OJRDVR1jsKs49+idNZZoDCE8TnjF3wev0LAvJbx+mS2aentHJPJUMEFq98tLiRXZXXHyQrMUDx/zI4cVIATaAqcTf3AD44KpEbuzoGkkaWlRrTknBOd+2mp6V3V6WjptjlozjP5wBBJf51z0shMTpLrvwIoYrCEurOSjlAxjoVkj1kWuhwWuu2ahSRGLAvVjigDWchTQMEzn9dIQsX1lJLvOz5yzCMlNWdsSUlzUnL7nbNSizyveaxUE72rZyU1jzuHcQjJVRLTicFiHhGp2d4pXbNg0MvXL0tYKYuZB3E2JyBEzHNlCEgyfVBHRyMw7r//GUkAnEvkDC5I5OzbbLJ+Imc2fegrcvbVbLIVOZVBZd5NkzylFTmPDBzjbqA8m17WbyV/gJY6Fzk9m14+NKIM5CQ1vYz4QgzR7V/r5asJC/py2vnoCDKPnGya+eLIqXPt07NZ5kMjykByUrPM109Hx4eJeQyk5pctA2nOQN0LnV6LXK95FFQTvaunIO2eDNabgmpgYhwF+WquV8ENDOdQLjyzJfcLjABFOL7P92TL04yD3D5nKbqMRJxgHP7GX5VlxVeQwDuQLHpF0bH99M48cpVRHJu1mDezFgXClOA1mcF9s7+YXKnkvLqKDd6A2r2qWxIjpZGkffhebvIeID1z4s0hunvtV/BS4LoV9GTXKg7LkaN48ivCauAMK56yzlA8HQ2Dapb4OQ2dVdnPrrIHgzIY/OGo4f2OASq73yIzbfT9+jlVdr8G0Lqo7L6aubYquzKozLtj99X0s1XZjwEc8+7h7Rcu9EsjHaClzlV2X7uctUZZJN/Qz1v4akIaz2brVbrY152bdASMeVxkH0Q+IhedjH4619F97fLVx6Cf/xEvQ581ltOWPjg4Dc8cHxnGUUtgHya+BGrpXiAPWqRpTeCWwNBnhgM182q5pREyzOOWBs8C6yiDbxD9IecYtv0P3/4SiNLdprDrThIZazrZ/tg1iRUKR/Fiflhayo87keQuVTXtJfeqNho48tvCrSV3v+LJdSqeTiy5B2rK+CsEs8U1fJn74jX3wLFvtudIbZGnNvqu/5yae1AzE+uiuQdqHttq7sqgMnBFoGanreZ+DOCYt2Bokb82mpbOqbkfoKXONXfZAH0SEhpp7tmIMo+TBmpaewkIQVB7YtIRLcYR0aBFstsSkR5E1Ln6PtAuM64REWUjykAiavE9DMtAtTAxj4Hs48cXx0Ddi/QD+/zxoSFlIAW1+CCGpaBamJhHQQ2eOtZRvj+VpC5FM5MldWd4LEmdFfP/op1Vz/8buXf/Hw==</diagram></mxfile>" style="background-color: rgb(255, 255, 255);"><defs><clipPath id="mx-clip-50-260-30-30-0"><rect x="50" y="260" width="30" height="30"/></clipPath><clipPath id="mx-clip-86-260-144-30-0"><rect x="86" y="260" width="144" height="30"/></clipPath><clipPath id="mx-clip-86-290-144-30-0"><rect x="86" y="290" width="144" height="30"/></clipPath><clipPath id="mx-clip-86-320-144-30-0"><rect x="86" y="320" width="144" height="30"/></clipPath><clipPath id="mx-clip-86-350-144-30-0"><rect x="86" y="350" width="144" height="30"/></clipPath><clipPath id="mx-clip-635-260-30-30-0"><rect x="635" y="260" width="30" height="30"/></clipPath><clipPath id="mx-clip-671-260-144-30-0"><rect x="671" y="260" width="144" height="30"/></clipPath><clipPath id="mx-clip-671-290-144-30-0"><rect x="671" y="290" width="144" height="30"/></clipPath><clipPath id="mx-clip-365-80-30-30-0"><rect x="365" y="80" width="30" height="30"/></clipPath><clipPath id="mx-clip-401-80-144-30-0"><rect x="401" y="80" width="144" height="30"/></clipPath><clipPath id="mx-clip-401-110-144-30-0"><rect x="401" y="110" width="144" height="30"/></clipPath><clipPath id="mx-clip-365-360-30-30-0"><rect x="365" y="360" width="30" height="30"/></clipPath><clipPath id="mx-clip-401-360-144-30-0"><rect x="401" y="360" width="144" height="30"/></clipPath><clipPath id="mx-clip-401-390-144-30-0"><rect x="401" y="390" width="144" height="30"/></clipPath></defs><g><path d="M 230 260 L 230 243.5 Q 230 230 216.5 230 L 63.5 230 Q 50 230 50 243.5 L 50 260" fill="none" stroke="none" pointer-events="all"/><path d="M 228.39 260.64 L 227.53 238.36 L 223.16 231.4 L 217.34 231.16 L 59.74 228.53 L 56.62 230.92 L 49.91 237.56 L 49.97 261.69" fill="rgb(255, 255, 255)" stroke="none" pointer-events="none"/><path d="M 230 260 M 230 260 C 231.43 255.65 230.98 251.52 230 243.5 M 230 260 C 229.56 255.61 229.45 249.91 230 243.5 M 230 243.5 C 228.22 233.07 225.8 230.4 216.5 230 M 230 243.5 C 231.97 232.99 223.85 228.33 216.5 230 M 216.5 230 C 172.04 227.79 128.6 227.66 63.5 230 M 216.5 230 C 168.31 230.62 119.43 230.36 63.5 230 M 63.5 230 C 54 229.15 48.49 234.8 50 243.5 M 63.5 230 C 55.1 231.22 51.95 235.47 50 243.5 M 50 243.5 C 50.04 247.74 48.98 251.54 50 260 M 50 243.5 C 50.04 248.12 50.28 252.03 50 260" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 50 260 M 50 260 C 51.14 283.98 49.88 311.93 50 376.5 M 50 260 C 50.33 301.22 49.19 343.41 50 376.5 M 50 376.5 C 49.97 387.19 52.78 391.74 63.5 390 M 50 376.5 C 50.99 387.7 53.36 391.57 63.5 390 M 63.5 390 C 95.23 389.88 130.18 389.62 216.5 390 M 63.5 390 C 101.69 391.29 140.44 390.43 216.5 390 M 216.5 390 C 224.06 388.55 229.7 384.71 230 376.5 M 216.5 390 C 223.83 389.03 228.74 384.73 230 376.5 M 230 376.5 C 231.45 349.56 228.5 321.25 230 260 M 230 376.5 C 229.53 352.32 230.55 328.38 230 260" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 50 260 M 50 260 C 90.24 259.9 128.45 262.3 230 260 M 50 260 C 115.12 261.02 178.43 261.5 230 260" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 80 260 M 80 260 C 80.86 265.01 79.6 273.99 80 290 M 80 260 C 80.58 270.25 79.44 281.47 80 290 M 80 290 C 82 299.81 82.17 306.91 80 320 M 80 290 C 78.9 300.51 79.04 312.64 80 320 M 80 320 C 78.42 326.79 80.25 334.7 80 350 M 80 320 C 79.64 326.63 79.06 333.63 80 350 M 80 350 C 80.26 357.51 81.56 365.57 80 380 M 80 350 C 79.8 356.63 79.29 364.26 80 380" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="139.5" y="249.5">Users</text></g><path d="M 50 260 M 230 260 M 230 290 M 230 290 C 190.15 292.1 152.24 290.7 50 290 M 230 290 C 188.46 289.29 147.49 288.98 50 290" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 50 260 M 80 260 M 80 290 M 50 290" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" pointer-events="none" clip-path="url(#mx-clip-50-260-30-30-0)" text-anchor="middle" font-size="12px"><text x="64.5" y="279.5">PK</text></g><path d="M 80 260 M 230 260 M 230 290 M 80 290" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" text-decoration="underline" pointer-events="none" clip-path="url(#mx-clip-86-260-144-30-0)" font-size="12px"><text x="87.5" y="279.5">id</text></g><path d="M 50 290 M 80 290 M 80 320 M 50 320" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 80 290 M 230 290 M 230 320 M 80 320" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" pointer-events="none" clip-path="url(#mx-clip-86-290-144-30-0)" font-size="12px"><text x="87.5" y="309.5">name</text></g><path d="M 50 320 M 80 320 M 80 350 M 50 350" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 80 320 M 230 320 M 230 350 M 80 350" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" pointer-events="none" clip-path="url(#mx-clip-86-320-144-30-0)" font-size="12px"><text x="87.5" y="339.5">age</text></g><path d="M 50 350 M 80 350 M 80 380 M 50 380" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 80 350 M 230 350 M 230 380 M 80 380" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" pointer-events="none" clip-path="url(#mx-clip-86-350-144-30-0)" font-size="12px"><text x="87.5" y="369.5">gender</text></g><path d="M 813.39 260.2 L 814.31 239.51 L 808.93 232.53 L 801.89 228.12 L 645.92 229.55 L 638.96 233.44 L 635.39 238.91 L 634.86 259.68" fill="rgb(255, 255, 255)" stroke="none" pointer-events="none"/><path d="M 815 260 M 815 260 C 813.68 254.54 815.37 248.34 815 243.5 M 815 260 C 814.48 254.03 814.91 249.27 815 243.5 M 815 243.5 C 813.44 236.35 809.24 228.91 801.5 230 M 815 243.5 C 813.99 232.78 809.13 230.23 801.5 230 M 801.5 230 C 755.39 229.04 706.55 231.89 648.5 230 M 801.5 230 C 770.84 231.98 739.47 231.58 648.5 230 M 648.5 230 C 637.96 231.59 635.77 234.42 635 243.5 M 648.5 230 C 639.96 230.97 636.77 233.43 635 243.5 M 635 243.5 C 634.44 249.29 636.16 254.08 635 260 M 635 243.5 C 634.37 248.76 635.27 254.25 635 260" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 635 260 M 635 260 C 637.03 284.77 635.75 311.51 635 376.5 M 635 260 C 634.68 284.75 635.11 308.62 635 376.5 M 635 376.5 C 634.86 385.18 639.66 391.08 648.5 390 M 635 376.5 C 633.55 383.78 638.98 390.64 648.5 390 M 648.5 390 C 679.73 387.72 711.04 388.76 801.5 390 M 648.5 390 C 692.61 388.04 737.53 387.84 801.5 390 M 801.5 390 C 809.31 390.2 815.16 386.22 815 376.5 M 801.5 390 C 811.2 391.16 813.36 384.68 815 376.5 M 815 376.5 C 817.55 334.82 817.84 291.73 815 260 M 815 376.5 C 816.28 336.07 816.1 296.14 815 260" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 635 260 M 635 260 C 676.41 259.07 714.63 260.25 815 260 M 635 260 C 671.4 261.37 708.88 261.26 815 260" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 665 260 M 665 260 C 666.95 265.79 665.67 273.55 665 290 M 665 260 C 664.43 266.94 664.86 273.01 665 290 M 665 290 C 666.03 297.52 663.46 307.12 665 320 M 665 290 C 665.64 299.43 664.28 308.89 665 320 M 665 320 C 666.83 327.98 663.89 337.59 665 350 M 665 320 C 664.9 327.11 665.12 334.01 665 350 M 665 350 C 663.01 356.28 666.34 365.32 665 380 M 665 350 C 664.5 362.4 665.65 373.18 665 380" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="724.5" y="249.5">Students</text></g><path d="M 635 260 M 815 260 M 815 290 M 815 290 C 776.27 286.87 734.32 288.25 635 290 M 815 290 C 765.53 291.47 715.52 290.58 635 290" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 635 260 M 665 260 M 665 290 M 635 290" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" pointer-events="none" clip-path="url(#mx-clip-635-260-30-30-0)" text-anchor="middle" font-size="12px"><text x="649.5" y="279.5">PK</text></g><path d="M 665 260 M 815 260 M 815 290 M 665 290" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" text-decoration="underline" pointer-events="none" clip-path="url(#mx-clip-671-260-144-30-0)" font-size="12px"><text x="672.5" y="279.5">id</text></g><path d="M 635 290 M 665 290 M 665 320 M 635 320" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 665 290 M 815 290 M 815 320 M 665 320" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" pointer-events="none" clip-path="url(#mx-clip-671-290-144-30-0)" font-size="12px"><text x="672.5" y="309.5">identityNumber</text></g><path d="M 635 320 M 665 320 M 665 350 M 635 350" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 665 320 M 815 320 M 815 350 M 665 350" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 635 350 M 665 350 M 665 380 M 635 380" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 665 350 M 815 350 M 815 380 M 665 380" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 635 275 M 635 275 C 627.47 273.29 622.87 273.43 605 275 M 635 275 C 623.17 275.77 613.28 274.66 605 275 M 605 275 C 527.68 272.14 449.16 274.42 260 275 M 605 275 C 478.24 275.19 351.17 274.92 260 275 M 260 275 C 248.6 275.66 234.68 274.48 230 275 M 260 275 C 252.14 274.8 244.4 273.75 230 275" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 230 271 M 230 271 C 229.58 272.05 230.38 273.86 230 279 M 230 271 C 229.63 274.13 230.06 276.61 230 279" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 543.39 79.25 L 543.01 59.52 L 540.91 50.63 L 533.02 48.75 L 375.03 49.1 L 370.93 53.35 L 367.82 59.27 L 364.21 81.31" fill="rgb(255, 255, 255)" stroke="none" pointer-events="none"/><path d="M 545 80 M 545 80 C 546.5 72.71 545.7 69.3 545 63.5 M 545 80 C 545.52 74.43 545.49 68.91 545 63.5 M 545 63.5 C 543.55 54.22 538.56 49.51 531.5 50 M 545 63.5 C 543.14 54.87 540.67 48.48 531.5 50 M 531.5 50 C 491.28 48.88 449.65 47.72 378.5 50 M 531.5 50 C 491.33 50.03 449 49.64 378.5 50 M 378.5 50 C 370.71 50.43 363.17 55.44 365 63.5 M 378.5 50 C 371.62 51.92 364.86 53.32 365 63.5 M 365 63.5 C 363.86 68.73 363.55 72.05 365 80 M 365 63.5 C 364.55 67.6 364.7 70.42 365 80" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 365 80 M 365 80 C 366.49 106.78 363.29 132.71 365 196.5 M 365 80 C 365.15 108.39 365.81 136.17 365 196.5 M 365 196.5 C 364.21 206.81 370.88 210.21 378.5 210 M 365 196.5 C 365.47 207.61 367.83 211 378.5 210 M 378.5 210 C 439.34 211.63 497.7 211.53 531.5 210 M 378.5 210 C 424.29 209.97 471.21 210.37 531.5 210 M 531.5 210 C 540.65 208.68 544.27 205.89 545 196.5 M 531.5 210 C 538.6 210.08 545.17 204.05 545 196.5 M 545 196.5 C 545.78 169.12 544.82 137.42 545 80 M 545 196.5 C 543.38 169.87 545.22 143.13 545 80" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 365 80 M 365 80 C 406.47 82.22 442.82 82.56 545 80 M 365 80 C 408.08 81.72 451.49 81.83 545 80" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 395 80 M 395 80 C 396.81 87.78 393.62 94.7 395 110 M 395 80 C 395.28 87.85 395.94 95.09 395 110 M 395 110 C 395.41 118.22 397.03 124.17 395 140 M 395 110 C 394.95 120.93 395.84 130.61 395 140 M 395 140 C 394.74 148.64 394.53 159.53 395 170 M 395 140 C 394.66 149.68 394.2 159 395 170 M 395 170 C 394.17 177.43 395.22 190.07 395 200 M 395 170 C 395.45 178.38 393.93 186.8 395 200" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="454.5" y="69.5">Parents</text></g><path d="M 365 80 M 545 80 M 545 110 M 545 110 C 506.24 111.28 466.32 111.82 365 110 M 545 110 C 488.82 111.03 433.34 110.36 365 110" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 365 80 M 395 80 M 395 110 M 365 110" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" pointer-events="none" clip-path="url(#mx-clip-365-80-30-30-0)" text-anchor="middle" font-size="12px"><text x="379.5" y="99.5">PK</text></g><path d="M 395 80 M 545 80 M 545 110 M 395 110" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" text-decoration="underline" pointer-events="none" clip-path="url(#mx-clip-401-80-144-30-0)" font-size="12px"><text x="402.5" y="99.5">id</text></g><path d="M 365 110 M 395 110 M 395 140 M 365 140" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 395 110 M 545 110 M 545 140 M 395 140" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" pointer-events="none" clip-path="url(#mx-clip-401-110-144-30-0)" font-size="12px"><text x="402.5" y="129.5">occupation</text></g><path d="M 365 140 M 395 140 M 395 170 M 365 170" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 395 140 M 545 140 M 545 170 M 395 170" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 365 170 M 395 170 M 395 200 M 365 200" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 395 170 M 545 170 M 545 200 M 395 200" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 365 95 M 365 95 C 357.47 97.05 351.67 96.17 335 95 M 365 95 C 357.44 94.97 347.11 94.5 335 95 M 335 95 C 314.8 138.9 294.57 185.57 260 275 M 335 95 C 313.23 150.82 291.88 205.32 260 275 M 260 275 C 251.68 275.32 243.38 274.6 230 275 M 260 275 C 250.65 276 241.79 276.01 230 275" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 230 271 M 230 271 C 229.58 273.54 229.9 274.95 230 279 M 230 271 C 230.43 273.28 229.72 275.37 230 279" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 543.4 359.16 L 543.19 339.52 L 540.65 333.44 L 531.73 331.15 L 376.47 331.33 L 370.66 332.3 L 365.84 339.49 L 364.8 361.83" fill="rgb(255, 255, 255)" stroke="none" pointer-events="none"/><path d="M 545 360 M 545 360 C 545.83 356.51 544.71 351.55 545 343.5 M 545 360 C 545.68 356.53 544.11 353.01 545 343.5 M 545 343.5 C 544.12 332.89 542.13 329.39 531.5 330 M 545 343.5 C 543.18 335.6 539.33 330.84 531.5 330 M 531.5 330 C 499.28 329.34 468.49 332.67 378.5 330 M 531.5 330 C 488.46 330.18 444.35 330.29 378.5 330 M 378.5 330 C 370.93 328.71 363.05 334.58 365 343.5 M 378.5 330 C 368.64 329.63 364.81 333.25 365 343.5 M 365 343.5 C 365.11 348.38 364.36 352.43 365 360 M 365 343.5 C 364.41 347.48 364.71 352.35 365 360" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 365 360 M 365 360 C 366.43 386.53 366.05 411.46 365 476.5 M 365 360 C 365.86 401.82 365.66 444.19 365 476.5 M 365 476.5 C 364.8 487.33 367.64 489.17 378.5 490 M 365 476.5 C 365.53 486.56 369.41 489.5 378.5 490 M 378.5 490 C 410.45 490.89 440.81 487.09 531.5 490 M 378.5 490 C 431.17 490.93 481.41 491.71 531.5 490 M 531.5 490 C 539.48 490.73 543.21 483.68 545 476.5 M 531.5 490 C 541.58 489.98 543.42 487.1 545 476.5 M 545 476.5 C 544.47 430.35 546.72 382.06 545 360 M 545 476.5 C 543.19 431.53 543.79 386.32 545 360" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 365 360 M 365 360 C 406.5 361.79 445.68 361.1 545 360 M 365 360 C 429.51 359.19 493.62 359.94 545 360" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 395 360 M 395 360 C 396.8 367.52 396.41 373.43 395 390 M 395 360 C 395.36 370.92 395.17 382.38 395 390 M 395 390 C 394.44 399.16 396.2 407.32 395 420 M 395 390 C 395.38 398.86 395.66 406.93 395 420 M 395 420 C 393.51 427.8 394.51 430.75 395 450 M 395 420 C 393.95 429.53 395.32 440.86 395 450 M 395 450 C 394.85 458.4 394.47 464.05 395 480 M 395 450 C 395.45 460.62 393.75 472.56 395 480" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" pointer-events="none" text-anchor="middle" font-size="12px"><text x="454.5" y="349.5">Teachers</text></g><path d="M 365 360 M 545 360 M 545 390 M 545 390 C 506.21 391.18 465.07 390.69 365 390 M 545 390 C 503.12 388.9 463.23 388.87 365 390" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 365 360 M 395 360 M 395 390 M 365 390" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" pointer-events="none" clip-path="url(#mx-clip-365-360-30-30-0)" text-anchor="middle" font-size="12px"><text x="379.5" y="379.5">PK</text></g><path d="M 395 360 M 545 360 M 545 390 M 395 390" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" font-weight="bold" text-decoration="underline" pointer-events="none" clip-path="url(#mx-clip-401-360-144-30-0)" font-size="12px"><text x="402.5" y="379.5">id</text></g><path d="M 365 390 M 395 390 M 395 420 M 365 420" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 395 390 M 545 390 M 545 420 M 395 420" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><g fill="rgb(0, 0, 0)" font-family="Comic Sans MS" pointer-events="none" clip-path="url(#mx-clip-401-390-144-30-0)" font-size="12px"><text x="402.5" y="409.5">married</text></g><path d="M 365 420 M 395 420 M 395 450 M 365 450" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 395 420 M 545 420 M 545 450 M 395 450" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 365 450 M 395 450 M 395 480 M 365 480" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 395 450 M 545 450 M 545 480 M 395 480" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/><path d="M 365 375 M 365 375 C 357.47 376.82 350.47 374.9 335 375 M 365 375 C 359.71 374.18 352.93 374.34 335 375 M 335 375 C 312.24 344.89 293.91 318.55 260 275 M 335 375 C 316.6 351.47 297.54 327.94 260 275 M 260 275 C 252.76 274.97 244.08 274.72 230 275 M 260 275 C 249.17 274.6 239.17 275.68 230 275" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/><path d="M 230 271 M 230 271 C 229.58 273.44 229.41 274.43 230 279 M 230 271 C 230.28 272.42 230.03 274.13 230 279" fill="none" stroke="rgb(0, 0, 0)" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="none"/></g></svg> \ No newline at end of file diff --git a/docs/fr-FR/welcome/release/inherits/form.jpg b/docs/fr-FR/welcome/release/inherits/form.jpg new file mode 100644 index 000000000..2de047cd5 Binary files /dev/null and b/docs/fr-FR/welcome/release/inherits/form.jpg differ diff --git a/docs/fr-FR/welcome/release/inherits/inherit-fields.jpg b/docs/fr-FR/welcome/release/inherits/inherit-fields.jpg new file mode 100644 index 000000000..acdaddda9 Binary files /dev/null and b/docs/fr-FR/welcome/release/inherits/inherit-fields.jpg differ diff --git a/docs/fr-FR/welcome/release/inherits/inherit.jpg b/docs/fr-FR/welcome/release/inherits/inherit.jpg new file mode 100644 index 000000000..ecc419daa Binary files /dev/null and b/docs/fr-FR/welcome/release/inherits/inherit.jpg differ diff --git a/docs/fr-FR/welcome/release/inherits/inherited-blocks.jpg b/docs/fr-FR/welcome/release/inherits/inherited-blocks.jpg new file mode 100644 index 000000000..e95928c20 Binary files /dev/null and b/docs/fr-FR/welcome/release/inherits/inherited-blocks.jpg differ diff --git a/docs/fr-FR/welcome/release/logger.md b/docs/fr-FR/welcome/release/logger.md new file mode 100644 index 000000000..bb438dcf1 --- /dev/null +++ b/docs/fr-FR/welcome/release/logger.md @@ -0,0 +1,70 @@ +# v0.9.0 : Système de journalisation de NocoBase (Logger) + +## `@nocobase/logger` + +Le système de journalisation de NocoBase est basé sur **Winston** et fournit une méthode pratique pour créer des instances de `logger`. + +```ts +const logger = createLogger(); +logger.info('Bonjour fichiers de log distribués !'); + +const { instance, middleware } = createAppLogger(); // Utilisé par @nocobase/server +app.logger = instance; +app.use(middleware); +``` + +## Variables d'environnement ajoutées + +Les variables d'environnement liées à la journalisation incluent : + +- [LOGGER_TRANSPORT](../getting-started/env.md#logger_transport) +- [LOGGER_BASE_PATH](./getting-started/env.md#logger_base_path) + +## Configuration du logger pour l'application + +Exemple de configuration du logger dans NocoBase : + +```ts +const app = new Application({ + logger: { + async skip(ctx) { + return false; + }, + requestWhitelist: [], + responseWhitelist: [], + transports: ['console', 'dailyRotateFile'], + }, +}); +``` + +Pour plus de détails sur les options de configuration, vous pouvez vous référer à la [documentation de Winston](https://github.com/winstonjs/winston#table-of-contents). + +## `app.logger` et `ctx.logger` + +L'objet `ctx.logger` est lié à un identifiant de requête (`reqId`). Cet identifiant est unique pour toute la durée du cycle de vie de la requête (`ctx`). + +```ts +ctx.logger = app.logger.child({ reqId: ctx.reqId }); +``` + +Les deux objets, `app.logger` et `ctx.logger`, sont des instances de Winston. Vous pouvez consulter la [documentation complète de Winston](https://github.com/winstonjs/winston#table-of-contents) pour des informations détaillées sur leur utilisation. + +## Transports personnalisés + +En plus des options natives de Winston, NocoBase permet de définir des transports personnalisés de manière simplifiée : + +```ts +import { Transports } from '@nocobase/logger'; + +Transports['custom'] = () => { + return new winston.transports.Console(); +}; + +const app = new Application({ + logger: { + transports: ['custom'], + }, +}); +``` + +Cela vous permet d'ajouter facilement des options de transport pour le logger sans avoir à modifier directement les configurations Winston. diff --git a/docs/fr-FR/welcome/release/roadmap.md b/docs/fr-FR/welcome/release/roadmap.md new file mode 100644 index 000000000..932b7b766 --- /dev/null +++ b/docs/fr-FR/welcome/release/roadmap.md @@ -0,0 +1,48 @@ +# Roadmap + +*Mise à jour le 11 juin 2024* + +Nous sommes en train de développer ou avons déjà prévu les nouvelles fonctionnalités et plugins suivants. ☑️ indique les fonctionnalités déjà complétées et publiées : + +## Fonctionnalités : + +- Prise en charge des expressions pour les valeurs par défaut des champs +- Les champs d'association prennent en charge les règles de liaison +- Mode d'ouverture des enregistrements : Page (en complément de Dialog, Drawer) +- [x] Action de lien, prise en charge des variables et des expressions +- [x] Portée des données et valeurs par défaut des champs prenant en charge les paramètres de la requête +- [x] Définir la hauteur du bloc +- [x] Markdown prend en charge les variables +- [x] L'adresse Iframe prend en charge les variables +- Prise en charge du rafraîchissement lié entre les blocs +- Ajouter des blocs de graphiques dans les fenêtres contextuelles +- [x] Refactorisation du plugin Import et Export pour traiter plus de données simultanément +- Un seul enregistrement/fenêtre contextuelle prend en charge l'URL indépendante +- [x] Amélioration du bloc de tableau en arborescence +- Refactorisation des flux de travail + - [x] Créer un nœud d'enregistrement + - [x] Mettre à jour un nœud d'enregistrement + - Gestion automatique des références de variables (déprécation du préchargement) +- Moteur de traitement des dates et heures +- Architecture distribuée +- Tutoriel sur les plugins + +## Plugins : + +- [x] DingTalk +- WeChat +- [x] Scanner de code QR +- [x] Bloc de tableau de bord +- [x] Bloc en arborescence +- Journaux d'audit +- Action : Importer des enregistrements pro +- Action : Exporter des enregistrements pro +- Gestionnaire multi-applications +- Partager des pages +- Source de données : API +- Workflow : Nœud de script +- Workflow : Déclencheur Webhook +- Masque de saisie +- Intégration de systèmes externes +- Nouveau client mobile +- Notifications diff --git a/docs/fr-FR/welcome/release/tree-collection.md b/docs/fr-FR/welcome/release/tree-collection.md new file mode 100644 index 000000000..3549b2679 --- /dev/null +++ b/docs/fr-FR/welcome/release/tree-collection.md @@ -0,0 +1,44 @@ +# Collection Arborescente (Tree Collection) + +## Options de la collection + +```ts +{ + name: 'categories', + tree: 'adjacency-list', + fields: [ + { + type: 'belongsTo', + name: 'parent', + treeParent: true, + }, + { + type: 'hasMany', + name: 'children', + treeChildren: true, + }, + ], +} +``` + +## Interface Utilisateur (UI) + +### Créer une collection arborescente + +![Créer une collection arborescente](./tree-collection/tree-collection.jpg) + +### Champs par défaut + +![Champs par défaut](./tree-collection/init.jpg) + +### Bloc Tableau + +![Bloc Tableau](./tree-collection/tree-table.jpg) + +### Ajouter un enfant + +![Ajouter un enfant](./tree-collection/add-child.jpg) + +### Développer/Réduire + +![Développer/Réduire](./tree-collection/expend-collapse.jpg) diff --git a/docs/fr-FR/welcome/release/tree-collection/add-child.jpg b/docs/fr-FR/welcome/release/tree-collection/add-child.jpg new file mode 100644 index 000000000..0c1285d5d Binary files /dev/null and b/docs/fr-FR/welcome/release/tree-collection/add-child.jpg differ diff --git a/docs/fr-FR/welcome/release/tree-collection/expend-collapse.jpg b/docs/fr-FR/welcome/release/tree-collection/expend-collapse.jpg new file mode 100644 index 000000000..de703b86b Binary files /dev/null and b/docs/fr-FR/welcome/release/tree-collection/expend-collapse.jpg differ diff --git a/docs/fr-FR/welcome/release/tree-collection/init.jpg b/docs/fr-FR/welcome/release/tree-collection/init.jpg new file mode 100644 index 000000000..86b4d5b42 Binary files /dev/null and b/docs/fr-FR/welcome/release/tree-collection/init.jpg differ diff --git a/docs/fr-FR/welcome/release/tree-collection/tree-collection.jpg b/docs/fr-FR/welcome/release/tree-collection/tree-collection.jpg new file mode 100644 index 000000000..1733aca53 Binary files /dev/null and b/docs/fr-FR/welcome/release/tree-collection/tree-collection.jpg differ diff --git a/docs/fr-FR/welcome/release/tree-collection/tree-table.jpg b/docs/fr-FR/welcome/release/tree-collection/tree-table.jpg new file mode 100644 index 000000000..4eeb1e6f2 Binary files /dev/null and b/docs/fr-FR/welcome/release/tree-collection/tree-table.jpg differ diff --git a/docs/fr-FR/welcome/release/upgrade-to/v017.md b/docs/fr-FR/welcome/release/upgrade-to/v017.md new file mode 100644 index 000000000..f55738d67 --- /dev/null +++ b/docs/fr-FR/welcome/release/upgrade-to/v017.md @@ -0,0 +1,451 @@ +# Changements incompatibles dans NocoBase 0.17 + +:::warning +Cet article couvre uniquement les changements incompatibles liés au développement de plugins. +::: + +## Changements dans `SchemaInitializer` + +- Ajout de `SchemaInitializerManager` pour enregistrer les `SchemaInitializer`. +- Ajout de `useSchemaInitializerRender()` pour remplacer la méthode `render()` de `useSchemaInitializer()`. +- Ajout de `useSchemaInitializerItem()` pour obtenir le contexte de l'élément d'initialisation actuel. +- Ajout du composant `SchemaInitializerItemGroup` comme composant par défaut pour `type: 'itemGroup'`. +- Ajout du composant `SchemaInitializerSubMenu` comme composant par défaut pour `type: 'subMenu'`. +- Ajout du composant `SchemaInitializerDivider` comme composant par défaut pour `type: 'divider'`. +- Ajout du composant `SchemaInitializerChildren` pour un rendu personnalisé de plusieurs éléments de liste. +- Ajout du composant `SchemaInitializerChild` pour un rendu personnalisé d'un seul élément de liste. +- Modification des responsabilités de `SchemaInitializerContext` pour stocker le contexte du `SchemaInitializer` actuel. +- Modification des responsabilités de `useSchemaInitializer()` pour obtenir le contexte du `SchemaInitializer` actuel. +- Transformation de `function SchemaInitializer` en `class SchemaInitializer` pour définir un initialiseur. +- Changement des paramètres de `SchemaInitializer` : + - Ajout du paramètre `name` obligatoire pour la valeur de `x-initializer`. + - Ajout du paramètre `Component` pour un rendu personnalisé du bouton. Par défaut, `SchemaInitializerButton`. + - Ajout des paramètres `componentProps` et `style` pour configurer les propriétés et le style du `Component`. + - Ajout du paramètre `ItemsComponent` pour un rendu personnalisé de la liste. Par défaut, `SchemaInitializerItems`. + - Ajout des paramètres `itemsComponentProps` et `itemsComponentStyle` pour configurer les propriétés et le style du `ItemsComponent`. + - Ajout du paramètre `popover` pour configurer l'effet `popover`. + - Ajout du paramètre `useInsert` pour utiliser des hooks dans la fonction `insert`. + - Modification du paramètre `dropdown` en `popoverProps`, utilisant `Popover` au lieu de `Dropdown`. +- Modification des paramètres `items` pour `SchemaInitializer` : + - Ajout de la fonction `useChildren` pour contrôler dynamiquement les éléments enfants. + - Ajout de la fonction `componentProps` pour les propriétés du composant. + - Ajout de la fonction `useComponentProps` pour traiter dynamiquement les propriétés du composant. + - Modification du paramètre `key` en `name` pour identifier de manière unique les éléments de la liste. + - Modification du paramètre `visible` en fonction `useVisible` pour contrôler dynamiquement l'affichage des éléments. + - Modification du paramètre `component` en `Component` pour rendre les éléments de la liste. +- Modification de `SchemaInitializer.Button` en `SchemaInitializerButton`, la valeur par défaut pour le paramètre `Component` de `SchemaInitializer`. +- Modification de `SchemaInitializer.Item` en `SchemaInitializerItem`, avec les mêmes paramètres. +- Modification de `SchemaInitializer.ActionModal` en `SchemaInitializerActionModal`, avec les mêmes paramètres. +- Modification de `SchemaInitializer.SwitchItem` en `SchemaInitializer.Switch`, avec les mêmes paramètres. +- Suppression de `SchemaInitializerProvider`, remplacé par `SchemaInitializerManager`. +- Suppression de `SchemaInitializer.itemWrap`, il n'est plus nécessaire d'envelopper le composant `item`. + +Pour plus d'informations, consultez la documentation suivante : + +- [Développement de plugins / Initialisation de schémas](/development/client/ui-schema/initializer) +- [Documentation API / SchemaInitializer](https://client.docs.nocobase.com/core/ui-schema/schema-component) + +### Ajouter des éléments à un initialiseur existant + +Auparavant, nous obtenions tous les `Initializers` via `SchemaInitializerContext` puis nous les ajoutions, supprimions ou modifiions. Par exemple, le code suivant ajoutait `Hello` au `media` dans `BlockInitializers` : + +```tsx | pure +const items = useContext<any>(SchemaInitializerContext); +const mediaItems = items.BlockInitializers.items.find( + (item) => item.key === 'media', +); + +if (process.env.NODE_ENV !== 'production' && !mediaItems) { + throw new Error('Initialiseur de bloc media introuvable'); +} + +const children = mediaItems.children; +if (!children.find((item) => item.key === 'hello')) { + children.push({ + key: 'hello', + type: 'item', + title: '{{t("Bloc Hello")}}', + component: HelloBlockInitializer, + }); +} +``` + +La nouvelle méthode pour ajouter des éléments est d'utiliser `schemaInitializerManager.addItem()` dans la méthode de chargement du plugin. + +```tsx | pure +class MyPlugin extends Plugin { + async load() { + this.schemaInitializerManager.addItem( + 'BlockInitializers', + 'otherBlocks.hello', + { + title: '{{t("Bloc Hello")}}', + Component: HelloBlockInitializer, + }, + ); + } +} +``` + +Références détaillées de la documentation : + +- [Développement de plugins / Initialisation de schémas / Ajouter des éléments à un initialiseur existant](/development/client/ui-schema/initializer) +- [Documentation API / SchemaInitializer / Composants et types intégrés](https://client.docs.nocobase.com/core/ui-schema/schema-initializer) + +### Ajouter le nouvel initialiseur à l'application + +Auparavant ajouté via `SchemaInitializerProvider`, par exemple : + +```tsx | pure +<SchemaInitializerProvider + initializers={{ BlockInitializers }} + components={{ ManualActionDesigner }} +></SchemaInitializerProvider> +``` + +Maintenant, vous l'ajoutez dans le `load` du plugin, par exemple : + +```tsx | pure +import { Plugin } from '@nocobase/client'; + +class MyPlugin extends Plugin { + async load() { + this.app.schemaInitializerManager.add(blockInitializers); + this.app.addComponents({ ManualActionDesigner }); + } +} +``` + +Pour la documentation détaillée, consultez : + +- [Développement de plugins / Initialisation de schémas / Ajouter un nouvel initialiseur](/development/client/ui-schema/initializer) +- [Documentation API / SchemaInitializerManager / schemaInitializerManager.addItem()](https://client.docs.nocobase.com/core/ui-schema/schema-initializer-manager) + +### Ajouter un nouvel initialiseur + +Avant, `SchemaInitializer` supportait les objets JSON et l'écriture de composants, maintenant il supporte uniquement `new SchemaInitializer()`. + +Exemple 1 : L'ancienne méthode d'écriture JSON est maintenant remplacée par `new SchemaInitializer()`. + +```diff +- export const BlockInitializers = { ++ export const blockInitializers = new SchemaInitializer({ ++ name: 'BlockInitializers', + 'data-testid': 'add-block-button-in-page', + title: '{{t("Ajouter un bloc")}}', + icon: 'PlusOutlined', + wrap: gridRowColWrap, + items: [ + { +- key: 'dataBlocks', ++ name: 'data-blocks', + type: 'itemGroup', + title: '{{t("Blocs de données")}}', + children: [ + { +- key: 'table', ++ name: 'table', +- type: 'item', + title: '{{t("Table")}}', +- component: TableBlockInitializer, ++ Component: TableBlockInitializer, + }, + { + key: 'form', + type: 'item', + title: '{{t("Formulaire")}}', + component: FormBlockInitializer, + } + ], + }, + ], +}); +``` + +Exemple 2 : Modifier la manière d'écrire le composant vers `new SchemaInitializer()`. + +Cela concerne la définition des composants : + +```tsx | pure +export const BulkEditFormItemInitializers = (props: any) => { + const { t } = useTranslation(); + const { insertPosition, component } = props; + const associationFields = useAssociatedFormItemInitializerFields({ + readPretty: true, + block: 'Form', + }); + return ( + <SchemaInitializer.Button + data-testid="configure-fields-button-of-bulk-edit-form-item" + wrap={gridRowColWrap} + icon={'SettingOutlined'} + items={[ + { + type: 'itemGroup', + title: t('Display fields'), + children: useCustomBulkEditFormItemInitializerFields(), + }, + { + type: 'divider', + }, + { + type: 'item', + title: t('Add text'), + component: BlockItemInitializer, + }, + ]} + insertPosition={insertPosition} + component={component} + title={component ? null : t('Configure fields')} + /> + ); +}; +``` + +Cela doit maintenant être changé pour la méthode `new SchemaInitializer()` : + +```tsx | pure +const bulkEditFormItemInitializers = new SchemaInitializer({ + name: 'BulkEditFormItemInitializers', + 'data-testid': 'configure-fields-button-of-bulk-edit-form-item', + wrap: gridRowColWrap, + icon: 'SettingOutlined', + items: [ + { + type: 'itemGroup', + title: t('Display fields'), + name: 'displayFields', + useChildren: useCustomBulkEditFormItemInitializerFields, + }, + { + type: 'divider', + }, + { + title: t('Add text'), + name: 'addText', + Component: BlockItemInitializer, + }, + ], +}); +``` + +Références déta + +illées de la documentation : + +- [Développement de plugins / Initialisation de schémas / Ajouter un nouvel initialiseur](/development/client/ui-schema/initializer) +- [Documentation API / SchemaInitializer / new SchemaInitializer(options)](https://client.docs.nocobase.com/core/ui-schema/schema-initializer) + +### Définition et implémentation des éléments + +Auparavant, lors de la configuration d'un élément, les props des composants étaient placées directement dans l'élément, mais maintenant il est recommandé d'utiliser `componentProps` et `useComponentProps`. + +```diff +{ + name: 'BlockInitializers', + items: [ + { + name: 'xxx', + Component: XXXSchemaInitializerItem, + title: 'Title 1', + schema: {}, +- foo: 'bar', ++ useComponentProps: () => { ++ return { foo: 'bar' } ++ } + } + ] +} +``` + +Dans le composant `Item`, la configuration de l'élément était auparavant transmise directement par props, mais maintenant elle est obtenue par `useSchemaInitializerItem()`, et les hooks associés sont inclus : + +- `useSchemaInitializer()` pour obtenir le contexte actuel de l'initialiseur. +- `useSchemaInitializerItem()` pour obtenir le contexte de l'élément actuel. + +```diff +const XXXSchemaInitializerItem = (props) => { +- const { insert, title, schema, foo } = props; ++ const { foo } = props; ++ const { insert } = useSchemaInitializer(); ++ const { title, schema } = useSchemaInitializerItem(); + // ... +} +``` + +Références détaillées de la documentation : + +- [Documentation API / SchemaInitializer / Composants et types intégrés](https://client.docs.nocobase.com/core/ui-schema/schema-initializer) + +## Changements dans `SchemaSettings` + +- Ajout de `SchemaSettingsManager` pour enregistrer les `SchemaSettings`. +- Ajout de `useSchemaSettingsItem()`. +- Ajout de `useSchemaSettingsRender()`. +- Ajout du paramètre `x-settings` pour configurer les paramètres du schéma. +- Ajout du paramètre `x-toolbar` pour configurer la barre d'outils du schéma. +- Ajout du composant `SchemaToolbar` pour personnaliser la barre d'outils du schéma. +- Ajout de `useSchemaToolbarRender()` pour remplacer `useDesigner()`. +- Transformation de `function SchemaSettings` en `class SchemaSettings` pour définir les paramètres. +- Changement de `SchemaSettings` en `SchemaSettingsDropdown`. +- Modification de `SchemaSettings.Item` en `SchemaSettingsItem`. +- Modification de `SchemaSettings.ItemGroup` en `SchemaSettingsItemGroup`. +- Modification de `SchemaSettings.SubMenu` en `SchemaSettingsSubMenu`. +- Modification de `SchemaSettings.Divider` en `SchemaSettingsDivider`. +- Modification de `SchemaSettings.Remove` en `SchemaSettingsRemove`. +- Modification de `SchemaSettings.SelectItem` en `SchemaSettingsSelectItem`. +- Modification de `SchemaSettings.CascaderItem` en `SchemaSettingsCascaderItem`. +- Modification de `SchemaSettings.SwitchItem` en `SchemaSettingsSwitchItem`. +- Modification de `SchemaSettings.ModalItem` en `SchemaSettingsModalItem`. +- Modification de `SchemaSettings.ActionModalItem` en `SchemaSettingsActionModalItem`. +- Suppression de `x-designer`, obsolète, et remplacement par `x-toolbar`. +- Suppression de `useDesigner()`, obsolète, remplacé par `useSchemaToolbarRender()`. + +Références liées : + +- [Développement de plugins / Paramètres de schéma](/development/client/ui-schema/initializer) +- [Plugins / SchemaToolbar](/development/client/ui-schema/initializer) +- [Documentation API / SchemaSettings](https://client.docs.nocobase.com/core/ui-schema/schema-component) +- [Documentation API / SchemaSettingsManager](https://client.docs.nocobase.com/core/ui-schema/schema-component) +- [Documentation API / SchemaToolbar](https://client.docs.nocobase.com/core/ui-schema/schema-component) + +### Définition et implémentation des paramètres + +Auparavant, `SchemaSettings` était implémenté avec `GeneralSchemaDesigner` et utilisé dans `x-designer`. + +```tsx | pure +<GeneralSchemaDesigner> + <SchemaSettings.SwitchItem + title={'Enable Header'} + onClick={() => {}} + ></SchemaSettings.SwitchItem> + <SchemaSettings.Divider /> + <SchemaSettings.ModalItem + title={'xxx'} + schema={} + onSubmit={props.onSubmit} + ></SchemaSettings.ModalItem> +</GeneralSchemaDesigner> +``` + +Maintenant, les deux sont séparés en `x-toolbar` et `x-settings`, avec `x-toolbar` étant manquant et `SchemaSettings` utilisé dans `x-settings`. + +```ts +const mySettings = new SchemaSettings({ + name: 'MySettings', + items: [ + { + name: 'enableHeader', + type: 'switch', + componentProps: { + title: 'Enable Header', + onClick: () => {}, + }, + }, + { + name: 'divider', + type: 'divider', + }, + { + name: 'xxx', + type: 'modal', + useComponentProps() { + // useSchemaDesigner() fournit les props + const { onSubmit } = useSchemaDesigner(); + return { + title: 'xxx', + schema: {}, + onSubmit, + }; + }, + }, + ], +}); +``` + +### Implémentation de l'élément pour les paramètres + +La version précédente du composant `Item` était difficile à implémenter, mais maintenant nous utilisons `useSchemaSettings()` pour obtenir le `Designable` du schéma actuel, et utiliser le `Designable` pour modifier le schéma actuel. + +```diff +function EditBlockTitle(props) { +- const field = useField(); +- const fieldSchema = useFieldSchema(); +- const { dn } = useDesignable(); ++ const { dn } = useSchemaSettings(); + + return ( + <SchemaSettings.ModalItem + title={'Edit block title'} + schema={ + { + type: 'object', + title: 'Edit block title', + properties: { + title: { + title: 'Block title', + type: 'string', + // Obtient la valeur par défaut du schéma +- default: fieldSchema?.['x-decorator-props']?.title, ++ default: dn.getSchemaAttribute('x-decorator-props.title'), + 'x-decorator': 'FormItem', + 'x-component': 'Input', + 'x-compile-omitted': ['default'], + }, + }, + } as ISchema + } + onSubmit={({ title }) => { +- field.decoratorProps.title = title; +- fieldSchema['x-decorator-props'] = fieldSchema['x-decorator-props'] || {}; +- fieldSchema['x-decorator-props'].title = title; +- dn.emit('patch', { +- schema: { +- ['x-uid']: fieldSchema['x-uid'], +- 'x-decorator-props': { +- ...fieldSchema['x-decorator-props'], +- }, +- }, +- }); +- dn.refresh(); ++ dn.deepMerge({ ++ 'x-decorator-props': { ++ title, ++ }, ++ }); + }} + /> + ); +} +``` + +Références détaillées : + +- [Développement de plugins / Paramètres de schéma / Comment implémenter les paramètres du schéma](/development/client/ui-schema/settings) +- [Développement de plugins / Concepteur de schémas](/development/client/ui-schema/designable) +- [Documentation API / SchemaSettings / Composants et types intégrés](https://client.docs.nocobase.com/core/ui-schema/schema-settings) +- [Documentation API / Designable](https://client.docs.nocobase.com/core/ui-schema/designable) + +## Autres Changements + +### Méthode `app.addComponent` privatée + +La méthode `app.addComponent` a été privatisée et n'est plus exposée au public. Vous devez enregistrer le composant via la méthode `app.addComponents`. + +```diff +- app.addComponent(MyComponent, 'MyComponent') ++ app.addComponents({ MyComponent }) +``` + +### Suppression de `PluginManagerContext` + +```diff +const MyProvider = props => { +- const ctx = useContext(PluginManagerContext); +return <div> +- <PluginManagerContext.Provider value={{components: { ...ctx?.components }}}> + {/* ... */} +- </PluginManagerContext.Provider> +</div> +} +``` diff --git a/docs/fr-FR/welcome/release/v0040-changelog.md b/docs/fr-FR/welcome/release/v0040-changelog.md new file mode 100644 index 000000000..ebb69cb9b --- /dev/null +++ b/docs/fr-FR/welcome/release/v0040-changelog.md @@ -0,0 +1,52 @@ +Voici un résumé des changements apportés dans la version **v0.4** de **NocoBase** du 7 avril 2021 : + +Cette version v0.4 introduit de nombreuses fonctionnalités améliorées pour la gestion des plugins, des permissions, des journaux d'actions et des nouveaux opérateurs pour les requêtes. De plus, elle corrige plusieurs erreurs liées à la gestion des associations, au tri et à la pagination. + +## Merged +### Refactorisations et améliorations : +- **Refactorisation** de la gestion des valeurs booléennes dans les paramètres (#74). +- **Refactorisation** des middlewares de l'application (#17362a8). +- **Changements dans la publication des packages** pour la version alpha 0.4.0 (#c2f1876). + +### Nouvelles fonctionnalités : +- **Plugin de région Chine** (#66). +- **Filtre pour le champ `linkTo`** (#64). +- **Automatisations des plugins** (#65). +- **Journaux d'action** (#61, #62). +- **Verrouillage de destruction** (#60). +- **Permissions sur les routes** (#58). +- **Plugin de permissions** (#53, #57). +- **Ajout d'opérateurs personnalisés pour les requêtes** (#48). +- **Téléchargement de fichiers unique vers les pièces jointes** (#46). +- **Gestion des champs `createdBy` et `updatedBy` dans les tables gérées par les collections** (#43). + +### Corrections de bugs : +- **Problèmes mineurs corrigés** (#72). +- **Problème d'impossibilité de détruire la vue/tab par défaut** (#63). +- **Problèmes liés à l'association des champs** (#59, #51, #34). +- **Bug avec les associations imbriquées dans `toInclude`** (#47). +- **Bug de mise à jour d'autres champs évité** (#51). + +### Améliorations de la base de données : +- **Support des champs virtuels** (#27). +- **Options de tri** (#36, #38, #37). +- **Amélioration des options de pagination** (#20). + +### Tests : +- **Amélioration des tests CI** (#31, #17). +- **Référencement des tests pour la base de données et les actions** (#16, #15). + +## Fixed +### Problèmes résolus : +- **Problème de connexion** : Amélioration des styles du formulaire de connexion (#9). +- **Messages d'erreur** dans les formulaires de connexion et d'inscription (#9). + +### Commit : +- Ajustement des paramètres pour une meilleure gestion (#b95e2da). +- Formatage du code (#ce4a22f). + +## Liens vers les Pull Requests : +- [#74](https://github.com/nocobase/nocobase/pull/74) +- [#66](https://github.com/nocobase/nocobase/pull/66) +- [#61](https://github.com/nocobase/nocobase/pull/61) +- [#53](https://github.com/nocobase/nocobase/pull/53) diff --git a/docs/fr-FR/welcome/release/v0050-changelog.md b/docs/fr-FR/welcome/release/v0050-changelog.md new file mode 100644 index 000000000..400aa5ea2 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0050-changelog.md @@ -0,0 +1,28 @@ +Voici un résumé des changements dans la version **v0.5** de **NocoBase**, du 21 novembre 2021 : + +## Merged +### Corrections et Améliorations : +- **Mise à jour de Formily et rendu du menu latéral** : Utilisation de `createPortal` et de l'effet de comparaison profonde pour améliorer le rendu du menu latéral (#103). +- **Amélioration du `SchemaRenderer`** pour obtenir correctement les valeurs du schéma (#102). +- **Stratégie de surcharge pour `form.setValues`** après mise à jour de Formily (#101). + +### Nouvelles fonctionnalités : +- **Support de l'internationalisation (i18n)** (#99). +- **Nouvelle version de la documentation** (#95). +- **Amélioration du style des tags d'option** (#92). +- **Ajout d'une favicon pour `create-nocobase-app`** (#91). +- **Amélioration du processus de création d'une application NocoBase avec des options simples et Quickstart** (#87). +- **Exportation de plugins** (#73). + +## Commits +- Version v0.5 publiée : [commit 2cbcd08](https://github.com/nocobase/nocobase/commit/2cbcd087ce6629d8f0df550ee35e02065db41dbc). +- Refactorisation du code : [commit 75cd158](https://github.com/nocobase/nocobase/commit/75cd158a270935559a9922d1dd074811253013b9). +- Amélioration du code : [commit c6b68f2](https://github.com/nocobase/nocobase/commit/c6b68f2b10e4e8df5257345f5e39408666c5810d). + +## Principales améliorations : +- La version 0.5 apporte une prise en charge complète de l'internationalisation (i18n), permettant de traduire l'interface dans différentes langues. +- Le processus de création d'applications NocoBase a été simplifié, avec l'ajout d'une option *Quickstart* pour démarrer plus rapidement. +- La mise à jour de Formily a permis d'améliorer la gestion des formulaires, notamment en modifiant la stratégie de mise à jour des valeurs du formulaire. +- La documentation a été mise à jour pour offrir une meilleure expérience de l'utilisateur. + +En résumé, cette version v0.5 se concentre sur l'amélioration de l'expérience utilisateur avec de meilleures fonctionnalités de personnalisation, un processus de création d'application plus rapide, et la prise en charge des traductions (i18n). Elle inclut également des corrections de bugs et des améliorations de performance liées à l'interface. diff --git a/docs/fr-FR/welcome/release/v0060-changelog.md b/docs/fr-FR/welcome/release/v0060-changelog.md new file mode 100644 index 000000000..51dddc852 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0060-changelog.md @@ -0,0 +1,35 @@ +Voici un résumé des changements dans la version **v0.6** de **NocoBase**, du 5 avril 2022 : + +## Merged + +### Nouvelles fonctionnalités : +- **Plugin Workflow** : Introduction d'un plugin de gestion de workflow avec plusieurs améliorations (#288, #278, #264). +- **Améliorations de l'ACL (Contrôle d'accès)** : Améliorations majeures du module ACL avec ajout de nouvelles fonctionnalités comme la vérification des rôles (#283, #279, #280). +- **Composants UI** : Ajout de nouveaux composants pour les formulaires et l'interface utilisateur, y compris `Slate` pour le texte enrichi (#272), `Markdown` (#173), et d'autres composants comme `Select`, `TreeSelect`, `InputNumber`, et `DatePicker` (#168, #160, #161). +- **Améliorations de la gestion des erreurs** : Ajout de gestion des erreurs dans le workflow (#214), et plusieurs corrections liées aux filtres et aux opérateurs de requêtes (#219, #220, #217). + +### Corrections : +- **Problèmes avec les associations** : Correction des erreurs de conversion `toJSON` pour les associations `belongsTo` et `null` (#287, #260). +- **Problèmes de style** : Résolution de problèmes de styles CSS, notamment avec Slate et les styles par défaut d'Ant Design (#289, #277). +- **Problèmes de transactions et de données** : Résolution de bugs liés aux transactions, à la mise à jour des timestamps (`updatedAt`), et à la suppression des enregistrements (#242, #251, #235). +- **Améliorations du filtrage et du tri** : Divers correctifs pour améliorer le filtrage des données et le tri des champs (#205, #219, #213). + +### Autres améliorations : +- **Support des workflows avec des variables contextuelles à partir de déclencheurs de modèles** (#284). +- **Améliorations de la gestion des plugins** : Ajout de la possibilité d'installer des plugins et une meilleure gestion des erreurs (#211, #222). +- **Améliorations du schéma de données** : Prise en charge du tri dans les champs de collection et de l'ajout de nouveaux opérateurs pour les requêtes (#207, #233). +- **Amélioration de l'interface Kanban** : La fonctionnalité Kanban a été améliorée avec une nouvelle version (#223, #230). +- **Amélioration de la gestion des journaux d'action** : Ajout d'un modèle de journal d'action pour suivre les modifications (#239). + +## Commits +- **Fixes divers** : Plusieurs corrections de dépendances et de fichiers de configuration (`yarn.lock`) pour garantir une meilleure gestion des packages et des dépendances (#7a7eb0c, #e226f04). +- **Amélioration de la vue du schéma d'action** : Amélioration de l'initialisation des schémas d'action (#590ca26). +- **Amélioration du texte enrichi** : Ajout de la fonctionnalité de texte enrichi (Rich Text) avec un composant dédié (#5b41b33). + +## Principales améliorations : +- **Plugin Workflow** : Un des ajouts majeurs de cette version, avec une refonte du plugin de workflow, permettant la gestion des actions et des processus automatisés dans l'application. +- **Composants UI améliorés** : Nouvelles options de composants UI pour enrichir l'interface utilisateur, y compris des champs de formulaire avancés (Markdown, DatePicker, InputNumber, etc.). +- **Gestion des erreurs améliorée** : La gestion des erreurs dans les plugins et workflows a été renforcée, améliorant la robustesse de l'application. +- **Mise à jour des plugins et des actions** : Des plugins tels que `acl`, `workflow` et des actions comme la gestion des rôles et des permissions ont été refactorisés pour plus de flexibilité et d'intégration. + +En résumé, cette version v0.6 de **NocoBase** apporte des fonctionnalités puissantes comme le plugin Workflow, une gestion améliorée des ACL, de nouveaux composants UI et des corrections de bugs importants. Elle vise à améliorer la gestion des processus métier automatisés et à offrir une interface plus riche et plus flexible. diff --git a/docs/fr-FR/welcome/release/v0070-changelog.md b/docs/fr-FR/welcome/release/v0070-changelog.md new file mode 100644 index 000000000..3d7777039 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0070-changelog.md @@ -0,0 +1,66 @@ +# v0.7 : 2022-04-25 + +## Fonctionnalités Fusionnées + +- **Amélioration du client API et du SDK** : Amélioration du client API pour offrir de meilleures performances et fonctionnalités [`#425`](https://github.com/nocobase/nocobase/pull/425) +- **Commande create-plugin** : Ajout de la commande `create-plugin` pour faciliter la création de plugins [`#423`](https://github.com/nocobase/nocobase/pull/423) +- **Couleur des boutons** : Ajout de l'option pour personnaliser la couleur des boutons dans l'interface utilisateur [`#420`](https://github.com/nocobase/nocobase/pull/420) +- **Réponse 204 (Aucun contenu)** : Correction du problème lié aux réponses 204 sans contenu [`#378`](https://github.com/nocobase/nocobase/pull/378) +- **Destruction des champs d'association** : Suppression du champ d'association lorsque la collection cible est supprimée [`#376`](https://github.com/nocobase/nocobase/pull/376) +- **Correction des types** : Utilisation de `Transactionable` natif de Sequelize au lieu de `TransactionAble` pour la gestion des transactions [`#410`](https://github.com/nocobase/nocobase/pull/410) +- **Correction des workflows de plugins** : Suppression des anciens auditeurs lorsqu'une collection est modifiée dans la configuration [`#409`](https://github.com/nocobase/nocobase/pull/409) +- **Ajout d'action personnalisée** : Ajout de la possibilité d'ajouter des actions personnalisées dans les workflows [`#396`](https://github.com/nocobase/nocobase/pull/396) +- **Refactorisation des workflows de plugins** : Gestion de multiples instances et événements (résolution du problème #384) [`#408`](https://github.com/nocobase/nocobase/pull/408) +- **Correction de la gestion des titres dans les workflows** : Correction de l'affichage du titre du type de noeud dans les tiroirs (`drawers`) [`#389`](https://github.com/nocobase/nocobase/pull/389) +- **Correction de la récupération des propriétés de résultats de tâches** : Correction du problème d'accès aux propriétés des résultats de tâche dans les workflows [`#382`](https://github.com/nocobase/nocobase/pull/382) +- **Lancer une erreur au démarrage du serveur** : Ajout d'une fonctionnalité qui génère une erreur au démarrage du serveur en cas de problème [`#374`](https://github.com/nocobase/nocobase/pull/374) +- **Options de l'application** : Ajout de diverses options pour la configuration de l'application [`#375`](https://github.com/nocobase/nocobase/pull/375) +- **Correction de l'opérateur "NOT IN" avec des valeurs nulles** : Correction du problème où les enregistrements avec des valeurs nulles dans l'opérateur "NOT IN" ne fonctionnaient pas correctement [`#377`](https://github.com/nocobase/nocobase/pull/377) +- **Révisions dans le workflow de plugin** : Ajout de fonctionnalités de révision dans les workflows de plugin [`#379`](https://github.com/nocobase/nocobase/pull/379) +- **Correction de l'index de la liste incluse dans le parser d'options** : Correction du problème lié à l'index de la liste dans le parser d'options [`#371`](https://github.com/nocobase/nocobase/pull/371) +- **Correction de la duplication des descriptions dans les valeurs de champ** : Correction des descriptions dupliquées dans les champs de la configuration des workflows [`#368`](https://github.com/nocobase/nocobase/pull/368) +- **Correction du type et de la gestion des transactions dans le dépôt** : Résolution des problèmes liés aux types et aux transactions dans le dépôt de données [`#366`](https://github.com/nocobase/nocobase/pull/366) +- **Correction des transactions d'exécution dans le workflow de plugin** : Correction de la gestion des transactions lors de l'exécution d'un workflow [`#364`](https://github.com/nocobase/nocobase/pull/364) +- **Ajout d'un titre de document dans le workflow de plugin** : Ajout de titres de documents dans les configurations de workflow de plugin [`#363`](https://github.com/nocobase/nocobase/pull/363) +- **Correction de l'affichage avec confirmation** : Résolution des problèmes d'affichage liés à l'option de confirmation [`#361`](https://github.com/nocobase/nocobase/pull/361) +- **Erreur de ressource ACL vide** : Correction d'une erreur liée à une ACL de ressource vide [`#357`](https://github.com/nocobase/nocobase/pull/357) +- **Valeurs modifiées lorsque non enregistrées** : Ajout d'une invite pour les valeurs modifiées mais non enregistrées [`#351`](https://github.com/nocobase/nocobase/pull/351) +- **Modification de la couleur de l'icône de fermeture du filtre** : Correction de la couleur de l'icône de fermeture du filtre [`#356`](https://github.com/nocobase/nocobase/pull/356) +- **Correction de l'internationalisation (i18n)** : Correction des traductions dans le workflow de plugin [`#354`](https://github.com/nocobase/nocobase/pull/354) +- **Correction du workflow de plugin** : Diverses améliorations et corrections mineures [`#353`](https://github.com/nocobase/nocobase/pull/353) +- **Mise à jour du gestionnaire de fichiers pour corriger la taille** : Mise à jour du paquet `multer-aliyun-oss` pour corriger les problèmes de taille de fichier [`#352`](https://github.com/nocobase/nocobase/pull/352) +- **Améliorations du code** : Optimisation et amélioration générale du code [`#350`](https://github.com/nocobase/nocobase/pull/350) +- **Correction du workflow de plugin** : Diverses corrections pour améliorer le workflow des plugins [`#349`](https://github.com/nocobase/nocobase/pull/349) +- **Problème avec la synchronisation de la base de données** : Correction du problème de synchronisation de la base de données avec la commande `db:sync` [`#348`](https://github.com/nocobase/nocobase/pull/348) +- **Correction de la logique de liaison des déclencheurs dans le workflow de plugin** : Correction de la logique des déclencheurs pour éviter les doublons [`#347`](https://github.com/nocobase/nocobase/pull/347) +- **Correction du style de l'URL du menu** : Correction de l'affichage du style de l'URL du menu [`#344`](https://github.com/nocobase/nocobase/pull/344) +- **Ajout de la traduction dans le workflow de plugin** : Ajout de la fonctionnalité de traduction pour les workflows de plugins [`#345`](https://github.com/nocobase/nocobase/pull/345) +- **Correction de l'effet de boucle dans les déclencheurs via l'ID de transaction** : Correction pour briser la boucle de déclenchement causée par l'ID de transaction [`#341`](https://github.com/nocobase/nocobase/pull/341) +- **Appel de `model.beforeCreate` non effectué** : Correction du problème où `beforeCreate` n'était pas appelé dans certains cas [`#343`](https://github.com/nocobase/nocobase/pull/343) +- **Problème d'affichage des vignettes dans les cartes Kanban** : Correction des vignettes d'images dans les cartes Kanban [`#338`](https://github.com/nocobase/nocobase/pull/338) +- **Authentification de la base de données** : Ajout de l'authentification pour la base de données [`#342`](https://github.com/nocobase/nocobase/pull/342) +- **Installation asynchrone des sous-applications** : Optimisation de l'installation des sous-applications de manière asynchrone [`#336`](https://github.com/nocobase/nocobase/pull/336) +- **Amélioration de l'UX des entrées de valeurs de collection dans les noeuds de workflow** : Amélioration de l'expérience utilisateur lors de la saisie de valeurs de collection dans les noeuds de workflow [`#340`](https://github.com/nocobase/nocobase/pull/340) +- **Améliorations générales** : Diverses améliorations du système [`#335`](https://github.com/nocobase/nocobase/pull/335) +- **Ajout des champs modifiés dans la configuration du déclencheur de modèle** : Ajout des champs modifiés à la configuration des déclencheurs de modèle dans les workflows de plugins [`#332`](https://github.com/nocobase/nocobase/pull/332) +- **Compatibilité avec `create-nocobase-app`** + + : Correction des problèmes de compatibilité avec `create-nocobase-app` [`#323`](https://github.com/nocobase/nocobase/pull/323) +- **Version du paquet client pour `create-nocobase-app`** : Mise à jour de la version du paquet client pour la commande `create-nocobase-app` [`#321`](https://github.com/nocobase/nocobase/pull/321) +- **Gestion de l'application** : Correction du gestionnaire d'applications [`#320`](https://github.com/nocobase/nocobase/pull/320) +- **Refactorisation du style par défaut des étiquettes** : Modification du style des étiquettes par défaut dans l'interface [`#318`](https://github.com/nocobase/nocobase/pull/318) +- **Correction de la gestion des applications multiples** : Correction des problèmes de gestion des applications multiples [`#317`](https://github.com/nocobase/nocobase/pull/317) +- **Erreur d'action cible ACL** : Résolution des erreurs liées aux actions cibles dans les ACL [`#311`](https://github.com/nocobase/nocobase/pull/311) +- **Stockages de fichiers** : Ajout de la fonctionnalité de stockage de fichiers [`#314`](https://github.com/nocobase/nocobase/pull/314) +- **Amélioration de l'UX du workflow de plugin** : Diverses corrections de l'UX dans le workflow de plugin [`#313`](https://github.com/nocobase/nocobase/pull/313) +- **Correction du champ de la requête dans le noeud du workflow** : Correction du champ utilisé pour la récupération des données dans le noeud de requête [`#308`](https://github.com/nocobase/nocobase/pull/308) +- **Création de l'application Nocobase** : Correction du processus de création de l'application Nocobase [`#307`](https://github.com/nocobase/nocobase/pull/307) +- **Problème avec `create-nocobase-app`** : Résolution des problèmes liés à la commande `create-nocobase-app` [`#306`](https://github.com/nocobase/nocobase/pull/306) +- **Correction de l'ajout d'éléments dans le menu** : Correction du style `overflow:hidden` pour éviter les débordements visuels [`#304`](https://github.com/nocobase/nocobase/pull/304) + +## Commits + +- **Remplacement de la licence MIT par Apache-2.0** : Changement de licence du projet [`717efa8`](https://github.com/nocobase/nocobase/commit/717efa889d471fac3f909137e2adb96586414aad) +- **Ajout des traductions** : Ajout de nouvelles traductions pour l'interface utilisateur [`5c0184a`](https://github.com/nocobase/nocobase/commit/5c0184a397885d6de5307a7087c2d93042cd49f8) +- **Traductions supplémentaires** : Ajout de nouvelles traductions dans le projet [`1f04f90`](https://github.com/nocobase/nocobase/commit/1f04f90a00e071aa9ab294f21e8d02373191eecc) +- **Désactivation du glissement des cartes Kanban** : Ajout de la possibilité de désactiver le glissement des cartes Kanban [`05a251b`](https://github.com/nocobase/nocobase/commit/05a251b1fc06012e77e402b422e3120430effef1) diff --git a/docs/fr-FR/welcome/release/v0071-changelog.md b/docs/fr-FR/welcome/release/v0071-changelog.md new file mode 100644 index 000000000..474629508 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0071-changelog.md @@ -0,0 +1,74 @@ +# v0.7.1 : 2022-06-26 + +## Fonctionnalités Fusionnées + +- **chore(create-nocobase-app)** : Correction de certains bugs [`#538`](https://github.com/nocobase/nocobase/pull/538) +- **fix** : Destruction des champs de collection [`#536`](https://github.com/nocobase/nocobase/pull/536) +- **feat(plugin-workflow)** : Ajout d'un nouveau type de noeud "délai" [`#532`](https://github.com/nocobase/nocobase/pull/532) +- **refactor** : Refactorisation de l'application cliente [`#533`](https://github.com/nocobase/nocobase/pull/533) +- **fix** : Correction de la transaction manquante [`#531`](https://github.com/nocobase/nocobase/pull/531) +- **fix** : Ajout de la propriété d'ellipsis dans le sélecteur d'enregistrements [`#527`](https://github.com/nocobase/nocobase/pull/527) +- **fix** : Suppression du modèle sans élément de formulaire [`#528`](https://github.com/nocobase/nocobase/pull/528) +- **fix(plugin-workflow)** : Mise à jour de la propriété "current" lors de la mise à jour [`#526`](https://github.com/nocobase/nocobase/pull/526) +- **fix** : Ordre des valeurs nulles en dernier [`#519`](https://github.com/nocobase/nocobase/pull/519) +- **fix** : Chargement des actions, rafraîchissement du contexte, soumission de formulaire et validation [`#523`](https://github.com/nocobase/nocobase/pull/523) +- **fix** : Correction du modèle de champ [`#520`](https://github.com/nocobase/nocobase/pull/520) +- **fix(plugin-workflow)** : Correction de la largeur minimale du sélecteur de recherche [`#524`](https://github.com/nocobase/nocobase/pull/524) +- **fix** : Modèle avec uniquement des champs [`#517`](https://github.com/nocobase/nocobase/pull/517) +- **fix(plugin-workflow)** : Correction de la mise à jour de la propriété "current" dans le workflow [`#521`](https://github.com/nocobase/nocobase/pull/521) +- **refactor(plugin-workflow)** : Abstraction vers des classes [`#515`](https://github.com/nocobase/nocobase/pull/515) +- **feat** : Colonnes triables et modèle de champ [`#518`](https://github.com/nocobase/nocobase/pull/518) +- **fix(custom-request)** : Support des modèles string/json [`#514`](https://github.com/nocobase/nocobase/pull/514) +- **feat** : Ajout du titre de bloc [`#513`](https://github.com/nocobase/nocobase/pull/513) +- **fix** : Suppression des collections et des champs de la base de données [`#511`](https://github.com/nocobase/nocobase/pull/511) +- **feat** : Amélioration des migrations [`#510`](https://github.com/nocobase/nocobase/pull/510) +- **fix(client)** : Consolidation de l'utilisation des dates/heure en UTC lors du transfert [`#509`](https://github.com/nocobase/nocobase/pull/509) +- **fix** : Correction du bug de la formule [`#508`](https://github.com/nocobase/nocobase/pull/508) +- **fix** : Exportation par défaut des champs [`#506`](https://github.com/nocobase/nocobase/pull/506) +- **feat** : Bloc de champ d'association [`#493`](https://github.com/nocobase/nocobase/pull/493) +- **feat** : Exportation de plugins [`#479`](https://github.com/nocobase/nocobase/pull/479) +- **fix(client)** : Chemin du paquet corrigé (fix #503) [`#504`](https://github.com/nocobase/nocobase/pull/504) +- **fix** : Correction de l'erreur lors de la création ou suppression de collection [`#501`](https://github.com/nocobase/nocobase/pull/501) +- **feat** : Mise à jour des collections et des champs [`#500`](https://github.com/nocobase/nocobase/pull/500) +- **fix** : Rollback lorsque la création d'un champ échoue [`#498`](https://github.com/nocobase/nocobase/pull/498) +- **fix(client)** : Définition de `dropdownMatchSelectWidth` sur `false` globalement [`#497`](https://github.com/nocobase/nocobase/pull/497) +- **fix(client)** : Avertissement de clé manquante dans les éléments de menu utilisateur [`#496`](https://github.com/nocobase/nocobase/pull/496) +- **feat(plugin workflow)** : Ajout du champ cron pour la configuration des déclencheurs programmés [`#495`](https://github.com/nocobase/nocobase/pull/495) +- **feat** : Journaux d'audit [`#494`](https://github.com/nocobase/nocobase/pull/494) +- **refactor(plugin-workflow)** : Ajout d'une colonne de révision à l'exécution [`#491`](https://github.com/nocobase/nocobase/pull/491) +- **feat** : UI Schema pour le champ de relation [`#487`](https://github.com/nocobase/nocobase/pull/487) +- **feat** : Changement du FK en composant de saisie [`#488`](https://github.com/nocobase/nocobase/pull/488) +- **fix(plugin-multi-app-manager)** : Correction des tests de création de base de données pg qui échouent [`#486`](https://github.com/nocobase/nocobase/pull/486) +- **refactor(database)** : Proxy pour les hooks [`#402`](https://github.com/nocobase/nocobase/pull/402) +- **feat** : Blocs de graphiques [`#484`](https://github.com/nocobase/nocobase/pull/484) +- **refactor(plugin-workflow)** : Support des nombres dans la configuration de répétition pour la planification [`#482`](https://github.com/nocobase/nocobase/pull/482) +- **chore(debug)** : Ajout de la configuration de débogage [`#475`](https://github.com/nocobase/nocobase/pull/475) +- **fix** : Correction du bug "has one" [`#478`](https://github.com/nocobase/nocobase/pull/478) +- **feat** : Relations [`#473`](https://github.com/nocobase/nocobase/pull/473) +- **fix(plugin-workflow)** : Correction de la transaction de déclencheur de collection [`#474`](https://github.com/nocobase/nocobase/pull/474) +- **fix(plugin-workflow)** : Solution temporaire pour les conditions de déclencheur de collection [`#472`](https://github.com/nocobase/nocobase/pull/472) +- **fix** : Composant markdown [`#469`](https://github.com/nocobase/nocobase/pull/469) +- **fix** : Champ de formule et champ pourcentage [`#467`](https://github.com/nocobase/nocobase/pull/467) +- **fix(plugin-workflow)** : Correction de la mise à jour de l'action dans le workflow [`#464`](https://github.com/nocobase/nocobase/pull/464) +- **fix** : Mise à jour du champ de formule et du champ pourcentage [`#461`](https://github.com/nocobase/nocobase/pull/461) +- **feat** : Ajout du type de champ formule [`#457`](https://github.com/nocobase/nocobase/pull/457) +- **fix** : Les détails des données associées dans le sous-tableau ne sont pas affichés [`#454`](https://github.com/nocobase/nocobase/pull/454) +- **fix(plugin-workflow)** : Correction des langues [`#451`](https://github.com/nocobase/nocobase/pull/451) +- **fix** : Le hook `afterSync` n'est pas déclenché [`#450`](https://github.com/nocobase/nocobase/pull/450) +- **docs(various)** : Amélioration de la lisibilité [`#447`](https://github.com/nocobase/nocobase/pull/447) +- **feat** : Requête personnalisée [`#439`](https://github.com/nocobase/nocobase/pull/439) +- **feat(plugin workflow)** : Déclencheur programmé [`#438`](https://github.com/nocobase/nocobase/pull/438) +- **feat** : Migrateur de base de données [`#432`](https://github.com/nocobase/nocobase/pull/432) +- **fix(client)** : Le composant de sélection ne peut pas être ouvert dans un bloc de sous-table [`#431`](https://github.com/nocobase/nocobase/pull/431) +- **docs(github)** : Passage au format markdown [`#430`](https://github.com/nocobase/nocobase/pull/430) +- **fix(cli)** : Correction de fautes de frappe [`#429`](https://github.com/nocobase/nocobase/pull/429) + +## Problèmes Résolus + +- **fix(client)** : Chemin du paquet corrigé (fix #503) [`#503`](https://github.com/nocobase/nocobase/issues/503) + +## Commits + +- **feat(client)** : Mise à jour des locales [`e57e60e`](https://github.com/nocobase/nocobase/commit/e57e60e6cb84431e694e69830d128cd71938388f) +- **docs** : Mise à jour de la documentation [`e5cb948`](https://github.com/nocobase/nocobase/commit/e5cb94803f738961fcbc1986a94d258ef9e191a9) +- **fix(client)** : Amélioration du composant datepicker, prise en charge des dates avec fuseau horaire et GMT [`1c03fbb`](https://github.com/nocobase/nocobase/commit/1c03fbb853b5885547835f50fc9a0932f63c363b) diff --git a/docs/fr-FR/welcome/release/v0072-changelog.md b/docs/fr-FR/welcome/release/v0072-changelog.md new file mode 100644 index 000000000..294ff54ea --- /dev/null +++ b/docs/fr-FR/welcome/release/v0072-changelog.md @@ -0,0 +1,29 @@ +# v0.7.2 : 2022-07-05 + +## Fonctionnalités Fusionnées + +- **chore(versions)** : Publication de la version v0.7.2-alpha.1 😊 [`#578`](https://github.com/nocobase/nocobase/pull/578) +- **fix** : Suppression de toutes les clés étrangères [`#576`](https://github.com/nocobase/nocobase/pull/576) +- **fix(plugin-workflow)** : Correction de la configuration du déclencheur de collection [`#575`](https://github.com/nocobase/nocobase/pull/575) +- **feat** : Filtrage avec variables [`#574`](https://github.com/nocobase/nocobase/pull/574) +- **feat(cli)** : Vérification de la version de la base de données avant l'installation [`#572`](https://github.com/nocobase/nocobase/pull/572) +- **fix(database)** : Correction de l'index invalide [`#564`](https://github.com/nocobase/nocobase/pull/564) +- **fix** : Exportation des données de la table d'association [`#561`](https://github.com/nocobase/nocobase/pull/561) +- **refactor(plugin-workflow)** : Déplacement des fichiers client dans le plugin [`#556`](https://github.com/nocobase/nocobase/pull/556) +- **fix(database)** : Les contraintes sont maintenant par défaut à `false` [`#550`](https://github.com/nocobase/nocobase/pull/550) +- **fix(plugin-workflow)** : Correction de la largeur du sélecteur [`#552`](https://github.com/nocobase/nocobase/pull/552) +- **feat** : Compatible avec l'ancien Kanban [`#553`](https://github.com/nocobase/nocobase/pull/553) +- **feat** : Affichage des champs d'association [`#512`](https://github.com/nocobase/nocobase/pull/512) +- **fix(plugin-workflow)** : Correction générale dans le plugin workflow [`#549`](https://github.com/nocobase/nocobase/pull/549) +- **fix** : Mise à jour du port MySQL [`#548`](https://github.com/nocobase/nocobase/pull/548) +- **fix** : Exportation des blocs de relation [`#546`](https://github.com/nocobase/nocobase/pull/546) +- **fix(plugin-workflow)** : Réinitialisation des options lors du changement de collection [`#547`](https://github.com/nocobase/nocobase/pull/547) +- **feat(plugin-workflow)** : Ajout du mode "race" [`#542`](https://github.com/nocobase/nocobase/pull/542) +- **fix(client)** : Changement de `toArr` à `_.castArray` dans le composant de sélection [`#543`](https://github.com/nocobase/nocobase/pull/543) +- **chore(versions)** : Publication de la version v0.7.1-alpha.7 😊 [`#539`](https://github.com/nocobase/nocobase/pull/539) + +## Commits + +- **fix(client)** : Commentaire du code inutile [`4e9384b`](https://github.com/nocobase/nocobase/commit/4e9384bce27676a3cc1ce8d8fd08f5611cffbe5a) +- **fix(workflow)** : Fusion des fournisseurs de workflow [`008a7f7`](https://github.com/nocobase/nocobase/commit/008a7f7f3351bdedf01b4490d1658edeacc95a16) +- **feat(client)** : Champ entier [`9928424`](https://github.com/nocobase/nocobase/commit/9928424f5a163fe4edd7cfd60f349ca65b47c9bf) diff --git a/docs/fr-FR/welcome/release/v0073-changelog.md b/docs/fr-FR/welcome/release/v0073-changelog.md new file mode 100644 index 000000000..a57372254 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0073-changelog.md @@ -0,0 +1,33 @@ +# v0.7.3 : 2022-07-10 + +## Fonctionnalités Fusionnées + +- **chore(versions)** : Publication de la version v0.7.3-alpha.1 😊 [`#657`](https://github.com/nocobase/nocobase/pull/657) +- **feat** : Action d'impression (`print action`) [`#652`](https://github.com/nocobase/nocobase/pull/652) +- **feat** : Restauration des hooks d'actions (`restore action-hooks`) [`#655`](https://github.com/nocobase/nocobase/pull/655) +- **feat** : Problème de pagination des collections et des champs (`collections&fields pagination issue`) [`#653`](https://github.com/nocobase/nocobase/pull/653) +- **fix(core)** : Changement des méthodes de l'agent proxy par des méthodes natives (`change proxied agent methods to native`) [`#654`](https://github.com/nocobase/nocobase/pull/654) +- **feat** : Suppression des actions de détails de champs de table (`remove table field details actions`) [`#638`](https://github.com/nocobase/nocobase/pull/638) +- **fix** : Lien vers la valeur par défaut (`link to default value`) [`#641`](https://github.com/nocobase/nocobase/pull/641) +- **feat** : Prise en charge de l'affichage des champs de tables relationnelles dans les blocs de détails ou de formulaires (`support for displaying relational table fields in details or form blocks`) [`#635`](https://github.com/nocobase/nocobase/pull/635) +- **fix** : Sélecteur d'enregistrements ne peut pas sélectionner d'éléments à partir de pages différentes (`record picker cannot select from different pages`) [`#623`](https://github.com/nocobase/nocobase/pull/623) +- **fix** : Faire glisser un élément vers la gauche, la droite ou le bas faisait disparaître l'élément (`dragging an element to the left, right, or bottom would cause the element to disappear`) [`#620`](https://github.com/nocobase/nocobase/pull/620) +- **feat** : Ajout d'un bouton de rechargement pour l'action de la table (`table action add reload button`) [`#630`](https://github.com/nocobase/nocobase/pull/630) +- **feat** : Amélioration des paramètres de langue (`improve language settings`) [`#627`](https://github.com/nocobase/nocobase/pull/627) +- **feat** : L'assignation des champs pour les actions personnalisées prend désormais en charge les variables de type chaîne de caractères (`field assignment for custom actions supports string variables`) [`#597`](https://github.com/nocobase/nocobase/pull/597) +- **fix** : Sauter la suppression récursive sur le composant de grille (`skip recursive remove on grid component`) [`#621`](https://github.com/nocobase/nocobase/pull/621) +- **feat** : Correction de l'heure et de la pagination des collections (`fix time and collection pagination`) [`#618`](https://github.com/nocobase/nocobase/pull/618) +- **feat** : Sélection des champs d'initialisation du bloc d'enregistrement (`recordblockinitializers fields pick`) [`#558`](https://github.com/nocobase/nocobase/pull/558) +- **fix** : Problème d'arrière-plan actif incorrect (`incorrectly :active background`) [`#607`](https://github.com/nocobase/nocobase/pull/607) +- **fix** : Sélecteur de table OBO (`obo table selector`) [`#613`](https://github.com/nocobase/nocobase/pull/613) +- **feat** : Validation des formulaires (`form validator`) [`#569`](https://github.com/nocobase/nocobase/pull/569) +- **fix** : Sélecteur de table (`table selector`) [`#612`](https://github.com/nocobase/nocobase/pull/612) +- **chore(versions)** : Publication de la version v0.7.2-alpha.7 😊 [`#611`](https://github.com/nocobase/nocobase/pull/611) +- **chore(versions)** : Publication de la version v0.7.2-alpha.3 😊 [`#608`](https://github.com/nocobase/nocobase/pull/608) +- **chore(versions)** : Publication de la version v0.7.2-alpha.2 😊 [`#606`](https://github.com/nocobase/nocobase/pull/606) + +## Commits + +- **fix(client)** : Correction d'une erreur de build (`build error`) [`600f13f`](https://github.com/nocobase/nocobase/commit/600f13f4a06ccfed27df928d7435afa83391c18a) +- **fix(client)** : Les blocs sont supprimés lorsqu'ils sont glissés sous le bloc actuel (`blocks are deleted when they are dragged below the current block`) [`20ab8c1`](https://github.com/nocobase/nocobase/commit/20ab8c15017d9dbf941bf963ce3023115050edf8) +- **feat(client)** : Ajout des icônes et traductions de la barre d'outils du plugin (`plugin toolbar icons and translations`) [`c51c6c0`](https://github.com/nocobase/nocobase/commit/c51c6c097f24417f0ff82d3c5178ec3be1ee7630) diff --git a/docs/fr-FR/welcome/release/v0074-changelog.md b/docs/fr-FR/welcome/release/v0074-changelog.md new file mode 100644 index 000000000..67ae11cde --- /dev/null +++ b/docs/fr-FR/welcome/release/v0074-changelog.md @@ -0,0 +1,40 @@ +# v0.7.4 : 2022-08-12 + +## Fonctionnalités Fusionnées + +- **chore(versions)** : Publication de la version v0.7.4-alpha.4 😊 [`#727`](https://github.com/nocobase/nocobase/pull/727) +- **fix** : Synchronisation du tri des tables avec l'export (`sync table sort to export`) [`#723`](https://github.com/nocobase/nocobase/pull/723) +- **feat** : Version complète du fichier Docker de NocoBase (`full version of the NocoBase dockerfile`) [`#719`](https://github.com/nocobase/nocobase/pull/719) +- **fix(plugin-workflow)** : Correction de l'extension de la collection (`fix extend collection`) [`#708`](https://github.com/nocobase/nocobase/pull/708) +- **fix** : Le préfixe DB_TABLE_PREFIX n'est pas appliqué (`DB_TABLE_PREFIX doesn't get applied`) [`#710`](https://github.com/nocobase/nocobase/pull/710) +- **feat** : Valeur par défaut (`default value`) [`#679`](https://github.com/nocobase/nocobase/pull/679) +- **fix** : Erreur de soumission lors de la suppression d'un champ requis (`required field delete submit error`) [`#694`](https://github.com/nocobase/nocobase/pull/694) +- **chore(versions)** : Publication de la version v0.7.4-alpha.1 😊 [`#696`](https://github.com/nocobase/nocobase/pull/696) +- **fix** : Ajout des rôles à l'utilisateur actuel (`append roles to current user`) [`#695`](https://github.com/nocobase/nocobase/pull/695) +- **fix** : Correction du format de la date (`fix date format`) [`#686`](https://github.com/nocobase/nocobase/pull/686) +- **test(plugin-workflow)** : Sauter les tests de prompt (`skip prompt tests`) [`#692`](https://github.com/nocobase/nocobase/pull/692) +- **fix** : Correction de la précision des pourcentages (`fix accuracy of percent`) [`#685`](https://github.com/nocobase/nocobase/pull/685) +- **fix(plugin-workflow)** : Ajustement du temps d'attente de l'async pour les cas de test (`adjust await sleep time for test cases`) [`#691`](https://github.com/nocobase/nocobase/pull/691) +- **feat(plugin-workflow)** : Ajout de la configuration des assignees pour l'instruction de prompt (`add assignees config for prompt instruction`) [`#690`](https://github.com/nocobase/nocobase/pull/690) +- **fix** : Problème d'affichage du bouton d'exportation des rôles (`role export button display`) [`#666`](https://github.com/nocobase/nocobase/pull/666) +- **feat** : Validation de l'UID (`uid validate`) [`#681`](https://github.com/nocobase/nocobase/pull/681) +- **refactor** : Remplacement de `react-drag-listview` par `@dnd-kit/sortable` (`replace react-drag-listview with @dnd-kit/sortable`) [`#660`](https://github.com/nocobase/nocobase/pull/660) +- **refactor(plugin-users)** : Amélioration de l'extensibilité des middlewares (`improve extendibility of middlewares`) [`#677`](https://github.com/nocobase/nocobase/pull/677) +- **feat** : O2M (One to Many) suppression sans rafraîchissement (`o2m delete not refresh`) [`#646`](https://github.com/nocobase/nocobase/pull/646) +- **feat** : Ajout de la description au Kanban (`kanban add description`) [`#659`](https://github.com/nocobase/nocobase/pull/659) +- **fix** : Perte de l'énumération d'un champ (`field loss enum`) [`#667`](https://github.com/nocobase/nocobase/pull/667) +- **feat** : Ajout du raccourci clavier Ctrl+Shift+U pour l'éditeur (`add editor hot key Ctrl+Shift+U`) [`#675`](https://github.com/nocobase/nocobase/pull/675) +- **fix** : Correction de l'erreur de changement de champ dans le calendrier (`Fix calendar change field error`) [`#671`](https://github.com/nocobase/nocobase/pull/671) +- **chore** : Correction de l'outil ESLint qui ne fonctionnait pas (`fix eslint not work`) [`#670`](https://github.com/nocobase/nocobase/pull/670) +- **feat** : Précision des nombres (`number precision`) [`#661`](https://github.com/nocobase/nocobase/pull/661) +- **feat** : Configuration de Nginx (`nginx config`) [`#664`](https://github.com/nocobase/nocobase/pull/664) +- **feat** : Problème de bascule de formulaire dans le designer (`form item designer form switch issue`) [`#656`](https://github.com/nocobase/nocobase/pull/656) + +## Commits + +- **feat** : Ajout d'exemples (`add examples`) [`b848b9c`](https://github.com/nocobase/nocobase/commit/b848b9cd6774df6ed86acd30edb81ed6381c3555) +- **fix** : Le fournisseur d'enregistrements est requis pour la lecture correcte (`record provider required for read pretty`) [`38c3e3e`](https://github.com/nocobase/nocobase/commit/38c3e3e4cc2698069c741d25ddda8e3e8e4d1db0) +- **update** : Mise à jour du README.zh-CN.md (`Update README.zh-CN.md`) [`ba0e618`](https://github.com/nocobase/nocobase/commit/ba0e61873e7f69dee6a76929eb774828ac980760) +- **fix(client)** : Problème avec `fieldNames` du `RecordPicker` (`fieldNames of RecordPicker`) [`9038d11`](https://github.com/nocobase/nocobase/commit/9038d111ea71a89798cb1499f3dadc3f9c3dbfd7) +- **fix(client)** : Champ requis pour le sous-tableau (`required for the sub-table field`) [`609b0e2`](https://github.com/nocobase/nocobase/commit/609b0e2ff2d5aece96185cbcd30ec1810194be0d) +- **feat(client)** : Ajout d'icône d'onglet (`tab icon`) [`d9b2bf8`](https://github.com/nocobase/nocobase/commit/d9b2bf8af1c42e2f4e81533f6db92b19523410bd) diff --git a/docs/fr-FR/welcome/release/v0075-changelog.md b/docs/fr-FR/welcome/release/v0075-changelog.md new file mode 100644 index 000000000..c57e44cf4 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0075-changelog.md @@ -0,0 +1,61 @@ +# v0.7.5 : 2022-10-16 + +## Fonctionnalités Fusionnées + +- **chore(versions)** : Publication de la version v0.7.5-alpha.1 😊 [`#920`](https://github.com/nocobase/nocobase/pull/920) +- **feat** : Ajout du champ de collection dans le plugin workflow (`plugin workflow collection field`) [`#919`](https://github.com/nocobase/nocobase/pull/919) +- **feat** : Création avec un tableau de valeurs (`create with array of values`) [`#912`](https://github.com/nocobase/nocobase/pull/912) +- **fix** : Détachement en cas d'erreur (`unbind on error throwing`) [`#914`](https://github.com/nocobase/nocobase/pull/914) +- **fix** : Fusion des ajouts utilisant désormais la clé primaire (`appends merge now using primary key`) [`#911`](https://github.com/nocobase/nocobase/pull/911) +- **feat** : Limite de l'identifiant de la base de données (`limit database identifier`) [`#908`](https://github.com/nocobase/nocobase/pull/908) +- **fix** : Synchronisation de la valeur par défaut du champ de collection (`sync collection field default value`) [`#907`](https://github.com/nocobase/nocobase/pull/907) +- **fix** : Fusion des ajouts incluant désormais les bonnes relations (`appends merge includes`) [`#905`](https://github.com/nocobase/nocobase/pull/905) +- **fix** : Problème de requête avec les relations simples (`single relation repository appends query issue`) [`#901`](https://github.com/nocobase/nocobase/pull/901) +- **feat(plugin-workflow)** : Ajout du calculateur de concaténation (`add concat calculator`) [`#894`](https://github.com/nocobase/nocobase/pull/894) +- **fix(client/record-picker)** : Support de la vue formatée pour `DataPicker` dans le `RecordPicker` (`support record-picker show format DataPicker`) [`#888`](https://github.com/nocobase/nocobase/pull/888) +- **fix(client/block-select-collection)** : Correction de l'erreur d'affichage du menu de sélection de collection (`fix select collection menu view error`) [`#889`](https://github.com/nocobase/nocobase/pull/889) +- **fix** : Impossible de soumettre un formulaire lors du téléchargement de fichiers (`unable to submit form during file upload`) [`#892`](https://github.com/nocobase/nocobase/pull/892) +- **fix** : Exécution des tests par Jest (`run test by jest`) [`#891`](https://github.com/nocobase/nocobase/pull/891) +- **feat(collection-manager)** : Les champs inversés peuvent être configurés (`inverse fields can be configured`) [`#883`](https://github.com/nocobase/nocobase/pull/883) +- **fix(formula)** : Support des entiers et correction de l'erreur NaN (`support integer and fix NaN error`) [`#879`](https://github.com/nocobase/nocobase/pull/879) +- **fix** : Le paramètre de tri est manquant (`sort parameter is missing`) [`#849`](https://github.com/nocobase/nocobase/pull/849) +- **fix** : Requête de jointure lente émise par les ajouts de champs dans la méthode `find` du repository (`slow join query issued by appends field in find method of repository`) [`#845`](https://github.com/nocobase/nocobase/pull/845) +- **feat(core/cache)** : Support du cache (`support cache`) [`#876`](https://github.com/nocobase/nocobase/pull/876) +- **feat** : Mise à jour des options nécessitant un filtre ou `filterByTk` (`update option must have filter or filterByTk`) [`#847`](https://github.com/nocobase/nocobase/pull/847) +- **feat** : Traduction en russe ajoutée (`added Russian translation`) [`#840`](https://github.com/nocobase/nocobase/pull/840) +- **feat(database)** : Ajout du type de champ séquence (`add sequence field type`) [`#779`](https://github.com/nocobase/nocobase/pull/779) +- **fix** : Impossible d'accéder aux pages sans permission via URL (`can't access pages without permission via url`) [`#826`](https://github.com/nocobase/nocobase/pull/826) +- **refactor(resourcer)** : Combinaison des classes de middleware (`combine middleware class`) [`#825`](https://github.com/nocobase/nocobase/pull/825) +- **refactor(database)** : Correction de certains champs et types (`fix some fields and types`) [`#820`](https://github.com/nocobase/nocobase/pull/820) +- **feat(locale)** : Traduction en japonais ajoutée (`added Japanese translation`) [`#813`](https://github.com/nocobase/nocobase/pull/813) +- **fix(plugin-workflow)** : Correction du type de valeur pour `DatePicker` vers `moment` (`fix value type for DatePicker to moment`) [`#819`](https://github.com/nocobase/nocobase/pull/819) +- **refactor(plugin-workflow)** : Exportation du registre des calculateurs client (`export client calculators registry`) [`#816`](https://github.com/nocobase/nocobase/pull/816) +- **fix** : Le type de stockage des nombres a été changé en double (`number storage type changed to double`) [`#810`](https://github.com/nocobase/nocobase/pull/810) +- **refactor(server)** : Refactorisation du serveur (`refactor server`) [`#795`](https://github.com/nocobase/nocobase/pull/795) +- **fix(plugin-verification)** : Changement de l'erreur de limitation du taux du fournisseur à 429 (`change provider rate limit error to 429`) [`#788`](https://github.com/nocobase/nocobase/pull/788) +- **fix(plugin-cm)** : Correction du champ qui disparaît après une mise à jour échouée (`fix field disappear after failed to update`) [`#773`](https://github.com/nocobase/nocobase/pull/773) +- **fix** : Correction de `uiSchema` indéfini (`fix uiSchema undefined`) [`#770`](https://github.com/nocobase/nocobase/pull/770) +- **fix(plugin-cm)** : Correction de la valeur par défaut de l'option unique pour la mise à jour (`fix unique option default value to update`) [`#768`](https://github.com/nocobase/nocobase/pull/768) +- **fix(plugin-users)** : Correction de l'erreur 500 lors de la mise à jour du profil (`fix update profile 500`) [`#767`](https://github.com/nocobase/nocobase/pull/767) +- **fix** : Colonne MySQL dans la clause WHERE ambiguë (`mysql column in where clause is ambiguous`) [`#756`](https://github.com/nocobase/nocobase/pull/756) +- **feat(plugin-cm)** : Ajout de l'option unique pour les champs de base (`add unique option for base fields`) [`#745`](https://github.com/nocobase/nocobase/pull/745) +- **feat(plugin-verification)** : Ajout du plugin de vérification et du téléphone pour les utilisateurs (`add plugin-verification and phone for users`) [`#722`](https://github.com/nocobase/nocobase/pull/722) +- **feat** : Redimensionnement des colonnes de la grille avec glisser-déposer (`resize grid columns with drag and drop`) [`#748`](https://github.com/nocobase/nocobase/pull/748) +- **refactor(client)** : Scission des initialisateurs de schéma en plusieurs fichiers (`split schema-initializer items into multiple files`) [`#744`](https://github.com/nocobase/nocobase/pull/744) +- **refactor(plugin-workflow)** : Changement du mode des fichiers en 644 (`change files mode to 644`) [`#755`](https://github.com/nocobase/nocobase/pull/755) +- **fix** : Vérification de la version de la base de données (`db version check`) [`#749`](https://github.com/nocobase/nocobase/pull/749) +- **feat** : Ajout d'exemples (`add examples`) [`#718`](https://github.com/nocobase/nocobase/pull/718) + +## Corrections + +- **fix(plugin-workflow)** : Correction du type de valeur pour `DatePicker` vers `moment` (`fix value type for DatePicker to moment`) [`#815`](https://github.com/nocobase/nocobase/issues/815) +- **fix(plugin-users)** : Correction de l'erreur 500 lors de la mise à jour du profil (`fix + + update profile 500`) [`#766`](https://github.com/nocobase/nocobase/issues/766) +- **fix** : Vérification de la version de la base de données (`db version check`) [`#742`](https://github.com/nocobase/nocobase/issues/742) + +## Commits + +- **fix(client)** : Initialisateurs de panneau d'onglets pour le formulaire de création de bloc (`tab pane initializers for create form block`) [`7efc4bc`](https://github.com/nocobase/nocobase/commit/7efc4bca0e3c5f2e1c5cd9e1365e77a005f3e108) +- **fix** : Problème de transaction qui ne peut être annulée (`transaction cannot be rolled back because it has been finished with state: rollback`) [`6dacec4`](https://github.com/nocobase/nocobase/commit/6dacec4158103fd165ec2865ea87ed9d3d4ceaa4) +- **fix(database)** : Correction de l'erreur de nom d'index trop long (`fix the index name too long error`) [`7bfe6b8`](https://github.com/nocobase/nocobase/commit/7bfe6b8c46bef0183c4703683175561c7fc91aee) diff --git a/docs/fr-FR/welcome/release/v0080-changelog.md b/docs/fr-FR/welcome/release/v0080-changelog.md new file mode 100644 index 000000000..c95911fef --- /dev/null +++ b/docs/fr-FR/welcome/release/v0080-changelog.md @@ -0,0 +1,215 @@ +# v0.8 : 2022-11-01 + +Avec la version v0.8, NocoBase introduit un **gestionnaire de plugins** et une **documentation de développement** plus complète. Voici les principaux changements apportés. + +## Améliorations de l'interface (coin supérieur droit) + +- **UI Editor** +- **Plugin Manager** +- **Settings Center** +- **Personal Center** + +![Coin supérieur droit de l'interface](./v08-changelog/topright.jpg) + +## Nouveau gestionnaire de plugins + +La version v0.8 introduit un gestionnaire de plugins puissant pour gérer les plugins de manière sans code. + +### Flux du gestionnaire de plugins + +![Flux du gestionnaire de plugins](./v08-changelog/pm-flow.svg) + +### Interface du gestionnaire de plugins + +Actuellement, il est principalement utilisé pour désactiver, activer et supprimer des plugins locaux. Les plugins intégrés ne peuvent pas être supprimés. + +![Interface du gestionnaire de plugins](./v08-changelog/pm-ui.jpg) + +### Commandes du gestionnaire de plugins + +Outre la possibilité d'activer et de désactiver des plugins depuis l'interface sans code, vous pouvez également gérer les plugins de manière plus complète via la ligne de commande. + +```bash +# Créer un plugin +yarn pm create hello +# Enregistrer le plugin +yarn pm add hello +# Activer le plugin +yarn pm enable hello +# Désactiver le plugin +yarn pm disable hello +# Supprimer le plugin +yarn pm remove hello +``` + +Note : La publication et la mise à jour des plugins seront prises en charge dans les prochaines versions. + +```bash +# Publier le plugin +yarn pm publish hello +# Mettre à jour le plugin +yarn pm upgrade hello +``` + +Pour plus d'exemples de plugins, consultez [packages/samples](https://github.com/nocobase/nocobase/tree/main/packages/samples). + +## Changements relatifs aux plugins + +### Structure du répertoire d'un plugin + +``` +|- /hello + |- /src + |- /client # Plugin côté client + |- /server # Plugin côté serveur + |- client.d.ts + |- client.js + |- package.json # Informations sur le package du plugin + |- server.d.ts + |- server.js +``` + +### Spécification du nom du plugin + +Un plugin NocoBase est également un package NPM. La règle de correspondance entre le nom du plugin et le nom du package NPM est `${PLUGIN_PACKAGE_PREFIX}-${pluginName}`. + +`PLUGIN_PACKAGE_PREFIX` est le préfixe du package du plugin, et peut être personnalisé dans le fichier `.env`. [Cliquez ici pour la description de `PLUGIN_PACKAGE_PREFIX`](https://www.notion.so/api/env#plugin_package_prefix). + +Par exemple, un projet nommé `my-nocobase-app` ajoutant le plugin `hello` aura le nom du package `@my-nocobase-app/plugin-hello`. + +La configuration de `PLUGIN_PACKAGE_PREFIX` se fait comme suit : + +```bash +PLUGIN_PACKAGE_PREFIX=@nocobase/plugin-,@nocobase/preset-,@my-nocobase-app/plugin- +``` + +La correspondance entre le nom du plugin et le nom du package est la suivante : + +- Plugin `users` → nom du package `@nocobase/plugin-users` +- Plugin `nocobase` → nom du package `@nocobase/preset-nocobase` +- Plugin `hello` → nom du package `@my-nocobase-app/plugin-hello` + +### Cycle de vie du plugin + +La version v0.8 introduit un cycle de vie plus complet pour les plugins. + +```typescript +import { InstallOptions, Plugin } from '@nocobase/server'; + +export class HelloPlugin extends Plugin { + afterAdd() { + // Après l'ajout du plugin via pm.add + } + + beforeLoad() { + // Avant le chargement de tous les plugins, généralement utilisé pour enregistrer des classes et des écouteurs d'événements + } + + async load() { + // Charger la configuration + } + + async install(options?: InstallOptions) { + // Logique d'installation + } + + async afterEnable() { + // Après l'activation + } + + async afterDisable() { + // Après la désactivation + } + + async remove() { + // Logique de suppression + } +} + +export default HelloPlugin; +``` + +### Entrées pour les plugins côté client et côté serveur + +Le cycle de vie du plugin est contrôlé par le serveur. + +```typescript +import { Application } from '@nocobase/server'; + +const app = new Application({ + // ... +}); + +class MyPlugin extends Plugin { + afterAdd() {} + beforeLoad() {} + load() {} + install() {} + afterEnable() {} + afterDisable() {} + remove() {} +} + +app.plugin(MyPlugin, { name: 'my-plugin' }); +``` + +Le côté client du plugin existe en tant que `Context.Provider` (similaire au middleware côté serveur). + +```typescript +import React from 'react'; +import { Application } from '@nocobase/client'; + +const app = new Application({ + apiClient: { + baseURL: process.env.API_BASE_URL, + }, + dynamicImport: (name: string) => { + return import(`../plugins/${name}`); + }, +}); + +// Lorsque vous visitez la page /hello, cela affiche "Hello world!" +const HelloProvider = React.memo((props) => { + const location = useLocation(); + if (location.pathname === '/hello') { + return <div>Hello world!</div>; + } + return <>{props.children}</>; +}); +HelloProvider.displayName = 'HelloProvider'; + +app.use(HelloProvider); +``` + +## Code métier personnalisé + +Les plugins de la version v0.7 n'étaient pas entièrement complétés, et le code métier personnalisé était souvent dispersé dans `packages/app/client` et `packages/app/server`, ce qui compliquait les mises à jour et la maintenance. La version v0.8 recommande maintenant d'organiser ce code sous forme de packages de plugins et d'utiliser `yarn pm` pour gérer les plugins. + +## Documentation plus complète + +- **Welcome** : Une vue rapide de NocoBase +- **Manual** : Apprenez-en davantage sur les fonctionnalités principales de NocoBase +- **Plugin Development Tutorial** : Approfondissez le développement de plugins +- **API Reference** : Consultez l'API lors du développement de plugins +- **Client Components Library** (en préparation) : Fournit des exemples et l'utilisation des composants NocoBase + +## Plus d'exemples de plugins + +- [command](https://github.com/nocobase/nocobase/tree/develop/packages/samples/command) +- [custom-block](https://github.com/nocobase/nocobase/tree/develop/packages/samples/custom-block) +- [custom-page](https://github.com/nocobase/nocobase/tree/develop/packages/samples/custom-page) +- [custom-signup-page](https://github.com/nocobase/nocobase/tree/develop/packages/samples/custom-signup-page) +- [hello](https://github.com/nocobase/nocobase/tree/develop/packages/samples/hello) +- [ratelimit](https://github.com/nocobase/nocobase/tree/develop/packages/samples/ratelimit) +- [shop-actions](https://github.com/nocobase/nocobase/tree/develop/packages/samples/shop-actions) +- [shop-events](https://github.com/nocobase/nocobase/tree/develop/packages/samples/shop-events) +- [shop-i18n](https://github.com/nocobase/nocobase/tree/develop/packages/samples/shop-i18n) +- [shop-modeling](https://github.com/nocobase/nocobase/tree/develop/packages/samples/shop-modeling) + +## Autres nouvelles fonctionnalités + +- Importation depuis Excel +- Mise à jour et édition en masse +- Collections graphiques +- Historique d'exécution des workflows +- Champ JSON diff --git a/docs/fr-FR/welcome/release/v0091-changelog.md b/docs/fr-FR/welcome/release/v0091-changelog.md new file mode 100644 index 000000000..4ff00385c --- /dev/null +++ b/docs/fr-FR/welcome/release/v0091-changelog.md @@ -0,0 +1,108 @@ +# v0.9.1 : 2023-03-09 + +## Fusionnées + +- **fix(plugin-workflow)** : correction de l'importation des modules (#1550) [`#1552`](https://github.com/nocobase/nocobase/pull/1552) +- **chore** : réponse du référentiel de relation lorsque le modèle source n'est pas trouvé [`#1546`](https://github.com/nocobase/nocobase/pull/1546) +- **fix(plugin-workflow)** : correction du composant de configuration des assignees dans le nœud manuel [`#1547`](https://github.com/nocobase/nocobase/pull/1547) +- **feat** : ajout de l'état "stopped" dans l'application [`#1543`](https://github.com/nocobase/nocobase/pull/1543) +- **fix(plugin-workflow)** : correction du chemin du champ AssociationInput [`#1542`](https://github.com/nocobase/nocobase/pull/1542) +- **fix** : correction du cache avec index.html [`#1541`](https://github.com/nocobase/nocobase/pull/1541) +- **fix** : correction du "belongs to many" à travers une table avec un schéma personnalisé [`#1539`](https://github.com/nocobase/nocobase/pull/1539) +- **fix(plugin-formula)** : exposition du résultat du champ de formule dans le formulaire [`#1534`](https://github.com/nocobase/nocobase/pull/1534) +- **test** : tests avec l'environnement `collection_manager_schema` [`#1532`](https://github.com/nocobase/nocobase/pull/1532) +- **fix** : correction du filtre par champ d'association avec underscore [`#1537`](https://github.com/nocobase/nocobase/pull/1537) +- **fix(charts)** : correction de la copie [`#1533`](https://github.com/nocobase/nocobase/pull/1533) +- **feat** : ajout du plugin graphique [`#1477`](https://github.com/nocobase/nocobase/pull/1477) +- **feat** : support pour ajouter un nouvel élément dans un bloc pour la collection d'héritage [`#1518`](https://github.com/nocobase/nocobase/pull/1518) +- **refactor(plugin-workflow)** : modification de la carte de canevas et ajustement des styles [`#1529`](https://github.com/nocobase/nocobase/pull/1529) +- **fix** : test avec le plugin Nocobase [`#1525`](https://github.com/nocobase/nocobase/pull/1525) +- **fix** : correction du cache Nginx [`#1523`](https://github.com/nocobase/nocobase/pull/1523) +- **fix** : suppression du champ lorsque la collection a un schéma différent de celui de la base de données [`#1524`](https://github.com/nocobase/nocobase/pull/1524) +- **refactor** : bloc des logs d'audit [`#1517`](https://github.com/nocobase/nocobase/pull/1517) +- **fix(evaluators)** : correction du prétraitement et ajout des cas de test [`#1519`](https://github.com/nocobase/nocobase/pull/1519) +- **chore(debug)** : correction du nom de fichier de débogage lors de l'exécution des tests [`#1520`](https://github.com/nocobase/nocobase/pull/1520) +- **feat** : ajout de l'environnement `collection_manager_schema` [`#1506`](https://github.com/nocobase/nocobase/pull/1506) +- **fix(client)** : correction de l'affichage des cases à cocher décochées [`#1508`](https://github.com/nocobase/nocobase/pull/1508) +- **feat(snapshot-field)** : amélioration de la transition [`#1513`](https://github.com/nocobase/nocobase/pull/1513) +- **fix(plugin-workflow)** : correction de la validation du champ CollectionField lors de l'utilisation de variables [`#1512`](https://github.com/nocobase/nocobase/pull/1512) +- **feat(plugin-formula)** : calcul avec un champ snapshot [`#1498`](https://github.com/nocobase/nocobase/pull/1498) +- **fix(association-select)** : le filtre sans portée de données ne fonctionne pas [`#1509`](https://github.com/nocobase/nocobase/pull/1509) +- **feat** : champ de tri par défaut initialisé sur le champ `createdAt` [`#1507`](https://github.com/nocobase/nocobase/pull/1507) +- **fix(graphical-interface)** : la catégorie de collection ne s'affiche pas avec le titre [`#1503`](https://github.com/nocobase/nocobase/pull/1503) +- **fix(association-select)** : les données sont incorrectes lorsqu'on utilise la portée de données [`#1491`](https://github.com/nocobase/nocobase/pull/1491) +- **feat** : ajout des accesseurs de version de dialecte [`#1502`](https://github.com/nocobase/nocobase/pull/1502) +- **fix** : le schéma de collection a été mis à jour mais le modèle `_schema` n'a pas changé [`#1500`](https://github.com/nocobase/nocobase/pull/1500) +- Mise à jour de `zh_CN.ts` [`#1481`](https://github.com/nocobase/nocobase/pull/1481) +- **fix(linkageRules)** : support pour une condition vide [`#1496`](https://github.com/nocobase/nocobase/pull/1496) +- **feat** : règles de liaison pour formulaire/bouton [`#1456`](https://github.com/nocobase/nocobase/pull/1456) +- **fix** : l'importateur de collection a une référence incorrecte [`#1495`](https://github.com/nocobase/nocobase/pull/1495) +- **feat** : support pour le déploiement de plugins personnalisés dans Dockerfile [`#1494`](https://github.com/nocobase/nocobase/pull/1494) +- **fix** : correction des variables d'environnement [`#1490`](https://github.com/nocobase/nocobase/pull/1490) +- **feat** : préparation de la méthode de base de données [`#1492`](https://github.com/nocobase/nocobase/pull/1492) +- **Fix/multiple schema query** [`#1488`](https://github.com/nocobase/nocobase/pull/1488) +- **fix** : violation de chaîne [`#1487`](https://github.com/nocobase/nocobase/pull/1487) +- **refactor(plugin-workflow)** : migration des évaluateurs [`#1485`](https://github.com/nocobase/nocobase/pull/1485) +- **docs** : correction de faute de frappe [`#1482`](https://github.com/nocobase/nocobase/pull/1482) +- **fix(plugin-workflow)** : correction du statut personnalisé des tâches [`#1484`](https://github.com/nocobase/nocobase/pull/1484) +- **fix(plugin-workflow)** : correction du paramètre de configuration de la condition [`#1483`](https://github.com/nocobase/nocobase/pull/1483) +- **fix(plugin-workflow)** : correction de la migration [`#1479`](https://github.com/nocobase/nocobase/pull/1479) +- **fix(plugin-workflow)** : correction de la migration avec le préfixe de table [`#1478`](https://github.com/nocobase/nocobase/pull/1478) +- **refactor(plugin-formula)** : fusion des deux types de champs de formule en un seul [`#1457`](https://github.com/nocobase/nocobase/pull/1457) +- **fix(plugin-workflow)** : correction de la migration pour les calculs [`#1476`](https://github.com/nocobase/nocobase/pull/1476) +- **fix(plugin-workflow)** : correction du nombre de répétitions dans le déclencheur de planification [`#1475`](https://github.com/nocobase/nocobase/pull/1475) +- **feat(plugin-workflow)** : ajout d'instructions manuelles [`#1339`](https://github.com/nocobase/nocobase/pull/1339) +- **feat** : support pour l'importation de pièces jointes [`#1466`](https://github.com/nocobase/nocobase/pull/1466) +- **fix** : erreur "column does not exist" après la destruction du champ de relation [`#1465`](https://github.com/nocobase/nocobase/pull/1465) +- **fix** : ajout de schéma [`#1464`](https://github.com/nocobase/nocobase/pull/1464) +- **fix** : éviter que o2o et o2m ne sélectionnent des données déjà sélectionnées [`#1462`](https://github.com/nocobase/nocobase/pull/1462) +- **feat** : ajout de cas de test [`#1463`](https://github.com/nocobase/nocobase/pull/1463) +- **feat** : mise à jour de `zh_CN.ts` [`#1458`](https://github.com/nocobase/nocobase/pull/1458) +- **refactor** : exportation du plugin [`#1460`](https://github.com/nocobase/nocobase/pull/1460) +- **Fix/pg schema with inherit** [`#1446`](https://github.com/nocobase/nocobase/pull/1446) +- **feat** : administration de plusieurs applications [`#1431`](https://github.com/nocobase/nocobase/pull/1431) +- **chore** : correction d'erreur de build du plugin [`#1454`](https://github.com/nocobase/nocobase/pull/1454) +- **feat** : ajout de l'option pour les noms de colonnes avec underscores dans la base de données [`#1366`](https://github.com/nocobase/nocobase/pull/1366) +- **Revert** "fix(table): make filed overflow behavior right (#1392)" [`#1452`](https://github.com/nocobase/nocobase/pull/1452) +- **fix(collection category)** : défaut de la locale zh_cn [`#1451`](https://github.com/nocobase/nocobase/pull/1451) +- **feat** : ajout des paramètres de namespace et duplicator pour les options de collection [`#1449`](https://github.com/nocobase/nocobase/pull/1449) +- **fix(snapshot-field)** : suppression de la limite de profondeur [`#1450`](https://github.com/nocobase/nocobase/pull/1450) +- **chore** : mise à jour des URLs des licences [`#1285`](https://github.com/nocobase/nocobase/pull/1285) +- **feat** : snapshot d'association [`#1438`](https://github.com/nocobase/nocobase/pull/1438) +- **fix(table)** : correction du comportement de débordement de champ [`#1392`](https://github.com/nocobase/nocobase/pull/1392) +- **fix(plugin-sequence)** : correction du champ `createdAt` manquant dans le hook de bulk [`#1448`](https://github.com/nocobase/nocobase/pull/1448) +- **fix** : erreur `0308010C:digital envelope routines::unsupported` [`#1447`](https://github.com/nocobase/nocobase/pull/1447) +- **feat** : catégories de collection [`#1327`](https://github.com/nocobase/nocobase/pull/1327) +- **fix(plugin-fm)** : correction de la configuration du chemin pour les stockages [`#1445`](https://github.com/nocobase/nocobase/pull/1445) +- **fix** : correction pour Node.js 17+, ajout du `openssl-legacy-provider` [`#1434`](https://github.com/nocobase/nocobase/pull/1434) +- **fix(plugin-workflow)** : correction du champ null pour la planification [`#1442`](https://github.com/nocobase/nocobase/pull/1442) +- **feat** : support du schéma PG [`#1439`](https://github.com/nocobase/nocobase/pull/1439) +- **fix(i18n)** : définir les séparateurs de clé et de namespace à `false` par défaut [`#1432`](https://github.com/nocobase/nocobase/pull/1432) +- **feat** : désactiver le déclencheur lors de l'importation d'une collection [`#1417`](https://github.com/nocobase/nocobase/pull/1417) +- **chore** : traduire "Add tab" dans l'en-tête de page [`#1424`](https://github.com/nocobase/nocobase/pull/1424) +- **fix(plugin-workflow)** : utiliser une promesse pour les requêtes [`#1426`](https://github.com/nocobase/nocobase/pull/1426) +- **fix(acl)** : stratégie de fusion pour les ajouts personnalisés [`#1416`](https://github.com/nocobase/nocobase/pull/1416) +- **docs** : mise à jour de l'URL d'exemple G2Plot [`#1408`](https://github.com/nocobase/nocobase/pull/1408) +- **docs** : correction de faute de frappe [`#1412`](https://github.com/nocobase/nocobase/pull/1412) +- **fix(FixedBlock)** : l'utilisation de filtres d'association et de FixedBlock empêche l'affichage complet du tableau [`#1405`](https://github.com/nocobase/nocobase/pull/1405) +- **feat(calendar)** : les champs `startDate` et `endDate` supportent l'utilisation des champs d'association [`#1397`](https://github.com/nocobase/nocobase/pull/1397) +- **fix** : charger les collections avant de lier le champ `belongsToMany` [`#1409`](https://github.com/nocobase/nocobase/pull/1409) +- **feat(verification-plugin)** : support du SMS Tencent [`#1382`](https://github.com/nocobase/nocobase/pull/1382) +- **fix** : les clés étrangères sont éditables lors de l'ajout de champs [`#1404`](https://github.com/nocobase/nocobase/pull/1404) +- **fix** : style de la barre de navigation (`navbar_ui`) [`#1398`](https://github.com/nocobase/nocobase/pull/1398) +- **fix** : tri d'héritage au démarrage [`#1402`](https://github.com/nocobase/nocobase/pull/1402) +- **fix(plugin-workflow)** : correction de la largeur du champ URL dans la configuration de la requête [`#1401`](https://github.com/nocobase/nocobase/pull/1401) +- **Fix/snapshot** [`#1396`](https://github.com/nocobase/nocobase/pull/1396) +- **feat** : correction du filtre des collections à travers les relations héritées [`#1394`](https://github.com/nocobase/nocobase/pull/1394) +- **Fix(plugin-sequence)** : support des champs de séquence dans la table à travers `m2m` [`#1383`](https://github.com/nocobase/nocobase/pull/1383) +- **fix(plugin-workflow)** : ajustement de la position de l'alerte exécutée [`#1381`](https://github.com/nocobase/nocobase/pull/1381) +- **fix** : hooks individuels dans les collections à travers [`#1378`](https://github.com/nocobase/nocobase/pull/1378) +- **fix** : les enregistrements des collections à travers ne doivent pas être réinitialisés [`#1377`](https://github.com/nocobase/nocobase/pull/1377) +- **feat(client)** : ajout du contexte désactivé pour les formulaires [`#1374`](https://github.com/nocobase/nocobase/pull/1374) +- **Fix(plugin-workflow)** : requête du nœud [`#1367`](https://github.com/nocobase/nocobase/pull/1367) + +## Commits +- **docs** : ajout de la documentation pour les plugins [`68511f0`](https://github.com/nocobase/nocobase/commit/68511f05bc7dbca49e0ab95eb868a193a3502d71) +- **feat(db)** : analyseur de valeurs de champs [`5805b69`](https://github.com/nocobase/nocobase/commit/5805b69455532ad643e9c87831da985d41bc5d6d) +- **chore(versions)** : 😊 publication de la version `v0.9.1-alpha.1` [`946c8f2`](https://github.com/nocobase/nocobase/commit/946c8f25a3df538f4a83abe4468786cf554d8914) + diff --git a/docs/fr-FR/welcome/release/v0092-changelog.md b/docs/fr-FR/welcome/release/v0092-changelog.md new file mode 100644 index 000000000..5d327fd1e --- /dev/null +++ b/docs/fr-FR/welcome/release/v0092-changelog.md @@ -0,0 +1,140 @@ +# v0.9.2:2023-04-19 + +## Changements Fusionnés + +- **refactor(plugin-workflow)** : changer le formulaire unique en bloc de formulaire personnalisé [`#1707`](https://github.com/nocobase/nocobase/pull/1707) +- **chore(ci)** : ajouter une configuration de timeout pour les jobs [`#1725`](https://github.com/nocobase/nocobase/pull/1725) +- **refactor(plugin-workflow)** : migrer les éléments de menu vers des options [`#1724`](https://github.com/nocobase/nocobase/pull/1724) +- **fix(client)** : corriger l'erreur lors de la suppression de valeur dans le champ de saisie variable [`#1723`](https://github.com/nocobase/nocobase/pull/1723) +- **fix(record-picker)** : corriger le problème de pagination du tableau [`#1718`](https://github.com/nocobase/nocobase/pull/1718) +- **fix(map-plugin)** : certaines données sont incorrectes [`#1717`](https://github.com/nocobase/nocobase/pull/1717) +- **fix** : la portée des données n'est pas prise en compte dans le Gantt [`#1716`](https://github.com/nocobase/nocobase/pull/1716) +- **fix** : le chargement des boutons ne disparaît pas lorsque la soumission de l'opération échoue [`#1698`](https://github.com/nocobase/nocobase/pull/1698) +- **fix(linkage rule)** : l'évaluation de la condition de sélection multiple échoue [`#1715`](https://github.com/nocobase/nocobase/pull/1715) +- **Fix** : sauvegarde des données via le tableau [`#1714`](https://github.com/nocobase/nocobase/pull/1714) +- **feat** : améliorer le design de l'interface utilisateur pour l'action de liaison [`#1659`](https://github.com/nocobase/nocobase/pull/1659) +- **feat(map)** : support de filtrage pour d'autres blocs [`#1691`](https://github.com/nocobase/nocobase/pull/1691) +- **refactor** : améliorer l'activation des règles de liaison [`#1700`](https://github.com/nocobase/nocobase/pull/1700) +- **fix** : correction de l'argument pour les champs trouvés [`#1710`](https://github.com/nocobase/nocobase/pull/1710) +- **feat(form-block)** : modèles de données [`#1704`](https://github.com/nocobase/nocobase/pull/1704) +- **fix** : échec du jugement de la condition des données de relation de liaison [`#1681`](https://github.com/nocobase/nocobase/pull/1681) +- **fix(gantt)** : mettre à jour la vérification des permissions dans le bloc Gantt [`#1701`](https://github.com/nocobase/nocobase/pull/1701) +- **fix** : clearFormGraph [`#1706`](https://github.com/nocobase/nocobase/pull/1706) +- **fix(plugin-workflow)** : corriger le composant de variable dans le corps de la requête [`#1703`](https://github.com/nocobase/nocobase/pull/1703) +- **fix(gantt)** : améliorer le texte de la barre des tâches [`#1696`](https://github.com/nocobase/nocobase/pull/1696) +- **fix** : le texte long doit être coupé en ligne [`#1686`](https://github.com/nocobase/nocobase/pull/1686) +- **fix** : impossible d'afficher les données lorsque la dernière page est supprimée et que la page ne contient qu'un seul élément [`#1685`](https://github.com/nocobase/nocobase/pull/1685) +- **fix** : problème de requête avec l'ACL des métadonnées et les associations [`#1695`](https://github.com/nocobase/nocobase/pull/1695) +- **fix** : impossible de définir un titre vide pour la règle de liaison [`#1688`](https://github.com/nocobase/nocobase/pull/1688) +- **feat** : améliorer l'interface de gestion des plugins [`#1650`](https://github.com/nocobase/nocobase/pull/1650) +- **feat** : bloc Gantt [`#1393`](https://github.com/nocobase/nocobase/pull/1393) +- **fix(client)** : corriger la perte de focus pour les composants constants dans les variables [`#1689`](https://github.com/nocobase/nocobase/pull/1689) +- **feat(plugin-workflow)** : ajouter un logger spécifique au workflow [`#1677`](https://github.com/nocobase/nocobase/pull/1677) +- **fix** : supprimer le designer [`#1684`](https://github.com/nocobase/nocobase/pull/1684) +- **test** : charger le fichier `.env.test` [`#1678`](https://github.com/nocobase/nocobase/pull/1678) +- **fix** : problème de langue après la déconnexion [`#1679`](https://github.com/nocobase/nocobase/pull/1679) +- **feat** : optimiser la collecte de fichiers [`#1666`](https://github.com/nocobase/nocobase/pull/1666) +- **fix** : performance du champ de tri [`#1675`](https://github.com/nocobase/nocobase/pull/1675) +- **fix(plugin-workflow)** : corriger les champs de collection nuls [`#1674`](https://github.com/nocobase/nocobase/pull/1674) +- **fix(client)** : corriger la lecture du mode "pretty" pour les composants variables [`#1673`](https://github.com/nocobase/nocobase/pull/1673) +- **fix** : problème de thème compact [`#1670`](https://github.com/nocobase/nocobase/pull/1670) +- **fix** : effet d'activation de la règle de liaison dans le formulaire [`#1669`](https://github.com/nocobase/nocobase/pull/1669) +- **feat** : résumé du modèle de collection [`#1672`](https://github.com/nocobase/nocobase/pull/1672) +- **feat** : expression dynamique pour le plugin workflow [`#1560`](https://github.com/nocobase/nocobase/pull/1560) +- **chore** : avertissement pour la collection héritée [`#1663`](https://github.com/nocobase/nocobase/pull/1663) +- **fix** : exception lors de la fermeture de la configuration des règles de liaison [`#1665`](https://github.com/nocobase/nocobase/pull/1665) +- **feat** : support du filtre `tableoid` [`#1657`](https://github.com/nocobase/nocobase/pull/1657) +- **feat(plugin-workflow)** : ajouter un support de mappage de tableau dans le processeur [`#1662`](https://github.com/nocobase/nocobase/pull/1662) +- **fix(plugin-workflow)** : corriger l'ajout de null à la collection déclenchée [`#1661`](https://github.com/nocobase/nocobase/pull/1661) +- **feat(filter-operators)** : les opérateurs `eq` et `ne` supportent les tableaux [`#1658`](https://github.com/nocobase/nocobase/pull/1658) +- **fix(plugin-workflow)** : corriger le chargement des données du tiroir Todo [`#1656`](https://github.com/nocobase/nocobase/pull/1656) +- **refactor(client)** : améliorer la traduction [`#1654`](https://github.com/nocobase/nocobase/pull/1654) +- **fix** : corriger la disparition du bouton "Ajouter un élément de menu" [`#1655`](https://github.com/nocobase/nocobase/pull/1655) +- **chore** : ajouter une nouvelle configuration `allowAddtoCurrent` [`#1652`](https://github.com/nocobase/nocobase/pull/1652) +- **feat** : support des collections de fichiers [`#1636`](https://github.com/nocobase/nocobase/pull/1636) +- **fix(plugin-workflow)** : corriger le tiroir des nœuds manuels [`#1653`](https://github.com/nocobase/nocobase/pull/1653) +- **chore** : API héritée avec des schémas différents [`#1545`](https://github.com/nocobase/nocobase/pull/1545) + +Voici la traduction en français des changements et des commits mentionnés pour la version de Nocobase (v0.9.2-alpha.1) : + +--- + +## Changements et Corrections + +- **fix** : le sélecteur d'enregistrement ne permet pas d'activer la collection enfant [`#1649`](https://github.com/nocobase/nocobase/pull/1649) +- **feat** : ajout du hook `before enable` pour les plugins [`#1648`](https://github.com/nocobase/nocobase/pull/1648) +- **chore** : ajout de la transaction dans l'action "set field" [`#1647`](https://github.com/nocobase/nocobase/pull/1647) +- **fix (règle de liaison)** : la règle de liaison ne s'affiche pas dans l'action [`#1644`](https://github.com/nocobase/nocobase/pull/1644) +- **refactor** : options de vue pour les collections [`#1643`](https://github.com/nocobase/nocobase/pull/1643) +- **fix** : mise à jour de l'erreur de champ [`#1645`](https://github.com/nocobase/nocobase/pull/1645) +- **feat (Table)** : l'action sur les colonnes prend en charge les règles de liaison [`#1638`](https://github.com/nocobase/nocobase/pull/1638) +- **fix (view-collection)** : le nom du champ ne peut pas être modifié lorsqu'il est lié à une source de champ [`#1642`](https://github.com/nocobase/nocobase/pull/1642) +- **fix** : la fermeture de la configuration des règles de liaison nécessite la réouverture du formulaire pour que les modifications prennent effet [`#1640`](https://github.com/nocobase/nocobase/pull/1640) +- **refactor (client)** : changer `Variable.TextArea` en composant contrôlé [`#1605`](https://github.com/nocobase/nocobase/pull/1605) +- **fix** : obtenir la définition de la vue PG [`#1641`](https://github.com/nocobase/nocobase/pull/1641) +- **fix** : inférer le type de colonne de vue avec un alias [`#1634`](https://github.com/nocobase/nocobase/pull/1634) +- **fix (plugin-workflow)** : correction de petits problèmes d'UI [`#1635`](https://github.com/nocobase/nocobase/pull/1635) +- **chore** : désactivation du souligné dans la vue collection [`#1633`](https://github.com/nocobase/nocobase/pull/1633) +- **fix** : l'aire de glisser-déposer de l'action de formulaire est trop grande [`#1628`](https://github.com/nocobase/nocobase/pull/1628) +- **fix** : interface utilisateur liée à `FixedBlock` [`#1632`](https://github.com/nocobase/nocobase/pull/1632) +- **feat** : vue de base de données pour les collections [`#1587`](https://github.com/nocobase/nocobase/pull/1587) +- **fix** : initialiser la valeur de tri dans le champ de tri avec `scopeKey` [`#1626`](https://github.com/nocobase/nocobase/pull/1626) +- **style** : amélioration du style des règles de liaison [`#1625`](https://github.com/nocobase/nocobase/pull/1625) +- **fix** : recherche avec attributs et groupements [`#1411`](https://github.com/nocobase/nocobase/pull/1411) +- **docs** : transformer le lien vidéo en balise vidéo [`#1414`](https://github.com/nocobase/nocobase/pull/1414) +- **feat (parse-variables)** : prise en charge de l'analyse des variables dans les paramètres de filtre [`#1558`](https://github.com/nocobase/nocobase/pull/1558) +- **fix (règles de liaison)** : prise en charge de la dénomination, activation/désactivation, copie et attribution de valeurs nulles [`#1511`](https://github.com/nocobase/nocobase/pull/1511) +- **chore** : mise à jour des tests CI [`#1622`](https://github.com/nocobase/nocobase/pull/1622) +- **fix** : le bouton "ajouter" dans l'historique ne prend pas en charge l'activation des collections enfants [`#1536`](https://github.com/nocobase/nocobase/pull/1536) +- **fix (linkages-action)** : les actions du bloc de détail ne prennent pas en charge les règles de liaison [`#1504`](https://github.com/nocobase/nocobase/pull/1504) +- **fix** : éviter que `FixedBlock` ne fonctionne dans une fenêtre popup [`#1621`](https://github.com/nocobase/nocobase/pull/1621) +- **fix** : lorsque la page contient `FixedBlock`, le tableau de la popup ne s'affiche pas [`#1619`](https://github.com/nocobase/nocobase/pull/1619) +- **feat** : amélioration du filtre d'association [`#1606`](https://github.com/nocobase/nocobase/pull/1606) +- **fix (Table)** : les données du tableau ne s'affichent pas [`#1617`](https://github.com/nocobase/nocobase/pull/1617) +- **fix (plugin-workflow)** : corriger la lecture en mode "pretty" de la todo list pour les utilisateurs non assignés [`#1615`](https://github.com/nocobase/nocobase/pull/1615) +- **feat (table)** : cacher la pagination lorsque seulement une page est disponible [`#1614`](https://github.com/nocobase/nocobase/pull/1614) +- **refactor** : améliorer la performance de `FixedBlock` [`#1593`](https://github.com/nocobase/nocobase/pull/1593) +- **fix (collection-manager)** : éviter la récursion infinie [`#1608`](https://github.com/nocobase/nocobase/pull/1608) +- **fix (audit-logs)** : ajouter la fonctionnalité de points de suspension aux colonnes du tableau [`#1603`](https://github.com/nocobase/nocobase/pull/1603) +- **feat** : améliorer l'interface de données non liées pour les associations [`#1602`](https://github.com/nocobase/nocobase/pull/1602) +- **feat (Kanban)** : la carte prend en charge le mode ouvert [`#1601`](https://github.com/nocobase/nocobase/pull/1601) +- **fix (importable-field)** : mauvaise affichage lors du déplacement de la poignée de tri [`#1613`](https://github.com/nocobase/nocobase/pull/1613) +- **fix** : les collections enfants restent après la suppression d'une collection enfant [`#1610`](https://github.com/nocobase/nocobase/pull/1610) +- **fix** : destruction via la table d'enregistrements référencée dans les collections [`#1611`](https://github.com/nocobase/nocobase/pull/1611) +- **fix (plugin-workflow)** : ajouter la valeur par défaut pour les actions du nœud manuel [`#1600`](https://github.com/nocobase/nocobase/pull/1600) +- **feat (plugin-workflow)** : ajouter l'option `failOnEmpty` pour les nœuds de requête [`#1599`](https://github.com/nocobase/nocobase/pull/1599) +- **fix (plugin-workflow)** : utiliser `toJSON` au lieu de `get` pour obtenir des résultats valides [`#1596`](https://github.com/nocobase/nocobase/pull/1596) +- **traduction pt-BR** (portugais brésilien) [`#1591`](https://github.com/nocobase/nocobase/pull/1591) +- **fix** : problème de permission de rôle qui affiche un espace vide lors de l'ajout de nouveau scope [`#1592`](https://github.com/nocobase/nocobase/pull/1592) +- **fix (FixedBlock)** : éviter le déclenchement du défilement programmatique de Kanban [`#1406`](https://github.com/nocobase/nocobase/pull/1406) +- **fix** : répétition des catégories de demande lors du passage entre l'interface graphique et la collection&fields [`#1590`](https://github.com/nocobase/nocobase/pull/1590) +- **fix** : `collectionFieldsOptions` ne peut pas récupérer tous les champs [`#1588`](https://github.com/nocobase/nocobase/pull/1588) +- **fix (plugin-workflow)** : correction de la largeur du champ de saisie dans la configuration du nœud de requête [`#1585`](https://github.com/nocobase/nocobase/pull/1585) +- **feat (filter-blocks)** : prise en charge des blocs de filtres [`#1505`](https://github.com/nocobase/nocobase/pull/1505) +- **refactor** : multi-app [`#1578`](https://github.com/nocobase/nocobase/pull/1578) +- **feat** : thème compact [`#1574`](https://github.com/nocobase/nocobase/pull/1574) +- **feat** : prise en charge des champs cron [`#1421`](https://github.com/nocobase/nocobase/pull/1421) +- **fix (Calendar)** : s'assurer d'obtenir le bon `gridInitializer` lors de l'ajout d'un nouvel élément [`#1425`](https://github.com/nocobase/nocobase/pull/1425) +- **feat (markdown)** : prise en charge de mermaid et meilleure gestion du style [`#1583`](https://github.com/nocobase/nocobase/pull/1583) +- **fix (plugin-map)** : correction du bloc de carte répétitif [`#1582`](https://github.com/nocobase/nocobase/pull/1582) +- **feat** : ajout de la collection d'arbre [`#1561`](https://github.com/nocobase/nocobase/pull/1561) +- **feat (plugin-map)** : ajout du bloc de carte [`#1486`](https://github.com/nocobase/nocobase/pull/1486) +- **chore** : chargement différé de l'application dans la collection partagée [`#1569`](https://github.com/nocobase/nocobase/pull/1569) +- **fix (record-picker)** : prise en charge de l'ajout d'enregistrements de sous-collection [`#1573`](https://github.com/nocobase/nocobase/pull/1573) +- **fix** : rechargement du gestionnaire d'applications [`#1565`](https://github.com/nocobase/nocobase/pull/1565) +- **feat** : plugin multi-app pour partager les collections [`#1562`](https://github.com/nocobase/nocobase/pull/1562) +- **feat** : prise en charge de la sélection d'enregistrements pour activer des liens [`#1515`](https://github.com/nocobase/nocobase/pull/1515) +- **feat** : support des applications multiples [`#1540`](https://github.com/nocobase/nocobase/pull/1540) +- **docs (client)** : ajout de la documentation des variables [`#1556`](https://github.com/nocobase/nocobase/pull/1556) +- **fix (charts)** : améliorer l'aperçu du tableau des graphiques avec le type objet [`#1555`](https://github.com/nocobase/nocobase/pull/1555) +- **feat (plugin-workflow)** : configurer le préchargement des associations dans les déclencheurs et nœuds [`#1548`](https://github.com/nocobase/nocobase/pull/1548) + +## Correction spécifique + +- **fix (plugin-workflow)** : correction du formulaire de la todo list en mode lecture "pretty" pour les utilisateurs non assignés [`#1572`](https://github.com/nocobase/nocobase/issues/1572) + +## Commits + +- **chore (versions)** : publication de la version `v0.9.2-alpha.1` [`d1adc9d`](https://github.com/nocobase/nocobase/commit/d1adc9de0b87b896e90c81c226646b840309c240) +- **fix (file-manager)** : mise à jour de la version S3 [`50183b0`](https://github.com/nocobase/nocobase/commit/50183b065d32be5d2f6590bfb0c6190fafc12881) +- **fix** : correction de la règle de liaison [`b8776fe`](https://github.com/nocobase/nocobase/commit/b8776fe2d0fd6729c18b968d9f7b15e7c81c4ef2) diff --git a/docs/fr-FR/welcome/release/v0093-changelog.md b/docs/fr-FR/welcome/release/v0093-changelog.md new file mode 100644 index 000000000..bc83f37ef --- /dev/null +++ b/docs/fr-FR/welcome/release/v0093-changelog.md @@ -0,0 +1,134 @@ +# v0.9.3:2023-05-11 + +## Fusionnés + +- **Refactorisation (plugin-workflow)** : changement du formulaire unique en un bloc de formulaire personnalisé [`#1707`](https://github.com/nocobase/nocobase/pull/1707) +- **Chore (CI)** : ajout d'une configuration de délai d'attente pour les jobs [`#1725`](https://github.com/nocobase/nocobase/pull/1725) +- **Refactorisation (plugin-workflow)** : migration des éléments de menu vers des options [`#1724`](https://github.com/nocobase/nocobase/pull/1724) +- **Correction (client)** : correction de l'erreur lors de la suppression de la valeur dans le champ de saisie des variables [`#1723`](https://github.com/nocobase/nocobase/pull/1723) +- **Correction (record-picker)** : correction du problème de pagination dans le tableau [`#1718`](https://github.com/nocobase/nocobase/pull/1718) +- **Correction (map-plugin)** : certaines données sont incorrectes [`#1717`](https://github.com/nocobase/nocobase/pull/1717) +- **Correction** : la portée des données n'a pas d'effet dans le bloc Gantt [`#1716`](https://github.com/nocobase/nocobase/pull/1716) +- **Correction** : le bouton de chargement ne disparaît pas lorsque la soumission de l'opération échoue [`#1698`](https://github.com/nocobase/nocobase/pull/1698) +- **Correction (règle de liaison)** : échec du jugement des conditions de sélection multiple [`#1715`](https://github.com/nocobase/nocobase/pull/1715) +- **Correction** : sauvegarde des données à travers le tableau [`#1714`](https://github.com/nocobase/nocobase/pull/1714) +- **Fonctionnalité** : amélioration de la conception de l'interface utilisateur pour l'action de liaison [`#1659`](https://github.com/nocobase/nocobase/pull/1659) +- **Fonctionnalité (map)** : prise en charge du filtrage d'autres blocs [`#1691`](https://github.com/nocobase/nocobase/pull/1691) +- **Refactorisation** : amélioration de l'activation des règles de liaison [`#1700`](https://github.com/nocobase/nocobase/pull/1700) +- **Correction** : argument des champs de recherche [`#1710`](https://github.com/nocobase/nocobase/pull/1710) +- **Fonctionnalité (form-block)** : modèles de données [`#1704`](https://github.com/nocobase/nocobase/pull/1704) +- **Correction** : échec du jugement des conditions de données de la relation de liaison [`#1681`](https://github.com/nocobase/nocobase/pull/1681) +- **Correction (gantt)** : mise à jour de la vérification des permissions dans le bloc Gantt [`#1701`](https://github.com/nocobase/nocobase/pull/1701) +- **Correction** : réinitialisation du graphique de formulaire [`#1706`](https://github.com/nocobase/nocobase/pull/1706) +- **Correction (plugin-workflow)** : correction du composant de variable dans le corps de la requête [`#1703`](https://github.com/nocobase/nocobase/pull/1703) +- **Correction (gantt)** : amélioration du texte de la barre de tâches dans Gantt [`#1696`](https://github.com/nocobase/nocobase/pull/1696) +- **Correction** : le texte long doit passer à la ligne [`#1686`](https://github.com/nocobase/nocobase/pull/1686) +- **Correction** : impossible d'afficher les données lorsqu'on supprime la dernière page et que la page contient un seul élément [`#1685`](https://github.com/nocobase/nocobase/pull/1685) +- **Correction** : meta ACL avec la requête d'association [`#1695`](https://github.com/nocobase/nocobase/pull/1695) +- **Correction** : le titre de la règle de liaison ne peut pas être vide [`#1688`](https://github.com/nocobase/nocobase/pull/1688) +- **Fonctionnalité** : amélioration de l'interface utilisateur du gestionnaire de plugins [`#1650`](https://github.com/nocobase/nocobase/pull/1650) +- **Fonctionnalité** : bloc Gantt [`#1393`](https://github.com/nocobase/nocobase/pull/1393) +- **Correction (client)** : correction de la perte de focus dans le champ de saisie des constantes dans la variable [`#1689`](https://github.com/nocobase/nocobase/pull/1689) +- **Fonctionnalité (plugin-workflow)** : ajout d'un logger spécifique pour les workflows [`#1677`](https://github.com/nocobase/nocobase/pull/1677) +- **Correction** : suppression du designer [`#1684`](https://github.com/nocobase/nocobase/pull/1684) +- **Test** : doit charger le fichier `.env.test` [`#1678`](https://github.com/nocobase/nocobase/pull/1678) +- **Correction** : langue incorrecte après la déconnexion [`#1679`](https://github.com/nocobase/nocobase/pull/1679) +- **Fonctionnalité** : optimisation de la collecte de fichiers [`#1666`](https://github.com/nocobase/nocobase/pull/1666) +- **Correction** : performance d'initialisation du champ de tri [`#1675`](https://github.com/nocobase/nocobase/pull/1675) +- **Correction (plugin-workflow)** : correction des champs de collection nulles [`#1674`](https://github.com/nocobase/nocobase/pull/1674) +- **Correction (client)** : correction du mode de lecture en mode "beau" pour le composant de variable [`#1673`](https://github.com/nocobase/nocobase/pull/1673) +- **Correction** : problème d'interface avec le thème compact [`#1670`](https://github.com/nocobase/nocobase/pull/1670) +- **Correction** : effet de l'activation de la règle de liaison dans le formulaire [`#1669`](https://github.com/nocobase/nocobase/pull/1669) +- **Fonctionnalité** : résumé du modèle de collection [`#1672`](https://github.com/nocobase/nocobase/pull/1672) +- **Fonctionnalité (plugin-workflow)** : expression dynamique [`#1560`](https://github.com/nocobase/nocobase/pull/1560) +- **Chore** : avertissement de collection héritée à trouver [`#1663`](https://github.com/nocobase/nocobase/pull/1663) +- **Correction** : exception lors de la configuration du titre de la règle de liaison [`#1665`](https://github.com/nocobase/nocobase/pull/1665) +- **Fonctionnalité** : prise en charge du filtrage par tableoid [`#1657`](https://github.com/nocobase/nocobase/pull/1657) +- **Fonctionnalité (plugin-workflow)** : ajout du support du mappage de tableaux dans le processeur [`#1662`](https://github.com/nocobase/nocobase/pull/1662) +- **Correction (plugin-workflow)** : correction de l'ajout de null à la collection de déclenchement [`#1661`](https://github.com/nocobase/nocobase/pull/1661) +- **Fonctionnalité (opérateurs de filtrage)** : prise en charge des opérateurs `eq` et `ne` pour les tableaux [`#1658`](https://github.com/nocobase/nocobase/pull/1658) +- **Correction (plugin-workflow)** : correction du chargement des données dans le tiroir des tâches [`#1656`](https://github.com/nocobase/nocobase/pull/1656) +- **Refactorisation (client)** : amélioration de la traduction [`#1654`](https://github.com/nocobase/nocobase/pull/1654) +- **Correction** : correction du bouton "Ajouter un élément de menu" qui disparaît [`#1655`](https://github.com/nocobase/nocobase/pull/1655) +- **Chore** : ajout d'une nouvelle configuration `allowAddtoCurrent` [`#1652`](https://github.com/nocobase/nocobase/pull/1652) +- **Fonctionnalité** : prise en charge de la collection de fichiers [`#1636`](https://github.com/nocobase/nocobase/pull/1636) +- **Correction (plugin-workflow)** : correction du tiroir de nœud manuel [`#1653`](https://github.com/nocobase/nocobase/pull/1653) +- **Chore** : API héritée avec un schéma différent [`#1545`](https://github.com/nocobase/nocobase/pull/1545) +- **Correction** : impossible d'activer la collection enfant dans le sélecteur d'enregistrements [`#1649`](https://github.com/nocobase/nocobase/pull/1649) +- **Fonctionnalité** : ajout d'un hook avant l'activation du plugin [`#1648`](https://github.com/nocobase/nocobase/pull/1648) +- **Chore** : ajout de la transaction dans l'action de définition du champ [`#1647`](https://github.com/nocobase/nocobase/pull/1647) +- **Correction (règle de liaison)** : la règle de liaison ne s'affiche pas dans l'action [`#1644`](https://github.com/nocobase/nocobase/pull/1644) +- **Refactorisation** : options de collection de vue [`#1643`](https://github.com/nocobase/nocobase/pull/1643) +- **Correction** : mise à jour de l'erreur du champ [`#1645`](https://github.com/nocobase/nocobase/pull/1645) +- **Fonctionnalité (Table)** : les actions de colonne supportent les règles de liaison [`#1638`](https://github.com/nocobase/nocobase/pull/1638) +- **Correction (view-collection)** : le nom du champ ne peut pas être modifié lorsqu'il y a une source de champ [`#1642`](https://github.com/nocobase/nocobase/pull/1642) +- **Correction** : la configuration des règles de liaison nécessite de rouvrir le formulaire pour que les modifications prennent effet [`#1640`](https://github.com/nocobase/nocobase/pull/1640) +- **Refactorisation (client)** : changement de `Variable.TextArea` en composant contrôlé [`#1605`](https://github.com/nocobase/nocobase/pull/1605) +- **Correction** : récupération de la définition de vue PG [`#1641`](https://github.com/nocobase/nocobase/pull/1641) +- **Correction** : inférer le type de colonne de la vue avec alias [`#1634`](https://github.com/nocobase/nocobase/pull/1634) +- **Correction (plugin-workflow)** : correction de petits problèmes d'interface utilisateur [`#1635`](https://github.com/nocobase/nocobase/pull/1635) +- **Chore** : désactivation des underscores dans la collection de vue [`#1633`](https://github.com/nocobase/nocobase/pull/1633) +- **Correction** : la zone de glissement de l'action de formulaire est trop large [`#1628`](https://github.com/nocobase/nocobase/pull/1628) +- **Correction** : problème d'interface lié au `FixedBlock` [`#1632`](https://github.com/nocobase/nocobase/pull/1632) +- **Fonctionnalité** : vue de collection de base de données [`#1587`](https://github.com/nocobase/nocobase/pull/1587) +- **Correction** : initialisation de la valeur de tri dans le champ de tri avec `scopeKey` [`#1626`](https://github.com/nocobase/nocobase/pull/1626) +- **Style** : amélioration du style des règles de liaison [`#1625`](https://github.com/nocobase/nocobase/pull/1625) +- **Correction** : recherche avec attributs et groupe [`#1411`](https://github.com/nocobase/nocobase/pull/1411) +- **Documentation** : transformation du lien vidéo en balise vidéo [`#1414`](https://github.com/nocobase/nocobase/pull/1414) +- **Fonctionnalité (parse-variables)** : prise en charge de l'analyse des variables dans les paramètres de filtre [`#1558`](https://github.com/nocobase/nocobase/pull/1558) +- **Correction (règles de liaison)** : prise en charge du nommage, de l'activation et de la désactivation, de la copie et de l'assignation de valeurs nulles [`#1511`](https://github.com/nocobase/nocobase/pull/1511) +- **Chore** : mise à jour du test CI [`#1622`](https://github.com/nocobase/nocobase/pull/1622) +- **Correction** : le bouton "Ajouter un nouvel élément" ne prend pas en charge l'activation de la collection enfant [`#1536`](https://github.com/nocobase/nocobase/pull/1536) +- **Correction (actions de liaison)** : les actions du bloc de détails ne prennent pas en charge les règles de liaison [`#1504`](https://github.com/nocobase/nocobase/pull/1504) +- **Correction** : éviter que la hauteur de `FixedBlock` ne fonctionne dans la popup [`#1621`](https://github.com/nocobase/nocobase/pull/1621) +- **Correction** : lorsque la page a un `FixedBlock`, le tableau de la popup ne s'affiche pas [`#1619`](https://github.com/nocobase/nocobase/pull/1619) +- **Fonctionnalité** : amélioration du filtre d'association [`#1606`](https://github.com/nocobase/nocobase/pull/1606) +- **Correction (Table)** : impossible d'afficher les données du tableau [`#1617`](https://github.com/nocobase/nocobase/pull/1617) +- **Correction (plugin-workflow)** : correction du formulaire de la liste de tâches pour les utilisateurs non assignés en mode lecture-pretty [`#1615`](https://github.com/nocobase/nocobase/pull/1615) +- **Fonctionnalité (table)** : masquage de la pagination lorsque seule une page est disponible [`#1614`](https://github.com/nocobase/nocobase/pull/1614) +- **Refactorisation** : amélioration des performances de `FixedBlock` [`#1593`](https://github.com/nocobase/nocobase/pull/1593) +- **Correction (collection-manager)** : récursion infinie [`#1608`](https://github.com/nocobase/nocobase/pull/1608) +- **Correction (audit-logs)** : ajout de la fonctionnalité de points de suspension dans les colonnes du tableau [`#1603`](https://github.com/nocobase/nocobase/pull/1603) +- **Fonctionnalité** : amélioration de l'interface utilisateur des données d'association non liées [`#1602`](https://github.com/nocobase/nocobase/pull/1602) +- **Fonctionnalité (Kanban)** : la carte prend en charge le mode ouverture [`#1601`](https://github.com/nocobase/nocobase/pull/1601) +- **Correction (importable-field)** : affichage incorrect lors du déplacement du curseur de tri [`#1613`](https://github.com/nocobase/nocobase/pull/1613) +- **Correction** : les collections enfants restent activées après la suppression d'une collection enfant [`#1610`](https://github.com/nocobase/nocobase/pull/1610) +- **Correction** : suppression via table d'enregistrements référencés dans les collections de table [`#1611`](https://github.com/nocobase/nocobase/pull/1611) +- **Correction (plugin-workflow)** : ajout de la valeur par défaut pour les actions du nœud manuel [`#1600`](https://github.com/nocobase/nocobase/pull/1600) +- **Fonctionnalité (plugin-workflow)** : ajout de l'option `failOnEmpty` pour le nœud de requête [`#1599`](https://github.com/nocobase/nocobase/pull/1599) +- **Correction (plugin-workflow)** : utilisation de `toJSON` au lieu de `get` pour obtenir un résultat valide [`#1596`](https://github.com/nocobase/nocobase/pull/1596) +- **Traduction pt-BR (Portugais brésilien)** [`#1591`](https://github.com/nocobase/nocobase/pull/1591) +- **Correction** : le rôle de permission ajoute un nouvel affichage de portée vide [`#1592`](https://github.com/nocobase/nocobase/pull/1592) +- **Correction (FixedBlock)** : éviter que le Kanban ne déclenche un défilement programmatique [`#1406`](https://github.com/nocobase/nocobase/pull/1406) +- **Correction** : répétition des catégories de requêtes lors du passage entre l'interface graphique et la collection/champs [`#1590`](https://github.com/nocobase/nocobase/pull/1590) +- **Correction** : `collectionFieldsOptions` ne peut pas récupérer tous les champs [`#1588`](https://github.com/nocobase/nocobase/pull/1588) +- **Correction (plugin-workflow)** : correction de la largeur de l'entrée dans la configuration du nœud de requête [`#1585`](https://github.com/nocobase/nocobase/pull/1585) +- **Fonctionnalité (filter-blocks)** : prise en charge des `filter-blocks` [`#1505`](https://github.com/nocobase/nocobase/pull/1505) +- **Refactorisation** : multi-app [`#1578`](https://github.com/nocobase/nocobase/pull/1578) +- **Fonctionnalité** : thème compact [`#1574`](https://github.com/nocobase/nocobase/pull/1574) +- **Fonctionnalité** : prise en charge du champ cron [`#1421`](https://github.com/nocobase/nocobase/pull/1421) +- **Correction (Calendar)** : garantir l'obtention du `gridInitializer` correct lors de l'ajout d'un nouvel élément [`#1425`](https://github.com/nocobase/nocobase/pull/1425) +- **Fonctionnalité (markdown)** : prise en charge de Mermaid et meilleure gestion du style [`#1583`](https://github.com/nocobase/nocobase/pull/1583) +- **Correction (plugin-map)** : répétition du bloc de carte [`#1582`](https://github.com/nocobase/nocobase/pull/1582) +- **Fonctionnalité** : collection arbre [`#1561`](https://github.com/nocobase/nocobase/pull/1561) +- **Fonctionnalité (plugin-map)** : ajout du bloc de carte [`#1486`](https://github.com/nocobase/nocobase/pull/1486) +- **Chore** : chargement paresseux des sous-applications dans la collection partagée [`#1569`](https://github.com/nocobase/nocobase/pull/1569) +- **Correction (record-picker)** : prise en charge de l'ajout d'enregistrements de sous-collections [`#1573`](https://github.com/nocobase/nocobase/pull/1573) +- **Correction** : rechargement du gestionnaire d'applications [`#1565`](https://github.com/nocobase/nocobase/pull/1565) +- **Fonctionnalité** : plugin de partage multi-applications [`#1562`](https://github.com/nocobase/nocobase/pull/1562) +- **Fonctionnalité** : le sélecteur d'enregistrements prend en charge l'activation des liens [`#1515`](https://github.com/nocobase/nocobase/pull/1515) +- **Fonctionnalité** : plusieurs applications [`#1540`](https://github.com/nocobase/nocobase/pull/1540) +- **Documentation (client)** : ajout de la documentation des variables [`#1556`](https://github.com/nocobase/nocobase/pull/1556) +- **Correction (charts)** : amélioration de l'aperçu du tableau des graphiques avec le type objet [`#1555`](https://github.com/nocobase/nocobase/pull/1555) +- **Fonctionnalité (plugin-workflow)** : configuration du préchargement des associations dans les déclencheurs et nœuds [`#1548`](https://github.com/nocobase/nocobase/pull/1548) + +### **Corrigé** + +- **Correction (plugin-workflow)** : correction du formulaire de la liste de tâches pour les utilisateurs non assignés en mode lecture-pretty [`#1572`](https://github.com/nocobase/nocobase/issues/1572) + +### **Commits** + +- **Chore (versions)** : publication de la version v0.9.2-alpha.1 [`d1adc9d`](https://github.com/nocobase/nocobase/commit/d1adc9de0b87b896e90c81c226646b840309c240) +- **Correction (file-manager)** : mise à jour de la version de S3 [`50183b0`](https://github.com/nocobase/nocobase/commit/50183b065d32be5d2f6590bfb0c6190fafc12881) +- **Correction** : règle de liaison [`b8776fe`](https://github.com/nocobase/nocobase/commit/b8776fe2d0fd6729c18b968d9f7b15e7c81c4ef2) + diff --git a/docs/fr-FR/welcome/release/v0094-changelog.md b/docs/fr-FR/welcome/release/v0094-changelog.md new file mode 100644 index 000000000..c9abd7f5e --- /dev/null +++ b/docs/fr-FR/welcome/release/v0094-changelog.md @@ -0,0 +1,67 @@ +# v0.9.4 : 25 mai 2023 + +## Fusionné + +- **chore** : charger la collection de vues lorsque la source n'est pas trouvée [`#1930`](https://github.com/nocobase/nocobase/pull/1930) +- **fonctionnalité (data-template)** : prise en charge de la définition du champ de portée des données et du champ titre [`#1918`](https://github.com/nocobase/nocobase/pull/1918) +- **fonctionnalité (data-template)** : prise en charge de la sélection de champs avec un nombre illimité de niveaux [`#1910`](https://github.com/nocobase/nocobase/pull/1910) +- **chore** : en utilisant le champ d'association en mode sélecteur, sa taille d'ouverture peut être modifiée [`#1926`](https://github.com/nocobase/nocobase/pull/1926) +- **correction (ConfigurationTabs)** : éviter l'erreur [`#1782`](https://github.com/nocobase/nocobase/pull/1782) +- **correction** : requête de données du champ de table dans l'action "ajouter un enfant" [`#1876`](https://github.com/nocobase/nocobase/pull/1876) +- **refactorisation** : tests frontend avec vitest [`#1900`](https://github.com/nocobase/nocobase/pull/1900) +- **correction** : désactiver le bouton popup dans la fenêtre d'ajout (`add-modal`) [`#1808`](https://github.com/nocobase/nocobase/pull/1808) +- **correction** : ajouter les paramètres de ressource ACL [`#1923`](https://github.com/nocobase/nocobase/pull/1923) +- **chore** : mettre à jour la protection avec un tableau contenant null [`#1922`](https://github.com/nocobase/nocobase/pull/1922) +- **refactorisation** : initialisation lors du changement de composants de champ [`#1915`](https://github.com/nocobase/nocobase/pull/1915) +- **correction (association-field)** : les données ne peuvent être associées que si la création des nouvelles données a réussi [`#1884`](https://github.com/nocobase/nocobase/pull/1884) +- **correction** : chargement immédiat avec "belongs to many" avec clé source personnalisée [`#1913`](https://github.com/nocobase/nocobase/pull/1913) +- **correction** : masquer le titre d'un sous-formulaire masquera tous les titres embarqués [`#1904`](https://github.com/nocobase/nocobase/pull/1904) +- **correction** : mise à jour des valeurs de l'association [`#1903`](https://github.com/nocobase/nocobase/pull/1903) +- **correction (plugin-formula)** : utiliser le composant "read-pretty" dans les résultats [`#1911`](https://github.com/nocobase/nocobase/pull/1911) +- **correction** : impossible de définir la valeur par défaut lorsque le champ du formulaire est requis [`#1887`](https://github.com/nocobase/nocobase/pull/1887) +- **correction (Data-template)** : correction d'un bug lors de la suppression de champs [`#1907`](https://github.com/nocobase/nocobase/pull/1907) +- **fonctionnalité (app)** : ajout d'un bouton pour vider le cache [`#1909`](https://github.com/nocobase/nocobase/pull/1909) +- **correction** : chargement immédiat pour les associations "belongs to many" [`#1906`](https://github.com/nocobase/nocobase/pull/1906) +- **fonctionnalité** : prise en charge des variables de champ "to-multi" [`#1680`](https://github.com/nocobase/nocobase/pull/1680) +- **correction** : ajouter une association "belongs to" avec des champs [`#1894`](https://github.com/nocobase/nocobase/pull/1894) +- **correction** : ajout d'une association "belongs to" [`#1893`](https://github.com/nocobase/nocobase/pull/1893) +- **correction** : préchargement des données relationnelles [`#1847`](https://github.com/nocobase/nocobase/pull/1847) +- **fonctionnalité** : prise en charge du redémarrage manuel de l'application [`#1889`](https://github.com/nocobase/nocobase/pull/1889) +- **refactorisation/ajout de champs** [`#1883`](https://github.com/nocobase/nocobase/pull/1883) +- **chore** : analyseur SQL pg [`#1890`](https://github.com/nocobase/nocobase/pull/1890) +- **correction (plugin-workflow)** : correction de la langue [`#1886`](https://github.com/nocobase/nocobase/pull/1886) +- **correction** : champ requis lors de la définition des règles de tri [`#1885`](https://github.com/nocobase/nocobase/pull/1885) +- **fonctionnalité (plugin-workflow)** : ajouter une description de nœud au tiroir lors de l'édition du nœud [`#1882`](https://github.com/nocobase/nocobase/pull/1882) +- **correction (plugin-workflow)** : correction de l'appel d'API des variables dans les boucles [`#1877`](https://github.com/nocobase/nocobase/pull/1877) +- **chore (github-template)** : nettoyer les commentaires et le format [`#1878`](https://github.com/nocobase/nocobase/pull/1878) +- **fonctionnalité (association-field)** : définir une donnée par défaut pour l'association "to-many" [`#1873`](https://github.com/nocobase/nocobase/pull/1873) +- **correction (plugin-workflow)** : correction du titre du déclencheur lorsque le flux de travail n'est pas chargé [`#1875`](https://github.com/nocobase/nocobase/pull/1875) +- **fonctionnalité (plugin-workflow)** : agrégation [`#1852`](https://github.com/nocobase/nocobase/pull/1852) +- **fonctionnalité/Traduction (es_ES)** [`#1801`](https://github.com/nocobase/nocobase/pull/1801) +- **correction** : les données ne sont pas mises à jour lorsque les ajouts sont modifiés [`#1872`](https://github.com/nocobase/nocobase/pull/1872) +- **correction** : sélection d'association sans options lors du nettoyage des filtres [`#1866`](https://github.com/nocobase/nocobase/pull/1866) +- **correction (acl)** : problème avec le champ "createdById" répété [`#1871`](https://github.com/nocobase/nocobase/pull/1871) +- **fonctionnalité (client)** : permettre la recherche par titre dans la sélection de collection [`#1869`](https://github.com/nocobase/nocobase/pull/1869) +- **chore** : ignorer la récupération des sous-applications de déploiement autonome [`#1868`](https://github.com/nocobase/nocobase/pull/1868) +- **correction (plugin-workflow)** : suppression de l'option de contexte inutile [`#1867`](https://github.com/nocobase/nocobase/pull/1867) +- **correction** : filtrer les champs de clé étrangère hérités [`#1864`](https://github.com/nocobase/nocobase/pull/1864) +- **fonctionnalité (plugin-workflow)** : boucle [`#1787`](https://github.com/nocobase/nocobase/pull/1787) +- **correction** : `insertAdjacent` non trouvé [`#1861`](https://github.com/nocobase/nocobase/pull/1861) +- **refactorisation (add-new)** : le champ d'association "ajouter un nouveau" prend en charge le bouton d'édition [`#1854`](https://github.com/nocobase/nocobase/pull/1854) +- **fonctionnalité** : prise en charge des blocs "List" et "Grid Card" [`#1753`](https://github.com/nocobase/nocobase/pull/1753) +- **correction** : correction du champ multi-sélection qui ne montre pas le bouton "Autoriser plusieurs" [`#1857`](https://github.com/nocobase/nocobase/pull/1857) +- **correction** : champ pour type d'interface de pièce jointe sans ajouts [`#1856`](https://github.com/nocobase/nocobase/pull/1856) +- **correction** : erreur d'action lors de la suppression d'un champ [`#1849`](https://github.com/nocobase/nocobase/pull/1849) +- **fonctionnalité** : prise en charge de l'exécution d'une seule sous-application [`#1853`](https://github.com/nocobase/nocobase/pull/1853) +- **correction** : assignation de champ avec champ supprimé [`#1850`](https://github.com/nocobase/nocobase/pull/1850) +- **correction** : champ titre dans les valeurs des champs assignés [`#1848`](https://github.com/nocobase/nocobase/pull/1848) +- **correction** : ajouts d'association [`#1842`](https://github.com/nocobase/nocobase/pull/1842) +- **fonctionnalité (plugin-workflow)** : ajouter un bouton de suppression dans la page du canevas du flux de travail [`#1844`](https://github.com/nocobase/nocobase/pull/1844) +- **correction (block-provider)** : correction du filtre `getNesterAppends` [`#1839`](https://github.com/nocobase/nocobase/pull/1839) +- **fonctionnalité** : méthode d'agrégation du dépôt [`#1829`](https://github.com/nocobase/nocobase/pull/1829) + +## Commits + +- **fonctionnalité (docs)** : mise à jour de la documentation [`0b0a8d2`](https://github.com/nocobase/nocobase/commit/0b0a8d2be5f007c94c2050ddf28767100eba2ea8) +- **chore (versions)** : publication de la version v0.9.4-alpha.1 [`9c94840`](https://github.com/nocobase/nocobase/commit/9c94840c6b8cafa7dfc37bb660a7269c2480f995) +- **chore** : mise à jour du changelog [`a6c7b41`](https://github.com/nocobase/nocobase/commit/a6c7b417dee9b45006b77459a29ebbdb8428dfc5) diff --git a/docs/fr-FR/welcome/release/v0100-changelog.md b/docs/fr-FR/welcome/release/v0100-changelog.md new file mode 100644 index 000000000..18e737041 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0100-changelog.md @@ -0,0 +1,233 @@ +# v0.10 : 2023-06-20 + +## Nouvelles fonctionnalités du deuxième trimestre + +- Améliorations du composant champ d'association, prise en charge du changement de plusieurs composants + - Sélection + - Sélecteur d'enregistrements + - Sous-formulaire/Sous-détails + - Sous-tableau + - Gestionnaire de fichiers + - Titre (en lecture seule) +- Création rapide de données relationnelles, prise en charge de deux modes de création rapide + - Ajouter dans le menu déroulant pour créer rapidement un nouvel enregistrement basé sur le champ titre + - Ajouter dans une fenêtre contextuelle pour configurer des formulaires d'ajout complexes +- Action de duplication, prend en charge deux modes + - Duplication directe + - Copier dans le formulaire et continuer à remplir +- Modèles de données de formulaire +- Prise en charge des variables dans le filtre de portée de données +- Bloc de liste +- Bloc de carte en grille +- Plugin client mobile +- Plugin d'authentification des utilisateurs, prise en charge de différentes méthodes d'authentification + - E-mail/Mot de passe + - SMS + - OIDC + - SAML +- Nœuds de workflow + - Mise à niveau du nœud manuel, prise en charge de l'ajout et de l'édition à partir des collections existantes + - Nœud de boucle + - Nœud d'agrégation +- Gestionnaire de fichiers + - Fournir un modèle de collection de fichiers + - Fournir un composant gestionnaire de fichiers + +## Mise à niveau des applications + +### Mise à niveau pour Docker Compose + +Aucune modification, référence de mise à niveau [Mise à niveau pour Docker Compose](/welcome/getting-started/upgrading/docker-compose) + +### Mise à niveau pour le code source Git + +v0.10 comporte une mise à niveau majeure des dépendances, afin d'éviter des erreurs lors de la mise à niveau du code source, vous devez supprimer les répertoires suivants avant la mise à niveau : + +```bash +# Supprimer le cache .umi +yarn rimraf -rf "./**/{.umi,.umi-production}" +# Supprimer les fichiers compilés +yarn rimraf -rf "./packages/*/*/{lib,esm,es,dist,node_modules}" +# Supprimer les dépendances +yarn rimraf -rf node_modules +``` + +Voir [Mise à niveau pour le code source Git](/welcome/getting-started/upgrading/git-clone) pour plus de détails + +### Mise à niveau pour create-nocobase-app + +Il est recommandé de redéfinir la nouvelle version avec `yarn create` et de modifier la configuration `.env`. Pour plus de détails, consultez [guide de mise à niveau majeure](/welcome/getting-started/upgrading/create-nocobase-app#major-upgrade) + +## Modifications et changements potentiels de compatibilité + +### Composant de champ sous-tableau + +Non compatible avec la nouvelle version, les champs de bloc doivent être supprimés et réassignés (réaffectation uniquement au niveau de l'UI) + +### Changements de l'API de téléchargement de fichiers + +En plus de la table de pièces jointes intégrée, les utilisateurs peuvent également créer une collection de fichiers personnalisée. L'API de téléchargement pour les pièces jointes a été modifiée de `/api/attachments:upload` à `/api/<file-collection>:create`. Le téléchargement est obsolète, encore compatible avec v0.10 mais sera supprimé. + +### Changements des API de connexion/inscription + +Le noyau de Nocobase fournit un module [auth] plus puissant avec les changements suivants pour les API de connexion, d'enregistrement, de vérification et de déconnexion des utilisateurs : + +```bash +/api/users:signin -> /api/auth:signIn +/api/users:signup -> /api/auth:signUp +/api/users:signout -> /api/auth:signOut +/api/users:check -> /api/auth:check +``` + +Note : Les anciennes interfaces des utilisateurs sont obsolètes, encore compatibles avec v0.10 mais seront supprimées dans la prochaine version majeure. + +### Ajustements pour le filtrage des champs de date + +Si un filtrage lié aux dates a été configuré dans la plage de données précédemment, il doit être supprimé et reconfiguré. + +## Guide de mise à niveau des plugins tiers + +### Mise à niveau des dépendances + +Les dépendances comprennent principalement : + +- `react` mis à jour vers v18 +- `react-dom` mis à jour vers v18 +- `react-router` mis à jour vers v6.11 +- `umi` mis à jour vers v4 +- `dumi` mis à jour vers v2 + +Le fichier `package.json` des dépendances doit être mis à jour vers la dernière version, par exemple : + +```diff +{ + "devDependencies": { ++ "react": "^18". ++ "react-dom": "^18". ++ "react-router-dom": "^6.11.2". +- "react": "^17". +- "react-dom": "^17". +- "react-router-dom": "^5". + } +} +``` + +### Modifications du code + +Étant donné que `react-router` a été mis à jour, le code associé doit également être modifié. Les principales modifications incluent : + +### Composant Layout + +Le composant Layout doit utiliser `<Outlet />` au lieu de `props.children`. + +```diff +import React from 'react'; ++ import { Outlet } from 'react-router-dom'; + +export default function Layout(props) { + return ( + <div> +- { props.children } ++ <Outlet /> + </div> + ); +} +``` + +Si vous utilisez `React.cloneElement` pour rendre le composant de la route, vous devez le changer ainsi : + +```diff +import React from 'react'; ++ import { Outlet } from 'react-router-dom'; + +export default function RouteComponent(props) { + return ( + <div> +- { React.cloneElement(props.children, { someProp: 'p1' }) } ++ <Outlet context={{ someProp: 'p1' }} /> + </div> + ); +} +``` + +Modifiez le composant de la route pour obtenir la valeur via `useOutletContext` : + +```diff +import React from 'react'; ++ import { useOutletContext } from 'react-router-dom'; + +- export function Comp(props){ ++ export function Comp() { ++ const props = useOutletContext(); + return props.someProp; +} +``` + +### Redirection + +`<Redirect>` est remplacé par `<Navigate replace />`. + +```diff +- <Redirect to="about" /> ++ <Navigate to="about" replace /> +``` + +### useHistory + +`useHistory` est remplacé par `useNavigate`. + +```diff +- import { useHistory } from 'react-router-dom'; ++ import { useNavigate} from 'react-router-dom'; + +- const history = useHistory(); ++ const navigate = useNavigate(); + +- history.push('/about') ++ navigate('/about') + +- history.replace('/about') ++ navigate('/about', { replace: true }) +``` + +### useLocation + +`useLocation<type>()` est remplacé par `useLocation`. + +```diff +- const location= useLocation<type>(); ++ const location= useLocation(); +``` + +`const { query } = useLocation()` est remplacé par `useSearchParams()`. + +```diff +- const location = useLocation(); +- const query = location.query; +- const name = query.name; ++ const [searchParams, setSearchParams] = useSearchParams(); ++ searchParams.get('name'); +``` + +### Chemin + +Tous les chemins de route suivants sont valides en v6 : + +``` +/groups +/groups/admin +/users/:id +/users/:id/messages +/files/* +/files/:id/* +``` + +Les chemins de route de type RegExp suivants ne sont pas valides en v6 : + +``` +/tweets/:id(\d+) +/files/*/cat.jpg +/files-* +``` + +Pour plus d'informations sur les changements d'API, consultez [react-router@6](https://reactrouter.com/en/main/upgrading/v5). diff --git a/docs/fr-FR/welcome/release/v0110-changelog.md b/docs/fr-FR/welcome/release/v0110-changelog.md new file mode 100644 index 000000000..f004b8e54 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0110-changelog.md @@ -0,0 +1,120 @@ +# v0.11 : 2023-07-08 + +## Nouvelles fonctionnalités + +- Nouvelle application client, plugin et routeur +- Mise à niveau de Ant Design vers v5 +- Nouveaux plugins : + - Visualisation de données + - Clés API + - Google Maps + +## Changements incompatibles + +### Nouvelle application client, plugin et routeur + +#### Changements de plugin + +Avant, vous deviez passer un composant et ce composant devait passer `props.children`. Par exemple : + +```tsx | pure +const HelloProvider = (props) => { + // faire quelque logique + return <div>{props.children}</div>; +}; + +export default HelloProvider; +``` + +Maintenant, vous devez changer pour la méthode des plugins, par exemple : + +```diff | pure ++ import { Plugin } from '@nocobase/client'; + +const HelloProvider = (props) => { + // faire quelque logique + return <div> + {props.children} + </div>; +} + ++ export class HelloPlugin extends Plugin { ++ async load() { ++ this.app.addProvider(HelloProvider); ++ } ++ } + +- export default HelloProvider; ++ export default HelloPlugin; +``` + +Les plugins sont très puissants et peuvent faire beaucoup de choses lors de la phase `load` : + +- modifier les routes +- ajouter des composants +- ajouter des fournisseurs +- ajouter des portées +- charger d'autres plugins + +#### Changements de routage + +Si vous utilisiez `RouteSwitchContext` pour modifier la route auparavant, vous devez maintenant le remplacer par un plugin : + +```tsx | pure +import { RouteSwitchContext } from '@nocobase/client'; + +const HelloProvider = () => { + const { routes, ...others } = useContext(RouteSwitchContext); + routes[1].routes.unshift({ + path: '/hello', + component: Hello, + }); + + return ( + <div> + <RouteSwitchContext.Provider value={{ ...others, routes }}> + {props.children} + </RouteSwitchContext.Provider> + </div> + ); +}; +``` + +Maintenant, vous devez changer pour la méthode des plugins, par exemple : + +```diff | pure +- import { RouteSwitchContext } from '@nocobase/client'; ++ import { Plugin } from '@nocobase/client'; + +const HelloProvider = (props) => { +- const { routes, ...others } = useContext(RouteSwitchContext); +- routes[1].routes.unshift({ +- path: '/hello', +- component: Hello, +- }); + + return <div> +- <RouteSwitchContext.Provider value={{ ...others, routes }}> + {props.children} +- </RouteSwitchContext.Provider> + </div> +} + ++ export class HelloPlugin extends Plugin { ++ async load() { ++ this.app.router.add('admin.hello', { ++ path: '/hello', ++ Component: Hello, ++ }); ++ this.app.addProvider(HelloProvider); ++ } ++ } ++ export default HelloPlugin; +``` + +Plus de détails peuvent être trouvés dans [packages/core/client/src/application/index.md](https://github.com/nocobase/nocobase/blob/main/packages/core/client/src/application/index.md) + +### Mise à niveau de Ant Design vers v5 + +- Pour les détails concernant `antd`, consultez le site officiel [V4 vers V5](https://ant.design/docs/react/migration-v5) +- `@formily/antd` est remplacé par `@formily/antd-v5` diff --git a/docs/fr-FR/welcome/release/v0120-changelog.md b/docs/fr-FR/welcome/release/v0120-changelog.md new file mode 100644 index 000000000..f465a3c48 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0120-changelog.md @@ -0,0 +1,180 @@ +# v0.12: 2023-08-02 + +## Nouvelles fonctionnalités + +- Nouvel outil de génération de plugins. Les plugins générés pourront être utilisés directement en production sans nécessiter une seconde génération. + +## Mises à jour des applications + +### Mise à jour de l'installation Docker + +Aucun changement, consultez le [Guide de mise à jour de l'image Docker](/welcome/getting-started/upgrading/docker-compose) pour la mise à jour. + +### Mise à jour de l'installation du code source + +L'outil de génération des plugins a été mis à jour, et il est nécessaire de vider le cache après avoir récupéré les nouvelles sources. + +```bash +git pull # Récupérer les nouvelles sources. +yarn clean # Vider le cache. +``` + +Pour plus de détails, consultez le [Guide de mise à jour du code source Git](/welcome/getting-started/upgrading/git-clone). + +### Mise à jour de l'installation `create-nocobase-app` + +Redownload la nouvelle version via `yarn create` et mettez à jour la configuration `.env`. Consultez le [guide de mise à jour de version majeure](/welcome/getting-started/upgrading/create-nocobase-app#Major-version-upgrade) pour plus de détails. + +## Changements incompatibles + +### Fusion de `@nocobase/app-client` et `@nocobase/app-server` en `@nocobase-app` + +Les applications installées via `create-nocobase-app` n'ont plus le répertoire `packages/app`, et le code personnalisé dans `packages/app` doit être déplacé vers le plugin personnalisé. + +### Changement du chemin `dist/client` de l'application + +Si vous configurez vous-même `nginx`, vous devrez ajuster comme suit : + +```diff +server { +- root /app/nocobase/packages/app/client/dist; ++ root /app/nocobase/node_modules/@nocobase/app/dist/client; + + location / { +- root /app/nocobase/packages/app/client/dist; ++ root /app/nocobase/node_modules/@nocobase/app/dist/client; + try_files $uri $uri/ /index.html; + add_header Last-Modified $date_gmt; + add_header Cache-Control 'no-store, no-cache'; + if_modified_since off; + expires off; + etag off; + } +} +``` + +### Les plugins tiers doivent être reconstruits + +Référez-vous au guide de mise à jour des plugins tiers ci-dessous. + +## Guide de mise à jour des plugins tiers + +### Le répertoire du plugin doit avoir les répertoires `src/client` et `src/server`. + +```js +// src/client/index.ts +import { Plugin } from '@nocobase/client'; + +class MyPlugin extends Plugin { + async load() { + // ... + } +} + +export default MyPlugin; +``` + +```js +// src/server/index.ts +import { Plugin } from '@nocobase/server'; + +class MyPlugin extends Plugin { + async load() { + // ... + } +} + +export default MyPlugin; +``` + +Un code d'exemple spécifique peut être consulté ici : [sample-hello](https://github.com/nocobase/nocobase/tree/main/packages/samples/hello) + +### Placement multilingue du plugin dans le répertoire `src/locale` + +Pour le frontend et le backend, les fichiers de traduction multilingue sont placés dans le répertoire `src/locale`, ainsi le plugin n'a pas besoin de charger les packages multilingues lui-même. + +### Ajustement des dépendances du plugin + +Les dépendances du plugin sont divisées en dépendances propres et dépendances globales. Les dépendances globales sont utilisées globalement et ne seront pas empaquetées dans le produit du plugin, tandis que les dépendances propres seront empaquetées dans le produit. Après la génération du plugin, l'environnement de production sera plug-and-play, sans nécessité d'installer des dépendances ou de générer deux fois. Les ajustements des dépendances du plugin incluent : + +- Placer les packages `@nocobase/*` dans `peerDependencies` et spécifier la version en `0.x` ; +- Placer les autres dépendances dans `devDependencies`, pas dans `dependencies`, car le plugin extraira toutes les dépendances nécessaires pour l'environnement de production après son empaquetage. + +```diff +{ + "devDependencies": { + "@formily/react": "2.x", + "@formily/shared": "2.x", + "ahooks": "3.x", + "antd": "5.x", + "dayjs": "1.x", + "i18next": "22.x", + "react": "18.x", + "react-dom": "18.x", + "react-i18next": "11.x" + }, + "peerDependencies": { + "@nocobase/actions": "0.x", + "@nocobase/client": "0.x", + "@nocobase/database": "0.x", + "@nocobase/resourcer": "0.x", + "@nocobase/server": "0.x", + "@nocobase/test": "0.x", + "@nocobase/utils": "0.x" + } +} +``` + +### Le chemin de sortie du plugin a changé de `lib` à `dist` + +Structure du répertoire `dist` : + +```bash +|- dist + |- client # Côté client, umd + |- index.js + |- index.d.ts + |- server # Côté serveur, cjs + |- index.js + |- index.d.ts + |- others + |- locale # Package multilingue + |- node_modules # Dépendances du serveur +``` + +Autres ajustements liés : + +Ajustement du paramètre `main` dans `package.json` : + +```diff +{ + - "main": "./lib/server/index.js", + + "main": "./dist/server/index.js", +} +``` + +`client.d.ts` : + +```ts +export * from './dist/client'; +export { default } from './dist/client'; +``` + +`client.js` : + +```js +module.exports = require('./dist/client/index.js'); +``` + +`server.d.ts` : + +```ts +export * from './dist/server'; +export { default } from './dist/server'; +``` + +`server.js` : + +```js +module.exports = require('./dist/server/index.js'); +``` diff --git a/docs/fr-FR/welcome/release/v0130-changelog.md b/docs/fr-FR/welcome/release/v0130-changelog.md new file mode 100644 index 000000000..657842b3c --- /dev/null +++ b/docs/fr-FR/welcome/release/v0130-changelog.md @@ -0,0 +1,23 @@ +# v0.13: 2023-08-24 + +## Nouvelles fonctionnalités + +### Flux d'état de l'application + +Cette version introduit un nouveau flux d'état de l'application pour mieux gérer les statuts de processus au sein des applications. + +![Application Status Flow](https://nocobase.oss-cn-beijing.aliyuncs.com/57c8e420be0c9c27392d793d5073c060.png) + +### Vidéo de démonstration + +Vous pouvez consulter la vidéo de démonstration pour découvrir les nouvelles fonctionnalités en action. + +<video controls width="100%"> + <source src="https://nocobase.oss-cn-beijing.aliyuncs.com/6430cb4ca6310724a7c25a256bce995f.mp4" type="video/mp4" /> +</video> + +## Mise à jour + +- [Mise à jour pour Docker compose](/welcome/getting-started/upgrading/docker-compose) +- [Mise à jour pour create-nocobase-app](/welcome/getting-started/upgrading/create-nocobase-app) +- [Mise à jour pour Git source code](/welcome/getting-started/upgrading/git-clone) diff --git a/docs/fr-FR/welcome/release/v0140-changelog.md b/docs/fr-FR/welcome/release/v0140-changelog.md new file mode 100644 index 000000000..689ff0687 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0140-changelog.md @@ -0,0 +1,84 @@ +# v0.14: 2023-09-12 + +Cette version permet l'utilisation de plugins plug-and-play en environnements de production. Vous pouvez désormais ajouter des plugins directement via l'interface utilisateur, avec un support pour le téléchargement depuis le registre npm (y compris privé), les téléchargements locaux et les téléchargements depuis des URL. + +## Nouvelles fonctionnalités + +### Nouvelle interface de gestion des plugins + +Cette mise à jour introduit une interface plus conviviale pour la gestion des plugins. + +![Plugin Manager Interface](https://static-docs.nocobase.com/20240429074459.png) + +### Plugins téléchargés situés dans le répertoire `storage/plugins` + +Les plugins téléchargés sont maintenant organisés dans le répertoire `storage/plugins` sous forme de packages npm. + +```bash +|- /storage/ + |- /plugins/ + |- /@nocobase/ + |- /plugin-hello1/ + |- /plugin-hello2/ + |- /@foo/ + |- /bar/ + |- /my-nocobase-plugin-hello/ +``` + +### Mises à jour des plugins + +Les plugins peuvent désormais être mis à jour directement depuis le répertoire `storage/plugins`. Voici à quoi cela ressemble : + +![Plugin Update](https://static-docs.nocobase.com/20240429074511.png) + +Note : Pour faciliter la maintenance et la mise à jour des plugins, vous pouvez déposer directement la nouvelle version du plugin dans le répertoire `storage/plugins` avant de procéder à la mise à jour. + +## Changements incompatibles + +### Changements dans les noms de plugins + +- La variable d'environnement `PLUGIN_PACKAGE_PREFIX` n'est plus fournie. +- Les noms de plugins et de packages sont désormais unifiés. Les anciens noms de plugins peuvent toujours exister en tant qu'alias. + +### Améliorations de la commande `pm.add` + +```bash +# Utilisez packageName au lieu de pluginName, cherche localement, erreur si non trouvé +pm add packageName + +# Télécharge depuis un registre distant si spécifié, vous pouvez également préciser la version +pm add packageName --registry=xx --auth-token=yy --version=zz + +# Vous pouvez aussi fournir un zip local, plusieurs ajouts possibles, seul le dernier sera pris +pm add /a/plugin.zip + +# Télécharge un zip distant, remplace-le par le même nom +pm add http://url/plugin.zip +``` + +### Modifications de la configuration Nginx + +Ajoutez la localisation `/static/plugins/` dans votre configuration Nginx. + +```conf +server { + location ^~ /static/plugins/ { + proxy_pass http://127.0.0.1:13000/static/plugins/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + } +} +``` + +Pour plus de détails, vous pouvez consulter la version complète de [nocobase.conf](https://github.com/nocobase/nocobase/blob/main/docker/nocobase/nocobase.conf). + +## Guide de développement de plugins + +Commencez à développer votre premier plugin en suivant ce guide : [Développer votre premier plugin](/development/your-fisrt-plugin). diff --git a/docs/fr-FR/welcome/release/v0150-changelog.md b/docs/fr-FR/welcome/release/v0150-changelog.md new file mode 100644 index 000000000..450ee2ab4 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0150-changelog.md @@ -0,0 +1,163 @@ +# v0.15: 2023-11-13 + +## Nouvelles fonctionnalités + +![Gestionnaire de paramètres de plugin](https://static-docs.nocobase.com/20240115140600.png) + +## Changements incompatibles + +### API d'enregistrement de la page de configuration du plugin + +Auparavant, la page de configuration du plugin était enregistrée à l'aide de `SettingsCenterProvider`. Désormais, l'enregistrement se fait directement via le plugin. + +#### Cas 1 : Il n'y a qu'un seul onglet sur la page + +Lorsqu'il n'y a qu'un seul onglet sur la page, la nouvelle version supprimera cet onglet, ne laissant que le titre et l'icône de la page. + +Avant : + +```tsx | pure +const HelloProvider = React.memo(props => { + return ( + <SettingsCenterProvider + settings={{ + hello: { + title: "Hello", + icon: "ApiOutlined", + tabs: { + tab1: { + title: "Hello tab", + component: HelloPluginSettingPage, + }, + }, + }, + }} + > + {props.children} + </SettingsCenterProvider> + ); +}); +``` + +Maintenant, il faut changer en : + +```tsx | pure +class HelloPlugin extends Plugin { + async load() { + this.app.pluginSettingsManager.add("hello", { + title: "Hello", + icon: "ApiOutlined", + Component: HelloPluginSettingPage, + // Ce paramètre n'est pas nécessaire s'il s'agit d'un nouveau plugin + aclSnippet: "pm.hello.tab1", + }); + } +} +``` + +Le `Hello Tab` de `tab1` a été supprimé. + +Le paramètre `aclSnippet` (`pm.hello.tab1`) correspond à la clé de l'objet `settings` d'origine : + +```tsx +<SettingsCenterProvider + settings={{ + hello: { + // Ce `hello` correspond à `hello` dans `pm.hello.tab1` + tabs: { + tab1: { + // Ici, `tab1` correspond à `tab1` dans `pm.hello.tab1` + }, + }, + }, + }} +></SettingsCenterProvider> +``` + +#### Cas 2 : Il y a plusieurs onglets sur la page + +Avant : + +```tsx +const HelloProvider = React.memo(props => { + return ( + <SettingsCenterProvider + settings={{ + hello: { + title: "Hello", + icon: "ApiOutlined", + tabs: { + tab1: { + title: "Hello tab1", + component: HelloPluginSettingPage1, + }, + tab2: { + title: "Hello tab2", + component: HelloPluginSettingPage2, + }, + }, + }, + }} + > + {props.children} + </SettingsCenterProvider> + ); +}); +``` + +Maintenant, il faut changer en : + +```tsx +import { Outlet } from "react-router-dom"; + +class HelloPlugin extends Plugin { + async load() { + this.app.pluginSettingsManager.add("hello", { + title: "Hello", + icon: "ApiOutlined", + Component: Outlet, + }); + + this.app.pluginSettingsManager.add("hello.tab1", { + title: "Hello tab1", + Component: HelloPluginSettingPage1, + }); + + this.app.pluginSettingsManager.add("hello.tab2", { + title: "Hello tab2", + Component: HelloPluginSettingPage1, + }); + } +} +``` + +Pour récupérer les informations de routage correspondantes au `pluginSettingsManager` : + +```tsx +const baseName = app.pluginSettingsManager.getRouteName("hello"); +// admin.settings.hello +const basePath = app.pluginSettingsManager.getRoutePath("hello"); // /admin/settings. +// /admin/settings/hello +``` + +Si un lien de navigation existe à l'intérieur de la page de configuration du plugin, il faut le mettre à jour comme suit : + +Avant : + +```tsx | pure +navigate("/admin/settings/hello/1").navigate("/admin/settings/hello/2"); +``` + +Maintenant, il doit être remplacé par : + +```tsx | pure +const basePath = app.pluginSettingsManager.getRoutePath("hello"); +navigate(`${basePath}/1`); +navigate(`${basePath}/2`); +``` + +Pour plus d'informations, consultez le [gestionnaire de paramètres de plugin](https://docs.nocobase.com/development/client/plugin-settings). + +## Changements + +Pour un changelog complet, veuillez consulter [Changelog](https://github.com/nocobase/nocobase/blob/main/CHANGELOG.md). diff --git a/docs/fr-FR/welcome/release/v0160-changelog.md b/docs/fr-FR/welcome/release/v0160-changelog.md new file mode 100644 index 000000000..310a6391f --- /dev/null +++ b/docs/fr-FR/welcome/release/v0160-changelog.md @@ -0,0 +1,77 @@ +# v0.16: 2023-11-20 + +## Nouveaux ajouts + +### Refactorisation du cache + +La version précédente du cache avait une faible utilisation (ne supportait que le cache en mémoire). La version v0.16 a été refactorisée pour inclure à la fois un cache en mémoire et un cache Redis, avec un support pour des magasins personnalisés. Pour plus de détails sur son utilisation, consultez la [documentation de l'API](https://docs.nocobase.com/api/cache/cache-manager). + +## Changements incompatibles + +### Mise à jour de la version minimale de Node + +La version 16 de Node n'est plus maintenue. La version minimale est désormais la v18. + +```json +{ + "engines": { + "node": ">=18" + } +} +``` + +### Mise à jour de la méthode de création du cache + +La méthode de création de cache précédente est obsolète. Utilisez désormais `createCache`. + +Avant : + +```ts +import { createCache } from "@nocobase/cache"; + +const cache = createCache(); +``` + +Désormais, le cache est géré par `CacheManager` et créé avec `app.cacheManager`. + +```ts +const cache = await app.cacheManager.createCache({ + name: "memory", // nom unique du cache + store: "memory", // méthode de cache unique + // autres configurations + max: 2000, + ttl: 60 * 1000, +}); +``` + +### Mise à jour des variables d'environnement + +Les variables d'environnement précédentes pour la configuration du cache nécessitaient une chaîne JSON. + +Avant : + +```bash +CACHE_CONFIG={"storePackage":"cache-manager-fs-hash","ttl":86400,"max":1000} +``` + +Les nouvelles variables d'environnement pour configurer le cache sont les suivantes : + +```bash +# Nom unique de la méthode de cache par défaut, mémoire ou redis +CACHE_DEFAULT_STORE=memory +# Nombre maximum d'éléments dans le cache en mémoire +CACHE_MEMORY_MAX=2000 +# Redis, optionnel +CACHE_REDIS_URL=redis://localhost:6379 +``` + +## Changements complets du changelog + +- refactorisation(cache): amélioration du cache [`#3004`](https://github.com/nocobase/nocobase/pull/3004) +- correction: URL de base pour le stockage local [`#3063`](https://github.com/nocobase/nocobase/pull/3063) +- fonctionnalité: affichage de la définition de la table [`#3061`](https://github.com/nocobase/nocobase/pull/3061) +- fonctionnalité: support de MariaDB [`#3052`](https://github.com/nocobase/nocobase/pull/3052) +- correction(plugin-workflow): corrections mineures côté client [`#3062`](https://github.com/nocobase/nocobase/pull/3062) +- tâche: inférence de vue [`#3060`](https://github.com/nocobase/nocobase/pull/3060) +- correction: tri par collection d'association [`#3058`](https://github.com/nocobase/nocobase/pull/3058) +- fonctionnalité: Node >= 18 [`#3066`](https://github.com/nocobase/nocobase/pull/3066) diff --git a/docs/fr-FR/welcome/release/v0170-changelog.md b/docs/fr-FR/welcome/release/v0170-changelog.md new file mode 100644 index 000000000..e764254f4 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0170-changelog.md @@ -0,0 +1,86 @@ +# v0.17 : 4 décembre 2023 + +## Nouvelles fonctionnalités + +Afin de réduire les coûts d'apprentissage pour les développeurs et d'offrir une meilleure expérience de développement frontend, nous avons entrepris une refonte progressive du cœur frontend au cours des derniers mois, ce qui inclut : + +![20240115141058](https://static-docs.nocobase.com/20240115141058.png) + +Cette version v0.17 a refactorisé les éléments liés au **UI Schema Designer**, notamment **SchemaInitializer** et **SchemaSettings**. + +![20240115141118](https://static-docs.nocobase.com/20240115141118.png) + +![20240115141129](https://static-docs.nocobase.com/20240115141129.png) + +### Refonte de la documentation + +Pour faciliter la prise en main par les utilisateurs, nous avons également réorganisé diverses sections de la documentation : + +- **Développement de plugins** : La section a été complètement révisée et publiée. Consultez-la [ici](https://docs.nocobase.com/development). +- **Référence API / Client** : Une nouvelle section dédiée à l'[API Client](https://client.docs.nocobase.com/core/application/application), déjà publiée. +- **Manuel Utilisateur** : Une version complètement révisée sera publiée dans une à deux semaines. +- **Liste des plugins** : Nouvelle section qui comprendra des introductions, des instructions d'utilisation et des guides pour le développement d'extensions pour tous les plugins existants, prévue pour être publiée dans une à deux semaines. + +## Modifications incompatibles + +### Modifications de `SchemaInitializer` + +- Ajout de `SchemaInitializerManager` pour enregistrer les `SchemaInitializer`. +- Ajout de `useSchemaInitializerRender()` pour remplacer l'ancienne méthode `useSchemaInitializer()` et sa fonction `render()`. +- Ajout de `useSchemaInitializerItem()` pour obtenir le contexte de l'élément d'initialisation actuel. +- Ajout du composant `SchemaInitializerItemGroup` comme composant par défaut pour `type: 'itemGroup'`. +- Ajout du composant `SchemaInitializerSubMenu` comme composant par défaut pour `type: 'subMenu'`. +- Ajout du composant `SchemaInitializerDivider` comme composant par défaut pour `type: 'divider'`. +- Ajout du composant `SchemaInitializerChildren` pour rendre de manière personnalisée plusieurs éléments de liste. +- Ajout du composant `SchemaInitializerChild` pour rendre de manière personnalisée un seul élément de liste. +- Changement des responsabilités de `SchemaInitializerContext` pour stocker le contexte de l'initialiseur actuel. +- Changement des responsabilités de `useSchemaInitializer()` pour obtenir le contexte de l'initialiseur actuel. +- Transformation de `SchemaInitializer` de fonction en `class` pour définir l'initialiseur. +- Modifications des paramètres de `SchemaInitializer` : + - Ajout du paramètre requis `name` pour la valeur de `x-initializer`. + - Ajout du paramètre `Component` pour personnaliser le rendu du bouton. Par défaut, c'est `SchemaInitializerButton`. + - Ajout des paramètres `componentProps`, `style` pour configurer les propriétés et le style du `Component`. + - Ajout du paramètre `ItemsComponent` pour personnaliser le rendu de la liste. Par défaut, c'est `SchemaInitializerItems`. + - Ajout des paramètres `itemsComponentProps`, `itemsComponentStyle` pour configurer les propriétés et le style de `ItemsComponent`. + - Ajout du paramètre `popover` pour configurer l'affichage de l'effet `popover`. + - Ajout du paramètre `useInsert` pour les cas où la fonction `insert` nécessite l'utilisation de hooks. + - Changement du paramètre `dropdown` en `popoverProps`, utilisant `Popover` au lieu de `Dropdown`. +- Modifications des paramètres de `items` pour `SchemaInitializer` : + - Ajout de la fonction `useChildren` pour contrôler dynamiquement les éléments enfants. + - Ajout de la fonction `componentProps` pour les propriétés du composant lui-même. + - Ajout de la fonction `useComponentProps` pour traiter dynamiquement les propriétés du composant. + - Changement du paramètre `key` en `name` pour l'identification unique des éléments de la liste. + - Changement du paramètre `visible` en fonction `useVisible` pour contrôler dynamiquement l'affichage. + - Changement du paramètre `component` en `Component` pour rendre les éléments de la liste. +- Changement de `SchemaInitializer.Button` en `SchemaInitializerButton`, qui devient la valeur par défaut pour le paramètre `Component` de `SchemaInitializer`. +- Changement de `SchemaInitializer.Item` en `SchemaInitializerItem`, sans modification des paramètres. +- Changement de `SchemaInitializer.ActionModal` en `SchemaInitializerActionModal`, sans modification des paramètres. +- Changement de `SchemaInitializer.SwitchItem` en `SchemaInitializer.Switch`, sans modification des paramètres. +- Suppression de `SchemaInitializerProvider`, remplacé par `SchemaInitializerManager`. +- Suppression de `SchemaInitializer.itemWrap`, inutile désormais pour envelopper le composant `item`. + +### Modifications de `SchemaSettings` + +- Ajout de `SchemaSettingsManager` pour enregistrer les `SchemaSettings`. +- Ajout de `useSchemaSettingsItem()`. +- Ajout de `useSchemaSettingsRender()`. +- Ajout du paramètre `x-settings` pour configurer les paramètres du schéma. +- Ajout du paramètre `x-toolbar` pour configurer la barre d'outils du schéma. +- Ajout du composant `SchemaToolbar` pour personnaliser la barre d'outils du schéma. +- Ajout de `useSchemaToolbarRender()` pour remplacer l'ancienne méthode `useDesigner()`. +- Transformation de `function SchemaSettings` en `class SchemaSettings` pour définir les paramètres. +- Changement de l'ancien `SchemaSettings` en `SchemaSettingsDropdown`. +- Changement de `SchemaSettings.Item` en `SchemaSettingsItem`. +- Changement de `SchemaSettings.ItemGroup` en `SchemaSettingsItemGroup`. +- Changement de `SchemaSettings.SubMenu` en `SchemaSettingsSubMenu`. +- Changement de `SchemaSettings.Divider` en `SchemaSettingsDivider`. +- Changement de `SchemaSettings.Remove` en `SchemaSettingsRemove`. +- Changement de `SchemaSettings.SelectItem` en `SchemaSettingsSelectItem`. +- Changement de `SchemaSettings.CascaderItem` en `SchemaSettingsCascaderItem`. +- Changement de `SchemaSettings.SwitchItem` en `SchemaSettingsSwitchItem`. +- Changement de `SchemaSettings.ModalItem` en `SchemaSettingsModalItem`. +- Changement de `SchemaSettings.ActionModalItem` en `SchemaSettingsActionModalItem`. +- Suppression du paramètre `x-designer`, obsolète, qui sera supprimé dans les futures versions, à remplacer par `x-toolbar`. +- Suppression de `useDesigner()`, obsolète, qui sera supprimé dans les futures versions, à remplacer par `useSchemaToolbarRender()`. + +Pour plus de détails, consultez [les modifications incompatibles dans NocoBase 0.17](https://docs.nocobase.com/welcome/release/upgrade-to/v017). diff --git a/docs/fr-FR/welcome/release/v0180-changelog.md b/docs/fr-FR/welcome/release/v0180-changelog.md new file mode 100644 index 000000000..0728c2354 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0180-changelog.md @@ -0,0 +1,185 @@ +# v0.18 : 2023-12-21 + +## Nouvelles fonctionnalités + +Afin d'améliorer la robustesse de NocoBase, nous avons intégré des tests E2E (end-to-end) au cours du quatrième trimestre. Parallèlement, nous avons également peaufiné l'ensemble du système de test. + +### @nocobase/test + +Le kit de test NocoBase comprend : + +- **`@nocobase/test/server`** pour les tests côté serveur + - Intégration de **`supertest`** pour les tests d'interface. + - `mockDatabase` et `mockServer` sont intégrés. + +- **`@nocobase/test/client`** pour les tests côté client + - Intégration de **`@testing-library/react`** et **`@testing-library/user-event`**. + +- **`@nocobase/test/e2e`** pour les tests E2E + - Intégration de **`@playwright/test`**. + - Méthodes de simulation communes intégrées. + +### Framework de tests + +- **Tests côté serveur** : utilisant le framework **Vitest**. +- **Tests côté client** : utilisant le framework **Vitest**. +- **Tests E2E** : utilisant le framework **Playwright**. + +### Écriture des tests + +#### Tests côté serveur + +```typescript +import { mockDatabase } from '@nocobase/test/server'; + +describe('ma suite de tests pour la base de données', () => { + let db; + + beforeEach(async () => { + db = mockDatabase(); + db.collection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + ], + }); + await db.sync(); + }); + + afterEach(async () => { + await db.close(); + }); + + test('mon cas de test', async () => { + const repository = db.getRepository('posts'); + const post = await repository.create({ + values: { + title: 'hello', + }, + }); + + expect(post.get('title')).toEqual('hello'); + }); +}); +``` + +Dans cet exemple de test côté serveur, un environnement de base de données est simulé avec `mockDatabase()`. La collection "posts" est créée, puis un enregistrement est inséré. Après cela, nous vérifions si la valeur du champ `title` est bien "hello". + +#### Tests côté client + +```typescript +import { render, screen, userEvent, waitFor } from '@nocobase/test/client'; + +it('devrait afficher la valeur de l\'entrée de l\'utilisateur', async () => { + const { container } = render(<App1 />); + const input = container.querySelector('input'); + await userEvent.type(input, 'Hello World'); + await waitFor(() => { + expect(screen.getByText('Hello World')).toBeInTheDocument(); + }); +}); +``` + +Dans cet exemple de test côté client, l'application `App1` est rendue et un utilisateur tape du texte dans un champ de saisie. Ensuite, le test attend que le texte "Hello World" apparaisse dans le document, ce qui est vérifié avec `screen.getByText`. + +#### Tests E2E (End-to-End) + +```typescript +import { test } from '@nocobase/test/e2e'; + +test('connexion', async ({ page }) => { + await page.goto('/'); + await page.getByPlaceholder('Nom d\'utilisateur/Email').click(); + await page.getByPlaceholder('Nom d\'utilisateur/Email').fill('admin@nocobase.com'); + await page.getByPlaceholder('Mot de passe').click(); + await page.getByPlaceholder('Mot de passe').fill('admin123'); + await page.getByRole('button', { name: 'Se connecter' }).click(); + await expect( + page.getByTestId('user-center-button').getByText('Super Admin') + ).toBeVisible(); +}); +``` + +Dans ce test E2E, la page de connexion est simulée. Un utilisateur entre ses identifiants, clique sur le bouton de connexion, puis le test vérifie que le bouton "Super Admin" est visible après la connexion réussie. + +### Exécution des tests avec Vitest + +```bash +# Exécute tous les tests avec deux processus parallèles Vitest pour le frontend et le backend. +yarn test + +# Exécute les tests côté client. +yarn test --client +# équivalent à +yarn cross-env TEST_ENV=client-side vitest + +# Exécute les tests côté serveur. +yarn test --server +# équivalent à +yarn cross-env TEST_ENV=server-side vitest + +# Spécifie un répertoire ou un fichier spécifique. +yarn test your/path/src/__tests__/test-file.test.ts +# Les fichiers côté client doivent inclure /client/ +yarn test your/path/client/src/__tests__/test-file.test.ts +``` + +📢 **Différence avec l'exécution directe de Vitest :** + +- Lorsque vous spécifiez un chemin, le système reconnaît automatiquement le côté frontend et backend. Le côté frontend doit inclure `/client/`. +- Les tests backend sont exécutés avec l'option `-single-thread` par défaut. Si vous souhaitez la désactiver, ajoutez `-single-thread=false`. +- L'option par défaut est `--run`. Si vous devez écouter les changements, ajoutez `--watch`. + +### Exécution des tests Playwright + +```bash +# Installer les dépendances +yarn e2e install-deps + +# Exécuter les tests +yarn e2e test + +# Mode UI +yarn e2e test --ui + +# Spécifier l'URL de l'application +yarn e2e test --url=http://localhost:20000 + +# Démarrer une application. Elle est réinstallée à chaque fois. +yarn e2e start-app +``` + +## Autres changements + +### Optimisation du plugin d'authentification + +- Guide de développement de l'extension d'authentification [https://docs.nocobase.com/plugins/auth/dev/guide](https://docs.nocobase.com/plugins/auth/dev/guide) +- Changements incompatibles [https://docs.nocobase.com/breaking-changes/v0-18-0-alpha-1](https://docs.nocobase.com/breaking-changes/v0-18-0-alpha-1) + +### Décomposition modulaire en plugins + +Afin d'affiner le noyau et de le rendre plus léger, certaines fonctionnalités ont été séparées de manière modulaire. Récemment, les plugins qui ont subi cette modularisation comprennent : + +| Nom du plugin | Nom du package | +| ------------------------------------ | -------------------------------------------- | +| Action - Édition en masse | @nocobase/plugin-action-bulk-edit | +| Action - Mise à jour en masse | @nocobase/plugin-action-bulk-update | +| Action - Duplication | @nocobase/plugin-action-duplicate | +| Kanban | @nocobase/plugin-kanban | +| Gantt | @nocobase/plugin-gantt | +| Workflow - Agrégation | @nocobase/plugin-workflow-aggregate | +| Workflow - Approbation | @nocobase/plugin-workflow-approval | +| Workflow - Délai | @nocobase/plugin-workflow-delay | +| Workflow - Calcul dynamique | @nocobase/plugin-workflow-dynamic-calculation| +| Workflow - Déclencheur de formulaire | @nocobase/plugin-workflow-form-trigger | +| Workflow - Requête JSON | @nocobase/plugin-workflow-json-query | +| Workflow - Boucle | @nocobase/plugin-workflow-loop | +| Workflow - Manuel | @nocobase/plugin-workflow-manual | +| Workflow - Parallèle | @nocobase/plugin-workflow-parallel | +| Workflow - Demande | @nocobase/plugin-workflow-request | +| Workflow - SQL | @nocobase/plugin-workflow-sql | + +Voir la [liste complète des plugins](https://docs.nocobase.com/plugins) pour plus de détails. Le document est en construction, avec certains contenus qui peuvent être manquants ou en attente de traduction. Vous pouvez suivre les mises à jour sur [nocobase/docs](https://github.com/nocobase/docs). diff --git a/docs/fr-FR/welcome/release/v0190-changelog.md b/docs/fr-FR/welcome/release/v0190-changelog.md new file mode 100644 index 000000000..1ecdb6e52 --- /dev/null +++ b/docs/fr-FR/welcome/release/v0190-changelog.md @@ -0,0 +1,278 @@ +# v0.19 : 8 janvier 2024 + +## Nouvelles fonctionnalités + +### Télémétrie + +- Documentation pour les développeurs : [Documentation de la télémétrie](https://docs.nocobase.com/development/server/telemetry) +- API du noyau : [API de la télémétrie](https://docs.nocobase.com/api/telemetry/telemetry) +- Plugin Prometheus : [Plugin de télémétrie Prometheus](https://docs.nocobase.com/plugins/telemetry-prometheus) + +### Sauvegarde et restauration d'application + +- Documentation du plugin : [Plugin de sauvegarde et restauration](https://docs.nocobase.com/plugins/backup-restore) + +## Optimisations du noyau + +### Optimisations de la ligne de commande + +Pour NocoBase 0.19 et les versions ultérieures, les commandes personnalisées des plugins doivent être placées dans le répertoire `src/server/commands/*.ts` du plugin avec le contenu suivant : + +```typescript +export default function(app) { + app.command('custom1').action(); +} +``` + +Flux d'exécution de la ligne de commande : + +![20240115141900](https://static-docs.nocobase.com/20240115141900.png) + +Configuration spéciale de la commande + +- `ipc()` : Lorsque l'application fonctionne, la ligne de commande envoie des commandes via ipc pour opérer sur l'instance d'application en cours d'exécution. Lorsque `ipc()` n'est pas configuré, une nouvelle instance de l'application est créée, puis l'opération est exécutée (cela n'interfère pas avec l'instance de l'application en cours d'exécution). +- `auth()` : Effectue une vérification de la base de données. Si la configuration de la base de données est incorrecte, cette commande ne sera pas exécutée. +- `preload()` : Indique si la configuration de l'application doit être préchargée, c'est-à-dire si `app.load()` doit être exécuté. + +Cela peut être configuré en fonction de l'utilisation réelle de la commande. Voici des exemples : + +```typescript +app.command('a').ipc().action() +app.command('a').auth().action() +app.command('a').preload().action() +``` + +### Optimisation du processus d'installation + +![20240115141914](https://static-docs.nocobase.com/20240115141914.png) + +### Optimisation du processus de démarrage + +![20240115141922](https://static-docs.nocobase.com/20240115141922.png) + +### Optimisation du processus de mise à jour + +![20240115141933](https://static-docs.nocobase.com/20240115141933.png) + +Les migrations de mise à jour sont catégorisées en **beforeLoad**, **afterSync**, et **afterLoad** : + +- **beforeLoad** : Exécuté avant le chargement de chaque module, divisé en trois étapes : + - Avant de charger les modules du noyau + - Avant de charger les plugins prédéfinis + - Avant de charger les autres plugins + +- **afterSync** : Exécuté après la synchronisation des configurations des tables de données avec la base de données, divisé en trois étapes : + - Après la synchronisation des tables du noyau avec la base de données + - Après la synchronisation des tables des plugins prédéfinis avec la base de données + - Après la synchronisation des tables des autres plugins avec la base de données + +- **afterLoad** : Exécuté uniquement après le chargement complet de l'application. + +Voici un exemple de migration : + +```typescript +export default class extends Migration { + // Quand effectuer la migration + on = 'beforeLoad'; + // Exécuter uniquement si la version de l'application correspond. + appVersion = '<=0.13.0-alpha.5'; + // Exécuter uniquement si la version du plugin correspond. + pluginVersion = '<=0.13.0-alpha.5'; + // Script de mise à jour. + async up() {} +} +``` + +### Ajouter la commande `create-migration` + +Crée un fichier de migration + +```bash +yarn nocobase create-migration -h + +Usage: nocobase create-migration [options] <name> + +Options: + --pkg <pkg> nom du package + --on [on] Options disponibles : beforeLoad, afterSync et afterLoad + -h, --help affiche l'aide pour cette commande +``` + +Exemple + +```bash +$ yarn nocobase create-migration update-ui --pkg=@nocobase/plugin-client + +2024-01-07 17:33:13 [info ] ajout de l'application principale dans le superviseur +2024-01-07 17:33:13 [info ] fichier de migration dans /nocobase/packages/plugins/@nocobase/plugin-client/src/server/migrations/20240107173313-update-ui.ts +✨ Terminé en 5.02s. +``` + +Un fichier de migration sera généré dans `src/server/migrations` du package plugin `@nocobase/plugin-client` sous le nom `20240107173313-update-ui.ts` avec le contenu initial suivant : + +```typescript +import { Migration } from '@nocobase/server'; + +export default class extends Migration { + on = 'afterLoad'; // 'beforeLoad' | 'afterSync' | 'afterLoad' + appVersion = '<0.18.0-alpha.10'; + + async up() { + // code ici + } +} +``` + +### Les répertoires basés sur la convention pour les plugins + +```bash +|- /plugin-sample-hello + |- /dist # Répertoire pour le plugin compilé + |- /src # Code source du plugin + |- /client + |- plugin.ts + |- index.ts # Point d'entrée côté client + |- /locale # Répertoire conventionnel pour les fichiers multilingues partagés entre le frontend et le backend + |- /swagger # Répertoire conventionnel pour la documentation Swagger + |- /server + |- collections # Répertoire conventionnel pour les configurations des tables de données du plugin + |- commands # Répertoire conventionnel pour les commandes personnalisées + |- migrations # Répertoire conventionnel pour les fichiers de migration + |- plugin.ts # Classe du plugin + |- index.ts # Point d'entrée côté serveur + |- index.ts + |- .npmignore + |- client.d.ts + |- client.js + |- package.json + |- server.d.ts + |- server.js +``` + +### Optimisation du processus de test + +Des méthodes plus conviviales comme `createMockServer()` et `startMockServer()` ont été fournies pour l'écriture des cas de test : + +- `createMockServer()` Crée et démarre rapidement une application. +- `startMockServer()` Démarre rapidement une application (sans réinstallation). + +```typescript +import { createMockServer } from '@nocobase/server'; + +describe('test example', () => { + let app: MockServer; + + beforeEach(async () => { + app = await createMockServer({ + plugins: ['nocobase'], + }); + }); + + afterEach(async () => { + await app.destroy(); + }); + + test('case1', async () => { + // codage... + }); +}); +``` + +## Changements incompatibles + +### Changement de la configuration des collections, des commandes et des migrations vers des répertoires basés sur la convention + +Exemple 1 : Collections chargées par `importCollections`, le code est directement supprimé, et le fichier de configuration des collections doit être placé dans le répertoire `src/server/collections`. + +```diff +export class AuthPlugin extends Plugin { + async load() { +- await this.importCollections(resolve(__dirname, 'collections')); + } +} +``` + +Exemple 2 : Collections chargées via `this.db.import`, le code est directement supprimé, et le fichier de configuration des collections doit être placé dans le répertoire `src/server/collections`. + +```diff +export class AuthPlugin extends Plugin { + async load() { +- await this.db.import({ +- directory: resolve(__dirname, 'collections') +- }); + } +} +``` + +Exemple 3 : Une collection définie par `db.collection()` est recommandée à être placée dans le répertoire `src/server/collections`. + +```diff +export class AuthPlugin extends Plugin { + async load() { +- this.db.collection({ +- name: 'examples', +- }); + } +} +``` + +Ajoutez un nouveau fichier `src/server/collections/examples.ts` avec le contenu suivant : + +```typescript +import { defineCollection } from '@nocobase/database'; + +export default defineCollection({ + name: 'examples', +}); +``` + +Exemple 4 : Supprimez `db.addMigrations()` et placez le fichier de migration dans le répertoire `src/server/migrations`. + +```diff +export class AuthPlugin extends Plugin { + async load() { +- this.db.addMigrations({ +- namespace: 'auth', +- directory: resolve(__dirname, 'migrations'), +- context: { +- plugin: this, +- }, +- }); + } +} +``` + +### Exemple 5 : Personnalisation de la ligne de commande + +```diff +export class MyPlugin extends Plugin { + load() { +- this.app +- .command('echo') +- .option('-v, --version'); +- .action(async ([options]) => { +- console.log('Hello World!'); +- if (options.version) { +- console.log('Current version:', app.getVersion()); +- } +- }); +- } +} +``` + +Ajoutez un nouveau fichier `src/server/commands/echo.ts` avec le contenu suivant : + +```typescript +export default function(app) { + app + .command('echo') + .option('-v, --version') + .action(async ([options]) => { + console.log('Hello World!'); + if (options.version) { + console.log('Current version:', await app.version.get()); + } + }); +} +``` + diff --git a/docs/fr-FR/welcome/release/v0200-changelog/20240303170947_rec_.gif b/docs/fr-FR/welcome/release/v0200-changelog/20240303170947_rec_.gif new file mode 100644 index 000000000..597aafc8f Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/20240303170947_rec_.gif differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/20240303172205_rec_.gif b/docs/fr-FR/welcome/release/v0200-changelog/20240303172205_rec_.gif new file mode 100644 index 000000000..f2713b5a3 Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/20240303172205_rec_.gif differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-1.png b/docs/fr-FR/welcome/release/v0200-changelog/image-1.png new file mode 100644 index 000000000..75b48b6ce Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-1.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-10.png b/docs/fr-FR/welcome/release/v0200-changelog/image-10.png new file mode 100644 index 000000000..c4c9ca82d Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-10.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-11.png b/docs/fr-FR/welcome/release/v0200-changelog/image-11.png new file mode 100644 index 000000000..762ea21ee Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-11.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-12.png b/docs/fr-FR/welcome/release/v0200-changelog/image-12.png new file mode 100644 index 000000000..9a83fb1be Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-12.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-13.png b/docs/fr-FR/welcome/release/v0200-changelog/image-13.png new file mode 100644 index 000000000..ff459608d Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-13.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-14.png b/docs/fr-FR/welcome/release/v0200-changelog/image-14.png new file mode 100644 index 000000000..f7f8b7082 Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-14.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-15.png b/docs/fr-FR/welcome/release/v0200-changelog/image-15.png new file mode 100644 index 000000000..1aa59c4d9 Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-15.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-16.png b/docs/fr-FR/welcome/release/v0200-changelog/image-16.png new file mode 100644 index 000000000..2313fccba Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-16.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-17.png b/docs/fr-FR/welcome/release/v0200-changelog/image-17.png new file mode 100644 index 000000000..88aa7ddf6 Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-17.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-18.png b/docs/fr-FR/welcome/release/v0200-changelog/image-18.png new file mode 100644 index 000000000..c2e205942 Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-18.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-2.png b/docs/fr-FR/welcome/release/v0200-changelog/image-2.png new file mode 100644 index 000000000..7498245c0 Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-2.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-3.png b/docs/fr-FR/welcome/release/v0200-changelog/image-3.png new file mode 100644 index 000000000..acd326aa9 Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-3.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-4.png b/docs/fr-FR/welcome/release/v0200-changelog/image-4.png new file mode 100644 index 000000000..95e4985ee Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-4.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-5.png b/docs/fr-FR/welcome/release/v0200-changelog/image-5.png new file mode 100644 index 000000000..c4cd97426 Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-5.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-6.png b/docs/fr-FR/welcome/release/v0200-changelog/image-6.png new file mode 100644 index 000000000..ad2cd8af5 Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-6.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-7.png b/docs/fr-FR/welcome/release/v0200-changelog/image-7.png new file mode 100644 index 000000000..5fbfd54d0 Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-7.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-8.png b/docs/fr-FR/welcome/release/v0200-changelog/image-8.png new file mode 100644 index 000000000..aa70bb33f Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-8.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image-9.png b/docs/fr-FR/welcome/release/v0200-changelog/image-9.png new file mode 100644 index 000000000..2716b6a3f Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image-9.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/image.png b/docs/fr-FR/welcome/release/v0200-changelog/image.png new file mode 100644 index 000000000..1e9a56c9e Binary files /dev/null and b/docs/fr-FR/welcome/release/v0200-changelog/image.png differ diff --git a/docs/fr-FR/welcome/release/v0200-changelog/index.md b/docs/fr-FR/welcome/release/v0200-changelog/index.md new file mode 100644 index 000000000..e5c4ebe5e --- /dev/null +++ b/docs/fr-FR/welcome/release/v0200-changelog/index.md @@ -0,0 +1,363 @@ +# v0.20 : 2024-03-03 + +## Nouvelles fonctionnalités + +### Support de plusieurs sources de données + +Ajout du plugin "[Gestionnaire de sources de données](/handbook/data-source-manager)", utilisé pour gérer toutes les collections et champs des sources de données. Le plugin Gestionnaire de sources de données offre une interface centralisée pour gérer les sources de données, mais ne fournit pas la capacité d'accéder directement à ces sources. Il doit être utilisé en combinaison avec divers plugins de sources de données. Les sources de données actuellement prises en charge incluent : + +- [Base de données principale](/handbook/data-source-main) : Base de données principale de NocoBase, prenant en charge les bases de données relationnelles telles que MySQL, PostgreSQL, SQLite, etc. +- [Source de données MySQL externe](/handbook/data-source-external-mysql) : Accès à une base de données MySQL existante en tant que source de données. +- [Source de données MariaDB externe](/handbook/data-source-external-mariadb) : Accès à une base de données MariaDB existante en tant que source de données. +- [Source de données PostgreSQL externe](/handbook/data-source-external-postgres) : Accès à une base de données PostgreSQL existante en tant que source de données. + +De plus, d'autres sources de données peuvent être étendues, qu'il s'agisse de types de bases de données courants ou de plateformes offrant des API (SDK). + +![Gestionnaire de sources de données](https://static-docs.nocobase.com/fe8ecdaf640097eeb310c94a997b9090.png) + +### Ajustement de la gestion des collections + +Le gestionnaire de collections d'origine a été déplacé vers "Source de données > Base de données principale > Configuration". + +![Configuration de la base de données principale](https://static-docs.nocobase.com/b5ad882a131e447f78b0c22a92ec9df6.gif) + +### Support des champs non-ID comme clés primaires et contraintes de relation + +Lors de la création d'une collection, vous pouvez choisir de ne pas créer de champ ID. + +![Champs prédéfinis](https://static-docs.nocobase.com/87dc4101a884f97cbfce00f1891f7cf6.png) + +Les champs de type entier peuvent être utilisés comme clés primaires. + +![Les champs de type entier peuvent être utilisés comme clés primaires](https://static-docs.nocobase.com/cce37d7d8e9feaa66970da0c643a2d9d.png) + +Les champs de texte à une ligne peuvent également être utilisés comme clés primaires. + +![Les champs de texte à une ligne peuvent également être utilisés comme clés primaires](https://static-docs.nocobase.com/b2c797f52bedfcfa06936a244dd9be4b.png) + +Les contraintes de relation prennent en charge la sélection d'autres champs avec des index uniques définis en tant que champs non-clés primaires. + +![](https://static-docs.nocobase.com/e5515e58426c5be08ba982b0bb311410.png) + +### Ajustement du tri par glisser-déposer + +Ajout d'un champ de type "Tri". Les champs de tri ne sont plus générés automatiquement lors de la création des collections et doivent être créés manuellement. + +![Champ de tri](https://static-docs.nocobase.com/470891c7bb34c506328c1f3824a6cf20.png) + +Lors de la sélection d'un champ en tant que groupe, le regroupement sera effectué avant le tri. + +![Tri avant le regroupement](https://static-docs.nocobase.com/0794d0a9c0dc288a8fc924a3542bb86e.png) + +Lorsque le tri par glisser-déposer est activé dans le bloc de table, il est nécessaire de sélectionner le champ de tri. + +![Sélectionner le champ de tri](https://static-docs.nocobase.com/20cf12fd7ca3d8c0aa1917a95c0a7e7c.png) + +Lors de la création d'un bloc Kanban, vous devez sélectionner le champ de tri. + +![Sélectionner le champ de tri pour Kanban](https://static-docs.nocobase.com/b810265790d6a1ec099e3d88d1361271.png) + +### Ajustement des interfaces utilisateur et des permissions + +Ajout de l'interface de gestion des utilisateurs et unification de la gestion des utilisateurs et des rôles sous un même menu. + +![Interface de gestion des utilisateurs](https://static-docs.nocobase.com/7be26746652098f07ce105dbae373522.png) + +Ajustement de l'interface de gestion des rôles pour faciliter la gestion des rôles associés aux utilisateurs, des permissions, des départements, etc. + +![Interface de gestion des rôles](https://static-docs.nocobase.com/4ec942af764dfcec1ddc9a244816a6ee.png) + +Déplacement des "Permissions d'action" vers l'onglet "Source de données". + +![Permissions d'action](https://static-docs.nocobase.com/461ab881fe94a33f9a122e9734b85f4d.gif) + +### Plugin Département + +Organisez les utilisateurs en départements, définissez des relations hiérarchiques, associez des rôles pour contrôler les permissions et utilisez les départements comme variables dans les workflows et expressions. + +![Plugin Département](https://static-docs.nocobase.com/093473d9c23a789d41899df9bcaf3389.png) + +### Workflow : Approvisionnement + +Le plugin d'approbation fournit des types de workflow dédiés (déclencheurs) "Initier une approbation" et "Approuver" pour ce processus. Combiné avec les tables de données personnalisées et les blocs personnalisés de NocoBase, il est possible de créer et gérer rapidement divers scénarios d'approbation de manière flexible. + +Configuration de l'approbation + +![Configuration de l'approbation](https://static-docs.nocobase.com/21acc5615ecc03aeeb44671ab945baea.png) + +Processus d'approbation + +![Processus d'approbation](https://static-docs.nocobase.com/6a879641bd15de0648cd4602779ef9fa.png) + +Plus de détails sont disponibles dans la documentation : [Workflow Approvisionnement](/handbook/workflow-approval) + +### Workflow : Noeud de fin de processus + +Ce noeud met immédiatement fin à l'exécution en cours du workflow lorsqu'il est exécuté et se termine avec le statut configuré dans le noeud. Il est généralement utilisé pour contrôler le flux logique spécifique, pour sortir du workflow actuel après avoir satisfait certaines conditions logiques, sans continuer avec les traitements suivants. Cela peut être comparé à la commande de retour dans les langages de programmation, utilisée pour sortir de la fonction en cours d'exécution. + +![Noeud de fin de processus](https://static-docs.nocobase.com/38d6352211d791fd4233f5cd4bdb34f2.png) + +Plus de détails sont disponibles dans la documentation : [Noeud de fin de processus](/handbook/workflow/manual/nodes/end) + +### Workflow : Noeud de variable personnalisée + +Les variables peuvent être déclarées dans le workflow ou affecter des valeurs aux variables précédemment déclarées, généralement utilisées pour stocker des données temporaires dans le workflow. Il est adapté aux scénarios où les résultats de calcul doivent être stockés pour une utilisation ultérieure en dehors des branches (comme les boucles, le parallélisme, etc.). + +![Noeud de variable personnalisée](https://static-docs.nocobase.com/c19913f99968d987a52aaa53578a7318.png) + +Plus de détails sont disponibles dans la documentation : [Noeud de variable personnalisée](/handbook/workflow-variable) + +### Workflow: Intercepteur de requêtes + +Le plugin **intercepteur de requêtes** fournit un mécanisme pour intercepter les opérations sur les formulaires, où l'événement d'interception est déclenché après que l'opération de formulaire correspondante ait été soumise, mais avant qu'elle ne soit traitée. Si un nœud **"Fin de processus"** est exécuté dans le flux de processus suivant après le déclenchement, ou si d'autres nœuds échouent à s'exécuter (erreurs ou autres exécutions incomplètes), l'opération de formulaire sera interceptée. Sinon, l'opération prévue sera exécutée normalement. Cela peut être utilisé pour la validation métier ou les vérifications logiques pour approuver ou intercepter les opérations de création, mise à jour et suppression soumises par le client. + +![Intercepteur de requêtes](https://static-docs.nocobase.com/3f3991aaf9d73b8c2f7c179e7702d16b.png) + +Plus de détails sont disponibles dans la documentation : [Intercepteur de requêtes](/handbook/workflow-request-interceptor) + +### Workflow: Nœud de message de réponse + +Le nœud **message de réponse** est utilisé pour fournir un retour au client avec des messages personnalisés dans des types de workflows spécifiques (comme l'interception de requêtes et les événements de formulaire). + +**Configuration du nœud** + +![Configuration du nœud](https://static-docs.nocobase.com/4376843af541ef6a08696e074cb6cd07.png) + +**Message de notification** + +![Message de notification](https://static-docs.nocobase.com/051f12855bd0ce74b22de191b8b87cf5.png) + +Plus de détails sont disponibles dans la documentation : [Nœud de message de réponse](/handbook/workflow-response-message) + +## Changements incompatibles + +### API avec des noms conflictuels + +Dans ce changement du noyau, certaines nouvelles API versionnées sont en conflit avec les anciens noms des API. Ces anciennes API conflictuelles seront conservées dans cette version mais auront toutes le suffixe `_deprecated`. + +| API d'origine | API obsolète | Nouvelle API | +| ----------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| CollectionProvider | CollectionProvider_deprecated | [CollectionProvider](https://client.docs.nocobase.com/core/data-source/collection-provider) | +| useCollection | useCollection_deprecated | [useCollection](https://client.docs.nocobase.com/core/data-source/collection-provider#hooks) | +| useCollectionField | useCollectionField_deprecated | [useCollectionField](https://client.docs.nocobase.com/core/data-source/collection-field#hooks) | +| useCollectionManager | useCollectionManager_deprecated | [useCollectionManager](https://client.docs.nocobase.com/core/data-source/collection-manager-provider#hooks) | +| useContext(CollectionManagerContext) | useCollectionManager_deprecated | [useCollectionManager](https://client.docs.nocobase.com/core/data-source/collection-manager-provider#hooks) | + +Si vous utilisez les API ci-dessus, vous avez deux options pour effectuer la modification : + +- **Remplacement simple** : Remplacez l'API d'origine par celle suffixée avec `_deprecated`, par exemple, remplacez `useCollection()` par `useRecord_deprecated()`. +- **Utilisez la nouvelle API** en suivant la nouvelle documentation : Bien que les noms des nouvelles API soient les mêmes que ceux des anciennes API, il existe des différences dans les paramètres et les valeurs de retour. Vous devez vous référer à la nouvelle documentation pour ajuster le code correspondant. + +### Autres ajustements d'API + +- `registerTemplate()` a été remplacé par `app.dataSourceManager.addCollectionTemplates()` +- `registerField()` a été remplacé par `app.dataSourceManager.addFieldInterfaces()` +- `registerGroup()` a été remplacé par `app.dataSourceManager.addFieldInterfaceGroups()` +- `useContext(CollectionManagerContext)` a été remplacé par `useCollectionManager_deprecated()` +- Pour étendre les collections, utilisez `ExtendCollectionsProvider` +- `RecordProvider` nécessite maintenant de passer explicitement le paramètre parent lorsqu'il est nécessaire. + +### Exemples de changements + +### Extension du modèle de collection + +#### Définition + +Auparavant défini en tant qu'objet, il doit maintenant être modifié pour être une classe. Par exemple : + +Avant : + +```typescript +import { ICollectionTemplate } from '@nocobase/client'; + +const calendar: ICollectionTemplate = { + name: 'calendar', + title: 'Calendar collection', + order: 2, + color: 'orange', + // ... +} +``` + +Maintenant : + +```typescript +import { CollectionTemplate } from '@nocobase/client'; + +class CalendarCollectionTemplate extends CollectionTemplate { + name = 'calendar'; + title = 'Calendar collection'; + order = 2; + color = 'orange'; +} +``` + +Les propriétés de l'objet d'origine deviennent des membres de la classe. + +#### Enregistrement + +Auparavant enregistré via `registerTemplate`, il doit maintenant être enregistré via `dataSourceManager.addCollectionTemplates` du plugin. Par exemple : + +Avant : + +```typescript +import { registerTemplate } from '@nocobase/client'; +import { calendar } from './calendar' + +registerTemplate('calendar', calendar); +``` + +Maintenant : + +```typescript +import { Plugin } from '@nocobase/client'; +import { CalendarCollectionTemplate } from './calendar' + +export class CalendarPluginClient extends Plugin { + async load() { + this.app.dataSourceManager.addCollectionTemplates([CalendarCollectionTemplate]); + } +} +``` + +### Extension de l'interface de champ + +#### Définition + +Auparavant définie comme un objet, elle doit maintenant être modifiée pour être une classe. Par exemple : + +Avant : + +```typescript +import { IField } from '@nocobase/client'; + +const attachment: IField = { + name: 'attachment', + type: 'object', + group: 'media', + title: 'Attachment', + // ... +} +``` + +Maintenant : + +```typescript +import { CollectionFieldInterface } from '@nocobase/client'; + +class AttachmentFieldInterface extends CollectionFieldInterface { + name = 'attachment'; + type = 'object'; + group = 'media'; + title = 'Attachment'; + // ... +} +``` + +Les propriétés de l'objet d'origine deviennent des membres de la classe. + +#### Enregistrement + +Auparavant enregistré via `registerField`, il doit maintenant être enregistré via `dataSourceManager.addFieldInterfaces` du plugin et ne nécessite plus de passer `CollectionManagerProvider` à nouveau. Par exemple : + +Avant : + +```diff +import { registerField } from '@nocobase/client'; +import { attachment } from './attachment' + +- registerField(attachment.group, 'attachment', attachment); + +export const FileManagerProvider: FC = (props) => { + return ( +- <CollectionManagerProvider interfaces={{ attachment }}> + <SchemaComponentOptions scope={hooks} components={{ UploadActionInitializer }}> + {props.children} + </SchemaComponentOptions> +- </CollectionManagerProvider> + ); +}; +``` + +Maintenant : + +```typescript +import { Plugin } from '@nocobase/client'; +import { AttachmentFieldInterface } from './attachment' + +export class FilePlugin extends Plugin { + async load() { + this.app.dataSourceManager.addFieldInterfaces([AttachmentFieldInterface]); + } +} +``` + +### Extension de l'interface de groupe de champs + +Auparavant enregistré via `registerGroup`, il doit maintenant être enregistré via `dataSourceManager.addFieldInterfaceGroups` du plugin. Par exemple : + +```diff +- import { registerGroup, Plugin } from '@nocobase/client'; ++ import { Plugin } from '@nocobase/client'; + +- registerGroup('map', { +- label: 'Map-based geometry', +- order: 10 +- }) + +export class MapPlugin extends Plugin { + async load() { ++ this.app.dataSourceManager.addFieldInterfaceGroups({ ++ map: { ++ label: generateNTemplate('Map-based geometry'), ++ order: 51, ++ }, ++ }); + } +} +``` + +### `useContext(CollectionManagerContext)` modifié en `useCollectionManager_deprecated()` + +```diff +- const ctx = useContext(CollectionManagerContext); ++ const ctx = useCollectionManager_deprecated(); +``` + +### Étendre les collections, utiliser `ExtendCollectionsProvider` au lieu de `CollectionManagerProvider` + +```diff +const Demo = () => { +- <CollectionManagerProvider collections={[apiKeysCollection]}> ++ <ExtendCollectionsProvider collections={[apiKeysCollection]}> +... +- </CollectionManagerProvider> ++ </ExtendCollectionsProvider> +} +``` + +### Changements dans RecordProvider + +Auparavant, lorsque la propriété parent n'était pas passée, la valeur du dernier `RecordProvider` était automatiquement récupérée comme parent. Maintenant, le parent doit être explicitement passé, et lorsque le parent n'est pas passé, la valeur du parent sera `undefined`. + +```diff +- <RecordProvider record={recordData}> ++ <RecordProvider record={recordData} parent={parentRecordData}> +... +</RecordProvider> +``` + +Si vous n'avez pas de compatibilité historique, vous pouvez également utiliser directement `CollectionRecordProvider` pour remplacer. + +```diff +- <RecordProvider record={recordData}> ++ <CollectionRecordProvider record={recordData} parent={parentRecordData}> +... +- </RecordProvider> ++ </CollectionRecordProvider> +``` + +:::warning{title="Différence entre RecordProvider et CollectionRecordProvider"} +- `RecordProvider` est obsolète et sera supprimé dans le futur. +- `RecordProvider` utilise l'ancien `RecordContext`, tandis que `CollectionRecordProvider` ne le fait pas. +::: diff --git a/docs/fr-FR/welcome/release/v0210-changelog/index.md b/docs/fr-FR/welcome/release/v0210-changelog/index.md new file mode 100644 index 000000000..10a3aff8d --- /dev/null +++ b/docs/fr-FR/welcome/release/v0210-changelog/index.md @@ -0,0 +1,184 @@ +## v0.21 : 2024-03-29 + +### Annonce + +![v1.0](https://static-docs.nocobase.com/img_v3_029o_3dd91ba0-bb96-4315-a273-208f06d432fg.png) + +## Nouvelles fonctionnalités + +### Prise en charge de plusieurs sources de données pour les graphiques + +![20240407222304](https://static-docs.nocobase.com/20240407222304.png) + +Avec cette version, vous pouvez maintenant intégrer plusieurs sources de données dans vos graphiques pour une visualisation de données plus riche. Cela vous permet d'afficher et d'analyser les données de différentes sources dans un seul graphique. + +Pour plus de détails, consultez la [documentation sur la visualisation des données](/handbook/data-visualization). + +### Prise en charge de plusieurs sources de données pour les flux de travail + +![20240407222523](https://static-docs.nocobase.com/20240407222523.png) + +Les flux de travail peuvent maintenant intégrer plusieurs sources de données de manière transparente, ce qui vous permet de déclencher des événements ou des actions en fonction des données de différentes sources. Cela améliore la flexibilité et la scalabilité de l'automatisation des flux de travail. + +Pour plus d'informations, consultez la [documentation sur les flux de travail](/handbook/workflow). + +### Optimisation des événements de déclenchement des flux de travail + +Nous avons apporté plusieurs améliorations aux événements de déclenchement des flux de travail. Les noms de certains déclencheurs ont été modifiés pour plus de clarté et de cohérence : + +| Nom original | Nouveau nom | +| ------------------------- | ---------------------- | +| Événements de formulaire, événements d'opération | Événements post-opération | +| Tâches planifiées | Événements planifiés | +| Intercepteurs de requêtes | Événements pré-opération | +| Approbation | Événements d'approbation | + +#### Événements post-opération + +Les événements post-opération sont désormais plus personnalisables et peuvent être déclenchés après des actions spécifiques dans les flux de travail. Ces événements vous permettent d'affiner le comportement de vos flux de travail. + +![20240407222652](https://static-docs.nocobase.com/20240407222652.png) + +Pour plus de détails, consultez la [documentation sur les événements post-opération](/handbook/workflow-action-trigger). + +#### Événements pré-opération + +Les événements pré-opération vous permettent d'intercepter et de modifier les données ou les opérations avant qu'elles ne soient exécutées. Cette fonctionnalité est utile pour mettre en place des validations, des conditions ou une logique de prétraitement. + +![20240407222834](https://static-docs.nocobase.com/20240407222834.png) + +Pour plus d'informations, consultez la [documentation sur les événements pré-opération](/handbook/workflow-request-interceptor). + +### Plugin de marque personnalisée + +![20240407222949](https://static-docs.nocobase.com/20240407222949.png) + +Nous avons ajouté un support pour un plugin de **marque personnalisée**. Cela vous permet d’adapter l’apparence visuelle et la marque de votre instance NocoBase pour correspondre à l’identité de votre organisation. + +Pour plus de détails, consultez la [documentation sur la marque personnalisée](/handbook/custom-brand). + +### Prise en charge du champ Nanoid + +![20240407223221](https://static-docs.nocobase.com/20240407223221.png) + +Le type de champ **Nanoid** a été introduit, vous permettant de générer des identifiants plus courts et plus sécurisés pour vos collections. Cela peut être utilisé comme alternative aux identifiants auto-incrémentés traditionnels. + +Pour plus d'informations, consultez la [documentation sur le champ Nanoid](/handbook/data-modeling/collection-fields/advanced/nanoid). + +### Prise en charge du champ UUID + +![20240407223431](https://static-docs.nocobase.com/20240407223431.png) + +Les champs **UUID** (Identifiant unique universel) sont désormais pris en charge, vous permettant de générer des identifiants uniques à l'échelle mondiale pour vos enregistrements. Cela est utile pour les systèmes qui doivent garantir des identifiants uniques dans des systèmes distribués. + +Pour plus de détails, consultez la [documentation sur le champ UUID](/handbook/data-modeling/collection-fields/advanced/uuid). + +### Support pour le champ de timestamp Unix + +![20240407223512](https://static-docs.nocobase.com/20240407223512.png) + +Le champ **timestamp Unix** a été ajouté pour faciliter l'utilisation des dates et heures sous forme de nombres entiers représentant le nombre de secondes écoulées depuis le 1er janvier 1970. + +Pour plus d'informations, consultez la [documentation sur le champ de timestamp Unix](/handbook/data-modeling/collection-fields/datetime/unix-timestamp). + +### Le champ de type nombre prend en charge la configuration de formatage + +![20240407223736_rec_](https://static-docs.nocobase.com/20240407223736_rec_.gif) + +Les champs de type **nombre** peuvent désormais être formatés en utilisant des configurations spécifiques, par exemple pour ajouter des séparateurs de milliers, des décimales ou des préfixes. Cela permet d'afficher des valeurs numériques de manière plus lisible. + +Pour plus d'informations, consultez la [documentation sur la configuration du champ / Paramètres des propriétés spécifiques / Composant Nombre](/handbook/ui/fields/field-settings/input-number). + +### Prise en charge du déploiement sous sous-chemin + +La variable d'environnement `APP_PUBLIC_PATH` a été ajoutée pour prendre en charge le déploiement sous un sous-chemin. Par exemple : + +```bash +APP_PUBLIC_PATH=/nocobase/ +``` + +Cela vous permet d'accéder à l'application localement via l'URL suivante : +[http://localhost:13000/nocobase/](http://localhost:13000/nocobase/) + +Exemple de proxy Nginx : + +```bash +server { + listen 80; + server_name your_domain.com; # Remplacez your_domain.com par votre domaine + + location /nocobase/ { + proxy_pass http://127.0.0.1:13000/nocobase/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + } +} +``` + +Vous pouvez désormais y accéder via [http://your_domain.com/nocobase/](http://your_domain.com/nocobase/). + +### Optimisation des performances des blocs + +#### Prise en charge de l'effet écran de squelette + +Les **cartes de blocs** peuvent désormais afficher un effet d'écran de squelette pour améliorer l'expérience utilisateur en indiquant le chargement de données. + +Cartes de Kanban + +![20240407224811](https://static-docs.nocobase.com/20240407224811.png) + +Cellules de tableau + +![20240407230028](https://static-docs.nocobase.com/20240407230028.png) + +#### Traitement distribué de la configuration des blocs + +Auparavant, toute modification de Schéma sur la page entière entraînait le re-rendu de toute la page. Désormais, chaque Schéma de bloc est indépendant, ce qui améliore les performances. + +```tsx | pure +<SchemaComponent distributed schema={} /> +``` + +Le composant **Grid** prend également en charge le traitement distribué. + +```tsx | pure +{ + 'x-component': 'Grid', + 'x-component-props': { + distributed: true, + }, +} +``` + +## Changements incompatibles + +### Divers `useProps` du Schéma UI remplacés par `x-use-decorator-props` et `x-use-component-props` + +Pour **useProps**, au lieu d'utiliser `x-component-props` avec la clé `useProps`, vous utilisez maintenant `x-use-component-props`. Voici le diff : + +```diff +{ + "x-component": "Input", ++ "x-use-component-props": "useInputProps", +- "x-component-props": { +- useProps: "{{ useInputProps }}" +- } +} +``` + +Pour **useParams** et **useSourceId**, au lieu d'utiliser `x-decorator-props` avec les clés pour `useParams` et `useSourceId`, vous utilisez maintenant `x-use-decorator-props` avec une seule clé. Voici le diff : + +```diff +{ + "x-decorator": "TableBlockProvider", ++ "x-use-decorator-props": "useDecoratorProps", +- "x-decorator-props": { +- useParams: "{{ useParams }}", +- useSourceId: "{{ useSourceId }}" +- } +} +``` + +Pour plus d'informations sur `x-use-decorator-props` et la distinction entre les propriétés statiques et dynamiques, consultez : [Propriétés statiques et dynamiques](https://client.docs.nocobase.com/core/data-block/data-block-provider#%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7%E5%92%8C%E5%8A%A8%E6%80%81%E5%B1%9E%E6%80%A7). diff --git a/docs/fr-FR/welcome/release/v08-1-collection-templates/v08-1-collection-templates.jpg b/docs/fr-FR/welcome/release/v08-1-collection-templates/v08-1-collection-templates.jpg new file mode 100644 index 000000000..dd0a99af8 Binary files /dev/null and b/docs/fr-FR/welcome/release/v08-1-collection-templates/v08-1-collection-templates.jpg differ diff --git a/docs/fr-FR/welcome/release/v08-changelog/pm-flow.svg b/docs/fr-FR/welcome/release/v08-changelog/pm-flow.svg new file mode 100644 index 000000000..d15cf800c --- /dev/null +++ b/docs/fr-FR/welcome/release/v08-changelog/pm-flow.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="833px" height="633px" viewBox="-0.5 -0.5 833 633"><defs/><g><path d="M 276 176 L 275.84 176 L 275.76 184 L 275.77 192 L 276.22 200 L 275.87 208 L 276 216 L 276 215.97 L 286 216.08 L 296 215.53 L 306 216.69 L 316 216.6 L 326 215.28 L 336 215.48 L 346 215.77 L 356 216.18 L 366 216.11 L 376 215.91 L 386 216.44 L 396 215.95 L 406 216.44 L 416 216.73 L 426 216.59 L 436 215.66 L 446 216.68 L 456 215.37 L 466 216.06 L 476 216 L 475.77 216 L 476.14 222.73 L 475.94 229.45 L 475.79 236.18 L 475.93 242.91 L 476 249.63" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 476 254.88 L 476.21 254.98 L 475.29 253.48 L 474.56 252.06 L 473.75 250.61 L 473.24 249.3 L 472.5 247.88 L 472.44 247.77 L 473.31 248.45 L 473.88 248.55 L 474.71 249.15 L 475.3 249.29 L 476 249.63 L 475.99 249.62 L 476.69 249.27 L 477.36 248.84 L 478 248.38 L 478.72 248.08 L 479.5 247.88 L 479.33 247.8 L 478.72 249.24 L 478.08 250.67 L 477.59 252.18 L 476.51 253.39 L 476 254.88 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 276 116 L 276.59 116 L 276.49 106 L 275.52 96 L 276.4 86 L 276.27 76 L 276.35 66 L 276.3 56 L 276 46 L 276 46.14 L 286.28 46.66 L 296.56 46.04 L 306.84 45.63 L 317.12 45.6 L 327.4 45.34 L 337.68 45.84 L 347.96 46.15 L 358.24 45.59 L 368.51 45.5 L 378.79 46.44 L 389.07 45.7 L 399.35 46.18 L 409.63 46" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 414.88 46 L 414.94 46.12 L 413.59 46.92 L 412.07 47.37 L 410.69 48.12 L 409.24 48.71 L 407.88 49.5 L 407.82 49.47 L 408.16 48.77 L 408.6 48.11 L 409.12 47.5 L 409.28 46.7 L 409.63 46 L 409.46 45.91 L 409.15 45.23 L 409.07 44.67 L 408.49 43.85 L 408.18 43.17 L 407.88 42.5 L 407.98 42.7 L 409.33 43.3 L 410.61 43.76 L 412.08 44.59 L 413.56 45.45 L 414.88 46 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 216 116 L 216 115.51 L 226 115.63 L 236 115.42 L 246 116.26 L 256 116.68 L 266 116.12 L 276 115.71 L 286 115.53 L 296 116.37 L 306 116.4 L 316 116.13 L 326 116.63 L 336 116 L 336.17 116 L 335.29 126 L 335.75 136 L 336.65 146 L 335.89 156 L 335.8 166 L 336 176 L 336 175.59 L 326 175.87 L 316 176.04 L 306 176.37 L 296 176.09 L 286 175.33 L 276 175.72 L 266 176.38 L 256 175.29 L 246 175.39 L 236 175.98 L 226 175.28 L 216 176 L 215.48 176 L 215.81 166 L 216.36 156 L 216.48 146 L 215.94 136 L 216.67 126 L 216 116 L 216 116 Z Z" fill="#e1d5e7" stroke="#9673a6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 146px; margin-left: 217px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Local</div></div></div></foreignObject></g><path d="M 136 146 L 136 146.64 L 146.52 145.54 L 157.04 146.39 L 167.56 145.32 L 178.08 146.46 L 188.59 145.66 L 199.11 146.59 L 209.63 146" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 214.88 146 L 214.83 145.91 L 213.53 146.8 L 212.05 147.34 L 210.59 147.92 L 209.21 148.66 L 207.88 149.5 L 207.92 149.52 L 208.44 148.91 L 208.4 148.01 L 208.81 147.34 L 209.39 146.76 L 209.63 146 L 209.46 145.91 L 209.37 145.34 L 209.13 144.7 L 208.74 143.98 L 208.3 143.24 L 207.88 142.5 L 207.78 142.29 L 209.19 143.02 L 210.64 143.81 L 212.02 144.47 L 213.51 145.35 L 214.88 146 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 16 116 L 16 116.09 L 26 115.82 L 36 115.28 L 46 116.04 L 56 116.1 L 66 116.49 L 76 116.23 L 86 115.59 L 96 116.57 L 106 116.59 L 116 116.49 L 126 115.49 L 136 116 L 136.72 116 L 135.49 126 L 136.4 136 L 136.02 146 L 136.46 156 L 135.69 166 L 136 176 L 136 176.72 L 126 176.52 L 116 176.68 L 106 176.63 L 96 176.19 L 86 175.79 L 76 176.02 L 66 175.42 L 56 176.11 L 46 176.15 L 36 175.51 L 26 175.45 L 16 176 L 15.33 176 L 15.4 166 L 16.1 156 L 16.67 146 L 15.95 136 L 16.45 126 L 16 116 L 16 116 Z Z" fill="#dae8fc" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 146px; margin-left: 17px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">pm.create</div></div></div></foreignObject></g><path d="M 476 176 L 475.68 176 L 475.91 186.52 L 475.86 197.04 L 475.46 207.56 L 475.75 218.08 L 475.91 228.59 L 475.52 239.11 L 476 249.63" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 476 254.88 L 476.02 254.89 L 475.46 253.56 L 474.41 251.99 L 474.05 250.76 L 473.41 249.39 L 472.5 247.88 L 472.42 247.72 L 473.14 248.11 L 473.85 248.48 L 474.6 248.94 L 475.35 249.39 L 476 249.63 L 475.9 249.44 L 476.59 249.06 L 477.29 248.72 L 478.04 248.46 L 478.71 248.06 L 479.5 247.88 L 479.7 247.98 L 478.64 249.2 L 478.28 250.77 L 477.53 252.15 L 476.63 253.45 L 476 254.88 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 416 116 L 416 115.72 L 426 115.43 L 436 115.98 L 446 115.58 L 456 116.19 L 466 115.69 L 476 116.39 L 486 115.61 L 496 116.44 L 506 116.64 L 516 116.4 L 526 115.32 L 536 116 L 536.44 116 L 536.07 126 L 536.25 136 L 536.48 146 L 535.52 156 L 535.7 166 L 536 176 L 536 175.77 L 526 176.05 L 516 176.05 L 506 176.66 L 496 176.01 L 486 175.31 L 476 176.52 L 466 175.54 L 456 176.56 L 446 175.25 L 436 176.66 L 426 175.57 L 416 176 L 416.62 176 L 415.52 166 L 416.5 156 L 416.01 146 L 416.07 136 L 415.38 126 L 416 116 L 416 116 Z Z" fill="#e1d5e7" stroke="#9673a6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 146px; margin-left: 417px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Marketplace</div></div></div></foreignObject></g><path d="M 476 76 L 476.09 76 L 476.2 82.73 L 476.07 89.45 L 475.92 96.18 L 475.93 102.91 L 476 109.63" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 476 114.88 L 475.85 114.81 L 475.15 113.41 L 474.76 112.16 L 474.07 110.77 L 472.99 109.18 L 472.5 107.88 L 472.56 108.01 L 473.3 108.44 L 473.85 108.48 L 474.68 109.1 L 475.3 109.29 L 476 109.63 L 475.94 109.51 L 476.63 109.14 L 477.33 108.79 L 478.2 108.79 L 478.78 108.19 L 479.5 107.88 L 479.65 107.96 L 478.89 109.33 L 477.9 110.58 L 477.33 112.05 L 476.88 113.57 L 476 114.88 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 536 46 L 536 46.14 L 546 45.36 L 556 46.35 L 566 45.61 L 576 46.27 L 586 45.68 L 596 45.46 L 606 46.73 L 616 46.33 L 626 45.85 L 636 46.71 L 646 46.04 L 656 45.52 L 666 46.19 L 676 46.01 L 686 45.45 L 696 46 L 695.97 46 L 695.86 56.61 L 696.51 67.21 L 696.62 77.82 L 696.53 88.42 L 695.35 99.03 L 696 109.63" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 696 114.88 L 695.85 114.81 L 695.08 113.37 L 694.74 112.15 L 693.94 110.7 L 693.05 109.21 L 692.5 107.88 L 692.4 107.68 L 693.21 108.25 L 693.94 108.67 L 694.51 108.75 L 695.4 109.49 L 696 109.63 L 695.95 109.52 L 696.64 109.16 L 697.42 108.97 L 698 108.37 L 698.78 108.19 L 699.5 107.88 L 699.71 107.98 L 698.76 109.26 L 698.04 110.65 L 697.6 112.18 L 696.55 113.41 L 696 114.88 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 416 16 L 416 16.21 L 426 15.63 L 436 15.67 L 446 15.6 L 456 15.94 L 466 16.62 L 476 16.18 L 486 15.44 L 496 16.27 L 506 16.21 L 516 16.47 L 526 15.47 L 536 16 L 535.33 16 L 536.37 26 L 535.62 36 L 536.45 46 L 535.71 56 L 535.4 66 L 536 76 L 536 76.41 L 526 75.29 L 516 76.7 L 506 75.75 L 496 75.37 L 486 75.34 L 476 75.82 L 466 76.12 L 456 75.36 L 446 76.66 L 436 76.6 L 426 75.97 L 416 76 L 416.02 76 L 416.18 66 L 416.44 56 L 415.96 46 L 416.27 36 L 415.54 26 L 416 16 L 416 16 Z Z" fill="#dae8fc" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 46px; margin-left: 417px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">pm.publish</div></div></div></foreignObject></g><path d="M 696 176 L 696.19 176 L 695.76 184 L 696.15 192 L 695.97 200 L 695.85 208 L 696 216 L 696 216 L 686 216.03 L 676 216.08 L 666 215.43 L 656 216.43 L 646 215.43 L 636 216.22 L 626 216.01 L 616 216.47 L 606 216.33 L 596 215.72 L 586 215.43 L 576 216.63 L 566 216.58 L 556 216.12 L 546 215.65 L 536 216.2 L 526 216.7 L 516 215.73 L 506 215.88 L 496 216.39 L 486 216.01 L 476 216 L 476.16 216 L 476 222.73 L 476.1 229.45 L 476.07 236.18 L 475.75 242.91 L 476 249.63" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 476 254.88 L 475.86 254.81 L 475.36 253.51 L 474.76 252.16 L 473.69 250.58 L 473.4 249.38 L 472.5 247.88 L 472.43 247.74 L 473.25 248.33 L 473.86 248.5 L 474.63 248.99 L 475.39 249.45 L 476 249.63 L 475.98 249.59 L 476.8 249.48 L 477.37 248.87 L 478.04 248.46 L 478.83 248.3 L 479.5 247.88 L 479.35 247.81 L 478.65 249.21 L 478.29 250.78 L 477.33 252.05 L 476.76 253.51 L 476 254.88 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 636 116 L 636 116.75 L 646 115.63 L 656 115.34 L 666 116.68 L 676 115.27 L 686 116.44 L 696 116.44 L 706 116.11 L 716 116.47 L 726 116.52 L 736 116.59 L 746 115.67 L 756 116 L 756.61 116 L 756.45 126 L 756.02 136 L 755.86 146 L 755.43 156 L 755.31 166 L 756 176 L 756 175.32 L 746 176.21 L 736 175.38 L 726 176.2 L 716 176.08 L 706 175.88 L 696 176.68 L 686 175.65 L 676 176.07 L 666 176.57 L 656 175.35 L 646 175.5 L 636 176 L 635.89 176 L 636.61 166 L 635.78 156 L 635.59 146 L 636.26 136 L 635.71 126 L 636 116 L 636 116 Z Z" fill="#e1d5e7" stroke="#9673a6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 146px; margin-left: 637px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">NPM registry</div></div></div></foreignObject></g><path d="M 536 286 L 536 285.93 L 546.24 285.82 L 556.48 285.29 L 566.73 286.55 L 576.97 285.36 L 587.21 286.49 L 597.45 286.73 L 607.69 285.67 L 617.94 286.02 L 628.18 286.41 L 638.42 285.52 L 648.66 285.82 L 658.91 286.54 L 669.15 285.62 L 679.39 286.19 L 689.63 286" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 694.88 286 L 694.93 286.1 L 693.42 286.58 L 692.18 287.6 L 690.78 288.3 L 689.33 288.89 L 687.88 289.5 L 687.92 289.52 L 688.43 288.9 L 688.8 288.21 L 688.77 287.32 L 689.22 286.67 L 689.63 286 L 689.8 286.08 L 689.09 285.2 L 689.02 284.64 L 688.55 283.88 L 688.02 283.1 L 687.88 282.5 L 687.81 282.36 L 689.38 283.39 L 690.67 283.87 L 691.99 284.42 L 693.41 285.16 L 694.88 286 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 286px; margin-left: 616px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">Extracting client files</div></div></div></foreignObject></g><path d="M 416 256 L 416 256.21 L 426 256.64 L 436 256.56 L 446 256.49 L 456 255.37 L 466 256.36 L 476 256.6 L 486 256.35 L 496 255.57 L 506 256.06 L 516 256.36 L 526 255.84 L 536 256 L 536.53 256 L 536.31 266 L 536.7 276 L 535.45 286 L 536.02 296 L 536.69 306 L 536 316 L 536 316.3 L 526 316.7 L 516 316.42 L 506 315.29 L 496 315.98 L 486 315.48 L 476 316.39 L 466 315.67 L 456 316.72 L 446 315.52 L 436 316.5 L 426 315.78 L 416 316 L 415.9 316 L 415.52 306 L 416.42 296 L 416.2 286 L 415.43 276 L 415.74 266 L 416 256 L 416 256 Z Z" fill="#dae8fc" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 286px; margin-left: 417px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">pm.add</div></div></div></foreignObject></g><path d="M 696 256 L 696 255.44 L 706 255.58 L 716 255.54 L 726 256.11 L 736 256 L 746 255.25 L 756 256.35 L 766 255.53 L 776 255.49 L 786 255.8 L 796 255.9 L 806 256.24 L 816 256 L 816.3 256 L 815.88 266 L 815.75 276 L 816.33 286 L 815.28 296 L 815.5 306 L 816 316 L 816 315.78 L 806 316.17 L 796 315.31 L 786 315.7 L 776 316.48 L 766 315.66 L 756 316.68 L 746 316.17 L 736 316.38 L 726 315.95 L 716 315.6 L 706 316.57 L 696 316 L 696.67 316 L 695.28 306 L 696.61 296 L 695.54 286 L 696.23 276 L 696.59 266 L 696 256 L 696 256 Z Z" fill="#ffe6cc" stroke="#d79b00" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 286px; margin-left: 697px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">app/client plugins</div></div></div></foreignObject></g><path d="M 476 316 L 475.97 316 L 475.76 322.73 L 475.86 329.45 L 476.15 336.18 L 475.9 342.91 L 476 349.63" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 476 354.88 L 476.1 354.93 L 475.51 353.59 L 474.72 352.14 L 474.12 350.79 L 473.41 349.39 L 472.5 347.88 L 472.59 348.05 L 473.18 348.19 L 473.91 348.6 L 474.49 348.71 L 475.27 349.23 L 476 349.63 L 476.07 349.77 L 476.64 349.17 L 477.35 348.83 L 478.08 348.53 L 478.85 348.33 L 479.5 347.88 L 479.36 347.81 L 478.73 349.25 L 478.18 350.72 L 477.59 352.18 L 476.92 353.59 L 476 354.88 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 476 416 L 476.07 416 L 475.96 422.73 L 475.92 429.45 L 475.99 436.18 L 475.89 442.91 L 476 449.63" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 476 454.88 L 476.06 454.91 L 475.25 453.46 L 474.69 452.13 L 473.85 450.66 L 473.21 449.29 L 472.5 447.88 L 472.53 447.95 L 473.13 448.09 L 473.85 448.49 L 474.67 449.07 L 475.38 449.44 L 476 449.63 L 475.96 449.56 L 476.68 449.25 L 477.47 449.07 L 478.09 448.56 L 478.81 448.25 L 479.5 447.88 L 479.33 447.8 L 478.69 449.23 L 477.99 450.63 L 477.43 452.1 L 476.89 453.58 L 476 454.88 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 416 356 L 416 356.2 L 426 355.28 L 436 356.24 L 446 355.32 L 456 355.83 L 466 355.46 L 476 356.04 L 486 355.37 L 496 356.21 L 506 356.38 L 516 356.28 L 526 355.87 L 536 356 L 535.99 356 L 536.2 366 L 535.76 376 L 535.77 386 L 535.36 396 L 535.33 406 L 536 416 L 536 415.34 L 526 416.62 L 516 416.67 L 506 416.04 L 496 416.64 L 486 415.95 L 476 415.34 L 466 416 L 456 416.44 L 446 416.7 L 436 415.48 L 426 416.69 L 416 416 L 415.89 416 L 416.1 406 L 416.57 396 L 415.39 386 L 415.96 376 L 416.1 366 L 416 356 L 416 356 Z Z" fill="#dae8fc" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 386px; margin-left: 417px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">pm.enable</div></div></div></foreignObject></g><path d="M 476 516 L 476.19 516 L 476.25 522.73 L 475.88 529.45 L 475.88 536.18 L 476.16 542.91 L 476 549.63" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 476 554.88 L 475.99 554.88 L 475.09 553.38 L 474.56 552.06 L 474.05 550.75 L 473.31 549.34 L 472.5 547.88 L 472.52 547.91 L 473.3 548.43 L 473.93 548.65 L 474.61 548.95 L 475.31 549.3 L 476 549.63 L 475.92 549.47 L 476.68 549.23 L 477.4 548.93 L 478.02 548.42 L 478.78 548.2 L 479.5 547.88 L 479.46 547.86 L 478.96 549.36 L 478.24 550.75 L 477.35 552.06 L 476.59 553.43 L 476 554.88 Z Z" fill="#6c8ebf" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 416 456 L 416 456.62 L 426 455.28 L 436 455.99 L 446 455.29 L 456 456.54 L 466 455.74 L 476 455.65 L 486 455.76 L 496 456.41 L 506 455.76 L 516 455.69 L 526 455.78 L 536 456 L 536.33 456 L 536.19 466 L 535.85 476 L 536.34 486 L 535.58 496 L 535.64 506 L 536 516 L 536 515.51 L 526 516.66 L 516 516.12 L 506 515.97 L 496 515.37 L 486 516.22 L 476 515.71 L 466 516.46 L 456 516.52 L 446 515.87 L 436 516.72 L 426 516.36 L 416 516 L 416.48 516 L 416.44 506 L 416.72 496 L 415.76 486 L 415.75 476 L 416.38 466 L 416 456 L 416 456 Z Z" fill="#dae8fc" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 486px; margin-left: 417px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">pm.disable</div></div></div></foreignObject></g><path d="M 416 556 L 416 555.7 L 426 555.76 L 436 556.21 L 446 556.24 L 456 555.43 L 466 555.27 L 476 555.72 L 486 555.86 L 496 555.8 L 506 555.89 L 516 556.48 L 526 556.46 L 536 556 L 536.63 556 L 535.35 566 L 536.62 576 L 536.1 586 L 535.97 596 L 536.38 606 L 536 616 L 536 616.55 L 526 615.52 L 516 616.05 L 506 616.36 L 496 616.2 L 486 616.52 L 476 615.83 L 466 615.4 L 456 616.41 L 446 615.67 L 436 616.24 L 426 615.75 L 416 616 L 416.74 616 L 415.79 606 L 416.4 596 L 415.83 586 L 416.04 576 L 416.38 566 L 416 556 L 416 556 Z Z" fill="#dae8fc" stroke="#6c8ebf" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 586px; margin-left: 417px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Comic Sans MS; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">pm.remove</div></div></div></foreignObject></g></g></svg> \ No newline at end of file diff --git a/docs/fr-FR/welcome/release/v08-changelog/pm-ui.jpg b/docs/fr-FR/welcome/release/v08-changelog/pm-ui.jpg new file mode 100644 index 000000000..4c8fdd3c1 Binary files /dev/null and b/docs/fr-FR/welcome/release/v08-changelog/pm-ui.jpg differ diff --git a/docs/fr-FR/welcome/release/v08-changelog/topright.jpg b/docs/fr-FR/welcome/release/v08-changelog/topright.jpg new file mode 100644 index 000000000..8ce510973 Binary files /dev/null and b/docs/fr-FR/welcome/release/v08-changelog/topright.jpg differ diff --git a/docs/fr-FR/welcome/release/v1001-changelog.md b/docs/fr-FR/welcome/release/v1001-changelog.md new file mode 100644 index 000000000..d711ac3f5 --- /dev/null +++ b/docs/fr-FR/welcome/release/v1001-changelog.md @@ -0,0 +1,367 @@ +# v1.0 : 2024-04-28 + +## Milestone v1.0 + +Après 3 ans de développement, NocoBase atteint sa première mise à jour majeure, passant de la version 0.x à la version 1.0. Cela marque une étape importante dans l'évolution du projet. + +- **Phase 0.x** : L'API principale et les fonctionnalités ont subi de fréquents changements, chaque nouvelle version pouvant introduire des changements incompatibles. +- **Phase 1.x** : L'API principale a été stabilisée, et NocoBase se concentrera désormais sur l'ajout de nouveaux plugins, l'optimisation de la sécurité et l'amélioration des performances, tout en maintenant la stabilité. + +## Nouvelles fonctionnalités + +- L'éditeur de thèmes permet désormais de configurer les marges de page et de modal, l'espacement des blocs et le rayon des coins des blocs. +- Lors de l'ajout de blocs, les collections prennent en charge le filtrage. +- Les enregistrements de relations prennent désormais en charge le tri. +- L'interactivité des visualisations de données a été améliorée. +- Prise en charge de l'ajout de blocs de graphiques sur les appareils mobiles. +- Les blocs de filtres de graphiques prennent en charge la définition du périmètre des données des champs. +- Ajout de plus de variables, [voir les détails](https://docs.nocobase.com/handbook/ui/variables). +- Les blocs de toutes les collections peuvent être ajoutés dans des popups. +- Workflows : Les événements "Post-action" peuvent être déclenchés par des boutons à l'intérieur des blocs d'association. +- Actualisation automatique des données dans le conteneur parent lorsque les données changent dans une popup. +- Améliorations significatives des performances des blocs de tableaux. +- Augmentation substantielle de la couverture des tests. + +## Nouveaux Plugins + +- **Champ : Markdown (Vditor)** + + - Permet de stocker du Markdown et de le rendre à l'aide de l'éditeur Vditor, avec prise en charge de la syntaxe Markdown courante, ainsi que l'upload d'images, de fichiers audio, etc. Il permet également un rendu instantané, où ce que vous voyez est ce que vous obtenez. + +- **Commentaires** + + - Fournit un modèle de collection et un bloc pour ajouter une fonctionnalité de commentaires à n'importe quelle collection. + +# Changelog complet + +<details> +<summary>Voir le changelog complet</summary> + +- **feat(plugin-workflow)** : actualiser la liste après la synchronisation <u>#4177</u> +- **feat(plugin-workflow)** : afficher la clé du workflow en tant que tooltip sur le titre <u>#4178</u> +- **test(plugin-workflow)** : ajouter des cas de test <u>#4199</u> +- **chore** : en-tête de contrôle de cache API <u>#4203</u> +- **feat** : charger la dépendance vditor depuis le local <u>#4190</u> +- **test** : test du séparateur de nombre dans le champ numérique <u>#4204</u> +- **fix** : le champ numérique doit prendre en charge la configuration du séparateur <u>#4197</u> +- **fix(plugin-workflow)** : améliorer l'expérience utilisateur <u>#4195</u> +- **chore** : optimiser la formulation des avertissements pour l'import et l'export <u>#4196</u> +- **refactor** : gestionnaire de collections de sources de données externes <u>#4193</u> +- **fix** : bug environnement <u>#4191</u> +- **fix** : opérateur vide avec un champ d'association <u>#4189</u> +- **chore** : ajouter un test e2e <u>#4184</u> +- **fix** : version de vditor <u>#4183</u> +- **refactor** : amélioration des locales de modèles de données de formulaire <u>#4188</u> +- **test** : ajouter des tests automatisés <u>#4098</u> +- **chore** : instance de logger pour la source de données <u>#4181</u> +- **chore** : obtenir l'instance de la base de données dans le référentiel des relations <u>#4179</u> +- **chore** : ajouter un test e2e pour les variables <u>#4152</u> +- **chore** : définir un message de débogage pour les collections <u>#4176</u> +- **chore** : champs non pris en charge dans la vue de collection <u>#4155</u> +- **feat** : ajouter le plugin-field-markdown-vditor <u>#4065</u> +- **fix** : erreur de l'action de modification en masse du formulaire acl <u>#4166</u> +- **fix** : création automatique de clé étrangère uuid dans le champ de relation <u>#4160</u> +- **fix(plugin-fm)** : corriger l'indication de taille limite confuse <u>#4153</u> +- **fix(users)** : améliorer la mise à jour du profil des utilisateurs <u>#4162</u> +- **fix(client)** : obtenir l'URL de l'API <u>#4161</u> +- **feat** : supprimer le plugin-ui-routes-storage <u>#4140</u> +- **fix** : verrouiller la version de cytoscape <u>#4158</u> +- **refactor** : prise en charge de presetFieldsDisabled dans le modèle de collection <u>#4159</u> +- **fix** : schéma de grille <u>#4157</u> +- **test** : test unitaire du client <u>#4150</u> +- **fix** : mettre à jour l'association "appartient à" où la clé cible n'est pas la clé primaire <u>#4146</u> +- **refactor** : améliorer les locales des modèles de données de formulaire <u>#4148</u> +- **fix(database)** : nom de colonne dans le champ de tableau <u>#4110</u> +- **test** : test e2e pour actualisation sur action <u>#4147</u> +- **fix(custom-request)** : prise en charge de la configuration du type de contenu <u>#4144</u> +- **chore** : déprécier la variable de l'enregistrement actuel dans le formulaire <u>#4063</u> +- **feat(Theme)** : ajout de quelques tokens <u>#4137</u> +- **fix(client)** : correction de certains avertissements <u>#4143</u> +- **style** : amélioration du style de la colonne d'action du tableau <u>#4138</u> +- **fix** : amélioration du style de la barre d'action <u>#4123</u> +- **chore** : message d'avertissement en cas de conflit de suppression <u>#4141</u> +- **fix(plugin-workflow-manual)** : permettre de passer un noeud lorsque aucun assignataire n'est défini <u>#4139</u> +- **chore** : API du gestionnaire de sources de données <u>#4124</u> +- **fix(plugin-workflow-manual)** : corriger le bug de l'analyse des assignataires <u>#4125</u> +- **fix** : charger un champ d'association dans la collection <u>#4122</u> +- **perf** : supprimer toute animation Skeleton <u>#4113</u> +- **test** : ajout d'un test e2e <u>#4121</u> +- **chore(data-vi)** : ajustement de l'API <u>#4116</u> +- **fix** : déclencheur de l'événement programmé <u>#4114</u> +- **feat(plugin-workflow)** : ajouter un vérificateur pour la distribution à intervalles <u>#4119</u> +- **feat** : ajouter le filtreOtherRecordsCollection pour DataBlockInitializer <u>#4117</u> +- **refactor** : optimisation du champ de collection <u>#4111</u> +- **fix** : améliorer la migration des champs triés <u>#4112</u> +- **fix** : composant de champ <u>#4102</u> +- **fix** : ajouter un mode d'ajout au sélecteur d'association <u>#4108</u> +- **fix** : options de cibles createdBy et updatedBy <u>#4109</u> +- **fix(linkage-rule)** : la règle de liaison prend désormais en charge les conditions vides <u>#4103</u> +- **fix** : ajouter SanitizedCollectionProvider <u>#4100</u> +- **fix** : erreur dans la cible de la collection en arbre <u>#4105</u> +- **fix** : ajouter ClearCollectionFieldContext <u>#4101</u> +- **feat** : améliorer le bloc de formulaire <u>#4099</u> +- **chore** : migrer les options triables vers le champ de tri <u>#4011</u> +- **feat** : prise en charge de l'option de tri dans les ajouts <u>#4056</u> +- **feat(data-vi)** : permet aux graphiques en secteurs d'accepter des nombres négatifs, corrige T-4075 <u>#4094</u> +- **fix(data-vi)** : le nombre devient une chaîne après la transformation de précision <u>#4092</u> +- **fix** : encodage des paramètres d'URL <u>#4055</u> +- **test(plugin-workflow)** : ajouter des cas de test pour le déclenchement en double d'un workflow programmé <u>#3817</u> +- **perf(LinkageRules)** : résoudre les problèmes de décalage <u>#4090</u> +- **fix(subTable)** : ne pas afficher l'option Ajouter de nouvelles données <u>#4086</u> +- **fix** : champs manquants <u>#4083</u> +- **fix** : erreur de pagination dans la sélection du tableau <u>#4078</u> +- **fix** : réinitialiser la page lors de la définition du périmètre de données du bloc <u>#4081</u> +- **fix** : rôle de la liste de demande personnalisée <u>#4074</u> +- **fix** : analyse de la semaine ISO <u>#4068</u> +- **fix(sourceId)** : éviter les erreurs <u>#4077</u> +- **fix(sql-collection)** : impossible de sélectionner l'interface lors de la définition des champs <u>#4079</u> +- **fix** : chargement avec un champ source <u>#4075</u> +- **fix** : suppression des règles de liaison ne prenant pas effet en temps réel <u>#4058</u> +- **fix(core)** : correction du bug d'arrondi dans l'évaluateur de formules <u>#4070</u> +- **test** : ajout de tests e2e pour les modes de chargement des données <u>#4069</u> +- **fix(filterForm)** : éviter les noms dupliqués <u>#4071</u> +- **chore** : optimisation du titre des blocs <u>#4040</u> +- **fix** : synchroniser les valeurs par défaut dans la vue <u>#4067</u> +- **fix(defaultValue)** : correction du problème de disparition des valeurs par défaut après un rafraîchissement de page <u>#4066</u> +- **refactor** : bloc Gantt <u>#4059</u> +- **fix** : le sous-tableau de grands champs doit prendre en charge la valeur par défaut variable <u>#4062</u> +- **chore(Theme)** : définir la taille de police par défaut du thème Compact à 16 <u>#4064</u> +- **test** : ajout de tests e2e pour les actions <u>#4053</u> +- **fix(variable)** : variables manquantes et traductions invalides <u>#4054</u> +- **test** : ajout de tests unitaires front-end <u>#3991</u> +- **feat** : prise en charge de l'option "Autres" dans le popup <u>#4015</u> +- **fix(collection-manager)** : pas de rafraîchissement après avoir écrasé le champ <u>#4022</u> +- **chore** : ajouter des avertissements pour l'import et l'export <u>#4027</u> +- **refactor** : prise en charge du tri des champs groupés par source de données tierces <u>#4023</u> +- **fix(plugin-acl)** : correction du snippet pm.acl.roles <u>#4026</u> +- **test** : test e2e pour le bloc de nom d'association <u>#4021</u> +- **fix** : obtenir l'URL de l'API <u>#4020</u> +- **fix(Sub-details)** : le bouton d'initialisation n'est pas affiché lorsque la valeur du champ est vide <u>#4019</u> +- **fix** : l'initialiseur utilise useAassociationName <u>#4018</u> +- **fix(auth)** : bug de connexion cas lorsque le déploiement utilise un sous-répertoire <u>#4017</u> +- **fix(TreeTable)** : ajouter une erreur enfant <u>#4008</u> +- **fix** : retirer le champ actif ne doit pas effacer la valeur <u>#4012</u> +- **fix(plugin-acl)** : correction du snippet des rôles de la source de données <u>#4016</u> +- **fix** : après avoir sélectionné tout, la mise à jour en masse affiche des données non sélectionnées <u>#4010</u> +- **refactor** : le tableau d'arbre n'est pas activé par défaut <u>#4001</u> +- **feat(plugin-workflow-action-trigger)** : prise en charge des actions d'association pour le déclenchement <u>#4007</u> +- **update** : application.ts <u>#4006</u> +- **fix** : configuration du champ de tag <u>#4009</u> +- **fix(users)** : suppression de la validation du téléphone en raison de la vérification incorrecte des numéros de téléphone étrangers <u>#4005</u> +- **fix** : échec de la vérification des permissions d'action du bloc d'association <u>#3994</u> +- **refactor** : les champs de tri des tableaux ne peuvent pas sélectionner de champs de tri avec scopekey <u>#3984</u> +- **fix(Form)** : erreur de parentRecord invalide <u>#3998</u> +- **fix(plugin-workflow)** : ajuster la locale <u>#3993</u> +- **fix** : sous-tableau prend désormais en charge la configuration allowSelectExistingRecord <u>#4004</u> +- **fix(auth)** : la page d'inscription n'est pas trouvée lors de l'entrée directe par URL <u>#4002</u> +- **chore(database)** : définir une valeur nulle lorsque le champ est unique et que la valeur est une chaîne vide <u>#3997</u> +- **chore(gateway)** : signaler une erreur avec le message de cause <u>#3999</u> +- **chore(error-handler)** : afficher le message expliquant l'erreur <u>#3996</u> +- **fix** : restaurer avec le nom de la table en camel case <u>#3995</u> +- **refactor(plugin-workflow)** : ajuster les commentaires <u>#3990</u> +- **fix** : correction de la fonctionnalité de réduction et d'expansion dans Gantt <u>#3982</u> +- **fix(BulkForm)** : le champ doit être requis lors du passage à "Changed to" <u>#3965</u> +- **fix** : déplacer l'action <u>#3985</u> +- **refactor** : le champ de tri ne doit pas avoir de valeur par défaut <u>#3986</u> +- **chore** : mettre à jour les noms de classe des plugins <u>#3981</u> +- **feat(plugin-workflow-sync)** : ajouter la synchronisation lorsque multi-app-share-collection est activé <u>#3969</u> +- **fix(localization)** : mauvaise locale lors de la première entrée <u>#3968</u> +- **chore** : ajuster et ajouter des commentaires à l'API <u>#3951</u> +- **refactor** : configuration des options de sélection <u>#3964</u> +- **fix(GridCard)** : définir le nombre de colonnes affichées dans une ligne <u>#3960</u> +- **refactor** : seuls les champs de formule numériques doivent prendre en charge le format <u>#3962</u> +- **chore(plugin-workflow)** : ajouter des commentaires <u>#3959</u> +- **chore** : supprimer les anciens plugins de formule <u>#3939</u> +- **fix(LinkageRules)** : la règle de liaison doit être immédiatement effective <u>#3958</u> +- **fix(Picker)** : doit afficher l'option "Allow add new data" <u>#3957</u> +- **fix(connect-data-blocks)** : doit s'afficher immédiatement dans le menu déroulant <u>#3953</u> +- **fix** : modifier le titre du menu gauche <u>#3956</u> +- **fix** : bug du fournisseur de la liste de modèles <u>#3950</u> +- **refactor** : auto-complétion pour nanoid et uuid <u>#3955</u> +- **feat** : ajouter getParentJsonSchema dans le référentiel du schéma UI <u>#3690</u> +- **fix** : sauvegarder uuid et nano id avec validation sequelize <u>#3952</u> +- **fix** : la recherche floue est maintenant prise en charge par throughCollection <u>#3949</u> +- **fix** : obtenir la clé source par association <u>#3947</u> +- **fix(RichText)** : unification du style <u>#3946</u> +- **fix(connectDataBlocks)** : doit ajouter FilterBlockProvider à la grille <u>#3944</u> +- **chore** : ajouter appVersion au schéma <u>#3936</u> +- **fix** : collectionFieldInterfaceSelect <u>#3945</u> +- **fix** : correction du sourceId des modèles <u>#3941</u> +- **fix(collection manager)** : gestionnaire de collections prend désormais en charge la configuration de la clé primaire, nanoid et uuid <u>#3943</u> +- **fix(plugin-formula-field)** : correction du contexte du composant <u>#3937</u> +- **fix** : disponibilité des types nanoid <u>#3942</u> +- **fix** : génération automatique des valeurs par défaut <u>#3940</u> +- **fix** : erreur de calcul dans le champ de formule <u>#3938</u> +- **fix** : prise en charge du format dans le champ de formule <u>#3928</u> +- **refactor** : unification de l'initialisation des onglets <u>#3932</u> +- **fix** : ajout de zIndex au style de la superposition Lightbox <u>#3934</u> +- **fix(Table)** : correction du problème où le contenu du champ d'association n'est pas affiché <u>#3930</u> +- **fix(evaluators)** : correction de l'aplatissement des tableaux <u>#3931</u> +- **refactor** : vue principale de la source de données, prise en charge du filtreTargetKey dans la collection <u>#3818</u> +- **fix** : correction de l'erreur de calcul dans le champ de formule <u>#3929</u> +- **fix** : charger la collection de vues "appartient à" avec les options source <u>#3912</u> +- **fix** : lorsque le formulaire n'a pas été modifié, ne pas afficher l'avertissement de non-sauvegarde lors de la fermeture de la fenêtre modale <u>#3920</u> +- **fix(Collapse)** : correction du problème pour chinaRegions <u>#3925</u> +- **fix** : format d'affichage du nombre <u>#3924</u> + +# Changelog complet + +<details> +<summary>Voir le changelog complet</summary> + +- **fix(defaultValue)** : les valeurs par défaut doivent avoir un effet immédiat lors de leur définition <u>#3923</u> +- **feat** : la configuration de `refreshDataBlockRequest` est désormais prise en charge pour les actions <u>#3882</u> +- **refactor** : refactorisation des `formBlockProvider` et `detailBlockProvider` <u>#3898</u> +- **feat(data-vi)** : possibilité d'ajouter des graphiques pour le client mobile <u>#3922</u> +- **chore** : ajouter des commentaires dans l'API <u>#3919</u> +- **fix** : correction de la pagination <u>#3921</u> +- **test(plugin-error-handler)** : test du middleware <u>#3909</u> +- **fix** : mise à jour du plugin <u>#3895</u> +- **fix** : correction de la pagination du bloc Gantt <u>#3918</u> +- **fix** : correction de la source id nulle <u>#3917</u> +- **fix(Table)** : correction de la pagination <u>#3916</u> +- **fix** : obtenir le bon `sourceId` <u>#3897</u> +- **fix(DataScope)** : résolution du problème d'absence d'effet immédiat après la sauvegarde <u>#3910</u> +- **fix** : correction des options initiales du champ de sélection <u>#3911</u> +- **fix** : correction du clic sur les liens externes <u>#3908</u> +- **fix(inputNumber)** : perte de précision dans `inputNumber` <u>#3902</u> +- **feat(plugin-workflow-action-trigger)** : ajout des événements d'action globaux <u>#3883</u> +- **docs** : ajout des commentaires API <u>#3868</u> +- **fix** : correction du bug de configuration de `vitest` <u>#3907</u> +- **fix** : correction du bug avec le tableau fixe <u>#3901</u> +- **fix** : correction de l'erreur de données non définies dans la liste <u>#3905</u> +- **fix** : correction du bug de rendu paresseux <u>#3886</u> +- **fix** : paramètres de tri manquants <u>#3906</u> +- **refactor** : changement de `useProps` à `x-use-component-props` <u>#3853</u> +- **fix(withDynamicSchemaProps)** : changement de la fusion profonde en fusion superficielle <u>#3899</u> +- **fix** : ajout d'un bouton d'impression pour le bloc historique, correction de l'erreur lors du clic sur le bouton d'impression <u>#3900</u> +- **fix** : correction du bug `tar` <u>#3891</u> +- **chore** : retourner `bigInt` sous forme de chaîne <u>#3887</u> +- **feat(data-vi)** : ajout de la portée des données pour filtrer les champs des graphiques <u>#3894</u> +- **feat** : ajustement du menu d'ajout de nouveaux éléments <u>#3884</u> +- **fix(plugin-custom-request)** : correction du dialogue du bouton d'édition <u>#3893</u> +- **fix** : correction de l'absence de `fieldNames` lors de la définition de la portée des données <u>#3892</u> +- **fix** : erreur de vérification des dépendances lorsque l'on ajoute un plugin de production en mode développement <u>#3848</u> +- **fix** : les onglets du workflow n'existent pas <u>#3889</u> +- **fix** : prise en charge de la portée des données par le champ d'association <u>#3888</u> +- **fix** : `templateBlockProvider` prend désormais en charge l'ajout de champs d'association <u>#3866</u> +- **chore** : mise à jour de l'API de la source de données principale <u>#3880</u> +- **feat** : exécution de `vitest` avec couverture <u>#3802</u> +- **fix** : éviter les clés de menu en double <u>#3885</u> +- **fix(data-vi)** : le graphique à axes doubles s'affiche de manière anormale <u>#3881</u> +- **fix** : rejeter la mise à jour lorsque le filtre est un objet vide <u>#3777</u> +- **chore** : mise à jour du champ avec l'attribut clé primaire <u>#3852</u> +- **refactor** : prise en charge de la configuration de la valeur par défaut pour `uuid` et `nanoid` <u>#3830</u> +- **feat** : amélioration des performances du tableau <u>#3791</u> +- **fix** : correction de `setFormValueChanged` non défini <u>#3879</u> +- **fix(client)** : correction du problème avec `disabled` dans les composants dynamiques de filtre <u>#3874</u> +- **fix(plugin-workflow-parallel)** : correction de la locale <u>#3876</u> +- **fix(formula-field)** : mise à jour de la valeur du formulaire pour les champs de formule <u>#3873</u> +- **fix** : correction de l'affichage du bloc `formBlockProvider` <u>#3877</u> +- **refactor(plugin-workflow)** : modification de la structure du code <u>#3871</u> +- **fix** : correction de l'affichage anormal du modal de la carte Kanban <u>#3863</u> +- **fix** : `filterTargetKey` ne prend en charge que les collections de vue <u>#3872</u> + +</details> + +## Modifications des Plugins + +### Plugins Supprimés + +Les plugins suivants ne sont plus disponibles en version open-source. Les utilisateurs qui utilisent ces plugins en production sont invités à contacter NocoBase pour obtenir une mise à jour : + +- **@nocobase/plugin-auth-cas** : Authentifie l'identité via le protocole CAS. +- **@nocobase/plugin-auth-odic** : Authentifie l'identité via le protocole OIDC (OpenID Connect). +- **@nocobase/plugin-auth-saml** : Authentifie l'identité via le protocole SAML 2.0. + +### Plugins Dépréciés + +Les plugins suivants ont été dépréciés et seront supprimés dans les versions futures. Ils ne seront plus installés dans les nouvelles versions, bien qu'ils soient encore disponibles temporairement : + +- **@nocobase/plugin-audit-logs** : Déprécié, ne sera pas installé dans la nouvelle version. +- **@nocobase/plugin-snapshot-field** : Déprécié, ne sera pas installé dans la nouvelle version. +- **@nocobase/plugin-charts** : Utilisez **@nocobase/plugin-data-visualization** à la place. +- **@nocobase/plugin-excel-formula-field** : Utilisez **@nocobase/plugin-field-formula** à la place. +- **@nocobase/plugin-math-formula-field** : Utilisez **@nocobase/plugin-field-formula** à la place. +- **@nocobase/plugin-ui-routes-storage** : Déprécié, les routes frontend peuvent être étendues directement dans le frontend. + +Pour la liste complète des plugins, veuillez consulter [Plugins NocoBase](https://www.nocobase.com/plugins.html). + +## Commentaires de Code + +Pour améliorer l'expérience de développement, nous avons ajouté les commentaires suivants à certaines API spéciales : + +- **@internal** : Indique les détails d'implémentation internes ou les méthodes qui ne sont pas destinées à un usage public. +- **@experimental** : Marque les API ou fonctionnalités encore en développement ou en phase de test. Ces API peuvent subir des modifications importantes ou être supprimées dans les futures versions. +- **@deprecated** : Identifie les fonctionnalités, méthodes ou API dépréciées qui peuvent être supprimées à l'avenir. Des alternatives meilleures peuvent être disponibles. + +## Accord de Licence + +NocoBase est sous licence double AGPL-3.0 et commerciale. Pour plus de détails, veuillez consulter l'[Accord de Licence NocoBase](https://cn.nocobase.com/agreement-cn.html). + +## Guide de Mise à Jour + +### Notes Importantes : +- **Sauvegardez toujours votre base de données avant de mettre à jour !** Pensez également à sauvegarder tout le code de votre projet. + +Puisque les plugins **Auth : CAS**, **Auth : OIDC** et **Auth : SAML** ont été supprimés du code open-source, le processus de mise à jour variera en fonction de votre utilisation des plugins. + +### Si Vous N'utilisez Pas de Plugins SSO : +Veuillez suivre la [méthode de mise à jour conventionnelle](https://docs.nocobase.com/welcome/getting-started/upgrading) pour effectuer la mise à jour. + +### Si Vous Utilisez des Plugins SSO : + +Suivez les étapes ci-dessous pour effectuer la mise à jour : + +#### 1. Mettre à Jour l'Application + +- Référez-vous à l'[Aperçu de la Mise à Jour de NocoBase](/welcome/getting-started/upgrading) et mettez à jour NocoBase vers la dernière version. + +Si vous avez activé les plugins CAS, OIDC ou SAML précédemment, vous verrez les invites suivantes lors de la mise à jour : + +- **Invite en ligne de commande** : + + ![20240428212151](https://static-docs.nocobase.com/20240428212151.png) + +- **Invite de l'interface Docker** : + + ![20240428194926](https://static-docs.nocobase.com/20240428194926.png) + +#### 2. Supprimer les Plugins ou Obtenir la Version 1.0 des Plugins + +**Si vous choisissez de supprimer les plugins et de continuer la mise à jour :** + +Supprimez les plugins selon les invites. + +```bash +# Application principale +yarn pm remove cas oidc saml --force +# Si c'est une sous-application, ajoutez le paramètre --app +yarn pm remove cas oidc saml --force --app=sub-app1 +``` + +Continuez la mise à jour : + +```bash +yarn nocobase upgrade +``` + +**Si vous choisissez de mettre à jour les plugins vers la version 1.0 :** + +Contactez l'équipe NocoBase pour obtenir la version 1.0 des plugins et poursuivez la mise à jour. + +#### 3. Processus de Mise à Jour des Plugins CAS, OIDC, SAML + +À ce stade, l'interface de l'application ne sera plus accessible. Vous devrez donc effectuer la mise à jour manuellement. + +1. Connectez-vous à la **Plateforme de Services Utilisateurs Entreprise** pour télécharger les dernières versions des plugins. +2. Décompressez les plugins dans les répertoires spécifiés : + - Plugin CAS dans `./storage/plugins/@nocobase/plugin-auth-cas` + - Plugin OIDC dans `./storage/plugins/@nocobase/plugin-auth-oidc` + - Plugin SAML dans `./storage/plugins/@nocobase/plugin-auth-saml` +3. Mettez à jour l'application : + - Pour Docker, redémarrez simplement le conteneur. + - Pour la version du code source ou `create-nocobase-app` : + 1. Téléchargez les dépendances : `yarn install` + 2. Exécutez la commande de mise à jour : `yarn nocobase upgrade` + 3. Redémarrez l'application. diff --git a/package.json b/package.json index 7ec5cc9af..bd63f239c 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,11 @@ "start": "npm run dev", "dev": "dumi dev", "dev:en": "cross-env DOC_LANG=en-US dumi dev", + "dev:fr": "cross-env DOC_LANG=fr-FR dumi dev", "dev:ja": "cross-env DOC_LANG=ja-JP dumi dev", "build": "dumi build", "build:en": "cross-env DOC_LANG=en-US dumi build", + "build:fr": "cross-env DOC_LANG=fr-FR dumi build", "build:ja": "cross-env DOC_LANG=ja-JP dumi build", "prepare": "husky install && dumi setup" },