diff --git a/frontend/src/metabase/reference/databases/FieldSidebar.jsx b/frontend/src/metabase/reference/databases/FieldSidebar.jsx index 6ebc3d009e83c25e1d16eca863d83be5578c7c0a..27709b6000e58036681a8a642d5e95a21c000d05 100644 --- a/frontend/src/metabase/reference/databases/FieldSidebar.jsx +++ b/frontend/src/metabase/reference/databases/FieldSidebar.jsx @@ -46,12 +46,12 @@ const FieldSidebar = ({ /> { - // <SidebarItem - // key={`/auto/dashboard/field/${field.id}`} - // href={`/auto/dashboard/field/${field.id}`} - // icon='bolt' - // name={t`Generate a dashboard based on this field`} - // /> + <SidebarItem + key={`/auto/dashboard/field/${field.id}`} + href={`/auto/dashboard/field/${field.id}`} + icon="bolt" + name={t`Generate a dashboard based on this field`} + /> } {showXray && ( diff --git a/resources/automagic_dashboards/special/field.yaml b/resources/automagic_dashboards/special/field.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2e5c8f19ce788705e4d4fe3336aca990045ce183 --- /dev/null +++ b/resources/automagic_dashboards/special/field.yaml @@ -0,0 +1,47 @@ +title: Analysis of [[this]] +table_type: GenericTable +metrics: +- Sum: [sum, [dimension, GenericNumber]] +- Avg: [avg, [dimension, GenericNumber]] +- Count: [count] +dimensions: + - Field: + field_type: "*" + score: 0 + - GenericNumber: GenericTable.Number +# bind just so they don't get used + - LongLat: GenericTable.Coordinate + - ZipCode: GenericTable.ZipCode +# only used for filters + - Country: + field_type: GenericTable.Country + - State: + field_type: GenericTable.State + - GenericCategoryMedium: + field_type: GenericTable.Category + max_cardinality: 12 + score: 90 + - Timestamp: + field_type: CreationTimestamp + score: 100 + - Timestamp: + field_type: DateTime + score: 90 +dashboard_filters: + - Timestamp + - State + - Country + - GenericCategoryMedium +cards: + - Distribution: + title: Distribution of [[Field]] + visualization: bar + metrics: Count + dimensions: Field + - ByNumber: + title: "[[GenericNumber]] by [[Field]]" + visualization: line + metrics: + - Sum + - Avg + dimensions: Field \ No newline at end of file diff --git a/src/metabase/api/automagic_dashboards.clj b/src/metabase/api/automagic_dashboards.clj index 21c3491bb842241e9c59a990c5bad4f66ee4b829..8d0ec3934f5ce96e429aeeef61b8981ef6f5f01a 100644 --- a/src/metabase/api/automagic_dashboards.clj +++ b/src/metabase/api/automagic_dashboards.clj @@ -82,10 +82,10 @@ [id] (-> id Metric api/check-404 magic/automagic-analysis)) -;; (api/defendpoint GET "/field/:id" -;; "Return an automagic dashboard analyzing field with id `id`." -;; [id] -;; (-> id Field api/check-404 :table_id Table magic/automagic-dashboard)) +(api/defendpoint GET "/field/:id" + "Return an automagic dashboard analyzing field with id `id`." + [id] + (-> id Field api/check-404 magic/automagic-analysis)) (api/defendpoint GET "/question/:id" "Return an automagic dashboard analyzing question with id `id`." diff --git a/src/metabase/automagic_dashboards/core.clj b/src/metabase/automagic_dashboards/core.clj index 799fd1cd912901e68688c0f6a712a84bc97b55a0..ad35b9e45a601ce5624df6702dd4917431788d88 100644 --- a/src/metabase/automagic_dashboards/core.clj +++ b/src/metabase/automagic_dashboards/core.clj @@ -234,10 +234,9 @@ `links_to`, ...) are used; 3) if there is still a tie, `score`." (comp last (partial sort-by (comp (fn [[_ definition]] - [(->> definition - :field_type - (map (comp count ancestors)) - (reduce + )) + [(transduce (map (comp count ancestors)) + + + (:field_type definition)) (count definition) (:score definition)]) first)))) @@ -245,8 +244,8 @@ (defn- bind-dimensions "Bind fields to dimensions and resolve overloading. Each field x aggregation pair will be bound to only one dimension. If multiple - dimension definitions match a single field, the field is bound to the specific - definition is used (see `most-specific-defintion` for details)." + dimension definitions match a single field, the field is bound to the most + specific definition used (see `most-specific-defintion` for details)." [context dimensions] (->> dimensions (mapcat (comp (partial make-binding context) first)) @@ -540,7 +539,7 @@ (remove (comp #{root} :table)) (take (- max-related (count indepth)))) :indepth indepth}))) - (log/info (format "Skipping %s: no cards fully match the topology." + (log/info (format "Skipping %s: no cards fully match bound dimensions." (full-name root)))))) (def ^:private ^{:arglists '([card])} table-like? @@ -573,4 +572,15 @@ (defmethod automagic-analysis (type Field) [field] - nil) + (-> "special/field.yaml" + rules/load-rule + (update :dimensions conj + {"Field" + {:field_type [(-> field table :entity_type) + ((some-fn :special_type :base_type) field)] + :named (:name field) + :score 100 + :aggregation (cond + (isa? (:base_type field) :type/DateTime) :month + (isa? (:base_type field) :type/Number) :default)}}) + (automagic-dashboard field))) diff --git a/src/metabase/automagic_dashboards/filters.clj b/src/metabase/automagic_dashboards/filters.clj index 52aadf565c1c1d8651f8a2927fa93248e73123bc..d4e88216339931b82512064211fbb08701dfe671 100644 --- a/src/metabase/automagic_dashboards/filters.clj +++ b/src/metabase/automagic_dashboards/filters.clj @@ -33,10 +33,11 @@ (defn- build-fk-map [tables field] - (->> (db/select [Field :id :fk_target_field_id :table_id] + (->> (db/select Field :fk_target_field_id [:not= nil] :table_id [:in tables]) - (filter (comp #{(:table_id field)} :table_id Field :fk_target_field_id)) + field/with-targets + (filter (comp #{(:table_id field)} :table_id :target)) (group-by :table_id) (keep (fn [[_ [fk & fks]]] ;; Bail out if there is more than one FK from the same table @@ -51,17 +52,16 @@ (defn- add-filter [dashcard filter-id field] - (if-let [targets (->> (conj (:series dashcard) (:card dashcard)) - (keep (fn [card] - (some-> card - (filter-for-card field) - (vector card)))) - not-empty)] - (update dashcard :parameter_mappings concat (for [[target card] targets] - {:parameter_id filter-id - :target target - :card_id (:id card)})) - dashcard)) + (let [mappings (->> (conj (:series dashcard) (:card dashcard)) + (keep (fn [card] + (when-let [target (filter-for-card card field)] + {:parameter_id filter-id + :target target + :card_id (:id card)}))) + not-empty)] + (cond + (nil? (:card dashcard)) dashcard + mappings (update dashcard :parameter_mappings concat mappings)))) (defn- filter-type [{:keys [base_type special_type] :as field}] @@ -89,11 +89,13 @@ (let [filter-id (-> candidate hash str) dashcards (:ordered_cards dashboard) dashcards-new (map #(add-filter % filter-id candidate) dashcards)] - (cond-> dashboard - (not= dashcards dashcards-new) - (-> (assoc :ordered_cards dashcards-new) + ;; Only add filters that apply to all cards. + (if (= (count dashcards) (count dashcards-new)) + (-> dashboard + (assoc :ordered_cards dashcards-new) (update :parameters conj {:id filter-id :type (filter-type candidate) :name (:display_name candidate) - :slug (:name candidate)}))))) + :slug (:name candidate)})) + dashboard))) dashboard)))) diff --git a/test/metabase/automagic_dashboards/core_test.clj b/test/metabase/automagic_dashboards/core_test.clj index d3eb52803e20cf0211df397b514edcc0fc00a3a2..04c48e7f3f2481c55f163e724bff17438aa70eab 100644 --- a/test/metabase/automagic_dashboards/core_test.clj +++ b/test/metabase/automagic_dashboards/core_test.clj @@ -52,14 +52,6 @@ (-> (keep automagic-dashboard (Table)) count pos?)))) -;; Identity -(expect - :d1 - (-> [{:d1 {:field_type [:type/Category] :score 100}}] - (#'magic/most-specific-definition) - first - key)) - ;; Identity (expect :d1