From 09770599979da496046168c1d69ff7ef9c091e76 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 24 Oct 2022 20:11:57 +0800 Subject: [PATCH] [add] form widget bind.form & bind.table --- widgets/field/field.go | 2 +- widgets/form/action.go | 52 ++++++++++++++++++ widgets/form/bind.go | 77 +++++++++++++++++++++++++- widgets/form/fields.go | 53 +++++++++++++++++- widgets/form/form.go | 107 +++++++++++++++++++++++------------- widgets/form/form_test.go | 21 ++++++- widgets/form/layout.go | 85 ++++++++++++++++++++++++++++ widgets/form/types.go | 1 + widgets/table/fields.go | 5 ++ widgets/table/table.go | 17 +++--- widgets/table/table_test.go | 2 +- 11 files changed, 370 insertions(+), 52 deletions(-) diff --git a/widgets/field/field.go b/widgets/field/field.go index 20868de0..7400ca76 100644 --- a/widgets/field/field.go +++ b/widgets/field/field.go @@ -42,7 +42,7 @@ func LoadAndExport(cfg config.Config) error { func SelectTransform(name string) (*Transform, error) { trans, has := Transforms[name] if !has { - return nil, fmt.Errorf("%s does not found", name) + return nil, fmt.Errorf("SelectTransform %s does not found", name) } return trans, nil } diff --git a/widgets/form/action.go b/widgets/form/action.go index 61768fe6..6c7449f6 100644 --- a/widgets/form/action.go +++ b/widgets/form/action.go @@ -5,6 +5,8 @@ import ( "github.com/yaoapp/gou" "github.com/yaoapp/yao/widgets/action" + "github.com/yaoapp/yao/widgets/hook" + "github.com/yaoapp/yao/widgets/table" ) var processActionDefaults = map[string]*action.Process{ @@ -100,3 +102,53 @@ func (act *ActionDSL) BindModel(m *gou.Model) { act.Find.Default[1] = act.Bind.Option } } + +// BindForm bind form +func (act *ActionDSL) BindForm(form *DSL) error { + + // Copy Hooks + hook.CopyBefore(act.BeforeFind, form.Action.BeforeFind) + hook.CopyBefore(act.BeforeSave, form.Action.BeforeSave) + hook.CopyBefore(act.BeforeCreate, form.Action.BeforeCreate) + hook.CopyBefore(act.BeforeUpdate, form.Action.BeforeUpdate) + hook.CopyBefore(act.BeforeDelete, form.Action.BeforeDelete) + hook.CopyAfter(act.AfterFind, form.Action.AfterFind) + hook.CopyAfter(act.AfterSave, form.Action.AfterSave) + hook.CopyAfter(act.AfterCreate, form.Action.AfterCreate) + hook.CopyAfter(act.AfterUpdate, form.Action.AfterUpdate) + hook.CopyAfter(act.AfterDelete, form.Action.AfterDelete) + + // Merge Actions + act.Find.Merge(form.Action.Find) + act.Save.Merge(form.Action.Save) + act.Create.Merge(form.Action.Create) + act.Update.Merge(form.Action.Update) + act.Delete.Merge(form.Action.Delete) + + return nil +} + +// BindTable bind table +func (act *ActionDSL) BindTable(tab *table.DSL) error { + + // Copy Hooks + hook.CopyBefore(act.BeforeFind, tab.Action.BeforeFind) + hook.CopyBefore(act.BeforeSave, tab.Action.BeforeSave) + hook.CopyBefore(act.BeforeCreate, tab.Action.BeforeCreate) + hook.CopyBefore(act.BeforeUpdate, tab.Action.BeforeUpdate) + hook.CopyBefore(act.BeforeDelete, tab.Action.BeforeDelete) + hook.CopyAfter(act.AfterFind, tab.Action.AfterFind) + hook.CopyAfter(act.AfterSave, tab.Action.AfterSave) + hook.CopyAfter(act.AfterCreate, tab.Action.AfterCreate) + hook.CopyAfter(act.AfterUpdate, tab.Action.AfterUpdate) + hook.CopyAfter(act.AfterDelete, tab.Action.AfterDelete) + + // Merge Actions + act.Find.Merge(tab.Action.Find) + act.Save.Merge(tab.Action.Save) + act.Create.Merge(tab.Action.Create) + act.Update.Merge(tab.Action.Update) + act.Delete.Merge(tab.Action.Delete) + + return nil +} diff --git a/widgets/form/bind.go b/widgets/form/bind.go index befb4f29..58aec8dc 100644 --- a/widgets/form/bind.go +++ b/widgets/form/bind.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/yaoapp/gou" + "github.com/yaoapp/yao/widgets/table" ) // Bind model / store / table / ... @@ -17,6 +18,10 @@ func (dsl *DSL) Bind() error { return dsl.bindModel() } + if dsl.Action.Bind.Form != "" { + return dsl.bindForm() + } + if dsl.Action.Bind.Store != "" { return dsl.bindStore() } @@ -42,9 +47,79 @@ func (dsl *DSL) bindModel() error { return nil } +func (dsl *DSL) bindForm() error { + id := dsl.Action.Bind.Form + if id == dsl.ID { + return fmt.Errorf("bind.form %s can't bind self form", id) + } + + // Load form + if _, has := Forms[id]; !has { + if err := LoadID(id, dsl.Root); err != nil { + return err + } + } + + form, err := Get(id) + if err != nil { + return err + } + + // Bind Fields + err = dsl.Fields.BindForm(form) + if err != nil { + return err + } + + // Bind Actions + err = dsl.Action.BindForm(form) + if err != nil { + return err + } + + // Bind Layout + err = dsl.Layout.BindForm(form, dsl.Fields) + if err != nil { + return err + } + + return nil +} + func (dsl *DSL) bindTable() error { id := dsl.Action.Bind.Table - return fmt.Errorf("bind.table %s does not support yet", id) + + // Load table + if _, has := table.Tables[id]; !has { + if err := table.LoadID(id, dsl.Root); err != nil { + return err + } + } + + tab, err := table.Get(id) + if err != nil { + return err + } + + // Bind Fields + err = dsl.Fields.BindTable(tab) + if err != nil { + return err + } + + // Bind Actions + err = dsl.Action.BindTable(tab) + if err != nil { + return err + } + + // Bind Layout + err = dsl.Layout.BindTable(tab, dsl.ID, dsl.Fields) + if err != nil { + return err + } + + return nil } func (dsl *DSL) bindStore() error { diff --git a/widgets/form/fields.go b/widgets/form/fields.go index ed2fcaee..25307baf 100644 --- a/widgets/form/fields.go +++ b/widgets/form/fields.go @@ -6,6 +6,7 @@ import ( "github.com/yaoapp/gou" "github.com/yaoapp/yao/widgets/field" + "github.com/yaoapp/yao/widgets/table" ) // BindModel bind model @@ -26,7 +27,7 @@ func (fields *FieldsDSL) BindModel(m *gou.Model) error { } // append columns - if _, has := fields.formMap[formField.Key]; !has { + if _, has := fields.Form[formField.Key]; !has { fields.Form[formField.Key] = *formField fields.formMap[col.Name] = fields.Form[formField.Key] } @@ -35,6 +36,56 @@ func (fields *FieldsDSL) BindModel(m *gou.Model) error { return nil } +// BindForm bind form +func (fields *FieldsDSL) BindForm(form *DSL) error { + // Bind Form + if fields.Form == nil || len(fields.Form) == 0 { + fields.Form = form.Fields.Form + } else if form.Fields.Form != nil { + for key, form := range form.Fields.Form { + if _, has := fields.Form[key]; !has { + fields.Form[key] = form + } + } + } + return nil +} + +// BindTable bind table +func (fields *FieldsDSL) BindTable(tab *table.DSL) error { + + // Bind tab + if fields.Form == nil || len(fields.Form) == 0 { + fields.Form = field.Columns{} + fields.formMap = map[string]field.ColumnDSL{} + } + + if tab.Fields.Table != nil { + for key, form := range tab.Fields.Table { + if form.Edit == nil { + continue + } + + if _, has := fields.Form[key]; !has { + edit := *form.Edit + fields.Form[key] = field.ColumnDSL{Key: key, Bind: form.Bind, Edit: &edit} + } + } + + mapping := tab.Fields.TableMap() + for name, form := range mapping { + if _, has := fields.formMap[name]; !has { + if form.Edit == nil { + continue + } + fields.formMap[name] = fields.Form[name] + } + } + + } + return nil +} + // Xgen trans to xgen setting func (fields *FieldsDSL) Xgen(layout *LayoutDSL) (map[string]interface{}, error) { res := map[string]interface{}{} diff --git a/widgets/form/form.go b/widgets/form/form.go index e8fc0939..e8c61978 100644 --- a/widgets/form/form.go +++ b/widgets/form/form.go @@ -8,9 +8,11 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou" "github.com/yaoapp/kun/exception" + "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/share" "github.com/yaoapp/yao/widgets/component" + "github.com/yaoapp/yao/widgets/environment" "github.com/yaoapp/yao/widgets/field" ) @@ -65,7 +67,7 @@ func New(id string) *DSL { func LoadAndExport(cfg config.Config) error { err := Load(cfg) if err != nil { - return err + log.Error(err.Error()) } return Export() } @@ -86,58 +88,85 @@ func LoadFrom(dir string, prefix string) error { 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) + data, err := environment.ReadFile(filename) if err != nil { - messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error())) + messages = append(messages, err.Error()) return } - if dsl.Action == nil { - dsl.Action = &ActionDSL{} - } - dsl.Action.SetDefaultProcess() - - if dsl.Layout == nil { - dsl.Layout = &LayoutDSL{} - } - - if dsl.Fields == nil { - dsl.Fields = &FieldsDSL{} - } - - // Bind model / store / table / ... - err = dsl.Bind() + err = LoadData(data, id, filepath.Dir(dir)) if err != nil { - messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error())) - return + messages = append(messages, err.Error()) } - - // 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 - } - - Forms[id] = dsl }) if len(messages) > 0 { - return fmt.Errorf(strings.Join(messages, ";")) + return fmt.Errorf(strings.Join(messages, ";\n")) } return err } +// LoadID load via id +func LoadID(id string, root string) error { + dirs := strings.Split(id, ".") + name := fmt.Sprintf("%s.form.json", dirs[len(dirs)-1]) + elems := []string{root} + elems = append(elems, dirs[0:len(dirs)-1]...) + elems = append(elems, "forms", name) + filename := filepath.Join(elems...) + data, err := environment.ReadFile(filename) + if err != nil { + return fmt.Errorf("[Form] LoadID %s root=%s %s", id, root, err.Error()) + } + return LoadData(data, id, root) +} + +// LoadData load via data +func LoadData(data []byte, id string, root string) error { + dsl := New(id) + dsl.Root = root + + err := jsoniter.Unmarshal(data, dsl) + if err != nil { + return fmt.Errorf("[Form] LoadData %s %s", id, err.Error()) + } + + if dsl.Action == nil { + dsl.Action = &ActionDSL{} + } + dsl.Action.SetDefaultProcess() + + if dsl.Layout == nil { + dsl.Layout = &LayoutDSL{} + } + + if dsl.Fields == nil { + dsl.Fields = &FieldsDSL{} + } + + // Bind model / store / table / ... + err = dsl.Bind() + if err != nil { + return fmt.Errorf("[Form] LoadData Bind %s %s", id, err.Error()) + } + + // Parse + err = dsl.Parse() + if err != nil { + return fmt.Errorf("[Form] LoadData Parse %s %s", id, err.Error()) + } + + // Validate + err = dsl.Validate() + if err != nil { + return fmt.Errorf("[Form] LoadData Validate %s %s", id, err.Error()) + } + + Forms[id] = dsl + return nil +} + // Get form via process or id func Get(form interface{}) (*DSL, error) { id := "" diff --git a/widgets/form/form_test.go b/widgets/form/form_test.go index 9bc46d0b..28482365 100644 --- a/widgets/form/form_test.go +++ b/widgets/form/form_test.go @@ -9,6 +9,9 @@ import ( "github.com/yaoapp/yao/model" "github.com/yaoapp/yao/script" "github.com/yaoapp/yao/share" + "github.com/yaoapp/yao/table" + "github.com/yaoapp/yao/widgets/expression" + "github.com/yaoapp/yao/widgets/field" ) func TestLoad(t *testing.T) { @@ -38,7 +41,23 @@ func prepare(t *testing.T, language ...string) { t.Fatal(err) } - // load scripts + // load field transform + err = field.LoadAndExport(config.Conf) + if err != nil { + t.Fatal(err) + } + + // load expression + err = expression.Export() + if err != nil { + t.Fatal(err) + } + + // load tables + err = table.Load(config.Conf) + if err != nil { + t.Fatal(err) + } // export err = Export() diff --git a/widgets/form/layout.go b/widgets/form/layout.go index 798478ae..da0528df 100644 --- a/widgets/form/layout.go +++ b/widgets/form/layout.go @@ -6,6 +6,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou" "github.com/yaoapp/yao/widgets/component" + "github.com/yaoapp/yao/widgets/table" ) // BindModel bind model @@ -58,7 +59,91 @@ func (layout *LayoutDSL) BindModel(m *gou.Model, formID string, fields *FieldsDS } layout.Form.Sections = []SectionDSL{{Columns: columns}} } +} +// BindForm bind form +func (layout *LayoutDSL) BindForm(form *DSL, fields *FieldsDSL) error { + + if layout.Primary == "" { + layout.Primary = form.Layout.Primary + } + + if layout.Operation == nil && form.Layout.Operation != nil { + layout.Operation = &OperationLayoutDSL{ + Actions: []component.ActionDSL{}, + Preset: map[string]map[string]interface{}{}, + } + } + + if (layout.Operation.Actions == nil || len(layout.Operation.Actions) == 0) && + form.Layout.Operation.Actions != nil { + layout.Operation.Actions = form.Layout.Operation.Actions + } + + if layout.Operation.Preset == nil || len(layout.Operation.Preset) == 0 && + form.Layout.Operation.Preset != nil { + layout.Operation.Preset = form.Layout.Operation.Preset + } + + if layout.Form == nil && form.Layout.Form != nil { + layout.Form = &ViewLayoutDSL{} + *layout.Form = *form.Layout.Form + } + return nil +} + +// BindTable bind table +func (layout *LayoutDSL) BindTable(tab *table.DSL, formID string, fields *FieldsDSL) error { + + if layout.Primary == "" { + layout.Primary = tab.Layout.Primary + } + + if layout.Operation == nil { + layout.Operation = &OperationLayoutDSL{ + Preset: map[string]map[string]interface{}{"save": {}, "back": {}}, + Actions: []component.ActionDSL{ + { + Title: "::Delete", + Icon: "icon-trash-2", + Style: "danger", + Action: map[string]component.ParamsDSL{ + "Table.delete": {"model": formID}, + }, + Confirm: &component.ConfirmActionDSL{ + Title: "::Confirm", + Desc: "::Please confirm, the data cannot be recovered", + }, + }, + }, + } + } + + if layout.Form == nil && + tab.Layout != nil && tab.Layout.Table != nil && tab.Layout.Table.Columns != nil && + len(tab.Layout.Table.Columns) > 0 { + + layout.Form = &ViewLayoutDSL{ + Props: component.PropsDSL{}, + Sections: []SectionDSL{{Columns: []Column{}}}, + } + + columns := []Column{} + for _, column := range tab.Fields.Table { + if column.Edit == nil { + continue + } + + name := column.Key + if col, has := fields.Form[name]; has { + width := 12 + columns = append(columns, Column{InstanceDSL: component.InstanceDSL{Name: col.Key, Width: width}}) + } + } + layout.Form.Sections = []SectionDSL{{Columns: columns}} + } + + return nil } func (layout *LayoutDSL) listColumns(fn func(string, Column), path string, sections []SectionDSL) { diff --git a/widgets/form/types.go b/widgets/form/types.go index 66b78f0e..3f114248 100644 --- a/widgets/form/types.go +++ b/widgets/form/types.go @@ -11,6 +11,7 @@ import ( // DSL the form DSL type DSL struct { ID string `json:"id,omitempty"` + Root string `json:"-"` Name string `json:"name,omitempty"` Action *ActionDSL `json:"action"` Layout *LayoutDSL `json:"layout"` diff --git a/widgets/table/fields.go b/widgets/table/fields.go index 6ee72ea8..e8b96fd9 100644 --- a/widgets/table/fields.go +++ b/widgets/table/fields.go @@ -8,6 +8,11 @@ import ( "github.com/yaoapp/yao/widgets/field" ) +// TableMap get table maps +func (fields *FieldsDSL) TableMap() map[string]field.ColumnDSL { + return fields.tableMap +} + // BindModel cast model to fields func (fields *FieldsDSL) BindModel(m *gou.Model) error { diff --git a/widgets/table/table.go b/widgets/table/table.go index 8685460a..e011c8aa 100644 --- a/widgets/table/table.go +++ b/widgets/table/table.go @@ -8,6 +8,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou" "github.com/yaoapp/kun/exception" + "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/share" "github.com/yaoapp/yao/widgets/component" @@ -91,7 +92,7 @@ func New(id string) *DSL { func LoadAndExport(cfg config.Config) error { err := Export() if err != nil { - return err + log.Error(err.Error()) } return Load(cfg) } @@ -108,11 +109,11 @@ func LoadID(id string, root string) error { name := fmt.Sprintf("%s.tab.json", dirs[len(dirs)-1]) elems := []string{root} elems = append(elems, dirs[0:len(dirs)-1]...) - elems = append(elems, name) + elems = append(elems, "tables", name) filename := filepath.Join(elems...) data, err := environment.ReadFile(filename) if err != nil { - return fmt.Errorf("[%s] root=%s %s", id, root, err.Error()) + return fmt.Errorf("[table] LoadID %s root=%s %s", id, root, err.Error()) } return LoadData(data, id, root) } @@ -133,7 +134,7 @@ func LoadFrom(dir string, prefix string) error { return } - err = LoadData(data, id, root) + err = LoadData(data, id, filepath.Dir(dir)) if err != nil { messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error())) return @@ -154,7 +155,7 @@ func LoadData(data []byte, id string, root string) error { err := jsoniter.Unmarshal(data, dsl) if err != nil { - return fmt.Errorf("[%s] %s", id, err.Error()) + return fmt.Errorf("[Table] LoadData %s %s", id, err.Error()) } if dsl.Action == nil { @@ -178,19 +179,19 @@ func LoadData(data []byte, id string, root string) error { // Bind model / store / table / ... err = dsl.Bind() if err != nil { - return fmt.Errorf("[%s] %s", id, err.Error()) + return fmt.Errorf("[Table] LoadData Bind %s %s", id, err.Error()) } // Parse err = dsl.Parse() if err != nil { - return fmt.Errorf("[%s] %s", id, err.Error()) + return fmt.Errorf("[Table] LoadData Parse %s %s", id, err.Error()) } // Validate err = dsl.Validate() if err != nil { - return fmt.Errorf("[%s] %s", id, err.Error()) + return fmt.Errorf("[Table] LoadData Validate %s %s", id, err.Error()) } Tables[id] = dsl diff --git a/widgets/table/table_test.go b/widgets/table/table_test.go index 33d83ecf..8aead9cf 100644 --- a/widgets/table/table_test.go +++ b/widgets/table/table_test.go @@ -27,7 +27,7 @@ func TestLoad(t *testing.T) { func TestLoadID(t *testing.T) { prepare(t) - err := LoadID("pet", filepath.Join(config.Conf.Root, "tables")) + err := LoadID("pet", filepath.Join(config.Conf.Root)) if err != nil { t.Fatal(err) }