123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- package presets
- import (
- "fmt"
- "net/http"
- "net/url"
- "reflect"
- "strings"
- "github.com/iancoleman/strcase"
- "github.com/jinzhu/inflection"
- "github.com/qor5/admin/presets/actions"
- "github.com/qor5/web"
- "github.com/qor5/x/perm"
- )
- type ModelBuilder struct {
- p *Builder
- model interface{}
- primaryField string
- modelType reflect.Type
- menuGroupName string
- notInMenu bool
- menuIcon string
- uriName string
- defaultURLQueryFunc func(*http.Request) url.Values
- label string
- fieldLabels []string
- placeholders []string
- listing *ListingBuilder
- detailing *DetailingBuilder
- editing *EditingBuilder
- creating *EditingBuilder
- writeFields *FieldsBuilder
- hasDetailing bool
- rightDrawerWidth string
- link string
- layoutConfig *LayoutConfig
- modelInfo *ModelInfo
- singleton bool
- web.EventsHub
- }
- func NewModelBuilder(p *Builder, model interface{}) (mb *ModelBuilder) {
- mb = &ModelBuilder{p: p, model: model, primaryField: "ID"}
- mb.modelType = reflect.TypeOf(model)
- if mb.modelType.Kind() != reflect.Ptr {
- panic(fmt.Sprintf("model %#+v must be pointer", model))
- }
- modelstr := mb.modelType.String()
- modelName := modelstr[strings.LastIndex(modelstr, ".")+1:]
- mb.label = strcase.ToCamel(inflection.Plural(modelName))
- mb.uriName = inflection.Plural(strcase.ToKebab(modelName))
- mb.modelInfo = &ModelInfo{mb: mb}
- // Be aware the uriName here is still the original struct
- mb.newListing()
- mb.newDetailing()
- mb.newEditing()
- return
- }
- func (mb *ModelBuilder) RightDrawerWidth(v string) *ModelBuilder {
- mb.rightDrawerWidth = v
- return mb
- }
- func (mb *ModelBuilder) Link(v string) *ModelBuilder {
- mb.link = v
- return mb
- }
- func (mb *ModelBuilder) registerDefaultEventFuncs() {
- mb.RegisterEventFunc(actions.New, mb.editing.formNew)
- mb.RegisterEventFunc(actions.Edit, mb.editing.formEdit)
- mb.RegisterEventFunc(actions.DeleteConfirmation, mb.listing.deleteConfirmation)
- mb.RegisterEventFunc(actions.Update, mb.editing.defaultUpdate)
- mb.RegisterEventFunc(actions.DoDelete, mb.editing.doDelete)
- mb.RegisterEventFunc(actions.DoBulkAction, mb.listing.doBulkAction)
- mb.RegisterEventFunc(actions.DoListingAction, mb.listing.doListingAction)
- mb.RegisterEventFunc(actions.OpenBulkActionDialog, mb.listing.openBulkActionDialog)
- mb.RegisterEventFunc(actions.OpenActionDialog, mb.listing.openActionDialog)
- mb.RegisterEventFunc(actions.Action, mb.detailing.formDrawerAction)
- mb.RegisterEventFunc(actions.DoAction, mb.detailing.doAction)
- mb.RegisterEventFunc(actions.DetailingDrawer, mb.detailing.showInDrawer)
- mb.RegisterEventFunc(actions.ReloadList, mb.listing.reloadList)
- mb.RegisterEventFunc(actions.OpenListingDialog, mb.listing.openListingDialog)
- mb.RegisterEventFunc(actions.UpdateListingDialog, mb.listing.updateListingDialog)
- // list editor
- mb.RegisterEventFunc(actions.AddRowEvent, addListItemRow(mb))
- mb.RegisterEventFunc(actions.RemoveRowEvent, removeListItemRow(mb))
- mb.RegisterEventFunc(actions.SortEvent, sortListItems(mb))
- }
- func (mb *ModelBuilder) NewModel() (r interface{}) {
- return reflect.New(mb.modelType.Elem()).Interface()
- }
- func (mb *ModelBuilder) NewModelSlice() (r interface{}) {
- return reflect.New(reflect.SliceOf(mb.modelType)).Interface()
- }
- func (mb *ModelBuilder) newListing() (lb *ListingBuilder) {
- mb.listing = &ListingBuilder{
- mb: mb,
- FieldsBuilder: *mb.p.listFieldDefaults.InspectFields(mb.model),
- dialogWidth: "1200px",
- }
- if mb.p.dataOperator != nil {
- mb.listing.SearchFunc(mb.p.dataOperator.Search)
- }
- rmb := mb.listing.RowMenu()
- rmb.RowMenuItem("Edit").ComponentFunc(editRowMenuItemFunc(mb.Info(), "", url.Values{}))
- rmb.RowMenuItem("Delete").ComponentFunc(deleteRowMenuItemFunc(mb.Info(), "", url.Values{}))
- return
- }
- func (mb *ModelBuilder) newEditing() (r *EditingBuilder) {
- mb.writeFields, mb.listing.searchColumns = mb.p.writeFieldDefaults.inspectFieldsAndCollectName(mb.model, reflect.TypeOf(""))
- mb.editing = &EditingBuilder{mb: mb, FieldsBuilder: *mb.writeFields}
- if mb.p.dataOperator != nil {
- mb.editing.FetchFunc(mb.p.dataOperator.Fetch)
- mb.editing.SaveFunc(mb.p.dataOperator.Save)
- mb.editing.DeleteFunc(mb.p.dataOperator.Delete)
- }
- return
- }
- func (mb *ModelBuilder) newDetailing() (r *DetailingBuilder) {
- mb.detailing = &DetailingBuilder{mb: mb, FieldsBuilder: *mb.p.detailFieldDefaults.InspectFields(mb.model)}
- if mb.p.dataOperator != nil {
- mb.detailing.FetchFunc(mb.p.dataOperator.Fetch)
- }
- return
- }
- func (mb *ModelBuilder) Info() (r *ModelInfo) {
- return mb.modelInfo
- }
- type ModelInfo struct {
- mb *ModelBuilder
- }
- func (b ModelInfo) ListingHref() string {
- return fmt.Sprintf("%s/%s", b.mb.p.prefix, b.mb.uriName)
- }
- func (b ModelInfo) EditingHref(id string) string {
- return fmt.Sprintf("%s/%s/%s/edit", b.mb.p.prefix, b.mb.uriName, id)
- }
- func (b ModelInfo) DetailingHref(id string) string {
- return fmt.Sprintf("%s/%s/%s", b.mb.p.prefix, b.mb.uriName, id)
- }
- func (b ModelInfo) HasDetailing() bool {
- return b.mb.hasDetailing
- }
- func (b ModelInfo) DetailingInDrawer() bool {
- return b.mb.detailing.drawer
- }
- func (b ModelInfo) PresetsPrefix() string {
- return b.mb.p.prefix
- }
- func (b ModelInfo) URIName() string {
- return b.mb.uriName
- }
- func (b ModelInfo) Label() string {
- return b.mb.label
- }
- func (b ModelInfo) Verifier() *perm.Verifier {
- v := b.mb.p.verifier.Spawn()
- if b.mb.menuGroupName != "" {
- v.SnakeOn("mg_" + b.mb.menuGroupName)
- }
- return v.SnakeOn(b.mb.uriName)
- }
- func (mb *ModelBuilder) URIName(v string) (r *ModelBuilder) {
- mb.uriName = v
- return mb
- }
- func (mb *ModelBuilder) DefaultURLQueryFunc(v func(*http.Request) url.Values) (r *ModelBuilder) {
- mb.defaultURLQueryFunc = v
- return mb
- }
- func (mb *ModelBuilder) PrimaryField(v string) (r *ModelBuilder) {
- mb.primaryField = v
- return mb
- }
- func (mb *ModelBuilder) InMenu(v bool) (r *ModelBuilder) {
- mb.notInMenu = !v
- return mb
- }
- func (mb *ModelBuilder) MenuIcon(v string) (r *ModelBuilder) {
- mb.menuIcon = v
- return mb
- }
- func (mb *ModelBuilder) Label(v string) (r *ModelBuilder) {
- mb.label = v
- return mb
- }
- func (mb *ModelBuilder) Labels(vs ...string) (r *ModelBuilder) {
- mb.fieldLabels = append(mb.fieldLabels, vs...)
- return mb
- }
- func (mb *ModelBuilder) LayoutConfig(v *LayoutConfig) (r *ModelBuilder) {
- mb.layoutConfig = v
- return mb
- }
- func (mb *ModelBuilder) Placeholders(vs ...string) (r *ModelBuilder) {
- mb.placeholders = append(mb.placeholders, vs...)
- return mb
- }
- func (mb *ModelBuilder) Singleton(v bool) (r *ModelBuilder) {
- mb.singleton = v
- return mb
- }
- func (mb *ModelBuilder) getComponentFuncField(field *FieldBuilder) (r *FieldContext) {
- r = &FieldContext{
- ModelInfo: mb.Info(),
- Name: field.name,
- Label: mb.getLabel(field.NameLabel),
- }
- return
- }
- func (mb *ModelBuilder) getLabel(field NameLabel) (r string) {
- if len(field.label) > 0 {
- return field.label
- }
- for i := 0; i < len(mb.fieldLabels)-1; i = i + 2 {
- if mb.fieldLabels[i] == field.name {
- return mb.fieldLabels[i+1]
- }
- }
- return humanizeString(field.name)
- }
|