[change] optimize forms
This commit is contained in:
parent
7e0732e973
commit
6bbcfec0cd
13 changed files with 601 additions and 493 deletions
|
|
@ -5,21 +5,23 @@ import (
|
|||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yaoapp/yao/helper"
|
||||
"github.com/yaoapp/yao/table"
|
||||
table_v0 "github.com/yaoapp/yao/table"
|
||||
|
||||
widget_table "github.com/yaoapp/yao/widgets/table"
|
||||
"github.com/yaoapp/yao/widgets/form"
|
||||
"github.com/yaoapp/yao/widgets/table"
|
||||
)
|
||||
|
||||
// Guards 服务中间件
|
||||
// Guards middlewares
|
||||
var Guards = map[string]gin.HandlerFunc{
|
||||
"bearer-jwt": bearerJWT, // JWT 鉴权
|
||||
"cross-domain": crossDomain, // 跨域许可
|
||||
"table-guard": table.Guard, // Table Guard
|
||||
"widget-table": widget_table.Guard, // Widget Table Guard
|
||||
"bearer-jwt": guardBearerJWT, // Bearer JWT
|
||||
"cross-origin": guardCrossOrigin, // Cross-Origin Resource Sharing
|
||||
"table-guard": table_v0.Guard, // Table Guard ( v0.9 table)
|
||||
"widget-table": table.Guard, // Widget Table Guard
|
||||
"widget-form": form.Guard, // Widget Form Guard
|
||||
}
|
||||
|
||||
// JWT 鉴权
|
||||
func bearerJWT(c *gin.Context) {
|
||||
// JWT Bearer JWT
|
||||
func guardBearerJWT(c *gin.Context) {
|
||||
tokenString := c.Request.Header.Get("Authorization")
|
||||
tokenString = strings.TrimSpace(strings.TrimPrefix(tokenString, "Bearer "))
|
||||
if tokenString == "" {
|
||||
|
|
@ -32,15 +34,15 @@ func bearerJWT(c *gin.Context) {
|
|||
c.Set("__sid", claims.SID)
|
||||
}
|
||||
|
||||
// crossDomain 跨域访问
|
||||
func crossDomain(c *gin.Context) {
|
||||
// CORS Cross Origin
|
||||
func guardCrossOrigin(c *gin.Context) {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(204)
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
|
|
|
|||
244
widgets/compute/compute.go
Normal file
244
widgets/compute/compute.go
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
package compute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/any"
|
||||
"github.com/yaoapp/kun/maps"
|
||||
"github.com/yaoapp/yao/widgets/field"
|
||||
)
|
||||
|
||||
var views = map[string]bool{"find": true, "get": true, "search": true}
|
||||
|
||||
// ComputeEdit edit compute edit
|
||||
func (c *Computable) ComputeEdit(name string, process *gou.Process, args []interface{}, getField func(string) (*field.ColumnDSL, string, error)) error {
|
||||
namer := strings.Split(strings.ToLower(name), ".")
|
||||
name = namer[len(namer)-1]
|
||||
|
||||
switch name {
|
||||
case "save", "create":
|
||||
if len(args) == 0 {
|
||||
return nil
|
||||
}
|
||||
switch args[0].(type) {
|
||||
case maps.MapStr:
|
||||
return c.editRow(process, args[0].(maps.MapStr), getField)
|
||||
|
||||
case map[string]interface{}:
|
||||
return c.editRow(process, args[0].(map[string]interface{}), getField)
|
||||
}
|
||||
return nil
|
||||
|
||||
case "update", "updatewhere", "updatein":
|
||||
if len(args) < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch args[1].(type) {
|
||||
case maps.MapStr:
|
||||
return c.editRow(process, args[1].(maps.MapStr), getField)
|
||||
|
||||
case map[string]interface{}:
|
||||
return c.editRow(process, args[1].(map[string]interface{}), getField)
|
||||
}
|
||||
return nil
|
||||
|
||||
case "insert":
|
||||
if len(args) < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, ok := args[0].([]string); !ok {
|
||||
return fmt.Errorf("args[0] is not a []string %s", reflect.ValueOf(args[0]).Type().Name())
|
||||
}
|
||||
|
||||
if _, ok := args[1].([][]interface{}); !ok {
|
||||
return fmt.Errorf("args[1] is not a [][] %s", reflect.ValueOf(args[1]).Type().Name())
|
||||
}
|
||||
|
||||
return c.editRows(process, args[0].([]string), args[1].([][]interface{}), getField)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditRow edit row
|
||||
func (c *Computable) editRow(process *gou.Process, res map[string]interface{}, getField func(string) (*field.ColumnDSL, string, error)) error {
|
||||
|
||||
messages := []string{}
|
||||
row := maps.MapOf(res).Dot()
|
||||
data := maps.StrAny{"row": row}.Dot()
|
||||
for key := range res {
|
||||
if computes, has := c.Computes.Edit[key]; has {
|
||||
unit := computes[0]
|
||||
field, path, err := getField(unit.Name)
|
||||
if err != nil {
|
||||
messages = append(messages, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
data.Set("value", res[key])
|
||||
data.Merge(any.MapOf(field.Edit.Map()).MapStrAny.Dot())
|
||||
new, err := field.Edit.Compute.Value(data, process.Sid, process.Global)
|
||||
if err != nil {
|
||||
messages = append(messages, fmt.Sprintf("%s.%s bind: %s, value: %v error: %s", path, unit.Name, key, res[key], err.Error()))
|
||||
continue
|
||||
}
|
||||
res[key] = new
|
||||
}
|
||||
}
|
||||
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditRows edit row
|
||||
func (c *Computable) editRows(process *gou.Process, columns []string, res [][]interface{}, getField func(string) (*field.ColumnDSL, string, error)) error {
|
||||
|
||||
messages := []string{}
|
||||
keys := map[string]int{}
|
||||
for i, name := range columns {
|
||||
keys[name] = i
|
||||
}
|
||||
|
||||
for i := range res {
|
||||
if len(keys) != len(res[i]) {
|
||||
continue
|
||||
}
|
||||
|
||||
row := map[string]interface{}{}
|
||||
for i, v := range res[i] {
|
||||
row[columns[i]] = v
|
||||
}
|
||||
|
||||
err := c.editRow(process, row, getField)
|
||||
if err != nil {
|
||||
messages = append(messages, err.Error())
|
||||
}
|
||||
|
||||
for k, v := range row {
|
||||
res[i][keys[k]] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ComputeView view view
|
||||
func (c *Computable) ComputeView(name string, process *gou.Process, res interface{}, getField func(string) (*field.ColumnDSL, string, error)) error {
|
||||
|
||||
namer := strings.Split(strings.ToLower(name), ".")
|
||||
name = namer[len(namer)-1]
|
||||
if _, has := views[name]; !has {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch res.(type) {
|
||||
case []maps.MapStrAny, []interface{}:
|
||||
return c.viewRows(name, process, res, getField)
|
||||
|
||||
case map[string]interface{}:
|
||||
return c.viewRow(name, process, res.(map[string]interface{}), getField)
|
||||
|
||||
case maps.MapStrAny:
|
||||
return c.viewRow(name, process, res.(maps.MapStrAny), getField)
|
||||
}
|
||||
|
||||
return fmt.Errorf("res should be a map or array, but got a %s", reflect.ValueOf(res).Kind().String())
|
||||
}
|
||||
|
||||
// ViewRows viewrows
|
||||
func (c *Computable) viewRows(name string, process *gou.Process, res interface{}, getField func(string) (*field.ColumnDSL, string, error)) error {
|
||||
switch res.(type) {
|
||||
|
||||
case []interface{}:
|
||||
messages := []string{}
|
||||
for i := range res.([]interface{}) {
|
||||
err := c.ComputeView(name, process, res.([]interface{})[i], getField)
|
||||
if err != nil {
|
||||
messages = append(messages, err.Error())
|
||||
}
|
||||
}
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
|
||||
}
|
||||
return nil
|
||||
|
||||
case []maps.MapStrAny:
|
||||
messages := []string{}
|
||||
for i := range res.([]maps.MapStrAny) {
|
||||
err := c.ComputeView(name, process, res.([]maps.MapStrAny)[i], getField)
|
||||
if err != nil {
|
||||
messages = append(messages, fmt.Sprintf("%d %s", i, err.Error()))
|
||||
}
|
||||
}
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ViewRow row
|
||||
func (c *Computable) viewRow(name string, process *gou.Process, res map[string]interface{}, getField func(string) (*field.ColumnDSL, string, error)) error {
|
||||
|
||||
messages := []string{}
|
||||
row := maps.MapOf(res).Dot()
|
||||
data := maps.StrAny{"row": row}.Dot()
|
||||
|
||||
// page
|
||||
if row.Has("data") && row.Has("total") &&
|
||||
row.Has("pagesize") && row.Has("pagecnt") &&
|
||||
row.Has("prev") && row.Has("next") {
|
||||
switch res["data"].(type) {
|
||||
|
||||
case []maps.MapStrAny:
|
||||
return c.viewRows(name, process, res["data"].([]maps.MapStrAny), getField)
|
||||
|
||||
case []interface{}:
|
||||
return c.viewRows(name, process, res["data"].([]interface{}), getField)
|
||||
}
|
||||
}
|
||||
|
||||
for key, computes := range c.Computes.View {
|
||||
unit := computes[0]
|
||||
field, path, err := getField(unit.Name)
|
||||
if err != nil {
|
||||
messages = append(messages, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
data.Set("value", res[key])
|
||||
data.Merge(any.MapOf(field.View.Map()).MapStrAny.Dot())
|
||||
new, err := field.View.Compute.Value(data, process.Sid, process.Global)
|
||||
if err != nil {
|
||||
res[key] = nil
|
||||
messages = append(messages, fmt.Sprintf("%s.%s bind: %s, value: %v error: %s", path, unit.Name, key, res[key], err.Error()))
|
||||
continue
|
||||
}
|
||||
res[key] = new
|
||||
}
|
||||
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ComputeFilter filter
|
||||
func (c *Computable) ComputeFilter(name string, process *gou.Process, args []interface{}, getFilter func(string) (*field.FilterDSL, string, error)) error {
|
||||
return nil
|
||||
}
|
||||
28
widgets/compute/types.go
Normal file
28
widgets/compute/types.go
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package compute
|
||||
|
||||
const (
|
||||
// View View component
|
||||
View uint8 = iota
|
||||
// Edit Edit component
|
||||
Edit
|
||||
// Filter Filter component
|
||||
Filter
|
||||
)
|
||||
|
||||
// Computable with computes
|
||||
type Computable struct {
|
||||
Computes *Maps
|
||||
}
|
||||
|
||||
// Maps compute mapping
|
||||
type Maps struct {
|
||||
Edit map[string][]Unit
|
||||
View map[string][]Unit
|
||||
Filter map[string][]Unit
|
||||
}
|
||||
|
||||
// Unit the compute unit
|
||||
type Unit struct {
|
||||
Name string // index
|
||||
Kind uint8 // Type
|
||||
}
|
||||
|
|
@ -4,11 +4,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/any"
|
||||
"github.com/yaoapp/kun/log"
|
||||
"github.com/yaoapp/kun/maps"
|
||||
"github.com/yaoapp/yao/config"
|
||||
"github.com/yaoapp/yao/i18n"
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
)
|
||||
|
||||
|
|
@ -16,31 +11,38 @@ var processActionDefaults = map[string]*action.Process{
|
|||
|
||||
"Setting": {
|
||||
Name: "yao.form.Setting",
|
||||
Guard: "bearer-jwt",
|
||||
Process: "yao.form.Xgen",
|
||||
Default: []interface{}{nil},
|
||||
},
|
||||
"Component": {
|
||||
Name: "yao.form.Component",
|
||||
Guard: "bearer-jwt",
|
||||
Default: []interface{}{nil, nil, nil},
|
||||
},
|
||||
"Find": {
|
||||
Name: "yao.form.Find",
|
||||
Guard: "bearer-jwt",
|
||||
Default: []interface{}{nil, nil},
|
||||
},
|
||||
"Save": {
|
||||
Name: "yao.form.Save",
|
||||
Guard: "bearer-jwt",
|
||||
Default: []interface{}{nil},
|
||||
},
|
||||
"Create": {
|
||||
Name: "yao.form.Create",
|
||||
Guard: "bearer-jwt",
|
||||
Default: []interface{}{nil},
|
||||
},
|
||||
"Update": {
|
||||
Name: "yao.form.Update",
|
||||
Guard: "bearer-jwt",
|
||||
Default: []interface{}{nil, nil},
|
||||
},
|
||||
"Delete": {
|
||||
Name: "yao.table.Delete",
|
||||
Guard: "bearer-jwt",
|
||||
Default: []interface{}{nil},
|
||||
},
|
||||
}
|
||||
|
|
@ -98,126 +100,3 @@ func (act *ActionDSL) BindModel(m *gou.Model) {
|
|||
act.Find.Default[1] = act.Bind.Option
|
||||
}
|
||||
}
|
||||
|
||||
func processHandler(p *action.Process, process *gou.Process) (interface{}, error) {
|
||||
|
||||
form, err := Get(process)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args := p.Args(process)
|
||||
|
||||
// Process
|
||||
name := p.Process
|
||||
if name == "" {
|
||||
name = p.ProcessBind
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
log.Error("[form] %s %s process is required", form.ID, p.Name)
|
||||
return nil, fmt.Errorf("[form] %s %s process is required", form.ID, p.Name)
|
||||
}
|
||||
|
||||
// Before Hook
|
||||
if p.Before != nil {
|
||||
log.Trace("[form] %s %s before: exec(%v)", form.ID, p.Name, args)
|
||||
newArgs, err := p.Before.Exec(args, process.Sid, process.Global)
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s before: %s", form.ID, p.Name, err.Error())
|
||||
} else {
|
||||
log.Trace("[form] %s %s before: args:%v", form.ID, p.Name, args)
|
||||
args = newArgs
|
||||
}
|
||||
}
|
||||
|
||||
// Compute In
|
||||
switch p.Name {
|
||||
case "yao.form.Save", "yao.form.Create":
|
||||
switch args[0].(type) {
|
||||
case map[string]interface{}, maps.MapStr:
|
||||
data := any.Of(args[0]).Map().MapStrAny
|
||||
err := form.computeSave(process, data)
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
}
|
||||
args[0] = data
|
||||
}
|
||||
break
|
||||
|
||||
case "yao.form.Update":
|
||||
switch args[1].(type) {
|
||||
case map[string]interface{}, maps.MapStr:
|
||||
data := any.Of(args[1]).Map().MapStrAny
|
||||
err := form.computeSave(process, data)
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
}
|
||||
args[1] = data
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// Execute Process
|
||||
act, err := gou.ProcessOf(name, args...)
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
return nil, fmt.Errorf("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
}
|
||||
|
||||
res, err := act.WithGlobal(process.Global).WithSID(process.Sid).Exec()
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
return nil, fmt.Errorf("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
}
|
||||
|
||||
// Compute Out
|
||||
switch p.Name {
|
||||
|
||||
case "yao.form.Find":
|
||||
switch res.(type) {
|
||||
case map[string]interface{}, maps.MapStr:
|
||||
data := any.MapOf(res).MapStrAny
|
||||
err := form.computeFind(process, data)
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
}
|
||||
res = data
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// After hook
|
||||
if p.After != nil {
|
||||
log.Trace("[form] %s %s after: exec(%v)", form.ID, p.Name, res)
|
||||
newRes, err := p.After.Exec(res, process.Sid, process.Global)
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s after: %s", form.ID, p.Name, err.Error())
|
||||
} else {
|
||||
log.Trace("[form] %s %s after: %v", form.ID, p.Name, newRes)
|
||||
res = newRes
|
||||
}
|
||||
}
|
||||
|
||||
// Tranlate
|
||||
if p.Name == "yao.form.Setting" {
|
||||
|
||||
widgets := []string{}
|
||||
if form.Action.Bind.Model != "" {
|
||||
m := gou.Select(form.Action.Bind.Model)
|
||||
widgets = append(widgets, fmt.Sprintf("model.%s", m.ID))
|
||||
}
|
||||
|
||||
if form.Action.Bind.Table != "" {
|
||||
widgets = append(widgets, fmt.Sprintf("table.%s", form.Action.Bind.Table))
|
||||
}
|
||||
|
||||
widgets = append(widgets, fmt.Sprintf("form.%s", form.ID))
|
||||
res, err = i18n.Trans(process.Lang(config.Conf.Lang), widgets, res)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[form] Trans.table.%s %s", form.ID, err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,71 @@
|
|||
package form
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/yao/share"
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
)
|
||||
|
||||
// Guard form widget guard
|
||||
func Guard(c *gin.Context) {
|
||||
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
abort(c, 400, "the form widget id does not found")
|
||||
return
|
||||
}
|
||||
|
||||
form, has := Forms[id]
|
||||
if !has {
|
||||
abort(c, 404, fmt.Sprintf("the form widget %s does not exist", id))
|
||||
return
|
||||
}
|
||||
|
||||
act, err := form.getAction(c.FullPath())
|
||||
if err != nil {
|
||||
abort(c, 404, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = act.UseGuard(c, id)
|
||||
if err != nil {
|
||||
abort(c, 400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func abort(c *gin.Context, code int, message string) {
|
||||
c.JSON(code, gin.H{"code": code, "message": message})
|
||||
c.Abort()
|
||||
}
|
||||
|
||||
func (form *DSL) getAction(path string) (*action.Process, error) {
|
||||
|
||||
switch path {
|
||||
case "/api/__yao/form/:id/setting":
|
||||
return form.Action.Setting, nil
|
||||
case "/api/__yao/form/:id/component/:xpath/:method":
|
||||
return form.Action.Component, nil
|
||||
case "/api/__yao/form/:id/find/:primary":
|
||||
return form.Action.Find, nil
|
||||
case "/api/__yao/form/:id/save":
|
||||
return form.Action.Save, nil
|
||||
case "/api/__yao/form/:id/create":
|
||||
return form.Action.Create, nil
|
||||
case "/api/__yao/form/:id/insert":
|
||||
return form.Action.Update, nil
|
||||
case "/api/__yao/form/:id/delete/:primary":
|
||||
return form.Action.Delete, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("the form widget %s %s action does not exist", form.ID, path)
|
||||
}
|
||||
|
||||
// export API
|
||||
func exportAPI() error {
|
||||
|
||||
|
|
@ -13,7 +73,7 @@ func exportAPI() error {
|
|||
Name: "Widget Form API",
|
||||
Description: "Widget Form API",
|
||||
Version: share.VERSION,
|
||||
Guard: "-",
|
||||
Guard: "widget-form",
|
||||
Group: "__yao/form",
|
||||
Paths: []gou.Path{},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,78 +2,62 @@ package form
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/log"
|
||||
"github.com/yaoapp/yao/widgets/compute"
|
||||
"github.com/yaoapp/yao/widgets/field"
|
||||
)
|
||||
|
||||
func (dsl *DSL) computeFind(process *gou.Process, values map[string]interface{}) error {
|
||||
func (dsl *DSL) getField() func(string) (*field.ColumnDSL, string, error) {
|
||||
return func(name string) (*field.ColumnDSL, string, error) {
|
||||
field, has := dsl.Fields.Form[name]
|
||||
if !has {
|
||||
return nil, "fields.table", fmt.Errorf("fields.table.%s does not exist", name)
|
||||
}
|
||||
return &field, "fields.table", nil
|
||||
}
|
||||
}
|
||||
|
||||
messages := []string{}
|
||||
for key := range values {
|
||||
err := dsl.computeOut(process, key, values)
|
||||
if err != nil {
|
||||
messages = append(messages, err.Error())
|
||||
func (dsl *DSL) computeMapping() error {
|
||||
if dsl.Computes == nil {
|
||||
dsl.Computes = &compute.Maps{
|
||||
Filter: map[string][]compute.Unit{},
|
||||
Edit: map[string][]compute.Unit{},
|
||||
View: map[string][]compute.Unit{},
|
||||
}
|
||||
}
|
||||
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(messages, ";"))
|
||||
if dsl.Fields == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if dsl.Fields.Form != nil && dsl.Layout.Form != nil && dsl.Layout.Form.Sections != nil {
|
||||
for _, section := range dsl.Layout.Form.Sections {
|
||||
|
||||
for _, inst := range section.Columns {
|
||||
|
||||
if field, has := dsl.Fields.Form[inst.Name]; has {
|
||||
|
||||
// View
|
||||
if field.View != nil && field.View.Compute != nil {
|
||||
bind := field.ViewBind()
|
||||
if _, has := dsl.Computes.View[bind]; !has {
|
||||
dsl.Computes.View[bind] = []compute.Unit{}
|
||||
}
|
||||
dsl.Computes.View[bind] = append(dsl.Computes.View[bind], compute.Unit{Name: inst.Name, Kind: compute.View})
|
||||
}
|
||||
|
||||
// Edit
|
||||
if field.Edit != nil && field.Edit.Compute != nil {
|
||||
bind := field.EditBind()
|
||||
if _, has := dsl.Computes.Edit[bind]; !has {
|
||||
dsl.Computes.Edit[bind] = []compute.Unit{}
|
||||
}
|
||||
dsl.Computes.Edit[bind] = append(dsl.Computes.Edit[bind], compute.Unit{Name: inst.Name, Kind: compute.Edit})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeSave(process *gou.Process, values map[string]interface{}) error {
|
||||
|
||||
messages := []string{}
|
||||
for key := range values {
|
||||
err := dsl.computeIn(process, key, values)
|
||||
if err != nil {
|
||||
messages = append(messages, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(messages, ";"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeIn(process *gou.Process, key string, values map[string]interface{}) error {
|
||||
if name, has := dsl.ComputesIn[key]; has {
|
||||
compute, err := gou.ProcessOf(name, key, values[key], values)
|
||||
if err != nil {
|
||||
log.Error("[form] %s compute-in -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
return fmt.Errorf("[form] %s compute-in -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
}
|
||||
|
||||
res, err := compute.WithGlobal(process.Global).WithSID(process.Sid).Exec()
|
||||
if err != nil {
|
||||
log.Error("[form] %s compute-in -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
return fmt.Errorf("[form] %s compute-in -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
}
|
||||
values[key] = res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeOut(process *gou.Process, key string, values map[string]interface{}) error {
|
||||
if name, has := dsl.ComputesOut[key]; has {
|
||||
compute, err := gou.ProcessOf(name, key, values[key], values)
|
||||
if err != nil {
|
||||
log.Error("[form] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
return fmt.Errorf("[form] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
}
|
||||
|
||||
res, err := compute.WithGlobal(process.Global).WithSID(process.Sid).Exec()
|
||||
if err != nil {
|
||||
log.Error("[form] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
return fmt.Errorf("[form] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
}
|
||||
values[key] = res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,11 +53,9 @@ var Forms map[string]*DSL = map[string]*DSL{}
|
|||
// New create a new DSL
|
||||
func New(id string) *DSL {
|
||||
return &DSL{
|
||||
ID: id,
|
||||
Fields: &FieldsDSL{Form: field.Columns{}},
|
||||
CProps: field.CloudProps{},
|
||||
ComputesIn: field.ComputeFields{},
|
||||
ComputesOut: field.ComputeFields{},
|
||||
ID: id,
|
||||
Fields: &FieldsDSL{Form: field.Columns{}},
|
||||
CProps: field.CloudProps{},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +168,10 @@ func MustGet(form interface{}) *DSL {
|
|||
func (dsl *DSL) Parse() error {
|
||||
|
||||
// ComputeFields
|
||||
// dsl.Fields.Form.ComputeFieldsMerge(dsl.ComputesIn, dsl.ComputesOut)
|
||||
err := dsl.computeMapping()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Columns
|
||||
return dsl.Fields.Form.CPropsMerge(dsl.CProps, func(name string, kind string, column field.ColumnDSL) (xpath string) {
|
||||
|
|
|
|||
125
widgets/form/handler.go
Normal file
125
widgets/form/handler.go
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
package form
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/log"
|
||||
"github.com/yaoapp/yao/config"
|
||||
"github.com/yaoapp/yao/i18n"
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
)
|
||||
|
||||
// ********************************
|
||||
// * Execute the process of form *
|
||||
// ********************************
|
||||
// Life-Circle: Before Hook → Compute Edit → Run Process → Compute View → After Hook
|
||||
// Execute Compute Edit On: Save, Create, Update
|
||||
// Execute Compute View On: Find
|
||||
func processHandler(p *action.Process, process *gou.Process) (interface{}, error) {
|
||||
|
||||
form, err := Get(process)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args := p.Args(process)
|
||||
|
||||
// Process
|
||||
name := p.Process
|
||||
if name == "" {
|
||||
name = p.ProcessBind
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
log.Error("[form] %s %s process is required", form.ID, p.Name)
|
||||
return nil, fmt.Errorf("[form] %s %s process is required", form.ID, p.Name)
|
||||
}
|
||||
|
||||
// Before Hook
|
||||
if p.Before != nil {
|
||||
log.Trace("[form] %s %s before: exec(%v)", form.ID, p.Name, args)
|
||||
newArgs, err := p.Before.Exec(args, process.Sid, process.Global)
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s before: %s", form.ID, p.Name, err.Error())
|
||||
} else {
|
||||
log.Trace("[form] %s %s before: args:%v", form.ID, p.Name, args)
|
||||
args = newArgs
|
||||
}
|
||||
}
|
||||
|
||||
// Compute Edit
|
||||
err = form.ComputeEdit(p.Name, process, args, form.getField())
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s Compute Edit Error: %s", form.ID, p.Name, err.Error())
|
||||
}
|
||||
|
||||
// Execute Process
|
||||
act, err := gou.ProcessOf(name, args...)
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
return nil, fmt.Errorf("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
}
|
||||
|
||||
res, err := act.WithGlobal(process.Global).WithSID(process.Sid).Exec()
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
return nil, fmt.Errorf("[form] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
}
|
||||
|
||||
// Compute View
|
||||
err = form.ComputeView(p.Name, process, res, form.getField())
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s Compute View Error: %s", form.ID, p.Name, err.Error())
|
||||
}
|
||||
|
||||
// After hook
|
||||
if p.After != nil {
|
||||
log.Trace("[form] %s %s after: exec(%v)", form.ID, p.Name, res)
|
||||
newRes, err := p.After.Exec(res, process.Sid, process.Global)
|
||||
if err != nil {
|
||||
log.Error("[form] %s %s after: %s", form.ID, p.Name, err.Error())
|
||||
} else {
|
||||
log.Trace("[form] %s %s after: %v", form.ID, p.Name, newRes)
|
||||
res = newRes
|
||||
}
|
||||
}
|
||||
|
||||
// Tranlate the result
|
||||
newRes, err := form.translate(p.Name, process, res)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[form] %s %s Translate Error: %s", form.ID, p.Name, err.Error())
|
||||
}
|
||||
|
||||
return newRes, nil
|
||||
}
|
||||
|
||||
// translateSetting
|
||||
func (dsl *DSL) translate(name string, process *gou.Process, data interface{}) (interface{}, error) {
|
||||
|
||||
if strings.ToLower(name) != "yao.form.setting" {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
widgets := []string{}
|
||||
if dsl.Action.Bind.Model != "" {
|
||||
m := gou.Select(dsl.Action.Bind.Model)
|
||||
widgets = append(widgets, fmt.Sprintf("model.%s", m.ID))
|
||||
}
|
||||
|
||||
if dsl.Action.Bind.Table != "" {
|
||||
widgets = append(widgets, fmt.Sprintf("table.%s", dsl.Action.Bind.Table))
|
||||
}
|
||||
|
||||
if dsl.Action.Bind.Form != "" {
|
||||
widgets = append(widgets, fmt.Sprintf("form.%s", dsl.Action.Bind.Form))
|
||||
}
|
||||
|
||||
widgets = append(widgets, fmt.Sprintf("form.%s", dsl.ID))
|
||||
res, err := i18n.Trans(process.Lang(config.Conf.Lang), widgets, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
|
@ -3,21 +3,21 @@ package form
|
|||
import (
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
"github.com/yaoapp/yao/widgets/component"
|
||||
"github.com/yaoapp/yao/widgets/compute"
|
||||
"github.com/yaoapp/yao/widgets/field"
|
||||
"github.com/yaoapp/yao/widgets/hook"
|
||||
)
|
||||
|
||||
// DSL the form DSL
|
||||
type DSL struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Action *ActionDSL `json:"action"`
|
||||
Layout *LayoutDSL `json:"layout"`
|
||||
Fields *FieldsDSL `json:"fields"`
|
||||
Config map[string]interface{} `json:"config,omitempty"`
|
||||
ComputesIn field.ComputeFields `json:"-"`
|
||||
ComputesOut field.ComputeFields `json:"-"`
|
||||
CProps field.CloudProps `json:"-"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Action *ActionDSL `json:"action"`
|
||||
Layout *LayoutDSL `json:"layout"`
|
||||
Fields *FieldsDSL `json:"fields"`
|
||||
Config map[string]interface{} `json:"config,omitempty"`
|
||||
CProps field.CloudProps `json:"-"`
|
||||
compute.Computable
|
||||
}
|
||||
|
||||
// ActionDSL the form action DSL
|
||||
|
|
@ -47,6 +47,7 @@ type BindActionDSL struct {
|
|||
Model string `json:"model,omitempty"` // bind model
|
||||
Store string `json:"store,omitempty"` // bind store
|
||||
Table string `json:"table,omitempty"` // bind table
|
||||
Form string `json:"form,omitempty"` // bind form
|
||||
Option map[string]interface{} `json:"option,omitempty"` // bind option
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,26 +2,37 @@ package table
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/any"
|
||||
"github.com/yaoapp/kun/maps"
|
||||
"github.com/yaoapp/yao/widgets/compute"
|
||||
"github.com/yaoapp/yao/widgets/field"
|
||||
)
|
||||
|
||||
var computeViews = map[string]bool{
|
||||
"yao.table.find": true,
|
||||
"yao.table.get": true,
|
||||
"yao.table.search": true,
|
||||
func (dsl *DSL) getField() func(string) (*field.ColumnDSL, string, error) {
|
||||
return func(name string) (*field.ColumnDSL, string, error) {
|
||||
field, has := dsl.Fields.Table[name]
|
||||
if !has {
|
||||
return nil, "fields.table", fmt.Errorf("fields.table.%s does not exist", name)
|
||||
}
|
||||
return &field, "fields.table", nil
|
||||
}
|
||||
}
|
||||
|
||||
func (dsl *DSL) getFilter() func(string) (*field.FilterDSL, string, error) {
|
||||
return func(name string) (*field.FilterDSL, string, error) {
|
||||
field, has := dsl.Fields.Filter[name]
|
||||
if !has {
|
||||
return nil, "fields.filter", fmt.Errorf("fields.filter.%s does not exist", name)
|
||||
}
|
||||
return &field, "fields.filter", nil
|
||||
}
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeMapping() error {
|
||||
if dsl.computes == nil {
|
||||
dsl.computes = &computeMaps{
|
||||
filter: map[string][]compute{},
|
||||
edit: map[string][]compute{},
|
||||
view: map[string][]compute{},
|
||||
if dsl.Computes == nil {
|
||||
dsl.Computes = &compute.Maps{
|
||||
Filter: map[string][]compute.Unit{},
|
||||
Edit: map[string][]compute.Unit{},
|
||||
View: map[string][]compute.Unit{},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -35,10 +46,10 @@ func (dsl *DSL) computeMapping() error {
|
|||
if filter, has := dsl.Fields.Filter[inst.Name]; has {
|
||||
if filter.Edit != nil && filter.Edit.Compute != nil {
|
||||
bind := filter.FilterBind()
|
||||
if _, has := dsl.computes.filter[bind]; !has {
|
||||
dsl.computes.filter[bind] = []compute{}
|
||||
if _, has := dsl.Computes.Filter[bind]; !has {
|
||||
dsl.Computes.Filter[bind] = []compute.Unit{}
|
||||
}
|
||||
dsl.computes.filter[bind] = append(dsl.computes.filter[bind], compute{name: inst.Name, kind: TypeFilter})
|
||||
dsl.Computes.Filter[bind] = append(dsl.Computes.Filter[bind], compute.Unit{Name: inst.Name, Kind: compute.Filter})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,19 +61,19 @@ func (dsl *DSL) computeMapping() error {
|
|||
// View
|
||||
if field.View != nil && field.View.Compute != nil {
|
||||
bind := field.ViewBind()
|
||||
if _, has := dsl.computes.view[bind]; !has {
|
||||
dsl.computes.view[bind] = []compute{}
|
||||
if _, has := dsl.Computes.View[bind]; !has {
|
||||
dsl.Computes.View[bind] = []compute.Unit{}
|
||||
}
|
||||
dsl.computes.view[bind] = append(dsl.computes.view[bind], compute{name: inst.Name, kind: TypeView})
|
||||
dsl.Computes.View[bind] = append(dsl.Computes.View[bind], compute.Unit{Name: inst.Name, Kind: compute.View})
|
||||
}
|
||||
|
||||
// Edit
|
||||
if field.Edit != nil && field.Edit.Compute != nil {
|
||||
bind := field.EditBind()
|
||||
if _, has := dsl.computes.edit[bind]; !has {
|
||||
dsl.computes.edit[bind] = []compute{}
|
||||
if _, has := dsl.Computes.Edit[bind]; !has {
|
||||
dsl.Computes.Edit[bind] = []compute.Unit{}
|
||||
}
|
||||
dsl.computes.edit[bind] = append(dsl.computes.edit[bind], compute{name: inst.Name, kind: TypeEdit})
|
||||
dsl.Computes.Edit[bind] = append(dsl.Computes.Edit[bind], compute.Unit{Name: inst.Name, Kind: compute.Edit})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -70,212 +81,3 @@ func (dsl *DSL) computeMapping() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeView(name string, process *gou.Process, res interface{}) error {
|
||||
|
||||
if _, has := computeViews[strings.ToLower(name)]; !has {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch res.(type) {
|
||||
case []maps.MapStrAny, []interface{}:
|
||||
return dsl.computeViewRows(name, process, res)
|
||||
|
||||
case map[string]interface{}:
|
||||
return dsl.computeViewRow(name, process, res.(map[string]interface{}))
|
||||
|
||||
case maps.MapStrAny:
|
||||
return dsl.computeViewRow(name, process, res.(maps.MapStrAny))
|
||||
}
|
||||
|
||||
return fmt.Errorf("res should be a map or array, but got a %s", reflect.ValueOf(res).Kind().String())
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeViewRows(name string, process *gou.Process, res interface{}) error {
|
||||
switch res.(type) {
|
||||
|
||||
case []interface{}:
|
||||
messages := []string{}
|
||||
for i := range res.([]interface{}) {
|
||||
err := dsl.computeView(name, process, res.([]interface{})[i])
|
||||
if err != nil {
|
||||
messages = append(messages, err.Error())
|
||||
}
|
||||
}
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
|
||||
}
|
||||
return nil
|
||||
|
||||
case []maps.MapStrAny:
|
||||
messages := []string{}
|
||||
for i := range res.([]maps.MapStrAny) {
|
||||
err := dsl.computeView(name, process, res.([]maps.MapStrAny)[i])
|
||||
if err != nil {
|
||||
messages = append(messages, fmt.Sprintf("%d %s", i, err.Error()))
|
||||
}
|
||||
}
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeViewRow(name string, process *gou.Process, res map[string]interface{}) error {
|
||||
|
||||
messages := []string{}
|
||||
row := maps.MapOf(res).Dot()
|
||||
data := maps.StrAny{"row": row}.Dot()
|
||||
|
||||
// page
|
||||
if row.Has("data") && row.Has("total") &&
|
||||
row.Has("pagesize") && row.Has("pagecnt") &&
|
||||
row.Has("prev") && row.Has("next") {
|
||||
switch res["data"].(type) {
|
||||
|
||||
case []maps.MapStrAny:
|
||||
return dsl.computeViewRows(name, process, res["data"].([]maps.MapStrAny))
|
||||
|
||||
case []interface{}:
|
||||
return dsl.computeViewRows(name, process, res["data"].([]interface{}))
|
||||
}
|
||||
}
|
||||
|
||||
for key, computes := range dsl.computes.view {
|
||||
c := computes[0]
|
||||
field := dsl.Fields.Table[c.name]
|
||||
data.Set("value", res[key])
|
||||
data.Merge(any.MapOf(field.View.Map()).MapStrAny.Dot())
|
||||
new, err := field.View.Compute.Value(data, process.Sid, process.Global)
|
||||
if err != nil {
|
||||
res[key] = nil
|
||||
messages = append(messages, fmt.Sprintf("fields.table.%s bind: %s, value: %v error: %s", c.name, key, res[key], err.Error()))
|
||||
continue
|
||||
}
|
||||
res[key] = new
|
||||
}
|
||||
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeEdit(name string, process *gou.Process, args []interface{}) error {
|
||||
name = strings.ToLower(name)
|
||||
switch name {
|
||||
case "yao.table.save", "yao.table.create":
|
||||
if len(args) == 0 {
|
||||
return nil
|
||||
}
|
||||
switch args[0].(type) {
|
||||
case maps.MapStr:
|
||||
return dsl.computeEditRow(name, process, args[0].(maps.MapStr))
|
||||
|
||||
case map[string]interface{}:
|
||||
return dsl.computeEditRow(name, process, args[0].(map[string]interface{}))
|
||||
}
|
||||
return nil
|
||||
|
||||
case "yao.table.update", "yao.table.updatewhere", "yao.table.updatein":
|
||||
if len(args) < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch args[1].(type) {
|
||||
case maps.MapStr:
|
||||
return dsl.computeEditRow(name, process, args[1].(maps.MapStr))
|
||||
|
||||
case map[string]interface{}:
|
||||
return dsl.computeEditRow(name, process, args[1].(map[string]interface{}))
|
||||
}
|
||||
return nil
|
||||
|
||||
case "yao.table.insert":
|
||||
if len(args) < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, ok := args[0].([]string); !ok {
|
||||
return fmt.Errorf("args[0] is not a []string %s", reflect.ValueOf(args[0]).Type().Name())
|
||||
}
|
||||
|
||||
if _, ok := args[1].([][]interface{}); !ok {
|
||||
return fmt.Errorf("args[1] is not a [][] %s", reflect.ValueOf(args[1]).Type().Name())
|
||||
}
|
||||
|
||||
return dsl.computeEditRows(name, process, args[0].([]string), args[1].([][]interface{}))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeEditRow(name string, process *gou.Process, res map[string]interface{}) error {
|
||||
|
||||
messages := []string{}
|
||||
row := maps.MapOf(res).Dot()
|
||||
data := maps.StrAny{"row": row}.Dot()
|
||||
for key := range res {
|
||||
if computes, has := dsl.computes.edit[key]; has {
|
||||
c := computes[0]
|
||||
field := dsl.Fields.Table[c.name]
|
||||
data.Set("value", res[key])
|
||||
data.Merge(any.MapOf(field.Edit.Map()).MapStrAny.Dot())
|
||||
new, err := field.Edit.Compute.Value(data, process.Sid, process.Global)
|
||||
if err != nil {
|
||||
messages = append(messages, fmt.Sprintf("fields.table.%s bind: %s, value: %v error: %s", c.name, key, res[key], err.Error()))
|
||||
continue
|
||||
}
|
||||
res[key] = new
|
||||
}
|
||||
}
|
||||
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeEditRows(name string, process *gou.Process, columns []string, res [][]interface{}) error {
|
||||
|
||||
messages := []string{}
|
||||
keys := map[string]int{}
|
||||
for i, name := range columns {
|
||||
keys[name] = i
|
||||
}
|
||||
|
||||
for i := range res {
|
||||
if len(keys) != len(res[i]) {
|
||||
continue
|
||||
}
|
||||
|
||||
row := map[string]interface{}{}
|
||||
for i, v := range res[i] {
|
||||
row[columns[i]] = v
|
||||
}
|
||||
|
||||
err := dsl.computeEditRow(name, process, row)
|
||||
if err != nil {
|
||||
messages = append(messages, err.Error())
|
||||
}
|
||||
|
||||
for k, v := range row {
|
||||
res[i][keys[k]] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsl *DSL) computeFilter(name string, process *gou.Process, args []interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@ func TestComputeMapping(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, 11, len(tab.computes.view))
|
||||
assert.Equal(t, 1, len(tab.computes.view["created_at"]))
|
||||
assert.Equal(t, 1, len(tab.computes.view["stay"]))
|
||||
assert.Equal(t, 4, len(tab.computes.edit))
|
||||
assert.Equal(t, 1, len(tab.computes.edit["stay"]))
|
||||
assert.Equal(t, 2, len(tab.computes.filter))
|
||||
assert.Equal(t, 2, len(tab.computes.filter["where.name.like"]))
|
||||
assert.Equal(t, 11, len(tab.Computes.View))
|
||||
assert.Equal(t, 1, len(tab.Computes.View["created_at"]))
|
||||
assert.Equal(t, 1, len(tab.Computes.View["stay"]))
|
||||
assert.Equal(t, 4, len(tab.Computes.Edit))
|
||||
assert.Equal(t, 1, len(tab.Computes.Edit["stay"]))
|
||||
assert.Equal(t, 2, len(tab.Computes.Filter))
|
||||
assert.Equal(t, 2, len(tab.Computes.Filter["where.name.like"]))
|
||||
}
|
||||
|
||||
func TestComputeFind(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package table
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/log"
|
||||
|
|
@ -15,7 +16,7 @@ import (
|
|||
// ********************************
|
||||
// Life-Circle: Compute Filter → Before Hook → Compute Edit → Run Process → Compute View → After Hook
|
||||
// Execute Compute Filter On: Search, Get, Find
|
||||
// Execute Compute Edit On: Save, Create, Update, UpdateWhere, UpdateIn, Insert(not support yet)
|
||||
// Execute Compute Edit On: Save, Create, Update, UpdateWhere, UpdateIn, Insert
|
||||
// Execute Compute View On: Search, Get, Find
|
||||
func processHandler(p *action.Process, process *gou.Process) (interface{}, error) {
|
||||
|
||||
|
|
@ -37,7 +38,7 @@ func processHandler(p *action.Process, process *gou.Process) (interface{}, error
|
|||
}
|
||||
|
||||
// Compute Filter
|
||||
err = tab.computeFilter(p.Name, process, args)
|
||||
err = tab.ComputeFilter(p.Name, process, args, tab.getFilter())
|
||||
if err != nil {
|
||||
log.Error("[table] %s %s Compute Filter Error: %s", tab.ID, p.Name, err.Error())
|
||||
}
|
||||
|
|
@ -55,7 +56,7 @@ func processHandler(p *action.Process, process *gou.Process) (interface{}, error
|
|||
}
|
||||
|
||||
// Compute Edit
|
||||
err = tab.computeEdit(p.Name, process, args)
|
||||
err = tab.ComputeEdit(p.Name, process, args, tab.getField())
|
||||
if err != nil {
|
||||
log.Error("[table] %s %s Compute Edit Error: %s", tab.ID, p.Name, err.Error())
|
||||
}
|
||||
|
|
@ -74,7 +75,7 @@ func processHandler(p *action.Process, process *gou.Process) (interface{}, error
|
|||
}
|
||||
|
||||
// Compute View
|
||||
err = tab.computeView(p.Name, process, res)
|
||||
err = tab.ComputeView(p.Name, process, res, tab.getField())
|
||||
if err != nil {
|
||||
log.Error("[table] %s %s Compute View Error: %s", tab.ID, p.Name, err.Error())
|
||||
}
|
||||
|
|
@ -103,7 +104,7 @@ func processHandler(p *action.Process, process *gou.Process) (interface{}, error
|
|||
// translateSetting
|
||||
func (dsl *DSL) translate(name string, process *gou.Process, data interface{}) (interface{}, error) {
|
||||
|
||||
if name != "yao.table.Setting" {
|
||||
if strings.ToLower(name) != "yao.table.setting" {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,41 +3,22 @@ package table
|
|||
import (
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
"github.com/yaoapp/yao/widgets/component"
|
||||
"github.com/yaoapp/yao/widgets/compute"
|
||||
"github.com/yaoapp/yao/widgets/field"
|
||||
"github.com/yaoapp/yao/widgets/hook"
|
||||
)
|
||||
|
||||
const (
|
||||
// TypeView View component
|
||||
TypeView uint8 = iota
|
||||
// TypeEdit Edit component
|
||||
TypeEdit
|
||||
// TypeFilter Filter component
|
||||
TypeFilter
|
||||
)
|
||||
|
||||
// DSL the table DSL
|
||||
type DSL struct {
|
||||
Root string `json:"-"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Action *ActionDSL `json:"action"`
|
||||
Layout *LayoutDSL `json:"layout"`
|
||||
Fields *FieldsDSL `json:"fields"`
|
||||
Config map[string]interface{} `json:"config,omitempty"`
|
||||
CProps field.CloudProps `json:"-"`
|
||||
computes *computeMaps
|
||||
}
|
||||
|
||||
type computeMaps struct {
|
||||
edit map[string][]compute
|
||||
view map[string][]compute
|
||||
filter map[string][]compute
|
||||
}
|
||||
|
||||
type compute struct {
|
||||
name string // index
|
||||
kind uint8 // Type
|
||||
Root string `json:"-"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Action *ActionDSL `json:"action"`
|
||||
Layout *LayoutDSL `json:"layout"`
|
||||
Fields *FieldsDSL `json:"fields"`
|
||||
Config map[string]interface{} `json:"config,omitempty"`
|
||||
CProps field.CloudProps `json:"-"`
|
||||
compute.Computable
|
||||
}
|
||||
|
||||
// ActionDSL the table action DSL
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue