[add] widget chart guard & compute
This commit is contained in:
parent
0977059997
commit
2b745dd7af
8 changed files with 237 additions and 131 deletions
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/yaoapp/yao/helper"
|
||||
table_v0 "github.com/yaoapp/yao/table"
|
||||
|
||||
"github.com/yaoapp/yao/widgets/chart"
|
||||
"github.com/yaoapp/yao/widgets/form"
|
||||
"github.com/yaoapp/yao/widgets/table"
|
||||
)
|
||||
|
|
@ -18,6 +19,7 @@ var Guards = map[string]gin.HandlerFunc{
|
|||
"table-guard": table_v0.Guard, // Table Guard ( v0.9 table)
|
||||
"widget-table": table.Guard, // Widget Table Guard
|
||||
"widget-form": form.Guard, // Widget Form Guard
|
||||
"widget-chart": chart.Guard, // Widget Chart Guard
|
||||
}
|
||||
|
||||
// JWT Bearer JWT
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
package chart
|
||||
|
||||
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/widgets/action"
|
||||
)
|
||||
|
||||
|
|
@ -14,15 +8,18 @@ var processActionDefaults = map[string]*action.Process{
|
|||
|
||||
"Setting": {
|
||||
Name: "yao.chart.Setting",
|
||||
Guard: "bearer-jwt",
|
||||
Process: "yao.chart.Xgen",
|
||||
Default: []interface{}{nil},
|
||||
},
|
||||
"Component": {
|
||||
Name: "yao.chart.Component",
|
||||
Guard: "bearer-jwt",
|
||||
Default: []interface{}{nil, nil, nil},
|
||||
},
|
||||
"Data": {
|
||||
Name: "yao.chart.Data",
|
||||
Guard: "bearer-jwt",
|
||||
Default: []interface{}{nil},
|
||||
},
|
||||
}
|
||||
|
|
@ -42,80 +39,4 @@ func (act *ActionDSL) SetDefaultProcess() {
|
|||
WithBefore(act.BeforeData).WithAfter(act.AfterData).
|
||||
Merge(processActionDefaults["Data"]).
|
||||
SetHandler(processHandler)
|
||||
|
||||
}
|
||||
|
||||
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("[chart] %s %s process is required", form.ID, p.Name)
|
||||
return nil, fmt.Errorf("[chart] %s %s process is required", form.ID, p.Name)
|
||||
}
|
||||
|
||||
// Before Hook
|
||||
if p.Before != nil {
|
||||
log.Trace("[chart] %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("[chart] %s %s before: %s", form.ID, p.Name, err.Error())
|
||||
} else {
|
||||
log.Trace("[chart] %s %s before: args:%v", form.ID, p.Name, args)
|
||||
args = newArgs
|
||||
}
|
||||
}
|
||||
|
||||
// Execute Process
|
||||
act, err := gou.ProcessOf(name, args...)
|
||||
if err != nil {
|
||||
log.Error("[chart] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
return nil, fmt.Errorf("[chart] %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("[chart] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
return nil, fmt.Errorf("[chart] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
}
|
||||
|
||||
// Compute Out
|
||||
switch p.Name {
|
||||
|
||||
case "yao.chart.Data":
|
||||
switch res.(type) {
|
||||
case map[string]interface{}, maps.MapStr:
|
||||
data := any.MapOf(res).MapStrAny
|
||||
err := form.computeData(process, data)
|
||||
if err != nil {
|
||||
log.Error("[chart] %s %s -> %s %s", form.ID, p.Name, name, err.Error())
|
||||
}
|
||||
res = data
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// After hook
|
||||
if p.After != nil {
|
||||
log.Trace("[chart] %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("[chart] %s %s after: %s", form.ID, p.Name, err.Error())
|
||||
} else {
|
||||
log.Trace("[chart] %s %s after: %v", form.ID, p.Name, newRes)
|
||||
res = newRes
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,63 @@
|
|||
package chart
|
||||
|
||||
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 chart
|
||||
func Guard(c *gin.Context) {
|
||||
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
abort(c, 400, "the chart widget id does not found")
|
||||
return
|
||||
}
|
||||
|
||||
chart, has := Charts[id]
|
||||
if !has {
|
||||
abort(c, 404, fmt.Sprintf("the chart widget %s does not exist", id))
|
||||
return
|
||||
}
|
||||
|
||||
act, err := chart.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 (chart *DSL) getAction(path string) (*action.Process, error) {
|
||||
|
||||
switch path {
|
||||
case "/api/__yao/chart/:id/setting":
|
||||
return chart.Action.Setting, nil
|
||||
case "/api/__yao/chart/:id/component/:xpath/:method":
|
||||
return chart.Action.Component, nil
|
||||
case "/api/__yao/chart/:id/data":
|
||||
return chart.Action.Data, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("the form widget %s %s action does not exist", chart.ID, path)
|
||||
}
|
||||
|
||||
// export API
|
||||
func exportAPI() error {
|
||||
|
||||
|
|
@ -13,7 +65,7 @@ func exportAPI() error {
|
|||
Name: "Widget Form API",
|
||||
Description: "Widget Form API",
|
||||
Version: share.VERSION,
|
||||
Guard: "-",
|
||||
Guard: "widget-chart",
|
||||
Group: "__yao/chart",
|
||||
Paths: []gou.Path{},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,11 +37,10 @@ var Charts map[string]*DSL = map[string]*DSL{}
|
|||
// New create a new DSL
|
||||
func New(id string) *DSL {
|
||||
return &DSL{
|
||||
ID: id,
|
||||
Fields: &FieldsDSL{Chart: field.Columns{}, Filter: field.Filters{}},
|
||||
CProps: field.CloudProps{},
|
||||
ComputesIn: field.ComputeFields{},
|
||||
ComputesOut: field.ComputeFields{},
|
||||
ID: id,
|
||||
Fields: &FieldsDSL{Chart: field.Columns{}, Filter: field.Filters{}},
|
||||
CProps: field.CloudProps{},
|
||||
Config: map[string]interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,10 +142,13 @@ func MustGet(chart interface{}) *DSL {
|
|||
func (dsl *DSL) Parse() error {
|
||||
|
||||
// ComputeFields
|
||||
// dsl.Fields.Chart.ComputeFieldsMerge(dsl.ComputesIn, dsl.ComputesOut)
|
||||
err := dsl.computeMapping()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Filters
|
||||
err := dsl.Fields.Filter.CPropsMerge(dsl.CProps, func(name string, filter field.FilterDSL) (xpath string) {
|
||||
err = dsl.Fields.Filter.CPropsMerge(dsl.CProps, func(name string, filter field.FilterDSL) (xpath string) {
|
||||
return fmt.Sprintf("fields.filter.%s.edit.props", name)
|
||||
})
|
||||
|
||||
|
|
@ -173,6 +175,11 @@ func (dsl *DSL) Xgen() (map[string]interface{}, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// full width default value
|
||||
if _, has := dsl.Config["full"]; !has {
|
||||
dsl.Config["full"] = true
|
||||
}
|
||||
|
||||
setting["fields"] = fields
|
||||
setting["config"] = dsl.Config
|
||||
for _, cProp := range dsl.CProps {
|
||||
|
|
|
|||
|
|
@ -2,43 +2,73 @@ package chart
|
|||
|
||||
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) computeData(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.Chart[name]
|
||||
if !has {
|
||||
return nil, "fields.chart", fmt.Errorf("fields.chart.%s does not exist", name)
|
||||
}
|
||||
return &field, "fields.chart", nil
|
||||
}
|
||||
}
|
||||
|
||||
messages := []string{}
|
||||
for key := range values {
|
||||
err := dsl.computeOut(process, key, values)
|
||||
if err != nil {
|
||||
messages = append(messages, err.Error())
|
||||
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 = &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
|
||||
}
|
||||
|
||||
// Filter
|
||||
if dsl.Fields.Filter != nil && dsl.Layout.Filter != nil && dsl.Layout.Filter.Columns != nil {
|
||||
for _, inst := range dsl.Layout.Filter.Columns {
|
||||
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.Unit{}
|
||||
}
|
||||
dsl.Computes.Filter[bind] = append(dsl.Computes.Filter[bind], compute.Unit{Name: inst.Name, Kind: compute.Filter})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if dsl.Fields.Chart != nil && dsl.Layout.Chart != nil && dsl.Layout.Chart.Columns != nil {
|
||||
for _, inst := range dsl.Layout.Chart.Columns {
|
||||
if field, has := dsl.Fields.Chart[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})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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("[chart] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
return fmt.Errorf("[chart] %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("[chart] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
return fmt.Errorf("[chart] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error())
|
||||
}
|
||||
values[key] = res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
85
widgets/chart/handler.go
Normal file
85
widgets/chart/handler.go
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
package chart
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/log"
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
)
|
||||
|
||||
// ********************************
|
||||
// * Execute the process of form *
|
||||
// ********************************
|
||||
// Life-Circle: Before Hook → Run Process → Compute View → After Hook
|
||||
// Execute Compute View On: Data
|
||||
func processHandler(p *action.Process, process *gou.Process) (interface{}, error) {
|
||||
|
||||
chart, 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("[chart] %s %s process is required", chart.ID, p.Name)
|
||||
return nil, fmt.Errorf("[chart] %s %s process is required", chart.ID, p.Name)
|
||||
}
|
||||
|
||||
// Compute Filter
|
||||
err = chart.ComputeFilter(p.Name, process, args, chart.getFilter())
|
||||
if err != nil {
|
||||
log.Error("[chart] %s %s Compute Filter Error: %s", chart.ID, p.Name, err.Error())
|
||||
}
|
||||
|
||||
// Before Hook
|
||||
if p.Before != nil {
|
||||
log.Trace("[chart] %s %s before: exec(%v)", chart.ID, p.Name, args)
|
||||
newArgs, err := p.Before.Exec(args, process.Sid, process.Global)
|
||||
if err != nil {
|
||||
log.Error("[chart] %s %s before: %s", chart.ID, p.Name, err.Error())
|
||||
} else {
|
||||
log.Trace("[chart] %s %s before: args:%v", chart.ID, p.Name, args)
|
||||
args = newArgs
|
||||
}
|
||||
}
|
||||
|
||||
// Execute Process
|
||||
act, err := gou.ProcessOf(name, args...)
|
||||
if err != nil {
|
||||
log.Error("[chart] %s %s -> %s %s", chart.ID, p.Name, name, err.Error())
|
||||
return nil, fmt.Errorf("[chart] %s %s -> %s %s", chart.ID, p.Name, name, err.Error())
|
||||
}
|
||||
|
||||
res, err := act.WithGlobal(process.Global).WithSID(process.Sid).Exec()
|
||||
if err != nil {
|
||||
log.Error("[chart] %s %s -> %s %s", chart.ID, p.Name, name, err.Error())
|
||||
return nil, fmt.Errorf("[chart] %s %s -> %s %s", chart.ID, p.Name, name, err.Error())
|
||||
}
|
||||
|
||||
// Compute View
|
||||
err = chart.ComputeView(p.Name, process, res, chart.getField())
|
||||
if err != nil {
|
||||
log.Error("[chart] %s %s Compute View Error: %s", chart.ID, p.Name, err.Error())
|
||||
}
|
||||
|
||||
// After hook
|
||||
if p.After != nil {
|
||||
log.Trace("[chart] %s %s after: exec(%v)", chart.ID, p.Name, res)
|
||||
newRes, err := p.After.Exec(res, process.Sid, process.Global)
|
||||
if err != nil {
|
||||
log.Error("[chart] %s %s after: %s", chart.ID, p.Name, err.Error())
|
||||
} else {
|
||||
log.Trace("[chart] %s %s after: %v", chart.ID, p.Name, newRes)
|
||||
res = newRes
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
|
@ -3,21 +3,21 @@ package chart
|
|||
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 chart 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 chart action DSL
|
||||
|
|
@ -31,14 +31,23 @@ type ActionDSL struct {
|
|||
|
||||
// FieldsDSL the chart fields DSL
|
||||
type FieldsDSL struct {
|
||||
Filter field.Filters `json:"filter,omitempty"`
|
||||
Chart field.Columns `json:"chart,omitempty"`
|
||||
Filter field.Filters `json:"filter,omitempty"`
|
||||
Chart field.Columns `json:"chart,omitempty"`
|
||||
filterMap map[string]field.FilterDSL
|
||||
chartMap map[string]field.ColumnDSL
|
||||
}
|
||||
|
||||
// LayoutDSL the chart layout DSL
|
||||
type LayoutDSL struct {
|
||||
Operation *OperationLayoutDSL `json:"operation,omitempty"`
|
||||
Chart *ViewLayoutDSL `json:"chart,omitempty"`
|
||||
Filter *FilterLayoutDSL `json:"filter,omitempty"`
|
||||
}
|
||||
|
||||
// FilterLayoutDSL layout.filter
|
||||
type FilterLayoutDSL struct {
|
||||
Actions component.Actions `json:"actions,omitempty"`
|
||||
Columns component.Instances `json:"columns,omitempty"`
|
||||
}
|
||||
|
||||
// OperationLayoutDSL layout.operation
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/yaoapp/yao/widgets/field"
|
||||
)
|
||||
|
||||
var views = map[string]bool{"find": true, "get": true, "search": true}
|
||||
var views = map[string]bool{"find": true, "get": true, "search": true, "data": true}
|
||||
|
||||
// ComputeEdit edit compute edit
|
||||
func (c *Computable) ComputeEdit(name string, process *gou.Process, args []interface{}, getField func(string) (*field.ColumnDSL, string, error)) error {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue