Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metadata #1

Open
andrerpena opened this issue Dec 30, 2014 · 6 comments
Open

Metadata #1

andrerpena opened this issue Dec 30, 2014 · 6 comments

Comments

@andrerpena
Copy link
Contributor

This is a proposition about Metadata. All ideas here are subject to change.    

Introduction

Metadata is one of the gearz pillars. Metadata is a collection of JavaScript objects that describe the domain of a gearz application. Metadata includes entities, entity-views, properties and property-groups.

Metadata serves as information for component rendering.

Gearz have three kinds of components:

  • Primitive component: A component that renders the display or editor for a single domain property. Primitive components render themselves based on a Property metadata. Examples: TextBox, CheckBox, Autocomplete.
  • Layout component: A component that renders a group of primitive components. Layout components render themselves based on an Entity-View metadata. Examples: EditForm, DisplayView. Grid.
  • Page component. A component that renders a page, which is the target of a route. For instance, then the user navigates to /contacts/edit/2, the user then accesses the Edit page component, which will, in turn, render one or more Layout Components. Examples: Edit page, Details page, Search Page.

Entities

Entities are object types the Gearz application can manipulate. Examples: Contacts, Sales proposals and Sales.

Entity properties

  • name (string): The entity name.
  • displayName (string): The human-friendly entity name.
  • properties (array of Property): The entity's property collection.

Entity views

Entity views are the visual representation of a view for a particular use. For instance, the entity contactmay have different properties depending on whether you are displaying, editing, or displaying a list of contacts.

EntityView properties

  • name (string): The entity view name.
  • entityName (string): The entity this entity view represents.
  • displayName (string). The human-friendly entity view name.
  • groups (array of PropertyGroup): The entity views's property group collection.

Property group

Entity-views have their properties separated by groups, which can be 1 or N.

PropertyGroup properties

  • name (string). The property group name.
  • displayName (string). The property group human-friendly name.
  • invisible (bool or text-expression): Whether or not the property group is invisible. Defaults to false.
  • disabled (bool or text-expression): Whether or not the property group is disabled. Defaults to false.
  • properties (array of Property): The group property collection.

Property

Represent a single field in an Entity or EntityView.

Property properties

  • name (string): The property name.
  • displayName (string): The property human-friendly name.
  • required (bool or text-expression): Whether or not the property is required. Defaults to false.
  • invisible (bool or text-expression): Whether or not the property is invisible. Defaults to false.
  • disabled (bool or text-expression): Whether or not the property is disabled. Defaults to false.
  • invalid (bool or text-expression): Whether or not the property is invalid. Defaults to false.

Object structure

Metadata is globally accessible through the window.meta property.

Example of getting whether or not the nameproperty of contact is required:

var required = window.meta.entities["contact"].propertyGroups["main"].properties["name"].required;

Scratch

meta.entities...
meta.components["lookup-contacts"]
    url
    columns



public class FluentMetadata : FluentMetadataProvider {
    public override SetupMetadata(MetadataContext c) {
        c.Components.Add("bool-display-principal",  new BoolDisplay() {
            TrueDisplay: "Sim",
            FalseDisplay: "Talvez"
        });

        c.EntityView<Processo>()
            .AddProperty(p => p.Principal)
                .Component("bool-display-principal");



        c.Components.Defaults.Display
            .Set(typeof(String), "TextBox")
            .Set(typeof(Bool), "CheckBox")
            .Set(typeof());


    }
}
@masbicudo
Copy link
Member

What do you think about this for groups:

    // SIMPLE EDIT PAGE
    c.EntityView<ProcessoSimplerrimo>(ctx => {
        // no grouping... we go straight to the nested property
        ctx.Property(p => p.ChildObject.NestedSubProp);
    })
    .DefaultEditorComponent("MetaEditor");

    // NORMAL EDIT PAGE
    c.EntityView<Processo>(ctx => {
        // we use the child object, and let the default component for that object be used
        ctx.Property(p => p.ChildObject); // will use the default editor
    })
    .DefaultEditorComponent("MetaGroupedEditor");

    // COMPLEX EDIT PAGE
    c.EntityView<ProcessoComplexo>(ctx => {
        // in this case, we won't use the default editor of the `ChildObjectType`
        ctx.Property(p => p.ChildObject).EditorComponent("ComplexChildEditor");
    })
    .DefaultEditorComponent("MetaTabbedEditor");

    // Editor for `ChildObjectType`
    c.EntityView<ChildObjectType>(ctx => {
        ctx.Property(p => p.NestedSubProp);
    })
    .DefaultEditorComponent("MetaEditor");

I really don't care for the format... just the idea of making groups by using nested objects.

If we decide to use no View Models, it's not a problem, just use text instead of expressions:

    // SIMPLE EDIT PAGE
    c.EntityView("ProcessoSimplerrimo")(ctx => {
        // no grouping... we go straight to the nested property
        ctx.Property("ChildObject.NestedSubProp");
    })
    .DefaultEditorComponent("MetaEditor");

    // NORMAL EDIT PAGE
    c.EntityView("Processo")(ctx => {
        // we use the child object, and let the default component for that object be used
        ctx.Property("ChildObject"); // will use the default editor
    })
    .DefaultEditorComponent("MetaGroupedEditor");

    // COMPLEX EDIT PAGE
    c.EntityView("ProcessoComplexo")(ctx => {
        // in this case, we won't use the default editor of the `ChildObjectType`
        ctx.Property("ChildObject").EditorComponent("ComplexChildEditor");
    })
    .DefaultEditorComponent("MetaTabbedEditor");

    // Editor for `ChildObject`
    c.EntityView("ChildObject")(ctx => {
        ctx.Property("NestedSubProp");
    })
    .DefaultEditorComponent("MetaEditor");

