[add] Widget (alpha)
This commit is contained in:
parent
3509956bce
commit
8d88682967
14 changed files with 580 additions and 2 deletions
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/yaoapp/yao/table"
|
"github.com/yaoapp/yao/table"
|
||||||
"github.com/yaoapp/yao/task"
|
"github.com/yaoapp/yao/task"
|
||||||
"github.com/yaoapp/yao/websocket"
|
"github.com/yaoapp/yao/websocket"
|
||||||
|
"github.com/yaoapp/yao/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Load 根据配置加载 API, FLow, Model, Plugin
|
// Load 根据配置加载 API, FLow, Model, Plugin
|
||||||
|
|
@ -133,6 +134,11 @@ func Load(cfg config.Config) (err error) {
|
||||||
log.Debug(err.Error())
|
log.Debug(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = widget.Load(cfg) // Load schedules
|
||||||
|
if err != nil {
|
||||||
|
log.Debug(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
58
tests/dyforms/app.form.json
Normal file
58
tests/dyforms/app.form.json
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"guard": "bearer-jwt",
|
||||||
|
"title": "应用表单",
|
||||||
|
"sn": "AP1024",
|
||||||
|
"orign": "手机应用",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "门店",
|
||||||
|
"field": "store_id",
|
||||||
|
"searchable": true,
|
||||||
|
"props": {
|
||||||
|
"value": ":store_id",
|
||||||
|
"type": "SelectStore",
|
||||||
|
"title": "门店",
|
||||||
|
"placeholder": "请选择门店",
|
||||||
|
"validation": [
|
||||||
|
{ "type": "Required" },
|
||||||
|
{ "type": "StoreStatus", "args": [":store_id"] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "订单数量",
|
||||||
|
"field": "orders_amount",
|
||||||
|
"searchable": true,
|
||||||
|
"props": {
|
||||||
|
"value": ":orders_amount",
|
||||||
|
"type": "Number",
|
||||||
|
"title": "订单数量",
|
||||||
|
"placeholder": "今日订单数量",
|
||||||
|
"computed": "OrderAmount",
|
||||||
|
"validation": [
|
||||||
|
{ "type": "Required" },
|
||||||
|
{ "type": "IsNumber", "args": [":orders_amount"] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "账单地址",
|
||||||
|
"field": "address",
|
||||||
|
"props": {
|
||||||
|
"value": ":address",
|
||||||
|
"type": "Text",
|
||||||
|
"title": "账单地址",
|
||||||
|
"placeholder": "填写账单地址",
|
||||||
|
"validation": [
|
||||||
|
{ "type": "Required" },
|
||||||
|
{ "type": "MaxLength", "args": [":address", 200] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filters": [],
|
||||||
|
"list-layout": {
|
||||||
|
"columns": [{ "name": "store_id" }, { "name": "orders_amount" }],
|
||||||
|
"filters": [{ "name": "订单数量" }]
|
||||||
|
}
|
||||||
|
}
|
||||||
77
tests/dyforms/website.form.json
Normal file
77
tests/dyforms/website.form.json
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
{
|
||||||
|
"guard": "bearer-jwt",
|
||||||
|
"title": "官网表单",
|
||||||
|
"sn": "AP2048",
|
||||||
|
"orign": "官方网站",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "门店",
|
||||||
|
"field": "store_id",
|
||||||
|
"searchable": true,
|
||||||
|
"props": {
|
||||||
|
"value": ":store_id",
|
||||||
|
"type": "SelectStore",
|
||||||
|
"title": "门店",
|
||||||
|
"placeholder": "请选择门店",
|
||||||
|
"validation": [
|
||||||
|
{ "type": "Required" },
|
||||||
|
{ "type": "StoreStatus", "args": [":store_id"] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "订单数量",
|
||||||
|
"field": "orders_amount",
|
||||||
|
"searchable": true,
|
||||||
|
"props": {
|
||||||
|
"value": ":orders_amount",
|
||||||
|
"type": "Number",
|
||||||
|
"title": "订单数量",
|
||||||
|
"placeholder": "今日订单数量",
|
||||||
|
"computed": "OrderAmount",
|
||||||
|
"validation": [
|
||||||
|
{ "type": "Required" },
|
||||||
|
{ "type": "IsNumber", "args": [":orders_amount"] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "账单地址",
|
||||||
|
"field": "address",
|
||||||
|
"props": {
|
||||||
|
"value": ":address",
|
||||||
|
"type": "Text",
|
||||||
|
"title": "账单地址",
|
||||||
|
"placeholder": "填写账单地址",
|
||||||
|
"validation": [
|
||||||
|
{ "type": "Required" },
|
||||||
|
{ "type": "MaxLength", "args": [":address", 200] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"订单数量": {
|
||||||
|
"label": "订单数量超过",
|
||||||
|
"bind": "where.orders_amount.ge",
|
||||||
|
"type": "Select",
|
||||||
|
"props": {
|
||||||
|
"placeholder": "订单数量",
|
||||||
|
"options": [
|
||||||
|
{ "label": "大于100", "value": 100 },
|
||||||
|
{ "label": "大于50", "value": 50 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"list-layout": {
|
||||||
|
"columns": [
|
||||||
|
{ "name": "store_id" },
|
||||||
|
{ "name": "orders_amount" },
|
||||||
|
{ "name": "address" }
|
||||||
|
],
|
||||||
|
"filters": [{ "name": "订单数量" }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,12 +12,12 @@ function NextID() {
|
||||||
|
|
||||||
function Send(id, mail, flag) {
|
function Send(id, mail, flag) {
|
||||||
for (var i = 1; i <= 3; i++) {
|
for (var i = 1; i <= 3; i++) {
|
||||||
Process("xiang.system.Sleep", 200);
|
Process("xiang.sys.Sleep", 200);
|
||||||
Process("tasks.mail.Progress", id, i, 3, "unit-test");
|
Process("tasks.mail.Progress", id, i, 3, "unit-test");
|
||||||
}
|
}
|
||||||
if (flag) {
|
if (flag) {
|
||||||
console.log(`flag: ${flag}`);
|
console.log(`flag: ${flag}`);
|
||||||
Process("xiang.system.Sleep", 2000);
|
Process("xiang.sys.Sleep", 2000);
|
||||||
}
|
}
|
||||||
console.log(
|
console.log(
|
||||||
`Send: ${JSON.stringify({ foo: "bar", mail: mail, flag: flag || "-" })}`
|
`Send: ${JSON.stringify({ foo: "bar", mail: mail, flag: flag || "-" })}`
|
||||||
|
|
|
||||||
3
tests/widgets/README.md
Normal file
3
tests/widgets/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Widgets
|
||||||
|
|
||||||
|
## a customize low-code modules
|
||||||
3
tests/widgets/dyform/README.md
Normal file
3
tests/widgets/dyform/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# DyForm
|
||||||
|
|
||||||
|
## A form widget. users can design forms online
|
||||||
5
tests/widgets/dyform/assets/README.md
Normal file
5
tests/widgets/dyform/assets/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Assets
|
||||||
|
|
||||||
|
1. The assets folder's file will be copied to the `ui/.widgets/<WIDGET NAME>/` folder.
|
||||||
|
2. If the folder does not exist will be created. To upgrade the assets, remove the `ui/.widgets/<WIDGET NAME>/` folder.
|
||||||
|
3. The asset file PUBLIC URL is `http(s)://<YOUR HOST>/.widgets/<WIDGET NAME>/<FILE PATH>`, ANYONE CAN VISIT DIRECTLY.
|
||||||
107
tests/widgets/dyform/compile.js
Normal file
107
tests/widgets/dyform/compile.js
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
/**
|
||||||
|
* The DSL compiler.
|
||||||
|
* Translate the customize DSL to Models, Processes, Flows, Tables, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source
|
||||||
|
* Where to get the source of DSL
|
||||||
|
*/
|
||||||
|
function Source() {
|
||||||
|
return dyforms();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile
|
||||||
|
* Translate or extend the customize DSL
|
||||||
|
* @param {*} dsl
|
||||||
|
*/
|
||||||
|
function Compile(name, dsl) {
|
||||||
|
let newdsl = { name: name };
|
||||||
|
return newdsl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OnLoad
|
||||||
|
* When the widget instance are loaded, the function will be called.
|
||||||
|
* For preparing the sources the widget need.
|
||||||
|
* @param {DSL} dsl
|
||||||
|
*/
|
||||||
|
function OnLoad(name, dsl) {
|
||||||
|
console.log(name, dsl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate
|
||||||
|
* When the migrate command executes, the function will be called
|
||||||
|
* @param {DSL} dsl
|
||||||
|
* @param {bool} force
|
||||||
|
*/
|
||||||
|
function Migrate(dsl, force) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customize DSL
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function dyforms() {
|
||||||
|
return {
|
||||||
|
pad: {
|
||||||
|
guard: "bearer-jwt",
|
||||||
|
title: "应用表单",
|
||||||
|
sn: "PAD1024",
|
||||||
|
orign: "手机平板",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: "门店",
|
||||||
|
field: "store_id",
|
||||||
|
searchable: true,
|
||||||
|
props: {
|
||||||
|
value: ":store_id",
|
||||||
|
type: "SelectStore",
|
||||||
|
title: "门店",
|
||||||
|
placeholder: "请选择门店",
|
||||||
|
validation: [
|
||||||
|
{ type: "Required" },
|
||||||
|
{ type: "StoreStatus", args: [":store_id"] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "订单数量",
|
||||||
|
field: "orders_amount",
|
||||||
|
searchable: true,
|
||||||
|
props: {
|
||||||
|
value: ":orders_amount",
|
||||||
|
type: "Number",
|
||||||
|
title: "订单数量",
|
||||||
|
placeholder: "今日订单数量",
|
||||||
|
computed: "OrderAmount",
|
||||||
|
validation: [
|
||||||
|
{ type: "Required" },
|
||||||
|
{ type: "IsNumber", args: [":orders_amount"] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "账单地址",
|
||||||
|
field: "address",
|
||||||
|
props: {
|
||||||
|
value: ":address",
|
||||||
|
type: "Text",
|
||||||
|
title: "账单地址",
|
||||||
|
placeholder: "填写账单地址",
|
||||||
|
validation: [
|
||||||
|
{ type: "Required" },
|
||||||
|
{ type: "MaxLength", args: [":address", 200] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
filters: [],
|
||||||
|
"list-layout": {
|
||||||
|
columns: [{ name: "store_id" }, { name: "orders_amount" }],
|
||||||
|
filters: [{ name: "订单数量" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
152
tests/widgets/dyform/export.js
Normal file
152
tests/widgets/dyform/export.js
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
/**
|
||||||
|
* Export Models, APIs, Flows, Tables, Tasks, Schedules, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export Apis
|
||||||
|
* @param {*} dsl
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function Apis() {
|
||||||
|
let apis = {};
|
||||||
|
apis[`dyform`] = dyformAPI();
|
||||||
|
return apis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export Models
|
||||||
|
* @param {*} dsl
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function Models(name, dsl) {
|
||||||
|
let models = {};
|
||||||
|
models[`dyform.${name}`] = dyformModel(name);
|
||||||
|
return models;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export Flows
|
||||||
|
* @param {*} dsl
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function Flows(name, dsl) {
|
||||||
|
return [{}];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export Tables
|
||||||
|
* @param {*} dsl
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function Tables(name, dsl) {
|
||||||
|
let tables = {};
|
||||||
|
tables[`dyform.${name}`] = dyformTable(name);
|
||||||
|
return tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export Tasks
|
||||||
|
* @param {*} dsl
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function Tasks(name, dsl) {
|
||||||
|
let tasks = {};
|
||||||
|
tasks[`dyform.${name}`] = dyformTask(name);
|
||||||
|
return tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export Schedules
|
||||||
|
* @param {*} dsl
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function Schedules(name, dsl) {
|
||||||
|
let schedules = {};
|
||||||
|
schedules[`dyform.${name}`] = dyformSchedule(name);
|
||||||
|
return schedules;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dyformSchedule(name) {
|
||||||
|
return {
|
||||||
|
name: `Schedule ${name}`,
|
||||||
|
schedule: "*/1 * * * *",
|
||||||
|
process: `widgets.dyform.Save`,
|
||||||
|
args: [name],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function dyformTask(name) {
|
||||||
|
return {
|
||||||
|
name: `Task ${name}`,
|
||||||
|
worker_nums: 2,
|
||||||
|
attempts: 3,
|
||||||
|
attempt_after: 200,
|
||||||
|
timeout: 2,
|
||||||
|
size: 1000,
|
||||||
|
process: `widgets.dyform.Save`,
|
||||||
|
args: [name],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function dyformAPI() {
|
||||||
|
return {
|
||||||
|
name: `dyform API`,
|
||||||
|
version: "1.0.0",
|
||||||
|
description: "dyform APIs",
|
||||||
|
group: "dyform",
|
||||||
|
guard: "-",
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
path: "/:name/search",
|
||||||
|
method: "GET",
|
||||||
|
process: `widgets.dyform.Save`,
|
||||||
|
in: ["$param.name", ":query"],
|
||||||
|
out: { status: 200, type: "application/json" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function dyformTable(name) {
|
||||||
|
return {
|
||||||
|
name: `dyform_${name}`,
|
||||||
|
version: "1.0.0",
|
||||||
|
decription: "云服务库",
|
||||||
|
bind: { model: `dyform.${name}` },
|
||||||
|
apis: {},
|
||||||
|
columns: {},
|
||||||
|
filters: {},
|
||||||
|
list: {
|
||||||
|
primary: "id",
|
||||||
|
layout: { columns: [{ name: "ID", width: 6 }], filters: [] },
|
||||||
|
actions: {},
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
primary: "id",
|
||||||
|
layout: { fieldset: [{ columns: [{ name: "ID", width: 6 }] }] },
|
||||||
|
actions: { cancel: {} },
|
||||||
|
},
|
||||||
|
insert: {},
|
||||||
|
view: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function dyformModel(name) {
|
||||||
|
return {
|
||||||
|
table: { name: `dyform_${name}` },
|
||||||
|
columns: [
|
||||||
|
{ label: "DYFORM ID", name: "id", type: "ID" },
|
||||||
|
{ label: "SN", name: "sn", type: "string", length: 20, unique: true },
|
||||||
|
{ label: "NAME", name: "name", type: "string", length: 200, index: true },
|
||||||
|
{ label: "SOURCE", name: "source", type: "JSON", nullable: true },
|
||||||
|
{
|
||||||
|
label: "TITLE",
|
||||||
|
name: "title",
|
||||||
|
type: "string",
|
||||||
|
length: 200,
|
||||||
|
index: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
indexes: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
3
tests/widgets/dyform/helper.js
Normal file
3
tests/widgets/dyform/helper.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
function Foo(param) {
|
||||||
|
return `${param} World`;
|
||||||
|
}
|
||||||
24
tests/widgets/dyform/process.js
Normal file
24
tests/widgets/dyform/process.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* Export the widget processes
|
||||||
|
* Export() defined witch function in this file will be registered as YAO PROCESS
|
||||||
|
* The process name is <WIDGET NAME>.<INSTANCE NAME>.<FUNCTION NAME>
|
||||||
|
* The processes can be used in compile.js and export.js DIRECTLY
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SchemaSave
|
||||||
|
* Save the schema of dyform
|
||||||
|
* @name: dyform.<INSTANCE>.Save
|
||||||
|
* @param {String} instance the instance name
|
||||||
|
* @param {*} payload
|
||||||
|
*/
|
||||||
|
function SchemaSave(instance, payload) {
|
||||||
|
return { instance: instance, payload: payload };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export processes
|
||||||
|
*/
|
||||||
|
function Export() {
|
||||||
|
return { Save: "SchemaSave" };
|
||||||
|
}
|
||||||
8
tests/widgets/dyform/widget.json
Normal file
8
tests/widgets/dyform/widget.json
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"label": "Dynamic Form",
|
||||||
|
"description": "A form widget. users can design forms online",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"root": "dyforms",
|
||||||
|
"extension": ".form.json",
|
||||||
|
"modules": ["Apis", "Models", "Tables", "Tasks", "Schedules"]
|
||||||
|
}
|
||||||
107
widget/widget.go
Normal file
107
widget/widget.go
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
package widget
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/gou/widget"
|
||||||
|
"github.com/yaoapp/kun/log"
|
||||||
|
"github.com/yaoapp/yao/config"
|
||||||
|
"github.com/yaoapp/yao/share"
|
||||||
|
"github.com/yaoapp/yao/table"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Load Widgets
|
||||||
|
func Load(cfg config.Config) error {
|
||||||
|
var root = filepath.Join(cfg.Root, "widgets")
|
||||||
|
return LoadFrom(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadFrom widget
|
||||||
|
func LoadFrom(dir string) error {
|
||||||
|
|
||||||
|
register := moduleRegister()
|
||||||
|
|
||||||
|
if share.DirNotExists(dir) {
|
||||||
|
return fmt.Errorf("%s does not exists", dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
paths, err := ioutil.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
|
||||||
|
if !path.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
name := path.Name()
|
||||||
|
if _, err := os.Stat(filepath.Join(dir, name, "widget.json")); errors.Is(err, os.ErrNotExist) {
|
||||||
|
// path/to/whatever does not exist
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
w, err := gou.LoadWidget(filepath.Join(dir, name), name, register)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load instances
|
||||||
|
err = w.Load()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func moduleRegister() widget.ModuleRegister {
|
||||||
|
return widget.ModuleRegister{
|
||||||
|
"Apis": func(name string, source []byte) error {
|
||||||
|
_, err := gou.LoadAPIReturn(string(source), name)
|
||||||
|
log.Trace("[Widget] Register api %s", name)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[Widget] Register api %s %v", name, err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
"Models": func(name string, source []byte) error {
|
||||||
|
_, err := gou.LoadModelReturn(string(source), name)
|
||||||
|
log.Trace("[Widget] Register model %s", name)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[Widget] Register model %s %v", name, err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
"Tables": func(name string, source []byte) error {
|
||||||
|
log.Trace("[Widget] Register table %s", name)
|
||||||
|
_, err := table.LoadTable(string(source), name)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[Widget] Register table %s %v", name, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
"Tasks": func(name string, source []byte) error {
|
||||||
|
log.Trace("[Widget] Register task %s", name)
|
||||||
|
_, err := gou.LoadTask(string(source), name)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[Widget] Register task %s %v", name, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
"Schedules": func(name string, source []byte) error {
|
||||||
|
log.Trace("[Widget] Register schedule %s", name)
|
||||||
|
_, err := gou.LoadSchedule(string(source), name)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[Widget] Register schedule %s %v", name, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
25
widget/widget_test.go
Normal file
25
widget/widget_test.go
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package widget
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/kun/any"
|
||||||
|
"github.com/yaoapp/yao/config"
|
||||||
|
"github.com/yaoapp/yao/share"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoad(t *testing.T) {
|
||||||
|
share.DBConnect(config.Conf.DB) // 创建数据库连接
|
||||||
|
Load(config.Conf)
|
||||||
|
LoadFrom("not a path")
|
||||||
|
v, err := gou.NewProcess("widgets.dyform.Save", "pad", "pay").Exec()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := any.Of(v).Map()
|
||||||
|
assert.Equal(t, "pad", res.Get("instance"))
|
||||||
|
assert.Equal(t, "pay", res.Get("payload"))
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue