From 688c2950ebaee907f935132dcc69bc54f14abfb0 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 28 Sep 2022 17:23:51 +0800 Subject: [PATCH] [add] widget chart --- Makefile | 4 +- lang/lang.go | 2 +- widgets/chart/action.go | 122 +++++++++++++++++++++ widgets/chart/api.go | 66 ++++++++++++ widgets/chart/chart.go | 197 ++++++++++++++++++++++++++++++++++ widgets/chart/chart_test.go | 53 +++++++++ widgets/chart/compute.go | 44 ++++++++ widgets/chart/export.go | 7 ++ widgets/chart/fields.go | 19 ++++ widgets/chart/lang.go | 7 ++ widgets/chart/layout.go | 19 ++++ widgets/chart/process.go | 67 ++++++++++++ widgets/chart/process_test.go | 91 ++++++++++++++++ widgets/chart/types.go | 51 +++++++++ widgets/chart/vaildate.go | 6 ++ widgets/field/types.go | 1 + widgets/form/api.go | 4 +- widgets/form/compute.go | 16 +-- widgets/table/api.go | 4 +- widgets/widgets.go | 7 ++ 20 files changed, 772 insertions(+), 15 deletions(-) create mode 100644 widgets/chart/action.go create mode 100644 widgets/chart/api.go create mode 100644 widgets/chart/chart.go create mode 100644 widgets/chart/chart_test.go create mode 100644 widgets/chart/compute.go create mode 100644 widgets/chart/export.go create mode 100644 widgets/chart/fields.go create mode 100644 widgets/chart/lang.go create mode 100644 widgets/chart/layout.go create mode 100644 widgets/chart/process.go create mode 100644 widgets/chart/process_test.go create mode 100644 widgets/chart/types.go create mode 100644 widgets/chart/vaildate.go diff --git a/Makefile b/Makefile index a9da61fc..383b67d9 100644 --- a/Makefile +++ b/Makefile @@ -207,7 +207,7 @@ artifacts-macos: clean mkdir -p .tmp/data/xgen cp -r ./ui .tmp/data/ui cp -r ../xgen-v0.9/dist .tmp/data/xgen/v0.9 - cp -r ../xgen-v1.0/packages/app/dist .tmp/data/xgen/v1.0 + cp -r ../xgen-v1.0/packages/xgen/dist .tmp/data/xgen/v1.0 cp -r yao .tmp/data/ go-bindata -fs -pkg data -o data/bindata.go -prefix ".tmp/data/" .tmp/data/... rm -rf .tmp/data @@ -318,7 +318,7 @@ linux-release: clean mkdir -p .tmp/data/xgen cp -r ./ui .tmp/data/ui cp -r .tmp/xgen/v0.9/dist .tmp/data/xgen/v0.9 - cp -r .tmp/xgen/v1.0/packages/app/dist .tmp/data/xgen/v1.0 + cp -r .tmp/xgen/v1.0/packages/xgen/dist .tmp/data/xgen/v1.0 cp -r yao .tmp/data/ go-bindata -fs -pkg data -o data/bindata.go -prefix ".tmp/data/" .tmp/data/... rm -rf .tmp/data diff --git a/lang/lang.go b/lang/lang.go index 4db2377b..84826cd6 100644 --- a/lang/lang.go +++ b/lang/lang.go @@ -10,13 +10,13 @@ import ( ) func init() { + lang.RegisterWidget("logins", "login") lang.RegisterWidget("tables", "table") lang.RegisterWidget("forms", "form") lang.RegisterWidget("charts", "chart") lang.RegisterWidget("kanban", "page") lang.RegisterWidget("screen", "page") lang.RegisterWidget("pages", "page") - lang.RegisterWidget("logins", "login") } // Load language packs diff --git a/widgets/chart/action.go b/widgets/chart/action.go new file mode 100644 index 00000000..e29f79f0 --- /dev/null +++ b/widgets/chart/action.go @@ -0,0 +1,122 @@ +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" +) + +var processActionDefaults = map[string]*action.Process{ + + "Setting": { + Name: "yao.chart.Setting", + Process: "yao.chart.Xgen", + Default: []interface{}{nil}, + }, + "Component": { + Name: "yao.chart.Component", + Default: []interface{}{nil, nil, nil}, + }, + "Data": { + Name: "yao.chart.Data", + Default: []interface{}{nil}, + }, +} + +// SetDefaultProcess set the default value of action +func (act *ActionDSL) SetDefaultProcess() { + + act.Setting = action.NewProcess("Setting", act.Setting). + SetDefault(processActionDefaults). + SetHandler(processHandler) + + act.Component = action.NewProcess("Component", act.Component). + SetDefault(processActionDefaults). + SetHandler(processHandler) + + act.Data = action.NewProcess("Data", act.Data). + WithBefore(act.BeforeData). + WithAfter(act.AfterData). + SetDefault(processActionDefaults). + 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 +} diff --git a/widgets/chart/api.go b/widgets/chart/api.go new file mode 100644 index 00000000..73736dca --- /dev/null +++ b/widgets/chart/api.go @@ -0,0 +1,66 @@ +package chart + +import ( + jsoniter "github.com/json-iterator/go" + "github.com/yaoapp/gou" + "github.com/yaoapp/yao/share" +) + +// export API +func exportAPI() error { + + http := gou.HTTP{ + Name: "Widget Form API", + Description: "Widget Form API", + Version: share.VERSION, + Guard: "-", + Group: "__yao/chart", + Paths: []gou.Path{}, + } + + // GET /api/__yao/chart/:id/setting -> Default process: yao.chart.Xgen + path := gou.Path{ + Label: "Setting", + Description: "Setting", + Path: "/:id/setting", + Method: "GET", + Process: "yao.chart.Setting", + In: []string{"$param.id"}, + Out: gou.Out{Status: 200, Type: "application/json"}, + } + http.Paths = append(http.Paths, path) + + // GET /api/__yao/chart/:id/data -> Default process: yao.chart.Data $param.id :query + path = gou.Path{ + Label: "Data", + Description: "Data", + Path: "/:id/data", + Method: "GET", + Process: "yao.chart.Data", + In: []string{"$param.id", ":query"}, + Out: gou.Out{Status: 200, Type: "application/json"}, + } + http.Paths = append(http.Paths, path) + + // GET /api/__yao/chart/:id/component/:xpath/:method -> Default process: yao.chart.Component $param.id $param.xpath $param.method :query + path = gou.Path{ + Label: "Component", + Description: "Component", + Path: "/:id/component/:xpath/:method", + Method: "GET", + Process: "yao.chart.Component", + In: []string{"$param.id", "$param.xpath", "$param.method", ":query"}, + Out: gou.Out{Status: 200, Type: "application/json"}, + } + http.Paths = append(http.Paths, path) + + // api source + source, err := jsoniter.Marshal(http) + if err != nil { + return err + } + + // load apis + _, err = gou.LoadAPIReturn(string(source), "widgets.chart") + return err +} diff --git a/widgets/chart/chart.go b/widgets/chart/chart.go new file mode 100644 index 00000000..d5fb9581 --- /dev/null +++ b/widgets/chart/chart.go @@ -0,0 +1,197 @@ +package chart + +import ( + "fmt" + "path/filepath" + "strings" + + jsoniter "github.com/json-iterator/go" + "github.com/yaoapp/gou" + "github.com/yaoapp/gou/lang" + "github.com/yaoapp/kun/exception" + "github.com/yaoapp/yao/config" + "github.com/yaoapp/yao/share" + "github.com/yaoapp/yao/widgets/component" + "github.com/yaoapp/yao/widgets/field" +) + +// +// API: +// GET /api/__yao/chart/:id/setting -> Default process: yao.chart.Xgen +// GET /api/__yao/chart/:id/data -> Default process: yao.chart.Data $param.id :query +// GET /api/__yao/chart/:id/component/:xpath/:method -> Default process: yao.chart.Component $param.id $param.xpath $param.method :query +// +// Process: +// yao.form.Setting Return the App DSL +// yao.form.Xgen Return the Xgen setting +// yao.form.Data Return the query data +// yao.form.Component Return the result defined in props.xProps +// +// Hook: +// before:data +// after:data +// + +// Charts the loaded chart widgets +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{}, + } +} + +// LoadAndExport load table +func LoadAndExport(cfg config.Config) error { + err := Load(cfg) + if err != nil { + return err + } + return Export() +} + +// Load load task +func Load(cfg config.Config) error { + var root = filepath.Join(cfg.Root, "charts") + return LoadFrom(root, "") +} + +// LoadFrom load from dir +func LoadFrom(dir string, prefix string) error { + + if share.DirNotExists(dir) { + return fmt.Errorf("%s does not exists", dir) + } + + messages := []string{} + err := share.Walk(dir, ".json", func(root, filename string) { + id := prefix + share.ID(root, filename) + data := share.ReadFile(filename) + dsl := New(id) + err := jsoniter.Unmarshal(data, dsl) + if err != nil { + messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error())) + return + } + + if dsl.Action == nil { + dsl.Action = &ActionDSL{} + } + dsl.Action.SetDefaultProcess() + + if dsl.Layout == nil { + dsl.Layout = &LayoutDSL{} + } + + // Parse + err = dsl.Parse() + if err != nil { + messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error())) + return + } + + // Validate + err = dsl.Validate() + if err != nil { + messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error())) + return + } + + // Apply a language pack + if lang.Default != nil { + lang.Default.Apply(dsl) + } + + Charts[id] = dsl + }) + + if len(messages) > 0 { + return fmt.Errorf(strings.Join(messages, ";")) + } + + return err +} + +// Get form via process or id +func Get(form interface{}) (*DSL, error) { + id := "" + switch form.(type) { + case string: + id = form.(string) + case *gou.Process: + id = form.(*gou.Process).ArgsString(0) + default: + return nil, fmt.Errorf("%v type does not support", form) + } + + t, has := Charts[id] + if !has { + return nil, fmt.Errorf("%s does not exist", id) + } + return t, nil +} + +// MustGet Get form via process or id thow error +func MustGet(form interface{}) *DSL { + t, err := Get(form) + if err != nil { + exception.New(err.Error(), 400).Throw() + } + return t +} + +// Parse Layout +func (dsl *DSL) Parse() error { + + // ComputeFields + dsl.Fields.Chart.ComputeFieldsMerge(dsl.ComputesIn, dsl.ComputesOut) + + // Filters + err := dsl.Fields.Filter.CPropsMerge(dsl.CProps, func(name string, filter field.FilterDSL) (xpath string) { + return fmt.Sprintf("fields.filter.%s.edit.props", name) + }) + + if err != nil { + return err + } + + // Columns + return dsl.Fields.Chart.CPropsMerge(dsl.CProps, func(name string, kind string, column field.ColumnDSL) (xpath string) { + return fmt.Sprintf("fields.chart.%s.%s.props", name, kind) + }) +} + +// Xgen trans to xgen setting +func (dsl *DSL) Xgen() (map[string]interface{}, error) { + + setting, err := dsl.Layout.Xgen() + if err != nil { + return nil, err + } + + fields, err := dsl.Fields.Xgen() + if err != nil { + return nil, err + } + + setting["fields"] = fields + for _, cProp := range dsl.CProps { + err := cProp.Replace(setting, func(cProp component.CloudPropsDSL) interface{} { + return map[string]interface{}{ + "api": fmt.Sprintf("/api/__yao/chart/%s/component/%s/%s", dsl.ID, cProp.Xpath, cProp.Name), + "params": cProp.Query, + } + }) + + if err != nil { + return nil, err + } + } + + return setting, nil +} diff --git a/widgets/chart/chart_test.go b/widgets/chart/chart_test.go new file mode 100644 index 00000000..9f1887dc --- /dev/null +++ b/widgets/chart/chart_test.go @@ -0,0 +1,53 @@ +package chart + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/yaoapp/yao/config" + "github.com/yaoapp/yao/lang" + "github.com/yaoapp/yao/model" + "github.com/yaoapp/yao/script" + "github.com/yaoapp/yao/share" +) + +func TestLoad(t *testing.T) { + prepare(t) + err := Load(config.Conf) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, 1, len(Charts)) +} + +func prepare(t *testing.T, language ...string) { + + // langs + if len(language) < 1 { + os.Unsetenv("YAO_LANG") + } else { + os.Setenv("YAO_LANG", language[0]) + } + lang.Load(config.Conf) + + share.DBConnect(config.Conf.DB) // removed later + + // load scripts + err := script.Load(config.Conf) + if err != nil { + t.Fatal(err) + } + + // load models + err = model.Load(config.Conf) + if err != nil { + t.Fatal(err) + } + + // export + err = Export() + if err != nil { + t.Fatal(err) + } +} diff --git a/widgets/chart/compute.go b/widgets/chart/compute.go new file mode 100644 index 00000000..ead1dbca --- /dev/null +++ b/widgets/chart/compute.go @@ -0,0 +1,44 @@ +package chart + +import ( + "fmt" + "strings" + + "github.com/yaoapp/gou" + "github.com/yaoapp/kun/log" +) + +func (dsl *DSL) computeData(process *gou.Process, values map[string]interface{}) error { + + messages := []string{} + for key := range values { + err := dsl.computeOut(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) 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 +} diff --git a/widgets/chart/export.go b/widgets/chart/export.go new file mode 100644 index 00000000..da00e886 --- /dev/null +++ b/widgets/chart/export.go @@ -0,0 +1,7 @@ +package chart + +// Export process & api +func Export() error { + exportProcess() + return exportAPI() +} diff --git a/widgets/chart/fields.go b/widgets/chart/fields.go new file mode 100644 index 00000000..a5952978 --- /dev/null +++ b/widgets/chart/fields.go @@ -0,0 +1,19 @@ +package chart + +import jsoniter "github.com/json-iterator/go" + +// Xgen trans to xgen setting +func (fields *FieldsDSL) Xgen() (map[string]interface{}, error) { + res := map[string]interface{}{} + data, err := jsoniter.Marshal(fields) + if err != nil { + return nil, err + } + + err = jsoniter.Unmarshal(data, &res) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/widgets/chart/lang.go b/widgets/chart/lang.go new file mode 100644 index 00000000..1aa0aa35 --- /dev/null +++ b/widgets/chart/lang.go @@ -0,0 +1,7 @@ +package chart + +// Lang for applying a language pack +func (dsl *DSL) Lang(trans func(widget string, inst string, value *string) bool) { + widget := "form" + trans(widget, dsl.ID, &dsl.Name) +} diff --git a/widgets/chart/layout.go b/widgets/chart/layout.go new file mode 100644 index 00000000..b4197b49 --- /dev/null +++ b/widgets/chart/layout.go @@ -0,0 +1,19 @@ +package chart + +import jsoniter "github.com/json-iterator/go" + +// Xgen trans to Xgen setting +func (layout *LayoutDSL) Xgen() (map[string]interface{}, error) { + res := map[string]interface{}{} + data, err := jsoniter.Marshal(layout) + if err != nil { + return nil, err + } + + err = jsoniter.Unmarshal(data, &res) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/widgets/chart/process.go b/widgets/chart/process.go new file mode 100644 index 00000000..0f0aa82e --- /dev/null +++ b/widgets/chart/process.go @@ -0,0 +1,67 @@ +package chart + +import ( + "fmt" + + "github.com/yaoapp/gou" + "github.com/yaoapp/kun/exception" +) + +// Export process +func exportProcess() { + gou.RegisterProcessHandler("yao.chart.setting", processSetting) + gou.RegisterProcessHandler("yao.chart.xgen", processXgen) + gou.RegisterProcessHandler("yao.chart.component", processComponent) + gou.RegisterProcessHandler("yao.chart.data", processData) +} + +func processXgen(process *gou.Process) interface{} { + + form := MustGet(process) + setting, err := form.Xgen() + if err != nil { + exception.New(err.Error(), 500).Throw() + } + + return setting +} + +func processComponent(process *gou.Process) interface{} { + + process.ValidateArgNums(3) + form := MustGet(process) + xpath := process.ArgsString(1) + method := process.ArgsString(2) + key := fmt.Sprintf("%s.$%s", xpath, method) + + // get cloud props + cProp, has := form.CProps[key] + if !has { + exception.New("%s does not exist", 400, key).Throw() + } + + // :query + query := map[string]interface{}{} + if process.NumOfArgsIs(4) { + query = process.ArgsMap(3) + } + + // execute query + res, err := cProp.ExecQuery(process, query) + if err != nil { + exception.New(err.Error(), 500).Throw() + } + + return res +} + +func processSetting(process *gou.Process) interface{} { + form := MustGet(process) + process.Args = append(process.Args, process.Args[0]) // chart name + return form.Action.Setting.MustExec(process) +} + +func processData(process *gou.Process) interface{} { + form := MustGet(process) + return form.Action.Data.MustExec(process) +} diff --git a/widgets/chart/process_test.go b/widgets/chart/process_test.go new file mode 100644 index 00000000..63f40570 --- /dev/null +++ b/widgets/chart/process_test.go @@ -0,0 +1,91 @@ +package chart + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/yaoapp/gou" + "github.com/yaoapp/kun/any" + "github.com/yaoapp/kun/maps" + "github.com/yaoapp/yao/config" + q "github.com/yaoapp/yao/query" +) + +func TestProcessData(t *testing.T) { + load(t) + args := []interface{}{"dashboard", map[string]interface{}{"range": "2022-01-02", "status": "checked"}} + res, err := gou.NewProcess("yao.chart.Data", args...).Exec() + if err != nil { + t.Fatal(err) + } + data := any.Of(res).MapStr() + assert.Equal(t, 14, len(data)) +} + +func TestProcessComponent(t *testing.T) { + load(t) + args := []interface{}{ + "dashboard", + "fields.filter.状态.edit.props.xProps", + "remote", + map[string]interface{}{"select": []string{"name", "status"}, "limit": 2}, + } + + res, err := gou.NewProcess("yao.chart.Component", args...).Exec() + if err != nil { + t.Fatal(err) + } + + pets, ok := res.([]maps.MapStr) + assert.True(t, ok) + assert.Equal(t, 2, len(pets)) + assert.Equal(t, "Cookie", pets[0]["name"]) + assert.Equal(t, "checked", pets[0]["status"]) + assert.Equal(t, "Baby", pets[1]["name"]) + assert.Equal(t, "checked", pets[1]["status"]) +} + +func TestProcessComponentError(t *testing.T) { + load(t) + args := []interface{}{ + "dashboard", + "fields.filter.edit.props.状态.::not-exist", + "remote", + map[string]interface{}{"select": []string{"name", "status"}, "limit": 2}, + } + _, err := gou.NewProcess("yao.chart.Component", args...).Exec() + assert.Contains(t, err.Error(), "fields.filter.edit.props.状态.::not-exist") +} + +func TestProcessSetting(t *testing.T) { + load(t) + args := []interface{}{"dashboard"} + res, err := gou.NewProcess("yao.chart.Setting", args...).Exec() + if err != nil { + t.Fatal(err) + } + + data := any.Of(res).MapStr().Dot() + assert.Equal(t, "/api/__yao/chart/dashboard/component/fields.filter.状态.edit.props.xProps/remote", data.Get("fields.filter.状态.edit.props.xProps.remote.api")) +} + +func TestProcessXgen(t *testing.T) { + load(t) + args := []interface{}{"dashboard"} + res, err := gou.NewProcess("yao.chart.Xgen", args...).Exec() + if err != nil { + t.Fatal(err) + } + + data := any.Of(res).MapStr().Dot() + assert.Equal(t, "/api/__yao/chart/dashboard/component/fields.filter.状态.edit.props.xProps/remote", data.Get("fields.filter.状态.edit.props.xProps.remote.api")) +} + +func load(t *testing.T) { + prepare(t) + err := Load(config.Conf) + if err != nil { + t.Fatal(err) + } + q.Load(config.Conf) +} diff --git a/widgets/chart/types.go b/widgets/chart/types.go new file mode 100644 index 00000000..0fee340b --- /dev/null +++ b/widgets/chart/types.go @@ -0,0 +1,51 @@ +package chart + +import ( + "github.com/yaoapp/yao/widgets/action" + "github.com/yaoapp/yao/widgets/component" + "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"` + ComputesIn field.ComputeFields `json:"-"` + ComputesOut field.ComputeFields `json:"-"` + CProps field.CloudProps `json:"-"` +} + +// ActionDSL the chart action DSL +type ActionDSL struct { + Setting *action.Process `json:"setting,omitempty"` + Component *action.Process `json:"-"` + Data *action.Process `json:"data,omitempty"` + BeforeData *hook.Before `json:"before:data,omitempty"` + AfterData *hook.After `json:"after:data,omitempty"` +} + +// FieldsDSL the chart fields DSL +type FieldsDSL struct { + Filter field.Filters `json:"filter,omitempty"` + Chart field.Columns `json:"chart,omitempty"` +} + +// LayoutDSL the chart layout DSL +type LayoutDSL struct { + Operation *OperationLayoutDSL `json:"operation,omitempty"` + Chart *ViewLayoutDSL `json:"chart,omitempty"` +} + +// OperationLayoutDSL layout.operation +type OperationLayoutDSL struct { + Actions []component.ActionDSL `json:"actions,omitempty"` +} + +// ViewLayoutDSL layout.form +type ViewLayoutDSL struct { + Columns component.Instances `json:"columns,omitempty"` +} diff --git a/widgets/chart/vaildate.go b/widgets/chart/vaildate.go new file mode 100644 index 00000000..73913d65 --- /dev/null +++ b/widgets/chart/vaildate.go @@ -0,0 +1,6 @@ +package chart + +// Validate table +func (dsl *DSL) Validate() error { + return nil +} diff --git a/widgets/field/types.go b/widgets/field/types.go index 25014920..95016708 100644 --- a/widgets/field/types.go +++ b/widgets/field/types.go @@ -17,6 +17,7 @@ type CloudProps map[string]component.CloudPropsDSL // ColumnDSL the field column dsl type ColumnDSL struct { Bind string `json:"bind,omitempty"` + Link string `json:"link,omitempty"` In string `json:"in,omitempty"` Out string `json:"out,omitempty"` View *component.DSL `json:"view,omitempty"` diff --git a/widgets/form/api.go b/widgets/form/api.go index db6e8a99..40a9c537 100644 --- a/widgets/form/api.go +++ b/widgets/form/api.go @@ -44,8 +44,8 @@ func exportAPI() error { // GET /api/__yao/form/:id/component/:xpath/:method -> Default process: yao.form.Component $param.id $param.xpath $param.method :query path = gou.Path{ - Label: "Find", - Description: "Find", + Label: "Component", + Description: "Component", Path: "/:id/component/:xpath/:method", Method: "GET", Process: "yao.form.Component", diff --git a/widgets/form/compute.go b/widgets/form/compute.go index 0ce4152c..dc3d80e2 100644 --- a/widgets/form/compute.go +++ b/widgets/form/compute.go @@ -46,14 +46,14 @@ func (dsl *DSL) computeIn(process *gou.Process, key string, values map[string]in if name, has := dsl.ComputesIn[key]; has { compute, err := gou.ProcessOf(name, key, values[key], values) if err != nil { - log.Error("[table] %s compute-in -> %s %s %s", dsl.ID, name, key, err.Error()) - return fmt.Errorf("[table] %s compute-in -> %s %s %s", dsl.ID, name, key, err.Error()) + 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("[table] %s compute-in -> %s %s %s", dsl.ID, name, key, err.Error()) - return fmt.Errorf("[table] %s compute-in -> %s %s %s", dsl.ID, name, key, err.Error()) + 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 } @@ -64,14 +64,14 @@ func (dsl *DSL) computeOut(process *gou.Process, key string, values map[string]i if name, has := dsl.ComputesOut[key]; has { compute, err := gou.ProcessOf(name, key, values[key], values) if err != nil { - log.Error("[table] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error()) - return fmt.Errorf("[table] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error()) + 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("[table] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error()) - return fmt.Errorf("[table] %s compute-out -> %s %s %s", dsl.ID, name, key, err.Error()) + 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 } diff --git a/widgets/table/api.go b/widgets/table/api.go index e2b2ac2b..e51739d2 100644 --- a/widgets/table/api.go +++ b/widgets/table/api.go @@ -68,8 +68,8 @@ func exportAPI() error { // GET /api/__yao/table/:id/component/:xpath/:method -> Default process: yao.table.Component $param.id $param.xpath $param.method :query path = gou.Path{ - Label: "Find", - Description: "Find", + Label: "Component", + Description: "Component", Path: "/:id/component/:xpath/:method", Method: "GET", Process: "yao.table.Component", diff --git a/widgets/widgets.go b/widgets/widgets.go index e780c612..e528cc49 100644 --- a/widgets/widgets.go +++ b/widgets/widgets.go @@ -3,6 +3,7 @@ package widgets import ( "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/widgets/app" + "github.com/yaoapp/yao/widgets/chart" "github.com/yaoapp/yao/widgets/form" "github.com/yaoapp/yao/widgets/login" "github.com/yaoapp/yao/widgets/table" @@ -35,5 +36,11 @@ func Load(cfg config.Config) error { return err } + // chart widget + err = chart.LoadAndExport(cfg) + if err != nil { + return err + } + return nil }