Giter Site home page Giter Site logo

datview's Introduction

Datview

[Insert explosive graphic]

Introduction

If om-next gets the idea of components requesting the shape of data they need correct, Datview goes one step further in realizing you can let the shape of the data you request direct the rendering of that data.

Instead of decorating components with information about where they get their data, decorate queries with information about how they render :-) This data driven approach leads to effortlessly composable view code, meaning complex UI can be programmatically constructed from simple pieces. This will make it possible to very rapidly build complex data driven applications.

It's going to take a bit of work to fully smooth out all the defaults and patterns, but I'm liking the picture so far.

How does it work?

We do this with metadata on parts of our pull expressions and queries

Example:

    (def small-fonts {:font-size "8px"})
    (def small-fonts-bold (merge small-fonts
                                 {:font-weight "bold"}))

    (def time-entry-view
      ^{:attributes {:e/description {:style small-fonts}}
        ;; Possible? But not supported yet.
        :derived-attributes {:time.entry/duration
                             ^{:datview.derived-attribute/of [:time.entry/stop-time :time.entry/start-time]}
                             (fn [{:as time-entry :keys [time.entry/stop-time time.entry/start-time]}]
                               (- stop-time start-time))}}
      [:e/description :time.entry/duration]

    (def todo-view
      ^{:attributes {:e/tags {:style small-fonts-bold :summarize tag-name-fn}
                     :e/description {:style small-fonts}
                     :e/category {:style small-fonts-bold}
                     :todo/hours {:wrapper todo-hours-with-summary}}
        :wrapper [lined-box]}
      [:e/name :e/category :e/tags :e/description
       ;; Here we have some reference attributes
       {:todo/time-entries time-entry-view}
       {:todo/subtasks ^{:note "Here merge into the attributes passed down recursively"}
                       '...}])

Functions (Reagent components) like pull-view, attr-view and value-view are wired together into a recursive tree, based on various entry points. Each one of these entry points can be customized in the structure of the pull metadata. Thus everything is perfectly composable, because everything is just data. We can override things so that when we push down into some particular part of a pull expression, the corresponding components will be rendered exactly as you wish :-)

The brilliant thing is that we can also just do this if you don't need customization:

(pull-view conn [:e/name :e/category :e/tags :e/description {:todo/subtasks ...}])
;; uhh... actually not _quite_ yet... need to get `'...` to work in posh

Or even better

(pull-view conn '[*] eid)

Fine...

(entity-view conn eid)

Collections?

Yeah, we got that too:

(pull-many-view conn todo-view todo-eids)
;; Just kidding! Coming soon...

What about q?

(q-view conn {:find [[('pull todo-view '?todo) '...]]
              :where '[[?todo :e/type :e.type/Todo]
                       [?todo :e/category :category/Work]]})
;; Haha; Also j/k. Vaporware Suckers (TM)!

This lets us build tables or other collection views using the full expressiveness of DataScript Datalog for scope.

Imagine that? Composing queries which know how to render themselves.

This schema is serializable to the DataScript DB, and can be accessed and operated upon in the component functions. The default functions pull from these. But you can customize and extend them more or less as you wish. And of course, all of these settings are overridable by the metadata specifications on a local basis.

Datview Specification Schema

Datview is half way towards using Prismatic Schema for type specifications. However, now that Clojure 1.9 has proper specs, we'll probably redraft in terms of those. Still, for the mean time, the specs in datview.schema should serve as a rough guide for the shape of the datview specification grammar.

Customizing global defaults

You might have a set of global defaults (for styles, wrappers, rendering functions, etc) you'd like to apply without having to manually pass in the metadata each time.

We support this with the following functions:

  • default-config: Returns a reaction of the default configuration.
  • update-default-config!: Atomically update default config using an update function.
  • set-default-config!: Resets the default-config.

datview's People

Contributors

bamarco avatar charles-dyfis-net avatar metasoarous avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

datview's Issues

spec for pull data

(defn mapply [f & args]
  (apply f (apply concat (butlast args) (last args))))

(s/def :dat.sys.view.entity.type :datomic.db.ident)
(s/def :dat.sys.view.entity.type.attributes (s/coll-of :datomic.db.ident))
;;(defmulti entity-type :dat.sys.view.entity.type)
(defmulti entity-type :e/type)
;;(s/def :dat.sys.view.entity (s/and map? (s/multi-spec entity-type :dat.sys.view.entity.type)))
(s/def :dat.sys.view.entity (s/and map? (s/multi-spec entity-type :e/type)))

(defonce value-type->spec
  {:db.type/string :datomic.db.type.string
   :db.type/boolean :datomic.db.type.boolean
   :db.type/long :datomic.db.type.long
   :db.type/bigint :datomic.db.type.bigint
   :db.type/float :datomic.db.type.float
   :db.type/double :datomic.db.type.double
   :db.type/bigdec :datomic.db.type.bigdec
   :db.type/ref :dat.sys.view.entity
   :db.type/instant :datomic.db.type.instant
   :db.type/uuid :datomic.db.type.uuid
   :db.type/uri :datomic.db.type.uri
   :db.type/bytes :datomic.db.type.bytes})

(s/def :dat.sys.view.entity/data
  (mapply s/or value-type->spec))

(defn dat-entity-schema? [{:as schema
                           entity-type :e/type ;; :dat.sys.view.entity.type
                           }]
  entity-type)

(defn dat-entity-type? [{:as schema
                         entity-type :e/type ;; :dat.sys.view.entity.type
                         }]
  (and entity-type (= entity-type :e.type/type ;; :dat.sys.view.entity.type
  )))

(defn defschema-attr-specs [schemas]
  (for [{attr :db/ident
         value-type :db/valueType} schemas]
    (s/def attr (value-type->spec value-type))))

(defn defschema-specs [schemas]
  (let [entity-types (filter dat-entity-type? schemas)
        attr-specs (remove dat-entity-schema? schemas)]
  (defschema-attr-specs attr-specs)
  (for [{attrs :e.type/attributes ;; :dat.sys.view.entity.type.attributes
         e-type :db/ident
         } entity-types]
  (defmethod entity-type e-type []
    (s/keys :req (into [:dat.sys.view.entity.type] attrs))))))

Datom controls should have a local mode

The default behavior for some input is to send transactions through the server, and wait for the transaction report to flow through the normal data circuit. However, there are cases where you might want to transact locally (for instance, for data that isn't even in the central DB, or for apps which don't even have a central db). And we also want to think about how we control different handler strategies like optimistic update etc. So I think some bit of context data and corresponding control indirection that tells us how a control is supposed to respond to changes would be stellar. Should ideally be flexible, orthogonal to other concerns, etc.

Make representations feel more first class?

Right now represent is a multimethod, and extensibility of datview involves defining custom methods. We should think about how we can make this more flexible and polished. Like, when you register one of these things, you should be able to register it with documentation, and specs for the context mapping. And maybe we can use a macro to do all this as well as define a var form of the component for convenience. Lots of questions here about how we can do this...

Examples/Getting Started

Greetings!

I'd like to start playing with DatView. Are there any examples I can use to get started? Bonus points if it also uses DatSync.

Thanks!

Using pull-form without the datview-schema :e/type stuff

I would like to use DatView but without having to augment my Datomic schema with the :e/type definitions.
I would prefer to specifically query the datoms I want, essentially moving these definitions to the client side with queries such as;

[dat.view/pull-form app '[:db/id :location/name :location/address] e]
or
[dat.view/pull-form app '[*] e]

However, DatView currently seems to ignore the pull-expr and only renders the datoms that have the :e/type definitions. If the entity does not contain a :e/type datom it fails with an "Error rendering component".

Is adding :e/type to entities a requirement for using DatView going forward?

Formalize context flow/scoping

Feels like there could be a lot of potential patterns for how one component sets up context for children components. We should think about these possible patterns and how we can standardize around a sort of meta-pattern here to keep things sane. Is this something that can be dispatched as well?

Make controls more composable

This is pretty open ended... The bottom line though is that you shouldn't have to override a representation to specify which controls something needs. Representations have a lot of gunk in them (passing down context etc), and folks shouldn't have to wade through that just to pick some controls. Maybe controls should be separately registered? What should the shape be? This would let us just specify the namespaced keywords for which controls we wanted, and separately specify how we group them together.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.