docs: update docs
This commit is contained in:
parent
c6b68f2b10
commit
d109732757
@ -58,7 +58,7 @@
|
||||
|
||||
.@{prefix}-menu-logo {
|
||||
display: inline-block;
|
||||
width: 66px;
|
||||
width: 70%;
|
||||
height: 65px;
|
||||
background: url(@img-logo) no-repeat 0 / contain;
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
---
|
||||
title: 介绍
|
||||
order: 0
|
||||
toc: menu
|
||||
nav:
|
||||
title: 核心
|
||||
order: 2
|
||||
---
|
||||
|
||||
# 介绍
|
@ -1,135 +0,0 @@
|
||||
---
|
||||
title: 数据库迁移
|
||||
order: 1
|
||||
toc: menu
|
||||
nav:
|
||||
title: 核心
|
||||
order: 2
|
||||
---
|
||||
|
||||
# 数据库迁移
|
||||
|
||||
NocoBase 通过配置来生成数据表和字段,如:
|
||||
|
||||
```ts
|
||||
const db = new Database();
|
||||
|
||||
db.table({
|
||||
name: 'examples',
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
{ type: 'string', name: 'title' },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
如果需要生成数据表和字段,直接执行 `db.sync()` 操作就可以了。
|
||||
|
||||
```ts
|
||||
// 只更新不删除
|
||||
await db.sync();
|
||||
|
||||
// 全部重建
|
||||
await db.sync({
|
||||
force: true,
|
||||
alter: {
|
||||
drop: true,
|
||||
},
|
||||
});
|
||||
|
||||
// 更多参数说明
|
||||
interface SyncOptions {
|
||||
|
||||
/**
|
||||
* The tables should be created or updated.
|
||||
*/
|
||||
tables?: string[] | Table[] | Map<string, Table>;
|
||||
|
||||
/**
|
||||
* If force is true, each DAO will do DROP TABLE IF EXISTS ..., before it tries to create its own table
|
||||
*/
|
||||
force?: boolean;
|
||||
|
||||
/**
|
||||
* If alter is true, each DAO will do ALTER TABLE ... CHANGE ...
|
||||
* Alters tables to fit models. Provide an object for additional configuration. Not recommended for production use. If not further configured deletes data in columns that were removed or had their type changed in the model.
|
||||
*/
|
||||
alter?: boolean | SyncAlterOptions;
|
||||
|
||||
/**
|
||||
* Match a regex against the database name before syncing, a safety check for cases where force: true is
|
||||
* used in tests but not live code
|
||||
*/
|
||||
match?: RegExp;
|
||||
|
||||
/**
|
||||
* The schema that the tables should be created in. This can be overridden for each table in sequelize.define
|
||||
*/
|
||||
schema?: string;
|
||||
|
||||
/**
|
||||
* An optional parameter to specify the schema search_path (Postgres only)
|
||||
*/
|
||||
searchPath?: string;
|
||||
}
|
||||
```
|
||||
|
||||
如果后续有新增或删除字段操作,直接修改配置即可,如:
|
||||
|
||||
```ts
|
||||
db.table({
|
||||
name: 'examples',
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
// { type: 'string', name: 'title' }, // 去掉 title 字段
|
||||
{ type: 'text', name: 'content' }, // 新增 content 字段
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
接着执行 `db.sync()` 操作就同步给数据库了。
|
||||
|
||||
但是,如果需要更改字段名怎么操作呢,比如将 name 改为 name2,需要将配置修一下:
|
||||
|
||||
```ts
|
||||
db.table({
|
||||
name: 'examples',
|
||||
fields: [
|
||||
{ type: 'string', name: 'name2' },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
这时,执行 `db.sync()` 操作并不会把 name 改为 name2,而是又生成了一个新的 name2 字段。如果要更改字段名称,需要配合 migration 来处理,如:
|
||||
|
||||
```ts
|
||||
await queryInterface.renameColumn('examples', 'name', 'name2');
|
||||
```
|
||||
|
||||
这个办法能解决问题,但是需要写另外的 migration 文件来处理。更好的办法,可以给字段一个显式的 uid,如:
|
||||
|
||||
```ts
|
||||
db.table({
|
||||
name: 'examples',
|
||||
fields: [
|
||||
{ uid: 'f0nyq8tg3j1y', type: 'string', name: 'name' },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
更改字段配置时,uid 不变,修改其他值即可
|
||||
|
||||
```ts
|
||||
db.table({
|
||||
name: 'examples',
|
||||
fields: [
|
||||
{ uid: 'f0nyq8tg3j1y', type: 'string', name: 'name2' },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
需要同步给数据库时,接着执行 `db.sync()` 方法。
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
uid 的方案适用于 table、field、index,但是还并未实现。暂时可以结合 migration 来管理数据库结构变更。
|
||||
</Alert>
|
@ -1,426 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/actions'
|
||||
order: 4
|
||||
# toc: menu
|
||||
---
|
||||
|
||||
# @nocobase/actions
|
||||
|
||||
## 介绍
|
||||
|
||||
为资源提供了几种默认方法:
|
||||
|
||||
- list:查看列表
|
||||
- get:查看详情
|
||||
- create:创建数据
|
||||
- update:更新数据
|
||||
- destroy:删除数据
|
||||
- set:建立关联
|
||||
- add:附加关联
|
||||
- remove:删除关联
|
||||
- toggle:附加或删除关联
|
||||
- sort:排序
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn add @nocobase/actions
|
||||
```
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
@nocobase/actions 不能单独使用,依赖于 @nocobase/database 和 @nocobase/resourcer
|
||||
</Alert>
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import Koa from 'koa';
|
||||
import Database from '@nocobase/database';
|
||||
import { actions, middlewares } from '@nocobase/actions';
|
||||
|
||||
// 配置数据表
|
||||
|
||||
const db = new Database({
|
||||
// 省略
|
||||
});
|
||||
|
||||
const table = db.table({
|
||||
name: 'posts',
|
||||
fields: [
|
||||
{type: 'string', name: 'title'},
|
||||
],
|
||||
});
|
||||
|
||||
await table.sync();
|
||||
|
||||
// 配置资源
|
||||
|
||||
const resourcer = new Resourcer();
|
||||
resourcer.registerActionHandlers({ ...actions.common });
|
||||
resourcer.define({
|
||||
name: 'posts',
|
||||
});
|
||||
|
||||
// 使用 Koa
|
||||
|
||||
const app = new Koa();
|
||||
app.use(async (ctx, next) => {
|
||||
ctx.db = database;
|
||||
await next();
|
||||
});
|
||||
app.use(resourcer.middleware({
|
||||
prefix: '/api',
|
||||
}));
|
||||
app.listen(3000);
|
||||
```
|
||||
|
||||
创建一条 posts 数据
|
||||
|
||||
```bash
|
||||
curl -d '{"title": "title 1"}' -H 'Content-Type: application/json' http://localhost:3000/api/posts
|
||||
```
|
||||
|
||||
## Actions
|
||||
|
||||
### list
|
||||
|
||||
查询列表数据
|
||||
|
||||
API
|
||||
|
||||
```bash
|
||||
# 常规
|
||||
GET /api/<resourceName>?filter[col1]=val1&fields=col1,col2&sort=-created_at&page=2&perPage=10
|
||||
# 关系资源
|
||||
GET /api/<associatedName>/<associatedKey>/<resourceName>?filter[col1]=val1&fields=col1,col2&sort=-created_at&page=2&perPage=10
|
||||
```
|
||||
|
||||
SDK
|
||||
|
||||
```ts
|
||||
// 常规
|
||||
api.resource('<resourceName>').list({
|
||||
filter,
|
||||
fields,
|
||||
sort,
|
||||
page,
|
||||
perPage,
|
||||
});
|
||||
|
||||
// 关系资源
|
||||
api.resource('<associatedName>.<resourceName>').list({
|
||||
associatedKey,
|
||||
filter,
|
||||
fields,
|
||||
sort,
|
||||
page,
|
||||
perPage,
|
||||
});
|
||||
```
|
||||
|
||||
### get
|
||||
|
||||
查询详情数据
|
||||
|
||||
API
|
||||
|
||||
```bash
|
||||
# 常规
|
||||
GET /api/<resourceName>/<resourceKey>?filter[col1]=val1&fields=col1,col2&sort=-created_at&page=2&perPage=10
|
||||
# 关系资源
|
||||
GET /api/<associatedName>/<associatedKey>/<resourceName>/<resourceKey>?filter[col1]=val1&fields=col1,col2&sort=-created_at&page=2&perPage=10
|
||||
```
|
||||
|
||||
SDK
|
||||
|
||||
```ts
|
||||
// 常规
|
||||
api.resource('<resourceName>').get({
|
||||
resourceKey,
|
||||
filter,
|
||||
fields,
|
||||
sort,
|
||||
page,
|
||||
perPage,
|
||||
});
|
||||
|
||||
// 关系资源
|
||||
api.resource('<associatedName>.<resourceName>').get({
|
||||
associatedKey,
|
||||
resourceKey,
|
||||
filter,
|
||||
fields,
|
||||
sort,
|
||||
page,
|
||||
perPage,
|
||||
});
|
||||
```
|
||||
|
||||
### create
|
||||
|
||||
新增数据
|
||||
|
||||
API
|
||||
|
||||
```bash
|
||||
# 常规
|
||||
POST /api/<resourceName>?fields=col1,col2
|
||||
# or 关系资源
|
||||
POST /api/<associatedName>/<associatedKey>/<resourceName>?fields=col1,col2
|
||||
|
||||
values # JSON 格式
|
||||
```
|
||||
|
||||
SDK
|
||||
|
||||
```ts
|
||||
// 常规
|
||||
api.resource('<resourceName>').create({
|
||||
fields,
|
||||
values
|
||||
});
|
||||
|
||||
// 关系资源
|
||||
api.resource('<associatedName>.<resourceName>').create({
|
||||
associatedKey,
|
||||
fields,
|
||||
values,
|
||||
});
|
||||
```
|
||||
|
||||
### update
|
||||
|
||||
更新数据
|
||||
|
||||
API
|
||||
|
||||
```bash
|
||||
# 常规
|
||||
PUT /api/<resourceName>/<resourceKey>?fields=col1,col2
|
||||
# 关系资源
|
||||
PUT /api/<associatedName>/<associatedKey>/<resourceName>/<resourceKey>?fields=col1,col2
|
||||
|
||||
values # JSON 格式
|
||||
```
|
||||
|
||||
SDK
|
||||
|
||||
```ts
|
||||
// 常规
|
||||
api.resource('<resourceName>').update({
|
||||
resourceKey,
|
||||
fields,
|
||||
values,
|
||||
});
|
||||
|
||||
// 关系资源
|
||||
api.resource('<associatedName>.<resourceName>').update({
|
||||
associatedKey,
|
||||
resourceKey,
|
||||
fields,
|
||||
values,
|
||||
});
|
||||
```
|
||||
|
||||
### destroy
|
||||
|
||||
删除数据
|
||||
|
||||
API
|
||||
|
||||
```bash
|
||||
# 常规
|
||||
DELETE /api/<resourceName>/<resourceKey>
|
||||
# 关系资源
|
||||
DELETE /api/<associatedName>/<associatedKey>/<resourceName>/<resourceKey>
|
||||
|
||||
# 常规,通过 filter 参数
|
||||
DELETE /api/<resourceName>?filter=
|
||||
# 关系资源,通过 filter 参数
|
||||
DELETE /api/<associatedName>/<associatedKey>/<resourceName>?filter=
|
||||
```
|
||||
|
||||
SDK
|
||||
|
||||
```ts
|
||||
// 常规
|
||||
api.resource('<resourceName>').destroy({
|
||||
resourceKey,
|
||||
filter,
|
||||
});
|
||||
|
||||
// 关系资源
|
||||
api.resource('<associatedName>.<resourceName>').destroy({
|
||||
associatedKey,
|
||||
resourceKey,
|
||||
filter,
|
||||
});
|
||||
```
|
||||
|
||||
### set
|
||||
|
||||
建立关联,旧关联会解除。此操作需要显式声明 actionName。
|
||||
|
||||
API
|
||||
|
||||
```bash
|
||||
POST /api/<associatedName>/<associatedKey>/<resourceName>:set/<resourceKey>
|
||||
|
||||
values
|
||||
```
|
||||
|
||||
SDK
|
||||
|
||||
```ts
|
||||
api.resource('<associatedName>.<resourceName>').set({
|
||||
associatedKey,
|
||||
resourceKey,
|
||||
values,
|
||||
});
|
||||
```
|
||||
|
||||
### add
|
||||
|
||||
关联的附加操作,此操作需要显式声明 actionName。
|
||||
|
||||
API
|
||||
|
||||
```bash
|
||||
POST /api/<associatedName>/<associatedKey>/<resourceName>:add/<resourceKey>
|
||||
|
||||
values
|
||||
```
|
||||
|
||||
SDK
|
||||
|
||||
```ts
|
||||
api.resource('<associatedName>.<resourceName>').add({
|
||||
associatedKey,
|
||||
resourceKey,
|
||||
values,
|
||||
});
|
||||
```
|
||||
|
||||
### remove
|
||||
|
||||
移除关联,此操作需要显式声明 actionName。
|
||||
|
||||
API
|
||||
|
||||
```bash
|
||||
POST /api/<associatedName>/<associatedKey>/<resourceName>:remove/<resourceKey>
|
||||
```
|
||||
|
||||
SDK
|
||||
|
||||
```ts
|
||||
// 常规
|
||||
api.resource('<resourceName>').remove({
|
||||
resourceKey,
|
||||
});
|
||||
|
||||
// 关系资源
|
||||
api.resource('<associatedName>.<resourceName>').remove({
|
||||
associatedKey,
|
||||
resourceKey,
|
||||
});
|
||||
```
|
||||
|
||||
### toggle
|
||||
|
||||
API
|
||||
|
||||
```bash
|
||||
POST /api/<associatedName>/<associatedKey>/<resourceName>:toggle/<resourceKey>
|
||||
```
|
||||
|
||||
SDK
|
||||
|
||||
```ts
|
||||
// 常规
|
||||
api.resource('<resourceName>').list({
|
||||
resourceKey,
|
||||
fields,
|
||||
});
|
||||
|
||||
// 关系资源
|
||||
api.resource('<associatedName>.<resourceName>').list({
|
||||
associatedKey,
|
||||
resourceKey,
|
||||
fields,
|
||||
});
|
||||
```
|
||||
|
||||
### sort
|
||||
|
||||
API
|
||||
|
||||
```bash
|
||||
# 常规
|
||||
GET /api/<resourceName>:sort/<resourceKey>
|
||||
# 关系资源
|
||||
GET /api/<associatedName>/<associatedKey>/<resourceName>:sort/<resourceKey>
|
||||
```
|
||||
|
||||
SDK
|
||||
|
||||
```ts
|
||||
// 常规
|
||||
api.resource('<resourceName>').sort({
|
||||
resourceKey,
|
||||
values: {
|
||||
field, // 默认为 sort 字段
|
||||
target: {
|
||||
id: 5,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// 关系资源
|
||||
api.resource('<associatedName>.<resourceName>').list({
|
||||
associatedKey,
|
||||
resourceKey,
|
||||
values: {
|
||||
field, // 默认为 sort 字段
|
||||
target: {
|
||||
id: 5,
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Middlewares
|
||||
|
||||
### associated
|
||||
|
||||
注入 associated 实例,同时会提供 resourceField 字段。
|
||||
|
||||
<Alert title="resourceField 和 resourceName 的区别?" type="warning">
|
||||
|
||||
关系资源 `<associatedName>.<resourceName>` 时,resourceName 并不一定是真实的 tableName,而是 fieldName。resource 的 tableName 为 resourceField.target。
|
||||
|
||||
</Alert>
|
||||
|
||||
### dataWrapping
|
||||
|
||||
输出的 JSON 会用 data 包裹。
|
||||
|
||||
用法:
|
||||
|
||||
```ts
|
||||
app.use(dataWrapping);
|
||||
```
|
||||
|
||||
用例:
|
||||
|
||||
```ts
|
||||
ctx.body = [];
|
||||
```
|
||||
|
||||
最终输出的 response body 为:
|
||||
|
||||
```ts
|
||||
{
|
||||
data: [],
|
||||
}
|
||||
```
|
File diff suppressed because it is too large
Load Diff
@ -1,20 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/migrator'
|
||||
order: 8
|
||||
# toc: menu
|
||||
---
|
||||
|
||||
# @nocobase/migrator <Badge>未实现</Badge>
|
||||
|
||||
NocoBase 的 Database 是基于 Sequelize,Sequelize 虽然提供了 sequelize-cli,包括 migrations 和 seeders 但是并不适用于 NocoBase。
|
||||
|
||||
- Sequelize 的 migration 只有 queryInterface,但是 NocoBase 考虑的更多是配置层面问题
|
||||
- 要考虑 Upgrade 层面的问题,比如 0.3 升级 0.6、0.4 升级 0.6、0.5 升级 0.6 等等一系列问题
|
||||
- 需要考虑插件里的 migrations
|
||||
|
||||
目前已知的开源项目里,Ghost 团队实现的 [knex-migrator](https://github.com/TryGhost/knex-migrator) 非常接近我们的需求。Ghost 的 [migrations](https://github.com/TryGhost/Ghost/tree/v4.2.2/core/server/data/migrations) 例子。
|
||||
|
||||
虽然非常接近,但也存在一些差异:
|
||||
|
||||
- NocoBase 的 database 用的是 Sequelize 而不是 Knex
|
||||
- NocoBase 的配置更复杂,我们要为此提供一些简易的 API 辅助完成 migrate
|
@ -1,570 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/resourcer'
|
||||
order: 2
|
||||
# toc: menu
|
||||
---
|
||||
|
||||
# @nocobase/resourcer
|
||||
|
||||
## 介绍
|
||||
|
||||
提供数据资源操作方法,可单独使用。
|
||||
|
||||
基于资源(resource)和操作方法(action)设计,将 REST 和 RPC 思想融合起来,为资源提供操作方法,执行方法时提供相关参数(params)。
|
||||
|
||||
特点:
|
||||
|
||||
- 可注册的 Middlewares 和 Actions
|
||||
- 提供灵活的多来源 Action Params 合并方案
|
||||
- 不局限于 Koa 框架
|
||||
- 不局限于 HTTP
|
||||
|
||||
<Alert title="何为多来源 Action Params?" type="info">
|
||||
|
||||
以 filter 为例,某数据表的过滤条件可能来自:
|
||||
|
||||
- 客户端请求参数
|
||||
- 视图限定了筛选范围
|
||||
- 权限也可能限定了筛选范围
|
||||
- 通过中间件注入定制化的过滤条件
|
||||
|
||||
resourcer 提供了非常方便的接口用于处理参数的合并(包括自定义合并或替换规则)
|
||||
|
||||
</Alert>
|
||||
|
||||
资源有五种类型:
|
||||
|
||||
- single 独立资源
|
||||
- hasOne 一对一的关系资源
|
||||
- hasMany 一对多的关系资源
|
||||
- belongsTo 一对一的关系资源
|
||||
- belongsToMany 多对多的关系资源
|
||||
|
||||
举例说明:
|
||||
|
||||
- users:独立资源;
|
||||
- posts:独立资源;
|
||||
- users.profile:关系资源,一对一关系 User.hasOne(Profile),资源为 profile,属于 users;
|
||||
- posts.user:关系资源,多对一关系 Post.belongsTo(User),资源为 user,属于 posts;
|
||||
- users.posts:关系资源,一对多关系 User.hasMany(Post),资源为 posts,属于 users;
|
||||
- posts.tags:关系资源,多对多关系 Post.belongsToMany(Tag),资源为 tags,属于 posts。
|
||||
|
||||
资源名称的格式:
|
||||
|
||||
- resourceName:独立资源
|
||||
- associatedName.resourceName:关系资源
|
||||
|
||||
操作名称的格式:
|
||||
|
||||
- create:全局操作
|
||||
- resourceName:create:隶属某个资源的操作
|
||||
- associatedName.resourceName:create:隶属某个关系资源的操作
|
||||
|
||||
这种资源和操作的格式,在 SDK 的协助下,看起来会更加直观,如:
|
||||
|
||||
```ts
|
||||
api.resource('users').login({
|
||||
// 省略具体参数
|
||||
});
|
||||
```
|
||||
|
||||
<Alert title="为什么不是 REST 或 GraphQL?" type="info">
|
||||
|
||||
Resourcer 是基于资源设计的,可以看做是 REST 的扩展(兼容的同时,但有些许不同),提供了类 REST 的 Resource Action API([点此查看细节](#resourcerkoarestapimiddleware)),非常灵活,同时弥补了 REST 的一些缺陷。不用 GraphQL 的原因是因为还不够完善,尤其为了追求 GraphQL 需要写很多代码,并不适合作为常规 API 开放给大众。后续如果反应强烈会考虑适配 GraphQL,其他感兴趣的开发也可以自由发挥,来完善 GraphQL API。
|
||||
|
||||
</Alert>
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn add @nocobase/resourcer
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import Resourcer from '@nocobase/resourcer';
|
||||
|
||||
const resourcer = new Resourcer();
|
||||
|
||||
resourcer.registerActions({
|
||||
async list(ctx, next) {
|
||||
ctx.arr.push(3);
|
||||
await next();
|
||||
ctx.arr.push(4);
|
||||
},
|
||||
async create(ctx, next) {
|
||||
ctx.arr.push(5);
|
||||
await next();
|
||||
ctx.arr.push(6);
|
||||
},
|
||||
});
|
||||
|
||||
resourcer.define({
|
||||
name: 'users',
|
||||
});
|
||||
|
||||
const context = {
|
||||
arr: [],
|
||||
};
|
||||
|
||||
await resourcer.execute({
|
||||
resource: 'users',
|
||||
action: 'list',
|
||||
}, context);
|
||||
|
||||
console.log(context.arr);
|
||||
// [1,3,4,2]
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### context.action.params
|
||||
|
||||
action.params 分为三类:
|
||||
|
||||
- 用于定位资源和操作的参数(这些暂时也放在 action.params 里了)
|
||||
|
||||
- actionName
|
||||
- resourceName
|
||||
- associatedName
|
||||
|
||||
- 定位资源 ID 相关参数
|
||||
|
||||
- resourceKey
|
||||
- associatedKey
|
||||
|
||||
- request 的 query 和 body 相关参数
|
||||
|
||||
- filter
|
||||
- fields
|
||||
- sort
|
||||
- page
|
||||
- perPage
|
||||
- values 对应为 request.body
|
||||
- 其他 query params
|
||||
|
||||
#### actionName
|
||||
|
||||
资源操作名称
|
||||
|
||||
#### resourceName
|
||||
|
||||
资源名称
|
||||
|
||||
#### associatedName
|
||||
|
||||
所属资源名称
|
||||
|
||||
#### resourceKey
|
||||
|
||||
资源 ID
|
||||
|
||||
#### associatedKey
|
||||
|
||||
所属资源 ID
|
||||
|
||||
#### filter
|
||||
|
||||
过滤条件
|
||||
|
||||
#### fields
|
||||
|
||||
字段
|
||||
|
||||
#### sort
|
||||
|
||||
排序
|
||||
|
||||
#### page
|
||||
|
||||
分页
|
||||
|
||||
#### perPage
|
||||
|
||||
每页显示条数
|
||||
|
||||
#### values
|
||||
|
||||
body 数据
|
||||
|
||||
#### 其他自定义参数
|
||||
|
||||
待补充...
|
||||
|
||||
### context.action.mergeParams
|
||||
|
||||
为 action.params 提供的多来源参数合并的方法
|
||||
|
||||
```ts
|
||||
action.mergeParams({
|
||||
filter: {col1: 'val1'},
|
||||
});
|
||||
```
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
|
||||
后续可能会使用 [deepmerge](https://www.npmjs.com/package/deepmerge) 重构,以便处理更灵活的自定义合并规则。
|
||||
|
||||
</Alert>
|
||||
|
||||
### resourcer.define
|
||||
|
||||
配置资源
|
||||
|
||||
用例:
|
||||
|
||||
```ts
|
||||
resourcer.define({
|
||||
name: 'posts',
|
||||
middlewares: [
|
||||
async (ctx, next) => {
|
||||
await next();
|
||||
},
|
||||
{
|
||||
only: [],
|
||||
except: [],
|
||||
handler: async (ctx, next) => {
|
||||
await next();
|
||||
},
|
||||
},
|
||||
],
|
||||
actions: {
|
||||
async get(ctx, next) {
|
||||
await next();
|
||||
},
|
||||
list: {
|
||||
fields,
|
||||
filter,
|
||||
sort,
|
||||
page,
|
||||
perPage,
|
||||
middlewares: [],
|
||||
handler: async (ctx, next) => {
|
||||
await next();
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### resourcer.execute <Badge>实验性</Badge>
|
||||
|
||||
注入 context
|
||||
|
||||
### resourcer.import
|
||||
|
||||
批量导入已配置的资源
|
||||
|
||||
### resourcer.isDefined
|
||||
|
||||
判断资源是否已定义
|
||||
|
||||
### resourcer.koaRestApiMiddleware <Badge>待完善</Badge>
|
||||
|
||||
原 resourcer.middleware
|
||||
|
||||
为 Koa 提供的类 REST API 中间件。提供了标准的 REST API 映射,Resource Action 与 Request Method 的对应关系如下:
|
||||
|
||||
| Resource Action | Request Method |
|
||||
| :-------------- | :---------------------- |
|
||||
| list | GET \<collection URL\> |
|
||||
| get | GET \<resource URL\> |
|
||||
| create | POST \<collection URL\> |
|
||||
| update | PUT \<resource URL\> |
|
||||
| destroy | DELETE \<resource URL\> |
|
||||
|
||||
标准的 REST API 映射下,actionName 可以缺失,但也可以显式声明,当指定 actionName 时,将不受 Request Method 影响。相关 HTTP 格式如下:
|
||||
|
||||
```bash
|
||||
# 独立资源
|
||||
<requestMethod> /api/<resourceName>:<actionName>?<queryString>
|
||||
<requestMethod> /api/<resourceName>:<actionName>/<resourceKey>?<queryString>
|
||||
|
||||
# 关系资源
|
||||
<requestMethod> /api/<associatedName>/<associatedKey>/<resourceName>:<actionName>?<queryString>
|
||||
<requestMethod> /api/<associatedName>/<associatedKey>/<resourceName>:<actionName>/<resourceKey>?<queryString>
|
||||
|
||||
<body> # 非 GET 请求时,可以提供 body 数据,一般为 JSON 格式
|
||||
```
|
||||
|
||||
为了让大家更理解 Resource Action API 设计,我们接下来举几个具体的例子:
|
||||
|
||||
##### 查看文章列表
|
||||
|
||||
```bash
|
||||
GET /api/posts?filter={"col1": "val1"}&fields=col1,col2&sort=-created_at
|
||||
```
|
||||
|
||||
对应的 context.action.params 为:
|
||||
|
||||
```ts
|
||||
{
|
||||
actionName: 'list',
|
||||
resourceName: 'posts',
|
||||
filter: {'col1': 'val1'},
|
||||
fields: ['col1', 'col2'],
|
||||
sort: ['-created_at'],
|
||||
}
|
||||
```
|
||||
|
||||
##### 新增文章
|
||||
|
||||
```bash
|
||||
POST /api/posts
|
||||
|
||||
{"title": "title1"}
|
||||
```
|
||||
|
||||
对应的 context.action.params 为:
|
||||
|
||||
```ts
|
||||
{
|
||||
resourceName: 'posts',
|
||||
actionName: 'create',
|
||||
values: {
|
||||
title: 'title1',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
##### 查看文章详情
|
||||
|
||||
```bash
|
||||
GET /api/posts/1?fields=col1,col2
|
||||
```
|
||||
|
||||
对应的 context.action.params 为:
|
||||
|
||||
```ts
|
||||
{
|
||||
resourceName: 'posts',
|
||||
resourceKey: 1,
|
||||
actionName: 'get',
|
||||
fields: ['col1', 'col2'],
|
||||
}
|
||||
```
|
||||
|
||||
##### 更新文章
|
||||
|
||||
```bash
|
||||
PUT /api/posts/1
|
||||
|
||||
{"title": "title1"}
|
||||
```
|
||||
|
||||
对应的 context.action.params 为:
|
||||
|
||||
```ts
|
||||
{
|
||||
resourceName: 'posts',
|
||||
resourceKey: 1,
|
||||
actionName: 'update',
|
||||
values: {
|
||||
title: 'title1',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
##### 删除文章
|
||||
|
||||
```bash
|
||||
DELETE /api/posts/1
|
||||
```
|
||||
|
||||
对应的 context.action.params 为:
|
||||
|
||||
```ts
|
||||
{
|
||||
resourceName: 'posts',
|
||||
resourceKey: 1,
|
||||
actionName: 'destroy',
|
||||
}
|
||||
```
|
||||
|
||||
##### 文章评论列表
|
||||
|
||||
```bash
|
||||
GET /api/posts/1/comments?filter={"col1": "val1"}&fields=col1,col2&sort=-created_at
|
||||
```
|
||||
|
||||
对应的 context.action.params 为:
|
||||
|
||||
```ts
|
||||
{
|
||||
associatedName: 'posts',
|
||||
associatedKey: 1,
|
||||
resourceName: 'comments',
|
||||
actionName: 'list',
|
||||
filter: {'col1': 'val1'},
|
||||
fields: ['col1', 'col2'],
|
||||
sort: ['-created_at'],
|
||||
}
|
||||
```
|
||||
|
||||
##### 文章评论详情
|
||||
|
||||
```bash
|
||||
GET /api/posts/1/comments/2
|
||||
```
|
||||
|
||||
对应的 context.action.params 为:
|
||||
|
||||
```ts
|
||||
{
|
||||
associatedName: 'posts',
|
||||
associatedKey: 1,
|
||||
resourceName: 'comments',
|
||||
resourceKey: 2,
|
||||
actionName: 'get',
|
||||
}
|
||||
```
|
||||
|
||||
##### 显式声明 actionName 的例子
|
||||
|
||||
```bash
|
||||
POST /api/users:login
|
||||
|
||||
{"username": "admin", "password": "password"}
|
||||
```
|
||||
|
||||
对应的 context.action.params 为:
|
||||
|
||||
```ts
|
||||
{
|
||||
resourceName: 'users',
|
||||
actionName: 'login',
|
||||
values: {
|
||||
username: 'admin',
|
||||
password: 'password',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
当不指定 actionName 时,默认为 create,对应的是「新建用户」操作,但是指定 actionName=login 时,就变为了「用户登录」操作了。
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
|
||||
在 Resource Action API 的设计理念里,即使类似 login、register、logout 等非标准的 REST API 也可以非常方便的扩展。大家可以更专注于 action 本身,而不必纠结于 request method 和 route 应该如何设计或派发,也不需要考虑 routes 优先级等问题。
|
||||
|
||||
</Alert>
|
||||
|
||||
|
||||
### resourcer.registerAction(name: ActionName, options: ActionOptions) <Badge>待完善</Badge>
|
||||
|
||||
原 resourcer.registerActionHandler
|
||||
|
||||
- name:操作名称
|
||||
- options:操作配置
|
||||
|
||||
可用于注册全局的或某资源特有的 action。
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
|
||||
与 resourcer.define 不同,registerAction 的 actionName 支持三种格式:
|
||||
|
||||
- `<actionName>` 全局操作
|
||||
- `<resourceName>:<actionName>` 某资源特有操作
|
||||
- `<associatedName>.<resourceName>:<actionName>` 某关系资源特有操作
|
||||
|
||||
更复杂判断条件,需要结合 `resourcer.use` 方法一起处理
|
||||
|
||||
</Alert>
|
||||
|
||||
示例
|
||||
|
||||
```ts
|
||||
resourcer.registerAction('actionName', async (ctx, next) => {
|
||||
await next();
|
||||
});
|
||||
|
||||
// 带配置
|
||||
resourcer.registerAction('actionName', {
|
||||
filter,
|
||||
fields,
|
||||
middlewares: [],
|
||||
handler: async (ctx, next) => {
|
||||
await next();
|
||||
},
|
||||
});
|
||||
|
||||
resourcer.registerAction('resourceName:actionName', async (ctx, next) => {
|
||||
await next();
|
||||
});
|
||||
|
||||
resourcer.registerAction('associatedName.resourceName:actionName', async (ctx, next) => {
|
||||
await next();
|
||||
});
|
||||
```
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
|
||||
resourcer 使用 koa-compress 来处理中间件,是一种洋葱圈模型,因此在 action handler 里也不要忘了 `next()`,不然会影响后置逻辑的处理。
|
||||
|
||||
</Alert>
|
||||
|
||||
|
||||
更复杂的情况:
|
||||
|
||||
```ts
|
||||
resourcer.use(async (ctx, next) => {
|
||||
const { actionName, resourceName } = ctx.action.params;
|
||||
if (actionName === 'foo') {
|
||||
// 其他判断条件
|
||||
// 不符合条件的 404 处理
|
||||
ctx.throw(404);
|
||||
}
|
||||
await next();
|
||||
});
|
||||
```
|
||||
|
||||
### resourcer.registerActions(actions) <Badge>待完善</Badge>
|
||||
|
||||
原 resourcer.registerActionHandlers
|
||||
|
||||
批量注册 actions,用法同 [resourcer.registerAction](#resourcerregisterActionname-actionname-handler-handlertype)
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
resourcer.registerActions({
|
||||
async foo(ctx, next) {
|
||||
await next();
|
||||
},
|
||||
async bar(ctx, next) {
|
||||
await next();
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### resourcer.registerActionMiddleware(actionName, handler) <Badge>未实现</Badge>
|
||||
|
||||
为某操作(action)注册特有的 middleware
|
||||
|
||||
### resourcer.registerResourceMiddleware(resourceName, options) <Badge>未实现</Badge>
|
||||
|
||||
为某资源(resource)注册特有的 middleware
|
||||
|
||||
### resourcer.use
|
||||
|
||||
注册 resourcer 全局 middleware
|
||||
|
||||
```ts
|
||||
resourcer.use(async (ctx, next) => {
|
||||
// code...
|
||||
await next();
|
||||
})
|
||||
```
|
||||
|
||||
<Alert title="为什么要提供不同的中间件注册方法?" type="warning">
|
||||
|
||||
虽然大部分框架都提供了中间件,但是中间件的执行顺序(优先级)依赖于编码顺序,这种方式非常不利于插件化管理。因此,在 Resourcer 设计思想里,将中间件做了分层,不同层级的 middlewares 不依赖于编码顺序,而是如下顺序:
|
||||
|
||||
1. 首先,koa 层:`koa.use`
|
||||
2. 其次,resourcer 层:`resourcer.use`
|
||||
3. 再次,resource 层(每个资源独立):`resourcer.registerActionMiddleware`
|
||||
4. 最后,action 层:`resourcer.registerResourceMiddleware`
|
||||
|
||||
不过,每层的中间件执行顺序还依赖于编码顺序,如有需要再进行更细微的改进。
|
||||
|
||||
</Alert>
|
@ -1,87 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/sdk'
|
||||
order: 5
|
||||
# toc: menu
|
||||
---
|
||||
|
||||
# @nocobase/sdk <Badge>待完善</Badge>
|
||||
|
||||
## 介绍
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn add @nocobase/sdk
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
SDK:
|
||||
|
||||
|
||||
```ts
|
||||
import API from '@nocobase/sdk';
|
||||
|
||||
const api = new API({
|
||||
baseUrl: 'http://localhost:3000/api'
|
||||
});
|
||||
|
||||
// 细节待补充
|
||||
await api.resource('demos').list();
|
||||
await api.resource('demos').create();
|
||||
await api.resource('demos').get();
|
||||
await api.resource('demos').update();
|
||||
await api.resource('demos').destroy();
|
||||
```
|
||||
|
||||
HTTP API:
|
||||
|
||||
```bash
|
||||
GET http://localhost:3000/api/demos
|
||||
POST http://localhost:3000/api/demos
|
||||
GET http://localhost:3000/api/demos/1
|
||||
PUT http://localhost:3000/api/demos/1
|
||||
DELETE http://localhost:3000/api/demos/1
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```bash
|
||||
# 独立资源
|
||||
<requestMethod> /api/<resourceName>:<actionName>?<queryString>
|
||||
<requestMethod> /api/<resourceName>:<actionName>/<resourceKey>?<queryString>
|
||||
|
||||
# 关系资源
|
||||
<requestMethod> /api/<associatedName>/<associatedKey>/<resourceName>:<actionName>?<queryString>
|
||||
<requestMethod> /api/<associatedName>/<associatedKey>/<resourceName>:<actionName>/<resourceKey>?<queryString>
|
||||
|
||||
<body> # 非 GET 请求时,可以提供 body 数据,一般为 JSON 格式
|
||||
```
|
||||
|
||||
## SDK
|
||||
|
||||
与 context.action.params 参数大体一致:
|
||||
|
||||
```ts
|
||||
api.resource('<resourceName>').<actionName>({
|
||||
resourceKey,
|
||||
filter,
|
||||
fields,
|
||||
sort,
|
||||
page,
|
||||
perPage,
|
||||
values,
|
||||
});
|
||||
|
||||
// 关系资源
|
||||
api.resource('<associatedName>.<resourceName>').<actionName>({
|
||||
associatedKey,
|
||||
resourceKey,
|
||||
filter,
|
||||
fields,
|
||||
sort,
|
||||
page,
|
||||
perPage,
|
||||
values,
|
||||
});
|
||||
```
|
@ -1,146 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/server'
|
||||
order: 5
|
||||
# toc: menu
|
||||
---
|
||||
|
||||
# @nocobase/server
|
||||
|
||||
## 介绍
|
||||
|
||||
提供最小核心的 NocoBase 服务
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn add @nocobase/server
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { Application } from '@nocobase/server';
|
||||
|
||||
const api = new Application({
|
||||
database: {},
|
||||
resourcer: {},
|
||||
});
|
||||
|
||||
// 配置数据表
|
||||
api.database.table({
|
||||
name: 'demos',
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
],
|
||||
});
|
||||
|
||||
await api.database.sync();
|
||||
|
||||
app.listen(3000);
|
||||
```
|
||||
|
||||
HTTP API:
|
||||
|
||||
```bash
|
||||
GET http://localhost:3000/api/demos
|
||||
POST http://localhost:3000/api/demos
|
||||
GET http://localhost:3000/api/demos/1
|
||||
PUT http://localhost:3000/api/demos/1
|
||||
DELETE http://localhost:3000/api/demos/1
|
||||
```
|
||||
|
||||
SDK:
|
||||
|
||||
```ts
|
||||
import API from '@nocobase/sdk';
|
||||
|
||||
const api = new API({
|
||||
baseUrl: 'http://localhost:3000/api'
|
||||
});
|
||||
|
||||
// 细节待定
|
||||
api.resource('demos').list();
|
||||
api.resource('demos').create();
|
||||
api.resource('demos').get();
|
||||
api.resource('demos').update();
|
||||
api.resource('demos').destroy();
|
||||
```
|
||||
|
||||
## Middlewares
|
||||
|
||||
### initializeActionParams
|
||||
|
||||
初始化 action.params
|
||||
|
||||
### appDistServe
|
||||
|
||||
为 app dist 提供静态文件代理服务
|
||||
|
||||
### dbResourceRouter
|
||||
|
||||
resource 动态初始化,如果 resource 不存在,从 database 里同步。
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
与 resourcer.koaRestApiMiddleware 方法存在大量重复,需要把 database 与 resource 的同步逻辑提炼出来
|
||||
</Alert>
|
||||
|
||||
### demoBlacklistedActions
|
||||
|
||||
actions 黑名单
|
||||
|
||||
```ts
|
||||
app.use(demoBlacklistedActions({
|
||||
blacklist: [],
|
||||
}));
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Server
|
||||
|
||||
Server 继承 Koa,更多用法可查阅 Koa API
|
||||
|
||||
#### server.constructor
|
||||
|
||||
初始化 server 实例
|
||||
|
||||
#### server.database
|
||||
|
||||
当前 server 实例的 database
|
||||
|
||||
#### server.resourcer
|
||||
|
||||
当前 server 实例的 resourcer
|
||||
|
||||
#### server.pluginManager <Badge>未实现</Badge>
|
||||
|
||||
当前 server 实例的 pluginManager
|
||||
|
||||
### PluginManager <Badge>未实现</Badge>
|
||||
|
||||
插件管理器
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
不同 server 实例也可能需要 PluginManager,后续 CLI 和后台可管理也都需要,插件管理器独立出来处理比较合适。
|
||||
</Alert>
|
||||
|
||||
#### pluginManager.register(name, options)
|
||||
|
||||
注册插件
|
||||
|
||||
#### pluginManager.has(name)
|
||||
|
||||
判断插件是否存在
|
||||
|
||||
#### pluginManager.get(name)
|
||||
|
||||
获取当前插件实例
|
||||
|
||||
#### pluginManager.load()
|
||||
|
||||
加载插件
|
||||
|
||||
#### pluginManager.reload()
|
||||
|
||||
重载插件
|
||||
|
@ -1,72 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/test'
|
||||
order: 7
|
||||
---
|
||||
|
||||
# @nocobase/test <Badge>未实现</Badge>
|
||||
|
||||
## mockDatabase
|
||||
|
||||
为 database 提供的测试套件,同时提供数据 mock(使用 mockjs)。
|
||||
|
||||
```ts
|
||||
import { mockDatabase } from '@nocobase/test';
|
||||
|
||||
describe('test', () => {
|
||||
let db;
|
||||
|
||||
beforeEach(async () => {
|
||||
db = mockDatabase({});
|
||||
db.table({
|
||||
name: 'examples',
|
||||
fields: [{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
mock: {
|
||||
"1-10": "★"
|
||||
},
|
||||
}],
|
||||
});
|
||||
await db.sync();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await db.close();
|
||||
});
|
||||
|
||||
it('test model', () => {
|
||||
const Test = db.getModel('tests');
|
||||
Test.mockCreate({});
|
||||
Test.mockBulkCreate([{}]);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## mockServer
|
||||
|
||||
为 server 提供的测试套件
|
||||
|
||||
```ts
|
||||
import { mockServer } from '@nocobase/test';
|
||||
|
||||
describe('test', () => {
|
||||
let api;
|
||||
|
||||
beforeEach(async () => {
|
||||
api = mockServer({});
|
||||
await api.database.sync();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await api.database.close();
|
||||
});
|
||||
|
||||
it('test resource', () => {
|
||||
await api.resource('demos').get();
|
||||
});
|
||||
|
||||
it('test request', () => {
|
||||
await api.request().get('/');
|
||||
});
|
||||
});
|
||||
```
|
@ -1,13 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/ui-schema'
|
||||
order: 4
|
||||
---
|
||||
|
||||
# @nocobase/ui-schema <Badge>未实现</Badge>
|
||||
|
||||
v0.5 前端完全重构了,减少了对 umijs 的直接依赖,前端后续会拆分成四部分
|
||||
|
||||
- ui-schema 核心组件库
|
||||
- ui-router 前端路由
|
||||
- sdk 供客户端使用
|
||||
- create-nocobase-app 项目脚手架,基于 umijs
|
@ -1,88 +0,0 @@
|
||||
---
|
||||
title: WEB API 设计
|
||||
order: 2
|
||||
toc: menu
|
||||
nav:
|
||||
title: 核心
|
||||
order: 2
|
||||
---
|
||||
|
||||
# WEB API 设计
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
以下各代码片段,仅供阅读参考,可能与实际代码略有偏差。
|
||||
</Alert>
|
||||
|
||||
和常规的 MVC 思路不同,NocoBase 的 Server 非常简单,先来一段简单例子代码感受一下:
|
||||
|
||||
```ts
|
||||
import { Application } from '@nocobase/server';
|
||||
|
||||
const api = new Application({
|
||||
database: {},
|
||||
resourcer: {},
|
||||
});
|
||||
|
||||
// 配置数据表
|
||||
api.database.table({
|
||||
name: 'users',
|
||||
fields: [
|
||||
{ type: 'string', name: 'username' },
|
||||
{ type: 'password', name: 'password' },
|
||||
],
|
||||
});
|
||||
|
||||
api.listen(3000);
|
||||
```
|
||||
|
||||
相对应的 HTTP API:
|
||||
|
||||
```bash
|
||||
GET http://localhost:3000/api/users
|
||||
POST http://localhost:3000/api/users
|
||||
GET http://localhost:3000/api/users/1
|
||||
PUT http://localhost:3000/api/users/1
|
||||
DELETE http://localhost:3000/api/users/1
|
||||
```
|
||||
|
||||
内置了基础的 REST API,除此之外还可以自行扩展,如:
|
||||
|
||||
```ts
|
||||
api.resourcer.registerAction('users:login', async (ctx, next) => {
|
||||
// 代码省略
|
||||
});
|
||||
```
|
||||
|
||||
HTTP API 新增了扩展
|
||||
|
||||
```bash
|
||||
POST http://localhost:3000/api/users:login
|
||||
```
|
||||
|
||||
配合 SDK 就是这样的了
|
||||
|
||||
```ts
|
||||
// 常用的 REST API
|
||||
|
||||
// GET http://localhost:3000/api/users
|
||||
api.resource('users').list();
|
||||
// POST http://localhost:3000/api/users
|
||||
api.resource('users').create();
|
||||
// GET http://localhost:3000/api/users/1
|
||||
api.resource('users').get();
|
||||
// PUT http://localhost:3000/api/users/1
|
||||
api.resource('users').update();
|
||||
// DELETE http://localhost:3000/api/users/1
|
||||
api.resource('users').destroy();
|
||||
|
||||
// 扩展的非 REST 风格的 API
|
||||
|
||||
// POST http://localhost:3000/api/users:login
|
||||
api.resource('users').login();
|
||||
// POST http://localhost:3000/api/users:register
|
||||
api.resource('users').register();
|
||||
// POST http://localhost:3000/api/users:logout
|
||||
api.resource('users').logout();
|
||||
// POST http://localhost:3000/api/users:export
|
||||
api.resource('users').export();
|
||||
```
|
@ -1,118 +0,0 @@
|
||||
---
|
||||
title: 配置文件
|
||||
order: 3
|
||||
toc: menu
|
||||
---
|
||||
|
||||
# 配置文件
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
暂时只支持 <code>.env</code> 环境变量配置,这种方式有些局限,接下来会提供更完整的 <code>.nocobaserc.ts</code> 文件,用于支持更灵活的配置,包括但不局限于数据库信息、插件等。
|
||||
</Alert>
|
||||
|
||||
## .env
|
||||
|
||||
### 数据库信息
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
暂时只提供了核心的一些配置参数,后续还需优化
|
||||
</Alert>
|
||||
|
||||
#### DB_DIALECT
|
||||
|
||||
#### DB_HOST
|
||||
|
||||
#### DB_PORT
|
||||
|
||||
#### DB_DATABASE
|
||||
|
||||
#### DB_USER
|
||||
|
||||
#### DB_PASSWORD
|
||||
|
||||
#### DB_LOG_SQL
|
||||
|
||||
### APP 信息
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
暂时只提供了核心的一些配置参数,后续还需优化
|
||||
</Alert>
|
||||
|
||||
#### NOCOBASE_ENV
|
||||
|
||||
NOCOBASE 环境
|
||||
|
||||
#### API_PREFIX
|
||||
|
||||
API 前缀
|
||||
|
||||
#### API_PORT
|
||||
|
||||
API 端口
|
||||
|
||||
#### APP_DIST
|
||||
|
||||
APP 前端静态文件路径
|
||||
|
||||
#### APP_USE_STATIC_SERVER
|
||||
|
||||
APP 前端静态文件是否使用 koa-static 代理。如不需要,你也可以使用 nginx 等服务。
|
||||
|
||||
### ADMIN 账号
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
仅用于初始化配置,后续会集成到 cli 里,安装时用户可输入。
|
||||
</Alert>
|
||||
|
||||
#### ADMIN_EMAIL
|
||||
|
||||
初始化的管理员邮箱
|
||||
|
||||
#### ADMIN_PASSWORD
|
||||
|
||||
初始化的管理员密码
|
||||
|
||||
### 文件管理器插件
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
仅用于初始化,目前还未提供插件管理面板,如果有修改,需要去 storages 表里修改。后续优化会集成到 cli 里,在插件安装时由用户输入,或通过插件管理器修改。
|
||||
</Alert>
|
||||
|
||||
#### STORAGE_TYPE
|
||||
|
||||
目前已支持的 storage 有:
|
||||
|
||||
- `local` 本地
|
||||
- `ali-oss` 阿里云 OSS
|
||||
|
||||
#### LOCAL_STORAGE_USE_STATIC_SERVER
|
||||
|
||||
文件静态文件是否使用 koa-static 代理。如不需要,你也可以使用 nginx 等服务。
|
||||
|
||||
#### LOCAL_STORAGE_BASE_URL
|
||||
|
||||
静态文件地址前缀
|
||||
|
||||
#### ALI_OSS_REGION
|
||||
#### ALI_OSS_ACCESS_KEY_ID
|
||||
#### ALI_OSS_ACCESS_KEY_SECRET
|
||||
#### ALI_OSS_BUCKET
|
||||
#### ALI_OSS_STORAGE_BASE_URL
|
||||
|
||||
## .nocobaserc.ts
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
暂不支持 .nocobaserc 配置
|
||||
</Alert>
|
||||
|
||||
### 数据库
|
||||
|
||||
待补充...
|
||||
|
||||
### APP 信息
|
||||
|
||||
待补充...
|
||||
|
||||
### 配置插件
|
||||
|
||||
待补充...
|
@ -1,196 +0,0 @@
|
||||
---
|
||||
title: 快速上手
|
||||
order: 2
|
||||
toc: menu
|
||||
---
|
||||
|
||||
# 快速上手
|
||||
|
||||
为大家提供了三种方式安装并运行 NocoBase
|
||||
|
||||
- [Npm & Yarn](#npm--yarn):仅用于无代码平台体验
|
||||
- [Docker](#docker):仅用于无代码平台体验
|
||||
- [Git](#git):参与项目开发
|
||||
|
||||
<Alert title="安装前准备" type="warning">
|
||||
|
||||
**OS:**
|
||||
|
||||
- Docker
|
||||
- Linux
|
||||
- MacOS(仅开发环境)
|
||||
- Windows(仅开发环境),没有在 win 平台测试过,可能存在一些小问题
|
||||
|
||||
**Node:**
|
||||
|
||||
- Node.js 12.x or 14.x
|
||||
|
||||
**Database(任选其一):**
|
||||
|
||||
现阶段还是以关系型数据库为主,接下来陆续兼容更多的关系型数据库。未来 @nocobase/database 稳定之后,会考虑适配 MongoDB。因为有几处用到了 JSON 类型字段,不同数据库的 JSON 字段有差异,现只兼容了 PostgreSQL 数据库的查询。
|
||||
|
||||
- PostgreSQL 10.x+(推荐)
|
||||
- MySQL 5.7.x+(JSON 类型查询有问题,后续会提供支持)
|
||||
- MariaDB 10.x(未知,后续会提供支持)
|
||||
- SQLite 3(未知,后续会提供支持)
|
||||
|
||||
</Alert>
|
||||
|
||||
## Npm & Yarn
|
||||
|
||||
创建并进入新目录
|
||||
|
||||
```bash
|
||||
mkdir my-nocobase-project && cd my-nocobase-project
|
||||
```
|
||||
|
||||
使用 yarn 或 npm 包管理器进行初始化
|
||||
|
||||
```bash
|
||||
yarn init # or npm init
|
||||
```
|
||||
|
||||
安装 NocoBase 依赖
|
||||
|
||||
```bash
|
||||
yarn add @nocobase/api @nocobase/app
|
||||
```
|
||||
|
||||
复制并配置 .env,[环境变量说明点此查看](config.md#.env)
|
||||
|
||||
```bash
|
||||
cp -r node_modules/@nocobase/api/.env.example .env
|
||||
```
|
||||
|
||||
数据库初始化
|
||||
|
||||
```bash
|
||||
yarn nocobase db-init
|
||||
```
|
||||
|
||||
启动应用
|
||||
|
||||
```bash
|
||||
yarn nocobase start
|
||||
```
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
|
||||
为什么是 @nocobase/api 和 @nocobase/app,而不是 create-nocobase-project?
|
||||
|
||||
早之前想提供 create-nocobase-project 的,但是有些细节还没想清楚,暂时不会提供,目前只提供了封装度较高的 @nocobase/api 和 @nocobase/app 两个前后端包,如果有二次开发需要,可 fork 相关 api 或 app 源码,再重新构建。
|
||||
|
||||
</Alert>
|
||||
|
||||
|
||||
## Docker
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
Docker 镜像暂未发布
|
||||
</Alert>
|
||||
|
||||
为了更方便的安装与部署,NocoBase 也发布了 Docker 镜像 `nocobase/nocobase`,创建并配置 `docker-compose.yml` 文件,样例如下:
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:10
|
||||
networks:
|
||||
- nocobase
|
||||
environment:
|
||||
POSTGRES_USER: nocobase
|
||||
POSTGRES_DB: nocobase
|
||||
POSTGRES_PASSWORD: nocobase
|
||||
nocobase:
|
||||
image: nocobase/nocobase:latest
|
||||
networks:
|
||||
- nocobase
|
||||
ports:
|
||||
- 23000:23000
|
||||
environment:
|
||||
DB_DIALECT: postgres
|
||||
DB_HOST: postgres
|
||||
DB_PORT: 5432
|
||||
DB_DATABASE: nocobase
|
||||
DB_USER: nocobase
|
||||
DB_PASSWORD: nocobase
|
||||
|
||||
API_PORT: 23000
|
||||
|
||||
ADMIN_EMAIL: admin@nocobase.com
|
||||
ADMIN_PASSWORD: admin
|
||||
|
||||
networks:
|
||||
nocobase:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
初始化并启动 NocoBase 应用
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
|
||||
## Git
|
||||
|
||||
通过 git 克隆 nocobase 仓库
|
||||
|
||||
```bash
|
||||
git clone https://github.com/nocobase/nocobase.git my-nocobase-project
|
||||
```
|
||||
|
||||
进入项目目录
|
||||
|
||||
```bash
|
||||
cd my-nocobase-project
|
||||
```
|
||||
|
||||
复制并配置 .env,[环境变量说明点此查看](#)
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
安装依赖
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
构建 packages 依赖
|
||||
|
||||
```bash
|
||||
yarn bootstrap
|
||||
yarn build
|
||||
```
|
||||
|
||||
数据库初始化
|
||||
|
||||
```bash
|
||||
yarn db-migrate init
|
||||
```
|
||||
|
||||
启动应用
|
||||
|
||||
```bash
|
||||
yarn start
|
||||
```
|
||||
|
||||
开发过程中其他常用的命令还有:
|
||||
|
||||
```bash
|
||||
### 测试 ###
|
||||
|
||||
yarn test
|
||||
# or
|
||||
yarn test packages/<name> packages/<name>
|
||||
|
||||
### 打包 ###
|
||||
|
||||
yarn build
|
||||
# or
|
||||
yarn build <package_name_1> <package_name_2> ...
|
||||
```
|
@ -1,49 +0,0 @@
|
||||
---
|
||||
title: 介绍
|
||||
order: 1
|
||||
toc: menu
|
||||
nav:
|
||||
title: 指南
|
||||
order: 1
|
||||
---
|
||||
|
||||
## NocoBase 是什么?
|
||||
|
||||
NocoBase 是一个开源免费的无代码、低代码开发平台。 无论是不懂编程的业务主管,还是精通编程的开发人员,都可以快速搭建各类定制化、私有部署的协作平台、管理系统。
|
||||
|
||||
## 架构
|
||||
|
||||
<img src="../nocobase.png" style="max-width: 800px;width:100%"/>
|
||||
|
||||
### 微内核
|
||||
|
||||
NocoBase 采用微内核架构,框架只保留核心的概念,具体各类功能都以插件的形式扩展。各个包可以拆出来单独或组合使用,也可用于现有项目中。
|
||||
|
||||
### 插件化
|
||||
|
||||
所有的功能需求都通过插件形式扩展,除了现有的几个核心插件以外,开发者还可以自由的扩展,包括但不局限于:
|
||||
|
||||
- Collection - 数据表
|
||||
- CollectionField - 字段
|
||||
- DataType - 存储类型
|
||||
- UI Schema/Component - 组件
|
||||
- Template - 模板
|
||||
- Model/Repository - 模型
|
||||
- Schema Builder - 构造器
|
||||
- Resource/Service - 资源/服务
|
||||
- Action - 方法
|
||||
- Hook/Event - 事件
|
||||
- Middleware - 中间件
|
||||
- Resource Middleware
|
||||
- Action Middleware
|
||||
- UI
|
||||
- UI Schema/Component - 前端组件
|
||||
- Router - 前端路由
|
||||
|
||||
### 配置化
|
||||
|
||||
配置化驱动,为了方便各场景配置需求,配置有三种写法:
|
||||
|
||||
- 直接写在代码里,多用于处理动态配置
|
||||
- 保存在文件里,多用于系统表配置或纯开发配置
|
||||
- 保存在数据表里,多用于业务表配置
|
579
docs/index.md
579
docs/index.md
@ -1,20 +1,563 @@
|
||||
---
|
||||
title: NocoBase - An open source and free no-code development platform
|
||||
hero:
|
||||
title: NocoBase
|
||||
desc: An open source and free no-code development platform
|
||||
actions:
|
||||
- text: Getting Started
|
||||
link: /guide
|
||||
features:
|
||||
- icon: https://gw.alipayobjects.com/zos/bmw-prod/881dc458-f20b-407b-947a-95104b5ec82b/k79dm8ih_w144_h144.png
|
||||
title: Feature 1
|
||||
desc: Balabala
|
||||
- icon: https://gw.alipayobjects.com/zos/bmw-prod/d60657df-0822-4631-9d7c-e7a869c2f21c/k79dmz3q_w126_h126.png
|
||||
title: Feature 2
|
||||
desc: Balabala
|
||||
- icon: https://gw.alipayobjects.com/zos/bmw-prod/d1ee0c6f-5aed-4a45-a507-339a4bfe076c/k7bjsocq_w144_h144.png
|
||||
title: Feature 3
|
||||
desc: Balabala
|
||||
footer: Copyright © 2020-2021 NocoBase. All rights reserved.
|
||||
title: 基础概念
|
||||
toc: menu
|
||||
---
|
||||
|
||||
# NocoBase
|
||||
|
||||
考虑到大家是初次接触 NocoBase,开发文档的第一篇,从宏观的角度,带大家了解 NocoBase 的基础概念。NocoBase 采用微内核的架构,框架只保留核心概念,各类功能都以插件形式扩展。
|
||||
|
||||
## 微服务 - Microservices
|
||||
|
||||
先来个例子一睹为快,新建一个 server.js 文件,代码如下:
|
||||
|
||||
```ts
|
||||
const Server = require('@nocobase/server');
|
||||
|
||||
const server = new Server();
|
||||
|
||||
server.collection({
|
||||
name: 'users',
|
||||
fields: [
|
||||
{ type: 'string', name: 'username' },
|
||||
{ type: 'password', name: 'password' },
|
||||
],
|
||||
});
|
||||
|
||||
server.start(process.argv);
|
||||
```
|
||||
|
||||
终端运行
|
||||
|
||||
```bash
|
||||
# 根据配置生成数据库表结构
|
||||
node server.js db sync
|
||||
# 启动应用
|
||||
node server.js start --port=3000
|
||||
```
|
||||
|
||||
相关 users 表的 REST API 就生成了
|
||||
|
||||
```bash
|
||||
GET http://localhost:3000/api/users
|
||||
POST http://localhost:3000/api/users
|
||||
GET http://localhost:3000/api/users/1
|
||||
PUT http://localhost:3000/api/users/1
|
||||
DELETE http://localhost:3000/api/users/1
|
||||
```
|
||||
|
||||
除了内置的 REST API 以外,还可以自定义其他操作,如登录、注册、注销等。
|
||||
|
||||
```ts
|
||||
server.registerActions({
|
||||
async login(ctx, next) {},
|
||||
async register(ctx, next) {},
|
||||
async logout(ctx, next) {},
|
||||
}, {
|
||||
resourceName: 'users',
|
||||
});
|
||||
```
|
||||
|
||||
以上操作的 HTTP API 为:
|
||||
|
||||
```bash
|
||||
POST http://localhost:3000/api/users:login
|
||||
POST http://localhost:3000/api/users:register
|
||||
POST http://localhost:3000/api/users:logout
|
||||
```
|
||||
|
||||
自定义的 HTTP API 依旧保持 REST API 的风格,以 `<resourceName>:<actionName>` 格式表示。REST API 也可以显式指定 actionName,当指定了 actionName 时,无所谓使用什么 Request Method,如:
|
||||
|
||||
```bash
|
||||
GET http://localhost:3000/api/users:list
|
||||
POST http://localhost:3000/api/users:create
|
||||
GET http://localhost:3000/api/users:get/1
|
||||
POST http://localhost:3000/api/users:update/1
|
||||
POST http://localhost:3000/api/users:destroy/1
|
||||
```
|
||||
|
||||
结合客户端 SDK 是这样的:
|
||||
|
||||
```ts
|
||||
const { ClientSDK } = require('@nocobase/client');
|
||||
|
||||
const client = new ClientSDK();
|
||||
|
||||
await client.resource('users').list();
|
||||
await client.resource('users').create();
|
||||
await client.resource('users').get();
|
||||
await client.resource('users').update();
|
||||
await client.resource('users').destroy();
|
||||
await client.resource('users').login();
|
||||
await client.resource('users').register();
|
||||
await client.resource('users').logout();
|
||||
```
|
||||
|
||||
## 数据集 - Collection
|
||||
|
||||
上述例子,通过 `server.collection()` 方法定义数据的 Schema,Schema 的核心为字段配置,字段类型包括:
|
||||
|
||||
Attribute 属性
|
||||
|
||||
- Boolean 布尔型
|
||||
- String 字符串
|
||||
- Text 长文本
|
||||
- Integer 整数型
|
||||
- Float 浮点型
|
||||
- Decimal 货币
|
||||
- Json/Jsonb/Array 不同数据库的 JSON 类型不一致,存在兼容性问题
|
||||
- Time 时间
|
||||
- Date 日期
|
||||
- Virtual 虚拟字段
|
||||
- Reference 引用
|
||||
- Formula 计算公式
|
||||
- Context 上下文
|
||||
- Password 密码
|
||||
- Sort 排序
|
||||
|
||||
Association/Realtion 关系
|
||||
|
||||
- HasOne 一对一
|
||||
- HasMany 一对多
|
||||
- BelongsTo 多对一
|
||||
- BelongsToMany 多对多
|
||||
- Polymorphic 多态
|
||||
|
||||
比如一个微型博客的表结构可以这样设计:
|
||||
|
||||
```ts
|
||||
// 用户
|
||||
server.collection({
|
||||
name: 'users',
|
||||
fields: [
|
||||
{ type: 'string', name: 'username', unique: true },
|
||||
{ type: 'password', name: 'password', unique: true },
|
||||
{ type: 'hasMany', name: 'posts' },
|
||||
],
|
||||
});
|
||||
|
||||
// 文章
|
||||
server.collection({
|
||||
name: 'posts',
|
||||
fields: [
|
||||
{ type: 'string', name: 'title' },
|
||||
{ type: 'text', name: 'content' },
|
||||
{ type: 'belongsToMany', name: 'tags' },
|
||||
{ type: 'hasMany', name: 'comments' },
|
||||
{ type: 'belongsTo', name: 'author', target: 'users' },
|
||||
],
|
||||
});
|
||||
|
||||
// 标签
|
||||
server.collection({
|
||||
name: 'tags',
|
||||
fields: [
|
||||
{ type: 'string', name: 'name' },
|
||||
{ type: 'belongsToMany', name: 'posts' },
|
||||
],
|
||||
});
|
||||
|
||||
// 评论
|
||||
server.collection({
|
||||
name: 'comments',
|
||||
fields: [
|
||||
{ type: 'text', name: 'content' },
|
||||
{ type: 'belongsTo', name: 'user' },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
存在外键关联时,也无需顾虑建表和字段的顺序,`db sync` 时会自动处理。为了方便开发,提供了一些有用的属性或方法:
|
||||
|
||||
- `server.db` 数据库实例
|
||||
- `server.db.getModel()` 获取 Model
|
||||
- `server.db.getTable()` 获取 Schema Table
|
||||
|
||||
## 资源 & 操作 - Resource & Action
|
||||
|
||||
不同于常规的 MVC + Router,NocoBase 的路由(Resourcer)基于资源(Resource)和操作(Action)设计,将 REST 和 RPC 结合起来,提供更为灵活且统一的 Resource Action API,Action 不局限于增删改查。资源可以通过 `server.resource` 方法定义,如:
|
||||
|
||||
```ts
|
||||
server.resource({
|
||||
name: 'users',
|
||||
actions: {
|
||||
list: {
|
||||
fields: ['id', 'username'], // 只输出 id 和 username 字段
|
||||
filter: {
|
||||
'username.$ne': 'admin', // 数据范围筛选过滤 username != admin
|
||||
},
|
||||
sort: ['-created_at'], // 创建时间倒序
|
||||
perPage: 50,
|
||||
},
|
||||
get: {
|
||||
fields: ['id', 'username'], // 只输出 id 和 username 字段
|
||||
filter: {
|
||||
'username.$ne': 'admin', // 数据范围筛选过滤 username != admin
|
||||
},
|
||||
},
|
||||
create: {
|
||||
fields: ['username'], // 白名单
|
||||
},
|
||||
update: {
|
||||
fields: ['username'], // 白名单
|
||||
},
|
||||
destroy: {
|
||||
filter: { // 不能删除 admin
|
||||
'username.$ne': 'admin',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
`server.collection()` 和 `server.resource()` 的区别?
|
||||
|
||||
- `server.collection()` 定义数据的 Schema(结构和关系)
|
||||
- `server.resource()` 定义数据的 Action(操作方法)
|
||||
|
||||
一般情况无需显式声明 collection 的 resource,因为已定义的 collection 会自动同步给 resource。
|
||||
|
||||
## 事件 - Event
|
||||
|
||||
在操作执行前、后都放置了相关的事件监听器,可以通过 `server.db.on` 和 `server.on` 添加。区别在于:
|
||||
|
||||
- `server.db.on` 添加数据库的监听器
|
||||
- `server.on` 添加服务器的监听器
|
||||
|
||||
以 `users:login` 为例,在数据库里为「查询」操作,在服务器里为「登录」操作。如果需要记录登录操作日志,需要在 `server.on` 里处理。
|
||||
|
||||
```ts
|
||||
// 创建数据时,执行 User.create() 时触发
|
||||
server.db.on('users:beforeCreate', async (model) => {});
|
||||
|
||||
// 客户端 `POST /api/users:login` 时触发
|
||||
server.on('users:beforeLogin', async (ctx, next) => {});
|
||||
|
||||
// 客户端 `POST /api/users` 时触发
|
||||
server.on('users:beforeCreate', async (ctx, next) => {});
|
||||
```
|
||||
|
||||
## 中间件 - Middleware
|
||||
|
||||
Server 基于 Koa,所有 Koa 的插件(中间件)都可以直接使用,可以通过 server.use 添加。如:
|
||||
|
||||
```ts
|
||||
server.use(async (ctx, next) => {
|
||||
const token = ctx.get('Authorization').replace(/^Bearer\s+/gi, '');
|
||||
if (token !== '123456') {
|
||||
return ctx.throw(401, 'Unauthorized');
|
||||
}
|
||||
return next();
|
||||
});
|
||||
```
|
||||
|
||||
弥补 koa.use 的不足,提供了更完善的 middleware 适配器
|
||||
|
||||
```ts
|
||||
import { middleware } from '@nocobase/server';
|
||||
|
||||
server.use(middleware(async (ctx, next) => {}, {
|
||||
name: 'middlewareName1',
|
||||
resourceNames: [],
|
||||
actionNames: [],
|
||||
insertBefore: '',
|
||||
insertAfter: '',
|
||||
}));
|
||||
```
|
||||
|
||||
## 命令行 - CLI
|
||||
|
||||
除此之外,Server 还集成了 commander,可用于 cli 场景。目前内置的有:
|
||||
|
||||
- `db sync --force` 用于配置与数据库表结构同步
|
||||
- `start --port` 启动应用
|
||||
|
||||
自定义:
|
||||
|
||||
```ts
|
||||
server.command('foo').action(async () => {
|
||||
console.log('foo...');
|
||||
});
|
||||
```
|
||||
|
||||
## 插件 - Plugin
|
||||
|
||||
上文,讲述了核心的扩展接口,包括但不局限于:
|
||||
|
||||
- Database/Collection
|
||||
- `server.db` database 实例
|
||||
- `server.collection()` 等同于 `server.db.table()`
|
||||
- Resource/Action
|
||||
- `server.resource()` 等同于 `server.resourcer.define()`
|
||||
- `server.registerActions()` 等同于 `server.resourcer.registerActions()`
|
||||
- Hook/Event
|
||||
- `server.on()` 添加服务器监听器
|
||||
- `server.db.on()` 添加数据库监听器
|
||||
- Middleware
|
||||
- `server.use()` 添加中间件
|
||||
- CLI
|
||||
- `server.cli` commander 实例
|
||||
- `server.command()` 等同于 `server.cli.command()`
|
||||
- Plugin
|
||||
- `server.pluginManager` 插件管理器
|
||||
- `server.plugin` 等同于 `server.pluginManager.add()`
|
||||
|
||||
基于以上扩展接口,提供模块化、可插拔的插件,可以通过 `server.plugin()` 添加。
|
||||
|
||||
**最简单的插件**
|
||||
|
||||
```ts
|
||||
server.plugin(function pluginName1() {
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
**JSON 风格**
|
||||
|
||||
包括安装、激活、载入、禁用、卸载流程的配置
|
||||
|
||||
```ts
|
||||
server.plugin({
|
||||
async install() {},
|
||||
async activate() {},
|
||||
async bootstrap() {},
|
||||
async deactivate() {},
|
||||
async unstall() {},
|
||||
}, {
|
||||
name: 'pluginName1',
|
||||
displayName: '插件名称',
|
||||
version: '1.2.3',
|
||||
dependencies: {
|
||||
pluginName2: '1.x',
|
||||
pluginName3: '1.x',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
**OOP 风格**
|
||||
|
||||
```ts
|
||||
class MyPlugin extends Plugin {
|
||||
async bootstrap() {}
|
||||
async install() {}
|
||||
async unstall() {}
|
||||
async activate() {}
|
||||
async deactivate() {}
|
||||
}
|
||||
|
||||
server.plugin(MyPlugin, {
|
||||
name: 'pluginName1',
|
||||
displayName: '插件名称',
|
||||
version: '1.2.3',
|
||||
dependencies: {
|
||||
pluginName2: '1.x',
|
||||
pluginName3: '1.x',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
**引用独立的 Package**
|
||||
|
||||
```ts
|
||||
server.plugin('@nocobase/plugin-action-logs');
|
||||
```
|
||||
|
||||
插件信息也可以直接写在 `package.json` 里
|
||||
|
||||
```js
|
||||
{
|
||||
name: 'pluginName1',
|
||||
displayName: '插件名称',
|
||||
version: '1.2.3',
|
||||
dependencies: {
|
||||
pluginName2: '1.x',
|
||||
pluginName3: '1.x',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
通过 `server.plugin()` 添加的插件需要激活才能使用
|
||||
|
||||
```ts
|
||||
await server.pluginManager.activate(['pluginName1', 'pluginName2']);
|
||||
```
|
||||
|
||||
**插件 CLI**
|
||||
|
||||
```bash
|
||||
plugin install pluginName1
|
||||
plugin unstall pluginName1
|
||||
plugin activate pluginName1
|
||||
plugin deactivate pluginName1
|
||||
```
|
||||
|
||||
目前已有的插件:
|
||||
|
||||
- @nocobase/plugin-collections 提供数据表配置接口,可通过 HTTP API 管理数据表。
|
||||
- @nocobase/plugin-action-logs 操作日志
|
||||
- @nocobase/plugin-automations 自动化(未升级 v0.5,暂不能使用)
|
||||
- @nocobase/plugin-china-region 中国行政区
|
||||
- @nocobase/plugin-client 提供客户端,无代码的可视化配置界面,需要与 @nocobase/client 配合使用
|
||||
- @nocobase/plugin-export 导出
|
||||
- @nocobase/plugin-file-manager 文件管理器
|
||||
- @nocobase/plugin-permissions 角色和权限
|
||||
- @nocobase/plugin-system-settings 系统配置
|
||||
- @nocobase/plugin-ui-router 前端路由配置
|
||||
- @nocobase/plugin-ui-schema ui 配置
|
||||
- @nocobase/plugin-users 用户模块
|
||||
|
||||
## 测试 - Testing
|
||||
|
||||
有代码就需要测试,@nocobase/test 提供了 mockDatabase 和 mockServer 用于数据库和服务器的测试,如:
|
||||
|
||||
```ts
|
||||
import { mockServer, MockServer } from '@nocobase/test';
|
||||
|
||||
describe('mock server', () => {
|
||||
let api: MockServer;
|
||||
|
||||
beforeEach(() => {
|
||||
api = mockServer({
|
||||
dataWrapping: false,
|
||||
});
|
||||
api.registerActions({
|
||||
list: async (ctx, next) => {
|
||||
ctx.body = [1, 2];
|
||||
await next();
|
||||
},
|
||||
});
|
||||
api.resource({
|
||||
name: 'test',
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
return api.destroy();
|
||||
});
|
||||
|
||||
it('agent.get', async () => {
|
||||
const response = await api.agent().get('/test');
|
||||
expect(response.body).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
it('agent.resource', async () => {
|
||||
const response = await api.agent().resource('test').list();
|
||||
expect(response.body).toEqual([1, 2]);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 客户端 - Client
|
||||
|
||||
为了让更多非开发人员也能参与进来,NocoBase 提供了配套的客户端插件 —— 无代码的可视化配置界面。客户端插件需要与 @nocobase/client 配合使用,可以直接使用,也可以自行改造。
|
||||
|
||||
插件配置
|
||||
|
||||
```ts
|
||||
server.plugin('@nocobase/plugin-client', {
|
||||
// 自定义 dist 路径
|
||||
dist: path.resolve(__dirname, './node_modules/@nocobase/client/app'),
|
||||
});
|
||||
```
|
||||
|
||||
为了满足各类场景需求,客户端 `@nocobase/client` 提供了丰富的基础组件:
|
||||
|
||||
- Action - 操作
|
||||
- Action.Window 当前浏览器窗口/标签里打开
|
||||
- Action.Drawer 打开抽屉(默认右侧划出)
|
||||
- Action.Modal 打开对话框
|
||||
- Action.Dropdown 下拉菜单
|
||||
- Action.Popover 气泡卡片
|
||||
- Action.Group 按钮分组
|
||||
- Action.Bar 操作栏
|
||||
- AddNew 「添加」模块
|
||||
- AddNew.CardItem - 添加区块
|
||||
- AddNew.PaneItem - 添加区块(查看面板,与当前查看的数据相关)
|
||||
- AddNew.FormItem - 添加字段
|
||||
- BlockItem/CardItem/FormItem - 装饰器
|
||||
- BlockItem - 普通装饰器(无包装效果)
|
||||
- CardItem - 卡片装饰器
|
||||
- FormItem - 字段装饰器
|
||||
- Calendar - 日历
|
||||
- Cascader - 级联选择
|
||||
- Chart - 图表
|
||||
- Checkbox - 勾选
|
||||
- Checkbox.Group - 多选框
|
||||
- Collection - 数据表配置
|
||||
- Collection.Field - 数据表字段
|
||||
- ColorSelect - 颜色选择器
|
||||
- DatePicker - 日期选择器
|
||||
- DesignableBar - 配置工具栏
|
||||
- Filter - 筛选器
|
||||
- Form - 表单
|
||||
- Grid - 栅格布局
|
||||
- IconPicker - 图标选择器
|
||||
- Input - 输入框
|
||||
- Input.TextArea - 多行输入框
|
||||
- InputNumber - 数字框
|
||||
- Kanban - 看板
|
||||
- ListPicker - 列表选择器(用于选择、展示关联数据)
|
||||
- Markdown 编辑器
|
||||
- Menu - 菜单
|
||||
- Password - 密码
|
||||
- Radio - 单选框
|
||||
- Select - 选择器
|
||||
- Table - 表格
|
||||
- Tabs - 标签页
|
||||
- TimePicker - 时间选择器
|
||||
- Upload - 上传
|
||||
|
||||
开发们也可以自行扩展,以上组件基于 Formily 构建,怎么自定义组件大家查看相关组件源码或 Formily 文档吧,这里说点不一样的。
|
||||
|
||||
- 如何扩展数据库字段?
|
||||
- 如何将第三方区块添加到 AddNew 模块中?
|
||||
- 如何在操作栏里添加更多的内置操作?
|
||||
- 如何自定义配置工具栏?
|
||||
|
||||
除了组件具备灵活的扩展以外,客户端也可以在任意前端框架中使用,可以自定义 Request 和 Router,如:
|
||||
|
||||
<pre lang="tsx">
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { ClientSDK, Application } from '@nocobase/client';
|
||||
|
||||
// 初始化 client 实例
|
||||
const client = new ClientSDK({
|
||||
request: (options) => Promise.resolve({}),
|
||||
});
|
||||
|
||||
// 适配 Route Component
|
||||
const RouteSwitch = createRouteSwitch({
|
||||
components: {
|
||||
AdminLayout,
|
||||
AuthLayout,
|
||||
RouteSchemaRenderer,
|
||||
},
|
||||
});
|
||||
|
||||
ReactDOM.render(
|
||||
<ClientProvider client={client}>
|
||||
<MemoryRouter initialEntries={['/admin']}>
|
||||
<RouteSwitch routes={[]}/>
|
||||
</MemoryRouter>
|
||||
</ClientProvider>,
|
||||
document.getElementById('root'),
|
||||
);
|
||||
</pre>
|
||||
|
||||
更多细节,可以通过 create-nocobase-app 初始化项目脚手架并体验。
|
||||
|
||||
```bash
|
||||
yarn create nocobase-app my-nocobase-project
|
||||
```
|
||||
|
||||
nocobase-app 默认使用 umijs 作为项目构建工具,并集成了 Server 作数据接口,初始化的目录结构如下:
|
||||
|
||||
```bash
|
||||
|- src
|
||||
|- pages
|
||||
|- apis
|
||||
|- .env
|
||||
|- .umirc.ts
|
||||
|- package.json
|
||||
```
|
||||
|
@ -1,20 +0,0 @@
|
||||
---
|
||||
title: NocoBase - An open source and free no-code development platform
|
||||
hero:
|
||||
title: NocoBase
|
||||
desc: An open source and free no-code development platform
|
||||
actions:
|
||||
- text: 快速上手
|
||||
link: /zh-CN/guide
|
||||
features:
|
||||
- icon: https://gw.alipayobjects.com/zos/bmw-prod/881dc458-f20b-407b-947a-95104b5ec82b/k79dm8ih_w144_h144.png
|
||||
title: 特性 1
|
||||
desc: Balabala
|
||||
- icon: https://gw.alipayobjects.com/zos/bmw-prod/d60657df-0822-4631-9d7c-e7a869c2f21c/k79dmz3q_w126_h126.png
|
||||
title: 特性 2
|
||||
desc: Balabala
|
||||
- icon: https://gw.alipayobjects.com/zos/bmw-prod/d1ee0c6f-5aed-4a45-a507-339a4bfe076c/k7bjsocq_w144_h144.png
|
||||
title: 特性 3
|
||||
desc: Balabala
|
||||
footer: Copyright © 2020-2021 NocoBase. All rights reserved.
|
||||
---
|
Binary file not shown.
Before Width: | Height: | Size: 318 KiB |
@ -1,24 +0,0 @@
|
||||
---
|
||||
title: Actions - 操作方法
|
||||
group:
|
||||
order: 2
|
||||
title: 概念
|
||||
---
|
||||
|
||||
# Actions - 操作方法
|
||||
|
||||
与 resourcer.registerAction 用法一致
|
||||
|
||||
```ts
|
||||
export async function get(ctx, next) {
|
||||
await next();
|
||||
}
|
||||
|
||||
export const list = {
|
||||
filter,
|
||||
fields, // 初始化的参数
|
||||
async handler(ctx, next) {
|
||||
await next();
|
||||
}
|
||||
}
|
||||
```
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Collection Fields - 数据表字段
|
||||
---
|
||||
|
||||
# Collection Fields - 数据表字段
|
@ -1,25 +0,0 @@
|
||||
---
|
||||
title: Collections - 数据集
|
||||
---
|
||||
|
||||
# Collections - 数据集
|
||||
|
||||
与 database.table 用法一致
|
||||
|
||||
```ts
|
||||
export default {
|
||||
name: 'examples',
|
||||
fields: [],
|
||||
}
|
||||
```
|
||||
|
||||
配置扩展
|
||||
|
||||
```ts
|
||||
import { extend } from '@nocobase/database';
|
||||
|
||||
export default extend({
|
||||
name: 'examples',
|
||||
fields: [],
|
||||
});
|
||||
```
|
@ -1,9 +0,0 @@
|
||||
---
|
||||
title: Hooks - 钩子
|
||||
---
|
||||
|
||||
# Hooks - 钩子
|
||||
|
||||
目前支持的 hook 有两类 database.addHook 和 Model.addHook
|
||||
|
||||
未完待续...
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Locales - 国际化
|
||||
---
|
||||
|
||||
# Locales - 国际化 <Badge>未实现</Badge>
|
@ -1,9 +0,0 @@
|
||||
---
|
||||
title: Middlewares - 中间件
|
||||
---
|
||||
|
||||
# Middlewares - 中间件
|
||||
|
||||
## koa
|
||||
## resourcer
|
||||
## action
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Migrations - 迁移
|
||||
---
|
||||
|
||||
# Migrations - 迁移
|
@ -1,33 +0,0 @@
|
||||
---
|
||||
title: Models - 模型
|
||||
---
|
||||
|
||||
# Models - 模型
|
||||
|
||||
将 models 统一放在 `/src/models`、`/lib/models` 目录下,将自动导入 database。
|
||||
|
||||
database.table 提供的数据表配置支持指定特殊 model,如:
|
||||
|
||||
```ts
|
||||
import { Model } from '@nocobase/database';
|
||||
|
||||
class Test extends Model {
|
||||
// 在这个类里可以为 Test Model 扩展其他 API
|
||||
static hello() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'tests',
|
||||
model: Test,
|
||||
};
|
||||
```
|
||||
|
||||
调用 Model
|
||||
|
||||
```ts
|
||||
const Test = db.getModel('tests');
|
||||
// Test 可以调用 hello 方法了
|
||||
Test.hello();
|
||||
```
|
@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Resources - 资源
|
||||
---
|
||||
|
||||
# Resources - 资源
|
||||
|
||||
用法同 resourcer.define
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
title: UI Schema - 组件
|
||||
---
|
||||
|
||||
# UI Schema - 组件
|
@ -1,17 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-action-logs'
|
||||
order: 5
|
||||
group:
|
||||
order: 3
|
||||
title: 官方插件
|
||||
---
|
||||
|
||||
# @nocobase/plugin-action-logs
|
||||
|
||||
操作记录
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn nocobase pull action-logs --start
|
||||
```
|
@ -1,101 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-automations'
|
||||
order: 4
|
||||
---
|
||||
|
||||
# @nocobase/plugin-automations
|
||||
|
||||
提供自动化模块
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn nocobase pull automations --start
|
||||
```
|
||||
|
||||
## 用例
|
||||
|
||||
```ts
|
||||
// 省略上文
|
||||
|
||||
database.table({
|
||||
name: 'tests',
|
||||
fields: [
|
||||
{
|
||||
type: 'string',
|
||||
name: 'name1',
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'name2',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
database.table({
|
||||
name: 'demos',
|
||||
fields: [
|
||||
{
|
||||
type: 'string',
|
||||
name: 'col1',
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'col2',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const [Automation, Test] = database.getModels(['automations', 'tests']);
|
||||
|
||||
const automation = await Automation.create({
|
||||
title: 'a1',
|
||||
enabled: true,
|
||||
type: 'collections:afterCreate',
|
||||
collection_name: 'tests',
|
||||
});
|
||||
|
||||
automation.startJob('test', async (result, options) => {
|
||||
// job 代码
|
||||
});
|
||||
|
||||
// 使用内置的 job
|
||||
await automation.updateAssociations({
|
||||
jobs: [
|
||||
{
|
||||
title: 'j1',
|
||||
enabled: true,
|
||||
type: 'create',
|
||||
collection_name: 'demos',
|
||||
values: [
|
||||
{
|
||||
column: 'col1',
|
||||
op: 'eq',
|
||||
value: 'n1'
|
||||
},
|
||||
{
|
||||
column: 'col2',
|
||||
op: 'ref',
|
||||
value: 'name2'
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
// tests 表新增数据会触发上面执行 job 任务
|
||||
await Test.create({
|
||||
name1: 'n11',
|
||||
name2: 'n22',
|
||||
});
|
||||
```
|
||||
|
||||
## Model API
|
||||
|
||||
### Automation.load()
|
||||
### automation.loadJobs()
|
||||
### automation.startJob(jobName: string, callback: any)
|
||||
### automation.cancelJob(jobName: string)
|
||||
### Job.bootstrap()
|
||||
### Job.process(result?: any, options?: any)
|
||||
### Job.cancel()
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-china-region'
|
||||
---
|
||||
|
||||
# @nocobase/plugin-china-region
|
@ -1,14 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-collections'
|
||||
order: 1
|
||||
---
|
||||
|
||||
# @nocobase/plugin-collections
|
||||
|
||||
提供数据表配置接口,可通过 HTTP API 管理数据表。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn nocobase pull collections --start
|
||||
```
|
@ -1,27 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-export'
|
||||
---
|
||||
|
||||
# @nocobase/plugin-export
|
||||
|
||||
提供导出功能
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
暂时只支持 excel 导出
|
||||
</Alert>
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn nocobase pull export --start
|
||||
```
|
||||
|
||||
## Action API
|
||||
|
||||
### export
|
||||
|
||||
参数和 list 一致,暂时只支持 excel 导出
|
||||
|
||||
```ts
|
||||
api.resource(resourceName).export(params);
|
||||
```
|
@ -1,45 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-file-manager'
|
||||
---
|
||||
|
||||
# @nocobase/plugin-file-manager
|
||||
|
||||
文件管理器
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn nocobase pull file-manager --start
|
||||
```
|
||||
|
||||
## Field Interfaces
|
||||
|
||||
### attachment
|
||||
|
||||
附件字段
|
||||
|
||||
## Action API
|
||||
|
||||
### upload
|
||||
|
||||
文件上传
|
||||
|
||||
```ts
|
||||
// 文件管理器接口
|
||||
await api.resource('attachments').upload({});
|
||||
|
||||
// 附件字段接口
|
||||
await api.resource('users.avatar').upload({
|
||||
associatedKey: 1,
|
||||
});
|
||||
```
|
||||
|
||||
## Storages
|
||||
|
||||
### local
|
||||
|
||||
本地存储
|
||||
|
||||
### ali-oss
|
||||
|
||||
阿里云 OSS
|
@ -1,69 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-notifications'
|
||||
---
|
||||
|
||||
# @nocobase/plugin-notifications
|
||||
|
||||
提供通知模块
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
|
||||
暂时只实现了核心三步骤:
|
||||
|
||||
- 通知模板:包括主题、内容、接收人配置、发送服务等等
|
||||
- 通知服务:可以是短信、邮件等等
|
||||
- 通知日志:记录通知状态
|
||||
|
||||
</Alert>
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn nocobase pull notifications --start
|
||||
```
|
||||
|
||||
## 示例
|
||||
|
||||
```ts
|
||||
const Notification = db.getModel('notifications');
|
||||
const notification = await Notification.create({
|
||||
subject: 'Subject',
|
||||
body: 'hell world',
|
||||
receiver_options: {
|
||||
data: 'to@nocobase.com',
|
||||
fromTable: 'users',
|
||||
filter: {},
|
||||
dataField: 'email',
|
||||
},
|
||||
});
|
||||
await notification.updateAssociations({
|
||||
service: {
|
||||
type: 'email',
|
||||
title: '阿里云邮件推送',
|
||||
options: {
|
||||
host: "smtpdm.aliyun.com",
|
||||
port: 465,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: 'from@nocobase.com',
|
||||
pass: 'pass',
|
||||
},
|
||||
from: 'NocoBase<from@nocobase.com>',
|
||||
},
|
||||
},
|
||||
});
|
||||
await notification.send();
|
||||
```
|
||||
|
||||
## Action API
|
||||
|
||||
### notifications:send
|
||||
|
||||
发送通知
|
||||
|
||||
```ts
|
||||
await api.resource('notifications').send({
|
||||
resourceKey: 1,
|
||||
to: 'demo@nocobase.com',
|
||||
});
|
||||
```
|
@ -1,14 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-pages'
|
||||
order: 1
|
||||
---
|
||||
|
||||
# @nocobase/plugin-pages
|
||||
|
||||
将客户端的组件参数交由服务端管理,由服务端控制输出客户端所需的 ui schema。开发者可以随意适配任意前端组件。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn nocobase pull pages --start
|
||||
```
|
@ -1,55 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-permissions'
|
||||
order: 1
|
||||
---
|
||||
|
||||
# @nocobase/plugin-permissions
|
||||
|
||||
提供权限模块
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn nocobase pull permissions --start
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
<Alert title="还需改进的一些细节" type="warning">
|
||||
|
||||
- 提供 Permission Model 相关快捷数据操作 API
|
||||
- 需要支持从代码层面快捷配置权限,无需经由后台
|
||||
系统表相关操作权限可能是直接通过权限 api 配置或者 permission model api,直接写入数据库
|
||||
- 提供 ui schema 需要的 fields/actions/pages 相关 permission api
|
||||
现在有个 ac.can 可用,实际体验不够直接
|
||||
- 数据表权限设置只开放了业务表,系统表权限需要开发自行处理,但无提供相关 api
|
||||
如操作记录表、中国行政区表、附件表的情况:
|
||||
- 操作记录表只开放查看,只能查看自己有权限能查看的数据表的操作
|
||||
- 中国行政区的省市区等数据仅登录用户可查看
|
||||
- 附件暂时没做权限限制
|
||||
|
||||
</Alert>
|
||||
|
||||
### context.ac.isRoot
|
||||
|
||||
是否为 root 权限
|
||||
|
||||
### context.ac.can(collection)
|
||||
|
||||
判断当前用户权限,支持链式操作。
|
||||
|
||||
#### ac.can(collection).permissions()
|
||||
|
||||
获取当前 collection 的所有权限配置
|
||||
|
||||
#### ac.can(collection).act(actionName).any()
|
||||
|
||||
是否允许 collection:actionName 操作,允许则返回相关配置
|
||||
|
||||
#### ac.can(collection).act(actionName).one(resourceKey)
|
||||
|
||||
具体 resourceKey 值的 collection,是否允许 collection:actionName 操作,允许则返回相关配置
|
||||
|
||||
#### ac.as(roles).can(collection)
|
||||
|
||||
指定 roles 的权限判断
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-system-settings'
|
||||
---
|
||||
|
||||
# @nocobase/plugin-system-settings
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-ui-router'
|
||||
---
|
||||
|
||||
# @nocobase/plugin-ui-router
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-ui-schema'
|
||||
---
|
||||
|
||||
# @nocobase/plugin-ui-schema
|
@ -1,146 +0,0 @@
|
||||
---
|
||||
title: '@nocobase/plugin-users'
|
||||
---
|
||||
|
||||
# @nocobase/plugin-users
|
||||
|
||||
提供用户模块
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
用户模块目前的实现较简单
|
||||
</Alert>
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
yarn nocobase pull users --start
|
||||
```
|
||||
|
||||
## Action API
|
||||
|
||||
### users:check
|
||||
|
||||
检查用户是否已登录
|
||||
|
||||
```ts
|
||||
await api.resource('users').check();
|
||||
```
|
||||
|
||||
### users:login
|
||||
|
||||
登录
|
||||
|
||||
```ts
|
||||
await api.resource('users').login({
|
||||
values: {
|
||||
email,
|
||||
password,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### users:register
|
||||
|
||||
注册
|
||||
|
||||
```ts
|
||||
await api.resource('users').register({
|
||||
values: {
|
||||
email,
|
||||
password,
|
||||
...others,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### users:logout
|
||||
|
||||
注销
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
注销后端暂无任何处理,实际需要清除 token。
|
||||
</Alert>
|
||||
|
||||
```ts
|
||||
await api.resource('users').logout();
|
||||
```
|
||||
|
||||
### users:lostpassword
|
||||
|
||||
忘记密码
|
||||
|
||||
```ts
|
||||
await api.resource('users').lostpassword({
|
||||
values: {
|
||||
email,
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### users:resetpassword
|
||||
|
||||
重置密码
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
未实现邮件发送
|
||||
</Alert>
|
||||
|
||||
```ts
|
||||
await api.resource('users').lostpassword({
|
||||
values: {
|
||||
email,
|
||||
password,
|
||||
reset_token,
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### users:getUserByResetToken
|
||||
|
||||
根据 reset token 获取用户信息
|
||||
|
||||
```ts
|
||||
await api.resource('users').getUserByResetToken({
|
||||
values: {
|
||||
reset_token,
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Fields Types
|
||||
|
||||
### context <Badge>未实现</Badge>
|
||||
|
||||
上下文类型,可以从 app.context 里获取信息,如 UA、Client IP 等。利用 context 类型,createdBy/updatedBy 的实现也变得更简单了:
|
||||
|
||||
createdBy
|
||||
|
||||
```ts
|
||||
{
|
||||
name: 'created_by_id',
|
||||
type: 'context',
|
||||
dataIndex: 'state.currentUser.id',
|
||||
createOnly: true,
|
||||
}
|
||||
```
|
||||
|
||||
updatedBy
|
||||
|
||||
```ts
|
||||
{
|
||||
name: 'updated_by_id',
|
||||
type: 'context',
|
||||
dataIndex: 'state.currentUser.id',
|
||||
}
|
||||
```
|
||||
|
||||
## Field Interfaces
|
||||
|
||||
### createdBy
|
||||
|
||||
创建人
|
||||
|
||||
### updatedBy
|
||||
|
||||
最后更新人
|
@ -1,12 +0,0 @@
|
||||
---
|
||||
title: 开发者模式
|
||||
order: 3
|
||||
toc: menu
|
||||
---
|
||||
|
||||
# 开发者模式 <Badge>待完善</Badge>
|
||||
|
||||
开发者模式是专门为开发者提供的修改、调试复杂配置项的运行环境。在开发者模式下:
|
||||
|
||||
- 可以查看系统配置表
|
||||
- 配置开放 JSON Editor,可以修改和调试更多隐藏配置项
|
@ -1,67 +0,0 @@
|
||||
---
|
||||
title: 了解插件
|
||||
order: 1
|
||||
nav:
|
||||
title: 插件
|
||||
order: 3
|
||||
path: /plugins
|
||||
group:
|
||||
order: 1
|
||||
title: 教程
|
||||
---
|
||||
|
||||
# 了解插件
|
||||
|
||||
NocoBase 核心提供了丰富的 API 用于处理扩展,但是直接调用底层 API 成本较高。因此,又提供了更为灵活、便捷的插件化管理方式,用户只需要将代码放在约定的几个目录里即可。
|
||||
|
||||
<Alert title="重要提示" type="warning">
|
||||
NocoBase 插件之间是平行的,不存在直接的依赖关系,不过插件在加载时可能有优先级。
|
||||
</Alert>
|
||||
|
||||
## 目录结构 <Badge>未实现</Badge>
|
||||
|
||||
```bash
|
||||
|- @nocobase/plugin-[name] 或 nocobase-plugin-[name]
|
||||
|- src
|
||||
|- actions
|
||||
|- collections
|
||||
|- fields
|
||||
|- hooks
|
||||
|- interfaces
|
||||
|- middlewares
|
||||
|- models
|
||||
|- resources
|
||||
|- blocks
|
||||
```
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
|
||||
目前 v0.4 版本的插件还十分简陋,只提供了一个非常原生态的函数扩展,其他的都需要开发者根据情况调用核心 API 来完成各类功能扩展,并未提供约定式目录,也没有完整的生命周期机制。没有安装/卸载、激活/禁用,加载即激活。
|
||||
|
||||
</Alert>
|
||||
|
||||
## PluginManager <Badge>未实现</Badge>
|
||||
|
||||
插件的几个状态
|
||||
|
||||
- 下载
|
||||
- 启动
|
||||
- 停止
|
||||
- 重启
|
||||
- 删除
|
||||
|
||||
### API <Badge>未实现</Badge>
|
||||
|
||||
- `pluginManager.pull()`
|
||||
- `pluginManager.start()`
|
||||
- `pluginManager.stop()`
|
||||
- `pluginManager.restart()`
|
||||
- `pluginManager.remove()`
|
||||
|
||||
### CLI <Badge>未实现</Badge>
|
||||
|
||||
- `yarn nocobase pull <name>`
|
||||
- `yarn nocobase start <name>`
|
||||
- `yarn nocobase stop <name>`
|
||||
- `yarn nocobase restart <name>`
|
||||
- `yarn nocobase remove <name>`
|
@ -1,23 +0,0 @@
|
||||
---
|
||||
title: 插件命令行操作
|
||||
order: 2
|
||||
toc: menu
|
||||
---
|
||||
|
||||
# 插件命令行操作 <Badge>未实现</Badge>
|
||||
|
||||
## pull - 拉取
|
||||
|
||||
将插件包从远程下载到本地列表
|
||||
|
||||
## start - 启动
|
||||
|
||||
启动插件
|
||||
|
||||
## stop - 停止
|
||||
|
||||
停止插件
|
||||
|
||||
## rm - 移除
|
||||
|
||||
插件将从本地列表移除
|
@ -1,74 +0,0 @@
|
||||
---
|
||||
title: NocoBase 生命周期
|
||||
order: 2
|
||||
toc: menu
|
||||
---
|
||||
|
||||
# NocoBase 生命周期
|
||||
|
||||
每个 NocoBase 实例在被创建时都要经过一系列的初始化过程,在这个过程中某些节点会运行一些函数,这些节点就是生命周期的钩子,有了钩子的存在,代码不论按什么顺序书写,都会按照既定的顺序执行。NocoBase 的生命周期大概分为四个环节:
|
||||
|
||||
1. 初始化实例
|
||||
2. 加载配置
|
||||
3. 数据库操作
|
||||
4. 每次请求中
|
||||
|
||||
## 初始化实例
|
||||
|
||||
- koa:nocobase 实例
|
||||
- database:数据库实例
|
||||
- resourcer:koa 的分支,负责 resource router
|
||||
- pluginManager:插件管理器实例
|
||||
|
||||
现阶段的设计 sever 直接继承了 koa application,其他三个作为 server 实例的成员存在。
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
pluginManager 的初始化存在较大缺陷,在初始化时直接加载了配置,暂时无法处理数据库操作。
|
||||
</Alert>
|
||||
|
||||
## 加载配置
|
||||
|
||||
- table hooks:表配置事件
|
||||
- table options:表配置
|
||||
- model hooks:model 事件
|
||||
|
||||
系统表配置从文件目录里导入,业务表配置从数据库里导入,部分开放的系统表从文件目录导入之后,又从数据库里更新,如用户表。
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
|
||||
resourcer 配置是运行时初始化,在 koa middleware 中。hooks 分 table、model、plugin、resourcer 四类,暂时并不统一。
|
||||
|
||||
另外,还有个非常重要的细节,生命周期解决了大结构的执行顺序,但并未解决同一挂载点多钩子之间的执行顺序。
|
||||
|
||||
</Alert>
|
||||
|
||||
## 数据库操作
|
||||
|
||||
- initialize:初始化,app 启动或重启时都执行
|
||||
- install:安装操作,只执行一次
|
||||
- upgrade:更新操作,只执行一次
|
||||
- uninstall:卸载操作,只执行一次
|
||||
|
||||
<Alert title="注意" type="warning">
|
||||
目前还不支持,这部分的钩子主要用于管理插件。
|
||||
</Alert>
|
||||
|
||||
## 每次请求中
|
||||
|
||||
- koa middleware
|
||||
- resourcer middleware
|
||||
- resource middleware
|
||||
- action middleware
|
||||
- action handler
|
||||
|
||||
客户端请求时,都会执行。
|
||||
|
||||
虽然大部分框架都提供了中间件,但是中间件的执行顺序(优先级)依赖于编码顺序,这种方式非常不利于插件化管理。因此,在 Resourcer 设计思想里,将中间件做了分层,不同层级的 middlewares 不依赖于编码顺序,而是如下顺序:
|
||||
|
||||
1. 首先,koa 层:`koa.use`
|
||||
2. 其次,resourcer 层:`resourcer.use`
|
||||
3. 再次,resource 层(每个资源独立):`resourcer.registerActionMiddleware`
|
||||
4. 然后,action 层:`resourcer.registerResourceMiddleware`
|
||||
5. 最后,执行 action handler
|
||||
|
||||
不过,每个层次的中间件执行顺序还依赖于编码顺序,如有需要再进行更细微的改进。
|
@ -1,34 +0,0 @@
|
||||
---
|
||||
title: 如何编写测试
|
||||
order: 4
|
||||
toc: menu
|
||||
---
|
||||
|
||||
# 如何编写测试 <Badge>未实现</Badge>
|
||||
|
||||
NocoBase 提供了 @nocobase/test 用于编写和调试插件。
|
||||
|
||||
```ts
|
||||
import { mockServer } from '@nocobase/test';
|
||||
|
||||
describe('test', () => {
|
||||
let api;
|
||||
|
||||
beforeEach(async () => {
|
||||
api = mockServer({});
|
||||
await api.database.sync();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await api.database.close();
|
||||
});
|
||||
|
||||
it('test resource', () => {
|
||||
await app.resource('demos').get();
|
||||
});
|
||||
|
||||
it('test request', () => {
|
||||
await app.request().get('/');
|
||||
});
|
||||
});
|
||||
```
|
Loading…
Reference in New Issue
Block a user