(ns metabase.channel.render.table (:require [clojure.string :as str] [hiccup.core :refer [h]] [medley.core :as m] [metabase.channel.render.js.color :as js.color] [metabase.channel.render.style :as style] [metabase.formatter]) (:import (metabase.formatter NumericWrapper))) | |
(comment metabase.formatter/keep-me) | |
(defn- bar-th-style []
(merge
(style/font-style)
{:font-size :12px
:font-weight 700
:color style/color-text-dark
:border-bottom (str "2px solid " style/color-border)
:border-right 0})) | |
(def ^:private max-bar-width 106) | |
(defn- bar-td-style []
(merge
(style/font-style)
{:font-size :12px
:font-weight 400
:text-align :left
:color style/color-text-dark
:border-bottom (str "1px solid " style/color-border)
:border-right (str "1px solid " style/color-border)
:padding "0.75em 1em"})) | |
(defn- bar-th-style-numeric []
(merge (style/font-style) (bar-th-style) {:text-align :right})) | |
(defn- bar-td-style-numeric []
(merge (style/font-style) (bar-td-style) {:text-align :right})) | |
(defn- render-bar-component
([color positive? width-in-pixels]
(render-bar-component color positive? width-in-pixels 0))
([color positive? width-in-pixels _offset]
[:div
{:style (style/style
(merge
{:width (format "%spx" width-in-pixels)
:background-color color
:max-height :10px
:height :10px
:margin-top :3px}
(if positive?
{:border-radius "0px 2px 2px 0px"}
{:border-radius "2px 0px 0px 2px"
;; `float: right` would be nice instead of the `margin-left` hack, but CSSBox puts in an erroneous 2px gap with it
:margin-left (format "%spx" (- max-bar-width width-in-pixels))})))}
" "])) | |
(defn- heading-style-for-type
[cell]
(if (instance? NumericWrapper cell)
(bar-th-style-numeric)
(bar-th-style))) | |
(defn- row-style-for-type
[cell]
(if (instance? NumericWrapper cell)
(bar-td-style-numeric)
(bar-td-style))) | |
(defn- normalized-score->pixels [score] (int (* (/ score 100.0) max-bar-width))) | |
(def ^:private max-column-character-length 16) | |
(defn- truncate-text [text]
(if (> (count text) max-column-character-length)
(str (str/trim (subs text 0 max-column-character-length)) "...")
text)) | |
(defn- render-table-head [column-names {:keys [bar-width row]}]
[:thead
(conj (into [:tr]
(map-indexed
(fn [idx header-cell]
(let [title (get column-names idx)]
[:th {:style (style/style
(row-style-for-type header-cell)
(heading-style-for-type header-cell)
{:min-width :42px})
:title title}
(truncate-text (h title))]))
row))
(when bar-width
[:th {:style (style/style (bar-td-style) (bar-th-style) {:width (str bar-width "%")})}]))]) | |
(defn- render-bar
[bar-width normalized-zero]
(if (< bar-width normalized-zero)
(list
[:td {:style (style/style (bar-td-style) {:width :99%, :border-right "1px solid black", :padding-right 0})}
(render-bar-component (style/secondary-color)
false
(normalized-score->pixels (- normalized-zero bar-width))
(normalized-score->pixels bar-width))]
[:td {:style (style/style (bar-td-style) {:width :99%})}])
(list
(when-not (zero? normalized-zero)
[:td {:style (style/style (bar-td-style) {:width :99%, :border-right "1px solid black"})}])
[:td {:style (style/style (bar-td-style) {:width :99%, :padding-left 0})}
(render-bar-component (style/primary-color)
true
(normalized-score->pixels (- bar-width normalized-zero)))]))) | |
Render Hiccup
(get-background-color cell-value column-name row-index) | (defn- render-table-body
[get-background-color normalized-zero column-names rows]
[:tbody
(for [[row-idx {:keys [row bar-width]}] (m/indexed rows)]
[:tr {:style (style/style {:color style/color-gray-3})}
(for [[col-idx cell] (m/indexed row)]
[:td {:style (style/style
(row-style-for-type cell)
{:background-color (get-background-color cell (get column-names col-idx) row-idx)}
(when (and bar-width (= col-idx 1))
{:font-weight 700})
(when (= row-idx (dec (count rows)))
{:border-bottom 0})
(when (= col-idx (dec (count row)))
{:border-right 0}))}
(h cell)])
(some-> bar-width (render-bar normalized-zero))])]) |
This function returns the HTML data structure for the pulse table.
| (defn render-table
([color-selector column-names-map contents]
(render-table color-selector 0 column-names-map contents))
([color-selector normalized-zero {:keys [col-names cols-for-color-lookup]} [header & rows]]
(let [pivot-grouping-idx (get (zipmap col-names (range)) "pivot-grouping")
col-names (cond->> col-names
pivot-grouping-idx (m/remove-nth pivot-grouping-idx))
header (cond-> header
pivot-grouping-idx (update :row #(m/remove-nth pivot-grouping-idx %)))
rows (cond->> rows
pivot-grouping-idx (keep (fn [row]
(let [group (:num-value (nth (:row row) pivot-grouping-idx))]
(when (= 0 group)
(update row :row #(m/remove-nth pivot-grouping-idx %)))))))]
[:table {:style (style/style {:max-width "100%"
:white-space :nowrap
:border (str "1px solid " style/color-border)
:border-radius :6px
:width "1%"})
:cellpadding "0"
:cellspacing "0"}
(render-table-head (vec col-names) header)
(render-table-body (partial js.color/get-background-color color-selector) normalized-zero cols-for-color-lookup rows)]))) |