Compare commits
256 Commits
document-b
...
test-pytho
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39a68def7e | ||
|
|
3da641ba00 | ||
|
|
91247c3be2 | ||
|
|
ed4f399a01 | ||
|
|
a291c967c7 | ||
|
|
4f1dec3ce8 | ||
|
|
f6347c776d | ||
|
|
ae3c2c7a2a | ||
|
|
3a985e46a2 | ||
|
|
ba2ae00dac | ||
|
|
0df6adcc51 | ||
|
|
87c2392827 | ||
|
|
0760630f10 | ||
|
|
27a078faf0 | ||
|
|
3177f079e8 | ||
|
|
49c0589aa8 | ||
|
|
57afac78ba | ||
|
|
1fed0f701c | ||
|
|
e9950fdc21 | ||
|
|
02f7a885ee | ||
|
|
3def5f4ca9 | ||
|
|
fcd7a98745 | ||
|
|
b025a5bfb7 | ||
|
|
02467bd231 | ||
|
|
ba60e617ba | ||
|
|
7738ae7271 | ||
|
|
08c8d0f1f6 | ||
|
|
bdef8558a9 | ||
|
|
20c7cb44a3 | ||
|
|
eda355803b | ||
|
|
e6df0dc8c5 | ||
|
|
90b57af0ae | ||
|
|
6ec03b098e | ||
|
|
7b7d02442a | ||
|
|
5decddf00c | ||
|
|
bacdb174ee | ||
|
|
bb6d7b1cbc | ||
|
|
f01ea21e37 | ||
|
|
e937214a8d | ||
|
|
d9060d941c | ||
|
|
15b31fb834 | ||
|
|
ce56b8e398 | ||
|
|
d2b54425f2 | ||
|
|
8722548f6d | ||
|
|
8a542dd80a | ||
|
|
940d244d2d | ||
|
|
33e9a2cc25 | ||
|
|
9ddffb2edf | ||
|
|
c396990a98 | ||
|
|
29f1dac45f | ||
|
|
db9c8dcfbf | ||
|
|
2dc59090e3 | ||
|
|
a13c7d234d | ||
|
|
577b1d8fb6 | ||
|
|
6586bba402 | ||
|
|
686113d2d7 | ||
|
|
a893803cfb | ||
|
|
aa200bc31f | ||
|
|
1b03fa10a9 | ||
|
|
ac8285254b | ||
|
|
1a8a04cf82 | ||
|
|
750c6ebb22 | ||
|
|
2c71824e61 | ||
|
|
a58b2ebefc | ||
|
|
ac22d632bc | ||
|
|
7fac1f9d24 | ||
|
|
b56f63252b | ||
|
|
62fceee952 | ||
|
|
2feb85417d | ||
|
|
8dc5cec918 | ||
|
|
560a253192 | ||
|
|
753c645216 | ||
|
|
bd18384233 | ||
|
|
67d603aa42 | ||
|
|
b9ac3ab886 | ||
|
|
bef6cb6908 | ||
|
|
f573f15de1 | ||
|
|
38bf19399d | ||
|
|
f3b85b3e33 | ||
|
|
23f74a039f | ||
|
|
3ad1913339 | ||
|
|
e622f71034 | ||
|
|
abeef3b5a8 | ||
|
|
2637538cee | ||
|
|
5aad91c383 | ||
|
|
5931cb0d0a | ||
|
|
8ad785fdbb | ||
|
|
78308b14f9 | ||
|
|
3d5410d199 | ||
|
|
497ef8ebe1 | ||
|
|
ec16936ff8 | ||
|
|
c4cfe78c2c | ||
|
|
d0fff0402a | ||
|
|
f267ce0c56 | ||
|
|
363ed3b959 | ||
|
|
b4c65c3299 | ||
|
|
195b18d690 | ||
|
|
3a0e283b12 | ||
|
|
97c57e7bac | ||
|
|
92cea5d4f5 | ||
|
|
dbf8855111 | ||
|
|
292a7c8058 | ||
|
|
83fdbaa65c | ||
|
|
0ab2b9f4f6 | ||
|
|
9d687287fe | ||
|
|
b5e93da266 | ||
|
|
78bf0474d6 | ||
|
|
b7bf8b6ecc | ||
|
|
65d95d9438 | ||
|
|
205bd075a9 | ||
|
|
0e8804a8cc | ||
|
|
6773707b3e | ||
|
|
3037854ee0 | ||
|
|
14b05dc189 | ||
|
|
20d149c48d | ||
|
|
165c061afb | ||
|
|
2fce0a53a6 | ||
|
|
fd2c44a380 | ||
|
|
b86eb24b0c | ||
|
|
8eb405c96b | ||
|
|
dd5117bdb1 | ||
|
|
935fe5a0e5 | ||
|
|
96750294f5 | ||
|
|
19a811f282 | ||
|
|
0be7ef31cf | ||
|
|
7c76029e6b | ||
|
|
7ee5fffead | ||
|
|
7491d37214 | ||
|
|
fc98a81852 | ||
|
|
d76377e784 | ||
|
|
dddf6568c1 | ||
|
|
9fd8200087 | ||
|
|
a9c06c5ece | ||
|
|
0a2aa0f087 | ||
|
|
f42ea9842a | ||
|
|
448ed2d9e0 | ||
|
|
0bcd797755 | ||
|
|
1a645a55d6 | ||
|
|
d1cb9336da | ||
|
|
f569537850 | ||
|
|
392a3ebc48 | ||
|
|
9e401daa2e | ||
|
|
f67961423a | ||
|
|
a4564a2e12 | ||
|
|
0cf0d86421 | ||
|
|
309e69774e | ||
|
|
5a880ebfb8 | ||
|
|
645543ff3e | ||
|
|
4b1ee493db | ||
|
|
db08e23530 | ||
|
|
d5131a98f6 | ||
|
|
4f99d70ece | ||
|
|
ed772da268 | ||
|
|
1d88be2135 | ||
|
|
d825953952 | ||
|
|
bf5799df15 | ||
|
|
4bc3b6484b | ||
|
|
ee29d769a0 | ||
|
|
013974b705 | ||
|
|
202290121b | ||
|
|
5766d22bce | ||
|
|
7b500427ec | ||
|
|
d0a36c3d7c | ||
|
|
ef7ee34349 | ||
|
|
24d6fc3d7d | ||
|
|
e00705930f | ||
|
|
a85b69ce0d | ||
|
|
dff77917f4 | ||
|
|
c25d90382f | ||
|
|
42d8c14a8e | ||
|
|
6b37f5f3af | ||
|
|
809503986a | ||
|
|
b551d305fc | ||
|
|
b24f87f5d1 | ||
|
|
9c95e9b8a7 | ||
|
|
8e8480fc95 | ||
|
|
abf5f8caa8 | ||
|
|
d13f7355c5 | ||
|
|
e560d95105 | ||
|
|
e7828cc2f8 | ||
|
|
0af03be7cc | ||
|
|
26915a1feb | ||
|
|
8fcd5d3839 | ||
|
|
39cefbab7f | ||
|
|
e002ff8980 | ||
|
|
95bb56b5e8 | ||
|
|
1e03d56dac | ||
|
|
a5d21e9623 | ||
|
|
3606567fc8 | ||
|
|
a3b380ca00 | ||
|
|
59ec9091d8 | ||
|
|
158ce159f7 | ||
|
|
a6a737b33b | ||
|
|
af75705b3c | ||
|
|
f904f950ba | ||
|
|
64a8ec3593 | ||
|
|
39e2e551dc | ||
|
|
7606803604 | ||
|
|
7fd1c79dad | ||
|
|
1a7017612c | ||
|
|
4420d0c963 | ||
|
|
3a00a330bc | ||
|
|
22211b18e8 | ||
|
|
bc5bcff995 | ||
|
|
27456e9669 | ||
|
|
13854b5c49 | ||
|
|
143ed4974c | ||
|
|
bca7756059 | ||
|
|
186aa9e644 | ||
|
|
1c92dfb462 | ||
|
|
9cae2a5080 | ||
|
|
127b23d986 | ||
|
|
62917d13bc | ||
|
|
47720ac7dc | ||
|
|
003c9e63b3 | ||
|
|
5c9d18b96a | ||
|
|
054c0477c0 | ||
|
|
c8da77672c | ||
|
|
7360cd88b6 | ||
|
|
55c789fa26 | ||
|
|
a93959a4c5 | ||
|
|
0e1bfe79f2 | ||
|
|
1efe3a5675 | ||
|
|
6ecbad3323 | ||
|
|
8ece3416e3 | ||
|
|
c360c2f457 | ||
|
|
63b43a98d5 | ||
|
|
d4f385694f | ||
|
|
a3d7c7e9f3 | ||
|
|
96ab264d7a | ||
|
|
59ebd75cec | ||
|
|
1ff9264e4c | ||
|
|
692acf2531 | ||
|
|
e0d12b32e4 | ||
|
|
b47e6f4313 | ||
|
|
bdd9dccdc9 | ||
|
|
35d5f824f9 | ||
|
|
c99b613fb3 | ||
|
|
5fc1f7309f | ||
|
|
b02eb58a79 | ||
|
|
337f5bb867 | ||
|
|
958390151e | ||
|
|
09377ed5e9 | ||
|
|
8334d3d91b | ||
|
|
66f7eb7039 | ||
|
|
d228328a29 | ||
|
|
cd8d1a8348 | ||
|
|
0c0b1f7a4b | ||
|
|
4e168d7e8c | ||
|
|
8b92275ceb | ||
|
|
9f04f3ce31 | ||
|
|
3ce8af616d | ||
|
|
577aa9ee51 | ||
|
|
5b9d0ce9fd | ||
|
|
e800c0673d | ||
|
|
5a7469143b |
@@ -25,6 +25,7 @@
|
||||
:reduce-without-init {:level :warning}
|
||||
:redundant-call {:level :warning}
|
||||
:redundant-fn-wrapper {:level :warning}
|
||||
:redundant-str-call {:level :warning}
|
||||
:self-requiring-namespace {:level :warning}
|
||||
:single-key-in {:level :warning}
|
||||
:unsorted-imports {:level :warning}
|
||||
@@ -489,6 +490,8 @@
|
||||
metabase.util.malli/defn- schema.core/defn
|
||||
metabase.util.malli/fn schema.core/fn
|
||||
metabase.util.namespaces/import-fns potemkin/import-vars
|
||||
metabase.util.performance/doseq clojure.core/doseq
|
||||
metabase.util.performance/for clojure.core/for
|
||||
metabase.util/with-timer-ms clojure.core/fn
|
||||
metabuild-common.core/with-open-jar-file-system clojure.core/let
|
||||
metabuild-common.files/with-open-jar-file-system clojure.core/let
|
||||
@@ -519,6 +522,7 @@
|
||||
metabase-enterprise.advanced-permissions.models.permissions.application-permissions-test/with-new-group-and-current-graph hooks.common/with-two-top-level-bindings
|
||||
metabase-enterprise.audit-app.pages-test/with-temp-objects hooks.common/with-one-binding
|
||||
metabase-enterprise.cache.config-test/with-temp-persist-models hooks.common/with-seven-bindings
|
||||
metabase-enterprise.metabot-v3.tools.dependencies-test/with-dependent-transforms! hooks.common/with-two-bindings
|
||||
metabase-enterprise.semantic-search.db.connection/with-migrate-tx hooks.common/let-one-with-optional-value
|
||||
metabase-enterprise.serialization.test-util/with-temp-dpc hooks.toucan2.tools.with-temp/with-temp
|
||||
metabase-enterprise.transforms-python.drivers-test/with-test-table hooks.common/with-two-bindings
|
||||
@@ -715,6 +719,8 @@
|
||||
:name metabase-lib}
|
||||
{:pattern "^metabase\\.lib\\..*"
|
||||
:name metabase-lib-excluding-legacy-mbql}
|
||||
{:pattern "^metabase\\.legacy-mbql\\..*"
|
||||
:name legacy-mbql-namespaces}
|
||||
;;
|
||||
;; QP and driver source namespaces: `metabase.query-processor.*`, `metabase-enterprise.sandbox.query-processor.*`,
|
||||
;; and `metabase.driver.*`, excluding `-test` namespaces.
|
||||
@@ -729,7 +735,7 @@
|
||||
;;
|
||||
;; driver namespaces, including tests
|
||||
;;
|
||||
{:pattern "metabase\\.driver.*$"
|
||||
{:pattern "metabase\\.driver(?:-api)?.*$"
|
||||
:name driver-namespaces}
|
||||
;;
|
||||
;; Perf-sensitive namespaces are currently the union of metabase.lib.*, driver namespaces, and QP (without tests).
|
||||
@@ -775,7 +781,14 @@
|
||||
clojure.core/eval {:message "Don't use eval outside of tests"}}
|
||||
|
||||
:discouraged-namespace
|
||||
{metabase.query-processor.store {:message "Please do not use the QP Store outside of legacy QP or driver code. Use MBQL 5/Lib or lib.metadata.jvm/applicaton-database-metadata-provider instead."}}}}
|
||||
{metabase.legacy-mbql.jvm-util {:message "Avoid legacy MBQL utils, use Lib instead"}
|
||||
metabase.legacy-mbql.normalize {:message "Avoid legacy MBQL normalization, use MBQL 5 + lib/normalize instead"}
|
||||
metabase.legacy-mbql.predicates {:message "Avoid legacy MBQL utils, use Lib instead"}
|
||||
metabase.legacy-mbql.schema {:message "Avoid the legacy MBQL schema, use MBQL 5 + lib.schema instead"}
|
||||
metabase.legacy-mbql.schema.helpers {:message "Avoid the legacy MBQL schema, use MBQL 5 + lib.schema instead"}
|
||||
metabase.legacy-mbql.schema.macros {:message "Avoid the legacy MBQL schema, use MBQL 5 + lib.schema instead"}
|
||||
metabase.legacy-mbql.util {:message "Avoid legacy MBQL utils, use Lib instead"}
|
||||
metabase.query-processor.store {:message "Please do not use the QP Store outside of legacy QP or driver code. Use MBQL 5/Lib or lib.metadata.jvm/applicaton-database-metadata-provider instead."}}}}
|
||||
|
||||
printable-namespaces
|
||||
{:linters
|
||||
@@ -817,20 +830,70 @@
|
||||
toucan2.core {:message "Don't use application database inside Lib code"}}}}
|
||||
|
||||
metabase-lib-excluding-legacy-mbql
|
||||
{:linters
|
||||
{:discouraged-var
|
||||
{metabase.legacy-mbql.util/unique-name-generator {:message "Use metabase.lib.util/unique-name-generator or non-truncating-unique-name-generator"}}}
|
||||
{}
|
||||
|
||||
:discouraged-namespace
|
||||
{metabase.legacy-mbql.js {:message "Avoid legacy MBQL utils in Lib; move things into Lib if needded."}
|
||||
metabase.legacy-mbql.jvm-util {:message "Avoid legacy MBQL utils in Lib; move things into Lib if needded."}
|
||||
metabase.legacy-mbql.predicates {:message "Avoid legacy MBQL utils in Lib; move things into Lib if needded."}
|
||||
metabase.legacy-mbql.util {:message "Avoid legacy MBQL utils in Lib; move things into Lib if needded."}}}
|
||||
legacy-mbql-namespaces
|
||||
{:linters
|
||||
{:discouraged-namespace
|
||||
{metabase.legacy-mbql.jvm-util {:level :off}
|
||||
metabase.legacy-mbql.normalize {:level :off}
|
||||
metabase.legacy-mbql.predicates {:level :off}
|
||||
metabase.legacy-mbql.schema {:level :off}
|
||||
metabase.legacy-mbql.schema.helpers {:level :off}
|
||||
metabase.legacy-mbql.schema.macros {:level :off}
|
||||
metabase.legacy-mbql.util {:level :off}
|
||||
metabase.query-processor.store {:level :off}}
|
||||
|
||||
;; the `metabase.legacy-mbql` stuff is all deprecated, so we don't need to warn inside the module about other stuff
|
||||
;; in the module being marked deprecated or discouraged.
|
||||
:deprecated-namespace {:level :off}
|
||||
:deprecated-var {:level :off}}}
|
||||
|
||||
driver-namespaces
|
||||
{:linters
|
||||
{:discouraged-var
|
||||
{metabase.driver/database-supports? {:level :off}}}}
|
||||
{metabase.driver/database-supports? {:level :off}}
|
||||
|
||||
;; don't warn about the legacy MBQL namespaces being deprecated or discouraged in driver code now, we don't have a
|
||||
;; real alternative YET so it's not a helpful warning.
|
||||
:discouraged-namespace
|
||||
{metabase.legacy-mbql.jvm-util {:level :off}
|
||||
metabase.legacy-mbql.normalize {:level :off}
|
||||
metabase.legacy-mbql.predicates {:level :off}
|
||||
metabase.legacy-mbql.schema {:level :off}
|
||||
metabase.legacy-mbql.schema.helpers {:level :off}
|
||||
metabase.legacy-mbql.schema.macros {:level :off}
|
||||
metabase.legacy-mbql.util {:level :off}
|
||||
metabase.query-processor.store {:level :off}}
|
||||
|
||||
:deprecated-namespace
|
||||
{:exclude
|
||||
[metabase.driver.common.parameters
|
||||
metabase.driver.common.parameters.dates
|
||||
metabase.driver.common.parameters.operators
|
||||
metabase.driver.common.parameters.parse
|
||||
metabase.driver.common.parameters.values
|
||||
metabase.legacy-mbql.jvm-util
|
||||
metabase.legacy-mbql.normalize
|
||||
metabase.legacy-mbql.predicates
|
||||
metabase.legacy-mbql.schema
|
||||
metabase.legacy-mbql.schema.helpers
|
||||
metabase.legacy-mbql.schema.macros
|
||||
metabase.legacy-mbql.util
|
||||
metabase.query-processor.store]}
|
||||
|
||||
:deprecated-var
|
||||
{:exclude
|
||||
{metabase.legacy-mbql.schema.helpers/is-clause? {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.legacy-mbql.schema.helpers/mbql-clause? {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.legacy-mbql.util/query->source-table-id {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.legacy-mbql.util/aggregation-at-index {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.legacy-mbql.util/assoc-field-options {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.legacy-mbql.util/expression-with-name {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.legacy-mbql.util/field-options {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.legacy-mbql.util/negate-filter-clause {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.legacy-mbql.util/normalize-token {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.legacy-mbql.util/update-field-options {:namespaces ["metabase\\.driver.*"]}}}}}
|
||||
|
||||
performance-sensitive
|
||||
{:linters
|
||||
@@ -865,16 +928,7 @@
|
||||
metabase.lib.core/->legacy-MBQL {:level :off}}}}
|
||||
|
||||
qp-source-namespaces
|
||||
{:linters
|
||||
{:discouraged-namespace
|
||||
{metabase.legacy-mbql.js {:message "Avoid legacy MBQL namespaces in the QP, use Lib instead"}
|
||||
metabase.legacy-mbql.jvm-util {:message "Avoid legacy MBQL namespaces in the QP, use Lib instead"}
|
||||
metabase.legacy-mbql.normalize {:message "Avoid legacy MBQL namespaces in the QP, use Lib instead"}
|
||||
metabase.legacy-mbql.predicates {:message "Avoid legacy MBQL namespaces in the QP, use Lib instead"}
|
||||
metabase.legacy-mbql.schema {:message "Avoid legacy MBQL namespaces in the QP, use Lib instead"}
|
||||
metabase.legacy-mbql.schema.helpers {:message "Avoid legacy MBQL namespaces in the QP, use Lib instead"}
|
||||
metabase.legacy-mbql.schema.macros {:message "Avoid legacy MBQL namespaces in the QP, use Lib instead"}
|
||||
metabase.legacy-mbql.util {:message "Avoid legacy MBQL namespaces in the QP, use Lib instead"}}}}
|
||||
{}
|
||||
|
||||
general-qp-and-driver-test-namespaces
|
||||
{:linters
|
||||
|
||||
@@ -119,9 +119,9 @@
|
||||
metabase.analyze.query-results}
|
||||
:uses #{config
|
||||
driver
|
||||
legacy-mbql
|
||||
lib
|
||||
models
|
||||
query-processor
|
||||
sync
|
||||
util}}
|
||||
|
||||
@@ -329,6 +329,7 @@
|
||||
collections
|
||||
{:team "UX West"
|
||||
:api #{metabase.collections.api
|
||||
metabase.collections.core
|
||||
metabase.collections.models.collection
|
||||
metabase.collections.models.collection.root}
|
||||
:uses #{api
|
||||
@@ -344,6 +345,7 @@
|
||||
permissions
|
||||
premium-features
|
||||
queries
|
||||
remote-sync
|
||||
request
|
||||
revisions
|
||||
search
|
||||
@@ -594,7 +596,6 @@
|
||||
metabase.legacy-mbql.schema
|
||||
metabase.legacy-mbql.util}
|
||||
:uses #{lib
|
||||
models
|
||||
types
|
||||
util}}
|
||||
|
||||
@@ -621,6 +622,7 @@
|
||||
metabase.lib.query
|
||||
metabase.lib.schema
|
||||
metabase.lib.schema.actions
|
||||
metabase.lib.schema.aggregation
|
||||
metabase.lib.schema.binning
|
||||
metabase.lib.schema.common
|
||||
metabase.lib.schema.constraints
|
||||
@@ -709,8 +711,7 @@
|
||||
|
||||
models
|
||||
{:team "DevEx"
|
||||
:api #{metabase.models.dispatch
|
||||
metabase.models.humanization
|
||||
:api #{metabase.models.humanization
|
||||
metabase.models.init
|
||||
metabase.models.interface
|
||||
metabase.models.resolution
|
||||
@@ -783,7 +784,6 @@
|
||||
:uses #{api
|
||||
app-db
|
||||
classloader
|
||||
legacy-mbql
|
||||
lib
|
||||
lib-be
|
||||
models
|
||||
@@ -806,6 +806,7 @@
|
||||
lib
|
||||
models
|
||||
premium-features
|
||||
remote-sync
|
||||
request
|
||||
settings
|
||||
util
|
||||
@@ -847,7 +848,6 @@
|
||||
app-db
|
||||
channel
|
||||
config
|
||||
driver
|
||||
premium-features
|
||||
settings
|
||||
task
|
||||
@@ -921,7 +921,6 @@
|
||||
eid-translation
|
||||
embedding
|
||||
events
|
||||
legacy-mbql
|
||||
lib
|
||||
lib-be
|
||||
models
|
||||
@@ -1020,6 +1019,14 @@
|
||||
users
|
||||
util}}
|
||||
|
||||
remote-sync
|
||||
{:team "UX West"
|
||||
:api #{metabase.remote-sync.core
|
||||
metabase.remote-sync.init}
|
||||
:uses #{api
|
||||
models
|
||||
premium-features}}
|
||||
|
||||
request
|
||||
{:team "UX West"
|
||||
:api #{metabase.request.core
|
||||
@@ -1098,7 +1105,8 @@
|
||||
|
||||
segments
|
||||
{:team "Querying"
|
||||
:api #{metabase.segments.api}
|
||||
:api #{metabase.segments.api
|
||||
metabase.segments.schema}
|
||||
:uses #{api
|
||||
events
|
||||
legacy-mbql
|
||||
@@ -1147,7 +1155,6 @@
|
||||
app-db
|
||||
channel
|
||||
config
|
||||
driver
|
||||
events
|
||||
login-history
|
||||
request
|
||||
@@ -1303,6 +1310,8 @@
|
||||
:uses #{analytics
|
||||
api
|
||||
collections
|
||||
config
|
||||
events
|
||||
models
|
||||
util}}
|
||||
|
||||
@@ -1320,10 +1329,8 @@
|
||||
:uses #{analytics
|
||||
api
|
||||
appearance
|
||||
collections
|
||||
driver
|
||||
events
|
||||
legacy-mbql
|
||||
lib
|
||||
model-persistence
|
||||
models
|
||||
@@ -1490,6 +1497,7 @@
|
||||
queries
|
||||
query-permissions
|
||||
query-processor
|
||||
segments
|
||||
settings
|
||||
util
|
||||
warehouse-schema}}
|
||||
@@ -1710,7 +1718,7 @@
|
||||
enterprise/dependencies
|
||||
{:team "Querying"
|
||||
:api #{metabase-enterprise.dependencies.api
|
||||
#_metabase-enterprise.dependencies.core
|
||||
metabase-enterprise.dependencies.core
|
||||
metabase-enterprise.dependencies.init}
|
||||
:uses #{analyze
|
||||
api
|
||||
@@ -1726,15 +1734,18 @@
|
||||
premium-features
|
||||
queries
|
||||
query-processor
|
||||
revisions
|
||||
settings
|
||||
task
|
||||
util}}
|
||||
util
|
||||
enterprise/documents}}
|
||||
|
||||
enterprise/documents
|
||||
{:team "UX West"
|
||||
:api #{metabase-enterprise.documents.api
|
||||
metabase-enterprise.documents.core
|
||||
metabase-enterprise.documents.init}
|
||||
metabase-enterprise.documents.init
|
||||
metabase-enterprise.documents.prose-mirror}
|
||||
:uses #{activity-feed
|
||||
api
|
||||
app-db
|
||||
@@ -1838,6 +1849,7 @@
|
||||
lib
|
||||
lib-be
|
||||
models
|
||||
native-query-snippets
|
||||
permissions
|
||||
premium-features
|
||||
pulse
|
||||
@@ -1854,7 +1866,10 @@
|
||||
util
|
||||
warehouse-schema
|
||||
warehouses
|
||||
enterprise/documents}}
|
||||
enterprise/dependencies
|
||||
enterprise/documents
|
||||
enterprise/transforms
|
||||
enterprise/transforms-python}}
|
||||
|
||||
enterprise/permission-debug
|
||||
{:team "UX West"
|
||||
@@ -1872,6 +1887,24 @@
|
||||
:uses #{premium-features
|
||||
util}}
|
||||
|
||||
enterprise/remote-sync
|
||||
{:team "UX West"
|
||||
:api #{metabase-enterprise.remote-sync.api
|
||||
metabase-enterprise.remote-sync.core
|
||||
metabase-enterprise.remote-sync.init}
|
||||
:uses #{analytics
|
||||
api
|
||||
app-db
|
||||
collections
|
||||
events
|
||||
models
|
||||
premium-features
|
||||
settings
|
||||
startup
|
||||
task
|
||||
util
|
||||
enterprise/serialization}}
|
||||
|
||||
enterprise/sandbox
|
||||
{:team "UX West"
|
||||
:api #{metabase-enterprise.sandbox.api.routes
|
||||
@@ -1880,6 +1913,7 @@
|
||||
app-db
|
||||
audit-app
|
||||
driver
|
||||
events
|
||||
legacy-mbql
|
||||
lib
|
||||
models
|
||||
@@ -1941,6 +1975,7 @@
|
||||
{:team "Workflows"
|
||||
:api #{metabase-enterprise.serialization.api
|
||||
metabase-enterprise.serialization.cmd
|
||||
metabase-enterprise.serialization.core
|
||||
metabase-enterprise.serialization.v2.backfill-ids}
|
||||
:uses #{analytics
|
||||
api
|
||||
@@ -2004,6 +2039,7 @@
|
||||
metabase-enterprise.transforms.core
|
||||
metabase-enterprise.transforms.init
|
||||
metabase-enterprise.transforms.instrumentation
|
||||
metabase-enterprise.transforms.interface
|
||||
metabase-enterprise.transforms.util}
|
||||
:uses #{analytics
|
||||
api
|
||||
@@ -2014,21 +2050,22 @@
|
||||
lib-be
|
||||
models
|
||||
premium-features
|
||||
queries
|
||||
query-processor
|
||||
request
|
||||
search
|
||||
settings
|
||||
sync
|
||||
task
|
||||
task-history
|
||||
util
|
||||
enterprise/transforms-python}}
|
||||
util}}
|
||||
|
||||
enterprise/transforms-python
|
||||
{:team "Querying"
|
||||
:api #{metabase-enterprise.transforms-python.api
|
||||
metabase-enterprise.transforms-python.execute
|
||||
metabase-enterprise.transforms-python.init}
|
||||
:uses #{api
|
||||
:uses #{analytics
|
||||
api
|
||||
app-db
|
||||
config
|
||||
driver
|
||||
|
||||
@@ -4,7 +4,6 @@ FROM mcr.microsoft.com/vscode/devcontainers/java:21
|
||||
|
||||
RUN ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash ) \
|
||||
&& export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-key adv --refresh-keys --keyserver keyserver.ubuntu.com \
|
||||
&& apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig
|
||||
|
||||
# install Clojure
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
.babel_cache
|
||||
docs/*
|
||||
target/*
|
||||
.circleci
|
||||
.cpcache
|
||||
|
||||
@@ -136,7 +136,7 @@ module.exports = {
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
es2020: true,
|
||||
commonjs: true,
|
||||
jest: true,
|
||||
"jest/globals": true,
|
||||
@@ -203,6 +203,7 @@ module.exports = {
|
||||
"frontend/src/metabase/admin/**/*",
|
||||
"frontend/src/metabase/setup/**/*",
|
||||
"enterprise/frontend/src/metabase-enterprise/whitelabel/**/*",
|
||||
"enterprise/frontend/src/metabase-enterprise/embedding/**/*",
|
||||
"frontend/lint/**/*",
|
||||
"*.stories.*",
|
||||
"**/.storybook/*",
|
||||
|
||||
@@ -17,8 +17,6 @@ runs:
|
||||
|
||||
- name: Prepare backend environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: cross-branch-migrations
|
||||
|
||||
- name: Run backend on base branch
|
||||
run: |
|
||||
|
||||
27
.github/actions/get-cache-keys/action.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Get cache keys
|
||||
description: |
|
||||
Get deterministic cache keys for Maven and Node.js caches based on the centrally controlled cache prefix,
|
||||
and the suffix based on the runner OS and the current week of the year.
|
||||
|
||||
outputs:
|
||||
m2-cache-key:
|
||||
description: "The cache key for the Maven cache."
|
||||
value: ${{ steps.keys-factory.outputs.m2-cache-key }}
|
||||
node-cache-key:
|
||||
description: "The cache key for the Node.js cache."
|
||||
value: ${{ steps.keys-factory.outputs.node-cache-key }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Generate and output cache keys
|
||||
id: keys-factory
|
||||
run: |
|
||||
M2_CACHE_PREFIX='M2'
|
||||
NODE_CACHE_PREFIX='node-modules'
|
||||
WEEK_OF_YEAR=$(/bin/date "+%G-%V")
|
||||
CACHE_SUFFIX="${{ runner.os }}-$WEEK_OF_YEAR"
|
||||
|
||||
echo "m2-cache-key=$M2_CACHE_PREFIX-$CACHE_SUFFIX" >> $GITHUB_OUTPUT
|
||||
echo "node-cache-key=$NODE_CACHE_PREFIX-$CACHE_SUFFIX" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
27
.github/actions/prepare-backend/action.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: Prepare back-end environment
|
||||
description: |
|
||||
Prepare the backend. Installs jdk, Clojure, and fetches the cache for m2. The CI config fetchs `ci-test-config.json`
|
||||
from master and lets us ignore tests at the var level if they are flaking.
|
||||
Prepare the backend. Installs jdk, Clojure, and fetches the cache for m2.
|
||||
The CI config fetches `ci-test-config.json` from master and lets us ignore tests at the var level if they are flaking.
|
||||
inputs:
|
||||
java-version:
|
||||
required: true
|
||||
@@ -9,10 +9,6 @@ inputs:
|
||||
clojure-version:
|
||||
required: true
|
||||
default: '1.12.0.1488'
|
||||
m2-cache-key:
|
||||
description: 'Key to cache M2 packages from Maven Central'
|
||||
required: true
|
||||
default: 'm2'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
@@ -28,21 +24,20 @@ runs:
|
||||
run: |
|
||||
curl -O https://download.clojure.org/install/linux-install-${{ inputs.clojure-version }}.sh &&
|
||||
sudo bash ./linux-install-${{ inputs.clojure-version }}.sh
|
||||
|
||||
- name: Fetch CI config
|
||||
shell: bash
|
||||
run: |
|
||||
curl -o ci-test-config.json https://raw.githubusercontent.com/metabase/metabase/refs/heads/master/ci-test-config.json
|
||||
- name: Check to see if dependencies should be cached
|
||||
if: ${{ contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
run: echo "Commit message includes [ci nocache]; dependencies will NOT be cached"
|
||||
shell: bash
|
||||
- name: Get M2 cache
|
||||
uses: actions/cache@v4
|
||||
if: ${{ !contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
|
||||
- name: Get M2 cache key
|
||||
uses: ./.github/actions/get-cache-keys
|
||||
id: get-cache-keys
|
||||
|
||||
- name: Restore M2 cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
~/.m2
|
||||
~/.gitlibs
|
||||
key: ${{ runner.os }}-${{ inputs.m2-cache-key }}-${{ hashFiles('**/deps.edn') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ inputs.m2-cache-key }}-
|
||||
key: ${{ steps.get-cache-keys.outputs.m2-cache-key }}
|
||||
|
||||
10
.github/actions/prepare-cypress/action.yml
vendored
@@ -22,16 +22,16 @@ runs:
|
||||
chrome-version: 1097615
|
||||
id: setup-chrome
|
||||
|
||||
- name: Check to see if dependencies should be cached
|
||||
if: ${{ contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
run: echo "Commit message includes [ci nocache]; dependencies will NOT be cached"
|
||||
- name: Get current week of year
|
||||
id: get-date
|
||||
run: |
|
||||
echo "week-of-year=$(/bin/date "+%G-%V")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
- name: Get Cypress cache
|
||||
uses: actions/cache@v4
|
||||
if: ${{ !contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
with:
|
||||
path: ~/.cache/Cypress
|
||||
key: ${{ runner.os }}-Cypress-${{ hashFiles('**/yarn.lock') }}
|
||||
key: ${{ runner.os }}-Cypress-${{ steps.get-date.outputs.week-of-year }}
|
||||
- name: Ensure that Cypress executable is ready
|
||||
run: |
|
||||
yarn cypress install
|
||||
|
||||
44
.github/actions/prepare-frontend/action.yml
vendored
@@ -3,6 +3,10 @@ inputs:
|
||||
node-version:
|
||||
description: "The version of Node.js to use, overriding .nvmrc"
|
||||
required: false
|
||||
apply-patches:
|
||||
description: "Whether to patch frontend dependencies with patch-package."
|
||||
required: true
|
||||
default: 'true'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
@@ -12,26 +16,32 @@ runs:
|
||||
node-version: ${{ inputs.node-version }} # this overrides, if present
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Check to see if dependencies should be cached
|
||||
if: ${{ contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
run: |
|
||||
echo "Commit message includes [ci nocache]; dependencies will NOT be cached"
|
||||
yarn cache clean
|
||||
shell: bash
|
||||
- name: Get M2 cache
|
||||
uses: actions/cache@v4
|
||||
if: ${{ !contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-cljs-${{ hashFiles('**/shadow-cljs.edn') }}
|
||||
- name: Get cache keys
|
||||
uses: ./.github/actions/get-cache-keys
|
||||
id: get-cache-keys
|
||||
|
||||
- name: Get node_modules cache
|
||||
uses: actions/cache@v4
|
||||
- name: Restore M2 cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
~/.m2
|
||||
~/.gitlibs
|
||||
key: ${{ steps.get-cache-keys.outputs.m2-cache-key }}
|
||||
|
||||
- name: Restore node_modules cache
|
||||
uses: actions/cache/restore@v4
|
||||
id: node-modules-cache
|
||||
if: ${{ !contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock', '**/patches/*.patch') }}
|
||||
key: ${{ steps.get-cache-keys.outputs.node-cache-key }}
|
||||
|
||||
- run: yarn install --frozen-lockfile --prefer-offline
|
||||
# postinstall lifecycle hook can be dangerous in CI so we only run it locally (see package.json)
|
||||
# If a job wants to patch packages, it does so explicitly in the CI. This setting is opt-out.
|
||||
# For example, we never want to cache node_modules with patches already applied so cache-generator.yml skips that step.
|
||||
- name: Clean install
|
||||
run: yarn install --frozen-lockfile --prefer-offline
|
||||
shell: bash
|
||||
- name: Patch frontend dependencies
|
||||
if: inputs.apply-patches == 'true'
|
||||
run: yarn patch-package
|
||||
shell: bash
|
||||
|
||||
@@ -7,8 +7,6 @@ runs:
|
||||
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
|
||||
- name: Compile CLJS
|
||||
run: yarn build-pure:cljs
|
||||
|
||||
2
.github/actions/test-driver/action.yml
vendored
@@ -15,8 +15,6 @@ runs:
|
||||
steps:
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: driver
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
if: ${{ inputs.build-static-viz == 'true' }}
|
||||
|
||||
41
.github/actions/update-cache/action.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Update cache
|
||||
description: |
|
||||
Update a GitHub Actions cache based on a provided path and key.
|
||||
If a cache entry already exists for the given key, it is first removed.
|
||||
This ensures immutability of cache entries, and prevents runtime errors.
|
||||
|
||||
inputs:
|
||||
path:
|
||||
description: "The path(s) to cache, separated by newlines."
|
||||
required: true
|
||||
key:
|
||||
description: "The cache key to use."
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Check if the cache entry exists
|
||||
id: cache-lookup
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
key: ${{ inputs.key }}
|
||||
lookup-only: true # Important bit: the action will not fetch anything, just check for the cache existence.
|
||||
- name: Delete the cache entry if it exists
|
||||
if: ${{ steps.cache-lookup.outputs.cache-hit == 'true' }}
|
||||
run: |
|
||||
echo "Cache entry found for key '${{ inputs.key }}'. Deleting it to ensure immutability."
|
||||
gh api \
|
||||
--method DELETE \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
/repos/${{ github.repository }}/actions/caches?key=${{ inputs.key }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
shell: bash
|
||||
- name: Save the new cache entry
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
key: ${{ inputs.key }}
|
||||
@@ -55,4 +55,3 @@ runs:
|
||||
variant: ${{ inputs.variant || inputs.output-name }}
|
||||
org-slug: metabase
|
||||
token: ${{ inputs.trunk-api-token }}
|
||||
continue-on-error: true
|
||||
|
||||
1
.github/scripts/build-e2e-matrix.js
vendored
@@ -18,6 +18,7 @@ const specialTestConfigs = [
|
||||
specs: DEFAULT_SPEC_PATTERN,
|
||||
},
|
||||
{ name: "mongo", tags: "@mongo", specs: DEFAULT_SPEC_PATTERN },
|
||||
{ name: "python", tags: "@python", specs: DEFAULT_SPEC_PATTERN },
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
18
.github/scripts/build-e2e-matrix.unit.spec.js
vendored
@@ -11,7 +11,7 @@ describe("buildMatrix", () => {
|
||||
it("should calculate correct regular chunks with default parameters", () => {
|
||||
const result = testBuildMatrix("./e2e/test/scenarios/**/*.cy.spec.*", 30);
|
||||
|
||||
expect(result.regularChunks).toBe(27);
|
||||
expect(result.regularChunks).toBe(26);
|
||||
});
|
||||
|
||||
it("should create correct number of configuration objects", () => {
|
||||
@@ -21,10 +21,10 @@ describe("buildMatrix", () => {
|
||||
});
|
||||
|
||||
it("should apply default specs path when empty entry is provided", () => {
|
||||
const result = testBuildMatrix("", 5);
|
||||
const result = testBuildMatrix("", 6);
|
||||
|
||||
expect(result.regularChunks).toBe(2);
|
||||
expect(result.config.length).toBe(5);
|
||||
expect(result.config.length).toBe(6);
|
||||
});
|
||||
|
||||
it("should name regular test groups sequentially", () => {
|
||||
@@ -39,13 +39,14 @@ describe("buildMatrix", () => {
|
||||
});
|
||||
|
||||
it("should handle case when input chunks equals special tests count", () => {
|
||||
const result = testBuildMatrix("./e2e/test/scenarios/**/*.cy.spec.*", 3);
|
||||
const result = testBuildMatrix("./e2e/test/scenarios/**/*.cy.spec.*", 4);
|
||||
|
||||
expect(result.regularChunks).toBe(0);
|
||||
expect(result.config.length).toBe(3);
|
||||
expect(result.config.length).toBe(4);
|
||||
expect(result.config[0].name).toBe("embedding-sdk");
|
||||
expect(result.config[1].name).toBe("oss-subset");
|
||||
expect(result.config[2].name).toBe("mongo");
|
||||
expect(result.config[3].name).toBe("python");
|
||||
});
|
||||
|
||||
it("should correctly calculate regularChunks for non-default spec pattern", () => {
|
||||
@@ -83,9 +84,10 @@ describe("buildMatrix", () => {
|
||||
it("should return special test configs when default spec pattern is provided", () => {
|
||||
const result = testBuildMatrix("./e2e/test/scenarios/**/*.cy.spec.*", 50);
|
||||
|
||||
expect(result.config[47].name).toBe("embedding-sdk");
|
||||
expect(result.config[48].name).toBe("oss-subset");
|
||||
expect(result.config[49].name).toBe("mongo");
|
||||
expect(result.config[46].name).toBe("embedding-sdk");
|
||||
expect(result.config[47].name).toBe("oss-subset");
|
||||
expect(result.config[48].name).toBe("mongo");
|
||||
expect(result.config[49].name).toBe("python");
|
||||
});
|
||||
|
||||
it("should not return special test configs when non-default spec pattern is provided", () => {
|
||||
|
||||
19
.github/team.json
vendored
@@ -38,8 +38,7 @@
|
||||
"members": [
|
||||
"piranha",
|
||||
"crisptrutski",
|
||||
"spalt08",
|
||||
"kulyk"
|
||||
"spalt08"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -54,7 +53,10 @@
|
||||
"label": ".Team/DevEx",
|
||||
"members": [
|
||||
"camsaul",
|
||||
"escherize"
|
||||
"dpsutton",
|
||||
"escherize",
|
||||
"fraserdrops",
|
||||
"nemanjaglumac"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -70,14 +72,6 @@
|
||||
"lbrdnk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Product Growth",
|
||||
"label": ".Team/ProductGrowth",
|
||||
"members": [
|
||||
"nemanjaglumac",
|
||||
"andsalves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cloud",
|
||||
"label": "cloud",
|
||||
@@ -104,7 +98,8 @@
|
||||
"edpaget",
|
||||
"deniskaber",
|
||||
"alxnddr",
|
||||
"bpander"
|
||||
"bpander",
|
||||
"andsalves"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
9
.github/workflows/auto-assign.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ steps.generate-token.outputs.token }}
|
||||
script: |
|
||||
script: | #js
|
||||
const fs = require('fs');
|
||||
const teamConfig = JSON.parse(fs.readFileSync('.github/team.json', 'utf-8'));
|
||||
const prAuthor = context.payload.pull_request.user.login;
|
||||
@@ -65,10 +65,3 @@ jobs:
|
||||
issue_number: prNumber,
|
||||
labels: [team.label]
|
||||
});
|
||||
|
||||
return team.projectUrl || null;
|
||||
- uses: actions/add-to-project@v0.5.0
|
||||
if: ${{ steps.auto-assign.outputs.result != 'null' }}
|
||||
with:
|
||||
project-url: ${{ steps.auto-assign.outputs.result }}
|
||||
github-token: ${{ steps.generate-token.outputs.token }}
|
||||
|
||||
2
.github/workflows/backend-cloverage.yml
vendored
@@ -15,8 +15,6 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cloverage"
|
||||
- name: Build static viz frontend
|
||||
run: yarn build-static-viz
|
||||
env:
|
||||
|
||||
9
.github/workflows/backend.yml
vendored
@@ -21,8 +21,6 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'kondo'
|
||||
- name: Run clj-kondo
|
||||
run: ./bin/mage kondo
|
||||
|
||||
@@ -35,8 +33,6 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "eastwood"
|
||||
- run: clojure -X:dev:ee:ee-dev:drivers:drivers-dev:test:eastwood
|
||||
name: Run Eastwood linter
|
||||
|
||||
@@ -112,7 +108,6 @@ jobs:
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: be-tests
|
||||
java-version: "${{ matrix.java-version }}"
|
||||
# Depending on which files changed, we might either have to build static-viz
|
||||
# from scratch or download the previously built artifact
|
||||
@@ -180,8 +175,6 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare backend
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: be-check
|
||||
# TODO -- we should probably also check WITHOUT ee -- do a check with only OSS namespaces on the classpath
|
||||
- name: Check namespaces
|
||||
run: clojure -M:ee:drivers:check
|
||||
@@ -195,8 +188,6 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'cljfmt'
|
||||
- name: Run cljfmt
|
||||
run: ./bin/mage cljfmt-all --force-check
|
||||
|
||||
|
||||
2
.github/workflows/build-scripts.yml
vendored
@@ -16,8 +16,6 @@ jobs:
|
||||
- name: Prepare back-end environment
|
||||
timeout-minutes: 5
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'build-scripts'
|
||||
|
||||
- name: Run build and release script tests
|
||||
run: clojure -X:dev:drivers:build:build-dev:build-test:ci
|
||||
|
||||
99
.github/workflows/cache-generator.yml
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
# This workflow is the single source of truth for generating and updating various caches used by our CI pipeline.
|
||||
# It sets the fresh cache each Monday but provides a manual trigger to update it on-demand.
|
||||
#
|
||||
# All other jobs only restore from this cache; *they never update it*!
|
||||
# They should always use `actions/cache/restore@v4` because `actions/cache@v4` would attempt to save the cache.
|
||||
#
|
||||
# Our agreed-upon strategy is to use a deterministic cache key based on the week of the year.
|
||||
# Jobs can utilize the prior week's cache if the current week's cache is not found.
|
||||
#
|
||||
#
|
||||
# PRINCIPLES:
|
||||
# - The cache is never wrong!
|
||||
# - Caches are immutable once created.
|
||||
# - Caches are for speeding up builds, not for correctness.
|
||||
# - It is faster to download a large cache than to re-resolve missing dependencies.
|
||||
#
|
||||
#
|
||||
# DESIGN:
|
||||
#
|
||||
# 1. Prepare
|
||||
# - A job first prepares the local environment (e.g., installs JDK, Clojure, Node.js, etc.)
|
||||
# - This fetches the dependencies from the cache (if it exists) and warms up the local cache for this workflow.
|
||||
# 2. Resolve
|
||||
# - The next step pre-resolves all dependencies, ensuring that the local cache is fully populated and up-to-date.
|
||||
# 3. Update
|
||||
# - The final step saves the local cache back to GitHub Actions cache with a deterministic key.
|
||||
# - If a cache entry already exists for that key, it is deleted first to ensure immutability.
|
||||
#
|
||||
name: Cache Generator
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 * * 1' # Mondays at 03:00 UTC
|
||||
workflow_dispatch: # manually update the cache
|
||||
|
||||
concurrency:
|
||||
group: cache-generator
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
get-cache-keys:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Get cache keys
|
||||
uses: ./.github/actions/get-cache-keys
|
||||
id: get-cache-keys
|
||||
outputs:
|
||||
m2-cache-key: ${{ steps.get-cache-keys.outputs.m2-cache-key }}
|
||||
node-cache-key: ${{ steps.get-cache-keys.outputs.node-cache-key }}
|
||||
|
||||
generate-m2-cache:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
needs: get-cache-keys
|
||||
env:
|
||||
M2_CACHE_KEY: ${{ needs.get-cache-keys.outputs.m2-cache-key }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare backend
|
||||
uses: ./.github/actions/prepare-backend
|
||||
|
||||
# Add or remove aliases to affect the cache size and its contents.
|
||||
# Adjust to taste, then redeploy this workflow.
|
||||
- name: Pre-resolve dependencies
|
||||
run: clojure -A:build:dev:ee:ee-dev:drivers:drivers-dev:cljs -P
|
||||
|
||||
- name: Update M2 cache
|
||||
uses: ./.github/actions/update-cache
|
||||
with:
|
||||
path: |
|
||||
~/.m2
|
||||
~/.gitlibs
|
||||
key: ${{ env.M2_CACHE_KEY }}
|
||||
|
||||
generate-node-modules-cache:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
needs: get-cache-keys
|
||||
env:
|
||||
NODE_CACHE_KEY: ${{ needs.get-cache-keys.outputs.node-cache-key }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# `prepare-frontend` action (1) prepares Node.js and (2) fetches the node_modules cache if it exists.
|
||||
# It then (3) runs `yarn install --frozen-lockfile --prefer-offline` which ensures the local cache is fully populated.
|
||||
# IMPORTANT: Caching node_modules after patches are already applied will break any PR that attempts to either:
|
||||
# - upgrade a patched library
|
||||
# - change a patch
|
||||
# Hence why we explicitly exclude patches from the cache (controlled by the `apply-patches` action input).
|
||||
- name: Install front-end dependencies
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
with:
|
||||
apply-patches: 'false'
|
||||
|
||||
- name: Update node_modules cache
|
||||
uses: ./.github/actions/update-cache
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ env.NODE_CACHE_KEY }}
|
||||
2
.github/workflows/chromatic.yml
vendored
@@ -40,8 +40,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Compile CLJS
|
||||
run: NODE_ENV=development yarn build-pure:cljs
|
||||
- name: Publish to Chromatic
|
||||
|
||||
6
.github/workflows/claude-code-review.yaml
vendored
@@ -2,18 +2,14 @@ name: "Claude Code Review"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled, unlabeled]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}-claude-code-review
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
EXCLUDED_PR_AUTHORS: '["kamilmielnik", "romeovs"]'
|
||||
|
||||
jobs:
|
||||
review:
|
||||
if: github.event.pull_request.draft == false && !contains(fromJSON(env.EXCLUDED_PR_AUTHORS), github.event.pull_request.user.login) }}
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
2
.github/workflows/cljs.yml
vendored
@@ -38,7 +38,5 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'cljs'
|
||||
- name: Run Cljs tests
|
||||
run: yarn run test-cljs
|
||||
|
||||
15
.github/workflows/coverage.yml
vendored
@@ -1,25 +1,28 @@
|
||||
name: Test coverage
|
||||
name: Frontend Test Coverage
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '40 1 * * *' # every day at 1:40
|
||||
|
||||
jobs:
|
||||
fe-test-coverage:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Run frontend unit tests
|
||||
run: yarn run test-unit --silent --coverage
|
||||
run: |
|
||||
yarn run test-unit \
|
||||
--silent \
|
||||
--coverage \
|
||||
--testTimeout=60000
|
||||
- name: Upload coverage to codecov.io
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: ./coverage/lcov.info
|
||||
flags: front-end
|
||||
|
||||
6
.github/workflows/docs-generate-base.yml
vendored
@@ -9,10 +9,6 @@ on:
|
||||
description: "The branch to check out and create a PR against"
|
||||
required: true
|
||||
type: string
|
||||
m2_cache_key_suffix:
|
||||
description: "A unique suffix for the Maven cache key"
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
automation_token:
|
||||
description: "A token with permissions to create branches and PRs"
|
||||
@@ -37,8 +33,6 @@ jobs:
|
||||
|
||||
- name: Prepare backend environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "auto-update-docs-${{ inputs.m2_cache_key_suffix }}"
|
||||
|
||||
- name: Generate environment variables documentation
|
||||
id: generate_env_docs
|
||||
|
||||
1
.github/workflows/docs-master-generate.yml
vendored
@@ -11,6 +11,5 @@ jobs:
|
||||
uses: ./.github/workflows/docs-generate-base.yml
|
||||
with:
|
||||
target_branch: "master"
|
||||
m2_cache_key_suffix: "master"
|
||||
secrets:
|
||||
automation_token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
|
||||
1
.github/workflows/docs-release-generate.yml
vendored
@@ -11,6 +11,5 @@ jobs:
|
||||
uses: ./.github/workflows/docs-generate-base.yml
|
||||
with:
|
||||
target_branch: "release-x.56.x"
|
||||
m2_cache_key_suffix: "release"
|
||||
secrets:
|
||||
automation_token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
|
||||
126
.github/workflows/drivers.yml
vendored
@@ -1020,72 +1020,75 @@ jobs:
|
||||
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
|
||||
logs-artifact-suffix: ${{ matrix.job.name }} ${{ matrix.version.name }}
|
||||
|
||||
be-tests-snowflake-ee:
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- name: Driver Tests
|
||||
test-args: >-
|
||||
:only-tags [:mb/driver-tests]
|
||||
:exclude-tags [:mb/transforms-python-test]
|
||||
# dan sutton 2025-10-23: disable snowflake because of account
|
||||
# issues. https://linear.app/metabase/issue/DEV-997/reenable-snowflake-in-ci. Note that the transforms tests were
|
||||
# disabled previously
|
||||
# be-tests-snowflake-ee:
|
||||
# if: ${{ !inputs.skip }}
|
||||
# runs-on: ubuntu-22.04
|
||||
# timeout-minutes: 60
|
||||
# strategy:
|
||||
# fail-fast: false
|
||||
# matrix:
|
||||
# job:
|
||||
# - name: Driver Tests
|
||||
# test-args: >-
|
||||
# :only-tags [:mb/driver-tests]
|
||||
# :exclude-tags [:mb/transforms-python-test]
|
||||
# DS 2025-09-26 temporarily disabled while we diagnose flakes
|
||||
# - name: Transforms Python Tests
|
||||
# test-args: >-
|
||||
# :only-tags [:mb/transforms-python-test]
|
||||
# needs-python-runner: true
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: snowflake
|
||||
MB_SNOWFLAKE_TEST_USER: METABASE CI
|
||||
MB_SNOWFLAKE_TEST_ACCOUNT: ${{ secrets.MB_SNOWFLAKE_TEST_ACCOUNT }}
|
||||
MB_SNOWFLAKE_TEST_PASSWORD: ${{ secrets.MB_SNOWFLAKE_TEST_PASSWORD }}
|
||||
MB_SNOWFLAKE_TEST_WAREHOUSE: ${{ secrets.MB_SNOWFLAKE_TEST_WAREHOUSE }}
|
||||
MB_SNOWFLAKE_TEST_PK_USER: METABASE PK
|
||||
MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY }}
|
||||
MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY_2: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY_2 }}
|
||||
MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY }}
|
||||
MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY_2: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY_2 }}
|
||||
# env:
|
||||
# CI: 'true'
|
||||
# DRIVERS: snowflake
|
||||
# MB_SNOWFLAKE_TEST_USER: METABASE CI
|
||||
# MB_SNOWFLAKE_TEST_ACCOUNT: ${{ secrets.MB_SNOWFLAKE_TEST_ACCOUNT }}
|
||||
# MB_SNOWFLAKE_TEST_PASSWORD: ${{ secrets.MB_SNOWFLAKE_TEST_PASSWORD }}
|
||||
# MB_SNOWFLAKE_TEST_WAREHOUSE: ${{ secrets.MB_SNOWFLAKE_TEST_WAREHOUSE }}
|
||||
# MB_SNOWFLAKE_TEST_PK_USER: METABASE PK
|
||||
# MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY }}
|
||||
# MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY_2: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY_2 }}
|
||||
# MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY }}
|
||||
# MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY_2: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY_2 }}
|
||||
|
||||
# RSA Role testing:
|
||||
MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_DEFAULT_USER: RSA_ROLE_TEST_DEFAULT_USER
|
||||
MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_CUSTOM_USER: RSA_ROLE_TEST_CUSTOM_USER
|
||||
MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_ROLE: RSA_ROLE_TEST_ROLE
|
||||
MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_DB: RSA_ROLE_TEST_DB
|
||||
name: Snowflake ${{ matrix.job.name }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup python-runner
|
||||
if: ${{ matrix.job.needs-python-runner == true }}
|
||||
uses: ./.github/actions/setup-python-runner
|
||||
with:
|
||||
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
- name: Test Snowflake driver
|
||||
id: test-driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-snowflake-ee'
|
||||
test-args: ${{ matrix.job.test-args }}
|
||||
- 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 }}
|
||||
- name: Cleanup python-runner
|
||||
if: ${{ always() && matrix.job.needs-python-runner == true }}
|
||||
uses: ./.github/actions/cleanup-python-runner
|
||||
with:
|
||||
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
|
||||
logs-artifact-suffix: ${{ matrix.job.name }} ${{ matrix.version.name }}
|
||||
# # RSA Role testing:
|
||||
# MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_DEFAULT_USER: RSA_ROLE_TEST_DEFAULT_USER
|
||||
# MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_CUSTOM_USER: RSA_ROLE_TEST_CUSTOM_USER
|
||||
# MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_ROLE: RSA_ROLE_TEST_ROLE
|
||||
# MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_DB: RSA_ROLE_TEST_DB
|
||||
# name: Snowflake ${{ matrix.job.name }}
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - name: Setup python-runner
|
||||
# if: ${{ matrix.job.needs-python-runner == true }}
|
||||
# uses: ./.github/actions/setup-python-runner
|
||||
# with:
|
||||
# metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
# - name: Test Snowflake driver
|
||||
# id: test-driver
|
||||
# uses: ./.github/actions/test-driver
|
||||
# with:
|
||||
# junit-name: 'be-tests-snowflake-ee'
|
||||
# test-args: ${{ matrix.job.test-args }}
|
||||
# - 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 }}
|
||||
# - name: Cleanup python-runner
|
||||
# if: ${{ always() && matrix.job.needs-python-runner == true }}
|
||||
# uses: ./.github/actions/cleanup-python-runner
|
||||
# with:
|
||||
# upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
|
||||
# logs-artifact-suffix: ${{ matrix.job.name }} ${{ matrix.version.name }}
|
||||
|
||||
be-tests-sparksql-ee:
|
||||
needs: determine-driver-skips
|
||||
@@ -1349,7 +1352,8 @@ jobs:
|
||||
- be-tests-postgres
|
||||
- be-tests-presto-jdbc-ee
|
||||
- be-tests-redshift-ee
|
||||
- be-tests-snowflake-ee
|
||||
# dan: disabled for account reasons. https://linear.app/metabase/issue/DEV-997/reenable-snowflake-in-ci
|
||||
# - be-tests-snowflake-ee
|
||||
- be-tests-sparksql-ee
|
||||
- be-tests-sqlite-ee
|
||||
- be-tests-sqlserver
|
||||
|
||||
@@ -112,7 +112,6 @@ jobs:
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: uberjar
|
||||
java-version: "${{ needs.get-build-requirements.outputs.java_version || 21 }}"
|
||||
|
||||
- name: Prepare front-end environment
|
||||
|
||||
@@ -83,7 +83,6 @@ jobs:
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: uberjar
|
||||
java-version: "${{ needs.get-build-requirements.outputs.java_version || 21 }}"
|
||||
|
||||
- name: Build uberjar with ./bin/build.sh
|
||||
@@ -144,8 +143,6 @@ jobs:
|
||||
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
|
||||
- name: Retrieve Embedding SDK dist artifact
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
@@ -167,7 +167,6 @@ jobs:
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: uberjar
|
||||
java-version: "${{ needs.get-build-requirements.outputs.java_version || 21 }}"
|
||||
|
||||
- name: Build uberjar with ./bin/build.sh
|
||||
@@ -179,7 +178,11 @@ jobs:
|
||||
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
|
||||
|
||||
- name: Build Embedding SDK package
|
||||
run: yarn build-embedding-sdk-package
|
||||
run: |
|
||||
# Remove the matchers to not report false positives on every PR
|
||||
# unrelated to embedding (EMB-765)
|
||||
echo "::remove-matcher owner=tsc::"
|
||||
yarn build-embedding-sdk-package
|
||||
|
||||
- name: Prepare Embedding SDK artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
17
.github/workflows/e2e-test.yml
vendored
@@ -65,6 +65,7 @@ jobs:
|
||||
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
|
||||
- name: Setup python-runner
|
||||
if: ${{ inputs.name == 'python' }}
|
||||
env:
|
||||
METABASE_AUTOMATION_USER_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
run: ./.github/scripts/setup-python-runner.sh
|
||||
@@ -139,9 +140,14 @@ jobs:
|
||||
run: |
|
||||
echo "Running tests with specs: $SPEC_PATH"
|
||||
node e2e/runner/run_cypress_ci.js e2e \
|
||||
--env grepTags="-@mongo+-@flaky+-@OSS+-@skip",grepOmitFiltered=true \
|
||||
--env grepTags="-@mongo+-@python+-@flaky+-@OSS+-@skip",grepOmitFiltered=true \
|
||||
--spec "$SPEC_PATH" \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
# Trunk Quarantine controls the final state of the run in the CI!
|
||||
# Even if this step fails, we let it pass and then `trunk-io/analytics-uploader` determines whether to fail or to
|
||||
# pass the whole job, based on the quarantine list.
|
||||
# We only want to "continue on error" (ignore failures) when the Trunk upload is active - i.e. not on drafts!
|
||||
continue-on-error: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true) }}
|
||||
|
||||
- name: Run Tagged EE Cypress tests on ${{ inputs.name }}
|
||||
if: ${{ inputs.specs }}
|
||||
@@ -154,18 +160,25 @@ jobs:
|
||||
--env grepTags="${{inputs.tags && format('{0}+-@skip', inputs.tags) || '-@skip'}}",grepOmitFiltered=true \
|
||||
--spec "$SPEC_PATH" \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
# Trunk Quarantine controls the final state of the run in the CI!
|
||||
# Even if this step fails, we let it pass and then `trunk-io/analytics-uploader` determines whether to fail or to
|
||||
# pass the whole job, based on the quarantine list.
|
||||
# We only want to "continue on error" (ignore failures) when the Trunk upload is active - i.e. not on drafts!
|
||||
continue-on-error: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true) }}
|
||||
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
if: always()
|
||||
with:
|
||||
input-path: ./target/junit
|
||||
# Related to our custom upload to S3
|
||||
output-name: e2e-${{ inputs.name }}
|
||||
variant: e2e-tests
|
||||
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 }}
|
||||
# Related to Trunk uploader
|
||||
variant: e2e-tests
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
- name: Upload Cypress Artifacts upon failure
|
||||
|
||||
8
.github/workflows/embedding-sdk.yml
vendored
@@ -40,10 +40,12 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Build Embedding SDK package
|
||||
run: yarn build-embedding-sdk-package
|
||||
run: |
|
||||
# Remove the matchers to not report false positives on every PR
|
||||
# unrelated to embedding (EMB-765)
|
||||
echo "::remove-matcher owner=tsc::"
|
||||
yarn build-embedding-sdk-package
|
||||
- name: Prepare Embedding SDK artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
@@ -43,8 +43,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Build cljs
|
||||
run: yarn build:cljs
|
||||
- name: Stress-test ${{ github.event.inputs.spec }} ${{ github.event.inputs.burn_in }} times
|
||||
|
||||
11
.github/workflows/frontend.yml
vendored
@@ -35,8 +35,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Restore ESLint cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
@@ -65,8 +63,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- run: yarn build-pure:cljs
|
||||
name: Compile CLJS
|
||||
- run: yarn type-check-pure
|
||||
@@ -90,10 +86,11 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Run frontend unit tests
|
||||
run: yarn run test-unit --silent --shard=${{ matrix.shard }}/${{ env.SHARDS }}
|
||||
# We want Trunk to still receive test reports even if this job fails.
|
||||
# It will filter out the quarantined tests, and will control the job exit code based on the analysis.
|
||||
continue-on-error: true
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
if: always() && github.event_name != 'workflow_dispatch'
|
||||
@@ -116,8 +113,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Run frontend timezones tests
|
||||
run: yarn run test-timezones
|
||||
|
||||
|
||||
6
.github/workflows/fuzzing.yml
vendored
@@ -22,8 +22,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- run: yarn test-unit frontend/src/metabase/querying/expressions/pratt/fuzz.lexifier.unit.spec.ts
|
||||
env:
|
||||
MB_FUZZ: 1
|
||||
@@ -38,8 +36,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- run: yarn test-unit frontend/src/metabase/querying/expressions/fuzz.compiler.unit.spec.ts
|
||||
env:
|
||||
MB_FUZZ: 1
|
||||
@@ -54,8 +50,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- run: yarn test-unit frontend/src/metabase/querying/expressions/fuzz.string.unit.spec.ts
|
||||
env:
|
||||
MB_FUZZ: 1
|
||||
|
||||
2
.github/workflows/generative-query-test.yml
vendored
@@ -40,8 +40,6 @@ jobs:
|
||||
ref: ${{ inputs.ref }}
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: generative-query-test
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
|
||||
|
||||
2
.github/workflows/i18n.yml
vendored
@@ -38,8 +38,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'i18n'
|
||||
- name: Install xgettext if necessary
|
||||
run: |
|
||||
if ! command -v xgettext > /dev/null; then
|
||||
|
||||
2
.github/workflows/loki-update.yml
vendored
@@ -20,8 +20,6 @@ jobs:
|
||||
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
|
||||
- name: Compile CLJS
|
||||
run: yarn build-pure:cljs
|
||||
|
||||
2
.github/workflows/loki.yml
vendored
@@ -47,8 +47,6 @@ jobs:
|
||||
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
|
||||
- name: Compile CLJS
|
||||
run: NODE_ENV=development yarn build-pure:cljs
|
||||
|
||||
6
.github/workflows/mage.yml
vendored
@@ -2,7 +2,7 @@ name: Mage Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths: ["mage/**", "test/mage/**"]
|
||||
paths: ["mage/**"]
|
||||
|
||||
jobs:
|
||||
# run mage tests even if the rest of be isnt needed
|
||||
@@ -13,8 +13,6 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'kondo'
|
||||
- name: Setup Babashka
|
||||
uses: turtlequeue/setup-babashka@v1.7.0
|
||||
with:
|
||||
@@ -24,4 +22,4 @@ jobs:
|
||||
- name: bb task list
|
||||
run: bb tasks
|
||||
- name: Run mage tests
|
||||
run: bb ./test/mage/runtests.clj
|
||||
run: bb ./mage/test/mage/runtests.clj
|
||||
|
||||
2
.github/workflows/migrations.yml
vendored
@@ -16,7 +16,5 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: lint-migrations
|
||||
- name: Verify Liquibase Migrations
|
||||
run: ./bin/mage lint-migrations
|
||||
|
||||
4
.github/workflows/release-embedding-sdk.yml
vendored
@@ -254,8 +254,6 @@ jobs:
|
||||
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "release-sdk"
|
||||
|
||||
- name: Run unit tests
|
||||
run: yarn embedding-sdk:test-unit
|
||||
@@ -277,8 +275,6 @@ jobs:
|
||||
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "release-sdk"
|
||||
|
||||
- name: Bump published npm package version
|
||||
# NOTE: this should happen before "Build SDK bundle" as we inject SDK version into the code during build step
|
||||
|
||||
2
.github/workflows/run-tests.yml
vendored
@@ -49,8 +49,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "files-changed"
|
||||
- name: Build static-viz frontend
|
||||
run: yarn build-static-viz
|
||||
env:
|
||||
|
||||
2
.github/workflows/snyk.yml
vendored
@@ -23,8 +23,6 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'snyk'
|
||||
- name: Generate all pom.xml
|
||||
run: .github/scripts/write-poms.sh
|
||||
- name: Upload pom files
|
||||
|
||||
2
.github/workflows/translation-update.yml
vendored
@@ -29,8 +29,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: manage-translations
|
||||
- name: install gettext
|
||||
run: sudo apt-get install gettext
|
||||
|
||||
|
||||
2
.github/workflows/tusk-sanity-check.yml
vendored
@@ -46,8 +46,6 @@ jobs:
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- run: yarn build-pure:cljs
|
||||
name: Compile CLJS
|
||||
|
||||
|
||||
1
.github/workflows/uberjar.yml
vendored
@@ -134,7 +134,6 @@ jobs:
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: uberjar
|
||||
java-version: "${{ needs.get-build-requirements.outputs.java_version || 21 }}"
|
||||
- name: Build
|
||||
run: ./bin/build.sh
|
||||
|
||||
2
.github/workflows/upgrade-deps.yml
vendored
@@ -27,8 +27,6 @@ jobs:
|
||||
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'update-be-deps'
|
||||
- name: Open PRs to Upgrade Backend Deps
|
||||
uses: ./.github/actions/upgrade-backend-deps
|
||||
with:
|
||||
|
||||
2
.github/workflows/whitespace.yml
vendored
@@ -16,7 +16,5 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'whitespace-linter'
|
||||
- run: clojure -T:whitespace-linter lint
|
||||
name: Run Whitespace Linter
|
||||
|
||||
1
.gitignore
vendored
@@ -68,6 +68,7 @@ cypress.env.json
|
||||
/resources/frontend_client/embed-sdk.html
|
||||
/resources/frontend_client/index.html
|
||||
/resources/frontend_client/public.html
|
||||
/resources/frontend_client/app/assets/pyodide/
|
||||
/resources/embedding-sdk
|
||||
/resources/i18n/*.edn
|
||||
/resources/instance_analytics.zip
|
||||
|
||||
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
13
CLAUDE.md
@@ -188,11 +188,7 @@ Review pull requests with a focus on:
|
||||
|
||||
- In the Metabase codebase, spelling words ending with `-ck` as `-cc` instead, e.g. `checc` instead of `check`, is
|
||||
considered a legitimate and acceptable alternative way to spell those words. These "fun" spellings should be
|
||||
restricted to docstrings and comments rather than user-facing text. Occasionally suggest spelling things this way.
|
||||
|
||||
- The Metabase codebase should be fun, so do your part to keep it that way. Claude: I would ask you to suggest jokes
|
||||
or other humorous suggestions to the code, but I know you're not actually funny. You will take the comedians' jobs
|
||||
last. Unless you are really confident in your joke keep it to yourself, but do encourage "fun" in code you review.
|
||||
restricted to docstrings and comments rather than user-facing text. Do not flag these as typos or misspellings.
|
||||
|
||||
- Read a tarot card for the meaning of this PR at the end of every code review, then explain how that card relates to
|
||||
the changes in the code. **Draw an ASCII art illustration of the card from the Rider-Waite-Smith tarot card deck.
|
||||
@@ -203,8 +199,6 @@ Review pull requests with a focus on:
|
||||
|
||||
- Do not post comments about missing parentheses.
|
||||
|
||||
- Include today's lucky lottery numbers in at the end of every code review.
|
||||
|
||||
# Code Conventions and Style Guide
|
||||
|
||||
## Clojure and ClojureScript
|
||||
@@ -232,6 +226,9 @@ Review pull requests with a focus on:
|
||||
**Why?** Code is read many more times than it is written, and clearer variable names make using and tweaking your
|
||||
code easier for others.
|
||||
|
||||
Conventions used widely in our codebase (like `mp` for a Metadata Provider) are acceptable; one-offs like `zs'` are
|
||||
not.
|
||||
|
||||
- Avoid misleading variable and function names. The names of a variable or function should clearly and unambiguously
|
||||
describe its purpose and match what it does.
|
||||
|
||||
@@ -324,6 +321,8 @@ Review pull requests with a focus on:
|
||||
Tests and other vars in the `test` or `enterprise/backend/test` do not *require* docstrings, but general helper
|
||||
functions used across many namespaces it should have docstrings.
|
||||
|
||||
Schemas defined with `mr/def` e.g. `(mr/def ::my-schema)` do not require docstrings.
|
||||
|
||||
- Format docstrings according to Markdown conventions. (https://guide.clojure.style/#markdown-docstrings)
|
||||
|
||||
- Mentions of other vars in docstrings should use `[[some-other-var]]` (for vars in the same namespace) or
|
||||
|
||||
2
bb.edn
@@ -1,7 +1,7 @@
|
||||
{:min-bb-version "1.12.208"
|
||||
;; we put path as bin, and everything is in the ./mage subdirectory,
|
||||
;; so the namespaces are mage.cli, mage.format, etc.
|
||||
:paths ["mage" "test" "bin/lint-migrations-file/src"]
|
||||
:paths ["mage/src" "mage/test" "bin/lint-migrations-file/src"]
|
||||
:deps {org.babashka/json {:mvn/version "0.1.6"}
|
||||
metosin/malli {:mvn/version "0.17.0"}
|
||||
table/table {:mvn/version "0.5.0"}
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
"net.thisptr" {"jackson-jq" {:resource "apache2_0.txt"}}
|
||||
"org.antlr" {"antlr-runtime" {:resource "BSD.txt"}
|
||||
"antlr4-runtime" {:resource "BSD.txt"}}
|
||||
"org.eclipse.jgit" {"org.eclipse.jgit" {:resource "BSD.txt"}}
|
||||
"org.eclipse.jetty" {"jetty-webapp" {:resource "EPL.txt"}}
|
||||
"org.eclipse.jetty.toolchain" {"jetty-jakarta-servlet-api" {:resource "EPL.txt"}}
|
||||
"org.eclipse.jetty.ee9.websocket" {"jetty-ee9-websocket-jetty-api" {:resource "EPL.txt"}
|
||||
|
||||
48
bin/download-pyodide.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
DEST_DIR="resources/frontend_client/app/assets"
|
||||
|
||||
REQUIRED_FILES=(
|
||||
"pyodide/pyodide-lock.json"
|
||||
"pyodide/pyodide.asm.js"
|
||||
"pyodide/pyodide.asm.wasm"
|
||||
"pyodide/pyodide.js"
|
||||
|
||||
"pyodide/python_stdlib.zip"
|
||||
|
||||
"pyodide/micropip-0.10.1-py3-none-any.whl"
|
||||
"pyodide/numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl"
|
||||
"pyodide/pandas-2.3.1-cp313-cp313-pyodide_2025_0_wasm32.whl"
|
||||
"pyodide/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"
|
||||
"pyodide/pytz-2025.2-py2.py3-none-any.whl"
|
||||
"pyodide/packaging-24.2-py3-none-any.whl"
|
||||
"pyodide/six-1.17.0-py2.py3-none-any.whl"
|
||||
)
|
||||
|
||||
PYODIDE_VERSION="0.28.3"
|
||||
DOWNLOAD_URL="https://github.com/pyodide/pyodide/releases/download/${PYODIDE_VERSION}/pyodide-${PYODIDE_VERSION}.tar.bz2"
|
||||
|
||||
function all_files_exist() {
|
||||
for FILE in "${REQUIRED_FILES[@]}"; do
|
||||
TEST_FILE="$DEST_DIR/$FILE"
|
||||
|
||||
if [ ! -f "$TEST_FILE" ]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
if all_files_exist; then
|
||||
echo "Pyodide files already exist, skipping download"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Downloading Pyodide $PYODIDE_VERSION into $DEST_DIR"
|
||||
echo "This might take a while"
|
||||
|
||||
rm -rf "$DEST_DIR/pyodide"
|
||||
mkdir -p "$DEST_DIR"
|
||||
|
||||
curl -Ls "$DOWNLOAD_URL" | tar xvfj - -C "$DEST_DIR" ${REQUIRED_FILES[@]}
|
||||
7
deps.edn
@@ -85,7 +85,7 @@
|
||||
hiccup/hiccup {:mvn/version "2.0.0"} ; HTML templating
|
||||
inflections/inflections {:mvn/version "0.15.0"} ; Clojure/Script library used for prularizing words
|
||||
instaparse/instaparse {:mvn/version "1.5.0"} ; Make your own parser
|
||||
io.github.camsaul/toucan2 {:mvn/version "1.0.567"}
|
||||
io.github.camsaul/toucan2 {:mvn/version "1.0.568"}
|
||||
io.github.eerohele/pp {#_#_:git/tag "2024-11-13.77" ; super fast pretty-printing library
|
||||
:git/sha "4998a1fdd9d3713d7034d04509e9212204773bf2"
|
||||
:git/url "https://github.com/eerohele/pp"}
|
||||
@@ -108,7 +108,7 @@
|
||||
org.bouncycastle/bcprov-jdk18on]}
|
||||
metabase/throttle {:mvn/version "1.0.2"} ; Tools for throttling access to API endpoints and other code pathways
|
||||
methodical/methodical {:mvn/version "1.0.127"} ; drop-in replacements for Clojure multimethods and adds several advanced features
|
||||
metosin/malli {:mvn/version "0.19.1"} ; Data-driven Schemas for Clojure/Script and babashka
|
||||
metosin/malli {:mvn/version "0.19.2"} ; Data-driven Schemas for Clojure/Script and babashka
|
||||
nano-id/nano-id {:mvn/version "1.1.0"} ; NanoID generator for generating entity_ids
|
||||
net.cgrand/macrovich {:mvn/version "0.2.2"} ; utils for writing macros for both Clojure & ClojureScript
|
||||
net.clojars.wkok/openai-clojure {:mvn/version "0.23.0"
|
||||
@@ -170,6 +170,7 @@
|
||||
org.eclipse.jetty/jetty-unixdomain-server {:mvn/version "12.0.25"}
|
||||
org.eclipse.jetty.ee9/jetty-ee9-servlet {:mvn/version "12.0.24"}
|
||||
org.eclipse.jetty.ee9.websocket/jetty-ee9-websocket-jetty-server {:mvn/version "12.0.25"}
|
||||
org.eclipse.jgit/org.eclipse.jgit {:mvn/version "7.3.0.202506031305-r"}; Java implementation of Git version control system
|
||||
org.flatland/ordered {:mvn/version "1.15.12"} ; ordered maps & sets
|
||||
org.graalvm.polyglot/js-community {:mvn/version "24.2.2" :extension "pom"} ; JavaScript engine
|
||||
org.graalvm.polyglot/polyglot {:mvn/version "24.2.2"} ; GraalVM platform, required by JS engine
|
||||
@@ -662,7 +663,7 @@
|
||||
:ns-regex
|
||||
["^metabase\\..*" "^metabase-enterprise\\..*"]
|
||||
|
||||
;; don't instrument Postgres/MySQL driver namespaces, because we don't current run tests for them
|
||||
;; don't instrument Postgres/MySQL driver namespaces, because we don't currently run tests for them
|
||||
;; as part of recording test coverage, which means they can give us false positives.
|
||||
;;
|
||||
;; regex literals aren't allowed in EDN. We parse them in `./test/cloverage.clj`
|
||||
|
||||
@@ -348,7 +348,9 @@
|
||||
(do
|
||||
;; prevent things like dereferencing metabase.api.common/*current-user-permissions-set* from triggering the check
|
||||
;; by calling `next-method` *twice*. To reduce the performance impact, just call it with the first instance.
|
||||
(maybe-realize (next-method model strategy k [(first instances)]))
|
||||
;; we do this for each model because e.g. we may have one `:RootCollection` and several `:Collection`s.
|
||||
(doseq [[_instance-model instances] (group-by t2/model instances)]
|
||||
(maybe-realize (next-method model strategy k [(first instances)])))
|
||||
;; Now we can actually run the hydration with the full set of instances and make sure no more DB calls happened.
|
||||
(t2/with-call-count [call-count]
|
||||
(let [res (maybe-realize (next-method model strategy k instances))]
|
||||
|
||||
@@ -88,13 +88,16 @@
|
||||
[zloc :- ::zloc]
|
||||
(when (= (z/tag zloc) :list)
|
||||
(let [first-child (z/down zloc)]
|
||||
(and (= (z/tag first-child) :token)
|
||||
(require-symbols (z/sexpr first-child))))))
|
||||
(when (= (z/tag first-child) :token)
|
||||
;; Check all child symbols on the line since `require` might be called in a threading macro
|
||||
;; like (-> 'ns require)
|
||||
(some require-symbols (z/child-sexprs zloc))))))
|
||||
|
||||
(mu/defn- find-required-namespace :- [:maybe simple-symbol?]
|
||||
"Given a `zloc` pointing to one of the children of something like `(require ...)` find a required namespace symbol."
|
||||
[zloc :- ::zloc]
|
||||
(when-let [symbol-loc (z/find-depth-first zloc #(and (= (z/tag %) :token)
|
||||
(symbol? (z/sexpr %))
|
||||
(not= (z/sexpr %) 'quote)))]
|
||||
(let [symb (z/sexpr symbol-loc)]
|
||||
(if (qualified-symbol? symb)
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
(deftest ^:parallel find-required-namespaces-test
|
||||
(are [s expected] (= (quote expected)
|
||||
(#'dev.deps-graph/find-required-namespaces (z/of-string s)))
|
||||
"(require 'malli.generator)" #{malli.generator}
|
||||
"(require (quote malli.generator))" #{malli.generator}
|
||||
"(classloader/require 'a 'b)" #{a b}
|
||||
"(requiring-resolve 'a/b 'c/d)" #{a c}
|
||||
"(require '[malli.generator :as mg])" #{malli.generator}
|
||||
"(require '[malli.generator])" #{malli.generator}))
|
||||
"(require 'malli.generator)" #{malli.generator}
|
||||
"(require (quote malli.generator))" #{malli.generator}
|
||||
"(classloader/require 'a 'b)" #{a b}
|
||||
"(requiring-resolve 'a/b 'c/d)" #{a c}
|
||||
"(require '[malli.generator :as mg])" #{malli.generator}
|
||||
"(require '[malli.generator])" #{malli.generator}
|
||||
"(-> 'malli.generator requiring-resolve)" #{malli.generator}))
|
||||
;; TODO: reader conditionals don't work properly
|
||||
; "(#?(:clj requiring-resolve :cljs resolve) 'malli.generator)" #{malli.generator}))
|
||||
|
||||
(deftest ^:parallel find-requires-test
|
||||
(are [s expected] (= (quote expected)
|
||||
@@ -21,6 +24,12 @@
|
||||
((require '[malli.generator])
|
||||
(requiring-resolve 'whatever/x))
|
||||
|
||||
"(-> 'whatever requiring-resolve)"
|
||||
((-> 'whatever requiring-resolve))
|
||||
|
||||
; "(#?(:clj requiring-resolve :cljs resolve) 'malli.generator)"
|
||||
; ((#?(:clj requiring-resolve :cljs resolve) 'malli.generator))
|
||||
|
||||
;; should ignore comments.
|
||||
"(do #_(require '[malli.generator]))"
|
||||
()
|
||||
|
||||
666
docs/api.html
@@ -946,7 +946,11 @@ redirect_from:
|
||||
}, {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.options"
|
||||
}, {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.id.segment"
|
||||
"oneOf" : [ {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
}, {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.id.segment"
|
||||
} ]
|
||||
} ]
|
||||
},
|
||||
"mbql.clause.share" : {
|
||||
@@ -3298,7 +3302,7 @@ redirect_from:
|
||||
"metabase.analyze.query-results.ResultsMetadata" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"$ref" : "#/components/schemas/metabase.legacy-mbql.schema.legacy-column-metadata"
|
||||
"$ref" : "#/components/schemas/metabase.query-processor.schema..result-metadata.column"
|
||||
},
|
||||
"description" : "value must be an array of valid results column metadata maps.",
|
||||
"optional" : true
|
||||
@@ -3606,6 +3610,225 @@ redirect_from:
|
||||
"description" : "schema for a valid legacy MBQL :tag clause",
|
||||
"allOf" : [ ]
|
||||
},
|
||||
"metabase.legacy-mbql.schema..expression.options" : {
|
||||
"description" : "Options for a legacy `:expression` ref in MBQL 4 are the same as in MBQL 5, except that `:lib/uuid` is optional and\n it cannot be empty.",
|
||||
"default" : { },
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"base-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
"database-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"display-name" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"effective-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
"lib/uuid" : {
|
||||
"type" : "string",
|
||||
"minLength" : 36,
|
||||
"maxLength" : 36
|
||||
},
|
||||
"name" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"semantic-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.semantic-or-relation-type"
|
||||
},
|
||||
"temporal-unit" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.temporal-bucketing.unit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metabase.legacy-mbql.schema..legacy-column-metadata.binning-info" : {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"bin_width" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.bin-width"
|
||||
},
|
||||
"binning_strategy" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.strategy"
|
||||
},
|
||||
"num_bins" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.num-bins"
|
||||
},
|
||||
"strategy" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.strategy"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy" ]
|
||||
},
|
||||
"metabase.legacy-mbql.schema..legacy-column-metadata.qualified-keys" : {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"lib/external-remap" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata..column.remapping.external"
|
||||
},
|
||||
"lib/source-column-alias" : {
|
||||
"description" : "Name for a column as returned/projected by the previous stage of the query or source Table/source Card. The\n left-hand side (LHS) of\n\n SELECT lhs AS rhs",
|
||||
"type" : "string"
|
||||
},
|
||||
"lib/type" : {
|
||||
"default" : "metadata/column",
|
||||
"const" : "metadata/column"
|
||||
},
|
||||
"lib/source-uuid" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.uuid"
|
||||
},
|
||||
"qp/implicit-field?" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"lib/ref-name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"lib/deduplicated-name" : {
|
||||
"type" : "string",
|
||||
"description" : "The simply-deduplicated name that was historically used in QP results metadata (originally calculated by\n the [[metabase.query-processor.middleware.annotate]] middleware, now calculated\n by [[metabase.lib.middleware.result-metadata]]). This just adds suffixes to column names e.g. `ID` and `ID` become\n `ID` and `ID_2`, respectively. Kept around because many old field refs use this column name."
|
||||
},
|
||||
"lib/original-expression-name" : {
|
||||
"type" : "string",
|
||||
"minLength" : 1
|
||||
},
|
||||
"lib/card-id" : {
|
||||
"description" : "Valid Card ID",
|
||||
"type" : "integer",
|
||||
"minimum" : 1
|
||||
},
|
||||
"lib/expression-name" : {
|
||||
"type" : "string",
|
||||
"minLength" : 1
|
||||
},
|
||||
"lib/breakout?" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"metabase.lib.field/temporal-unit" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "day", "day-of-month", "day-of-week", "day-of-year", "default", "hour", "hour-of-day", "millisecond", "minute", "minute-of-hour", "month", "month-of-year", "quarter", "quarter-of-year", "second", "second-of-minute", "week", "week-of-year", "year", "year-of-era" ]
|
||||
},
|
||||
"metabase.lib.field/binning" : {
|
||||
"description" : "Schema for `:binning` options passed to a `:field` clause.",
|
||||
"allOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"strategy" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.strategy"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy" ]
|
||||
}, {
|
||||
"oneOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"strategy" : {
|
||||
"const" : "default"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy" ]
|
||||
}, {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"bin-width" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.bin-width"
|
||||
},
|
||||
"strategy" : {
|
||||
"const" : "bin-width"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy", "bin-width" ]
|
||||
}, {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"num-bins" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.num-bins"
|
||||
},
|
||||
"strategy" : {
|
||||
"const" : "num-bins"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy", "num-bins" ]
|
||||
} ]
|
||||
} ]
|
||||
},
|
||||
"lib/model-display-name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"lib/internal-remap" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata..column.remapping.internal"
|
||||
},
|
||||
"metabase.lib.join/join-alias" : {
|
||||
"type" : "string",
|
||||
"minLength" : 1
|
||||
},
|
||||
"lib/original-binning" : {
|
||||
"description" : "Schema for `:binning` options passed to a `:field` clause.",
|
||||
"allOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"strategy" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.strategy"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy" ]
|
||||
}, {
|
||||
"oneOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"strategy" : {
|
||||
"const" : "default"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy" ]
|
||||
}, {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"bin-width" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.bin-width"
|
||||
},
|
||||
"strategy" : {
|
||||
"const" : "bin-width"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy", "bin-width" ]
|
||||
}, {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"num-bins" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.num-bins"
|
||||
},
|
||||
"strategy" : {
|
||||
"const" : "num-bins"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy", "num-bins" ]
|
||||
} ]
|
||||
} ]
|
||||
},
|
||||
"lib/original-join-alias" : {
|
||||
"type" : "string",
|
||||
"minLength" : 1
|
||||
},
|
||||
"lib/original-display-name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"lib/source" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata..column.source"
|
||||
},
|
||||
"lib/ref-display-name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"lib/original-name" : {
|
||||
"type" : "string",
|
||||
"description" : "The original name of the column as it appeared in the very first place it came from (i.e., the physical name of the\n column in the table it appears in). This should be the same as the `:lib/source-column-alias` for the very first\n usage of the column.\n Allowed to be blank because some databases like SQL Server allow blank column names."
|
||||
},
|
||||
"lib/desired-column-alias" : {
|
||||
"description" : "Name we should use as a column alias for a column in this stage of a query. The desired column alias in stage N\n becomes the source column alias in stage N+1. The right-hand side (RHS) in\n\n SELECT lhs AS rhs",
|
||||
"type" : "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metabase.legacy-mbql.schema./" : {
|
||||
"description" : "schema for a valid legacy MBQL :tag clause",
|
||||
"allOf" : [ ]
|
||||
@@ -3824,47 +4047,65 @@ redirect_from:
|
||||
"enum" : [ "iso", "us", "instance" ]
|
||||
},
|
||||
"metabase.legacy-mbql.schema.FieldOptions" : {
|
||||
"allOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"base-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
"binning" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.binning",
|
||||
"description" : "Replaces `binning-strategy`.\n\n Using binning requires the driver to support the `:binning` feature."
|
||||
},
|
||||
"inherited-temporal-unit" : {
|
||||
"$ref" : "#/components/schemas/metabase.legacy-mbql.schema.DateTimeUnit"
|
||||
},
|
||||
"join-alias" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.join.alias",
|
||||
"description" : "Replaces `joined-field`.\n\n `:join-alias` is used to refer to a FieldOrExpression from a different Table/nested query that you are EXPLICITLY\n JOINING against."
|
||||
},
|
||||
"source-field" : {
|
||||
"description" : "Replaces `fk->`.\n\n `:source-field` is used to refer to a FieldOrExpression from a different Table you would like IMPLICITLY JOINED to\n the source table.\n\n If both `:source-field` and `:join-alias` are supplied, `:join-alias` should be used to perform the join;\n `:source-field` should be for information purposes only.",
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.id.field"
|
||||
},
|
||||
"source-field-join-alias" : {
|
||||
"description" : "The join alias of the source field used for an implicit join.",
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"source-field-name" : {
|
||||
"description" : "The name or desired alias of the field used for an implicit join.",
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"temporal-unit" : {
|
||||
"$ref" : "#/components/schemas/metabase.legacy-mbql.schema.DateTimeUnit",
|
||||
"description" : "`:temporal-unit` is used to specify DATE BUCKETING for a FieldOrExpression that represents a moment in time of\n some sort.\n\n There is no requirement that all `:type/Temporal` derived FieldOrExpressions specify a `:temporal-unit`, but for\n legacy reasons `:field` clauses that refer to `:type/DateTime` FieldOrExpressions will be automatically \"bucketed\"\n in the `:breakout` and `:filter` clauses, but nowhere else. Auto-bucketing only applies to `:filter` clauses when\n values for comparison are `yyyy-MM-dd` date strings. See the `auto-bucket-datetimes` middleware for more details.\n `:field` clauses elsewhere will not be automatically bucketed, so drivers still need to make sure they do any\n special datetime handling for plain `:field` clauses when their FieldOrExpression derives from `:type/DateTime`."
|
||||
}
|
||||
"default" : { },
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"binning" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.binning"
|
||||
},
|
||||
"inherited-temporal-unit" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.temporal-bucketing.unit"
|
||||
},
|
||||
"database-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"metabase.lib.field/original-temporal-unit" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.temporal-bucketing.unit"
|
||||
},
|
||||
"display-name" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"source-field-name" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"effective-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
"base-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
"lib/uuid" : {
|
||||
"type" : "string",
|
||||
"minLength" : 36,
|
||||
"maxLength" : 36
|
||||
},
|
||||
"name" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"metabase.lib.field/original-effective-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
"source-field" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.id.field"
|
||||
},
|
||||
"join-alias" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.join.alias"
|
||||
},
|
||||
"lib/original-binning" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.binning"
|
||||
},
|
||||
"temporal-unit" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.temporal-bucketing.unit"
|
||||
},
|
||||
"source-field-join-alias" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"semantic-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.semantic-or-relation-type"
|
||||
}
|
||||
}, {
|
||||
"description" : "If `:base-type` is specified, the `:temporal-unit` must make sense, e.g. no bucketing by `:year`for\n a `:type/Time` column.",
|
||||
"$ref" : "#/components/schemas/metabase.legacy-mbql.schema.validate-temporal-unit"
|
||||
}, {
|
||||
"description" : "You cannot use `:binning` keys like `:strategy` in the top level.",
|
||||
"$ref" : "#/components/schemas/metabase.legacy-mbql.schema.no-binning-options-at-top-level"
|
||||
} ]
|
||||
},
|
||||
"description" : "Options for an MBQL 4 `:field` ref are the same as MBQL 5, except that `:lib/uuid` is not required and it cannot be\n empty.",
|
||||
"optional" : true
|
||||
},
|
||||
"metabase.legacy-mbql.schema.FieldOrExpressionDef" : {
|
||||
"description" : "Schema for anything that is accepted as a top-level expression definition, either an arithmetic expression such as a\n `:+` clause or a `:field` or `:value` clause.",
|
||||
@@ -4757,7 +4998,6 @@ redirect_from:
|
||||
"description" : "schema for a valid legacy MBQL :tag clause",
|
||||
"allOf" : [ ]
|
||||
}, {
|
||||
"description" : "Fields using names rather than integer IDs are required to specify `:base-type`.",
|
||||
"$ref" : "#/components/schemas/metabase.legacy-mbql.schema.require-base-type-for-field-name"
|
||||
} ]
|
||||
},
|
||||
@@ -4854,6 +5094,17 @@ redirect_from:
|
||||
"field_ref" : {
|
||||
"$ref" : "#/components/schemas/metabase.legacy-mbql.schema.Reference"
|
||||
},
|
||||
"lib/external-remap" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata..column.remapping.external"
|
||||
},
|
||||
"lib/source-column-alias" : {
|
||||
"description" : "Name for a column as returned/projected by the previous stage of the query or source Table/source Card. The\n left-hand side (LHS) of\n\n SELECT lhs AS rhs",
|
||||
"type" : "string"
|
||||
},
|
||||
"lib/type" : {
|
||||
"default" : "metadata/column",
|
||||
"const" : "metadata/column"
|
||||
},
|
||||
"fingerprint" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata.fingerprint.fingerprint"
|
||||
},
|
||||
@@ -4861,31 +5112,187 @@ redirect_from:
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata..column.visibility-type"
|
||||
},
|
||||
"base_type" : {
|
||||
"default" : "type/*",
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
"lib/source-uuid" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.uuid"
|
||||
},
|
||||
"qp/implicit-field?" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"lib/ref-name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"id" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.id.field"
|
||||
},
|
||||
"lib/deduplicated-name" : {
|
||||
"type" : "string",
|
||||
"description" : "The simply-deduplicated name that was historically used in QP results metadata (originally calculated by\n the [[metabase.query-processor.middleware.annotate]] middleware, now calculated\n by [[metabase.lib.middleware.result-metadata]]). This just adds suffixes to column names e.g. `ID` and `ID` become\n `ID` and `ID_2`, respectively. Kept around because many old field refs use this column name."
|
||||
},
|
||||
"lib/original-expression-name" : {
|
||||
"type" : "string",
|
||||
"minLength" : 1
|
||||
},
|
||||
"name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"lib/card-id" : {
|
||||
"description" : "Valid Card ID",
|
||||
"type" : "integer",
|
||||
"minimum" : 1
|
||||
},
|
||||
"lib/expression-name" : {
|
||||
"type" : "string",
|
||||
"minLength" : 1
|
||||
},
|
||||
"lib/breakout?" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"metabase.lib.field/temporal-unit" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "day", "day-of-month", "day-of-week", "day-of-year", "default", "hour", "hour-of-day", "millisecond", "minute", "minute-of-hour", "month", "month-of-year", "quarter", "quarter-of-year", "second", "second-of-minute", "week", "week-of-year", "year", "year-of-era" ]
|
||||
},
|
||||
"metabase.lib.field/binning" : {
|
||||
"description" : "Schema for `:binning` options passed to a `:field` clause.",
|
||||
"allOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"strategy" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.strategy"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy" ]
|
||||
}, {
|
||||
"oneOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"strategy" : {
|
||||
"const" : "default"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy" ]
|
||||
}, {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"bin-width" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.bin-width"
|
||||
},
|
||||
"strategy" : {
|
||||
"const" : "bin-width"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy", "bin-width" ]
|
||||
}, {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"num-bins" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.num-bins"
|
||||
},
|
||||
"strategy" : {
|
||||
"const" : "num-bins"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy", "num-bins" ]
|
||||
} ]
|
||||
} ]
|
||||
},
|
||||
"semantic_type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.semantic-or-relation-type"
|
||||
},
|
||||
"display_name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"lib/model-display-name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"lib/internal-remap" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata..column.remapping.internal"
|
||||
},
|
||||
"converted_timezone" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.expression.temporal.timezone-id"
|
||||
},
|
||||
"source" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata..column.legacy-source"
|
||||
},
|
||||
"metabase.lib.join/join-alias" : {
|
||||
"type" : "string",
|
||||
"minLength" : 1
|
||||
},
|
||||
"binning_info" : {
|
||||
"$ref" : "#/components/schemas/metabase.legacy-mbql.schema..legacy-column-metadata.binning-info"
|
||||
},
|
||||
"lib/original-binning" : {
|
||||
"description" : "Schema for `:binning` options passed to a `:field` clause.",
|
||||
"allOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"strategy" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.strategy"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy" ]
|
||||
}, {
|
||||
"oneOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"strategy" : {
|
||||
"const" : "default"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy" ]
|
||||
}, {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"bin-width" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.bin-width"
|
||||
},
|
||||
"strategy" : {
|
||||
"const" : "bin-width"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy", "bin-width" ]
|
||||
}, {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"num-bins" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.binning.num-bins"
|
||||
},
|
||||
"strategy" : {
|
||||
"const" : "num-bins"
|
||||
}
|
||||
},
|
||||
"required" : [ "strategy", "num-bins" ]
|
||||
} ]
|
||||
} ]
|
||||
},
|
||||
"effective_type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
"lib/original-join-alias" : {
|
||||
"type" : "string",
|
||||
"minLength" : 1
|
||||
},
|
||||
"lib/original-display-name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"unit" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.temporal-bucketing.unit"
|
||||
},
|
||||
"lib/source" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata..column.source"
|
||||
},
|
||||
"lib/ref-display-name" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"lib/original-name" : {
|
||||
"type" : "string",
|
||||
"description" : "The original name of the column as it appeared in the very first place it came from (i.e., the physical name of the\n column in the table it appears in). This should be the same as the `:lib/source-column-alias` for the very first\n usage of the column.\n Allowed to be blank because some databases like SQL Server allow blank column names."
|
||||
},
|
||||
"lib/desired-column-alias" : {
|
||||
"description" : "Name we should use as a column alias for a column in this stage of a query. The desired column alias in stage N\n becomes the source column alias in stage N+1. The right-hand side (RHS) in\n\n SELECT lhs AS rhs",
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"required" : [ "base_type", "display_name", "name" ]
|
||||
@@ -4926,7 +5333,6 @@ redirect_from:
|
||||
"description" : "schema for a valid legacy MBQL :tag clause",
|
||||
"allOf" : [ ]
|
||||
},
|
||||
"metabase.legacy-mbql.schema.no-binning-options-at-top-level" : { },
|
||||
"metabase.legacy-mbql.schema.not" : {
|
||||
"description" : "schema for a valid legacy MBQL :tag clause",
|
||||
"allOf" : [ ]
|
||||
@@ -4987,7 +5393,9 @@ redirect_from:
|
||||
"description" : "schema for a valid legacy MBQL :tag clause",
|
||||
"allOf" : [ ]
|
||||
},
|
||||
"metabase.legacy-mbql.schema.require-base-type-for-field-name" : { },
|
||||
"metabase.legacy-mbql.schema.require-base-type-for-field-name" : {
|
||||
"description" : "Fields using names rather than integer IDs are required to specify `:base-type`."
|
||||
},
|
||||
"metabase.legacy-mbql.schema.round" : {
|
||||
"description" : "schema for a valid legacy MBQL :tag clause",
|
||||
"allOf" : [ ]
|
||||
@@ -5069,7 +5477,6 @@ redirect_from:
|
||||
"description" : "schema for a valid legacy MBQL :tag clause",
|
||||
"allOf" : [ ]
|
||||
},
|
||||
"metabase.legacy-mbql.schema.validate-temporal-unit" : { },
|
||||
"metabase.legacy-mbql.schema.value" : {
|
||||
"description" : "schema for a valid legacy MBQL :tag clause",
|
||||
"allOf" : [ ]
|
||||
@@ -6247,6 +6654,7 @@ redirect_from:
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata.deduplicated-name"
|
||||
},
|
||||
"base-type" : {
|
||||
"default" : "type/*",
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
"lib/original-expression-name" : {
|
||||
@@ -6523,6 +6931,7 @@ redirect_from:
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata.deduplicated-name"
|
||||
},
|
||||
"base-type" : {
|
||||
"default" : "type/*",
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
"lib/original-expression-name" : {
|
||||
@@ -6744,6 +7153,19 @@ redirect_from:
|
||||
"metabase.lib.schema.parameter..target.legacy-field-ref" : {
|
||||
"$ref" : "#/components/schemas/metabase.legacy-mbql.schema.field"
|
||||
},
|
||||
"metabase.lib.schema.parameter..template-tag.tag-name" : {
|
||||
"oneOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"id" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
}
|
||||
},
|
||||
"required" : [ "id" ]
|
||||
}, {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
} ]
|
||||
},
|
||||
"metabase.lib.schema.parameter..variable.target" : {
|
||||
"oneOf" : [ {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.parameter..target.legacy-field-ref"
|
||||
@@ -6756,7 +7178,7 @@ redirect_from:
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"metabase.lib.schema.parameter.parameter" : {
|
||||
"description" : "Schema for the *value* of a parameter (e.g. a Dashboard parameter or a native query template tag) as passed in as\n part of the `:parameters` list in a query.",
|
||||
"description" : "Schema for the *value* of a parameter (e.g. a Dashboard parameter or a native query template tag) as passed in as\n part of the `:parameters` list in a query.\n\n Note that this is different from the parameter declarations that are saved as part of Dashboards and Cards; for THAT\n schema refer to `:metabase.parameters.schema/parameter`.",
|
||||
"allOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
@@ -6802,12 +7224,6 @@ redirect_from:
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.parameter.text-tag"
|
||||
}, {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.parameter..target.legacy-field-ref"
|
||||
}, {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.parameter..target.legacy-field-ref"
|
||||
}, {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.parameter..target.legacy-field-ref"
|
||||
}, {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.parameter..target.legacy-field-ref"
|
||||
} ]
|
||||
},
|
||||
"metabase.lib.schema.parameter.template-tag" : {
|
||||
@@ -6816,17 +7232,7 @@ redirect_from:
|
||||
"prefixItems" : [ {
|
||||
"const" : "template-tag"
|
||||
}, {
|
||||
"oneOf" : [ {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"id" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
}
|
||||
},
|
||||
"required" : [ "id" ]
|
||||
}, {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
} ]
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.parameter..template-tag.tag-name"
|
||||
} ]
|
||||
},
|
||||
"metabase.lib.schema.parameter.text-tag" : {
|
||||
@@ -6853,6 +7259,7 @@ redirect_from:
|
||||
} ]
|
||||
},
|
||||
"metabase.lib.schema.parameter.widget-type" : {
|
||||
"description" : "The type of widget to display in the FE UI for the user to use to pick values for this parameter.",
|
||||
"type" : "string",
|
||||
"enum" : [ "none", "number", "text", "date", "boolean", "date/single", "id", "category", "location/city", "location/state", "location/zip_code", "location/country", "date/range", "date/month-year", "date/quarter-year", "date/relative", "date/all-options", "temporal-unit", "number/!=", "number/<=", "number/=", "number/>=", "number/between", "string/!=", "string/=", "string/contains", "string/does-not-contain", "string/ends-with", "string/starts-with", "boolean/=" ]
|
||||
},
|
||||
@@ -6977,6 +7384,9 @@ redirect_from:
|
||||
"display-name" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"source-field-name" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"effective-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
@@ -7004,6 +7414,9 @@ redirect_from:
|
||||
"temporal-unit" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.temporal-bucketing.unit"
|
||||
},
|
||||
"source-field-join-alias" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"semantic-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.semantic-or-relation-type"
|
||||
}
|
||||
@@ -7029,6 +7442,9 @@ redirect_from:
|
||||
"display-name" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"source-field-name" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"effective-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.base-type"
|
||||
},
|
||||
@@ -7056,6 +7472,9 @@ redirect_from:
|
||||
"temporal-unit" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.temporal-bucketing.unit"
|
||||
},
|
||||
"source-field-join-alias" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.non-blank-string"
|
||||
},
|
||||
"semantic-type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.common.semantic-or-relation-type"
|
||||
}
|
||||
@@ -7376,8 +7795,8 @@ redirect_from:
|
||||
"enum" : [ "snippet", "card", "dimension", "number", "text", "date", "boolean", "temporal-unit" ]
|
||||
},
|
||||
"metabase.lib.schema.template-tag.widget-type" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "none", "number", "text", "date", "boolean", "date/single", "id", "category", "location/city", "location/state", "location/zip_code", "location/country", "date/range", "date/month-year", "date/quarter-year", "date/relative", "date/all-options", "temporal-unit", "number/!=", "number/<=", "number/=", "number/>=", "number/between", "string/!=", "string/=", "string/contains", "string/does-not-contain", "string/ends-with", "string/starts-with", "boolean/=" ]
|
||||
"description" : "Schema for valid values of `:widget-type` for a `:metabase.lib.schema.template-tag/field-filter` template tag.",
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.parameter.widget-type"
|
||||
},
|
||||
"metabase.lib.schema.temporal-bucketing..unit.date" : {
|
||||
"type" : "string",
|
||||
@@ -8150,6 +8569,12 @@ redirect_from:
|
||||
"parameters" : {
|
||||
"$ref" : "#/components/schemas/metabase.parameters.schema.parameters"
|
||||
},
|
||||
"result_metadata" : {
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata.lib-or-legacy-column"
|
||||
}
|
||||
},
|
||||
"type" : {
|
||||
"$ref" : "#/components/schemas/metabase.lib.schema.metadata..card.type"
|
||||
}
|
||||
@@ -8218,6 +8643,10 @@ redirect_from:
|
||||
} ]
|
||||
} ]
|
||||
},
|
||||
"metabase.query-processor.schema..result-metadata.column" : {
|
||||
"description" : "A single result metadata column as returned by the Query Processor.",
|
||||
"$ref" : "#/components/schemas/metabase.legacy-mbql.schema.legacy-column-metadata"
|
||||
},
|
||||
"metabase.query-processor.schema.export-format" : {
|
||||
"description" : "Schema for valid export formats for downloading query results.",
|
||||
"type" : "string",
|
||||
@@ -10652,21 +11081,6 @@ redirect_from:
|
||||
"pattern" : "^[A-Za-z0-9_\\-]{21}$"
|
||||
} ]
|
||||
}
|
||||
}, {
|
||||
"in" : "query",
|
||||
"name" : "ignore_view",
|
||||
"required" : false,
|
||||
"schema" : {
|
||||
"type" : "boolean"
|
||||
}
|
||||
}, {
|
||||
"in" : "query",
|
||||
"name" : "context",
|
||||
"required" : false,
|
||||
"schema" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "collection" ]
|
||||
}
|
||||
}, {
|
||||
"in" : "query",
|
||||
"name" : "legacy-mbql",
|
||||
@@ -15927,6 +16341,94 @@ redirect_from:
|
||||
"tags" : [ "/api/ee/dependencies" ]
|
||||
}
|
||||
},
|
||||
"/api/ee/dependencies/graph" : {
|
||||
"get" : {
|
||||
"summary" : "GET /api/ee/dependencies/graph",
|
||||
"description" : "TODO: This endpoint is supposed to take an :id and :type of an entity (currently :table, :card, :snippet,\n or :transform) and return the entity with all its upstream and downstream dependencies that should be fetched\n recursively. :edges match our :model/Dependency format. Each node in :nodes has :id, :type, and :data, and :data\n depends on the node type. For :table, there should be :display_name. For :card, there should be :name\n and :type. For :snippet -> :name. For :transform -> :name.",
|
||||
"parameters" : [ {
|
||||
"in" : "query",
|
||||
"name" : "id",
|
||||
"required" : false,
|
||||
"schema" : {
|
||||
"type" : "integer",
|
||||
"minimum" : 1
|
||||
},
|
||||
"description" : "value must be an integer greater than zero."
|
||||
}, {
|
||||
"in" : "query",
|
||||
"name" : "type",
|
||||
"required" : false,
|
||||
"schema" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "table", "card", "snippet", "transform" ]
|
||||
}
|
||||
} ],
|
||||
"responses" : {
|
||||
"2XX" : {
|
||||
"description" : "Successful response"
|
||||
},
|
||||
"4XX" : {
|
||||
"description" : "Client error response"
|
||||
},
|
||||
"5XX" : {
|
||||
"description" : "Server error response"
|
||||
}
|
||||
},
|
||||
"tags" : [ "/api/ee/dependencies" ]
|
||||
}
|
||||
},
|
||||
"/api/ee/dependencies/graph/dependents" : {
|
||||
"get" : {
|
||||
"summary" : "GET /api/ee/dependencies/graph/dependents",
|
||||
"description" : "TODO: This endpoint is supposed to take an :id and :type of an entity (currently :table, :card, :snippet,\n or :transform) and return the entity with all its upstream and downstream dependencies that should be fetched\n recursively. :edges match our :model/Dependency format. Each node in :nodes has :id, :type, and :data, and :data\n depends on the node type. For :table, there should be :display_name. For :card, there should be :name\n and :type. For :snippet -> :name. For :transform -> :name.",
|
||||
"parameters" : [ {
|
||||
"in" : "query",
|
||||
"name" : "id",
|
||||
"required" : true,
|
||||
"schema" : {
|
||||
"type" : "integer",
|
||||
"minimum" : 1
|
||||
},
|
||||
"description" : "value must be an integer greater than zero."
|
||||
}, {
|
||||
"in" : "query",
|
||||
"name" : "type",
|
||||
"required" : true,
|
||||
"schema" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "table", "card", "snippet", "transform" ]
|
||||
}
|
||||
}, {
|
||||
"in" : "query",
|
||||
"name" : "dependent_type",
|
||||
"required" : true,
|
||||
"schema" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "table", "card", "snippet", "transform" ]
|
||||
}
|
||||
}, {
|
||||
"in" : "query",
|
||||
"name" : "dependent_card_type",
|
||||
"required" : false,
|
||||
"schema" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "question", "model", "metric" ]
|
||||
}
|
||||
} ],
|
||||
"responses" : {
|
||||
"2XX" : {
|
||||
"description" : "Successful response"
|
||||
},
|
||||
"4XX" : {
|
||||
"description" : "Client error response"
|
||||
},
|
||||
"5XX" : {
|
||||
"description" : "Server error response"
|
||||
}
|
||||
},
|
||||
"tags" : [ "/api/ee/dependencies" ]
|
||||
}
|
||||
},
|
||||
"/api/ee/document/" : {
|
||||
"get" : {
|
||||
"summary" : "GET /api/ee/document/",
|
||||
@@ -25429,7 +25931,7 @@ redirect_from:
|
||||
"type" : "array",
|
||||
"items" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "dashboard", "table", "dataset", "segment", "collection", "document", "database", "action", "indexed-entity", "metric", "card" ]
|
||||
"enum" : [ "dashboard", "table", "dataset", "segment", "collection", "transform", "document", "database", "action", "indexed-entity", "metric", "card" ]
|
||||
}
|
||||
}
|
||||
}, {
|
||||
|
||||
@@ -49,4 +49,4 @@ Metabase also has a paid version that ships with all of the bells and whistles (
|
||||
- [Metabase Pro](https://www.metabase.com/product/pro)
|
||||
- [Metabase Enterprise](https://www.metabase.com/product/enterprise)
|
||||
|
||||
You can self-host this paid version, or have have us host it for you on Metabase Cloud for no additional cost. We don't charge more because we believe you'll have such a better experience that it'll be easier for us to support you.
|
||||
You can self-host this paid version, or have us host it for you on Metabase Cloud for no additional cost. We don't charge more because we believe you'll have such a better experience that it'll be easier for us to support you.
|
||||
|
||||
@@ -26,7 +26,7 @@ Companies with large number of users can talk to sales about our [Enterprise pla
|
||||
Though we bill you monthly, we calculate how much you owe each day. So, say you're on the [Starter plan](https://www.metabase.com/pricing/). Your monthly bill would include:
|
||||
|
||||
- $100 flat payment for the month. This payment additionally covers the first five people who use your Metabase that month. If you have fewer than five people using your Metabase, your bill will still be $100 that month.
|
||||
- Each additional person costs \$6, prorated for how many days their [accounts were available](#what-counts-as-a-user-account) that month. So if an account only existed for the last 10 days of your 30 day billing period, you'd only be charged for those 10 days, not for the full 30 days. Same goes if you deactivated an account prior to the end of the billing period, you'll only be charged for the days when the account was available for use during that billing period. Basically, you only ever pay for all accounts in your Metabase that haven't been deactivated yet.
|
||||
- Each additional person costs \$6, prorated for how many days their [accounts were available](#what-counts-as-a-user-account) that month. So if an account only existed for the last 10 days of your 30 day billing period, you'd only be charged for those 10 days, not for the full 30 days. Same goes if you deactivated an account before the end of the billing period, you'll only be charged for the days when the account was available for use during that billing period. Basically, you only ever pay for all accounts in your Metabase that haven't been deactivated yet.
|
||||
|
||||
## How annual billing works
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ title: API changelog
|
||||
When setting `archived` to `false`, you may optionally also provide a `collection_id` (for Dashboards or Cards) or a
|
||||
`parent_id` (for Collections). In this case, the entity will be re-parented to the specified Collection when it is
|
||||
moved from the Trash. If a new `collection_id` or `parent_id` is not provided, the entity will be moved back to its
|
||||
original location if possible. If this is not possible (for example, the original location is also in the Trash) an
|
||||
original location if possible. If this is impossible (for example, the original location is also in the Trash) an
|
||||
error will occur.
|
||||
|
||||
- `/api/metric`
|
||||
@@ -130,7 +130,7 @@ NOTE: These endpoint changes were added in 0.49.3, and a bug in `GET /api/embed/
|
||||
|
||||
The above endpoints now accept the `format_rows` query parameter. It is an optional boolean parameter that will default to `true` if not included in the request.
|
||||
When `format_rows` is `true`, the export will have formatting applied such that the values match what they appear as in the app.
|
||||
When `format_rows` is `false`, formatting is not applied and exports will behave as they did prior to 0.49.0.
|
||||
When `format_rows` is `false`, formatting is not applied and exports will behave as they did before 0.49.0.
|
||||
|
||||
The value of `format_rows` has no effect when exporting xlsx files.
|
||||
|
||||
|
||||
@@ -48,6 +48,12 @@ title: Driver interface changelog
|
||||
you can pass to [[metabase.lib.core/order-by]] -- for example a Lib `:metadata/column` or an [MBQL 5]
|
||||
`metabase.driver-api.core/order-by-clause`.
|
||||
|
||||
- `metabase.driver-api.core/nest-query` no longer automatically calls `metabase.driver-api.core/add-alias-info` on its
|
||||
results, but it also no longer expect its input to have this information. If you were using both of these tools in
|
||||
your driver, make change the order in which the are applied so `nest-query` happens first, followed by
|
||||
`add-alias-info`. Note that drivers deriving from `:sql` do not need to make any changes, since this is done by the
|
||||
base `:sql` driver implementation.
|
||||
|
||||
## Metabase 0.56.3
|
||||
|
||||
- Added the driver multi-method `driver/describe-database*` that drivers should now implement instead of `driver/describe-database`.
|
||||
@@ -100,7 +106,7 @@ title: Driver interface changelog
|
||||
|
||||
- Added a feature `:multi-level-schema` for drivers that support hierarchical levels between database and schema. Such as databricks' catalog. Defaults to false.
|
||||
|
||||
- Added the multi-method `adjust-schema-qualification` that allows drivers to to qualify, or unqualify table schemas based on enabling or disabling multi-level-schema support. Drivers may need to implement `sql.qp/->honeysql [driver ::h2x/identifier]` to properly quote fully qualified schemas.
|
||||
- Added the multi-method `adjust-schema-qualification` that allows drivers to qualify, or unqualify table schemas based on enabling or disabling multi-level-schema support. Drivers may need to implement `sql.qp/->honeysql [driver ::h2x/identifier]` to properly quote fully qualified schemas.
|
||||
|
||||
- Added the multi-method `float-dbtype` which returns the name of the float type we coerce to for coercion strategies and the `float()` custom expression function.
|
||||
|
||||
@@ -241,7 +247,7 @@ title: Driver interface changelog
|
||||
for better performance when saving Questions. Refer to the method docstring for more information and where to find
|
||||
an example implementation.
|
||||
|
||||
- Prior to 0.51.0, to generate SQL queries with inline parameters, Metabase would generate a parameterized SQL string,
|
||||
- Before 0.51.0, to generate SQL queries with inline parameters, Metabase would generate a parameterized SQL string,
|
||||
then attempt to parse the SQL replace and replace `?` placeholders with inline values from the driver method
|
||||
`metabase.driver.sql.util.unprepare/unprepare-value`. In 0.51.0+, Metabase instead generates these queries using
|
||||
Honey SQL 2's `:inline` option, eliminating the need to parse and replace `?` placeholders. As such, the
|
||||
@@ -319,7 +325,7 @@ title: Driver interface changelog
|
||||
- Similarly, `metabase.test.data.sql-jdbc.execute/execute-sql!` and helper functions like
|
||||
`metabase.test.data.sql-jdbc.execute/sequentially-execute-sql!` are now called with a `java.sql.Connection`
|
||||
instead of both a `DatabaseDefinition` and either `:server` or `:db` _context_; the appropriate connection type is
|
||||
created automatically and passed in in the calling code. Update your method implementations and usages
|
||||
created automatically and passed in the calling code. Update your method implementations and usages
|
||||
accordingly.
|
||||
|
||||
- Added method `metabase.test.data.interface/dataset-already-loaded?` to check if a test dataset has already been
|
||||
@@ -452,7 +458,7 @@ title: Driver interface changelog
|
||||
- New feature `:identifiers-with-spaces` has been added to indicate where a driver supports identifiers like table or
|
||||
column names that contains a space character. Defaults to `false`.
|
||||
|
||||
- New feature `:uuid-type` has been added to indicate that this database is able to distinguish and filter against UUIDs.
|
||||
- New feature `:uuid-type` has been added to indicate that this database can distinguish and filter against UUIDs.
|
||||
Only a few database support native UUID types. The default is `false`.
|
||||
|
||||
## Metabase 0.49.22
|
||||
@@ -576,7 +582,7 @@ title: Driver interface changelog
|
||||
new function takes a Field as returned by `lib.metadata/field`, i.e. a `kebab-case` map.
|
||||
|
||||
- Tests should try to avoid using any of the `with-temp` helpers or application database objects; instead, use the
|
||||
metadata functions above and and the helper _metadata providers_ in `metabase.lib`, `metabase.lib.test-util`, and
|
||||
metadata functions above and the helper _metadata providers_ in `metabase.lib`, `metabase.lib.test-util`, and
|
||||
`metabase.query-processor.test-util` for mocking them, such as `mock-metadata-provider`,
|
||||
`metabase-provider-with-cards-for-queries`, `remap-metadata-provider`, and `merged-mock-metadata-provider`.
|
||||
|
||||
@@ -831,7 +837,7 @@ differences between the library versions.
|
||||
|
||||
#### Breaking Changes in 0.46.0 related to the Honey SQL 2 transition
|
||||
|
||||
**Note: these breaking changes will hopefully be fixed before 0.46.0 ships. This will be updated if they are.**
|
||||
**Note: we expect these breaking changes to be fixed before 0.46.0 ships. This will be updated if they are.**
|
||||
|
||||
The classes `metabase.util.honeysql_extensions.Identifer` and `metabase.util.honeysql_extensions.TypedHoneySQLForm`
|
||||
have been moved to `metabase.util.honey_sql_1.Identifer` and `metabase.util.honey_sql_1.TypedHoneySQLForm`,
|
||||
|
||||
@@ -139,7 +139,7 @@ Documents work best for:
|
||||
|
||||
Dashboards work best for:
|
||||
|
||||
- Regular analysis. Numbers you want to keep an eye on every day, week, or month.
|
||||
- Regular analysis. Numbers you want to monitor every day, week, or month.
|
||||
- Filtering results across multiple charts.
|
||||
- More control over presentation.
|
||||
|
||||
|
||||
@@ -22,16 +22,18 @@ Currently you can choose to embed:
|
||||
- A question (chart). You can embed both questions built with the query builder and questions built with SQL.
|
||||
- Full graphical [query builder](../questions/query-builder/editor.md) to enable people to build their own charts and explorations.
|
||||
- A browser to navigate collections and open dashboards or questions.
|
||||
- [AI chat interface](./sdk/ai-chat.md).
|
||||
|
||||
## Quickstart
|
||||
|
||||
You can also follow the setup guide directly in Metabase in **Admin > Embedding > Setup guide**. We're recording the steps here for convenience.
|
||||
You can also follow the setup guide directly in Metabase in **Admin settings > Embedding > Setup guide**. We're recording the steps here for convenience.
|
||||
|
||||
### 1. Enable Embedded Analytics JS
|
||||
|
||||
1. In Metabase, go to **Admin > Embedding > Modular embedding**.
|
||||
1. In Metabase, go to **Admin settings > Embedding > Modular embedding**.
|
||||
2. Toggle on **Embedded Analytics JS**.
|
||||
3. Under **Cross-Origin Resource Sharing (CORS)**, add the URLs of the websites where you want to embed Metabase (such as `https://*.example.com`). For testing embeds, you can use `localhost` which is always included in CORS policy.
|
||||
4. If you are embedding Metabase components in a domain that's different from your Metabase's domain (including when you're testing the app locally but use Metabase Cloud), go to **Admin settings > Embedding > Security** and set **SameSite cookie** to **None**.
|
||||
|
||||
### 2. Create a new embed
|
||||
|
||||
@@ -40,10 +42,13 @@ You can also follow the setup guide directly in Metabase in **Admin > Embedding
|
||||
If you're planning to embed an existing question or dashboard, you can instead go straight to that question or dashboard, click on the **Share** button, and choose **Embedded Analytics JS**.
|
||||
|
||||
2. Choose the _type_ of entity to embed:
|
||||
|
||||
- Dashboard
|
||||
- Question
|
||||
- Chart
|
||||
- Exploration (which will embed the Metabase query builder)
|
||||
- Browser
|
||||
- Metabot question (which will embed AI chat)
|
||||
|
||||
3. Next, select the entity you want to embed. For browser, pick the collection you want people to start from.
|
||||
|
||||
Once you've selected what you want to embed, click Next to customize your embed.
|
||||
@@ -54,7 +59,7 @@ The exact customization options you see will depend on what type of entity you'r
|
||||
|
||||

|
||||
|
||||
You'll also be be able to pick brand, text, and background color used for all your embeds. To configure other colors (e.g. secondary colors, query builder colors etc), as well as font, you can specify a [theme](#theming) in your embed code snippet.
|
||||
You'll also be able to pick brand, text, and background color used for all your embeds. To configure other colors (e.g. secondary colors, query builder colors etc), as well as font, you can specify a [theme](#theming) in your embed code snippet.
|
||||
|
||||
All the customization options you select in this interactive flow will be reflected in the parameter values in the embed code, so you'll be able to adjust them later by editing the embed snippet.
|
||||
|
||||
@@ -124,7 +129,7 @@ Here's an example of a script:
|
||||
|
||||
Note the `defer` attribute and the reference to your Metabase URL in the script that loads `embed.js` library.
|
||||
|
||||
If you're embedding multiple entities on the same page, you only need to include the `<script>` tags once globally.
|
||||
If you're embedding multiple entities in a single page, you only need to include the `<script>` tags once globally.
|
||||
|
||||
You can also generate the code snippet for Embedded Analytics JS interactively in Metabase through **Admin > Embedding > Setup guide > Embed in your code**. Check out the [quickstart](#quickstart).
|
||||
|
||||
@@ -150,7 +155,7 @@ When you're creating a new embed using **Admin > Embedding > Setup guide > Embed
|
||||
|
||||
To define the configuration that applies to every embed on the page, use the `defineMetabaseConfig()` function. Its parameters include:
|
||||
|
||||
- `instanceUrl: "https://your-metabase-url"` (required): the URL of your Metabase instance, like https://youlooknicetoday.metabaseapp.com
|
||||
- `instanceUrl: "https://your-metabase-url"` (required): the URL of your Metabase instance, like `https://youlooknicetoday.metabaseapp.com`
|
||||
|
||||
- `theme: {...}` (optional): [appearance options for the embeds](#theming).
|
||||
|
||||
@@ -354,7 +359,7 @@ To render a dashboard:
|
||||
|
||||
### Question
|
||||
|
||||
To render a question (chart).
|
||||
To render a question (chart):
|
||||
|
||||
```html
|
||||
<metabase-question question-id="1"></metabase-question>
|
||||
@@ -375,9 +380,9 @@ To render a question (chart).
|
||||
- `is-save-enabled` (default is false)
|
||||
- `target-collection` - this is to enforce saving into a particular collection. Values: regular ID, entity ID, `"personal”`, `"root”`
|
||||
|
||||
- ### Browser
|
||||
### Browser
|
||||
|
||||
To render a collection browser so people can navigate a collection and open dashboards or questions.
|
||||
To render a collection browser so people can navigate a collection and open dashboards or questions:
|
||||
|
||||
```html
|
||||
<metabase-browser initial-collection="14" read-only="false"></metabase-browser>
|
||||
@@ -390,3 +395,40 @@ To render a collection browser so people can navigate a collection and open dash
|
||||
**Optional parameters:**
|
||||
|
||||
- `read-only` (default is true) – if true, people can interact with items (filter, summarize, drill-through) but cannot save. If false, they can create and edit items in the collection.
|
||||
|
||||
### Metabot
|
||||
|
||||
To render the AI chat interface:
|
||||
|
||||
```html
|
||||
<metabase-metabot></metabase-metabot>
|
||||
```
|
||||
|
||||
**Required parameters:**
|
||||
|
||||
None.
|
||||
|
||||
**Optional parameters:**
|
||||
|
||||
- `layout` (default is `auto`) – how should the browser position the visualization with respect to the chat interface. Possible values are:
|
||||
- `auto` (default): Metabot uses the `stacked` layout on mobile screens, and a `sidebar` layout on larger screens.
|
||||
- `stacked`: the question visualization stacks on top of the chat interface.
|
||||
- `sidebar`: the question visualization appears to the left of the chat interface, which is in the right sidebar.
|
||||
|
||||
## Embedding Metabase in a different domain
|
||||
|
||||
If you want to embed Metabase in another domain (say, if Metabase is hosted at `metabase.yourcompany.com`, but you want to embed Metabase at `yourcompany.github.io`), you can tell Metabase to set the session cookie's SameSite value to "none".
|
||||
|
||||
You can set session cookie's SameSite value in **Admin settings** > **Embedding** > **Security** > **SameSite cookie setting**.
|
||||
|
||||
SameSite values include:
|
||||
|
||||
- **Lax** (default): Allows Metabase session cookies to be shared on the same domain. Used for production instances on the same domain.
|
||||
- **None (requires HTTPS)**: Use "None" when your app and Metabase are hosted on different domains. Incompatible with Safari and iOS-based browsers.
|
||||
- **Strict** (not recommended): Does not allow Metabase session cookies to be shared with embedded instances. Use this if you do not want to enable session sharing with embedding.
|
||||
|
||||
You can also set the [`MB_SESSION_COOKIE_SAMESITE` environment variable](../configuring-metabase/environment-variables.md#mb_session_cookie_samesite).
|
||||
|
||||
If you're using Safari, you'll need to [allow cross-site tracking](https://support.apple.com/en-tj/guide/safari/sfri40732/mac). Depending on the browser, you may also run into issues when viewing emdedded items in private/incognito tabs.
|
||||
|
||||
Learn more about [SameSite cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite).
|
||||
|
||||
@@ -34,7 +34,7 @@ Check out the [Interactive embedding quick start](./interactive-embedding-quick-
|
||||
|
||||
If you're dealing with a [multi-tenant](https://www.metabase.com/learn/metabase-basics/embedding/multi-tenant-self-service-analytics) situation, check out our recommendations for [Configuring permissions for different customer schemas](../permissions/embedding.md).
|
||||
|
||||
If you have your app running locally, and you're using the Pro Cloud version, or hosting Metabase and your app in different domains, you'll need to set your Metabase environment's session cookie samesite option to "none".
|
||||
If you have your app running locally, and you're using the Pro Cloud version, or hosting Metabase and your app in different domains, you'll need to set your Metabase environment's session cookie SameSite option to "none".
|
||||
|
||||
## Enabling interactive embedding in Metabase
|
||||
|
||||
@@ -128,13 +128,13 @@ Note that your interactive embed must be compatible with Safari to run on _any_
|
||||
|
||||
If you want to embed Metabase in another domain (say, if Metabase is hosted at `metabase.yourcompany.com`, but you want to embed Metabase at `yourcompany.github.io`), you can tell Metabase to set the session cookie's SameSite value to "none".
|
||||
|
||||
You can set session cookie's SameSite value in **Admin settings** > **Embedding** > **Interactive** > **SameSite cookie setting**.
|
||||
You can set session cookie's SameSite value in **Admin settings** > **Embedding** > **Security** > **SameSite cookie setting**.
|
||||
|
||||
SameSite values include:
|
||||
|
||||
- **Lax** (default): Allows cookies to be sent when someone navigates to the origin site from an external site (like when following a link).
|
||||
- **None**: Allows all cross-site requests. Incompatible with most Safari and iOS browsers, such as Chrome on iOS. If you set this environment variable to "None", you must use HTTPS in Metabase to prevent browsers from rejecting the request.
|
||||
- **Strict** (not recommended): Never allows cookies to be sent on a cross-site request. Warning: this will prevent users from following external links to Metabase.
|
||||
- **Lax** (default): Allows Metabase session cookies to be shared on the same domain. Used for production instances on the same domain.
|
||||
- **None (requires HTTPS)**: Use "None" when your app and Metabase are hosted on different domains. Incompatible with Safari and iOS-based browsers.
|
||||
- **Strict** (not recommended): Does not allow Metabase session cookies to be shared with embedded instances. Use this if you do not want to enable session sharing with embedding.
|
||||
|
||||
You can also set the [`MB_SESSION_COOKIE_SAMESITE` environment variable](../configuring-metabase/environment-variables.md#mb_session_cookie_samesite).
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ redirect_from:
|
||||
|
||||
> Only admins can create public links and iframes.
|
||||
|
||||
Admins can create and share public links (URLs) for questions and dashboards. People can view them as standalone destinations (URLs) or as embedded iframes in another page or app. In both cases, the public item will display static (view-only) results of your question or dashboard, so visitors won't be able to drill-down into the underlying data on their own.
|
||||
Admins can create and share public links (URLs) for questions and dashboards. People can view them as standalone destinations (URLs) or as embedded iframes in another page or app. In both cases, the public item will display static (view-only) results of your question or dashboard, so visitors won't be able to drill down into the underlying data on their own.
|
||||
|
||||
## Create a public link for a question
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ You can check out a [demo of the AI chat component](https://embedded-analytics-s
|
||||
{% include_file "{{ dirname }}/snippets/questions/ai-question.tsx" %}
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
{% include_file "{{ dirname }}/api/snippets/MetabotQuestionProps.md" snippet="properties" %}
|
||||
|
||||
## API reference
|
||||
|
||||
- [Component](./api/MetabotQuestion.html)
|
||||
|
||||
@@ -102,7 +102,7 @@ From any Metabase page, click on the **gear** icon in the upper right and select
|
||||
|
||||
Turn on:
|
||||
|
||||
- Embedded analytics SDK (it's in in the **Modular** section)
|
||||
- Embedded analytics SDK (it's in the **Modular** section)
|
||||
- Static embedding
|
||||
|
||||
Otherwise, this whole thing is hopeless.
|
||||
|
||||
@@ -65,6 +65,9 @@ const theme = defineMetabaseTheme({
|
||||
// Color used to indicate dangerous actions and negative values/trends
|
||||
negative: "#FF7979",
|
||||
|
||||
/** Color used to outline elements in focus */
|
||||
focus: "#CAE1F7",
|
||||
|
||||
/** Color used for popover shadows */
|
||||
shadow: "rgba(0,0,0,0.08)",
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ yarn add @metabase/embedding-sdk-react@{next-major-version-number}-stable
|
||||
|
||||
See more on [SDK versions](./version.md).
|
||||
|
||||
### If there are deprecations or breaking changes changes, make the necessary changes to your application code
|
||||
### If there are deprecations or breaking changes, make the necessary changes to your application code
|
||||
|
||||
Deprecations or breaking changes are rare, but if you do need to make changes, we'll mention it in the release notes for the new major version and have docs that walk you through the changes.
|
||||
|
||||
|
||||
@@ -174,7 +174,8 @@ This key is shared across all static embeds. Whoever has access to this key coul
|
||||
Dashboards are a fixed aspect ratio, so if you'd like to ensure they're automatically sized vertically to fit their contents you can use the [iFrame Resizer](https://github.com/davidjbradshaw/iframe-resizer) script. Metabase serves a copy for convenience:
|
||||
|
||||
```html
|
||||
<script src="https://metabase.example.com/app/iframeResizer.js"></script>
|
||||
<script src="{your-metabase-url}/app/iframeResizer.js"></script>
|
||||
|
||||
<iframe
|
||||
src="https://metabase.example.com/embed/dashboard/TOKEN"
|
||||
onload="iFrameResize({}, this)"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
---
|
||||
title: Delete and restore
|
||||
summary: You can move questions, dashboards, models, and metrics to Trash where they can be restored or permanently deleted. Deleting items affects related content like dashboards and subscriptions. Other entities in Metabase can be deleted or archived, but won't show up in Trash.
|
||||
---
|
||||
|
||||
# Delete and restore
|
||||
|
||||
Sometimes your questions, dashboards, models, or collections outlive their usefulness. You can send outdated items to **Trash**.
|
||||
Sometimes your questions, dashboards, models, metrics, or collections outlive their usefulness. You can send outdated items to **Trash**.
|
||||
|
||||

|
||||
|
||||
@@ -104,7 +105,7 @@ What happens to related items when you delete a collection?
|
||||
| ---------------------------------------------- | -------- | ------------------- | -------- |
|
||||
| All items and subcollections in the collection | In Trash | N/A | Restored |
|
||||
|
||||
> You can't permanently delete collections
|
||||
> You can't permanently delete collections.
|
||||
|
||||
## Permanently deleting items
|
||||
|
||||
@@ -117,7 +118,7 @@ To permanently delete an item:
|
||||
3. Click on the checkbox next to the item to select it;
|
||||
4. Select "Permanently delete". If you click this button, you won't be able to recover the item. It'll be lost to the void.
|
||||
|
||||
> You can't permanently delete collections
|
||||
> You can't permanently delete collections.
|
||||
|
||||
## Deleting and restoring events and timelines
|
||||
|
||||
@@ -131,13 +132,11 @@ Snippets can be archived and unarchived. See [Archiving snippets](../questions/n
|
||||
|
||||
## Deleting segments
|
||||
|
||||
Segments can be retired. See [Retiring Segments](../data-modeling/segments.md#editing-and-retiring-segments).
|
||||
|
||||
You won't see retired Segments in Trash.
|
||||
Segments can be retired. See [Retiring Segments](../data-modeling/segments.md#editing-and-retiring-segments). You won't see retired Segments in Trash.
|
||||
|
||||
## Deleting subscriptions and alerts
|
||||
|
||||
See [Deleting a subscription](../dashboards/subscriptions.md#deleting-a-subscription) and [Deleting alerts](../questions/alerts.md#editing-and-deleting-alerts).
|
||||
See [Deleting a subscription](../dashboards/subscriptions.md#deleting-a-subscription) and [Deleting alerts](../questions/alerts.md#editing-deleting-and-unsubscribing-from-alerts).
|
||||
|
||||
## Deleting databases
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ View changes to a question, dashboard or model and revert to previous versions.
|
||||
|
||||
## [Delete and restore items](./delete-and-restore.md)
|
||||
|
||||
Move outdated outdated questions, models, and dashboards to trash, or delete them permanently.
|
||||
Move outdated questions, models, and dashboards to trash, or delete them permanently.
|
||||
|
||||
## [Data reference](./data-model-reference.md)
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ If you've already been running Metabase with the default application database (H
|
||||
|
||||
Here's an example `docker-compose.yml` file for running Metabase with a PostgreSQL database `metabaseappdb`:
|
||||
|
||||
> This is an example file and and is not meant to be used when running Metabase in a production environment. Please refer to our guide about [How to run Metabase in production](https://www.metabase.com/learn/metabase-basics/administration/administration-and-operation/metabase-in-production)
|
||||
> This is an example file and is not meant to be used when running Metabase in a production environment. Please refer to our guide about [How to run Metabase in production](https://www.metabase.com/learn/metabase-basics/administration/administration-and-operation/metabase-in-production)
|
||||
|
||||
```yml
|
||||
services:
|
||||
@@ -343,7 +343,7 @@ We currently support the following [environment variables](../configuring-metaba
|
||||
|
||||
In order for the Metabase container to read the files and use the contents as a secret, the environment variable name needs to be appended with a "\_FILE" as explained above.
|
||||
|
||||
> This is an example file and and is not meant to be used when running Metabase in a production environment. Please refer to our guide about [How to run Metabase in production](https://www.metabase.com/learn/metabase-basics/administration/administration-and-operation/metabase-in-production).
|
||||
> This is an example file and is not meant to be used when running Metabase in a production environment. Please refer to our guide about [How to run Metabase in production](https://www.metabase.com/learn/metabase-basics/administration/administration-and-operation/metabase-in-production).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ If you've already been running Metabase with the default application database (H
|
||||
|
||||
### Running Metabase as a service
|
||||
|
||||
We can use the [systemd](https://systemd.io/) initialization service to register a Metabase service that can be started and stopped automatically. Prior to executing this process, ensure that the Metabase container is operational. Then, utilize Podman's built-in feature to generate the service file as follows:
|
||||
We can use the [systemd](https://systemd.io/) initialization service to register a Metabase service that can be started and stopped automatically. Before executing this process, ensure that the Metabase container is operational. Then, utilize Podman's built-in feature to generate the service file as follows:
|
||||
|
||||
```
|
||||
sudo podman generate systemd --new --name metabase > metabase.service
|
||||
|
||||
@@ -50,7 +50,7 @@ To add a user attribute manually:
|
||||
4. Click **+ Add an attribute**.
|
||||
5. Add the name of the user attribute under "Key". For example, "Department".
|
||||
6. Add the value that applies to the specific person. For example, "Engineering".
|
||||
7. Optional: [create a group](#creating-a-group) to organize people who will get get row and column security.
|
||||
7. Optional: [create a group](#creating-a-group) to organize people who will get row and column security.
|
||||
8. Add the person to the group.
|
||||
|
||||
You can also sync user attributes from your identity provider [via SSO](./start.md#authentication).
|
||||
|
||||
@@ -6,14 +6,22 @@ title: Impersonation access
|
||||
|
||||
{% include plans-blockquote.html feature="Impersonation access" %}
|
||||
|
||||
> For now, impersonation access is only available for ClickHouse, MySQL, PostgreSQL, Redshift, Snowflake, and SQL Server. If you want to switch database _connections_ based on who is logged in, check out [Database routing](./database-routing.md).
|
||||
|
||||
> If you're using views in PostgresSQL, the row-level security policies on views will only work on Postgres versions 15 and higher.
|
||||
|
||||
This page covers the [View data](./data.md#view-data-permissions) permission level called Impersonation.
|
||||
|
||||
**Impersonation access** allows admins to "outsource" View data permissions to roles in your database. Admins can associate user attributes with database-defined roles and their privileges. If someone is in a group with their View data permission set to Impersonation, the person will be able to view and query data based on the privileges granted to the role specified by their user attribute.
|
||||
|
||||
## Databases that support impersonation
|
||||
|
||||
For now, impersonation access is only available for the following databases:
|
||||
- ClickHouse
|
||||
- MySQL
|
||||
- PostgreSQL. If you're using views in PostgresSQL, the row-level security policies on views will only work on Postgres versions 15 and higher.
|
||||
- Redshift
|
||||
- Snowflake
|
||||
- SQL Server.
|
||||
|
||||
If you want to switch database _connections_ based on who is logged in, check out [Database routing](./database-routing.md).
|
||||
|
||||
## Impersonation vs row and column security
|
||||
|
||||
### Impersonation sets permissions for questions written in both the SQL editor and the query builder
|
||||
@@ -39,7 +47,7 @@ For impersonation access to work, you'll first need to set up roles in your data
|
||||
|
||||
### Set up Metabase database connection for impersonation
|
||||
|
||||
Impersonation uses database roles to run queries on your database, but there still needs to be a default role that that will be used to run operations like [sync, scans, and fingerprinting](../databases/sync-scan.md). So the user account that Metabase uses to [connect to your database](../databases/connecting.md) should have access to everything in that database that any Metabase group may need access to, as that database user account is what Metabase uses to sync table information.
|
||||
Impersonation uses database roles to run queries on your database, but there still needs to be a default role that will be used to run operations like [sync, scans, and fingerprinting](../databases/sync-scan.md). So the user account that Metabase uses to [connect to your database](../databases/connecting.md) should have access to everything in that database that any Metabase group may need access to, as that database user account is what Metabase uses to sync table information.
|
||||
|
||||
You can then create roles in the database that have more restrictive access to the database (like row-level or table-level security). When the role is passed to the database using impersonation, the engine will return a subset of the data, or restrict the query altogether.
|
||||
|
||||
@@ -111,7 +119,7 @@ People in one group can have different attribute values, but must have the same
|
||||
|
||||
1. In Metabase, hit Cmd/Ctrl + K to bring up the command palette and search for **Permissions**, or go directly to **Admin settings** > **Permissions** > **Data**.
|
||||
|
||||
2. Select the group that you want to to associate with the database role you created.
|
||||
2. Select the group that you want to associate with the database role you created.
|
||||
|
||||
3. Select the database to configure access to.
|
||||
|
||||
|
||||
@@ -29,13 +29,16 @@ Only admins and people with [settings access](../permissions/application.md#sett
|
||||
To create an alert:
|
||||
|
||||
1. Save your question.
|
||||
2. Click on the sharing icon in the top-right of the screen.
|
||||
2. Click on the **three dots** in the top-right of the screen.
|
||||
3. Select **Create an alert**.
|
||||
4. Select what you want to be alerted about. The alert options will depend on the question's visualization. See [types of alerts](#types-of-alerts).
|
||||
5. Select when you want Metabase to check the results. Metabase can check for results by the minute, hourly, daily, weekly, monthly, or on a custom schedule that you set using the Quartz [cron syntax](https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html).
|
||||
6. Select the alert's destination: [email](../configuring-metabase/email.md), [Slack](../configuring-metabase/slack.md), or to a [webhook](../configuring-metabase/webhooks.md) (only admins and people with [settings access](../permissions/application.md#settings-access) can create and send to webhooks).
|
||||
7. Configure any other options (like [only sending the alert once](#send-a-one-time-alert)).
|
||||
8. Click **Done**.
|
||||
4. Select what you want to be alerted about (options depend on the question type):
|
||||
- [When a question returns a result](#results-alerts) - for any question.
|
||||
- [When a time series crosses a goal line](#goal-line-alerts) - for a line, bar, or area chart displaying a time series.
|
||||
- [When a progress bar reaches or goes below its goal](#progress-bar-alerts) - for progress bars.
|
||||
6. Select when you want Metabase to check the results: by the minute, hourly, daily, weekly, monthly, or on a custom schedule that you set using the Quartz [cron syntax](https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html).
|
||||
7. Select the alert's destination: [email](../configuring-metabase/email.md), [Slack](../configuring-metabase/slack.md), or to a [webhook](../configuring-metabase/webhooks.md) (only admins and people with [settings access](../permissions/application.md#settings-access) can create and send to webhooks).
|
||||
8. Configure any other options (like [only sending the alert once](#send-a-one-time-alert)).
|
||||
9. Click **Done**.
|
||||
|
||||
## Send a one-time alert
|
||||
|
||||
@@ -47,12 +50,6 @@ To test the alert, first make sure that the question returns results (if the que
|
||||
|
||||
Then hit the **Send now** button to trigger the alert.
|
||||
|
||||
## Types of alerts
|
||||
|
||||
- [Results alerts](#results-alerts): when a question returns any result.
|
||||
- [Goal line alerts](#goal-line-alerts) when a time series crosses a goal line.
|
||||
- [Progress bar alerts](#progress-bar-alerts): when a progress bar reaches or goes below its goal.
|
||||
|
||||
## Results alerts
|
||||
|
||||
Metabase can send you an alert on a schedule when one of your questions returns _any_ result. This kind of alert is also particularly useful if you have a question that doesn't _usually_ return any results, but you want to know when the question _does_ return results.
|
||||
@@ -69,27 +66,22 @@ _Requires a [bar, line, or area chart](./visualizations/line-bar-and-area-charts
|
||||
|
||||
Goal line alerts are useful when you're doing things like tracking daily active users (DAU) and you want to know when you reach a certain number of DAU, or when you're tracking orders per week and you want to know whenever the number of orders ever goes below a certain threshold.
|
||||
|
||||
To start, you'll need a line, area, or bar chart displaying a number over time.
|
||||
To create an alert when a time series crosses a goal line:
|
||||
|
||||
Next, you need to set up a goal line on your chart. Open up the visualization settings by clicking the **gear** icon in the bottom-left. Then click on the **Display** tab, and turn on the **Show goal** setting. Choose a value for your goal (and optionally a label) and click Done.
|
||||
1. Create a line, area, or bar chart displaying a number over time.
|
||||
2. Open up the visualization settings by clicking the **gear** icon in the bottom-left.
|
||||
3. In the **Display** tab, turn on the **Show goal** setting.
|
||||
4. Choose a value for your goal (and optionally a label) and click Done.
|
||||
5. Save the question.
|
||||
6. Click the **three dots** icon in top and select "Create alert"
|
||||
|
||||
You can choose:
|
||||
You can choose:
|
||||
|
||||
- Whether you want Metabase to alert you when the time series goes above the goal line or when it goes below the goal line.
|
||||
- Whether you want Metabase to alert you every time the time series crosses a goal line, or only the first time it crosses the goal line.
|
||||
- How often you want Metabase to check to see if the goal line has been crossed.
|
||||
|
||||
- Whether you want Metabase to alert you when the time series goes above the goal line or when it goes below the goal line.
|
||||
- Whether you want Metabase to alert you every time the time series crosses a goal line, or only the first time it crosses the goal line.
|
||||
- How often you want Metabase to check to see if the goal line has been crossed.
|
||||
|
||||
Click Done, and your alert will be all set up!
|
||||
|
||||
If you need to edit or unsubscribe from the alert you set up, just click that same icon. You'll see the Edit and Unsubscribe buttons. This is also where you'll see alerts about this question that admins might have added you to.
|
||||
|
||||
Metabase will email you when:
|
||||
|
||||
- You set up an alert
|
||||
- You've been unsubscribed from an alert
|
||||
- One of your alerts has stopped working
|
||||
- You unsubscribed from an alert
|
||||
- An admin added you to an alert
|
||||
7. Select the schedule and recepients for the alert, and click "Done"
|
||||
|
||||
## Progress bar alerts
|
||||
|
||||
@@ -97,11 +89,11 @@ _Requires the [progress bar visualization](./visualizations/progress-bar.md)._
|
||||
|
||||
If you want to set up an alert when a single number reaches a goal, you can use a progress bar visualization.
|
||||
|
||||
1. Create a question that returns a single number as its result,
|
||||
2. Choose the Progress Bar chart type,
|
||||
3. In Visualization settings, select a goal value
|
||||
4. Save your question,
|
||||
5. Create an alert by clicking on the Sharing icon in top right
|
||||
1. Create a question that returns a single number as its result.
|
||||
2. Choose the Progress Bar chart type.
|
||||
3. In Visualization settings, select a goal value.
|
||||
4. Save your question.
|
||||
5. Create an alert by clicking the **three dots** in top right.
|
||||
|
||||
You'll see the options for when you want to get alerts about this progress bar:
|
||||
|
||||
@@ -109,9 +101,9 @@ You'll see the options for when you want to get alerts about this progress bar:
|
||||
- Whether to alert only the first time the progress bar reaches the goal line, or every time
|
||||
- How often you want Metabase to check to see if the goal has been reached.
|
||||
|
||||
## Editing and deleting alerts
|
||||
## Editing, deleting, and unsubscribing from alerts
|
||||
|
||||
To edit or delete alerts on a question, click on the Sharing icon in the top right corner. What you can edit depends on whether you're an admin.
|
||||
To edit or delete alerts on a question, click on the **three dots** icon in the top right corner and select **Edit alerts**. What you can edit depends on whether you're an admin.
|
||||
|
||||
Everyone:
|
||||
|
||||
@@ -124,6 +116,14 @@ Admins:
|
||||
- Admins can add or remove recipients on any alert, even ones that they didn't create themselves.
|
||||
- Admins can bulk manage alerts per person from the [People menu in Admin settings](../people-and-groups/managing.md#unsubscribe-from-all-subscriptions-and-alerts).
|
||||
|
||||
Metabase will email you when:
|
||||
|
||||
- You set up an alert
|
||||
- You've been unsubscribed from an alert
|
||||
- One of your alerts has stopped working
|
||||
- You unsubscribed from an alert
|
||||
- An admin added you to an alert
|
||||
|
||||
## Avoid changing the name of the alerted channel in Slack
|
||||
|
||||
Once you set up an alert to a Slack channel, avoid changing the name of that channel in Slack. If you rename the channel in Slack, but you want Metabase to continue to send alerts to that renamed channel, you'll need to update the alert in Metabase to point to the new channel name.
|
||||
|
||||
@@ -61,7 +61,7 @@ If you use a datetime dimension in the **Group by** block, Metabase will accumul
|
||||
|
||||

|
||||
|
||||
If there are multiple datetime dimensions (including multiple groupings by the same datetime column), Metabase will accumulate along the the more granular dimension, regardless of their order. For example, if you're grouping by "Created At: Month" and "Viewed At: Week", Metabase will accumulate along "Viewed At: Week".
|
||||
If there are multiple datetime dimensions (including multiple groupings by the same datetime column), Metabase will accumulate along the more granular dimension, regardless of their order. For example, if you're grouping by "Created At: Month" and "Viewed At: Week", Metabase will accumulate along "Viewed At: Week".
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -91,5 +91,5 @@ Here's an incomplete list of example functions:
|
||||
| -------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
||||
| Postgres | `EXTRACT(WEEK FROM TIMESTAMP created_at)` | ISO algorithm |
|
||||
| MySQL | `WEEKOFYEAR("2017-06-15")` | The first day of the week is Monday and the first week of the year has more than 3 days. Alternative functions exist. |
|
||||
| BigQuery | `EXTRACT(WEEK FROM DATE ticreated_at)` | Weeks numbered from 0. Dates prior to the first Sunday of the year are in week 0. Alternative functions exist. |
|
||||
| BigQuery | `EXTRACT(WEEK FROM DATE ticreated_at)` | Weeks numbered from 0. Dates before the first Sunday of the year are in week 0. Alternative functions exist. |
|
||||
| Redshift | `DATE_PART(week, TIMESTAMP created_at)` | ISO algorithm |
|
||||
|
||||
@@ -36,7 +36,7 @@ By default, Metabase will present steps in the same order as they appear in the
|
||||
|
||||
To create a query with a result that has the shape required for a funnel chart, you'll probably need to summarize your data.
|
||||
|
||||
If your (original, unaggregated) data already contains a field with the the step for every data point, you can build a simple query with a breakout by steps:
|
||||
If your (original, unaggregated) data already contains a field with the step for every data point, you can build a simple query with a breakout by steps:
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Maps
|
||||
redirect_from:
|
||||
- /docs/latest/questions/sharing/visualizations/maps
|
||||
description: "Maps in Metabase allow you to visualize geographical data either using coordinates or by region. Metabase gives you three types of maps : pin map for unaggregated data, grid map for histograms, and region map for distributions by regions like countries or states. You can also create custom maps."
|
||||
description: "Maps in Metabase allow you to visualize geographic data either using coordinates or by region. Metabase gives you three types of maps : pin map for unaggregated data, grid map for histograms, and region map for distributions by regions like countries or states. You can also create custom maps."
|
||||
---
|
||||
|
||||
# Maps
|
||||
@@ -13,7 +13,7 @@ Metabase has three types of map visualization:
|
||||
- [**Grid map**](#grid-map) for distributing a large number of points over a specified area.
|
||||
- [**Region map**](#region-maps) for data broken out by regions, like countries or states. Metabase comes with two built-in maps, but you can upload your own custom regions.
|
||||
|
||||
When you select the **Map** visualization setting, Metabase will automatically try and pick the best kind of map to use based on the table or result set, as long as the columns with the geographical data have the [right metadata](../../data-modeling/metadata-editing.md).
|
||||
When you select the **Map** visualization setting, Metabase will automatically try and pick the best kind of map to use based on the table or result set, as long as the columns with the geographic data have the [right metadata](../../data-modeling/metadata-editing.md).
|
||||
|
||||

|
||||
|
||||
@@ -21,7 +21,7 @@ When you select the **Map** visualization setting, Metabase will automatically t
|
||||
|
||||
## Pin map
|
||||
|
||||
Pin maps display markers or tiles for individual data points on the map. They work best for displaying small amounts of unaggregated geographical data.
|
||||
Pin maps display markers or tiles for individual data points on the map. They work best for displaying small amounts of unaggregated geographic data.
|
||||
|
||||
### Pin map data shape
|
||||
|
||||
@@ -59,11 +59,11 @@ To change the pin type:
|
||||
|
||||
By default, maps can't display more than 2,000 individual unaggregated data points, regardless of the pin type. This limit is the same for every chart displaying unaggregated data in Metabase. To increase the number of data points rendered on charts based on unaggregated queries, you can use the environment variable [`MB_UNAGGREGATED_QUERY_ROW_LIMIT`](../../configuring-metabase/environment-variables.md#mb_unaggregated_query_row_limit). This setting will affect data points on _all_ charts—not just the pin maps—so increasing the limit too much could significantly slow down your Metabase and your browswer.
|
||||
|
||||
If you need to display a large number of geographical data points, consider using a grid map to display the distribution instead.
|
||||
If you need to display a large number of geographic data points, consider using a grid map to display the distribution instead.
|
||||
|
||||
## Grid map
|
||||
|
||||
Grid map is an aggregated version of the pin map — like a heatmap for the distribution of pins. Grid map breaks the the map into a grid based on latitude/longitude, and then colors each grid cell based on how many data points fall in it.
|
||||
Grid map is an aggregated version of the pin map — like a heatmap for the distribution of pins. Grid map breaks the map into a grid based on latitude/longitude, and then colors each grid cell based on how many data points fall in it.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ A **pie chart** can be used when breaking out a metric by a single dimension. In
|
||||
|
||||
Pie charts can be used to visualize a metric as part of a whole. Sunburst charts can be used to visualize hierarchical or nested data, or display multiple levels of categorization.
|
||||
|
||||
Pie and sunburst charts work best when when the number of possible breakout values is small, like accounts by plan. These charts should only be used to visualize metrics that add up to 100% (like count or sum of total).
|
||||
Pie and sunburst charts work best when the number of possible breakout values is small, like accounts by plan. These charts should only be used to visualize metrics that add up to 100% (like count or sum of total).
|
||||
|
||||
Pie charts should be used to communicate a general sense of the relative sizes of breakouts. If precise comparison is important so people can see the exact differences between values, or you have more than a few breakouts (like customers per country), it's usually better to use a bar or row chart.
|
||||
|
||||
|
||||
@@ -102,4 +102,4 @@ There are special considerations when exporting pivot tables as XLSX files. See
|
||||
- Pivot tables are only available for questions built with the query builder.
|
||||
- The query builder question must have a summary block.
|
||||
|
||||
If you must use SQL, and your SQL query does not have parameters, you can save that SQL query , then use its [results as the starting point](../native-editor/writing-sql.md#explore-sql-question-results-using-the-query-builder) for a query builder question in order to build a question. The trick here is to do your aggregation and grouping in the query builder. That is, use the SQL question to grab the raw data you want to work with (maybe [create a model](../../data-modeling/models.md)), then start a new question in the query builder to filter, summarize, and group that data.
|
||||
If you must use SQL, and your SQL query doesn't have parameters, you can save that SQL query , then use its [results as the starting point](../native-editor/writing-sql.md#explore-sql-question-results-using-the-query-builder) for a query builder question in order to build a question. The trick here is to do your aggregation and grouping in the query builder. That is, use the SQL question to grab the raw data you want to work with (maybe [create a model](../../data-modeling/models.md)), then start a new question in the query builder to filter, summarize, and group that data.
|
||||
|
||||
@@ -12,7 +12,7 @@ redirect_from:
|
||||
|
||||
## When to use a progress bar
|
||||
|
||||
Progress bars are useful when you want to show the movement of a metric toward a goal, like assessing performance of a KPI, or tracking the percentage of of completion on a project.
|
||||
Progress bars are useful when you want to show the movement of a metric toward a goal, like assessing performance of a KPI, or tracking the percentage of completion on a project.
|
||||
|
||||
Progress bars give you an option to set up an alert whenever the result of a question reaches the goal set in the progress bar settings. See [Progress bar alerts](../alerts.md#progress-bar-alerts).
|
||||
|
||||
|
||||
@@ -26,6 +26,6 @@ Or you could display one of the metrics on the chart, and include the other metr
|
||||
|
||||
Removing a metric will give you the option to add it as an additional metric to the tooltip. In the visualization settings, click on the **Display** tab, and add **Additional tooltip metrics**. Only metrics included in the summarization step of the question are available to add to the tooltip.
|
||||
|
||||

|
||||

|
||||
|
||||
Here we've kept the count on the chart, but now when you hover over a bar on the chart, the tooltip also includes the relevant average.
|
||||
|
||||
@@ -128,13 +128,11 @@
|
||||
"redux-auth-wrapper": "^2.1.0",
|
||||
"redux-promise": "^0.6.0",
|
||||
"redux-undo": "^1.1.0",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"rehype-external-links": "^2.0.1",
|
||||
"remark-gfm": "1.0.0",
|
||||
"reselect": "^5.1.0",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"screenfull": "^6.0.2",
|
||||
"scroll-into-view-if-needed": "^3.1.0",
|
||||
"server-text-width": "^1.0.2",
|
||||
"simple-statistics": "^3.0.0",
|
||||
"slugg": "^1.2.1",
|
||||
|
||||
@@ -49,6 +49,7 @@ const CypressBackend = {
|
||||
MB_DB_CONNECTION_URI: "", // ignore connection URI in favor of the db file
|
||||
MB_CONFIG_FILE_PATH: "__cypress__", // ignore config.yml
|
||||
MB_HTTP_CHANNEL_HOST_STRATEGY: "allow-all", // we use a local webhook service for testing
|
||||
MB_IS_CYPRESS: "true", // custom flag so we can detect we're running in Cypress, used in tests.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||