@andrerpena
Copy link
Contributor Author

I liked the idea of being able to render a complex object as a property. Example: You could render an Address object as a property of Contact.

However, it also seems a good idea to be able to visually group properties (eg in collapsible panels). For instance, in a Contact, you could group Phone properties even though they don't belong to a Phone object.

If we assume we will only have ViewModels and not Models, then it's plausible to force the developer to group Phone properties in a Phone object. Otherwise it's not.

@masbicudo
Copy link
Member

More ideas regarding your concerns:

    // COMPLEX EDIT PAGE
    c.EntityView<ProcessoComplexo>(ctx => {
        // in this case, we won't use the default editor of the `ChildObjectType`
        ctx.Property(p => p.ChildObject).EditorComponent("ComplexChildEditor");
        ctx.PropertyGroup("GrpPhones", p => p.Phone1, p => p.Phone2, p => p.Office.Phone)
            .EditorComponent("CustomPhonesCollapsiblePanel");
            // in the client-side, the CollapsiblePanel component, would receive:
            //   data: { Phone1: "(32)1234-1245", Phone2: "(21)4434-5242", 'Office.Phone': "(32)9188-6534", }
            //   meta: window.gearz.meta.{Editor...xpto.default}.ProcessoComplexo.GrpPhones
            //          the meta['Office.Phone'] would be pointing to
            //          window.gearz.meta.{Editor...xpto.default}.OfficeType.Phone
    })
    .DefaultEditorComponent("MetaTabbedEditor");

     // defining a default for groups called GrpPhone... ??? not sure about this???
     c.Group("GrpPhones")
        .DefaultEditorComponent("CollapsiblePanel");

The PropertyGroup method can be used to create groups of properties without needing class composition.

The Group method can be used to create default metadata for groups.

@andrerpena
Copy link
Contributor Author

As far as I see this, the developer would have to previously create the CustomPhonesCollapsiblePanel component. Because the EditorComponent would receive the name of a previously defined component.

This wouild make more sense to me:

    // COMPLEX EDIT PAGE
    c.EntityView<ProcessoComplexo>(ctx => {
        // in this case, we won't use the default editor of the `ChildObjectType`
        ctx.Property(p => p.ChildObject).EditorComponent("ComplexChildEditor");
        ctx.PropertyGroup("GrpPhones", "Phones").AddProperty(c => c.Phone1).AddProperty(c => c.Phone2);
        }
    }

This way, Phone1 and Phone2 would just be visually grouped in GrpPhones. You could optionally define a component for the group. It could be a collapsible panel by default.

@masbicudo
Copy link
Member

The EditorComponent call is optional... I was just giving an example on how to override the default component, if you wished to.

I reviewed the code I have posted, and changed it:

  • there was no way to create subgroups
  • it was not very fluent like (with some ; statement terminators in the middle of the fluent code)
  • virtual properties (that don't exist in the view model)
    • ability to create virtual properties
    • ability to use virtual properties (text based AND ALSO strongly typed)
  • how to set attributes of properties at any level
  • ability to set hints to the component that will be rendered
  • shortened the names of methods (just to see how it looks)
// defining a group type
var grpPhones = c.GroupType("GrpPhones")
    .Display("Phones")
    .Editor("CollapsiblePanel");

// COMPLEX EDIT PAGE
VirtualProperty<bool> vpHasPhone3;
c.EntityView<ProcessoComplexo>()
    .Editor("MetaTabbedEditor")
    .Property(proc => proc.ChildObject, p => p
        // OPTIONAL: override the default editor for the type of the `ChildObject`
        .Editor("ComplexChildEditor"))

    // creating a virtual property... does not exist in the view-model
    .Property<bool>("HasPhone2", pcx => pcx
        .Display("Has secondary phone"))

    // ALTERNATIVE: creating a virtual property... does not exist in the view-model
    .Property<bool>("HasPhone3", out vpHasPhone3, p => p
        .Display("Has third phone"))

    .Group(grpPhones, "Phones", gcx => gcx
        // OPTIONAL: override the default editor of the group type
        .Editor("CustomPhonesCollapsiblePanel")

        // OPTIONAL: override the default display name of the group type
        .Display("Phones ABCD")
        .SomeOtherAttribute("Xpto")
        .Hint("collapsed", false)

        // adding child elements
        .Property(proc => proc.Phone1, spcx => spcx
            // defining the display name of the property
            .Display("Main Phone"))
        .Property(proc => proc.Phone2, spcx => spcx
            .InvisibleWhen("!HasPhone2")) // text based reference to virtual prop
        .Property(proc => proc.Phone3, spcx => spcx
            .InvisibleWhen(p => !vpHasPhone3.Value)) // strongly typed reference to virtual prop
        .Property(proc => proc.Office.Phone)

        // referring the group-type by name... should it be possible?
        .Group("GrpPhones", "SecondaryPhones", sgcx => sgcx
            .Display("Other phones")
            .Hint("collapsed", true)
            .Property(proc => proc.Office.SecondaryPhone)
        )
    );

What do you think about this?

@andrerpena
Copy link
Contributor Author

I liked your last version :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants