Skip to content

Commit

Permalink
Merge pull request #568 from uosl/feature/subclasses
Browse files Browse the repository at this point in the history
Support subclasses
  • Loading branch information
heralden committed Oct 7, 2020
2 parents 8491974 + a9f3326 commit ce37972
Show file tree
Hide file tree
Showing 27 changed files with 681 additions and 235 deletions.
14 changes: 13 additions & 1 deletion docs/tools/tool-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ If your tool *accepts* `ids` and takes multiple *classes*, (see [config.json](/d
}
```

Subclasses (descendant of a class in the model hierarchy) might also be passed to your tool if it's descendant of one of your tool's *classes*. When this happens, the key will still be its superclass which you specified in *classes*, while the subclass name can be accessed under `class`. If you want your tool to work with subclasses, you'll need to make sure that any queries you build based on imEntity sets the `from` key to this `class` (`imEntity.Gene.class` in this example).

```json
{
"Gene": {
"class": "ORF",
"format": "id",
"value": 5
}
}
```

It is up to you which class you want to use in your tool, and you can even use multiple.

Currently, it is not possible to receive multiple classes on the report page with *accepts* `id`. However, the Tool API allows for this should it be an option in the future.
Expand Down Expand Up @@ -146,7 +158,7 @@ This file provides bluegenes-specific config info. Some further config info is d

Plurality (i.e. id vs ids) will help to determine which context a tool can appear (report page, list analysis page)

**classes** default to `*` if this tool isn't class / objectType specific. otherwise your tool might be specific to a certain class, e.g. a gene displayer.
**classes** default to `*` if this tool isn't class / objectType specific. Otherwise your tool might be specific to a certain class, e.g. a gene displayer. Note that a subclass of a class you specify here may be passed via *imEntity* (see its section above for more details).

**columnMapping** is an important way to specify (or override) which columns should be passed to the tool by BlueGenes. As an example, for a gene tool, you might want to pass a symbol, OR a primaryIdentifier, or even secondaryIdentifier - and this might change depending in the InterMine that is fuelling the BlueGenes. Set a default likely value here, and in the future individual bluegenes administrators can override it if needed.

Expand Down
21 changes: 19 additions & 2 deletions less/components/querybuilder.less
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,11 @@ div.column-container {
font-weight: 500;
color: @query-browser-class;
white-space: nowrap;

.label {
padding: @spacer*0.1 @spacer*0.6;
margin-left: @spacer/2;
}
}

.qb-type {
Expand Down Expand Up @@ -591,6 +596,10 @@ div.column-container {
.qb-class {
font-weight: 500;
color: @model-browser-class;

&.empty-class {
color: @body-foreground-color;
}
}

.light {
Expand Down Expand Up @@ -643,8 +652,16 @@ div.column-container {
z-index: 11;
}

.model-button-group {
display: flex;
.model-button-container {
padding-left: 0.6em;

.model-button-group {
display: flex;

.icon {
fill: @body-foreground-color;
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@

; Intermine Assets
[org.intermine/im-tables "0.10.1"]
[org.intermine/imcljs "1.1.0"]
[org.intermine/imcljs "1.2.0"]
[org.intermine/bluegenes-tool-store "0.2.0"]]

:deploy-repositories {"clojars" {:sign-releases false}}
Expand Down
17 changes: 14 additions & 3 deletions src/cljs/bluegenes/components/icons.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,6 @@

[:symbol#icon-summary
{:viewBox "0 0 16 16"}
[:title "summary"]
[:path.path1
{:d
"M13.5 0h-12c-0.825 0-1.5 0.675-1.5 1.5v13c0 0.825 0.675 1.5 1.5 1.5h12c0.825 0 1.5-0.675 1.5-1.5v-13c0-0.825-0.675-1.5-1.5-1.5zM13 14h-11v-12h11v12zM4 7h7v1h-7zM4 9h7v1h-7zM4 11h7v1h-7zM4 5h7v1h-7z"}]]
Expand Down Expand Up @@ -539,7 +538,6 @@

[:symbol#icon-bin
{:viewBox "0 0 16 16"}
[:title "bin"]
[:path
{:d
"M2 5v10c0 0.55 0.45 1 1 1h9c0.55 0 1-0.45 1-1v-10h-11zM5 14h-1v-7h1v7zM7 14h-1v-7h1v7zM9 14h-1v-7h1v7zM11 14h-1v-7h1v7z"}]
Expand Down Expand Up @@ -804,4 +802,17 @@
{:d
"M77.7675 47.9216H94.1618C94.3911 47.9216 94.6182 47.9677 94.83 48.0571C95.0419 48.1465 95.2344 48.2776 95.3965 48.4429C95.5587 48.6082 95.6873 48.8044 95.7751 49.0203C95.8628 49.2363 95.908 49.4677 95.908 49.7014V50.4089C95.908 50.8843 95.7227 51.3404 95.3928 51.6766C95.0629 52.0128 94.6155 52.2017 94.149 52.2017H77.7547C77.2853 52.2017 76.8351 52.0116 76.5032 51.6733C76.1713 51.335 75.9848 50.8761 75.9848 50.3977V49.7387C75.9848 49.2567 76.1726 48.7946 76.5069 48.4538C76.8413 48.1131 77.2947 47.9216 77.7675 47.9216Z"}]
[:path
{:d "M88.3843 52.1886V62.8165H92.5829V52.1886H88.3843Z"}]]]])
{:d "M88.3843 52.1886V62.8165H92.5829V52.1886H88.3843Z"}]]

[:symbol#icon-enlarge2
{:viewBox "0 0 32 32"}
[:path
{:d
"M32 0v13l-5-5-6 6-3-3 6-6-5-5zM14 21l-6 6 5 5h-13v-13l5 5 6-6z"}]]

[:symbol#icon-shrink
{:viewBox "0 0 32 32"}
[:path {:d "M18 14h13l-5-5 6-6-3-3-6 6-5-5z"}]
[:path {:d "M18 18v13l5-5 6 6 3-3-6-6 5-5z"}]
[:path {:d "M14 18h-13l5 5-6 6 3 3 6-6 5 5z"}]
[:path {:d "M14 14v-13l-5 5-6-6-3 3 6 6-5 5z"}]]]])
18 changes: 7 additions & 11 deletions src/cljs/bluegenes/components/idresolver/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@
::fx/http {:uri "/api/ids/parse"
:method :post
:multipart-params
(cond->
(map (fn [f] [(oget f :name) f])
js-Files)
; After creating multipart params for files,
; create one for text
; if there's a value
(cond-> (map (fn [f] [(oget f :name) f]) js-Files)
; After creating multipart params for files,
; create one for text
; if there's a value
(not (string/blank? text))
(conj ["text" text])
; And also a param for the case sensitive option
Expand Down Expand Up @@ -118,11 +116,9 @@
::update-type
(fn [db [_ model value]]
;; why are we disabling organism?
(let [disable-organism? (when
(not= value "_")
(not (contains?
(path/relationships model value)
:organism)))
(let [disable-organism? (when (not= value "_")
(not (contains? (path/relationships model value)
:organism)))
mine-details (get-in db [:mines (get db :current-mine)])]
(if disable-organism?
(update-in db [:idresolver :stage :options]
Expand Down
2 changes: 1 addition & 1 deletion src/cljs/bluegenes/components/lighttable.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

([results options]
(if (:title options) ;; we could tweak this further to make a nice passed-in title, too
[:div
[:div ; if you complete this component, you should assoc :type-constraints to current-model (see path/walk docstring)
[:h4 (:displayName (first (path/walk @current-model (:class results))))]
[table results]]
[table results])))))
Expand Down
5 changes: 2 additions & 3 deletions src/cljs/bluegenes/components/tools/effects.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,10 @@
;; In the latter case, it will merely call the tool's main function.
(reg-fx
:load-suitable-tools
(fn [{:keys [tools service entities]}]
(fn [{:keys [tools service hier entities]}]
(doseq [tool tools]
;; `entity` is nil if tool is not suitable to be displayed.
(when-let [entity (suitable-entities
(get-in service [:model :classes]) entities (:config tool))]
(when-let [entity (suitable-entities (get-in service [:model :classes]) hier entities (:config tool))]
(if-let [tool-id (get-in tool [:names :cljs])]
(do (fetch-script! tool tool-id :service service :entity entity)
(fetch-styles! tool tool-id))
Expand Down
5 changes: 4 additions & 1 deletion src/cljs/bluegenes/components/tools/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@
::load-tools
(fn [{db :db} [_]]
(let [tools (get-in db [:tools :installed])
service (get-in db [:mines (:current-mine db) :service])
mine (get-in db [:mines (:current-mine db)])
hier (get mine :model-hier)
service (get mine :service)
entities (get-in db [:tools :entities])]
(cond
;; Tools aren't ready yet.
Expand All @@ -76,4 +78,5 @@
:success? true}
:load-suitable-tools {:tools tools
:service service
:hier hier
:entities entities}}))))
5 changes: 3 additions & 2 deletions src/cljs/bluegenes/components/tools/subs.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@
:<- [::installed-tools]
:<- [::entities]
:<- [:model]
(fn [[tools entities model]]
(filter #(suitable-entities model entities (:config %)) tools)))
:<- [:current-model-hier]
(fn [[tools entities model hier]]
(filter #(suitable-entities model hier entities (:config %)) tools)))
5 changes: 3 additions & 2 deletions src/cljs/bluegenes/components/ui/constraint.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,15 @@
(defn one-of? [value col] (some? (some #{value} col)))
(def not-one-of? (complement one-of?))

(defn constraint-operator []
(defn constraint-operator
"Creates a dropdown for a query constraint.
:model The intermine model to use
:path The path of the constraint
:op The operator of the constraint
:on-change A function to call with the new operator
:lists (Optional) if provided, automatically disable list constraints
if there are no lists of that type"
[]
(fn [& {:keys [model path op on-change on-blur lists disabled value]}]
(let [path-class (im-path/class model path)
any-lists-with-class? (some? (some (fn [list] (= path-class (keyword (:type list)))) lists))
Expand Down Expand Up @@ -292,7 +293,7 @@
(create-class
{:component-did-mount (fn []
(when (nil? @pv)
(dispatch [:cache/fetch-possible-values path])))
(dispatch [:cache/fetch-possible-values path model false])))
:reagent-render (fn [& {:keys [lists model path value op code on-change
on-select-list on-change-operator on-remove
on-blur label? possible-values typeahead? hide-code?
Expand Down
11 changes: 4 additions & 7 deletions src/cljs/bluegenes/components/ui/results_preview.cljs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
(ns bluegenes.components.ui.results_preview
(:require [imcljs.path :as im-path]
[oops.core :refer [oget]]
[reagent.core :as reagent :refer [create-class]]
[bluegenes.components.loader :refer [loader]]
(:require [bluegenes.components.loader :refer [loader]]
[clojure.string :refer [split join]]))

(defn table-header []
Expand All @@ -16,9 +13,10 @@
[:td
(str (:value d))]) row))))

(defn preview-table []
(defn preview-table
"Creates a dropdown for a query constraint.
:query-results The intermine model to use"
[]
(fn [& {:keys [query-results loading? hide-count?]}]
(if loading?
[loader]
Expand All @@ -29,8 +27,7 @@
[table-header h])
(:columnHeaders query-results)))]
[:tbody
(if
(< (:iTotalRecords query-results) 1)
(if (< (:iTotalRecords query-results) 1)
[:tr
[:td {:col-span (count (:columnHeaders query-results))}
[:h4 "Query returned no results"]]]
Expand Down
6 changes: 4 additions & 2 deletions src/cljs/bluegenes/components/viz/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
:viz/run-queries
(fn [{db :db} [_]]
(let [entities (get-in db [:tools :entities])
model (get-in db [:mines (:current-mine db) :service :model :classes])]
current-mine (get-in db [:mines (:current-mine db)])
model (get-in current-mine [:service :model :classes])
hier (get current-mine :model-hier)]
{:dispatch-n (map (fn [{:keys [config query key]}]
(when-let [entity (suitable-entities model entities config)]
(when-let [entity (suitable-entities model hier entities config)]
[:viz/run-query key (query entity)]))
all-viz)})))

Expand Down
24 changes: 18 additions & 6 deletions src/cljs/bluegenes/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
[imcljs.path :as im-path]
[clojure.string :refer [join split]]
[cljs.core.async :refer [put! chan <! >! timeout close!]]
[imcljs.fetch :as fetch]
[cljs-bean.core :refer [->clj]]
[bluegenes.utils :refer [read-registry-mine]]))

Expand Down Expand Up @@ -218,17 +217,30 @@
(go
(dispatch [:cache/store-possible-values mine-kw summary-path (<! sum-chan)])))))

(defn get-active-type-constraints [db]
(->> (case (:active-panel db)
:templates-panel (get-in db [:components :template-chooser :selected-template :where])
nil)
(filterv :type)))

(reg-event-fx
:cache/fetch-possible-values
(fn [{db :db} [_ path]]
(let [mine (get-in db [:mines (get db :current-mine)])
(fn [{db :db} [_ path model ?type-constraints]]
(let [type-constraints (if (false? ?type-constraints)
(get-active-type-constraints db)
?type-constraints)
model (assoc model :type-constraints type-constraints)
mine (get-in db [:mines (get db :current-mine)])
split-path (split path ".")
existing-value (get-in db [:mines (get db :current-mine) :possible-values split-path])]

(if (and (nil? existing-value) (not (im-path/class? (get-in mine [:service :model]) path)))
(if (and (nil? existing-value) (not (im-path/class? model path)))
{:cache/fetch-possible-values-fx {:service (get mine :service)
:query {:from (first split-path)
:select [path]}
:query (merge
{:from (first split-path)
:select [path]}
(when (seq type-constraints)
{:where type-constraints}))
:mine-kw (get mine :id)
:summary-path path}}
{:dispatch [:cache/store-possible-values (get mine :id) path false]}))))
Expand Down
26 changes: 19 additions & 7 deletions src/cljs/bluegenes/events/boot.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
:token token}}
{:id :default
:name nil
:service {:root "https://alpha.flymine.org/alpha"
:service {:root "https://www.flymine.org/flymine"
:token token}})))

(defn wait-for-registry?
Expand Down Expand Up @@ -341,15 +341,27 @@
(keys (filter (comp #(contains? % preferred-tag)
set :tags second) (:classes model))))

(defn extends-hierarchy
"Subclasses in the model are specified via the extends key. We build a
first-class hierarchy type using this so we can query whether a class
is a subclass for another class."
[model-classes]
(reduce (fn [h [child {:keys [extends]}]]
(reduce #(derive %1 child %2) h (map keyword extends)))
(make-hierarchy)
model-classes))

(reg-event-db
:assets/success-fetch-model
(fn [db [_ mine-kw model]]
(let [model' (update model :classes
#(into {} (filter (comp pos? :count val) %)))]
(-> db
(assoc-in [:mines mine-kw :service :model] model')
(assoc-in [:mines mine-kw :default-object-types]
(sort (preferred-fields model')))))))
;; We used to remove empty classes (zero count) from the model here, but
;; this turned out to be a very bad idea! This is because the model is used
;; to parse paths into classes, which means it has to be complete. This also
;; applies to the model hierarchy.
(-> db
(assoc-in [:mines mine-kw :service :model] model)
(assoc-in [:mines mine-kw :default-object-types] (sort (preferred-fields model)))
(assoc-in [:mines mine-kw :model-hier] (extends-hierarchy (:classes model))))))

(reg-event-fx
:assets/fetch-model
Expand Down
Loading

0 comments on commit ce37972

Please sign in to comment.