Compare commits
92 Commits
mblib-exp-
...
attach-ren
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff11bd7f79 | ||
|
|
32011873b1 | ||
|
|
d19ad598b2 | ||
|
|
fa90376b08 | ||
|
|
2c3c328472 | ||
|
|
81621016d4 | ||
|
|
d67f3f5d99 | ||
|
|
03d5dec982 | ||
|
|
72443c62b1 | ||
|
|
2c1333ebb6 | ||
|
|
68435f9091 | ||
|
|
d5280c6bcf | ||
|
|
7038b2e4c2 | ||
|
|
3d0bc85a5b | ||
|
|
a3f19cd8c5 | ||
|
|
70c1474c87 | ||
|
|
6b59534f39 | ||
|
|
e5aa995590 | ||
|
|
557e6ead6a | ||
|
|
d711251a70 | ||
|
|
55c00bdd90 | ||
|
|
1947328ed9 | ||
|
|
78db8c4916 | ||
|
|
c1f1d98381 | ||
|
|
ead905b105 | ||
|
|
86b8825996 | ||
|
|
af6cecb863 | ||
|
|
9378e28ed4 | ||
|
|
c3c65abdf0 | ||
|
|
862ca7ea27 | ||
|
|
780532543c | ||
|
|
3b6def1eb7 | ||
|
|
54c8f9bac4 | ||
|
|
d6381501e9 | ||
|
|
ea7bd55939 | ||
|
|
0e8d4f8acf | ||
|
|
badf8b957b | ||
|
|
67ae7aded0 | ||
|
|
2bd4c9b59a | ||
|
|
42b6edb8c4 | ||
|
|
642a704e66 | ||
|
|
246f9b55ac | ||
|
|
f83080071b | ||
|
|
f143179759 | ||
|
|
378f0de215 | ||
|
|
e53aeff946 | ||
|
|
a39055459c | ||
|
|
52d5ccfaff | ||
|
|
6f2535e8d5 | ||
|
|
3b2736c22e | ||
|
|
63ecb0a303 | ||
|
|
b1eca0f9b7 | ||
|
|
a4add27807 | ||
|
|
beba8d5c01 | ||
|
|
b62726d36d | ||
|
|
1610201fba | ||
|
|
0975be548c | ||
|
|
24ec71c88e | ||
|
|
b77443a410 | ||
|
|
f134831a71 | ||
|
|
520c7dc94f | ||
|
|
7463c67887 | ||
|
|
85b053b77f | ||
|
|
b55e141fe8 | ||
|
|
7737d3c857 | ||
|
|
127d2626e5 | ||
|
|
07dae0a6b6 | ||
|
|
bee66b406b | ||
|
|
f811b08b6d | ||
|
|
84952a7f2b | ||
|
|
a672996a96 | ||
|
|
4c2d2400f9 | ||
|
|
d0314b2e9c | ||
|
|
96b357a625 | ||
|
|
10fee384b2 | ||
|
|
8cfca2c6ef | ||
|
|
cb828242f3 | ||
|
|
39c81419e8 | ||
|
|
0d95540349 | ||
|
|
f3a26b5135 | ||
|
|
a5c33e1756 | ||
|
|
b89f86c568 | ||
|
|
e108633f36 | ||
|
|
a54ef9bc99 | ||
|
|
9705d8976f | ||
|
|
a222ac98c0 | ||
|
|
520b1f6320 | ||
|
|
4a9d63ebc7 | ||
|
|
e16bfa4a76 | ||
|
|
d0148baa24 | ||
|
|
3e5d3985d8 | ||
|
|
6a61796277 |
@@ -1,5 +1,5 @@
|
||||
;; -*- comment-column: 100; -*-
|
||||
{:config-paths ["macros"]
|
||||
{:config-paths ["macros" "src"]
|
||||
:linters
|
||||
{:aliased-namespace-symbol {:level :warning}
|
||||
:invalid-arity {:skip-args [metabase.lib.util.match/match]} ; TODO (cam): can we fix these?
|
||||
@@ -193,6 +193,7 @@
|
||||
metabase.public-settings #{metabase.public-settings
|
||||
metabase.public-settings.premium-features}
|
||||
metabase.pulse #{metabase.pulse
|
||||
metabase.pulse.attachment
|
||||
metabase.pulse.markdown
|
||||
metabase.pulse.parameters
|
||||
metabase.pulse.preview
|
||||
@@ -428,10 +429,6 @@
|
||||
metabase.driver.druid.js druid.js
|
||||
metabase.driver.druid.query-processor druid.qp
|
||||
metabase.driver.druid.sync druid.sync
|
||||
metabase.driver.googleanalytics.client ga.client
|
||||
metabase.driver.googleanalytics.execute ga.execute
|
||||
metabase.driver.googleanalytics.metadata ga.metadata
|
||||
metabase.driver.googleanalytics.query-processor ga.qp
|
||||
metabase.driver.impl driver.impl
|
||||
metabase.driver.mongo.execute mongo.execute
|
||||
metabase.driver.mongo.parameters mongo.params
|
||||
@@ -687,6 +684,9 @@
|
||||
metabase.api.card-test/with-temp-native-card! hooks.common/with-two-bindings
|
||||
metabase.api.card-test/with-temp-native-card-with-params! hooks.common/with-two-bindings
|
||||
metabase.api.collection-test/with-french-user-and-personal-collection hooks.common/with-two-top-level-bindings
|
||||
metabase.api.common/defendpoint hooks.metabase.api.common/defendpoint
|
||||
metabase.api.common/defendpoint-async hooks.metabase.api.common/defendpoint
|
||||
metabase.api.common/defendpoint-async-schema hooks.metabase.api.common/defendpoint
|
||||
metabase.api.dashboard-test/with-chain-filter-fixtures hooks.common/let-one-with-optional-value
|
||||
metabase.api.dashboard-test/with-simple-dashboard-with-tabs hooks.common/with-one-binding
|
||||
metabase.api.card-test/with-card-param-values-fixtures hooks.common/let-one-with-optional-value
|
||||
@@ -785,9 +785,6 @@
|
||||
metabase.api.card-test/with-ordered-items macros.metabase.api.card-test/with-ordered-items
|
||||
metabase.api.collection-test/with-collection-hierarchy macros.metabase.api.collection-test/with-collection-hierarchy
|
||||
metabase.api.collection-test/with-some-children-of-collection macros.metabase.api.collection-test/with-some-children-of-collection
|
||||
metabase.api.common/defendpoint macros.metabase.api.common/defendpoint
|
||||
metabase.api.common/defendpoint-async macros.metabase.api.common/defendpoint
|
||||
metabase.api.common/defendpoint-async-schema macros.metabase.api.common/defendpoint
|
||||
metabase.api.common/define-routes macros.metabase.api.common/define-routes
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing macros.metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing macros.metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing
|
||||
|
||||
@@ -1,26 +1,7 @@
|
||||
(ns macros.metabase.api.common
|
||||
(:require
|
||||
[clojure.string :as str]))
|
||||
(ns macros.metabase.api.common)
|
||||
|
||||
(defmacro define-routes
|
||||
"Macro for api.common/define-routes"
|
||||
[& args]
|
||||
`(do (def ~'routes "docstring" nil)
|
||||
~@args))
|
||||
|
||||
(defn route-fn-name
|
||||
"route fn hook"
|
||||
[method route]
|
||||
(let [route (if (vector? route) (first route) route)]
|
||||
(-> (str (name method) route)
|
||||
(str/replace #"/" "_")
|
||||
symbol)))
|
||||
|
||||
(defmacro defendpoint
|
||||
"Macro for api.common/defendpoint*"
|
||||
[method route & body]
|
||||
(let [method-fn (symbol "compojure.core" (str method))
|
||||
route-name (route-fn-name method route)]
|
||||
`(do
|
||||
~method-fn
|
||||
(defn ~route-name ~@body))))
|
||||
|
||||
@@ -376,8 +376,15 @@
|
||||
(when (hooks/token-node? node)
|
||||
(let [sexpr (hooks/sexpr node)]
|
||||
(when (symbol? sexpr)
|
||||
(when-let [resolved (hooks/resolve {:name sexpr})]
|
||||
(symbol (name (:ns resolved)) (name (:name resolved)))))))
|
||||
(let [resolved (hooks/resolve {:name sexpr})]
|
||||
(cond
|
||||
(and resolved (:ns resolved))
|
||||
(symbol (name (:ns resolved)) (name (:name resolved)))
|
||||
|
||||
;; if it wasn't resolved but is still qualified it's probably using the full namespace name rather than an
|
||||
;; alias.
|
||||
(qualified-symbol? sexpr)
|
||||
sexpr)))))
|
||||
;; some symbols like `*count/Integer` aren't resolvable.
|
||||
(catch Exception _
|
||||
nil)))
|
||||
45
.clj-kondo/src/hooks/metabase/api/common.clj
Normal file
@@ -0,0 +1,45 @@
|
||||
(ns hooks.metabase.api.common
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn route-fn-name
|
||||
"route fn hook"
|
||||
[method route]
|
||||
(let [route (if (vector? route) (first route) route)]
|
||||
(-> (str (name method) route)
|
||||
(str/replace #"/" "_")
|
||||
symbol)))
|
||||
|
||||
(defn defendpoint
|
||||
[arg]
|
||||
(letfn [(update-defendpoint [node]
|
||||
(let [[_defendpoint method route & body] (:children node)]
|
||||
(api/list-node
|
||||
(list
|
||||
(api/token-node 'do)
|
||||
(api/token-node (symbol "compojure.core" (str (api/sexpr method))))
|
||||
(-> (api/list-node
|
||||
(list*
|
||||
(api/token-node 'clojure.core/defn)
|
||||
(api/token-node (route-fn-name (api/sexpr method) (api/sexpr route)))
|
||||
body))
|
||||
(with-meta (meta node)))))))]
|
||||
(update arg :node update-defendpoint)))
|
||||
|
||||
(comment
|
||||
(-> {:node (-> '(api/defendpoint POST "/:id/copy"
|
||||
"Copy a `Card`, with the new name 'Copy of _name_'"
|
||||
[id]
|
||||
{id [:maybe ms/PositiveInt]}
|
||||
(let [orig-card (api/read-check Card id)
|
||||
new-name (str (trs "Copy of ") (:name orig-card))
|
||||
new-card (assoc orig-card :name new-name)]
|
||||
(-> (card/create-card! new-card @api/*current-user*)
|
||||
hydrate-card-details
|
||||
(assoc :last-edit-info (last-edit/edit-information-for-user @api/*current-user*)))))
|
||||
pr-str
|
||||
api/parse-string)}
|
||||
defendpoint
|
||||
:node
|
||||
api/sexpr))
|
||||
@@ -124,40 +124,3 @@
|
||||
(check-for-i18n-format-specifiers node format-string)
|
||||
(check-format-string-arg-count node format-string args)))
|
||||
x)
|
||||
|
||||
(comment
|
||||
;; should fail, missing a format arg
|
||||
(infof
|
||||
{:node (api/parse-string
|
||||
(str '(log/warnf "Migration lock was acquired after %d retries.")))})
|
||||
|
||||
(infof
|
||||
{:node (api/parse-string
|
||||
(str '(log/warnf e "Migration lock was acquired after %d retries.")))})
|
||||
|
||||
;; should fail, too many format args
|
||||
(infof
|
||||
{:node (api/parse-string
|
||||
(str '(log/warnf "Migration lock was acquired after %d retries." 1 2)))})
|
||||
|
||||
(infof
|
||||
{:node (api/parse-string
|
||||
(str '(log/warnf e "Migration lock was acquired after %d retries." 1 2)))})
|
||||
|
||||
(infof
|
||||
{:node (api/parse-string
|
||||
(str '(log/warnf "Migration lock was acquired after {0} retries." 1)))})
|
||||
|
||||
;; should fail, has format args but is warn rather than warnf
|
||||
(info
|
||||
{:node (api/parse-string
|
||||
(str '(log/warn e "Migration lock was acquired after %d retries." 1 2)))})
|
||||
|
||||
;; should fail -- should not use i18n/tru or i18n/trs
|
||||
(infof
|
||||
{:node (api/parse-string
|
||||
(str '(log/warnf (metabase.util.i18n/tru "Migration lock was acquired after {0} retries." 1))))})
|
||||
|
||||
(info
|
||||
{:node (api/parse-string
|
||||
(str '(log/warn (metabase.util.i18n/trs "Migration lock was acquired after {0} retries." 1))))}))
|
||||
19
.clj-kondo/test/hooks/common_test.clj
Normal file
@@ -0,0 +1,19 @@
|
||||
(ns ^:mb/once hooks.common-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]
|
||||
[clj-kondo.impl.utils]
|
||||
[clojure.test :refer :all]
|
||||
[hooks.common]))
|
||||
|
||||
(deftest ^:parallel node->qualified-symbol-test
|
||||
(binding [clj-kondo.impl.utils/*ctx* {:namespaces (atom nil)}]
|
||||
(is (= 'metabase.util.i18n/tru
|
||||
(hooks.common/node->qualified-symbol (api/parse-string "metabase.util.i18n/tru"))))))
|
||||
|
||||
(deftest ^:parallel node->qualified-symbol-test-2
|
||||
(binding [clj-kondo.impl.utils/*ctx* {:namespaces (atom {:clj {:clj '{hooks.common-test {:qualify-ns {i18n metabase.util.i18n}}}}})
|
||||
:lang :clj
|
||||
:base-lang :clj
|
||||
:ns {:name 'hooks.common-test}}]
|
||||
(is (= 'metabase.util.i18n/tru
|
||||
(hooks.common/node->qualified-symbol (api/parse-string "i18n/tru"))))))
|
||||
77
.clj-kondo/test/hooks/metabase/util/log_test.clj
Normal file
@@ -0,0 +1,77 @@
|
||||
(ns ^:mb/once hooks.metabase.util.log-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]
|
||||
[clj-kondo.impl.utils]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :refer :all]
|
||||
[hooks.metabase.util.log]))
|
||||
|
||||
(defn- warnings
|
||||
[form]
|
||||
(let [f (if (str/ends-with? (name (first form)) "f")
|
||||
hooks.metabase.util.log/infof
|
||||
hooks.metabase.util.log/info)]
|
||||
(binding [clj-kondo.impl.utils/*ctx* {:config {:linters {:metabase/validate-logging {:level :warning}}}
|
||||
:ignores (atom nil)
|
||||
:findings (atom [])
|
||||
:namespaces (atom {})}]
|
||||
(f {:node (api/parse-string (pr-str form))})
|
||||
(mapv :message @(:findings clj-kondo.impl.utils/*ctx*)))))
|
||||
|
||||
(deftest ^:parallel warn-on-missing-format-args-test
|
||||
(testing "should fail, missing a format arg"
|
||||
(are [form] (= ["log format string expects 1 arguments instead of 0."]
|
||||
(warnings (quote form)))
|
||||
(metabase.util.log/warnf "Migration lock was acquired after %d retries.")
|
||||
(metabase.util.log/warnf e "Migration lock was acquired after %d retries."))))
|
||||
|
||||
(deftest ^:parallel warn-on-too-many-format-args-test-1
|
||||
(testing "should fail, too many format args"
|
||||
(are [form] (= ["log format string expects 1 arguments instead of 2."]
|
||||
(warnings (quote form)))
|
||||
(metabase.util.log/warnf "Migration lock was acquired after %d retries." 1 2)
|
||||
(metabase.util.log/warnf e "Migration lock was acquired after %d retries." 1 2))))
|
||||
|
||||
(deftest ^:parallel warn-on-too-many-format-args-test-2
|
||||
(testing "should fail, too many format args"
|
||||
(are [form] (= ["this looks like an i18n format string. Don't use identifiers like {0} in logging."
|
||||
"Don't use metabase.util.log/warnf with no format string arguments, use metabase.util.log/warn instead."
|
||||
"log format string expects 0 arguments instead of 1."]
|
||||
(warnings (quote form)))
|
||||
(metabase.util.log/warnf "Migration lock was acquired after {0} retries." 1)
|
||||
(metabase.util.log/warnf e "Migration lock was acquired after {0} retries." 1))))
|
||||
|
||||
(deftest ^:parallel warn-on-format-args-without-logf-test
|
||||
(testing "should fail, has format args but is warn rather than warnf"
|
||||
(are [form] (= ["metabase.util.log/warn used with a format string, use metabase.util.log/warnf instead."]
|
||||
(warnings (quote form)))
|
||||
(metabase.util.log/warn "Migration lock was acquired after %d retries." 1)
|
||||
(metabase.util.log/warn e "Migration lock was acquired after %d retries." 1))))
|
||||
|
||||
(deftest ^:parallel warn-on-format-without-logf-test
|
||||
(testing "should fail, has format args but is warn rather than warnf"
|
||||
(are [form] (= ["Use metabase.util.log/warnf instead of metabase.util.log/warn + format"]
|
||||
(warnings (quote form)))
|
||||
(metabase.util.log/warn (format "Migration lock was acquired after %d retries." 1))
|
||||
(metabase.util.log/warn e (format "Migration lock was acquired after %d retries." 1)))))
|
||||
|
||||
(deftest ^:parallel warn-on-logf-with-no-format-args-test
|
||||
(testing "should fail, has format args but is warn rather than warnf"
|
||||
(are [form] (= ["Don't use metabase.util.log/warnf with no format string arguments, use metabase.util.log/warn instead."]
|
||||
(warnings (quote form)))
|
||||
(metabase.util.log/warnf "Migration lock cleared.")
|
||||
(metabase.util.log/warnf e "Migration lock cleared."))))
|
||||
|
||||
(deftest ^:parallel warn-on-i18n-test-1
|
||||
(testing "should fail -- should not use i18n/tru or i18n/trs"
|
||||
(are [form] (= ["do not i18n the logs!"]
|
||||
(warnings (quote form)))
|
||||
(metabase.util.log/warnf (metabase.util.i18n/tru "Migration lock was acquired after {0} retries." 1))
|
||||
(metabase.util.log/warnf e (metabase.util.i18n/tru "Migration lock was acquired after {0} retries." 1)))))
|
||||
|
||||
(deftest ^:parallel warn-on-i18n-test-2
|
||||
(testing "should fail -- should not use i18n/tru or i18n/trs"
|
||||
(are [form] (= ["do not i18n the logs!"]
|
||||
(warnings (quote form)))
|
||||
(metabase.util.log/warn (metabase.util.i18n/trs "Migration lock was acquired after {0} retries." 1))
|
||||
(metabase.util.log/warn e (metabase.util.i18n/trs "Migration lock was acquired after {0} retries." 1)))))
|
||||
2
.github/actions/build-e2e-matrix/action.yml
vendored
@@ -36,6 +36,7 @@ runs:
|
||||
["dashboard-filters", {} ],
|
||||
["embedding", {} ],
|
||||
["filters", {} ],
|
||||
["filters-reproductions", {}],
|
||||
["joins", {} ],
|
||||
["metrics", {} ],
|
||||
["models", {} ],
|
||||
@@ -45,6 +46,7 @@ runs:
|
||||
["organization", {} ],
|
||||
["permissions", {} ],
|
||||
["question", {} ],
|
||||
["question-reproductions", {} ],
|
||||
["search", {}],
|
||||
["sharing", {} ],
|
||||
["visualizations-charts", {} ],
|
||||
|
||||
2
.github/actions/prepare-frontend/action.yml
vendored
@@ -23,6 +23,6 @@ runs:
|
||||
if: ${{ !contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock', '**/patches/*.patch') }}
|
||||
- run: yarn install --frozen-lockfile --prefer-offline
|
||||
shell: bash
|
||||
|
||||
86
.github/github-slack-map.json
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"abdhabli": "U06BAV8JFDW",
|
||||
"adam-james-v": "U02P27ZRRR8",
|
||||
"agodbey": "U05UJR2C35Z",
|
||||
"albertoperdomo": "U05811B1WLX",
|
||||
"AlessioLaiso": "U06MAAUDTS6",
|
||||
"alexandermkinn": "U023UTA4MUL",
|
||||
"alexyarosh": "U06GXH3RVPU",
|
||||
"alxnddr": "U01S9BUHH8X",
|
||||
"brunobergher": "U01M2JJVA80",
|
||||
"bshepherdson": "U03AK3B43GA",
|
||||
"calherries": "U03KFGJ7X8S",
|
||||
"camsaul": "U07DG6C3X",
|
||||
"cbalusek": "U02M2Q0DJLD",
|
||||
"cdeweyx": "U02BX2BKPQS",
|
||||
"crisptrutski": "U06C5MNFF0S",
|
||||
"dahyeik": "U03MG3BCS22",
|
||||
"darksciencebase": "U04P2DVHG3U",
|
||||
"deniskaber": "U04QX6Z5N00",
|
||||
"devurandom": "U03N1ATKF7T",
|
||||
"dhuniverse": "U04RRCGJPJN",
|
||||
"dpsutton": "U01BP8Z3CVA",
|
||||
"EmmadUsmani": "U04QX6YUP7A",
|
||||
"escherize": "U02U4E60EHG",
|
||||
"filipesilva": "U04S45X3FLN",
|
||||
"FilmonK": "U05J39TB4A1",
|
||||
"gusaiani": "U020JGYQHK8",
|
||||
"heypoom": "U06TVDSUPGE",
|
||||
"iethree": "U5A85JL4V",
|
||||
"ignacio-mb": "U0558P1CZ5L",
|
||||
"imrkd": "U02MJBX8G65",
|
||||
"ixipixi": "U06C5JCNKM1",
|
||||
"jeff-bruemmer": "U014JGU9XK2",
|
||||
"JesseSDevaney": "U0511SK58DC",
|
||||
"jessillions": "U04P2AKMX4K",
|
||||
"jesusfloresmetabase": "U04MZ6TGQLA",
|
||||
"jill-lafond": "U0537V0L2DN",
|
||||
"johnswanson": "U0600BZ1XMK",
|
||||
"jrayski": "U03C28SM11N",
|
||||
"k8beeman": "U06PYT3N7EV",
|
||||
"kamilmielnik": "U057ENEC60M",
|
||||
"kdoh": "U078VJFED",
|
||||
"kidd": "U01JM8WM6N4",
|
||||
"kulyk": "U01TH98M6J2",
|
||||
"lbrdnk": "U06035L3V34",
|
||||
"le0li0n": "U06RDA3M6BZ",
|
||||
"likeshumidity": "U047NDX34UU",
|
||||
"losrebellos": "U022B12KVK6",
|
||||
"luizarakaki": "U02KWASDKHC",
|
||||
"margaretrimek": "U02AZVBQQU9",
|
||||
"maxzheng": "U03TBN466EN",
|
||||
"mazameli": "U0ALDAVHA",
|
||||
"metamben": "U03AN4TRM6Y",
|
||||
"mngr": "U06GXDTJQQ3",
|
||||
"mwsmales": "U043FSUUSNL",
|
||||
"nemanjaglumac": "U01BA9754AC",
|
||||
"NevRA": "U04T9044T7G",
|
||||
"ngapuileung": "U04HP1D66N4",
|
||||
"noahmoss": "U01V8S8DG78",
|
||||
"npfitz": "U037YBQFRR7",
|
||||
"npretto": "U05K43X7RV5",
|
||||
"oisincoveney": "U0511SKLXCN",
|
||||
"Onlinehead": "U02S8HGAB8A",
|
||||
"oreonl": "U05V7TSK1QQ",
|
||||
"paoliniluis": "U01GWGPG2CF",
|
||||
"perivamsi": "U05K2EFAT5G",
|
||||
"piranha": "U060FQBFE5P",
|
||||
"psalinasy": "U04LYLXV207",
|
||||
"qnkhuat": "U02LA6FF5N1",
|
||||
"rafpaf": "U0697CU8TTP",
|
||||
"ranquild": "U028HG073GS",
|
||||
"romeovs": "U06DHN2JA5D",
|
||||
"salsakran": "U078V228G",
|
||||
"sloansparger": "U06CJAUPV3K",
|
||||
"snoe": "U03AG715B61",
|
||||
"Somtom": "U06BREDB5V3",
|
||||
"taqattack": "U06C70CJ6RM",
|
||||
"Tony-metabase": "U03RFTD5SLR",
|
||||
"trinya": "U06CJJB3JJZ",
|
||||
"tsmacdonald": "U01BKUL0MHV",
|
||||
"uladzimirdev": "U04TU6TNPLZ",
|
||||
"vbenedetti": "U04MRS3JTLH",
|
||||
"victoriaspek": "U02KD3E703E",
|
||||
"WiNloSt": "U02MYNXD605",
|
||||
"zbodi74": "U05EV72TPN2"
|
||||
}
|
||||
2
.github/team.json
vendored
@@ -32,7 +32,7 @@
|
||||
{
|
||||
"name": "Query Processor",
|
||||
"label": ".Team/QueryProcessor",
|
||||
"projectUrl": "https://github.com/orgs/metabase/projects/85/views/1",
|
||||
"projectUrl": "https://github.com/orgs/metabase/projects/83/views/8",
|
||||
"members": ["camsaul", "snoe", "bshepherdson", "metamben", "lbrdnk"]
|
||||
},
|
||||
{
|
||||
|
||||
2
.github/workflows/build-for-release.yml
vendored
@@ -113,7 +113,7 @@ jobs:
|
||||
uses: actions/github-script@v7
|
||||
id: release_branch
|
||||
with:
|
||||
result_encoding: string
|
||||
result-encoding: string
|
||||
script: | # js
|
||||
const { getReleaseBranch } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
const version = '${{ inputs.version }}';
|
||||
|
||||
37
.github/workflows/drivers-stress-test.yml
vendored
@@ -21,7 +21,6 @@ on:
|
||||
- Athena
|
||||
- BigQuery
|
||||
- Druid
|
||||
- Google Analytics
|
||||
- Google Classpath Test
|
||||
- Maria DB
|
||||
- Maria DB (latest)
|
||||
@@ -109,42 +108,6 @@ jobs:
|
||||
junit-name: 'be-tests-druid-ee'
|
||||
test-args: ":only ${{ inputs.test }} :times ${{ inputs.times }}"
|
||||
|
||||
be-tests-googleanalytics-ee:
|
||||
if: inputs.driver == 'Google Analytics'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: googleanalytics
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test Google Analytics driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-googleanalytics-ee'
|
||||
test-args: ":only ${{ inputs.test }} :times ${{ inputs.times }}"
|
||||
|
||||
be-google-related-drivers-classpath-test:
|
||||
if: inputs.driver == 'Google Classpath Test'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: 'googleanalytics,bigquery-cloud-sdk'
|
||||
MB_BIGQUERY_TEST_PROJECT_ID: ${{ secrets.BIGQUERY_TEST_PROJECT_ID }}
|
||||
MB_BIGQUERY_TEST_CLIENT_ID: ${{ secrets.MB_BIGQUERY_TEST_CLIENT_ID }}
|
||||
MB_BIGQUERY_TEST_CLIENT_SECRET: ${{ secrets.MB_BIGQUERY_TEST_CLIENT_SECRET }}
|
||||
MB_BIGQUERY_TEST_ACCESS_TOKEN: ${{ secrets.MB_BIGQUERY_TEST_ACCESS_TOKEN }}
|
||||
MB_BIGQUERY_TEST_REFRESH_TOKEN: ${{ secrets.MB_BIGQUERY_TEST_REFRESH_TOKEN }}
|
||||
MB_BIGQUERY_CLOUD_SDK_TEST_SERVICE_ACCOUNT_JSON: ${{ secrets.MB_BIGQUERY_CLOUD_SDK_TEST_SERVICE_ACCOUNT_JSON }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test Google Related Drivers Classpath
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-google-related-drivers-classpath-test'
|
||||
test-args: ':only "[metabase.query-processor-test.expressions-test metabase.driver.google-test metabase.driver.googleanalytics-test ${{ inputs.test }}] :times ${{ inputs.times }}"'
|
||||
|
||||
be-tests-mariadb-10-2-ee:
|
||||
if: inputs.driver == 'Maria DB'
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
60
.github/workflows/drivers.yml
vendored
@@ -160,66 +160,6 @@ jobs:
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-tests-googleanalytics-ee:
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: googleanalytics
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test Google Analytics driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-googleanalytics-ee'
|
||||
test-args: ":exclude-tags '[:mb/once]'"
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
if: always()
|
||||
with:
|
||||
input-path: ./target/junit/
|
||||
output-name: ${{ github.job }}
|
||||
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
|
||||
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-google-related-drivers-classpath-test:
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: 'googleanalytics,bigquery-cloud-sdk'
|
||||
MB_BIGQUERY_TEST_PROJECT_ID: ${{ secrets.BIGQUERY_TEST_PROJECT_ID }}
|
||||
MB_BIGQUERY_TEST_CLIENT_ID: ${{ secrets.MB_BIGQUERY_TEST_CLIENT_ID }}
|
||||
MB_BIGQUERY_TEST_CLIENT_SECRET: ${{ secrets.MB_BIGQUERY_TEST_CLIENT_SECRET }}
|
||||
MB_BIGQUERY_TEST_ACCESS_TOKEN: ${{ secrets.MB_BIGQUERY_TEST_ACCESS_TOKEN }}
|
||||
MB_BIGQUERY_TEST_REFRESH_TOKEN: ${{ secrets.MB_BIGQUERY_TEST_REFRESH_TOKEN }}
|
||||
MB_BIGQUERY_CLOUD_SDK_TEST_SERVICE_ACCOUNT_JSON: ${{ secrets.MB_BIGQUERY_CLOUD_SDK_TEST_SERVICE_ACCOUNT_JSON }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test Google Related Drivers Classpath
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-google-related-drivers-classpath-test'
|
||||
test-args: ':only "[metabase.query-processor-test.expressions-test metabase.driver.google-test metabase.driver.googleanalytics-test]"'
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
if: always()
|
||||
with:
|
||||
input-path: ./target/junit/
|
||||
output-name: ${{ github.job }}
|
||||
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
|
||||
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-tests-mariadb-10-2-ee:
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
|
||||
105
.github/workflows/release-embedding-sdk.yml
vendored
@@ -20,7 +20,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
git-tag:
|
||||
check-git-tag:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
@@ -30,25 +30,21 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.git_ref }}
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Setup git user
|
||||
- name: check tags
|
||||
run: |
|
||||
git config --global user.email "metabase-bot@metabase.com"
|
||||
git config --global user.name "Metabase bot"
|
||||
|
||||
- name: Create a new git tag
|
||||
run: |
|
||||
git tag ${{ env.tag }}
|
||||
|
||||
- name: Push the new tag
|
||||
id : push-tag
|
||||
run: |
|
||||
git push origin ${{ env.tag }}
|
||||
- if: ${{ failure() && steps.push-tag.outcome == 'failure' }}
|
||||
run: echo "Tag '${{ env.tag }}' already exists. If you expect to run this workflow with the same tag, please remove the tag first and rerun this workflow again."
|
||||
if [ $(git tag -l | grep $tag) ]
|
||||
then
|
||||
echo "::error::Tag '${{ env.tag }}' already exists. If you expect to run this workflow with the same tag, please remove the tag first and rerun this workflow again."
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
test:
|
||||
needs: git-tag
|
||||
needs: check-git-tag
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
@@ -77,6 +73,8 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.git_ref }}
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
@@ -86,9 +84,24 @@ jobs:
|
||||
with:
|
||||
m2-cache-key: "release-sdk"
|
||||
|
||||
- name: Update readme
|
||||
run: |
|
||||
./bin/embedding-sdk/release_utils.bash update_readme ${{ inputs.sdk_version }}
|
||||
|
||||
- name: Bump published npm package version
|
||||
run: |
|
||||
sed -i -E 's/("version": ").*"/\1${{ inputs.sdk_version }}"/' enterprise/frontend/src/embedding-sdk/package.template.json
|
||||
./bin/embedding-sdk/release_utils.bash update_package_json_template ${{ inputs.sdk_version }}
|
||||
|
||||
# TODO: Remove this step after the build utils script is merged to master
|
||||
- name: Upload release utils script, so it can be used later on when checking out `master` branch
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-util
|
||||
path: ./bin/embedding-sdk/release_utils.bash
|
||||
|
||||
- name: Update changelog
|
||||
run: |
|
||||
yarn embedding-sdk:generate-changelog
|
||||
|
||||
- name: Build SDK bundle
|
||||
run: yarn run build-embedding-sdk
|
||||
@@ -102,6 +115,12 @@ jobs:
|
||||
name: metabase-sdk
|
||||
path: ./resources/embedding-sdk
|
||||
|
||||
- name: Upload changelog
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdk-changelog
|
||||
path: ./enterprise/frontend/src/embedding-sdk/CHANGELOG.md
|
||||
|
||||
build-jar:
|
||||
needs: test
|
||||
uses: ./.github/workflows/uberjar-sdk.yml
|
||||
@@ -136,7 +155,6 @@ jobs:
|
||||
run: |
|
||||
aws s3 cp $FILE s3://$BUCKET/$BUCKET_PATH
|
||||
|
||||
|
||||
publish-npm:
|
||||
needs: [build-sdk, upload-jar]
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -153,14 +171,30 @@ jobs:
|
||||
git config --global user.email "metabase-bot@metabase.com"
|
||||
git config --global user.name "Metabase bot"
|
||||
|
||||
# TODO: Remove this step after the build utils script is merged to master
|
||||
- name: Download release utils script
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-util
|
||||
path: ./bin/embedding-sdk/
|
||||
|
||||
- name: Update readme
|
||||
run: |
|
||||
sed -i -E 's|(embedding-sdk-)[0-9.]+|\1${{ inputs.sdk_version }}|' enterprise/frontend/src/embedding-sdk/README.md
|
||||
sed -i -E 's|(http://downloads.metabase.com/sdk/v)[0-9.]+|\1${{ inputs.sdk_version }}|' enterprise/frontend/src/embedding-sdk/README.md
|
||||
bash ./bin/embedding-sdk/release_utils.bash update_readme ${{ inputs.sdk_version }}
|
||||
|
||||
- name: Bump published npm package version
|
||||
run: |
|
||||
sed -i -E 's/("version": ").*"/\1${{ inputs.sdk_version }}"/' enterprise/frontend/src/embedding-sdk/package.template.json
|
||||
bash ./bin/embedding-sdk/release_utils.bash update_package_json_template ${{ inputs.sdk_version }}
|
||||
|
||||
- name: Retrieve SDK changelog
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sdk-changelog
|
||||
|
||||
# We need to do this because it's impossible to download an artifact to an existing location
|
||||
- name: Move over the downloaded changelog
|
||||
run: |
|
||||
mv CHANGELOG.md ./enterprise/frontend/src/embedding-sdk/CHANGELOG.md
|
||||
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
@@ -168,7 +202,7 @@ jobs:
|
||||
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
|
||||
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Create a PR updating readme + published version
|
||||
- name: Create a PR updating readme + published version, and changelog
|
||||
run: |
|
||||
git checkout -b update-sdk-version-${{ inputs.sdk_version }}
|
||||
git commit -a -m 'Update Readme version references and published npm version to ${{ inputs.sdk_version }}'
|
||||
@@ -177,6 +211,7 @@ jobs:
|
||||
--assignee "${GITHUB_ACTOR}"\
|
||||
--title "Update SDK version to ${{ inputs.sdk_version }}"\
|
||||
--body "Update Readme version references and published npm package version to ${{ inputs.sdk_version }}"
|
||||
gh pr edit --add-reviewer @metabase/embedding
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
@@ -191,3 +226,29 @@ jobs:
|
||||
cd sdk
|
||||
echo //registry.npmjs.org/:_authToken=${{ secrets.NPM_RELEASE_TOKEN }} > .npmrc
|
||||
npm publish
|
||||
|
||||
git-tag:
|
||||
needs: publish-npm
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
tag: embedding-sdk-${{ inputs.sdk_version }}
|
||||
steps:
|
||||
- name: Check out the code using the provided ref
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.git_ref }}
|
||||
|
||||
- name: Setup git user
|
||||
run: |
|
||||
git config --global user.email "metabase-bot@metabase.com"
|
||||
git config --global user.name "Metabase bot"
|
||||
|
||||
- name: Create a new git tag
|
||||
run: |
|
||||
git tag ${{ env.tag }}
|
||||
|
||||
- name: Push the new tag
|
||||
id : push-tag
|
||||
run: |
|
||||
git push origin ${{ env.tag }}
|
||||
|
||||
3
.gitignore
vendored
@@ -96,7 +96,8 @@ modules/drivers/*/.lsp/*
|
||||
.clj-kondo/*
|
||||
!.clj-kondo/README.md
|
||||
!.clj-kondo/config.edn
|
||||
!.clj-kondo/hooks/
|
||||
!.clj-kondo/src/
|
||||
!.clj-kondo/test/
|
||||
!.clj-kondo/macros/
|
||||
|
||||
# Editor- or environment-specific local files
|
||||
|
||||
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
.loki/reference/chrome_laptop_viz_PivotTable_Default.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
.loki/reference/chrome_laptop_viz_PivotTable_Embedding_Theme.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -20,8 +20,7 @@
|
||||
"/enterprise/backend/src"
|
||||
"/modules/drivers/bigquery-cloud-sdk/src"
|
||||
"/modules/drivers/druid/src"
|
||||
"/modules/drivers/google/src"
|
||||
"/modules/drivers/googleanalytics/src"
|
||||
"/modules/drivers/druid-jdbc/src"
|
||||
"/modules/drivers/mongo/src"
|
||||
"/modules/drivers/oracle/src"
|
||||
"/modules/drivers/presto-jdbc/src"
|
||||
|
||||
@@ -91,3 +91,4 @@ if (!fs.existsSync(SDK_DIST_DIR)) {
|
||||
generateSdkPackage();
|
||||
copyFileToOutput("LICENSE.txt");
|
||||
copyFileToOutput("frontend/src/embedding-sdk/README.md", "README.md");
|
||||
copyFileToOutput("frontend/src/embedding-sdk/CHANGELOG.md", "CHANGELOG.md");
|
||||
|
||||
11
bin/embedding-sdk/release_utils.bash
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
function update_readme() {
|
||||
sed -i -E 's|(embedding-sdk-)[0-9.]+|\1'"$1"'|' enterprise/frontend/src/embedding-sdk/README.md
|
||||
sed -i -E 's|(http://downloads.metabase.com/sdk/v)[0-9.]+|\1'"$1"'|' enterprise/frontend/src/embedding-sdk/README.md
|
||||
}
|
||||
|
||||
function update_package_json_template() {
|
||||
sed -i -E 's/("version": ").*"/\1'"$1"'"/' enterprise/frontend/src/embedding-sdk/package.template.json
|
||||
}
|
||||
|
||||
$1 $2
|
||||
21
deps.edn
@@ -49,7 +49,7 @@
|
||||
com.snowplowanalytics/snowplow-java-tracker
|
||||
{:mvn/version "1.0.1" ; Snowplow analytics
|
||||
:exclusions [com.fasterxml.jackson.core/jackson-databind]}
|
||||
com.taoensso/nippy {:mvn/version "3.3.0"} ; Fast serialization (i.e., GZIP) library for Clojure
|
||||
com.taoensso/nippy {:mvn/version "3.4.2"} ; Fast serialization (i.e., GZIP) library for Clojure
|
||||
com.vladsch.flexmark/flexmark {:mvn/version "0.64.8"} ; Markdown parsing
|
||||
com.vladsch.flexmark/flexmark-ext-autolink
|
||||
{:mvn/version "0.64.8"} ; Flexmark extension for auto-linking bare URLs
|
||||
@@ -76,7 +76,7 @@
|
||||
io.github.eerohele/pp {:git/tag "2024-01-04.60" ; super fast pretty-printing library
|
||||
:git/sha "a428751"
|
||||
:git/url "https://github.com/eerohele/pp"}
|
||||
io.github.metabase/macaw {:mvn/version "0.1.29"} ; Parse native SQL queries
|
||||
io.github.metabase/macaw {:mvn/version "0.1.44"} ; Parse native SQL queries
|
||||
;; The 2.X line of Resilience4j requires Java 17, so we cannot upgrade this dependency until that is our minimum JVM version
|
||||
io.github.resilience4j/resilience4j-retry {:mvn/version "1.7.1" #_ "must be 1.7.1"} ; Support for retrying operations
|
||||
io.prometheus/simpleclient_hotspot {:mvn/version "0.16.0"} ; prometheus jvm collector
|
||||
@@ -254,7 +254,7 @@
|
||||
ring/ring-mock {:mvn/version "0.4.0"} ; creating Ring request maps for testing purposes
|
||||
talltale/talltale {:mvn/version "0.5.14"}} ; generates fake data, useful for prototyping or load testing
|
||||
|
||||
:extra-paths ["dev/src" "local/src" "test" "test_resources"]
|
||||
:extra-paths ["dev/src" "local/src" "test" "test_resources" ".clj-kondo/src" ".clj-kondo/test"]
|
||||
:jvm-opts ["-Dmb.run.mode=dev"
|
||||
"-Dmb.field.filter.operators.enabled=true"
|
||||
"-Dmb.test.env.setting=ABCDEFG"
|
||||
@@ -385,7 +385,6 @@
|
||||
"modules/drivers/bigquery-cloud-sdk/test"
|
||||
"modules/drivers/druid/test"
|
||||
"modules/drivers/druid-jdbc/test"
|
||||
"modules/drivers/googleanalytics/test"
|
||||
"modules/drivers/mongo/test"
|
||||
"modules/drivers/oracle/test"
|
||||
"modules/drivers/presto-jdbc/test"
|
||||
@@ -412,7 +411,6 @@
|
||||
"modules/drivers/bigquery-cloud-sdk/src"
|
||||
"modules/drivers/druid/src"
|
||||
"modules/drivers/druid-jdbc/src"
|
||||
"modules/drivers/googleanalytics/src"
|
||||
"modules/drivers/mongo/src"
|
||||
"modules/drivers/oracle/src"
|
||||
"modules/drivers/presto-jdbc/src"
|
||||
@@ -435,7 +433,6 @@
|
||||
"modules/drivers/bigquery-cloud-sdk/src"
|
||||
"modules/drivers/druid/src"
|
||||
"modules/drivers/druid-jdbc/src"
|
||||
"modules/drivers/googleanalytics/src"
|
||||
"modules/drivers/mongo/src"
|
||||
"modules/drivers/oracle/src"
|
||||
"modules/drivers/presto-jdbc/src"
|
||||
@@ -622,9 +619,9 @@
|
||||
:extra-deps
|
||||
{org.clojure/data.json {:mvn/version "2.5.0"}}}
|
||||
|
||||
;;; Run tests for the build scripts:
|
||||
;;;
|
||||
;;; clj -X:dev:drivers:build:build-dev:build-test
|
||||
;; Run tests for the build scripts:
|
||||
;;
|
||||
;; clj -X:dev:drivers:build:build-dev:build-test
|
||||
:build-test
|
||||
{:exec-fn mb.hawk.core/find-and-run-tests-cli
|
||||
:exec-args {:only ["bin/build/test"]}}
|
||||
@@ -706,6 +703,12 @@
|
||||
{:exec-args {:only [metabase.api.search-test
|
||||
"test/metabase/search"]}}
|
||||
|
||||
;; test custom clj-kondo linters and hooks.
|
||||
;;
|
||||
;; clj -X:dev:test:test/kondo
|
||||
:test/kondo
|
||||
{:exec-args {:only [".clj-kondo/test"]}}
|
||||
|
||||
;; watch and reload clojure namespaces
|
||||
:watch {:extra-deps
|
||||
{com.nextjournal/beholder {:mvn/version "1.0.2"} ;; watcher
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
You can use [[reset-changes!]] to clear our all the current trackings.
|
||||
And [[untrack-all!]] or [[untrack!]] to stop tracking."
|
||||
(:require
|
||||
[clojure.pprint :as pprint]
|
||||
[clojure.string :as str]
|
||||
[metabase.util :as u]
|
||||
[methodical.core :as m]
|
||||
[toucan2.core :as t2]
|
||||
@@ -29,6 +29,19 @@
|
||||
|
||||
(def ^:private tracked-models (atom #{}))
|
||||
|
||||
(defn- indent [prefix s]
|
||||
(str/join "\n"
|
||||
(map
|
||||
(fn [line] (str prefix line))
|
||||
(str/split-lines s))))
|
||||
|
||||
(defn- sort-map-for-printing [m]
|
||||
(into (sorted-map-by (fn [a b]
|
||||
(cond (= a :id) -1
|
||||
(= b :id) 1
|
||||
:else (compare a b)))) m))
|
||||
|
||||
#_:clj-kondo/ignore ;; printlns
|
||||
(defn on-change
|
||||
"When a change occurred, execute this function.
|
||||
|
||||
@@ -43,7 +56,7 @@
|
||||
"
|
||||
[path change-info]
|
||||
(println (u/colorize :magenta :new-change) (u/colorize :magenta path))
|
||||
(pprint/pprint change-info))
|
||||
(println (->> change-info sort-map-for-printing u/pprint-to-str (indent " "))))
|
||||
|
||||
(defn- clean-change
|
||||
[change]
|
||||
@@ -98,7 +111,7 @@
|
||||
(defn track!
|
||||
"Start tracking a list of models.
|
||||
|
||||
(track! 'Card 'Dashboard)"
|
||||
(track! :model/Card :model/Dashboard)"
|
||||
[& models]
|
||||
(doseq [model (map t2.model/resolve-model models)]
|
||||
(track-one! model)
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
---
|
||||
title: Working with Google Analytics in Metabase
|
||||
redirect_from:
|
||||
- /docs/latest/administration-guide/databases/google-analytics
|
||||
---
|
||||
|
||||
# Google Analytics (DEPRECATED)
|
||||
|
||||
Metabase supported Google Analytics version 3, which Google has set an end-of-life date for July 1, 2023.
|
||||
|
||||
If you still want to view Google Analytics data in Metabase, we recommend:
|
||||
|
||||
- Upgrading to the latest version of [Google Analytics](https://support.google.com/analytics/answer/10089681?hl=en&ref_topic=12154439,12153943,2986333).
|
||||
- Setting up a [BigQuery](https://cloud.google.com/bigquery) account.
|
||||
- Connecting your [Bigquery to Metabase](./bigquery.md).
|
||||
- Exporting your [Google Analytics 4 data to BigQuery](https://support.google.com/analytics/answer/9358801?hl=en).
|
||||
|
||||
Google Analytics will export the data to BigQuery in one table per day. You can build native SQL models with [wildcard queries](https://cloud.google.com/bigquery/docs/querying-wildcard-tables), and then build Metabase questions over those views.
|
||||
@@ -4,6 +4,18 @@ title: API changelog
|
||||
|
||||
# Breaking changes to the API interface
|
||||
|
||||
## Metabase 0.51.0
|
||||
|
||||
- `GET /api/dashboard/:id/query_metadata`
|
||||
|
||||
New endpoint that combines responses for `/api/field/:id`, `/api/database/:id`, and `/api/table/:id/query_metadata`.
|
||||
This should drastically cut down on the required number of requests to display a card.
|
||||
|
||||
- `GET /api/card/:id/query_metadata`
|
||||
|
||||
New endpoint that combines responses for `/api/field/:id`, `/api/database/:id`, and `/api/table/:id/query_metadata`.
|
||||
This should drastically cut down on the required number of requests to display a dashboard.
|
||||
|
||||
## Metabase 0.50.0
|
||||
|
||||
- `GET /api/collection/tree` and `GET /api/collection/:id/items`
|
||||
@@ -55,4 +67,4 @@ NOTE: These endpoint changes were added in 0.49.3, and a bug in `GET /api/embed/
|
||||
|
||||
- all endpoints that return data (e.g. exports in JSON, XLSX, CSV, endpoints that end in "/query")
|
||||
|
||||
Starting from v49, we respond to the API calls with values formatted according to the instance localization options
|
||||
Starting from v49, we respond to the API calls with values formatted according to the instance localization options
|
||||
|
||||
@@ -86,7 +86,6 @@ These parents are kind of a big deal.
|
||||
- `:sql-jdbc` implements most of the four main features, but instead you must implement `sql-jdbc` multimethods found in `metabase.driver.sql-jdbc.*` namespaces, as well as some methods in `metabase.driver.sql.*` namespaces.
|
||||
- `:sql` is itself the parent of `:sql-jdbc`; it can be used for SQL-based databases that _do not_ have a JDBC driver, such as BigQuery.
|
||||
- `:sql` implements a significant chunk of driver functionality, but you must implement some methods found in `metabase.driver.sql.*` namespaces to use it.
|
||||
- Drivers that use Google's API, such as BigQuery and Google Analytics, can use the `:google` driver as a parent.
|
||||
- Some drivers use other "concrete" drivers as their parent -- for example, `:redshift` uses `:postgres` as a parent, only supplying method implementations to override postgres ones where needed.
|
||||
|
||||
### Calling parent driver implementations
|
||||
@@ -139,4 +138,4 @@ To start a REPL.
|
||||
clojure -A:dev:drivers:drivers-dev
|
||||
```
|
||||
|
||||
You'll need to rebuild the driver and install it in your `./plugins` directory, and restart Metabase when you make changes.
|
||||
You'll need to rebuild the driver and install it in your `./plugins` directory, and restart Metabase when you make changes.
|
||||
|
||||
@@ -116,7 +116,6 @@ Note that the first part of the timestamp is in UTC (same thing as GMT). The tim
|
||||
|
||||
- Amazon Athena
|
||||
- Druid
|
||||
- Google Analytics
|
||||
- MongoDB
|
||||
- Presto
|
||||
- SparkSQL
|
||||
|
||||
@@ -77,7 +77,6 @@ If your timestamps are stored as strings or numbers in your database, an admin c
|
||||
`datetimeDiff` is currently unavailable for the following databases:
|
||||
|
||||
- Druid
|
||||
- Google Analytics
|
||||
|
||||
## Related functions
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ Pivot tables allow you swap rows and columns, group data, and include subtotals
|
||||
Pivot tables are not currently available for the following databases in Metabase:
|
||||
|
||||
- Druid
|
||||
- Google Analytics
|
||||
- MongoDB
|
||||
|
||||
Pivot tables work for simple and custom questions with summarized data for all other [officially supported databases](../../../databases/connecting.md). They don't work for questions that lack aggregate data, and they don't work for questions written in SQL, as Metabase would need to modify your SQL code in order to calculate subtotals. If you really need to use SQL, the workaround here is to create your question in two steps: first do all the complex things you need to do in SQL, save the results as a question, then use that saved SQL question as the starting point for a new GUI question which summarizes that data.
|
||||
@@ -36,4 +35,4 @@ Where it makes sense, Metabase will automatically include subtotals for grouped
|
||||
|
||||
To collapse a group on a pivot table, you can click on the minus (–) button next to the group's heading (or the plus (+) button to expand it). When you save a pivot table, Metabase will remember which groups were expanded and which were collapsed.
|
||||
|
||||
For more, check out [How to create a pivot table to summarize your data](https://www.metabase.com/learn/basics/visualizing-data/how-to-create-pivot-tables.html).
|
||||
For more, check out [How to create a pivot table to summarize your data](https://www.metabase.com/learn/basics/visualizing-data/how-to-create-pivot-tables.html).
|
||||
|
||||
@@ -26,7 +26,7 @@ You can join data to combine your current data with another table, or even with
|
||||
|
||||
## Native query editor
|
||||
|
||||
Also known as the SQL editor (we say native because you can also query databases that don't use SQL, like MongoDB and Google Analytics).
|
||||
Also known as the SQL editor (we say native because you can also query databases that don't use SQL, like MongoDB).
|
||||
|
||||
### [Introduction to the native query editor](./native-editor/writing-sql.md)
|
||||
|
||||
|
||||
@@ -2,17 +2,13 @@ import { cypressWaitAll } from "e2e/support/helpers";
|
||||
|
||||
Cypress.Commands.add(
|
||||
"createDashboardWithQuestions",
|
||||
({ dashboardName, dashboardDetails, questions, cards }) => {
|
||||
({ dashboardName, dashboardDetails, questions }) => {
|
||||
return cy
|
||||
.createDashboard({ name: dashboardName, ...dashboardDetails })
|
||||
.then(({ body: dashboard }) => {
|
||||
return cypressWaitAll(
|
||||
questions.map((query, index) =>
|
||||
cy.createQuestionAndAddToDashboard(
|
||||
query,
|
||||
dashboard.id,
|
||||
cards ? cards[index] : undefined,
|
||||
),
|
||||
questions.map(query =>
|
||||
cy.createQuestionAndAddToDashboard(query, dashboard.id),
|
||||
),
|
||||
).then(dashcardResponses => {
|
||||
const questions = dashcardResponses.map(
|
||||
|
||||
@@ -20,7 +20,6 @@ Cypress.Commands.add(
|
||||
}).then(response => ({
|
||||
...response,
|
||||
body: response.body.dashcards[0],
|
||||
questionId,
|
||||
}));
|
||||
},
|
||||
);
|
||||
|
||||
@@ -9,8 +9,10 @@ export function setActionsEnabledForDB(dbId, enabled = true) {
|
||||
}
|
||||
|
||||
export function fillActionQuery(query) {
|
||||
cy.get(".ace_content:visible").type(query, {
|
||||
// Without this wait, content tends to drop from the beginning of the string. TODO: Fix
|
||||
cy.get(".ace_content:visible").wait(500).type(query, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 50,
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -129,7 +129,7 @@ function getIcon(actionType) {
|
||||
export function assertQueryBuilderRowCount(count) {
|
||||
const message =
|
||||
count === 1 ? "Showing 1 row" : `Showing ${count.toLocaleString()} rows`;
|
||||
cy.findByTestId("question-row-count").contains(message);
|
||||
cy.findByTestId("question-row-count").should("contain.text", message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,10 +3,10 @@ export const openCommandPalette = () => cy.get("body").type("{ctrl+k}{cmd+k}");
|
||||
export const commandPaletteButton = () =>
|
||||
cy.findByTestId("app-bar").findByRole("button", { name: /Search/ });
|
||||
export const closeCommandPalette = () => cy.get("body").type("{esc}");
|
||||
export const pressPageUp = () => cy.get("body").type("{pageup}");
|
||||
export const pressPageDown = () => cy.get("body").type("{pagedown}");
|
||||
export const pressHome = () => cy.get("body").type("{home}");
|
||||
export const pressEnd = () => cy.get("body").type("{end}");
|
||||
export const pressPageUp = () => cy.realPress("{pageup}");
|
||||
export const pressPageDown = () => cy.realPress("{pagedown}");
|
||||
export const pressHome = () => cy.realPress("{home}");
|
||||
export const pressEnd = () => cy.realPress("{end}");
|
||||
export const commandPaletteInput = () =>
|
||||
cy.findByPlaceholderText("Search for anything or jump somewhere…");
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ export function expressionEditorWidget() {
|
||||
* @param {Object} option
|
||||
* @param {string} option.formula
|
||||
* @param {string=} option.name
|
||||
* @param {boolean} option.blur true by default. However, if you need to examine the popover in the test, it should be set to false so the popover is not dismissed
|
||||
*/
|
||||
export function enterCustomColumnDetails({ formula, name }) {
|
||||
export function enterCustomColumnDetails({ formula, name, blur = true }) {
|
||||
cy.get(".ace_text-input")
|
||||
.first()
|
||||
.as("formula")
|
||||
@@ -15,11 +16,15 @@ export function enterCustomColumnDetails({ formula, name }) {
|
||||
.focus()
|
||||
.clear()
|
||||
.type(formula);
|
||||
if (blur) {
|
||||
cy.get("@formula").blur();
|
||||
}
|
||||
|
||||
if (name) {
|
||||
cy.findByPlaceholderText("Something nice and descriptive")
|
||||
.clear()
|
||||
.type(name);
|
||||
.type(name)
|
||||
.blur();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||