A cljs dataview from Ona.
This library is a work-in-progress to package up much of the dataview used in Ona's new product. It provides a set of Om components that can be used to visualize a dataset that has a schema attached to it.
Install via clojars with:
data is a vector of recordsflat-form is a vector of fieldsfield is a map, containing keys name, type, full-name, label at the very least.fields with type repeats are special; we will not go into detail about them for now.record is also a map. Each key in a record should correspond to the full-name of some field.app-state has the following structure:
{:data []
:map-page {:submission-clicked {:data nil}
:geofield {}}
:table-page {:submission-clicked {:data nil}}
:chart-page {:visible-charts []
:chart-data {}}
:dataset-info {}
:languages {:current nil :all []}}
The meaning of the state is as follows:
:data should be all of the data for this dataset. A list of records, each record being a submission.:dataset-info is what is available via the /forms/ endpoint. Inside here, there should be things like form metadata, num_of_submissions and instances_with_geopoints, enketo_url, enketo_preview_url and such.languages stores the set of languages labels in this form are written in inside of :all, the currently selected language (default English) is store in :current. This part of the app-state is used by the reference cursor language-cursor.:map-page, :table-page, and :chart-page contain the state necessary for each of those pages.
:submission-clicked stores data about the record which is clicked.visible-charts is the list of all charts that the user has called up on this page. chart-data is a map that stores the raw chart API data for all of the fields that the user has requested charts on.User has the responsibility of updating :data, :dataset-info and :flat-form by fetching them; the utility flatten-form is available to convert what you get from Ona into a flat form..
Note: for speed of decoding, it is assumed for now that the keys for data are plain strings, not keywords. data is exceptional in this way; other maps are expected to contain plain clojure(script) keywords.
shared-state needs:
{:flat-form []
:view-type :ona-default}
exposed cursors:
shared/language-cursor
To render the dataview into your application, you'll need something like the following. The app-state can be updated once constructed, and generally the right thing will happen. Shared state cannot be updated.
(om/root tabbed-dataview
app-state-atom
{:target ...
:shared {:flat-form _your-form_
:view-type _your-view-type_}})
(Future: flat-form will be moved to app-state, since it does need to be updated sometimes).
tabbed-dataview
dataview-infobarmap-page (cursor: map-page, dataset-info)
map-and-markers (cursor: map-page)geofield-chooser (cursor: map-page geo-field)view-by-legend (cursor: map-page view-by, dataset-info)
view-by-menu (cursor: dataset-info)view-by-answer-legend (cursor: view-by)submission-legend (cursor: map-page geo-field, map-page submission-clicked)
single-submission/submission-viewtable-page
label-changer (cursor: nil, works on shared cursor language-cursorsingle-submission/submission-viewchart-page
chart-chooser (cursor: nil)list-of-charts (cursor: chart-page)
single-chart (cursor: chart-page chart-data >element)settings-page (cursor: dataset-info)
Hatti will primarily provide a set of Om components that are meant to be used in a dataview such as Zebra. All of Hatti's Om components should be over-rideable, you should be able to over-ride any of the Internal Hatti components easily and have a new dataview that incorporates such over-riding. As such, here is the basic proposal for how Hatti's components should be written:
Components in Hatti should be multi-methods. By default, the dispatch value will be :view-type [1] stored in the application shared state.
(defmulti map-page
(fn [_ owner & _]
(om/get-shared owner :view-type)))
(defn map-page :ona-default
[cursor owner]
; actual map-page definition
...)
This will allow any user to include the map-page in their view.
Now say that they want to change the way the map view-by menu is rendered. They would do this by providing a value to correspond to ::view-type in the om/root call, and then overriding whatever component or subcomponent they want implemented differently.
(derive :my-view :ona-default)
(om/root map-page atom {:target ...
:shared {:view-type :my-view}})
(defn view-by-menu :my-view
[cursor owner]
; the view-by-menu definition specific to :my-view
...)
There may be some components which also need some special treatment within other views, eg. a submission-view which is different for the map and the table page. These should be implemented as multi-methods with a different dispatch function that still incorporates the shared ::view-type, An example could be:
(defmulti single-submission-view
(fn [cursor owner & _]
[(om/get-shared owner :view-type) (-> cursor :selected-view)]))
(defmethod single-submission-view [:ona-default :map]
(fn [cursor owner opts]
...))
(defmethod single-submission-view [:ona-default :table]
(fn [cursor owner opts]
...))
[1] - It will actually be the namespace-qualified ::view-type, but I need to do a bit more research to figure out how to use it properly.
Hatti is released under the Apache 2.0 License.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |