Compare commits
1 Commits
adm-759-de
...
fix-python
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d22eeba6c3 |
@@ -417,11 +417,13 @@
|
||||
metabase.model-persistence.core model-persistence
|
||||
metabase.models.dependency dependency
|
||||
metabase.models.interface mi
|
||||
metabase.models.setting setting
|
||||
metabase.notification.core notification
|
||||
metabase.notification.payload.core notification.payload
|
||||
metabase.notification.test-util notification.tu
|
||||
metabase.permissions.core perms
|
||||
metabase.plugins.initialize plugins.init
|
||||
metabase.public-settings public-settings
|
||||
metabase.public-sharing.core public-sharing
|
||||
metabase.premium-features.core premium-features
|
||||
metabase.pulse.core pulse
|
||||
@@ -464,7 +466,6 @@
|
||||
metabase.server.core server
|
||||
metabase.server.protocols server.protocols
|
||||
metabase.sso.core sso
|
||||
metabase.settings.core setting
|
||||
metabase.sync.analyze.fingerprint sync.fingerprint
|
||||
metabase.sync.field-values sync.field-values
|
||||
metabase.sync.interface i
|
||||
@@ -549,10 +550,14 @@
|
||||
metabase.driver.sql-jdbc.execute.diagnostic/capturing-diagnostic-info clojure.core/fn
|
||||
metabase.models.collection-test/with-collection-in-location clojure.core/let
|
||||
metabase.models.json-migration/def-json-migration clj-kondo.lint-as/def-catch-all
|
||||
metabase.models.setting/defsetting clj-kondo.lint-as/def-catch-all
|
||||
metabase.models.setting.multi-setting/define-multi-setting clojure.core/def
|
||||
metabase.models.util.spec-update/define-spec clojure.core/def
|
||||
metabase.notification.test-util/with-temp-notification clojure.core/let
|
||||
metabase.notification.test-util/with-card-notification clojure.core/let
|
||||
metabase.notification.test-util/with-system-event-notification! clojure.core/let
|
||||
metabase.public-settings.premium-features/defenterprise-schema clj-kondo.lint-as/def-catch-all
|
||||
metabase.public-settings.premium-features/define-premium-feature clojure.core/def
|
||||
metabase.premium-features.core/defenterprise-schema clj-kondo.lint-as/def-catch-all
|
||||
metabase.premium-features.core/define-premium-feature clojure.core/def
|
||||
metabase.premium-features.defenterprise/defenterprise-schema clj-kondo.lint-as/def-catch-all
|
||||
@@ -564,10 +569,6 @@
|
||||
metabase.query-processor.middleware.process-userland-query-test/with-query-execution! clojure.core/let
|
||||
metabase.query-processor.setup/with-qp-setup clojure.core/let
|
||||
metabase.search.api-test/do-test-users clojure.core/let
|
||||
metabase.settings.core/defsetting clj-kondo.lint-as/def-catch-all
|
||||
metabase.settings.core/define-multi-setting clojure.core/def
|
||||
metabase.settings.models.setting/defsetting clj-kondo.lint-as/def-catch-all
|
||||
metabase.settings.models.setting.multi-setting/define-multi-setting clojure.core/def
|
||||
metabase.sso.ldap/with-ldap-connection clojure.core/fn
|
||||
metabase.sync.util/sum-for clojure.core/for
|
||||
metabase.sync.util/with-emoji-progress-bar clojure.core/let
|
||||
@@ -634,6 +635,10 @@
|
||||
metabase.api.common.internal-test/with-jetty-server hooks.common/with-one-binding
|
||||
metabase.api.dashboard-test/with-chain-filter-fixtures hooks.common/let-one-with-optional-value
|
||||
metabase.api.dashboard-test/with-simple-dashboard-with-tabs hooks.common/with-one-binding
|
||||
metabase.api.embed-test/do-response-formats hooks.common/with-two-bindings
|
||||
metabase.api.embed-test/with-chain-filter-fixtures! hooks.common/let-one-with-optional-value
|
||||
metabase.api.embed-test/with-temp-card hooks.common/let-one-with-optional-value
|
||||
metabase.api.embed-test/with-temp-dashcard hooks.common/let-one-with-optional-value
|
||||
metabase.api.macros/defendpoint hooks.metabase.api.macros/defendpoint
|
||||
metabase.api.user-test/with-temp-user-email! hooks.common/with-one-binding
|
||||
metabase.channel.template.handlebars-helper/defhelper hooks.metabase.channel.template.handlebars-helper/defhelper
|
||||
@@ -643,10 +648,6 @@
|
||||
metabase.driver.bigquery-cloud-sdk-test/calculate-bird-scarcity hooks.metabase.query-processor-test.expressions-test/calculate-bird-scarcity
|
||||
metabase.driver.oracle-test/with-temp-user hooks.common/let-one-with-optional-value
|
||||
metabase.driver/register! hooks.metabase.driver/register!
|
||||
metabase.embedding.api.embed-test/do-response-formats hooks.common/with-two-bindings
|
||||
metabase.embedding.api.embed-test/with-chain-filter-fixtures! hooks.common/let-one-with-optional-value
|
||||
metabase.embedding.api.embed-test/with-temp-card hooks.common/let-one-with-optional-value
|
||||
metabase.embedding.api.embed-test/with-temp-dashcard hooks.common/let-one-with-optional-value
|
||||
metabase.legacy-mbql.schema.macros/defclause hooks.metabase.legacy-mbql.schemas.macros/defclause
|
||||
metabase.lib.schema.mbql-clause/define-catn-mbql-clause hooks.metabase.lib.schema.mbql-clause/define-mbql-clause
|
||||
metabase.lib.schema.mbql-clause/define-mbql-clause hooks.metabase.lib.schema.mbql-clause/define-mbql-clause
|
||||
@@ -663,6 +664,9 @@
|
||||
metabase.models.dashboard-test/with-dash-in-collection! hooks.common/with-three-bindings
|
||||
metabase.models.interface/define-batched-hydration-method hooks.metabase.models.interface/define-hydration-method
|
||||
metabase.models.interface/define-simple-hydration-method hooks.metabase.models.interface/define-hydration-method
|
||||
metabase.models.setting.multi-setting/define-multi-setting hooks.metabase.models.setting/define-multi-setting
|
||||
metabase.models.setting.multi-setting/define-multi-setting-impl hooks.metabase.models.setting/define-multi-setting-impl
|
||||
metabase.models.setting/defsetting hooks.metabase.models.setting/defsetting
|
||||
metabase.permissions.core/allow-changing-all-users-group-members hooks.common/do*
|
||||
metabase.permissions.core/disable-perms-cache hooks.common/do*
|
||||
metabase.plugins.classloader/require hooks.clojure.core.require/lint-require
|
||||
@@ -686,12 +690,6 @@
|
||||
metabase.search.api-test/with-search-items-in-collection hooks.metabase.search.api-test/with-search-items-in-collection
|
||||
metabase.search.api-test/with-search-items-in-root-collection hooks.common/do*
|
||||
metabase.server.streaming-response-test/with-start-execution-chan hooks.common/with-one-binding
|
||||
metabase.settings.core/define-multi-setting hooks.metabase.settings.models.setting/define-multi-setting
|
||||
metabase.settings.core/define-multi-setting-impl hooks.metabase.settings.models.setting/define-multi-setting-impl
|
||||
metabase.settings.core/defsetting hooks.metabase.settings.models.setting/defsetting
|
||||
metabase.settings.models.setting.multi-setting/define-multi-setting hooks.metabase.settings.models.setting/define-multi-setting
|
||||
metabase.settings.models.setting.multi-setting/define-multi-setting-impl hooks.metabase.settings.models.setting/define-multi-setting-impl
|
||||
metabase.settings.models.setting/defsetting hooks.metabase.settings.models.setting/defsetting
|
||||
metabase.stale-test/with-stale-items hooks.toucan2.tools.with-temp/with-temp
|
||||
metabase.test.data.datasets/test-driver hooks.metabase.test.data.datasets/test-driver
|
||||
metabase.test.data.datasets/test-drivers hooks.metabase.test.data.datasets/test-drivers
|
||||
@@ -751,43 +749,43 @@
|
||||
metabase.xrays.api.automagic-dashboards-test/with-indexed-model! hooks.metabase.xrays.api.automagic-dashboards-test/with-indexed-model!}
|
||||
|
||||
:macroexpand
|
||||
{clojurewerkz.quartzite.jobs/build macros.quartz/build-job
|
||||
clojurewerkz.quartzite.schedule.cron/schedule macros.quartz/schedule
|
||||
clojurewerkz.quartzite.schedule.simple/schedule macros.quartz/simple-schedule
|
||||
clojurewerkz.quartzite.triggers/build macros.quartz/build-trigger
|
||||
metabase-enterprise.database-routing.e2e-test/with-temp-dbs! macros.metabase-enterprise.database-routing.e2e-test/with-temp-dbs!
|
||||
metabase-enterprise.impersonation.util-test/with-impersonations! macros.metabase-enterprise.impersonation.util-test/with-impersonations!
|
||||
metabase-enterprise.query-reference-validation.api-test/with-test-setup! macros.metabase-enterprise.query-reference-validation.api-test/with-test-setup!
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps-for-user! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.serialization.test-util/with-world macros.metabase-enterprise.serialization.test-util/with-world
|
||||
metabase-enterprise.test/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.test/with-gtaps-for-user! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase.api.card-test/with-ordered-items macros.metabase.api.card-test/with-ordered-items
|
||||
metabase.api.collection-test/with-collection-hierarchy! macros.metabase.api.collection-test/with-collection-hierarchy!
|
||||
metabase.api.collection-test/with-some-children-of-collection! macros.metabase.api.collection-test/with-some-children-of-collection!
|
||||
metabase.embedding.api.embed-test/with-embedding-enabled-and-temp-card-referencing! macros.metabase.embedding.api.embed-test/with-embedding-enabled-and-temp-card-referencing!
|
||||
metabase.embedding.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing! macros.metabase.embedding.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing!
|
||||
metabase.lib.common/defop macros.metabase.lib.common/defop
|
||||
metabase.lib.filter/deffilter macros.metabase.lib.filter/deffilter
|
||||
metabase.models.params.chain-filter-test/chain-filter macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.params.chain-filter-test/chain-filter-search macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.user-test/with-groups macros.metabase.models.user-test/with-groups
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-card-referencing! macros.metabase.public-sharing.api-test/with-sharing-enabled-and-temp-card-referencing!
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-dashcard-referencing! macros.metabase.public-sharing.api-test/with-sharing-enabled-and-temp-dashcard-referencing!
|
||||
metabase.query-analysis.models.query-analysis-test/with-test-setup macros.metabase.query-analysis.models.query-analysis-test/with-test-setup
|
||||
metabase.query-analysis.task.test-setup/with-test-setup! macros.metabase.query-analysis.task.test-setup/with-test-setup!
|
||||
metabase.query-processor.streaming/streaming-response macros.metabase.query-processor.streaming/streaming-response
|
||||
metabase.server.statistics-handler-test/with-server macros.metabase.server.statistics-handler-test/with-server
|
||||
metabase.test.data.users/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test.util/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test.util/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.test/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.util.namespaces/import-fn macros.metabase.util.namespaces/import-fn
|
||||
metabase.xrays.domain-entities.malli/define-getters-and-setters macros.metabase.xrays.domain-entities.malli/define-getters-and-setters
|
||||
metabase.xrays.related-test/with-world macros.metabase.xrays.related-test/with-world}}
|
||||
{clojurewerkz.quartzite.jobs/build macros.quartz/build-job
|
||||
clojurewerkz.quartzite.schedule.cron/schedule macros.quartz/schedule
|
||||
clojurewerkz.quartzite.schedule.simple/schedule macros.quartz/simple-schedule
|
||||
clojurewerkz.quartzite.triggers/build macros.quartz/build-trigger
|
||||
metabase-enterprise.database-routing.e2e-test/with-temp-dbs! macros.metabase-enterprise.database-routing.e2e-test/with-temp-dbs!
|
||||
metabase-enterprise.impersonation.util-test/with-impersonations! macros.metabase-enterprise.impersonation.util-test/with-impersonations!
|
||||
metabase-enterprise.query-reference-validation.api-test/with-test-setup! macros.metabase-enterprise.query-reference-validation.api-test/with-test-setup!
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps-for-user! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.serialization.test-util/with-world macros.metabase-enterprise.serialization.test-util/with-world
|
||||
metabase-enterprise.test/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.test/with-gtaps-for-user! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase.api.card-test/with-ordered-items macros.metabase.api.card-test/with-ordered-items
|
||||
metabase.api.collection-test/with-collection-hierarchy! macros.metabase.api.collection-test/with-collection-hierarchy!
|
||||
metabase.api.collection-test/with-some-children-of-collection! macros.metabase.api.collection-test/with-some-children-of-collection!
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing! macros.metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing!
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing! macros.metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing!
|
||||
metabase.lib.common/defop macros.metabase.lib.common/defop
|
||||
metabase.lib.filter/deffilter macros.metabase.lib.filter/deffilter
|
||||
metabase.models.params.chain-filter-test/chain-filter macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.params.chain-filter-test/chain-filter-search macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.query-analysis-test/with-test-setup macros.metabase.models.query-analysis-test/with-test-setup
|
||||
metabase.models.user-test/with-groups macros.metabase.models.user-test/with-groups
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-card-referencing! macros.metabase.public-sharing.api-test/with-sharing-enabled-and-temp-card-referencing!
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-dashcard-referencing! macros.metabase.public-sharing.api-test/with-sharing-enabled-and-temp-dashcard-referencing!
|
||||
metabase.query-analysis.task.test-setup/with-test-setup! macros.metabase.query-analysis.task.test-setup/with-test-setup!
|
||||
metabase.query-processor.streaming/streaming-response macros.metabase.query-processor.streaming/streaming-response
|
||||
metabase.server.statistics-handler-test/with-server macros.metabase.server.statistics-handler-test/with-server
|
||||
metabase.test.data.users/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test.util/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test.util/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.test/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.util.namespaces/import-fn macros.metabase.util.namespaces/import-fn
|
||||
metabase.xrays.domain-entities.malli/define-getters-and-setters macros.metabase.xrays.domain-entities.malli/define-getters-and-setters
|
||||
metabase.xrays.related-test/with-world macros.metabase.xrays.related-test/with-world}}
|
||||
|
||||
:config-in-comment
|
||||
{:linters {:unresolved-symbol {:level :off}}}
|
||||
|
||||
@@ -30,12 +30,11 @@
|
||||
;; ## Tips
|
||||
;;
|
||||
;; PRO TIP: Check out the [[dev.deps-graph]] namespace for helpful tools to see where a module is used externally, and
|
||||
;; for tools for calculating this config -- you can use [[dev.deps-graph/print-kondo-config-diff]] to see what updates
|
||||
;; you need to make
|
||||
;; for tools for calculating this config.
|
||||
{:metabase/modules
|
||||
{actions
|
||||
{:api #{metabase.actions.api metabase.actions.core}
|
||||
:uses #{analytics api driver legacy-mbql lib model-persistence models query-processor search settings util}}
|
||||
:uses #{analytics api driver legacy-mbql lib model-persistence models query-processor search util}}
|
||||
|
||||
activity-feed
|
||||
{:api #{metabase.activity-feed.api metabase.activity-feed.init}
|
||||
@@ -54,7 +53,8 @@
|
||||
internal-stats
|
||||
models
|
||||
premium-features
|
||||
settings
|
||||
public-settings
|
||||
server
|
||||
util}}
|
||||
analyze
|
||||
{:api #{metabase.analyze.core metabase.analyze.query-results}
|
||||
@@ -62,6 +62,7 @@
|
||||
|
||||
api
|
||||
{:api #{metabase.api.auth
|
||||
metabase.api.cache
|
||||
metabase.api.card
|
||||
metabase.api.collection
|
||||
metabase.api.common
|
||||
@@ -80,9 +81,8 @@
|
||||
metabase.api.util.handlers}
|
||||
:uses :any}
|
||||
|
||||
audit
|
||||
{:api #{metabase.audit}
|
||||
:uses #{db settings}}
|
||||
audit {:api #{metabase.audit}
|
||||
:uses #{db models}}
|
||||
|
||||
auth-provider
|
||||
{:api #{metabase.auth-provider}
|
||||
@@ -92,12 +92,6 @@
|
||||
{:api #{metabase.bookmarks.api}
|
||||
:uses #{api db models util}}
|
||||
|
||||
cache
|
||||
{:api #{metabase.cache.api
|
||||
metabase.cache.core
|
||||
metabase.cache.init}
|
||||
:uses #{api config db events models premium-features settings util}}
|
||||
|
||||
channel
|
||||
{:api #{metabase.channel.api
|
||||
metabase.channel.core
|
||||
@@ -120,7 +114,7 @@
|
||||
notification
|
||||
permissions
|
||||
premium-features
|
||||
settings
|
||||
public-settings
|
||||
query-processor
|
||||
timeline
|
||||
types
|
||||
@@ -130,13 +124,13 @@
|
||||
{:api #{metabase.cloud-migration.api
|
||||
metabase.cloud-migration.core
|
||||
metabase.cloud-migration.init}
|
||||
:uses #{api cmd config db models premium-features settings task util}}
|
||||
:uses #{api cmd config db models premium-features task util}}
|
||||
|
||||
cmd
|
||||
{:api #{metabase.cmd
|
||||
metabase.cmd.copy
|
||||
metabase.cmd.dump-to-h2}
|
||||
:uses #{api config db legacy-mbql models plugins query-processor search settings util}}
|
||||
:uses #{api config db legacy-mbql models plugins query-processor search util}}
|
||||
|
||||
;; technically this 'uses' `enterprise/core` and `test` since it tries to load them to see if they exists so we know
|
||||
;; if EE/test code is available; however we can ignore them since they're not real usages.
|
||||
@@ -186,7 +180,6 @@
|
||||
metabase.driver.sync
|
||||
metabase.driver.util}
|
||||
:uses #{actions
|
||||
api
|
||||
auth-provider
|
||||
config
|
||||
connection-pool
|
||||
@@ -199,44 +192,30 @@
|
||||
notification
|
||||
plugins
|
||||
premium-features
|
||||
settings
|
||||
public-settings
|
||||
pulse
|
||||
query-processor
|
||||
sync
|
||||
task
|
||||
upload
|
||||
util}}
|
||||
util
|
||||
enterprise/database-routing}}
|
||||
|
||||
eid-translation
|
||||
{:api #{metabase.eid-translation.core}
|
||||
:uses #{settings util}}
|
||||
:uses #{}}
|
||||
|
||||
embedding
|
||||
{:api #{metabase.embedding.api
|
||||
metabase.embedding.app-origins-sdk
|
||||
metabase.embedding.init
|
||||
metabase.embedding.settings}
|
||||
:uses #{analytics
|
||||
api
|
||||
config
|
||||
driver
|
||||
eid-translation
|
||||
events
|
||||
models
|
||||
notification
|
||||
premium-features
|
||||
public-sharing
|
||||
query-processor
|
||||
settings
|
||||
tiles
|
||||
util}}
|
||||
embed
|
||||
{:api #{metabase.embed.settings metabase.embed.app-origins-sdk}
|
||||
:uses #{analytics models premium-features tiles util}}
|
||||
|
||||
events
|
||||
{:api #{metabase.events metabase.events.init metabase.events.notification}
|
||||
:uses #{api channel driver models notification premium-features task-history util}}
|
||||
:uses #{api channel driver models notification premium-features util}}
|
||||
|
||||
formatter
|
||||
{:api #{metabase.formatter}
|
||||
:uses #{models settings query-processor types util}}
|
||||
:uses #{models public-settings query-processor types util}}
|
||||
|
||||
indexed-entities
|
||||
{:api #{metabase.indexed-entities.api metabase.indexed-entities.init}
|
||||
@@ -244,10 +223,10 @@
|
||||
|
||||
integrations
|
||||
{:api #{metabase.integrations.slack}
|
||||
:uses #{events settings util}}
|
||||
:uses #{events models util}}
|
||||
|
||||
internal-stats
|
||||
{:api #{metabase.internal-stats.core}
|
||||
{:api #{metabase.internal-stats}
|
||||
:uses #{db models}}
|
||||
|
||||
legacy-mbql
|
||||
@@ -295,11 +274,11 @@
|
||||
metabase.lib.util
|
||||
metabase.lib.util.match
|
||||
metabase.lib.walk}
|
||||
:uses #{config legacy-mbql models settings types util}}
|
||||
:uses #{config driver legacy-mbql models types util}}
|
||||
|
||||
lib-be
|
||||
{:api #{metabase.lib-be.init}
|
||||
:uses #{models settings task util}}
|
||||
:uses #{models task util}}
|
||||
|
||||
logger
|
||||
{:api #{metabase.logger metabase.logger.init}
|
||||
@@ -309,18 +288,19 @@
|
||||
{:api #{metabase.login-history.api
|
||||
metabase.login-history.core
|
||||
metabase.login-history.init}
|
||||
:uses #{analytics api channel request settings util}}
|
||||
:uses #{analytics api channel models request util}}
|
||||
|
||||
model-persistence
|
||||
{:api #{metabase.model-persistence.api
|
||||
metabase.model-persistence.core
|
||||
metabase.model-persistence.init}
|
||||
:uses #{api db driver events lib models premium-features settings query-processor request task task-history util}}
|
||||
:uses #{api db driver events lib models premium-features public-settings query-processor request task util}}
|
||||
|
||||
models
|
||||
{:api #{metabase.models.api-key
|
||||
metabase.models.application-permissions-revision
|
||||
metabase.models.audit-log
|
||||
metabase.models.cache-config
|
||||
metabase.models.card
|
||||
metabase.models.card.metadata
|
||||
metabase.models.collection
|
||||
@@ -342,17 +322,23 @@
|
||||
metabase.models.moderation-review
|
||||
metabase.models.native-query-snippet
|
||||
metabase.models.native-query-snippet.permissions
|
||||
metabase.notification.models
|
||||
metabase.models.params
|
||||
metabase.models.params.chain-filter
|
||||
metabase.models.params.custom-values
|
||||
metabase.models.params.field-values
|
||||
metabase.models.params.shared
|
||||
metabase.models.query
|
||||
metabase.models.query-analysis
|
||||
metabase.models.query.permissions
|
||||
metabase.models.resolution
|
||||
metabase.models.secret
|
||||
metabase.models.serialization
|
||||
metabase.models.setting
|
||||
metabase.models.setting.cache
|
||||
metabase.models.setting.multi-setting
|
||||
metabase.models.table
|
||||
metabase.models.task-history
|
||||
metabase.models.user
|
||||
metabase.models.user-parameter-value
|
||||
metabase.models.util.spec-update
|
||||
@@ -362,7 +348,6 @@
|
||||
analyze
|
||||
api
|
||||
audit
|
||||
cache
|
||||
channel
|
||||
config
|
||||
db
|
||||
@@ -375,17 +360,20 @@
|
||||
permissions
|
||||
plugins
|
||||
premium-features
|
||||
settings
|
||||
public-settings
|
||||
public-sharing
|
||||
pulse
|
||||
query-analysis
|
||||
query-processor
|
||||
request
|
||||
search
|
||||
server
|
||||
setup
|
||||
sync
|
||||
task
|
||||
types
|
||||
util}}
|
||||
util
|
||||
enterprise/advanced-permissions}}
|
||||
|
||||
moderation
|
||||
{:api #{metabase.moderation}
|
||||
@@ -396,9 +384,7 @@
|
||||
metabase.notification.core
|
||||
metabase.notification.init
|
||||
metabase.notification.models
|
||||
metabase.notification.api.notification
|
||||
metabase.notification.payload.core
|
||||
metabase.notification.send}
|
||||
metabase.notification.payload.core}
|
||||
:uses #{analytics
|
||||
api
|
||||
channel
|
||||
@@ -408,11 +394,10 @@
|
||||
models
|
||||
permissions
|
||||
premium-features
|
||||
settings
|
||||
public-settings
|
||||
query-processor
|
||||
request
|
||||
task
|
||||
task-history
|
||||
util}}
|
||||
|
||||
permissions
|
||||
@@ -422,7 +407,7 @@
|
||||
metabase.permissions.models.permissions
|
||||
metabase.permissions.models.permissions-group
|
||||
metabase.permissions.util}
|
||||
:uses #{api audit config db models plugins premium-features request server settings util}}
|
||||
:uses #{api audit config db models plugins premium-features request server util}}
|
||||
|
||||
pivot
|
||||
{:api #{metabase.pivot.core}
|
||||
@@ -433,17 +418,19 @@
|
||||
:uses #{config driver util}}
|
||||
|
||||
premium-features
|
||||
{:api #{metabase.premium-features.api
|
||||
metabase.premium-features.core
|
||||
metabase.premium-features.init
|
||||
{:api #{metabase.premium-features.core
|
||||
metabase.premium-features.token-check}
|
||||
:uses #{api config db internal-stats plugins settings util}}
|
||||
:uses #{config db internal-stats models plugins util}}
|
||||
|
||||
public-settings
|
||||
{:api #{metabase.public-settings}
|
||||
:uses #{api config models premium-features util}}
|
||||
|
||||
public-sharing
|
||||
{:api #{metabase.public-sharing.api
|
||||
metabase.public-sharing.core
|
||||
metabase.public-sharing.init}
|
||||
:uses #{actions analytics api db events lib models query-processor request settings tiles util}}
|
||||
:uses #{actions analytics api db events lib models query-processor request tiles util}}
|
||||
|
||||
pulse
|
||||
{:api #{metabase.pulse.api
|
||||
@@ -451,12 +438,12 @@
|
||||
metabase.pulse.init
|
||||
metabase.pulse.task.send-pulses}
|
||||
:uses #{api channel config db driver events integrations models notification permissions plugins premium-features
|
||||
query-processor request task task-history util
|
||||
query-processor request task util
|
||||
enterprise/advanced-config enterprise/advanced-permissions enterprise/sandbox}}
|
||||
|
||||
query-analysis
|
||||
{:api #{metabase.query-analysis.core metabase.query-analysis.init}
|
||||
:uses #{config driver legacy-mbql lib query-processor settings task util}}
|
||||
:uses #{config driver legacy-mbql lib public-settings query-processor task util}}
|
||||
|
||||
query-processor
|
||||
{:api #{metabase.query-processor
|
||||
@@ -497,8 +484,8 @@
|
||||
analyze
|
||||
api
|
||||
audit
|
||||
cache
|
||||
config
|
||||
db
|
||||
driver
|
||||
events
|
||||
formatter
|
||||
@@ -509,7 +496,7 @@
|
||||
permissions
|
||||
pivot
|
||||
premium-features
|
||||
settings
|
||||
public-settings
|
||||
request
|
||||
server
|
||||
types
|
||||
@@ -517,7 +504,7 @@
|
||||
|
||||
request
|
||||
{:api #{metabase.request.core}
|
||||
:uses #{api config models permissions settings util}}
|
||||
:uses #{api config models permissions public-settings util}}
|
||||
|
||||
revisions
|
||||
{:api #{metabase.revisions.api metabase.revisions.core metabase.revisions.init}
|
||||
@@ -536,7 +523,7 @@
|
||||
metabase.search.ingestion
|
||||
metabase.search.init
|
||||
metabase.search.spec}
|
||||
:uses #{analytics api audit config db driver models permissions premium-features settings request task util}}
|
||||
:uses #{analytics api audit config db driver models permissions premium-features public-settings request task util}}
|
||||
|
||||
segments
|
||||
{:api #{metabase.segments.api}
|
||||
@@ -547,21 +534,14 @@
|
||||
metabase.server.middleware.json
|
||||
metabase.server.middleware.session
|
||||
metabase.server.streaming-response}
|
||||
:uses #{analytics api config core db driver embedding models premium-features settings session request util enterprise/sso}}
|
||||
:uses #{analytics api config core db driver embed models premium-features public-settings session request util enterprise/sso}}
|
||||
|
||||
session
|
||||
{:api #{metabase.session.core
|
||||
metabase.session.api
|
||||
metabase.session.init
|
||||
metabase.session.models.session}
|
||||
:uses #{api channel config db driver events login-history models settings request sso task util}}
|
||||
|
||||
settings
|
||||
{:api #{metabase.settings.api
|
||||
metabase.settings.core
|
||||
metabase.settings.deprecated-grab-bag
|
||||
metabase.settings.init}
|
||||
:uses #{api config db events models plugins premium-features server util enterprise/advanced-permissions}}
|
||||
:uses #{api channel config db driver events login-history models public-settings request sso task util}}
|
||||
|
||||
setup
|
||||
{:api #{metabase.setup.api metabase.setup.core}
|
||||
@@ -570,10 +550,13 @@
|
||||
channel
|
||||
config
|
||||
db
|
||||
embed
|
||||
events
|
||||
integrations
|
||||
models
|
||||
permissions
|
||||
settings
|
||||
premium-features
|
||||
public-settings
|
||||
request
|
||||
session
|
||||
util}}
|
||||
@@ -582,7 +565,7 @@
|
||||
{:api #{metabase.sso.api
|
||||
metabase.sso.core
|
||||
metabase.sso.init}
|
||||
:uses #{api models permissions premium-features settings util}}
|
||||
:uses #{api models permissions premium-features util}}
|
||||
|
||||
sync
|
||||
{:api #{metabase.sync.api
|
||||
@@ -591,41 +574,32 @@
|
||||
metabase.sync.schedules
|
||||
metabase.sync.task.sync-databases
|
||||
metabase.sync.util}
|
||||
:uses #{analyze api audit config db driver events lib models query-processor settings task task-history util}}
|
||||
:uses #{analyze api audit config db driver events lib models plugins query-processor task util}}
|
||||
|
||||
task
|
||||
{:api #{metabase.task
|
||||
metabase.task.bootstrap
|
||||
metabase.task.init}
|
||||
metabase.task.init
|
||||
metabase.task.notification}
|
||||
:uses #{analytics
|
||||
channel
|
||||
config
|
||||
db
|
||||
driver
|
||||
integrations
|
||||
models
|
||||
notification
|
||||
plugins
|
||||
premium-features
|
||||
settings
|
||||
task-history
|
||||
public-settings
|
||||
query-processor
|
||||
util
|
||||
enterprise/task}}
|
||||
|
||||
task-history
|
||||
{:api #{metabase.task-history.api
|
||||
metabase.task-history.core
|
||||
metabase.task-history.init}
|
||||
:uses #{api
|
||||
models
|
||||
permissions
|
||||
premium-features
|
||||
request
|
||||
task
|
||||
util}}
|
||||
|
||||
tiles
|
||||
{:api #{metabase.tiles.api
|
||||
metabase.tiles.init}
|
||||
:uses #{api legacy-mbql query-processor settings util}}
|
||||
:uses #{api legacy-mbql models query-processor util}}
|
||||
|
||||
timeline
|
||||
{:api #{metabase.timeline.api metabase.timeline.core}
|
||||
@@ -637,7 +611,7 @@
|
||||
|
||||
upload
|
||||
{:api #{metabase.upload}
|
||||
:uses #{analytics api driver events legacy-mbql lib model-persistence models permissions settings sync util}}
|
||||
:uses #{analytics api driver events legacy-mbql lib model-persistence models permissions public-settings sync util}}
|
||||
|
||||
user-key-value
|
||||
{:api #{metabase.user-key-value.api metabase.user-key-value.init}
|
||||
@@ -645,25 +619,24 @@
|
||||
|
||||
util
|
||||
{:api :any
|
||||
:uses #{config db driver legacy-mbql lib models plugins settings}}
|
||||
:uses #{config db driver legacy-mbql lib models plugins premium-features public-settings}}
|
||||
|
||||
xrays
|
||||
{:api #{metabase.xrays.api
|
||||
metabase.xrays.core
|
||||
metabase.xrays.init}
|
||||
:uses #{analyze api driver legacy-mbql lib models settings query-processor util}}
|
||||
{:api #{metabase.xrays.api metabase.xrays.core}
|
||||
:uses #{analyze api db driver legacy-mbql lib models public-settings query-processor util}}
|
||||
|
||||
enterprise/advanced-config
|
||||
{:api #{metabase-enterprise.advanced-config.api.logs
|
||||
metabase-enterprise.advanced-config.models.pulse-channel
|
||||
metabase-enterprise.advanced-config.file}
|
||||
:uses #{api db driver models permissions premium-features setup settings sync util}}
|
||||
metabase-enterprise.advanced-config.file
|
||||
metabase-enterprise.advanced-config.crufty}
|
||||
:uses #{api db driver models permissions premium-features setup sync util}}
|
||||
|
||||
enterprise/advanced-permissions
|
||||
{:api #{metabase-enterprise.advanced-permissions.api.routes
|
||||
metabase-enterprise.advanced-permissions.common
|
||||
metabase-enterprise.advanced-permissions.models.permissions.group-manager}
|
||||
:uses #{api enterprise/impersonation lib models permissions premium-features query-processor util}}
|
||||
:uses #{api audit driver enterprise/impersonation lib models permissions premium-features query-processor util enterprise/sandbox}}
|
||||
|
||||
enterprise/airgap
|
||||
{:api #{}
|
||||
@@ -686,7 +659,6 @@
|
||||
plugins
|
||||
premium-features
|
||||
query-processor
|
||||
settings
|
||||
sync
|
||||
util
|
||||
enterprise/serialization}}
|
||||
@@ -700,8 +672,8 @@
|
||||
:uses #{api premium-features util}}
|
||||
|
||||
enterprise/cache
|
||||
{:api #{metabase-enterprise.cache.init}
|
||||
:uses #{cache premium-features query-processor task util}}
|
||||
{:api #{metabase-enterprise.cache.strategies}
|
||||
:uses #{api models premium-features query-processor util}}
|
||||
|
||||
enterprise/content-verification
|
||||
{:api #{metabase-enterprise.content-verification.api.routes}
|
||||
@@ -709,47 +681,44 @@
|
||||
|
||||
enterprise/core
|
||||
{:api #{metabase-enterprise.core.init}
|
||||
:uses :any}
|
||||
:uses #{enterprise/enhancements}}
|
||||
|
||||
enterprise/dashboard-subscription-filters
|
||||
{:api #{}
|
||||
:uses #{premium-features}}
|
||||
|
||||
enterprise/data-editing
|
||||
{:api #{metabase-enterprise.data-editing.api}
|
||||
:uses #{api actions util}}
|
||||
|
||||
enterprise/database-routing
|
||||
{:api #{metabase-enterprise.database-routing.api}
|
||||
:uses #{api config database-routing events lib models premium-features query-processor settings util}}
|
||||
{:api #{metabase-enterprise.database-routing.core metabase-enterprise.database-routing.api}
|
||||
:uses #{api config database-routing events lib models premium-features query-processor util}}
|
||||
|
||||
enterprise/enhancements
|
||||
{:api #{metabase-enterprise.enhancements.init}
|
||||
:uses #{models premium-features settings sso util enterprise/sso}}
|
||||
:uses #{models premium-features sso util enterprise/sso}}
|
||||
|
||||
enterprise/gsheets
|
||||
{:api #{metabase-enterprise.gsheets.api}
|
||||
:uses #{api analytics premium-features settings util enterprise/harbormaster}}
|
||||
:uses #{api analytics enterprise/harbormaster models premium-features server util}}
|
||||
|
||||
enterprise/harbormaster
|
||||
{:api #{metabase-enterprise.harbormaster.client}
|
||||
:uses #{api cloud-migration util}}
|
||||
:uses #{api config cloud-migration models util}}
|
||||
|
||||
enterprise/impersonation
|
||||
{:api #{metabase-enterprise.impersonation.api}
|
||||
:uses #{api audit driver lib models premium-features query-processor util enterprise/sandbox}}
|
||||
{:api #{metabase-enterprise.impersonation.core
|
||||
metabase-enterprise.impersonation.api}
|
||||
:uses #{api audit driver enterprise/sandbox lib models permissions premium-features query-processor util}}
|
||||
|
||||
enterprise/internal-stats
|
||||
{:api #{}
|
||||
:uses #{premium-features settings}}
|
||||
{:api #{metabase-enterprise.internal-stats}
|
||||
:uses #{models premium-features}}
|
||||
|
||||
enterprise/llm
|
||||
{:api #{metabase-enterprise.llm.api}
|
||||
:uses #{analytics analyze api query-processor settings util}}
|
||||
:uses #{analytics analyze api models query-processor util}}
|
||||
|
||||
enterprise/query-reference-validation
|
||||
{:api #{metabase-enterprise.query-reference-validation.api}
|
||||
:uses #{api models query-analysis request util}}
|
||||
:uses #{api models public-settings request util}}
|
||||
|
||||
enterprise/sandbox
|
||||
{:api #{metabase-enterprise.sandbox.api.routes
|
||||
@@ -766,11 +735,12 @@
|
||||
query-processor
|
||||
request
|
||||
util
|
||||
enterprise/impersonation
|
||||
enterprise/api}}
|
||||
|
||||
enterprise/scim
|
||||
{:api #{metabase-enterprise.scim.api metabase-enterprise.scim.routes}
|
||||
:uses #{analytics api models permissions settings server util enterprise/serialization}}
|
||||
:uses #{analytics api models permissions public-settings server util enterprise/serialization}}
|
||||
|
||||
enterprise/search
|
||||
{:api #{}
|
||||
@@ -780,7 +750,7 @@
|
||||
{:api #{metabase-enterprise.serialization.api
|
||||
metabase-enterprise.serialization.cmd
|
||||
metabase-enterprise.serialization.v2.backfill-ids}
|
||||
:uses #{analytics api config db legacy-mbql lib logger models plugins premium-features settings setup util}}
|
||||
:uses #{analytics api config db legacy-mbql lib logger models plugins premium-features public-settings setup util}}
|
||||
|
||||
enterprise/snippet-collections
|
||||
{:api #{}
|
||||
@@ -790,19 +760,23 @@
|
||||
{:api #{metabase-enterprise.sso.api.routes
|
||||
metabase-enterprise.sso.integrations.sso-settings
|
||||
metabase-enterprise.sso.integrations.sso-utils}
|
||||
:uses #{api channel embedding events premium-features request session settings sso util enterprise/scim}}
|
||||
:uses #{api channel embed events models premium-features public-settings request session sso util enterprise/scim}}
|
||||
|
||||
enterprise/stale
|
||||
{:api #{metabase-enterprise.stale.routes}
|
||||
:uses #{analytics api embedding models premium-features request settings util}}
|
||||
:uses #{analytics api embed models premium-features public-settings request util}}
|
||||
|
||||
enterprise/stats
|
||||
{:api #{}
|
||||
:uses #{driver premium-features enterprise/advanced-config enterprise/scim enterprise/sso}}
|
||||
|
||||
enterprise/data-editing
|
||||
{:api #{}
|
||||
:uses #{api actions util}}
|
||||
|
||||
enterprise/task
|
||||
{:api #{metabase-enterprise.task.truncate-audit-tables}
|
||||
:uses #{premium-features}}
|
||||
:uses #{premium-features query-processor task util enterprise/cache}}
|
||||
|
||||
enterprise/upload-management
|
||||
{:api #{metabase-enterprise.upload-management.api}
|
||||
|
||||
@@ -74,6 +74,11 @@
|
||||
metabase.models.field-values/create-or-update-full-field-values!
|
||||
metabase.models.moderation-review/create-review!
|
||||
metabase.models.on-demand-test/add-dashcard-with-parameter-mapping!
|
||||
metabase.models.setting-test/test-user-local-allowed-setting!
|
||||
metabase.models.setting-test/test-user-local-only-setting!
|
||||
metabase.models.setting.cache/restore-cache!
|
||||
metabase.models.setting/set!
|
||||
metabase.models.setting/validate-settings-formatting!
|
||||
metabase.permissions.models.permissions/grant-application-permissions!
|
||||
metabase.permissions.models.permissions/grant-collection-read-permissions!
|
||||
metabase.permissions.models.permissions/grant-collection-readwrite-permissions!
|
||||
@@ -92,11 +97,6 @@
|
||||
metabase.query-processor.streaming.interface/finish!
|
||||
metabase.query-processor.streaming.interface/write-row!
|
||||
metabase.sample-data/try-to-extract-sample-database!
|
||||
metabase.settings.models.setting-test/test-user-local-allowed-setting!
|
||||
metabase.settings.models.setting-test/test-user-local-only-setting!
|
||||
metabase.settings.models.setting.cache/restore-cache!
|
||||
metabase.settings.models.setting/set!
|
||||
metabase.settings.models.setting/validate-settings-formatting!
|
||||
metabase.setup.core/create-token!
|
||||
metabase.sso.ldap-test-util/start-ldap-server!
|
||||
metabase.sync.core/sync-database!
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns macros.metabase.embedding.api.embed-test)
|
||||
(ns macros.metabase.api.embed-test)
|
||||
|
||||
(defmacro with-embedding-enabled-and-temp-card-referencing!
|
||||
[table-kw field-kw [card-binding] & body]
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns macros.metabase.query-analysis.models.query-analysis-test)
|
||||
(ns macros.metabase.models.query-analysis-test)
|
||||
|
||||
(defmacro with-test-setup [& body]
|
||||
`(let [~'card-id 1
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns hooks.metabase.settings.models.setting
|
||||
(ns hooks.metabase.models.setting
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[hooks.common :as common]))
|
||||
@@ -207,7 +207,7 @@
|
||||
anon-binding (hooks/map-node options-list)])
|
||||
(hooks/reg-keyword! (-> (hooks/keyword-node (keyword (hooks/sexpr setting-name)))
|
||||
(with-meta (meta setting-name)))
|
||||
'metabase.settings.models.setting/defsetting)
|
||||
'metabase.models.setting/defsetting)
|
||||
getter-node
|
||||
setter-node))
|
||||
(with-meta (meta node)))}))
|
||||
534
.cljfmt.edn
534
.cljfmt.edn
@@ -81,271 +81,269 @@
|
||||
throttle.core/with-throttling [[:block 1]]
|
||||
;; the rest of the stuff in this list is generated automatically based on `:style/indent` specs
|
||||
;; by running [[dev.generate-cljfmt-config/specs]]... use that code to update this list
|
||||
metabase-enterprise.cache.config-test/with-temp-persist-models [[:block 1]]
|
||||
metabase-enterprise.impersonation.util-test/with-impersonations! [[:inner 0]]
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps! [[:inner 0]]
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps-for-user! [[:inner 0]]
|
||||
metabase-enterprise.sandbox.test-util/with-user-attributes [[:block 2]]
|
||||
metabase-enterprise.serialization.test-util/with-dbs [[:inner 0]]
|
||||
metabase-enterprise.serialization.test-util/with-random-dump-dir [[:block 1]]
|
||||
metabase-enterprise.serialization.test-util/with-world [[:block 0]]
|
||||
metabase-enterprise.sso.integrations.jwt-test/with-users-with-email-deleted [[:block 1]]
|
||||
metabase-enterprise.test/with-gtaps! [[:inner 0]]
|
||||
metabase-enterprise.test/with-gtaps-for-user! [[:inner 0]]
|
||||
metabase-enterprise.test/with-user-attributes [[:block 2]]
|
||||
metabase.actions.actions-test/with-actions-test-data-and-actions-permissively-enabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions [[:block 1]]
|
||||
metabase.actions.test-util/with-actions-disabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions-enabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions-test-data [[:inner 0]]
|
||||
metabase.actions.test-util/with-actions-test-data-and-actions-enabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions-test-data-tables [[:block 1]]
|
||||
metabase.actions.test-util/with-empty-db [[:inner 0]]
|
||||
metabase.actions.test-util/with-temp-test-data [[:inner 0]]
|
||||
metabase.api.card-test/with-cards-in-readable-collection [[:block 1]]
|
||||
metabase.api.card-test/with-cards-in-writeable-collection [[:block 1]]
|
||||
metabase.api.card-test/with-ordered-items [[:inner 0]]
|
||||
metabase.api.card-test/with-temp-native-card! [[:block 1]]
|
||||
metabase.api.card-test/with-temp-native-card-with-params! [[:block 1]]
|
||||
metabase.api.collection-test/with-collection-hierarchy [[:block 1]]
|
||||
metabase.api.collection-test/with-french-user-and-personal-collection [[:block 2]]
|
||||
metabase.api.collection-test/with-some-children-of-collection [[:block 1]]
|
||||
metabase.api.common/check [[:default]]
|
||||
metabase.api.common/define-routes [[:block 0]]
|
||||
metabase.api.common/let-404 [[:block 1]]
|
||||
metabase.cmd.copy/step [[:block 1]]
|
||||
metabase.cmd.copy/with-connection-rollback-only [[:block 1]]
|
||||
metabase.cmd.copy/with-disabled-db-constraints [[:block 2]]
|
||||
metabase.config/build-type-case [[:block 0]]
|
||||
metabase.dashboard-subscription-test/with-link-card-fixture-for-dashboard [[:block 2]]
|
||||
metabase.db.liquibase/with-liquibase [[:block 1]]
|
||||
metabase.db.liquibase/with-scope-locked [[:block 1]]
|
||||
metabase.db.schema-migrations-test.impl/test-migrations [[:block 2]]
|
||||
metabase.db/with-application-db [[:inner 0]]
|
||||
metabase.driver.bigquery-cloud-sdk.query-processor/with-temporal-type [[:default]]
|
||||
metabase.driver.druid.client/DELETE [[:default]]
|
||||
metabase.driver.druid.client/GET [[:default]]
|
||||
metabase.driver.druid.client/POST [[:default]]
|
||||
metabase.driver.druid.query-processor-test/druid-query [[:block 0]]
|
||||
metabase.driver.druid.query-processor-test/druid-query-returning-rows [[:block 0]]
|
||||
metabase.driver.mongo.query-processor/mongo-let [[:block 1]]
|
||||
metabase.driver.sql-jdbc.actions/with-jdbc-transaction [[:block 1]]
|
||||
metabase.driver.sql-jdbc.connection/with-connection-spec-for-testing-connection [[:block 1]]
|
||||
metabase.driver.sql-jdbc.execute.diagnostic/capturing-diagnostic-info [[:block 1]]
|
||||
metabase.driver.sql.query-processor/apply-top-level-clause [[:default]]
|
||||
metabase.driver/with-driver [[:block 1]]
|
||||
metabase.embedding.api.embed-test/do-response-formats [[:block 1]]
|
||||
metabase.embedding.api.embed-test/with-embedding-enabled-and-new-secret-key [[:block 0]]
|
||||
metabase.embedding.api.embed-test/with-embedding-enabled-and-temp-card-referencing [[:block 3]]
|
||||
metabase.embedding.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing [[:block 3]]
|
||||
metabase.embedding.api.embed-test/with-new-secret-key [[:block 0]]
|
||||
metabase.embedding.api.embed-test/with-temp-card [[:block 1]]
|
||||
metabase.embedding.api.embed-test/with-temp-dashcard [[:block 1]]
|
||||
metabase.embedding.api.preview-embed-test/with-embedding-enabled-and-new-secret-key [[:block 0]]
|
||||
metabase.embedding.api.preview-embed-test/with-new-secret-key [[:block 0]]
|
||||
metabase.lib.binning/with-binning [[:default]]
|
||||
metabase.lib.core/with-binning [[:default]]
|
||||
metabase.lib.core/with-join-alias [[:default]]
|
||||
metabase.lib.core/with-join-conditions [[:default]]
|
||||
metabase.lib.join/with-join-alias [[:default]]
|
||||
metabase.lib.join/with-join-conditions [[:default]]
|
||||
metabase.lib.test-util.macros/$ids [[:inner 0]]
|
||||
metabase.lib.test-util.macros/mbql-query [[:inner 0]]
|
||||
metabase.lib.util.match/match [[:inner 0]]
|
||||
metabase.lib.util.match/match-one [[:inner 0]]
|
||||
metabase.lib.util.match/replace [[:inner 0]]
|
||||
metabase.lib.util.match/replace-in [[:inner 0]]
|
||||
metabase.models.collection-test/with-collection-hierarchy [[:block 1]]
|
||||
metabase.models.collection-test/with-current-user-perms-for-collections [[:block 1]]
|
||||
metabase.models.collection-test/with-personal-and-impersonal-collections [[:block 1]]
|
||||
metabase.models.dashboard-test/with-dash-in-collection [[:inner 0]]
|
||||
metabase.models.interface/define-batched-hydration-method [[:inner 0]]
|
||||
metabase.models.interface/define-simple-hydration-method [[:inner 0]]
|
||||
metabase.models.params.chain-filter-test/with-clean-field-values-for-field [[:block 1]]
|
||||
metabase.models.params.chain-filter-test/with-fk-field-to-field-remapping [[:block 0]]
|
||||
metabase.models.params.chain-filter-test/with-human-readable-values-remapping [[:block 0]]
|
||||
metabase.permissions.core/allow-changing-all-users-group-members [[:block 0]]
|
||||
metabase.permissions.core/disable-perms-cache [[:block 0]]
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-card-referencing [[:block 3]]
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-dashcard-referencing [[:block 3]]
|
||||
metabase.public-sharing.api-test/with-temp-public-card [[:block 1]]
|
||||
metabase.public-sharing.api-test/with-temp-public-dashboard [[:block 1]]
|
||||
metabase.public-sharing.api-test/with-temp-public-dashboard-and-card [[:block 1]]
|
||||
metabase.pulse.api.alert-test/with-alert-in-collection [[:block 1]]
|
||||
metabase.pulse.models.pulse-test/with-dashboard-subscription-in-collection [[:block 1]]
|
||||
metabase.pulse.models.pulse-test/with-pulse-in-collection [[:inner 0]]
|
||||
metabase.query-processor-test.pipeline-queries-test/pmbql-query [[:block 1]]
|
||||
metabase.query-processor-test.pipeline-queries-test/run-pmbql-query [[:block 1]]
|
||||
metabase.query-processor.debug/debug> [[:block 0]]
|
||||
metabase.query-processor.error-type/deferror [[:block 1]]
|
||||
metabase.query-processor.middleware.cache-backend.interface/with-cached-results [[:block 4]]
|
||||
metabase.query-processor.middleware.process-userland-query-test/with-query-execution [[:block 1]]
|
||||
metabase.query-processor.store/cached [[:block 1]]
|
||||
metabase.query-processor.store/with-metadata-provider [[:inner 0]]
|
||||
metabase.query-processor.streaming/streaming-response [[:block 1]]
|
||||
metabase.query-processor.test-util/format-rows-by [[:default]]
|
||||
metabase.request.core/as-admin [[:block 0]]
|
||||
metabase.request.core/with-current-request [[:inner 0]]
|
||||
metabase.request.core/with-current-user [[:inner 0]]
|
||||
metabase.request.core/with-limit-and-offset [[:inner 0]]
|
||||
metabase.request.session/as-admin [[:block 0]]
|
||||
metabase.request.session/with-current-user [[:inner 0]]
|
||||
metabase.sample-data-test/with-temp-sample-database-db [[:block 1]]
|
||||
metabase.search.api-test/do-test-users [[:block 1]]
|
||||
metabase.server.middleware.session/as-admin [[:block 0]]
|
||||
metabase.server.middleware.session/with-current-user [[:inner 0]]
|
||||
metabase.server.streaming-response-test/with-streaming-response-thread-pool [[:block 0]]
|
||||
metabase.server.streaming-response-test/with-test-driver-db! [[:block 0]]
|
||||
metabase.server.streaming-response/streaming-response [[:block 2]]
|
||||
metabase.session.api/http-401-on-error [[:block 0]]
|
||||
metabase.settings.core/define-multi-setting [[:inner 0]]
|
||||
metabase.settings.core/defsetting [[:block 1]]
|
||||
metabase.settings.models.setting.multi-setting/define-multi-setting [[:inner 0]]
|
||||
metabase.settings.models.setting/defsetting [[:block 1]]
|
||||
metabase.sync.fetch-metadata/log-if-error [[:block 1]]
|
||||
metabase.sync.sync-metadata.fields-test/with-test-db [[:block 0]]
|
||||
metabase.sync.util/do-with-start-and-finish-debug-logging [[:default]]
|
||||
metabase.sync.util/sum-for [[:block 1]]
|
||||
metabase.sync.util/sync-operation [[:block 3]]
|
||||
metabase.sync.util/with-db-logging-disabled [[:default]]
|
||||
metabase.sync.util/with-duplicate-ops-prevented [[:default]]
|
||||
metabase.sync.util/with-emoji-progress-bar [[:block 1]]
|
||||
metabase.sync.util/with-error-handling [[:block 1]]
|
||||
metabase.sync.util/with-start-and-finish-logging [[:default]]
|
||||
metabase.sync.util/with-start-and-finish-logging* [[:default]]
|
||||
metabase.sync.util/with-sync-events [[:default]]
|
||||
metabase.task-history.models.task-history/with-task-history [[:block 1]]
|
||||
metabase.task/rerun-on-error [[:block 1]]
|
||||
metabase.test.data.datasets/test-driver [[:inner 0]]
|
||||
metabase.test.data.datasets/test-drivers [[:inner 0]]
|
||||
metabase.test.data.one-off-dbs/with-blank-db [[:block 0]]
|
||||
metabase.test.data.one-off-dbs/with-blueberries-db [[:block 0]]
|
||||
metabase.test.data.users/with-test-user [[:inner 0]]
|
||||
metabase.test.data/$ids [[:inner 0]]
|
||||
metabase.test.data/dataset [[:inner 0]]
|
||||
metabase.test.data/mbql-query [[:inner 0]]
|
||||
metabase.test.data/native-query [[:block 0]]
|
||||
metabase.test.data/query [[:block 1]]
|
||||
metabase.test.data/run-mbql-query [[:inner 0]]
|
||||
metabase.test.data/with-empty-h2-app-db [[:block 0]]
|
||||
metabase.test.data/with-temp-copy-of-db [[:block 0]]
|
||||
metabase.test.util.public-settings/with-additional-premium-features [[:block 1]]
|
||||
metabase.test.util.public-settings/with-premium-features [[:block 1]]
|
||||
metabase.test.util.thread-local/test-helpers-set-global-values! [[:block 0]]
|
||||
metabase.test.util/discard-setting-changes [[:block 1]]
|
||||
metabase.test.util/let-url [[:block 1]]
|
||||
metabase.test.util/throw-if-called! [[:block 1]]
|
||||
metabase.test.util/with-temp-scheduler [[:block 0]]
|
||||
metabase.test.util/with-temp-vals-in-db [[:block 3]]
|
||||
metabase.test.util/with-user-in-groups [[:inner 0]]
|
||||
metabase.test/$ids [[:inner 0]]
|
||||
metabase.test/as-admin [[:inner 0]]
|
||||
metabase.test/dataset [[:inner 0]]
|
||||
metabase.test/discard-setting-changes [[:block 1]]
|
||||
metabase.test/format-rows-by [[:default]]
|
||||
metabase.test/let-url [[:block 1]]
|
||||
metabase.test/mbql-query [[:inner 0]]
|
||||
metabase.test/native-query [[:block 0]]
|
||||
metabase.test/query [[:block 1]]
|
||||
metabase.test/run-mbql-query [[:inner 0]]
|
||||
metabase.test/test-driver [[:inner 0]]
|
||||
metabase.test/test-drivers [[:inner 0]]
|
||||
metabase.test/test-helpers-set-global-values! [[:block 0]]
|
||||
metabase.test/throw-if-called! [[:block 1]]
|
||||
metabase.test/with-actions [[:block 1]]
|
||||
metabase.test/with-actions-disabled [[:block 0]]
|
||||
metabase.test/with-actions-enabled [[:block 0]]
|
||||
metabase.test/with-actions-test-data [[:inner 0]]
|
||||
metabase.test/with-actions-test-data-and-actions-enabled [[:block 0]]
|
||||
metabase.test/with-actions-test-data-tables [[:block 1]]
|
||||
metabase.test/with-additional-premium-features [[:block 1]]
|
||||
metabase.test/with-current-user [[:inner 0]]
|
||||
metabase.test/with-driver [[:block 1]]
|
||||
metabase.test/with-empty-db [[:inner 0]]
|
||||
metabase.test/with-empty-h2-app-db [[:block 0]]
|
||||
metabase.test/with-metadata-provider [[:inner 0]]
|
||||
metabase.test/with-premium-features [[:block 1]]
|
||||
metabase.test/with-temp [[:inner 0]]
|
||||
metabase.test/with-temp-copy-of-db [[:block 0]]
|
||||
metabase.test/with-temp-scheduler [[:block 0]]
|
||||
metabase.test/with-temp-test-data [[:inner 0]]
|
||||
metabase.test/with-temp-vals-in-db [[:block 3]]
|
||||
metabase.test/with-test-user [[:inner 0]]
|
||||
metabase.test/with-user-in-groups [[:inner 0]]
|
||||
metabase.timeseries-query-processor-test.util/test-timeseries-drivers [[:block 0]]
|
||||
metabase.timeseries-query-processor-test/run-mbql-query [[:inner 0]]
|
||||
metabase.upload-test/with-upload-table! [[:inner 0]]
|
||||
metabase.upload.types/with-currency [[:default]]
|
||||
metabase.upload.types/with-parens [[:default]]
|
||||
metabase.util.async/cancelable-thread [[:block 0]]
|
||||
metabase.util.date-2/with-time-zone-same-instant [[:default]]
|
||||
metabase.util.encryption-test/with-secret-key [[:block 1]]
|
||||
metabase.util.honey-sql-2/with-database-type-info [[:default]]
|
||||
metabase.util.i18n/deferred-trs [[:default]]
|
||||
metabase.util.i18n/deferred-tru [[:default]]
|
||||
metabase.util.i18n/trs [[:default]]
|
||||
metabase.util.i18n/trsn [[:default]]
|
||||
metabase.util.i18n/tru [[:default]]
|
||||
metabase.util.i18n/trun [[:default]]
|
||||
metabase.util.jvm/auto-retry [[:block 1]]
|
||||
metabase.util.jvm/varargs [[:block 1]]
|
||||
metabase.util.jvm/with-us-locale [[:block 0]]
|
||||
metabase.util.malli/disable-enforcement [[:block 0]]
|
||||
metabase.util.malli/with [[:default]]
|
||||
metabase.util.malli/with-api-error-message [[:default]]
|
||||
metabase.util.namespaces/import-fns [[:default]]
|
||||
metabase.util.queue-test/await-test-while [[:block 1]]
|
||||
metabase.util/auto-retry [[:block 1]]
|
||||
metabase.util/case-enum [[:block 1]]
|
||||
metabase.util/ignore-exceptions [[:block 0]]
|
||||
metabase.util/or-with [[:block 1]]
|
||||
metabase.util/profile [[:block 1]]
|
||||
metabase.util/prog1 [[:inner 0]]
|
||||
metabase.util/varargs [[:inner 0]]
|
||||
metabase.util/with-us-locale [[:block 0]]
|
||||
metabuild-common.core/exit-when-finished-nonzero-on-exception [[:block 0]]
|
||||
metabuild-common.core/step [[:block 1]]
|
||||
metabuild-common.entrypoint/exit-when-finished-nonzero-on-exception [[:block 0]]
|
||||
metabuild-common.steps/step [[:block 1]]
|
||||
methodical.core/defmethod [[:inner 0]]
|
||||
methodical.core/defmulti [[:inner 0]]
|
||||
methodical.core/with-dispatcher [[:default]]
|
||||
methodical.core/with-method-table [[:default]]
|
||||
methodical.core/with-prefers [[:default]]
|
||||
methodical.interface/with-dispatcher [[:default]]
|
||||
methodical.interface/with-method-table [[:default]]
|
||||
methodical.interface/with-prefers [[:default]]
|
||||
methodical.macros/defmethod [[:inner 0]]
|
||||
methodical.macros/defmulti [[:inner 0]]
|
||||
saml20-clj.sp.response/validate-confirmation-datas [[:block 1]]
|
||||
toucan2.connection/with-transaction [[:block 1]]
|
||||
toucan2.core/build [[:block 0]]
|
||||
toucan2.core/compile [[:block 0]]
|
||||
toucan2.core/debug [[:block 0]]
|
||||
toucan2.core/define-after-insert [[:inner 0]]
|
||||
toucan2.core/define-after-select [[:inner 0]]
|
||||
toucan2.core/define-after-update [[:inner 0]]
|
||||
toucan2.core/define-before-delete [[:inner 0]]
|
||||
toucan2.core/define-before-insert [[:inner 0]]
|
||||
toucan2.core/define-before-select [[:inner 0]]
|
||||
toucan2.core/define-default-fields [[:inner 0]]
|
||||
toucan2.core/define-named-query [[:block 1]]
|
||||
toucan2.core/deftransforms [[:block 1]]
|
||||
toucan2.core/with-transaction [[:block 1]]
|
||||
toucan2.tools.after-insert/define-after-insert [[:inner 0]]
|
||||
toucan2.tools.after-select/define-after-select [[:inner 0]]
|
||||
toucan2.tools.after-update/define-after-update [[:inner 0]]
|
||||
toucan2.tools.after/define-after-impl [[:default]]
|
||||
toucan2.tools.before-delete/define-before-delete [[:inner 0]]
|
||||
toucan2.tools.before-insert/define-before-insert [[:inner 0]]
|
||||
toucan2.tools.before-select/define-before-select [[:inner 0]]
|
||||
toucan2.tools.compile/build [[:block 0]]
|
||||
toucan2.tools.compile/compile [[:block 0]]
|
||||
toucan2.tools.compile/resolved [[:block 0]]
|
||||
toucan2.tools.debug/debug [[:block 0]]
|
||||
toucan2.tools.default-fields/define-default-fields [[:inner 0]]
|
||||
toucan2.tools.named-query/define-named-query [[:block 1]]
|
||||
toucan2.tools.simple-out-transform/define-out-transform [[:inner 0]]
|
||||
toucan2.tools.transformed/deftransforms [[:block 1]]
|
||||
toucan2.tools.with-temp/with-temp [[:inner 0]]
|
||||
toucan2.util/try-with-error-context [[:inner 0]]}}
|
||||
metabase-enterprise.impersonation.util-test/with-impersonations! [[:inner 0]]
|
||||
metabase-enterprise.cache.config-test/with-temp-persist-models [[:block 1]]
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps! [[:inner 0]]
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps-for-user! [[:inner 0]]
|
||||
metabase-enterprise.sandbox.test-util/with-user-attributes [[:block 2]]
|
||||
metabase-enterprise.serialization.test-util/with-dbs [[:inner 0]]
|
||||
metabase-enterprise.serialization.test-util/with-random-dump-dir [[:block 1]]
|
||||
metabase-enterprise.serialization.test-util/with-world [[:block 0]]
|
||||
metabase-enterprise.sso.integrations.jwt-test/with-users-with-email-deleted [[:block 1]]
|
||||
metabase-enterprise.test/with-gtaps! [[:inner 0]]
|
||||
metabase-enterprise.test/with-gtaps-for-user! [[:inner 0]]
|
||||
metabase-enterprise.test/with-user-attributes [[:block 2]]
|
||||
metabase.actions.actions-test/with-actions-test-data-and-actions-permissively-enabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions [[:block 1]]
|
||||
metabase.actions.test-util/with-actions-disabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions-enabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions-test-data [[:inner 0]]
|
||||
metabase.actions.test-util/with-actions-test-data-and-actions-enabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions-test-data-tables [[:block 1]]
|
||||
metabase.actions.test-util/with-empty-db [[:inner 0]]
|
||||
metabase.actions.test-util/with-temp-test-data [[:inner 0]]
|
||||
metabase.api.card-test/with-cards-in-readable-collection [[:block 1]]
|
||||
metabase.api.card-test/with-cards-in-writeable-collection [[:block 1]]
|
||||
metabase.api.card-test/with-ordered-items [[:inner 0]]
|
||||
metabase.api.card-test/with-temp-native-card! [[:block 1]]
|
||||
metabase.api.card-test/with-temp-native-card-with-params! [[:block 1]]
|
||||
metabase.api.collection-test/with-collection-hierarchy [[:block 1]]
|
||||
metabase.api.collection-test/with-french-user-and-personal-collection [[:block 2]]
|
||||
metabase.api.collection-test/with-some-children-of-collection [[:block 1]]
|
||||
metabase.api.common/check [[:default]]
|
||||
metabase.api.common/define-routes [[:block 0]]
|
||||
metabase.api.common/let-404 [[:block 1]]
|
||||
metabase.api.embed-test/do-response-formats [[:block 1]]
|
||||
metabase.api.embed-test/with-embedding-enabled-and-new-secret-key [[:block 0]]
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing [[:block 3]]
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing [[:block 3]]
|
||||
metabase.api.embed-test/with-new-secret-key [[:block 0]]
|
||||
metabase.api.embed-test/with-temp-card [[:block 1]]
|
||||
metabase.api.embed-test/with-temp-dashcard [[:block 1]]
|
||||
metabase.api.preview-embed-test/with-embedding-enabled-and-new-secret-key [[:block 0]]
|
||||
metabase.api.preview-embed-test/with-new-secret-key [[:block 0]]
|
||||
metabase.cmd.copy/step [[:block 1]]
|
||||
metabase.cmd.copy/with-connection-rollback-only [[:block 1]]
|
||||
metabase.cmd.copy/with-disabled-db-constraints [[:block 2]]
|
||||
metabase.config/build-type-case [[:block 0]]
|
||||
metabase.dashboard-subscription-test/with-link-card-fixture-for-dashboard [[:block 2]]
|
||||
metabase.db.liquibase/with-liquibase [[:block 1]]
|
||||
metabase.db.liquibase/with-scope-locked [[:block 1]]
|
||||
metabase.db.schema-migrations-test.impl/test-migrations [[:block 2]]
|
||||
metabase.db/with-application-db [[:inner 0]]
|
||||
metabase.driver.bigquery-cloud-sdk.query-processor/with-temporal-type [[:default]]
|
||||
metabase.driver.druid.client/DELETE [[:default]]
|
||||
metabase.driver.druid.client/GET [[:default]]
|
||||
metabase.driver.druid.client/POST [[:default]]
|
||||
metabase.driver.druid.query-processor-test/druid-query [[:block 0]]
|
||||
metabase.driver.druid.query-processor-test/druid-query-returning-rows [[:block 0]]
|
||||
metabase.driver.mongo.query-processor/mongo-let [[:block 1]]
|
||||
metabase.driver.sql-jdbc.actions/with-jdbc-transaction [[:block 1]]
|
||||
metabase.driver.sql-jdbc.connection/with-connection-spec-for-testing-connection [[:block 1]]
|
||||
metabase.driver.sql-jdbc.execute.diagnostic/capturing-diagnostic-info [[:block 1]]
|
||||
metabase.driver.sql.query-processor/apply-top-level-clause [[:default]]
|
||||
metabase.driver/with-driver [[:block 1]]
|
||||
metabase.lib.binning/with-binning [[:default]]
|
||||
metabase.lib.core/with-binning [[:default]]
|
||||
metabase.lib.core/with-join-alias [[:default]]
|
||||
metabase.lib.core/with-join-conditions [[:default]]
|
||||
metabase.lib.join/with-join-alias [[:default]]
|
||||
metabase.lib.join/with-join-conditions [[:default]]
|
||||
metabase.lib.test-util.macros/$ids [[:inner 0]]
|
||||
metabase.lib.test-util.macros/mbql-query [[:inner 0]]
|
||||
metabase.lib.util.match/match [[:inner 0]]
|
||||
metabase.lib.util.match/match-one [[:inner 0]]
|
||||
metabase.lib.util.match/replace [[:inner 0]]
|
||||
metabase.lib.util.match/replace-in [[:inner 0]]
|
||||
metabase.models.collection-test/with-collection-hierarchy [[:block 1]]
|
||||
metabase.models.collection-test/with-current-user-perms-for-collections [[:block 1]]
|
||||
metabase.models.collection-test/with-personal-and-impersonal-collections [[:block 1]]
|
||||
metabase.models.dashboard-test/with-dash-in-collection [[:inner 0]]
|
||||
metabase.models.interface/define-batched-hydration-method [[:inner 0]]
|
||||
metabase.models.interface/define-simple-hydration-method [[:inner 0]]
|
||||
metabase.models.params.chain-filter-test/with-clean-field-values-for-field [[:block 1]]
|
||||
metabase.models.params.chain-filter-test/with-fk-field-to-field-remapping [[:block 0]]
|
||||
metabase.models.params.chain-filter-test/with-human-readable-values-remapping [[:block 0]]
|
||||
metabase.models.setting.multi-setting/define-multi-setting [[:inner 0]]
|
||||
metabase.models.setting/defsetting [[:block 1]]
|
||||
metabase.models.task-history/with-task-history [[:block 1]]
|
||||
metabase.permissions.core/allow-changing-all-users-group-members [[:block 0]]
|
||||
metabase.permissions.core/disable-perms-cache [[:block 0]]
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-card-referencing [[:block 3]]
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-dashcard-referencing [[:block 3]]
|
||||
metabase.public-sharing.api-test/with-temp-public-card [[:block 1]]
|
||||
metabase.public-sharing.api-test/with-temp-public-dashboard [[:block 1]]
|
||||
metabase.public-sharing.api-test/with-temp-public-dashboard-and-card [[:block 1]]
|
||||
metabase.pulse.api.alert-test/with-alert-in-collection [[:block 1]]
|
||||
metabase.pulse.models.pulse-test/with-dashboard-subscription-in-collection [[:block 1]]
|
||||
metabase.pulse.models.pulse-test/with-pulse-in-collection [[:inner 0]]
|
||||
metabase.query-processor-test.pipeline-queries-test/pmbql-query [[:block 1]]
|
||||
metabase.query-processor-test.pipeline-queries-test/run-pmbql-query [[:block 1]]
|
||||
metabase.query-processor.debug/debug> [[:block 0]]
|
||||
metabase.query-processor.error-type/deferror [[:block 1]]
|
||||
metabase.query-processor.middleware.cache-backend.interface/with-cached-results [[:block 4]]
|
||||
metabase.query-processor.middleware.process-userland-query-test/with-query-execution [[:block 1]]
|
||||
metabase.query-processor.store/cached [[:block 1]]
|
||||
metabase.query-processor.store/with-metadata-provider [[:inner 0]]
|
||||
metabase.query-processor.streaming/streaming-response [[:block 1]]
|
||||
metabase.query-processor.test-util/format-rows-by [[:default]]
|
||||
metabase.request.core/as-admin [[:block 0]]
|
||||
metabase.request.core/with-current-request [[:inner 0]]
|
||||
metabase.request.core/with-current-user [[:inner 0]]
|
||||
metabase.request.core/with-limit-and-offset [[:inner 0]]
|
||||
metabase.request.session/as-admin [[:block 0]]
|
||||
metabase.request.session/with-current-user [[:inner 0]]
|
||||
metabase.sample-data-test/with-temp-sample-database-db [[:block 1]]
|
||||
metabase.search.api-test/do-test-users [[:block 1]]
|
||||
metabase.server.middleware.session/as-admin [[:block 0]]
|
||||
metabase.server.middleware.session/with-current-user [[:inner 0]]
|
||||
metabase.server.streaming-response-test/with-streaming-response-thread-pool [[:block 0]]
|
||||
metabase.server.streaming-response-test/with-test-driver-db! [[:block 0]]
|
||||
metabase.server.streaming-response/streaming-response [[:block 2]]
|
||||
metabase.session.api/http-401-on-error [[:block 0]]
|
||||
metabase.sync.fetch-metadata/log-if-error [[:block 1]]
|
||||
metabase.sync.sync-metadata.fields-test/with-test-db [[:block 0]]
|
||||
metabase.sync.util/do-with-start-and-finish-debug-logging [[:default]]
|
||||
metabase.sync.util/sum-for [[:block 1]]
|
||||
metabase.sync.util/sync-operation [[:block 3]]
|
||||
metabase.sync.util/with-db-logging-disabled [[:default]]
|
||||
metabase.sync.util/with-duplicate-ops-prevented [[:default]]
|
||||
metabase.sync.util/with-emoji-progress-bar [[:block 1]]
|
||||
metabase.sync.util/with-error-handling [[:block 1]]
|
||||
metabase.sync.util/with-start-and-finish-logging [[:default]]
|
||||
metabase.sync.util/with-start-and-finish-logging* [[:default]]
|
||||
metabase.sync.util/with-sync-events [[:default]]
|
||||
metabase.task/rerun-on-error [[:block 1]]
|
||||
metabase.test/$ids [[:inner 0]]
|
||||
metabase.test/as-admin [[:inner 0]]
|
||||
metabase.test/dataset [[:inner 0]]
|
||||
metabase.test/discard-setting-changes [[:block 1]]
|
||||
metabase.test/format-rows-by [[:default]]
|
||||
metabase.test/let-url [[:block 1]]
|
||||
metabase.test/mbql-query [[:inner 0]]
|
||||
metabase.test/native-query [[:block 0]]
|
||||
metabase.test/query [[:block 1]]
|
||||
metabase.test/run-mbql-query [[:inner 0]]
|
||||
metabase.test/test-driver [[:inner 0]]
|
||||
metabase.test/test-drivers [[:inner 0]]
|
||||
metabase.test/test-helpers-set-global-values! [[:block 0]]
|
||||
metabase.test/throw-if-called! [[:block 1]]
|
||||
metabase.test/with-actions [[:block 1]]
|
||||
metabase.test/with-actions-disabled [[:block 0]]
|
||||
metabase.test/with-actions-enabled [[:block 0]]
|
||||
metabase.test/with-actions-test-data [[:inner 0]]
|
||||
metabase.test/with-actions-test-data-and-actions-enabled [[:block 0]]
|
||||
metabase.test/with-actions-test-data-tables [[:block 1]]
|
||||
metabase.test/with-additional-premium-features [[:block 1]]
|
||||
metabase.test/with-current-user [[:inner 0]]
|
||||
metabase.test/with-driver [[:block 1]]
|
||||
metabase.test/with-empty-db [[:inner 0]]
|
||||
metabase.test/with-empty-h2-app-db [[:block 0]]
|
||||
metabase.test/with-metadata-provider [[:inner 0]]
|
||||
metabase.test/with-premium-features [[:block 1]]
|
||||
metabase.test/with-temp [[:inner 0]]
|
||||
metabase.test/with-temp-copy-of-db [[:block 0]]
|
||||
metabase.test/with-temp-scheduler [[:block 0]]
|
||||
metabase.test/with-temp-test-data [[:inner 0]]
|
||||
metabase.test/with-temp-vals-in-db [[:block 3]]
|
||||
metabase.test/with-test-user [[:inner 0]]
|
||||
metabase.test/with-user-in-groups [[:inner 0]]
|
||||
metabase.test.data/$ids [[:inner 0]]
|
||||
metabase.test.data/dataset [[:inner 0]]
|
||||
metabase.test.data/mbql-query [[:inner 0]]
|
||||
metabase.test.data/native-query [[:block 0]]
|
||||
metabase.test.data/query [[:block 1]]
|
||||
metabase.test.data/run-mbql-query [[:inner 0]]
|
||||
metabase.test.data/with-empty-h2-app-db [[:block 0]]
|
||||
metabase.test.data/with-temp-copy-of-db [[:block 0]]
|
||||
metabase.test.data.datasets/test-driver [[:inner 0]]
|
||||
metabase.test.data.datasets/test-drivers [[:inner 0]]
|
||||
metabase.test.data.one-off-dbs/with-blank-db [[:block 0]]
|
||||
metabase.test.data.one-off-dbs/with-blueberries-db [[:block 0]]
|
||||
metabase.test.data.users/with-test-user [[:inner 0]]
|
||||
metabase.test.util/discard-setting-changes [[:block 1]]
|
||||
metabase.test.util/let-url [[:block 1]]
|
||||
metabase.test.util/throw-if-called! [[:block 1]]
|
||||
metabase.test.util/with-temp-scheduler [[:block 0]]
|
||||
metabase.test.util/with-temp-vals-in-db [[:block 3]]
|
||||
metabase.test.util/with-user-in-groups [[:inner 0]]
|
||||
metabase.test.util.public-settings/with-additional-premium-features [[:block 1]]
|
||||
metabase.test.util.public-settings/with-premium-features [[:block 1]]
|
||||
metabase.test.util.thread-local/test-helpers-set-global-values! [[:block 0]]
|
||||
metabase.timeseries-query-processor-test.util/test-timeseries-drivers [[:block 0]]
|
||||
metabase.timeseries-query-processor-test/run-mbql-query [[:inner 0]]
|
||||
metabase.upload-test/with-upload-table! [[:inner 0]]
|
||||
metabase.upload.types/with-currency [[:default]]
|
||||
metabase.upload.types/with-parens [[:default]]
|
||||
metabase.util/auto-retry [[:block 1]]
|
||||
metabase.util/case-enum [[:block 1]]
|
||||
metabase.util/ignore-exceptions [[:block 0]]
|
||||
metabase.util/or-with [[:block 1]]
|
||||
metabase.util/profile [[:block 1]]
|
||||
metabase.util/prog1 [[:inner 0]]
|
||||
metabase.util/varargs [[:inner 0]]
|
||||
metabase.util/with-us-locale [[:block 0]]
|
||||
metabase.util.async/cancelable-thread [[:block 0]]
|
||||
metabase.util.date-2/with-time-zone-same-instant [[:default]]
|
||||
metabase.util.encryption-test/with-secret-key [[:block 1]]
|
||||
metabase.util.honey-sql-2/with-database-type-info [[:default]]
|
||||
metabase.util.i18n/deferred-trs [[:default]]
|
||||
metabase.util.i18n/deferred-tru [[:default]]
|
||||
metabase.util.i18n/trs [[:default]]
|
||||
metabase.util.i18n/trsn [[:default]]
|
||||
metabase.util.i18n/tru [[:default]]
|
||||
metabase.util.i18n/trun [[:default]]
|
||||
metabase.util.jvm/auto-retry [[:block 1]]
|
||||
metabase.util.jvm/varargs [[:block 1]]
|
||||
metabase.util.jvm/with-us-locale [[:block 0]]
|
||||
metabase.util.malli/disable-enforcement [[:block 0]]
|
||||
metabase.util.malli/with [[:default]]
|
||||
metabase.util.malli/with-api-error-message [[:default]]
|
||||
metabase.util.namespaces/import-fns [[:default]]
|
||||
metabase.util.queue-test/await-test-while [[:block 1]]
|
||||
metabuild-common.core/exit-when-finished-nonzero-on-exception [[:block 0]]
|
||||
metabuild-common.core/step [[:block 1]]
|
||||
metabuild-common.entrypoint/exit-when-finished-nonzero-on-exception [[:block 0]]
|
||||
metabuild-common.steps/step [[:block 1]]
|
||||
methodical.core/defmethod [[:inner 0]]
|
||||
methodical.core/defmulti [[:inner 0]]
|
||||
methodical.core/with-dispatcher [[:default]]
|
||||
methodical.core/with-method-table [[:default]]
|
||||
methodical.core/with-prefers [[:default]]
|
||||
methodical.interface/with-dispatcher [[:default]]
|
||||
methodical.interface/with-method-table [[:default]]
|
||||
methodical.interface/with-prefers [[:default]]
|
||||
methodical.macros/defmethod [[:inner 0]]
|
||||
methodical.macros/defmulti [[:inner 0]]
|
||||
saml20-clj.sp.response/validate-confirmation-datas [[:block 1]]
|
||||
toucan2.connection/with-transaction [[:block 1]]
|
||||
toucan2.core/build [[:block 0]]
|
||||
toucan2.core/compile [[:block 0]]
|
||||
toucan2.core/debug [[:block 0]]
|
||||
toucan2.core/define-after-insert [[:inner 0]]
|
||||
toucan2.core/define-after-select [[:inner 0]]
|
||||
toucan2.core/define-after-update [[:inner 0]]
|
||||
toucan2.core/define-before-delete [[:inner 0]]
|
||||
toucan2.core/define-before-insert [[:inner 0]]
|
||||
toucan2.core/define-before-select [[:inner 0]]
|
||||
toucan2.core/define-default-fields [[:inner 0]]
|
||||
toucan2.core/define-named-query [[:block 1]]
|
||||
toucan2.core/deftransforms [[:block 1]]
|
||||
toucan2.core/with-transaction [[:block 1]]
|
||||
toucan2.tools.after/define-after-impl [[:default]]
|
||||
toucan2.tools.after-insert/define-after-insert [[:inner 0]]
|
||||
toucan2.tools.after-select/define-after-select [[:inner 0]]
|
||||
toucan2.tools.after-update/define-after-update [[:inner 0]]
|
||||
toucan2.tools.before-delete/define-before-delete [[:inner 0]]
|
||||
toucan2.tools.before-insert/define-before-insert [[:inner 0]]
|
||||
toucan2.tools.before-select/define-before-select [[:inner 0]]
|
||||
toucan2.tools.compile/build [[:block 0]]
|
||||
toucan2.tools.compile/compile [[:block 0]]
|
||||
toucan2.tools.compile/resolved [[:block 0]]
|
||||
toucan2.tools.debug/debug [[:block 0]]
|
||||
toucan2.tools.default-fields/define-default-fields [[:inner 0]]
|
||||
toucan2.tools.named-query/define-named-query [[:block 1]]
|
||||
toucan2.tools.simple-out-transform/define-out-transform [[:inner 0]]
|
||||
toucan2.tools.transformed/deftransforms [[:block 1]]
|
||||
toucan2.tools.with-temp/with-temp [[:inner 0]]
|
||||
toucan2.util/try-with-error-context [[:inner 0]]}}
|
||||
|
||||
17
.github/workflows/containerize-jar.yml
vendored
17
.github/workflows/containerize-jar.yml
vendored
@@ -13,9 +13,6 @@ on:
|
||||
type: string
|
||||
commit:
|
||||
type: string
|
||||
release:
|
||||
type: string
|
||||
default: 'true'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
artifact-name:
|
||||
@@ -59,7 +56,7 @@ jobs:
|
||||
const version = "${{ inputs.tag }}".split('-')[0];
|
||||
|
||||
if (!isValidVersionString(version)) {
|
||||
return "linux/amd64,linux/arm64";
|
||||
return "linux/amd64";
|
||||
}
|
||||
// versions before 53 need to be handled differently
|
||||
const buildInfo = getBuildRequirements(version);
|
||||
@@ -69,8 +66,8 @@ jobs:
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_USERNAME || secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_TOKEN || secrets.DOCKERHUB_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_RELEASE_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_RELEASE_TOKEN }}
|
||||
- name: Set up QEMU
|
||||
if: contains(steps.platforms.outputs.result, 'arm')
|
||||
uses: docker/setup-qemu-action@v3
|
||||
@@ -106,8 +103,8 @@ jobs:
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_USERNAME || secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_TOKEN || secrets.DOCKERHUB_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_RELEASE_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_RELEASE_TOKEN }}
|
||||
- name: Pull the container image
|
||||
run: docker pull ${{ inputs.repo }}:${{ inputs.tag }}
|
||||
- name: Launch container
|
||||
@@ -126,8 +123,8 @@ jobs:
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_USERNAME || secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_TOKEN || secrets.DOCKERHUB_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_RELEASE_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_RELEASE_TOKEN }}
|
||||
- name: Pull the container image
|
||||
run: docker pull ${{ inputs.repo }}:${{ inputs.tag }}
|
||||
- name: Launch container
|
||||
|
||||
20
.github/workflows/docs_bump_detected.yml
vendored
20
.github/workflows/docs_bump_detected.yml
vendored
@@ -20,15 +20,11 @@ jobs:
|
||||
with:
|
||||
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
script: | #js
|
||||
if (process.env.BRANCH_NAME === "master" ||
|
||||
/^release-x\.\d+\.x$/.test(process.env.BRANCH_NAME)) {
|
||||
github.rest.repos.createDispatchEvent({
|
||||
owner: "${{ github.repository_owner }}",
|
||||
repo: "docs.metabase.github.io",
|
||||
event_type: "docs_update",
|
||||
client_payload: { branch_name: process.env.BRANCH_NAME
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log("Branch name is not to be published: ", process.env.BRANCH_NAME);
|
||||
}
|
||||
github.rest.repos.createDispatchEvent({
|
||||
owner: "${{ github.repository_owner }}",
|
||||
repo: "docs.metabase.github.io",
|
||||
event_type: "docs_update",
|
||||
client_payload: {
|
||||
branch_name: process.env.BRANCH_NAME // This needs to match the workflow file
|
||||
}
|
||||
});
|
||||
|
||||
207
.github/workflows/drivers.yml
vendored
207
.github/workflows/drivers.yml
vendored
@@ -12,6 +12,33 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
be-tests-h2:
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
name: H2
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test H2 driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-h2'
|
||||
test-args: >-
|
||||
:only-tags [:mb/driver-tests]
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
if: always()
|
||||
with:
|
||||
input-path: ./target/junit/
|
||||
output-name: ${{ github.job }}
|
||||
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
|
||||
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-tests-athena-ee:
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -81,53 +108,6 @@ jobs:
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-tests-clickhouse-ee:
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: clickhouse
|
||||
MB_CLICKHOUSE_TEST_HOST: localhost
|
||||
MB_CLICKHOUSE_TEST_PORT: 8123
|
||||
MB_CLICKHOUSE_TEST_OLD_PORT: 8124
|
||||
MB_CLICKHOUSE_TEST_NGINX_PORT: 8127
|
||||
name: Clickhouse
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Add ClickHouse TLS instance to /etc/hosts
|
||||
run: |
|
||||
sudo echo "127.0.0.1 server.clickhouseconnect.test" | sudo tee -a /etc/hosts
|
||||
- name: Start ClickHouse in Docker
|
||||
uses: hoverkraft-tech/compose-action@v2.0.0
|
||||
with:
|
||||
compose-file: "modules/drivers/clickhouse/docker-compose.yml"
|
||||
down-flags: "--volumes"
|
||||
services: |
|
||||
clickhouse
|
||||
clickhouse_tls
|
||||
clickhouse_older_version
|
||||
clickhouse_cluster_node1
|
||||
clickhouse_cluster_node2
|
||||
nginx
|
||||
- name: Test Clickhouse driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-clickhouse-ee'
|
||||
test-args: >-
|
||||
:only-tags [:mb/driver-tests]
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
if: always()
|
||||
with:
|
||||
input-path: ./target/junit/
|
||||
output-name: ${{ github.job }}
|
||||
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
|
||||
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-tests-druid-ee:
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -163,41 +143,6 @@ jobs:
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-tests-druid-jdbc-ee:
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: druid-jdbc
|
||||
services:
|
||||
druid:
|
||||
image: metabase/druid:29.0.1-json-no-ingestion
|
||||
ports:
|
||||
- "8888:8888"
|
||||
env:
|
||||
CLUSTER_SIZE: nano-quickstart
|
||||
name: Druid (JDBC)
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test Druid JDBC driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-druid-jdbc-ee'
|
||||
test-args: >-
|
||||
:only-tags [:mb/driver-tests]
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
if: always()
|
||||
with:
|
||||
input-path: ./target/junit/
|
||||
output-name: ${{ github.job }}
|
||||
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
|
||||
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-tests-databricks-ee:
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -232,54 +177,27 @@ jobs:
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-tests-databricks-multi-catalog-ee:
|
||||
be-tests-druid-jdbc-ee:
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: databricks
|
||||
MB_DATABRICKS_TEST_MULTI_LEVEL_SCHEMA: true
|
||||
MB_DATABRICKS_TEST_HOST: ${{ secrets.MB_DATABRICKS_JDBC_TEST_HOST }}
|
||||
MB_DATABRICKS_TEST_HTTP_PATH: ${{ secrets.MB_DATABRICKS_JDBC_TEST_HTTP_PATH }}
|
||||
MB_DATABRICKS_TEST_TOKEN: ${{ secrets.MB_DATABRICKS_JDBC_TEST_TOKEN }}
|
||||
MB_DATABRICKS_TEST_CATALOG: 'metabase_ci'
|
||||
MB_DATABRICKS_TEST_CLIENT_ID: ${{ secrets.MB_DATABRICKS_JDBC_TEST_CLIENT_ID }}
|
||||
MB_DATABRICKS_TEST_OAUTH_SECRET: ${{ secrets.MB_DATABRICKS_JDBC_TEST_OAUTH_SECRET }}
|
||||
name: Databricks (Multi-Catalog)
|
||||
DRIVERS: druid-jdbc
|
||||
services:
|
||||
druid:
|
||||
image: metabase/druid:29.0.1-json-no-ingestion
|
||||
ports:
|
||||
- "8888:8888"
|
||||
env:
|
||||
CLUSTER_SIZE: nano-quickstart
|
||||
name: Druid (JDBC)
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test Databricks driver with multi-catalog
|
||||
- name: Test Druid JDBC driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-databricks-multi-catalog-ee'
|
||||
test-args: >-
|
||||
:only-tags [:mb/driver-tests]
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
if: always()
|
||||
with:
|
||||
input-path: ./target/junit/
|
||||
output-name: ${{ github.job }}
|
||||
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
|
||||
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-tests-h2:
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
name: H2
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test H2 driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-h2'
|
||||
junit-name: 'be-tests-druid-jdbc-ee'
|
||||
test-args: >-
|
||||
:only-tags [:mb/driver-tests]
|
||||
- name: Upload Test Results
|
||||
@@ -1086,6 +1004,53 @@ jobs:
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
be-tests-clickhouse-ee:
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: clickhouse
|
||||
MB_CLICKHOUSE_TEST_HOST: localhost
|
||||
MB_CLICKHOUSE_TEST_PORT: 8123
|
||||
MB_CLICKHOUSE_TEST_OLD_PORT: 8124
|
||||
MB_CLICKHOUSE_TEST_NGINX_PORT: 8127
|
||||
name: Clickhouse
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Add ClickHouse TLS instance to /etc/hosts
|
||||
run: |
|
||||
sudo echo "127.0.0.1 server.clickhouseconnect.test" | sudo tee -a /etc/hosts
|
||||
- name: Start ClickHouse in Docker
|
||||
uses: hoverkraft-tech/compose-action@v2.0.0
|
||||
with:
|
||||
compose-file: "modules/drivers/clickhouse/docker-compose.yml"
|
||||
down-flags: "--volumes"
|
||||
services: |
|
||||
clickhouse
|
||||
clickhouse_tls
|
||||
clickhouse_older_version
|
||||
clickhouse_cluster_node1
|
||||
clickhouse_cluster_node2
|
||||
nginx
|
||||
- name: Test Clickhouse driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-clickhouse-ee'
|
||||
test-args: >-
|
||||
:only-tags [:mb/driver-tests]
|
||||
- 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 }}
|
||||
|
||||
drivers-tests-result:
|
||||
needs:
|
||||
# if you add a driver job, you must add it to this list for it to be a required check
|
||||
|
||||
37
.github/workflows/e2e-sample-apps-tests.yml
vendored
37
.github/workflows/e2e-sample-apps-tests.yml
vendored
@@ -17,13 +17,10 @@ env:
|
||||
TEST_SUITES: |
|
||||
[
|
||||
"metabase-nodejs-react-sdk-embedding-sample-e2e",
|
||||
"metabase-nextjs-sdk-embedding-sample-e2e",
|
||||
"shoppy-e2e"
|
||||
"metabase-nextjs-sdk-embedding-sample-e2e"
|
||||
]
|
||||
TEST_SUITES_TO_RUN_IN_MASTER_ONLY: |
|
||||
[
|
||||
"shoppy-e2e"
|
||||
]
|
||||
[]
|
||||
SAMPLE_APP_MAIN_BRANCH_NAME: "main"
|
||||
SAMPLE_APP_STABLE_RELEASE_BRANCH_NAME_SUFFIX: "stable"
|
||||
|
||||
@@ -218,9 +215,8 @@ jobs:
|
||||
TZ: US/Pacific # to make node match the instance tz
|
||||
# Sample Apps testing variables
|
||||
CYPRESS_CI: true
|
||||
TEST_SUITE: ${{ matrix.test_suite }}
|
||||
SAMPLE_APP_BRANCH_NAME: ${{ needs.get-sample-apps-data.outputs.branch_name }}
|
||||
permissions:
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -246,7 +242,6 @@ jobs:
|
||||
- name: Check if sample app branch exists
|
||||
id: check-sample-app-branch
|
||||
run: |
|
||||
TEST_SUITE="${{ matrix.test_suite }}"
|
||||
REPO_NAME="${TEST_SUITE%-e2e}"
|
||||
REPO_URL="https://github.com/metabase/${REPO_NAME}.git"
|
||||
echo "Checking if branch '${SAMPLE_APP_BRANCH_NAME}' exists in ${REPO_URL}..."
|
||||
@@ -256,29 +251,9 @@ jobs:
|
||||
echo "sample_app_branch_exists=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Configure AWS credentials
|
||||
if: ${{ matrix.test_suite == 'shoppy-e2e' }}
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: ${{ secrets.SHOPPY_IAM_ROLE }}
|
||||
role-session-name: GitHub_to_AWS_via_FederatedOIDC
|
||||
aws-region: us-east-1
|
||||
|
||||
- name: Download Shoppy's App DB PostgreSQL dump from S3
|
||||
if: ${{ matrix.test_suite == 'shoppy-e2e' }}
|
||||
run: |
|
||||
aws s3 cp s3://${{ secrets.SHOPPY_METABASE_APP_DB_S3_BUCKET }}/${{ secrets.SHOPPY_METABASE_APP_DB_S3_KEY }} ./e2e/tmp/db_dumps/shoppy_metabase_app_db_dump.sql
|
||||
|
||||
- name: Prepare and launch Sample Apps for shoppy-e2e test suite
|
||||
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' && matrix.test_suite == 'shoppy-e2e' }}
|
||||
env:
|
||||
METABASE_APP_DB_USER: ${{ secrets.SHOPPY_METABASE_APP_DB_USER }}
|
||||
METABASE_APP_DB: ${{ secrets.SHOPPY_METABASE_APP_DB_DATABASE }}
|
||||
run: npx tsx ./e2e/runner/start-sample-app-containers/start-ci.ts shoppy-e2e
|
||||
|
||||
- name: Prepare and launch Sample Apps for other test suites
|
||||
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' && matrix.test_suite != 'shoppy-e2e' }}
|
||||
run: npx tsx ./e2e/runner/start-sample-app-containers/start-ci.ts ${{ matrix.test_suite }}
|
||||
- name: Prepare and launch Sample Apps
|
||||
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' }}
|
||||
run: npx tsx ./e2e/runner/start-sample-app-containers/start-ci.ts
|
||||
|
||||
- name: Run e2e tests for Sample App
|
||||
id: run-e2e-tests
|
||||
|
||||
331
.github/workflows/uberjar.yml
vendored
331
.github/workflows/uberjar.yml
vendored
@@ -1,14 +1,12 @@
|
||||
name: Build + Docker Uberjar
|
||||
|
||||
# This workflow builds an uberjar and pushes it to dockerhub for any branch, either on-demand,
|
||||
# or automatically for the listed branches
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- "master"
|
||||
- metabot-v3-second-try
|
||||
- feature-visualizer
|
||||
- internal-tools
|
||||
- "internal-tools"
|
||||
paths-ignore:
|
||||
# config files
|
||||
- ".**"
|
||||
@@ -25,63 +23,16 @@ on:
|
||||
description: "Optional full-length commit SHA-1 hash"
|
||||
|
||||
jobs:
|
||||
get-container-info:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
name: Get container info
|
||||
outputs:
|
||||
editions: ${{ toJson(fromJson(steps.info.outputs.result).editions) }}
|
||||
ee: ${{ toJson(fromJson(steps.info.outputs.result).ee) }}
|
||||
oss: ${{ toJson(fromJson(steps.info.outputs.result).oss) }}
|
||||
steps:
|
||||
- name: Get docker repo and tag
|
||||
id: info
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: | # js
|
||||
const branch = '${{ github.head_ref || github.ref_name }}';
|
||||
const owner = '${{ github.repository_owner }}';
|
||||
|
||||
console.log(`Branch: ${branch}`);
|
||||
|
||||
if (branch === "master") {
|
||||
return {
|
||||
editions: ["ee", "oss"],
|
||||
ee: {
|
||||
repo: `${owner}/metabase-enterprise-head`,
|
||||
tag: "latest"
|
||||
},
|
||||
oss: {
|
||||
repo: `${owner}/metabase-head`,
|
||||
tag: "latest"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
editions: ["ee"],
|
||||
ee: {
|
||||
repo: `${owner}/metabase-dev`,
|
||||
tag: branch.replaceAll("/", "-"), // slashes make docker sad
|
||||
},
|
||||
};
|
||||
|
||||
- name: Print output
|
||||
run: |
|
||||
echo "${{ steps.info.outputs.result }}"
|
||||
|
||||
build:
|
||||
needs: get-container-info
|
||||
name: Build MB ${{ matrix.edition }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
matrix:
|
||||
edition: ${{ fromJson(needs.get-container-info.outputs.editions) }}
|
||||
edition: [ee, oss]
|
||||
env:
|
||||
MB_EDITION: ${{ matrix.edition }}
|
||||
INTERACTIVE: false
|
||||
SKIP_LICENSES: true # faster builds for dev
|
||||
steps:
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v4
|
||||
@@ -99,16 +50,16 @@ jobs:
|
||||
- name: Prepare uberjar artifact
|
||||
uses: ./.github/actions/prepare-uberjar-artifact
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.event.inputs.commit || github.sha }}-uberjar
|
||||
name: metabase-${{ matrix.edition }}-${{ github.sha }}-uberjar
|
||||
|
||||
check-jar-health:
|
||||
check_jar_health:
|
||||
runs-on: ubuntu-22.04
|
||||
name: Is ${{ matrix.edition }} (java ${{ matrix.java-version }}) healthy?
|
||||
needs: [build, get-container-info]
|
||||
needs: build
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
edition: ${{ fromJson(needs.get-container-info.outputs.editions) }}
|
||||
edition: [ee, oss]
|
||||
java-version: [21]
|
||||
steps:
|
||||
- name: Prepare JRE (Java Run-time Environment)
|
||||
@@ -121,51 +72,261 @@ jobs:
|
||||
- uses: actions/download-artifact@v4
|
||||
name: Retrieve uberjar artifact
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.event.inputs.commit || github.sha }}-uberjar
|
||||
name: metabase-${{ matrix.edition }}-${{ github.sha }}-uberjar
|
||||
- name: Launch uberjar
|
||||
run: >-
|
||||
java --add-opens java.base/java.nio=ALL-UNNAMED -jar ./target/uberjar/metabase.jar &
|
||||
- name: Wait for Metabase to start
|
||||
run: while ! curl 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
|
||||
containerize:
|
||||
needs: [check-jar-health, get-container-info]
|
||||
strategy:
|
||||
matrix:
|
||||
edition: ${{ fromJson(needs.get-container-info.outputs.editions) }}
|
||||
uses: ./.github/workflows/containerize-jar.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
artifact-name: metabase-${{ matrix.edition }}-${{ github.event.inputs.commit || github.sha }}-uberjar
|
||||
commit: ${{ github.event.inputs.commit || github.sha }}
|
||||
repo: ${{ fromJson(needs.get-container-info.outputs[matrix.edition]).repo }}
|
||||
tag: ${{ fromJson(needs.get-container-info.outputs[matrix.edition]).tag }}
|
||||
release: "false"
|
||||
|
||||
run-trivy:
|
||||
needs: [get-container-info, containerize]
|
||||
strategy:
|
||||
matrix:
|
||||
edition: ${{ fromJson(needs.get-container-info.outputs.editions) }}
|
||||
containerize_test_and_push_container:
|
||||
runs-on: ubuntu-22.04
|
||||
name: Run Trivy vulnerability scanner
|
||||
name: Containerize ${{ matrix.edition }}
|
||||
needs: check_jar_health
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [ee, oss]
|
||||
fail-fast: false
|
||||
services:
|
||||
registry:
|
||||
image: registry:2
|
||||
ports:
|
||||
- 5000:5000
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Check out the code
|
||||
- name: Extract and clean branch name
|
||||
shell: bash
|
||||
run: echo "branch=$(echo $GITHUB_REF_NAME | sed 's/[^-._a-zA-Z0-9]/-/g')" >> $GITHUB_OUTPUT
|
||||
id: extract_branch
|
||||
- name: Verify the intended tag of the container image
|
||||
run: echo "Container image will be tagged as ${{ steps.extract_branch.outputs.branch }}-${{ matrix.edition }}"
|
||||
- name: Check out the code (Dockerfile needed)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.commit || github.sha }}
|
||||
- name: Run Trivy vulnerability scanner
|
||||
ref: ${{ github.event.inputs.commit }}
|
||||
- name: Download uploaded artifacts to insert into container
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.sha }}-uberjar
|
||||
path: bin/docker/
|
||||
- name: Move the ${{ matrix.edition }} uberjar to the context dir
|
||||
run: mv bin/docker/target/uberjar/metabase.jar bin/docker/.
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2.5.0
|
||||
with:
|
||||
driver-opts: network=host
|
||||
- name: Build ${{ matrix.edition }} container
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-${{ matrix.edition }}
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: true
|
||||
push: true
|
||||
- name: Launch ${{ matrix.edition }} container
|
||||
run: docker run --rm -dp 3000:3000 localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-${{ matrix.edition }}
|
||||
timeout-minutes: 5
|
||||
- name: Is Docker running?
|
||||
run: docker ps
|
||||
- name: Wait for Metabase to start and reach 100% health
|
||||
run: while ! curl 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
timeout-minutes: 3
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Retag and push images if master (ee) - should be cached at this point
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'ee' }}
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: ${{ github.repository_owner }}/metabase-enterprise-head:latest
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: false
|
||||
push: true
|
||||
|
||||
# TODO: remove when we're done testing metabot
|
||||
- name: Retag and push images if metabot-v3-second-try (ee) - should be cached at this point
|
||||
if: ${{ (github.ref_name == 'metabot-v3-second-try') && matrix.edition == 'ee' }}
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: ${{ github.repository_owner }}/metabase-enterprise-head:metabot
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: false
|
||||
push: true
|
||||
|
||||
- name: Retag and push images if master (oss) - should be cached at this point
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'oss' }}
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: ${{ github.repository_owner }}/metabase-head:latest
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: false
|
||||
push: true
|
||||
|
||||
- name: Retag and push images if dev branch - should be cached at this point
|
||||
if: ${{ !(startsWith(github.ref_name,'master') || startsWith(github.ref_name,'backport')) && matrix.edition == 'ee' }}
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: ${{ github.repository_owner }}/metabase-dev:${{ steps.extract_branch.outputs.branch }}
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: false
|
||||
push: true
|
||||
|
||||
- name: Run Trivy vulnerability scanner if master (ee)
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'ee' }}
|
||||
uses: aquasecurity/trivy-action@0.29.0
|
||||
env:
|
||||
TRIVY_OFFLINE_SCAN: true
|
||||
repo: ${{ fromJson(needs.get-container-info.outputs[matrix.edition]).repo }}
|
||||
tag: ${{ fromJson(needs.get-container-info.outputs[matrix.edition]).tag }}
|
||||
with:
|
||||
image-ref: docker.io/${{ env.repo }}:${{ env.tag }}
|
||||
image-ref: docker.io/${{ github.repository_owner }}/metabase-enterprise-head:latest
|
||||
format: sarif
|
||||
output: trivy-results.sarif
|
||||
version: "v0.57.1"
|
||||
- name: Upload Trivy scan results to GitHub Security tab
|
||||
|
||||
- name: Run Trivy vulnerability scanner if master (oss)
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'oss' }}
|
||||
uses: aquasecurity/trivy-action@0.29.0
|
||||
env:
|
||||
TRIVY_OFFLINE_SCAN: true
|
||||
with:
|
||||
image-ref: docker.io/${{ github.repository_owner }}/metabase-head:latest
|
||||
format: sarif
|
||||
output: trivy-results.sarif
|
||||
version: "v0.57.1"
|
||||
|
||||
- name: Run Trivy vulnerability scanner if dev branch
|
||||
if: ${{ !(startsWith(github.ref_name,'master') || startsWith(github.ref_name,'backport')) && matrix.edition == 'ee' }}
|
||||
uses: aquasecurity/trivy-action@0.29.0
|
||||
env:
|
||||
TRIVY_OFFLINE_SCAN: true
|
||||
with:
|
||||
version: "v0.57.1"
|
||||
image-ref: docker.io/${{ github.repository_owner }}/metabase-dev:${{ steps.extract_branch.outputs.branch }}
|
||||
format: sarif
|
||||
output: trivy-results.sarif
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab if master (ee)
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'ee' }}
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: "trivy-results.sarif"
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab if master (oss)
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'oss' }}
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: "trivy-results.sarif"
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab if dev branch
|
||||
if: ${{ !(startsWith(github.ref_name,'master') || startsWith(github.ref_name,'backport')) && matrix.edition == 'ee' }}
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: "trivy-results.sarif"
|
||||
|
||||
containerize_multi_arch:
|
||||
runs-on: ubuntu-22.04
|
||||
name: Containerize multi-arch ${{ matrix.edition }}
|
||||
needs: check_jar_health
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [ee, oss]
|
||||
services:
|
||||
registry:
|
||||
image: registry:2
|
||||
ports:
|
||||
- 5000:5000
|
||||
steps:
|
||||
- name: Extract and clean branch name
|
||||
shell: bash
|
||||
run: echo "branch=$(echo $GITHUB_REF_NAME | sed 's/[^-._a-zA-Z0-9]/-/g')" >> $GITHUB_OUTPUT
|
||||
id: extract_branch
|
||||
- name: Verify the intended tag of the container image
|
||||
run: echo "Container image will be tagged as ${{ steps.extract_branch.outputs.branch }}-${{ matrix.edition }}"
|
||||
- name: Check out the code (Dockerfile needed)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.commit }}
|
||||
- name: Download uploaded artifacts to insert into container
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.sha }}-uberjar
|
||||
path: bin/docker/
|
||||
- name: Move the ${{ matrix.edition }} uberjar to the context dir
|
||||
run: mv bin/docker/target/uberjar/metabase.jar bin/docker/.
|
||||
# We need it for multi-arch build
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
with:
|
||||
platforms: "arm64"
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2.5.0
|
||||
with:
|
||||
driver-opts: network=host
|
||||
# Build experimental ubuntu-based images only for master
|
||||
- name: Build ${{ matrix.edition }} Ubuntu based multi-arch container
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
file: bin/docker/Dockerfile_ubuntu
|
||||
network: host
|
||||
tags: localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-${{ matrix.edition }}-ubuntu
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: true
|
||||
push: true
|
||||
- name: Launch ${{ matrix.edition }} Ubuntu based container
|
||||
run: docker run --rm -dp 3001:3000 localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-${{ matrix.edition }}-ubuntu
|
||||
timeout-minutes: 5
|
||||
- name: Is Docker with Ubuntu running?
|
||||
run: docker ps
|
||||
- name: Wait for Ubuntu-based Metabase container to start and reach 100% health
|
||||
run: while ! curl 'http://localhost:3001/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
timeout-minutes: 3
|
||||
- name: Login to Docker Hub
|
||||
if: ${{ github.ref_name == 'master' }}
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
# Push experimental ubuntu image only for versions based on a master
|
||||
- name: Install regctl
|
||||
if: ${{ github.ref_name == 'master' }}
|
||||
uses: regclient/actions/regctl-installer@main
|
||||
with:
|
||||
release: "v0.4.7"
|
||||
- name: Switch regctl to point to localhost:5000 via http
|
||||
if: ${{ github.ref_name == 'master' }}
|
||||
run: regctl registry set --tls disabled localhost:5000
|
||||
- name: Retag and push ubuntu-based images if master (ee)
|
||||
if: ${{ (matrix.edition == 'ee') && (github.ref_name == 'master') }}
|
||||
run: regctl image copy localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-ee-ubuntu ${{ github.repository_owner }}/metabase-enterprise-head:latest-ubuntu
|
||||
- name: Retag and push ubuntu-based images if master (oss)
|
||||
if: ${{ (matrix.edition == 'oss') && (github.ref_name == 'master') }}
|
||||
run: regctl image copy localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-oss-ubuntu ${{ github.repository_owner }}/metabase-head:latest-ubuntu
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -43,9 +43,6 @@
|
||||
/frontend/test/snapshots/*
|
||||
/e2e/snapshots/*
|
||||
/e2e/tmp/*
|
||||
!/e2e/tmp/db_dumps
|
||||
/e2e/tmp/db_dumps/*
|
||||
!/e2e/tmp/db_dumps/.gitkeep
|
||||
/lein-plugins/*/target
|
||||
/local
|
||||
/locales/metabase-*.pot
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copied from the instance settings and re-ordered, may go out of sync with the real ones
|
||||
// Locales in the format `xx_AA` were also changed to `xx-AA`
|
||||
export const availableLocales = [
|
||||
{ value: undefined, title: "default (instance locale)" },
|
||||
{ value: "en", right: "🇺🇸", title: "en" },
|
||||
{ value: "de", right: "🇩🇪", title: "de" }, // one that we know should be well supported
|
||||
{ value: "ar", right: "🇸🇦", title: "ar" },
|
||||
{ value: "ar-SA", right: "🇸🇦", title: "ar-SA" },
|
||||
{ value: "bg", right: "🇧🇬", title: "bg" },
|
||||
{ value: "ca", right: "🇪🇺", title: "ca" },
|
||||
{ value: "cs", right: "🇨🇿", title: "cs" },
|
||||
{ value: "da", right: "🇩🇰", title: "da" },
|
||||
{ value: "es", right: "🇪🇺", title: "es" },
|
||||
{ value: "fa", right: "🇮🇷", title: "fa" },
|
||||
{ value: "fi", right: "🇫🇮", title: "fi" },
|
||||
{ value: "fr", right: "🇫🇷", title: "fr" },
|
||||
{ value: "he", right: "🇮🇱", title: "he" },
|
||||
{ value: "hu", right: "🇭🇺", title: "hu" },
|
||||
{ value: "id", right: "🇮🇩", title: "id" },
|
||||
{ value: "it", right: "🇮🇹", title: "it" },
|
||||
{ value: "ja", right: "🇯🇵", title: "ja" },
|
||||
{ value: "ko", right: "🇰🇷", title: "ko" },
|
||||
{ value: "lv", right: "🇱🇻", title: "lv" },
|
||||
{ value: "ms", right: "🇲🇾", title: "ms" },
|
||||
{ value: "nb", right: "🇳🇴", title: "nb" },
|
||||
{ value: "nl", right: "🇳🇱", title: "nl" },
|
||||
{ value: "pl", right: "🇵🇱", title: "pl" },
|
||||
{ value: "pt-BR", right: "🇧🇷", title: "pt-BR" },
|
||||
{ value: "ru", right: "🇷🇺", title: "ru" },
|
||||
{ value: "sk", right: "🇸🇰", title: "sk" },
|
||||
{ value: "sl", right: "🇸🇱", title: "sl" },
|
||||
{ value: "sq", right: "🇦🇱", title: "sq" },
|
||||
{ value: "sr", right: "🇷🇸", title: "sr" },
|
||||
{ value: "sv", right: "🇸🇪", title: "sv" },
|
||||
{ value: "tr", right: "🇹🇷", title: "tr" },
|
||||
{ value: "uk", right: "🇺🇦", title: "uk" },
|
||||
{ value: "vi", right: "🇻🇳", title: "vi" },
|
||||
{ value: "zh-CN", right: "🇨🇳", title: "zh-CN" },
|
||||
{ value: "zh-HK", right: "🇭🇰", title: "zh-HK" },
|
||||
{ value: "zh-TW", right: "🇹🇼", title: "zh-TW" },
|
||||
];
|
||||
@@ -5,7 +5,6 @@ import { GlobalTypes } from "@storybook/types";
|
||||
window.METABASE_REMOVE_DELAYS = true;
|
||||
|
||||
import { storybookThemeOptions } from "embedding-sdk/test/storybook-themes";
|
||||
import { availableLocales } from "./constants";
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
@@ -42,15 +41,4 @@ export const globalTypes: GlobalTypes = {
|
||||
dynamicTitle: true,
|
||||
},
|
||||
},
|
||||
locale: {
|
||||
name: "Locale",
|
||||
description: "Locale to be passed to the MetabaseProvider",
|
||||
defaultValue: undefined,
|
||||
toolbar: {
|
||||
icon: "globe",
|
||||
items: availableLocales,
|
||||
showName: true,
|
||||
dynamicTitle: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
2
deps.edn
2
deps.edn
@@ -247,7 +247,7 @@
|
||||
{:mvn/version "1.6.1"} ; Enables local profiling and heat map generation
|
||||
com.clojure-goes-fast/clj-memory-meter
|
||||
{:mvn/version "0.4.0"} ; Enables easy memory measurement
|
||||
com.gfredericks/test.chuck {:mvn/version "0.2.15"} ; generating strings from regexes (useful with malli)
|
||||
com.gfredericks/test.chuck {:mvn/version "0.2.14"} ; generating strings from regexes (useful with malli)
|
||||
criterium/criterium {:mvn/version "0.4.6"} ; benchmarking library
|
||||
dev.weavejester/hashp {:mvn/version "0.4.0"} ; debugging/spying utility
|
||||
djblue/portal {:mvn/version "0.59.0"} ; ui for inspecting values
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
;; - [Drivers](#metabase.driver)
|
||||
;; - [Permissions](#metabase.models.permissions)
|
||||
;; - [The Query Processor](#metabase.query-processor)
|
||||
;; - [Application Settings](#metabase.settings.models.setting)
|
||||
;; - [Application Settings](#metabase.models.setting)
|
||||
;;
|
||||
;; ## Important Libraries
|
||||
;;
|
||||
@@ -72,11 +72,11 @@
|
||||
[metabase.driver :as driver]
|
||||
[metabase.driver.sql-jdbc.connection :as sql-jdbc.conn]
|
||||
[metabase.driver.sql-jdbc.execute :as sql-jdbc.execute]
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.query-processor.compile :as qp.compile]
|
||||
[metabase.query-processor.timezone :as qp.timezone]
|
||||
[metabase.server.handler :as handler]
|
||||
[metabase.server.instance :as server]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.sync.core :as sync]
|
||||
[metabase.test :as mt]
|
||||
[metabase.test-runner]
|
||||
|
||||
@@ -220,19 +220,15 @@
|
||||
static-deps (ns.parse/deps-from-ns-decl decl)
|
||||
dynamic-deps (for [symb (find-dynamically-loaded-namespaces file)]
|
||||
(vary-meta symb assoc ::dynamic :require-and-friends))
|
||||
;;
|
||||
;; excluded from the diff for now, see https://metaboat.slack.com/archives/C0669P4AF9N/p1745875106092029 for
|
||||
;; rationale.
|
||||
;;
|
||||
;; defenterprise-deps (for [symb (find-defenterprises file)]
|
||||
;; (vary-meta symb assoc ::dynamic :defenterprise))
|
||||
;; defenterprise-schema-deps (for [symb (find-defenterprise-schemas file)]
|
||||
;; (vary-meta symb assoc ::dynamic :defenterprise-schema))
|
||||
defenterprise-deps (for [symb (find-defenterprises file)]
|
||||
(vary-meta symb assoc ::dynamic :defenterprise))
|
||||
defenterprise-schema-deps (for [symb (find-defenterprise-schemas file)]
|
||||
(vary-meta symb assoc ::dynamic :defenterprise-schema))
|
||||
deps (into (sorted-set) cat
|
||||
[static-deps
|
||||
dynamic-deps
|
||||
#_defenterprise-deps
|
||||
#_defenterprise-schema-deps])]
|
||||
defenterprise-deps
|
||||
defenterprise-schema-deps])]
|
||||
{:namespace ns-symb
|
||||
:module (module ns-symb)
|
||||
:deps (sort-by pr-str
|
||||
|
||||
@@ -8,18 +8,12 @@ title: Driver interface changelog
|
||||
|
||||
- Added a feature `:expression-literals` for drivers that support expressions consisting of a single string, number, or boolean literal value.
|
||||
|
||||
- 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 a new abstract driver mix-in `:metabase.driver.sql.query-processor.boolean-is-comparison/boolean-is-comparison` that can be inherited by drivers that require boolean literal constants to be converted to comparison expressions in the top level of WHERE, AND, OR, NOT, and CASE clauses.
|
||||
|
||||
- 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.
|
||||
|
||||
- Added a feature `:expressions/float` for drivers that support casting text to floats.
|
||||
|
||||
- Added the multi-method `integer-dbtype` that allows the driver to control which type integers are cast to.
|
||||
|
||||
## Metabase 0.54.0
|
||||
|
||||
- Added the multi-method `allowed-promotions` that allows driver control over which column type promotions are supported for uploads.
|
||||
|
||||
@@ -189,8 +189,6 @@ In order to run the tests locally, see [sdk docs about e2e](https://github.com/m
|
||||
|
||||
In order to check compatibility between Sample Apps and Embedding SDK, we have a special test suite for each sample app that pulls this Sample App, starts it and runs its Cypress tests against the local `metabase.jar` and local `@metabase/embedding-sdk-react` package.
|
||||
|
||||
#### Local runs
|
||||
|
||||
To run these tests locally, run:
|
||||
```
|
||||
ENTERPRISE_TOKEN=<token> TEST_SUITE=<sample_app_repo_name>-e2e OPEN_UI=false EMBEDDING_SDK_VERSION=local START_METABASE=false GENERATE_SNAPSHOTS=false START_CONTAINERS=false yarn test-cypress
|
||||
@@ -201,16 +199,6 @@ For example for the `metabase-nodejs-react-sdk-embedding-sample`, run:
|
||||
ENTERPRISE_TOKEN=<token> TEST_SUITE=metabase-nodejs-react-sdk-embedding-sample-e2e OPEN_UI=false EMBEDDING_SDK_VERSION=local START_METABASE=false GENERATE_SNAPSHOTS=false START_CONTAINERS=false yarn test-cypress
|
||||
```
|
||||
|
||||
##### :warning: Obtaining the Shoppy's Metabase App DB Dump locally
|
||||
For the Shoppy's Sample App Tests (`TEST_SUITE=shoppy-e2e`) locally, a proper App DB dump of the Shoppy's Metabase Instance must be placed to the `./e2e/tmp/db_dumps/shoppy_metabase_app_db_dump.sql`
|
||||
|
||||
You can get it by:
|
||||
- Enabling the `Tailscale` and logging in using your work email address.
|
||||
- Running `pg_dump "postgres://{{ username }}:{{ password }}@{{ host }}:{{ port }}/{{ database }}" > ./e2e/tmp/db_dumps/shoppy_metabase_app_db_dump.sql` command.
|
||||
- See the `Shoppy Coredev Appdb` record in `1password` for credentials.
|
||||
|
||||
#### CI runs
|
||||
|
||||
On our CI, test failures do not block the merging of a pull request (PR). However, if a test fails, it’s most likely due to one of the following reasons:
|
||||
|
||||
- **Build Failure**:
|
||||
|
||||
@@ -109,7 +109,7 @@ You can add events to collections, and organize those events into timelines. See
|
||||
|
||||
## Uploading data
|
||||
|
||||
You can upload data to collections. See [Uploading data](./uploads.md).
|
||||
You can upload data to collections. See [Uploading data](./uploads.md)]
|
||||
|
||||
## Further reading
|
||||
|
||||
|
||||
@@ -123,9 +123,12 @@ To view your conditional counts by plan, set the **Group by** column to "Plan".
|
||||
|
||||
## Related functions
|
||||
|
||||
Different ways to do the same thing, because it's fun to try new things.
|
||||
|
||||
**Metabase**
|
||||
|
||||
- [Conditional running counts](#conditional-running-counts)
|
||||
- [case](#case)
|
||||
- [CumulativeCount](#cumulativecount)
|
||||
|
||||
**Other tools**
|
||||
|
||||
@@ -133,10 +136,43 @@ To view your conditional counts by plan, set the **Group by** column to "Plan".
|
||||
- [Spreadsheets](#spreadsheets)
|
||||
- [Python](#python)
|
||||
|
||||
### case
|
||||
|
||||
### Conditional running counts
|
||||
You can combine [`Count`](../expressions-list.md#count) with [`case`](./case.md):
|
||||
|
||||
`CountIf` doesn't do running counts, and [CumulativeCount](../expressions/cumulative) doesn't accept conditions (or any other arguments) . To do conditional running counts, you'll need to be creative: combine [CumulativeSum](../expressions/cumulative) (not `CumulativeCount`! ) with [`case`](./case.md). The idea is to use `case` to return `1` when a condition is satisfied and `0` when it isn't, then compute the running sum of all the 1's.
|
||||
```
|
||||
Count(case([Plan] = "Basic", [ID]))
|
||||
```
|
||||
|
||||
to do the same thing as `CountIf`:
|
||||
|
||||
```
|
||||
CountIf([Plan] = "Basic")
|
||||
```
|
||||
|
||||
The `case` version lets you count a different column when the condition isn't met. For example, if you've got data from different sources:
|
||||
|
||||
| ID: Source A | Plan: Source A | ID: Source B | Plan: Source B |
|
||||
| ------------ | -------------- | ------------ | -------------- |
|
||||
| 1 | Basic | | |
|
||||
| | | B | basic |
|
||||
| | | C | basic |
|
||||
| 4 | Business | D | business |
|
||||
| 5 | Premium | E | premium |
|
||||
|
||||
To count the total number of Basic plans across both sources, you could create a `case` expression to:
|
||||
|
||||
- Count the rows in "ID: Source A" where "Plan: Source A = "Basic"
|
||||
- Count the rows in "ID: Source B" where "Plan: Source B = "basic"
|
||||
|
||||
```
|
||||
Count(case([Plan: Source A] = "Basic", [ID: Source A],
|
||||
case([Plan: Source B] = "basic", [ID: Source B])))
|
||||
```
|
||||
|
||||
### CumulativeCount
|
||||
|
||||
`CountIf` doesn't do running counts. You'll need to combine [CumulativeCount](../expressions-list.md#cumulativecount) with [`case`](./case.md).
|
||||
|
||||
If our sample data is a time series:
|
||||
|
||||
@@ -158,7 +194,7 @@ And we want to get the running count of active plans like this:
|
||||
Create an aggregation from **Summarize** > **Custom expression**:
|
||||
|
||||
```
|
||||
CumulativeSum(case([Active Subscription] = true, 1,0))
|
||||
CumulativeCount(case([Active Subscription] = true, [ID]))
|
||||
```
|
||||
|
||||
You'll also need to set the **Group by** column to "Created Date: Month".
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import path from "path";
|
||||
|
||||
export const E2E_TMP_FOLDER_PATH = path.resolve(__dirname, "../../../tmp");
|
||||
@@ -1,7 +1,10 @@
|
||||
import fs from "fs";
|
||||
|
||||
import path from "path";
|
||||
|
||||
import { shell } from "../../cypress-runner-utils";
|
||||
import { E2E_TMP_FOLDER_PATH } from "../constants/e2e-tmp-folder-path";
|
||||
|
||||
const E2E_TMP_FOLDER_PATH = path.resolve(__dirname, "../../../tmp");
|
||||
|
||||
export function fetchApp({
|
||||
appName,
|
||||
|
||||
@@ -3,7 +3,6 @@ import fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
const ROOT_FOLDER_PATH = path.resolve(__dirname, "../../../..");
|
||||
import { E2E_TMP_FOLDER_PATH } from "../constants/e2e-tmp-folder-path";
|
||||
|
||||
const METABASE_JAR_DIST_PATH = path.join(ROOT_FOLDER_PATH, "target/uberjar");
|
||||
|
||||
@@ -30,31 +29,17 @@ export function copyExampleEnvFile({
|
||||
}
|
||||
|
||||
export function copyLocalMetabaseJar(rootPath: string) {
|
||||
const destinationPath = path.join(rootPath, LOCAL_DIST_PATH);
|
||||
const metabaseJarToPath = path.join(rootPath, LOCAL_DIST_PATH);
|
||||
|
||||
fs.cpSync(METABASE_JAR_DIST_PATH, destinationPath, { recursive: true });
|
||||
fs.cpSync(METABASE_JAR_DIST_PATH, metabaseJarToPath, { recursive: true });
|
||||
}
|
||||
|
||||
export function copyLocalEmbeddingSdkPackage(rootPath: string) {
|
||||
const destinationPath = path.join(rootPath, LOCAL_DIST_PATH, "embedding-sdk");
|
||||
|
||||
fs.cpSync(EMBEDDING_SDK_DIST_PATH, destinationPath, { recursive: true });
|
||||
}
|
||||
|
||||
// See `docs/developers-guide/e2e-tests.md` for more info
|
||||
export function copyShoppyMetabaseAppDBDump(rootPath: string) {
|
||||
const sourcePath = path.join(
|
||||
E2E_TMP_FOLDER_PATH,
|
||||
"db_dumps/shoppy_metabase_app_db_dump.sql",
|
||||
);
|
||||
|
||||
// The dump must be copied to the Shoppy's `local-dist` directory.
|
||||
// After that it will be used by the Shoppy's Docker container when it is built and started.
|
||||
const destinationPath = path.join(
|
||||
const embeddingSdkToPath = path.join(
|
||||
rootPath,
|
||||
LOCAL_DIST_PATH,
|
||||
"metabase_dump.sql",
|
||||
"embedding-sdk",
|
||||
);
|
||||
|
||||
fs.cpSync(sourcePath, destinationPath);
|
||||
fs.cpSync(EMBEDDING_SDK_DIST_PATH, embeddingSdkToPath, { recursive: true });
|
||||
}
|
||||
|
||||
@@ -2,10 +2,4 @@ import type { SampleAppTestSuiteName } from "../sample-apps-shared/types";
|
||||
|
||||
import { startSampleAppContainers } from "./startSampleAppContainers";
|
||||
|
||||
const testSuite = process.argv?.[2]?.trim() as SampleAppTestSuiteName;
|
||||
|
||||
if (!testSuite) {
|
||||
throw new Error("Test suite parameter is required");
|
||||
}
|
||||
|
||||
startSampleAppContainers(testSuite);
|
||||
startSampleAppContainers(process.env.TEST_SUITE as SampleAppTestSuiteName);
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
copyExampleEnvFile,
|
||||
copyLocalEmbeddingSdkPackage,
|
||||
copyLocalMetabaseJar,
|
||||
copyShoppyMetabaseAppDBDump,
|
||||
} from "../sample-apps-shared/helpers/prepare-app";
|
||||
import { setupAppCleanup } from "../sample-apps-shared/helpers/setup-app-cleanup";
|
||||
import { startContainers } from "../sample-apps-shared/helpers/start-containers";
|
||||
@@ -60,10 +59,6 @@ export async function startSampleAppContainers(
|
||||
copyLocalEmbeddingSdkPackage(rootPath);
|
||||
}
|
||||
|
||||
if (testSuite === "shoppy-e2e") {
|
||||
copyShoppyMetabaseAppDBDump(rootPath);
|
||||
}
|
||||
|
||||
await startContainers({
|
||||
cwd: rootPath,
|
||||
env,
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { CollectionBrowser } from "@metabase/embedding-sdk-react";
|
||||
|
||||
import { signInAsAdminAndEnableEmbeddingSdk } from "e2e/support/helpers/component-testing-sdk";
|
||||
import {
|
||||
mockAuthProviderAndJwtSignIn,
|
||||
mountSdkContent,
|
||||
} from "e2e/support/helpers/component-testing-sdk/component-embedding-sdk-helpers";
|
||||
|
||||
describe("scenarios > embedding-sdk > requests", () => {
|
||||
describe("cache preflight requests", () => {
|
||||
beforeEach(() => {
|
||||
signInAsAdminAndEnableEmbeddingSdk();
|
||||
cy.signOut();
|
||||
mockAuthProviderAndJwtSignIn();
|
||||
});
|
||||
|
||||
it("caches preflight requests by setting Access-Control-Max-Age header", () => {
|
||||
cy.intercept("GET", "/api/user/current").as("getCurrentUser");
|
||||
|
||||
mountSdkContent(<CollectionBrowser />);
|
||||
|
||||
cy.wait("@getCurrentUser").then(({ response }) => {
|
||||
const maxAgeHeader = response?.headers["access-control-max-age"];
|
||||
|
||||
expect(maxAgeHeader).to.equal("60");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -75,27 +75,6 @@ const INTEGER_TEST_CASES: CastTestCase[] = [
|
||||
filterValue: "29",
|
||||
expectedRowCount: 1,
|
||||
},
|
||||
{
|
||||
name: "FloatLiteral",
|
||||
expression: "integer(10.4)",
|
||||
filterOperator: "Equal to",
|
||||
filterValue: "10",
|
||||
expectedRowCount: 200,
|
||||
},
|
||||
{
|
||||
name: "FloatColumn",
|
||||
expression: "integer([Price])",
|
||||
filterOperator: "Equal to",
|
||||
filterValue: "29",
|
||||
expectedRowCount: 4,
|
||||
},
|
||||
{
|
||||
name: "FloatExpression",
|
||||
expression: "integer(42.333 + 0.56)",
|
||||
filterOperator: "Equal to",
|
||||
filterValue: "43",
|
||||
expectedRowCount: 200,
|
||||
},
|
||||
];
|
||||
|
||||
const DATE_TEST_CASES: CastTestCase[] = [
|
||||
|
||||
@@ -682,8 +682,10 @@ describe("issue 25990", () => {
|
||||
cy.findByText("People").click();
|
||||
cy.findByText("ID").click();
|
||||
cy.findByPlaceholderText("Enter an ID").type("10").blur();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
|
||||
cy.findByTestId("qb-filters-panel")
|
||||
@@ -1206,8 +1208,9 @@ describe("issue 45252", { tags: "@external" }, () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Binary").click();
|
||||
cy.findByLabelText("Is empty").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
H.assertQueryBuilderRowCount(0);
|
||||
|
||||
@@ -1223,8 +1226,9 @@ describe("issue 45252", { tags: "@external" }, () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Jsonb").click();
|
||||
cy.findByLabelText("Not empty").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
H.assertQueryBuilderRowCount(2);
|
||||
});
|
||||
|
||||
@@ -94,9 +94,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Quantity").click();
|
||||
cy.findByText("20").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("Quantity is equal to 20")
|
||||
@@ -124,9 +124,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
cy.findByText("Summaries").click();
|
||||
cy.findByText("Count").click();
|
||||
cy.findByPlaceholderText("Min").type("500");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("Count is greater than or equal to 500")
|
||||
.should("be.visible");
|
||||
@@ -140,9 +140,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
cy.findByText("Product").click();
|
||||
cy.findByText("Category").click();
|
||||
cy.findByText("Gadget").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("Product → Category is Gadget")
|
||||
.should("be.visible");
|
||||
@@ -184,7 +184,6 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
|
||||
it("should be able to add and remove filters for all query stages", () => {
|
||||
H.visitQuestionAdhoc(multiStageQuestionDetails);
|
||||
cy.get("@dataset.all").should("have.length", 1);
|
||||
|
||||
cy.log("add filters for all stages in the filter modal");
|
||||
cy.log("stage 0");
|
||||
@@ -192,37 +191,33 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Category").click();
|
||||
cy.findByText("Gadget").click();
|
||||
cy.button("Add another filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.get("@dataset.all").should("have.length", 1);
|
||||
|
||||
cy.log("stage 1");
|
||||
H.filter();
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Summaries").click();
|
||||
cy.findByText("Category").click();
|
||||
cy.findByText("Widget").click();
|
||||
cy.button("Add another filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.get("@dataset.all").should("have.length", 1);
|
||||
|
||||
cy.log("stage 2");
|
||||
H.filter();
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Summaries (2)").click();
|
||||
cy.findByText("Category").click();
|
||||
cy.findByText("Gizmo").click();
|
||||
cy.button("Add another filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.get("@dataset.all").should("have.length", 1);
|
||||
|
||||
cy.log("stage 3");
|
||||
H.filter();
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Summaries (3)").click();
|
||||
cy.findByText("Category").click();
|
||||
cy.findByText("Doohickey").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
cy.get("@dataset.all").should("have.length", 2);
|
||||
applyFilters();
|
||||
|
||||
cy.log("check filters from all stages to be present in the filter panel");
|
||||
H.queryBuilderFiltersPanel().within(() => {
|
||||
@@ -300,7 +295,7 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
});
|
||||
|
||||
H.popover().findByText(SEGMENT_2_NAME).click();
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText(SEGMENT_2_NAME)
|
||||
.should("be.visible");
|
||||
@@ -348,9 +343,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("boolean").click();
|
||||
cy.findByText("True").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.assertQueryBuilderRowCount(2);
|
||||
});
|
||||
|
||||
@@ -358,9 +353,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("boolean").click();
|
||||
cy.findByText("True").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.assertQueryBuilderRowCount(2);
|
||||
|
||||
H.queryBuilderFiltersPanel().findByText("boolean is true").click();
|
||||
@@ -376,9 +371,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("boolean").click();
|
||||
cy.findByText("True").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.assertQueryBuilderRowCount(2);
|
||||
|
||||
H.queryBuilderFiltersPanel()
|
||||
@@ -401,7 +396,7 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
cy.findByText("Created At").click();
|
||||
cy.findByText("Today").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("Created At is today")
|
||||
@@ -413,7 +408,7 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
cy.findByText("Created At").click();
|
||||
cy.findByText("Previous 3 months").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("Created At is in the previous 3 months")
|
||||
.should("be.visible");
|
||||
@@ -430,9 +425,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Source").click();
|
||||
cy.findByText("Affiliate").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("Source is Affiliate")
|
||||
.should("be.visible");
|
||||
@@ -443,9 +438,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("State").click();
|
||||
cy.findByText("AZ").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("State is AZ")
|
||||
.should("be.visible");
|
||||
@@ -463,9 +458,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("ID").click();
|
||||
cy.findByLabelText("Filter value").type("17,18");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.assertQueryBuilderRowCount(2);
|
||||
H.tableInteractive().within(() => {
|
||||
cy.findByText("131.68").should("be.visible"); // total for order id 17
|
||||
@@ -477,9 +472,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Product ID").click();
|
||||
cy.findByLabelText("Filter value").type("65");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.assertQueryBuilderRowCount(107);
|
||||
});
|
||||
});
|
||||
@@ -495,9 +490,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.selectFilterOperator("Contains");
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("Indian");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.assertQueryBuilderRowCount(5);
|
||||
});
|
||||
|
||||
@@ -506,9 +501,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.selectFilterOperator("Ends with");
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("Valley");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.assertQueryBuilderRowCount(8);
|
||||
});
|
||||
|
||||
@@ -518,9 +513,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
cy.findByLabelText("Filter value")
|
||||
.type("Indiantown,Indian Valley")
|
||||
.blur();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("City is 2 selections")
|
||||
.should("be.visible");
|
||||
@@ -539,9 +534,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
cy.findByText("Price").click();
|
||||
cy.findByPlaceholderText("Min").type("50");
|
||||
cy.findByPlaceholderText("Max").type("80");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("Price is between 50 and 80")
|
||||
.should("be.visible");
|
||||
@@ -553,9 +548,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.selectFilterOperator("Greater than");
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("50");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("Price is greater than 50")
|
||||
.should("be.visible");
|
||||
@@ -566,9 +561,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Price").click();
|
||||
cy.findByPlaceholderText("Max").type("50");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("Price is less than or equal to 50")
|
||||
.should("be.visible");
|
||||
@@ -602,9 +597,9 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
H.selectFilterOperator("Greater than");
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("90");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
cy.wait("@dataset");
|
||||
applyFilters();
|
||||
H.queryBuilderFiltersPanel()
|
||||
.findByText("Price is greater than 90")
|
||||
.should("be.visible");
|
||||
@@ -612,3 +607,8 @@ describe("scenarios > filters > bulk filtering", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const applyFilters = () => {
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
};
|
||||
|
||||
@@ -106,8 +106,9 @@ describe("scenarios > question > filter", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Product ID").click();
|
||||
cy.findByText("Aerodynamic Linen Coat").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
|
||||
cy.log("Reported failing on v0.36.4 and v0.36.5.1");
|
||||
cy.findByTestId("loading-indicator").should("not.exist");
|
||||
@@ -737,8 +738,9 @@ describe("scenarios > question > filter", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Category").click();
|
||||
cy.findByText("Gizmo").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
H.openNotebook();
|
||||
|
||||
H.verifyNotebookQuery("Products", [
|
||||
|
||||
@@ -1330,8 +1330,9 @@ describe("issue 45300", () => {
|
||||
cy.findAllByText("Product").should("have.length", 2).first().click();
|
||||
cy.findByText("Category").click();
|
||||
cy.findByText("Doohickey").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
|
||||
cy.findByTestId("filter-pill").should(
|
||||
|
||||
@@ -74,8 +74,9 @@ describe("scenarios > metrics > question", () => {
|
||||
cy.findByText("Product").click();
|
||||
cy.findByText("Category").click();
|
||||
cy.findByText("Gadget").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.findByTestId("scalar-container")
|
||||
.findByText("4,939")
|
||||
.should("be.visible");
|
||||
|
||||
@@ -393,8 +393,9 @@ describe("scenarios > models metadata", () => {
|
||||
cy.findByText("User").click();
|
||||
cy.findByText("Source").click();
|
||||
cy.findByText("Twitter").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
cy.findByTestId("question-row-count")
|
||||
.invoke("text")
|
||||
|
||||
@@ -52,8 +52,9 @@ describe("scenarios > models", () => {
|
||||
H.selectFilterOperator("Contains");
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("Fisher");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
|
||||
assertQuestionIsBasedOnModel({
|
||||
@@ -102,8 +103,9 @@ describe("scenarios > models", () => {
|
||||
H.selectFilterOperator("Contains");
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("Fisher");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
|
||||
assertQuestionIsBasedOnModel({
|
||||
@@ -168,8 +170,9 @@ describe("scenarios > models", () => {
|
||||
H.selectFilterOperator("Greater than");
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("30");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset").then(({ response }) => {
|
||||
expect(response.body.error).to.not.exist;
|
||||
});
|
||||
@@ -351,8 +354,8 @@ describe("scenarios > models", () => {
|
||||
.and("contain.text", "Orders");
|
||||
|
||||
cy.findByText("Everywhere").click();
|
||||
getResults().should("have.length", 5);
|
||||
cy.findByText("5 results").should("be.visible");
|
||||
getResults().should("have.length", 6);
|
||||
cy.findByText("6 results").should("be.visible");
|
||||
getResults()
|
||||
.eq(0)
|
||||
.should("have.attr", "data-model-type", "dataset")
|
||||
@@ -371,6 +374,10 @@ describe("scenarios > models", () => {
|
||||
.and("contain.text", "Orders, Count");
|
||||
getResults()
|
||||
.eq(4)
|
||||
.should("have.attr", "data-model-type", "card")
|
||||
.and("contain.text", "Orders");
|
||||
getResults()
|
||||
.eq(5)
|
||||
.should("have.attr", "data-model-type", "table")
|
||||
.and("contain.text", "Orders");
|
||||
});
|
||||
@@ -458,7 +465,8 @@ describe("scenarios > models", () => {
|
||||
H.filter();
|
||||
H.popover().findByText("Discount").click();
|
||||
H.selectFilterOperator("Not empty");
|
||||
H.popover().button("Apply filter").click();
|
||||
H.popover().button("Add filter").click();
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
|
||||
assertQuestionIsBasedOnModel({
|
||||
|
||||
@@ -613,6 +613,7 @@ describe(
|
||||
cy.findByText("Created At").click();
|
||||
cy.findByText("Today").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
cy.get("[data-testid=cell-data]")
|
||||
.should("have.length", 4)
|
||||
@@ -955,8 +956,9 @@ describe("issue 28971", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Quantity").click();
|
||||
cy.findByText("20").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
|
||||
cy.findByText("Quantity is equal to 20").should("exist");
|
||||
@@ -995,8 +997,9 @@ describe("issue 28971", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Quantity").click();
|
||||
cy.findByText("20").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
|
||||
cy.findByText("Quantity is equal to 20").should("exist");
|
||||
@@ -2130,6 +2133,7 @@ describe("cumulative count - issue 33330", () => {
|
||||
cy.findByText("Created At").click();
|
||||
cy.findByText("Today").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
|
||||
H.queryBuilderHeader().findByLabelText("Show filters").click();
|
||||
|
||||
@@ -32,7 +32,12 @@ export function addWidgetStringFilter(
|
||||
}
|
||||
|
||||
export function setWidgetStringFilter(value) {
|
||||
popover().first().find("input").not("[type=hidden]").first().type(`${value}`);
|
||||
popover()
|
||||
.first()
|
||||
.find("input")
|
||||
.not("[type=hidden]")
|
||||
.first()
|
||||
.type(`${value}{enter}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,10 +166,10 @@ export function closeEntryForm() {
|
||||
*/
|
||||
function addBetweenFilter([low, high] = [], buttonLabel = "Add filter") {
|
||||
popover().within(() => {
|
||||
cy.get("input").first().type(`${low}`);
|
||||
cy.get("input").first().type(`${low}{enter}`);
|
||||
|
||||
// eslint-disable-next-line no-unsafe-element-filtering
|
||||
cy.get("input").last().type(`${high}`);
|
||||
cy.get("input").last().type(`${high}{enter}`);
|
||||
});
|
||||
|
||||
cy.button(buttonLabel).click();
|
||||
@@ -175,7 +180,7 @@ function addBetweenFilter([low, high] = [], buttonLabel = "Add filter") {
|
||||
* @param {string} value
|
||||
*/
|
||||
function addSimpleNumberFilter(value, buttonLabel = "Add filter") {
|
||||
cy.findByPlaceholderText("Enter a number").type(`${value}`);
|
||||
cy.findByPlaceholderText("Enter a number").type(`${value}{enter}`);
|
||||
cy.button(buttonLabel).click();
|
||||
}
|
||||
|
||||
@@ -185,7 +190,9 @@ function addSimpleNumberFilter(value, buttonLabel = "Add filter") {
|
||||
*/
|
||||
function enterDefaultValue(value, buttonLabel = "Add filter") {
|
||||
cy.findByText("Enter a default value…").click();
|
||||
cy.findByPlaceholderText("Enter a default value…").type(`${value}`).blur();
|
||||
cy.findByPlaceholderText("Enter a default value…")
|
||||
.type(`${value}{enter}`)
|
||||
.blur();
|
||||
cy.button(buttonLabel).click();
|
||||
}
|
||||
|
||||
|
||||
@@ -197,8 +197,9 @@ describe("scenarios > question > native", () => {
|
||||
H.selectFilterOperator(operator);
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("This has a value");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
|
||||
cy.log(
|
||||
`**Mid-point assertion for "${operator}" filter| FAILING in v0.36.6**`,
|
||||
|
||||
@@ -571,8 +571,9 @@ describe(
|
||||
H.popover().within(() => {
|
||||
cy.findAllByText("ID").should("have.length", 2).first().click();
|
||||
cy.findByLabelText("Filter value").type(id).click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
H.assertQueryBuilderRowCount(1);
|
||||
removeFilter();
|
||||
|
||||
@@ -2290,7 +2291,7 @@ describe("issue 48829", () => {
|
||||
H.modal().should("not.exist");
|
||||
});
|
||||
|
||||
it("should not show the unsaved changes warning when switching back to chill mode from the notebook editor after adding a filter via the filter picker (metabase#48829)", () => {
|
||||
it("should not show the unsaved changes warning when switching back to chill mode from the notebook editor after adding a filter via the filter modal (metabase#48829)", () => {
|
||||
H.createQuestion(questionDetails, { visitQuestion: true });
|
||||
|
||||
H.queryBuilderHeader()
|
||||
@@ -2299,8 +2300,9 @@ describe("issue 48829", () => {
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Category").click();
|
||||
cy.findByText("Doohickey").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
|
||||
H.queryBuilderHeader()
|
||||
.button(/Editor/)
|
||||
|
||||
@@ -1164,7 +1164,7 @@ describe("scenarios > question > multiple column breakouts", () => {
|
||||
cy.findByText("Between").click();
|
||||
cy.findByLabelText("Start date").clear().type(columnMinValue);
|
||||
cy.findByLabelText("End date").clear().type(columnMaxValue);
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1202,6 +1202,7 @@ describe("scenarios > question > multiple column breakouts", () => {
|
||||
});
|
||||
|
||||
cy.log("assert query results");
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
}
|
||||
|
||||
@@ -1224,7 +1225,7 @@ describe("scenarios > question > multiple column breakouts", () => {
|
||||
cy.findByPlaceholderText("Max")
|
||||
.clear()
|
||||
.type(String(columnMaxValue));
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1262,6 +1263,7 @@ describe("scenarios > question > multiple column breakouts", () => {
|
||||
});
|
||||
|
||||
cy.log("assert query results");
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
}
|
||||
|
||||
|
||||
@@ -482,8 +482,9 @@ describe("scenarios > question > nested", () => {
|
||||
H.selectFilterOperator("Equal to");
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("4");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
|
||||
cy.findAllByTestId("cell-data")
|
||||
.should("contain", "Murray, Watsica and Wunsch")
|
||||
@@ -523,8 +524,9 @@ describe("scenarios > question > nested", () => {
|
||||
H.selectFilterOperator("Equal to");
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("5");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.wait("@dataset");
|
||||
|
||||
H.queryBuilderFiltersPanel().findByText("Count is equal to 5");
|
||||
|
||||
@@ -146,12 +146,8 @@ describe("scenarios > alert", () => {
|
||||
const allowedDomain = "metabase.test";
|
||||
const deniedDomain = "metabase.example";
|
||||
const deniedEmail = `mailer@${deniedDomain}`;
|
||||
const subscriptionError =
|
||||
"You're only allowed to email subscriptions to allowed domains";
|
||||
const alertError =
|
||||
"You're only allowed to email alerts to allowed domains";
|
||||
const adminSubscriptionError = `You're only allowed to email subscriptions to addresses ending in ${allowedDomain}`;
|
||||
const adminAlertError = `You're only allowed to email alerts to addresses ending in ${allowedDomain}`;
|
||||
const subscriptionError = `You're only allowed to email subscriptions to addresses ending in ${allowedDomain}`;
|
||||
const alertError = `You're only allowed to email alerts to addresses ending in ${allowedDomain}`;
|
||||
|
||||
function addEmailRecipient(email) {
|
||||
cy.findByRole("textbox").click().type(`${email}`).blur();
|
||||
@@ -181,7 +177,7 @@ describe("scenarios > alert", () => {
|
||||
addEmailRecipient(deniedEmail);
|
||||
});
|
||||
|
||||
cy.findByText(adminAlertError);
|
||||
cy.findByText(alertError);
|
||||
cy.button("Done").should("be.disabled");
|
||||
});
|
||||
});
|
||||
@@ -195,34 +191,6 @@ describe("scenarios > alert", () => {
|
||||
addEmailRecipient(deniedEmail);
|
||||
|
||||
// Reproduces metabase#17977
|
||||
cy.button("Send email now").should("be.disabled");
|
||||
cy.button("Done").should("be.disabled");
|
||||
cy.findByText(adminSubscriptionError);
|
||||
});
|
||||
});
|
||||
|
||||
it("should not display the list of approved domains for non-admins (metabase#57138)", () => {
|
||||
cy.signInAsNormalUser();
|
||||
H.visitQuestion(ORDERS_QUESTION_ID);
|
||||
|
||||
H.openSharingMenu("Create an alert");
|
||||
H.modal().within(() => {
|
||||
cy.findByText("New alert").should("be.visible");
|
||||
|
||||
cy.findByTestId("token-field").within(() => {
|
||||
addEmailRecipient(deniedEmail);
|
||||
});
|
||||
|
||||
cy.findByText(alertError);
|
||||
cy.button("Done").should("be.disabled");
|
||||
});
|
||||
|
||||
H.visitDashboard(ORDERS_DASHBOARD_ID);
|
||||
H.openSharingMenu("Subscriptions");
|
||||
|
||||
H.sidebar().within(() => {
|
||||
addEmailRecipient(deniedEmail);
|
||||
|
||||
cy.button("Send email now").should("be.disabled");
|
||||
cy.button("Done").should("be.disabled");
|
||||
cy.findByText(subscriptionError);
|
||||
|
||||
@@ -172,105 +172,6 @@ describe("scenarios > question > download", () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe("download format preference", { tags: "@flaky" }, () => {
|
||||
it("should remember the selected format across page reloads", () => {
|
||||
cy.intercept(
|
||||
"PUT",
|
||||
"/api/user-key-value/namespace/last_download_format/key/download_format_preference",
|
||||
).as("saveFormat");
|
||||
|
||||
H.createQuestion(
|
||||
{
|
||||
name: "Format Preference Test",
|
||||
query: {
|
||||
"source-table": ORDERS_ID,
|
||||
limit: 5,
|
||||
},
|
||||
display: "table",
|
||||
},
|
||||
{ visitQuestion: true },
|
||||
);
|
||||
|
||||
cy.findByRole("button", { name: "Download results" }).click();
|
||||
H.popover().within(() => {
|
||||
cy.findByText(".xlsx")
|
||||
.should("be.visible")
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.wait("@saveFormat");
|
||||
});
|
||||
});
|
||||
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/user-key-value/namespace/last_download_format/key/download_format_preference",
|
||||
).as("fetchFormat");
|
||||
|
||||
cy.reload();
|
||||
cy.wait("@fetchFormat");
|
||||
cy.findByRole("button", { name: "Download results" }).click();
|
||||
H.popover().within(() => {
|
||||
cy.get("[data-checked='true']").should("contain", ".xlsx");
|
||||
});
|
||||
});
|
||||
|
||||
it("should remember the download format on dashboards", () => {
|
||||
cy.intercept(
|
||||
"PUT",
|
||||
"/api/user-key-value/namespace/last_download_format/key/download_format_preference",
|
||||
).as("saveFormat");
|
||||
|
||||
H.createQuestion({
|
||||
name: "Dashboard Format Test",
|
||||
query: {
|
||||
"source-table": ORDERS_ID,
|
||||
limit: 5,
|
||||
},
|
||||
display: "table",
|
||||
}).then(({ body: { id: questionId } }) => {
|
||||
H.createDashboard().then(({ body: { id: dashboardId } }) => {
|
||||
H.addOrUpdateDashboardCard({
|
||||
card_id: questionId,
|
||||
dashboard_id: dashboardId,
|
||||
});
|
||||
|
||||
H.visitDashboard(dashboardId);
|
||||
|
||||
H.getDashboardCard(0).realHover();
|
||||
H.getDashboardCardMenu(0).click();
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Download results").click();
|
||||
});
|
||||
H.popover().within(() => {
|
||||
cy.findByText(".xlsx")
|
||||
.should("be.visible")
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.wait("@saveFormat");
|
||||
});
|
||||
});
|
||||
|
||||
cy.intercept(
|
||||
"GET",
|
||||
"/api/user-key-value/namespace/last_download_format/key/download_format_preference",
|
||||
).as("fetchFormat");
|
||||
|
||||
cy.reload();
|
||||
cy.wait("@fetchFormat");
|
||||
|
||||
H.getDashboardCard(0).realHover();
|
||||
H.getDashboardCardMenu(0).click();
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Download results").click();
|
||||
});
|
||||
H.popover().within(() => {
|
||||
cy.get("[data-checked='true']").should("contain", ".xlsx");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("respects renamed columns in self-joins", () => {
|
||||
const idLeftRef = [
|
||||
"field",
|
||||
|
||||
@@ -188,8 +188,9 @@ describe("scenarios > visualizations > bar chart", () => {
|
||||
H.selectFilterOperator("Is not");
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Gadget").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
H.getDraggableElements().should("have.length", 2);
|
||||
H.getDraggableElements().eq(0).should("have.text", "Doohickey");
|
||||
H.getDraggableElements().eq(1).should("have.text", "Widget");
|
||||
|
||||
@@ -79,8 +79,9 @@ describe("scenarios > visualizations > funnel chart", () => {
|
||||
H.selectFilterOperator("Is not");
|
||||
H.popover().within(() => {
|
||||
cy.findByText("Facebook").click();
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
|
||||
H.getDraggableElements().should("have.length", 4);
|
||||
|
||||
|
||||
@@ -185,8 +185,9 @@ describe("issue 17524", () => {
|
||||
H.selectFilterOperator("Greater than");
|
||||
H.popover().within(() => {
|
||||
cy.findByLabelText("Filter value").type("1");
|
||||
cy.button("Apply filter").click();
|
||||
cy.button("Add filter").click();
|
||||
});
|
||||
H.runButtonOverlay().click();
|
||||
cy.get("polygon");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -334,74 +334,3 @@ where x < {{param}}`,
|
||||
H.chartPathWithFillColor("#88BF4D").should("have.length", 4);
|
||||
});
|
||||
});
|
||||
|
||||
describe("issue 47757", () => {
|
||||
beforeEach(() => {
|
||||
H.restore();
|
||||
cy.signInAsNormalUser();
|
||||
});
|
||||
|
||||
it("should show correct tooltips for interpolated data points (metabase#47757)", () => {
|
||||
H.visitQuestionAdhoc({
|
||||
visualization_settings: {
|
||||
"graph.dimensions": ["X"],
|
||||
"graph.metrics": ["Y"],
|
||||
series_settings: { Y: { "line.missing": "zero" } },
|
||||
},
|
||||
dataset_query: {
|
||||
type: "native",
|
||||
native: {
|
||||
query: `select '2020-01-01' x, 10 y
|
||||
union all select '2020-03-01' x, 30 y
|
||||
union all select '2020-04-01' x, 40 y`,
|
||||
},
|
||||
database: SAMPLE_DB_ID,
|
||||
},
|
||||
display: "line",
|
||||
});
|
||||
|
||||
H.cartesianChartCircleWithColor("#88BF4D").eq(0).trigger("mousemove");
|
||||
H.assertEChartsTooltip({
|
||||
header: "January 2020",
|
||||
rows: [
|
||||
{
|
||||
color: "#88BF4D",
|
||||
name: "Y",
|
||||
value: 10,
|
||||
},
|
||||
],
|
||||
footer: null,
|
||||
blurAfter: true,
|
||||
});
|
||||
|
||||
H.cartesianChartCircleWithColor("#88BF4D").eq(1).trigger("mousemove");
|
||||
H.assertEChartsTooltip({
|
||||
header: "February 2020",
|
||||
rows: [
|
||||
{
|
||||
color: "#88BF4D",
|
||||
name: "Y",
|
||||
value: 0,
|
||||
secondaryValue: "-100%",
|
||||
},
|
||||
],
|
||||
footer: null,
|
||||
blurAfter: true,
|
||||
});
|
||||
|
||||
H.cartesianChartCircleWithColor("#88BF4D").eq(2).trigger("mousemove");
|
||||
H.assertEChartsTooltip({
|
||||
header: "March 2020",
|
||||
rows: [
|
||||
{
|
||||
color: "#88BF4D",
|
||||
name: "Y",
|
||||
value: 30,
|
||||
secondaryValue: "+∞%",
|
||||
},
|
||||
],
|
||||
footer: null,
|
||||
blurAfter: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,9 +47,7 @@ describe("issue 6010", () => {
|
||||
.then(({ body: { id } }) => createQuestion(id))
|
||||
.then(({ body: { id } }) => H.visitQuestion(id));
|
||||
|
||||
// Metric filters are transformed into aggregation case expression condition. The 21st point is first non filtered
|
||||
// point.
|
||||
H.cartesianChartCircle().eq(21).click();
|
||||
H.cartesianChartCircle().eq(0).click();
|
||||
|
||||
H.popover().findByText("See these Orders").click();
|
||||
cy.wait("@dataset");
|
||||
@@ -1352,117 +1350,3 @@ describe("issue 57132", () => {
|
||||
.should("be.visible");
|
||||
});
|
||||
});
|
||||
|
||||
describe("issue 52333", () => {
|
||||
const baseQuery = `
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT
|
||||
category,
|
||||
source,
|
||||
state,
|
||||
SUM(orders.discount) AS discount,
|
||||
SUM(orders.total) AS total,
|
||||
SUM(orders.quantity) AS quantity
|
||||
FROM
|
||||
orders
|
||||
LEFT JOIN products ON orders.product_id = products.id
|
||||
LEFT JOIN people ON orders.user_id = people.id
|
||||
GROUP BY category, source, state
|
||||
) AS filtered_orders
|
||||
WHERE NOT (
|
||||
category = 'Gizmo'
|
||||
AND (
|
||||
source IN ('Facebook', 'Google', 'Organic', 'Twitter')
|
||||
OR state NOT IN ('AK')
|
||||
)
|
||||
);`;
|
||||
|
||||
const baseQuestionDetails = {
|
||||
name: "52333",
|
||||
display: "table",
|
||||
native: {
|
||||
query: baseQuery,
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
H.restore();
|
||||
cy.signInAsAdmin();
|
||||
});
|
||||
|
||||
it("pivot table should show subtotals for a group of a single value (metabase#52333)", () => {
|
||||
H.createNativeQuestion(baseQuestionDetails, {
|
||||
visitQuestion: true,
|
||||
wrapId: true,
|
||||
});
|
||||
|
||||
cy.get("@questionId").then((id) => {
|
||||
const questionDetails = {
|
||||
query: {
|
||||
"source-table": `card__${id}`,
|
||||
aggregation: [["count"]],
|
||||
breakout: [
|
||||
[
|
||||
"field",
|
||||
"CATEGORY",
|
||||
{
|
||||
"base-type": "type/Text",
|
||||
},
|
||||
],
|
||||
[
|
||||
"field",
|
||||
"SOURCE",
|
||||
{
|
||||
"base-type": "type/Text",
|
||||
},
|
||||
],
|
||||
[
|
||||
"field",
|
||||
"STATE",
|
||||
{
|
||||
"base-type": "type/Text",
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
display: "pivot",
|
||||
visualization_settings: {
|
||||
"pivot_table.column_split": {
|
||||
rows: ["CATEGORY", "SOURCE", "STATE"],
|
||||
columns: [],
|
||||
values: ["count", "avg"],
|
||||
},
|
||||
"pivot_table.column_widths": {
|
||||
leftHeaderWidths: [104, 92, 80],
|
||||
totalLeftHeaderWidths: 276,
|
||||
valueHeaderWidths: {},
|
||||
},
|
||||
"pivot_table.collapsed_rows": {
|
||||
value: ['["Doohickey"]', '["Gadget"]', '["Widget"]'],
|
||||
rows: ["CATEGORY", "SOURCE", "STATE"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
H.createQuestion(questionDetails, { visitQuestion: true });
|
||||
});
|
||||
|
||||
H.queryBuilderMain().within(() => {
|
||||
cy.findByText("Affiliate");
|
||||
cy.findByText("AK");
|
||||
|
||||
// Ensure it does not show subtotals for the single value by default
|
||||
cy.findByText("Totals for Affiliate").should("not.exist");
|
||||
|
||||
H.openVizSettingsSidebar();
|
||||
});
|
||||
|
||||
H.sidebar().findByText("Condense duplicate totals").click();
|
||||
|
||||
// Ensure it shows subtotals for the single value
|
||||
H.queryBuilderMain()
|
||||
.findByText("Totals for Affiliate")
|
||||
.should("be.visible");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[medley.core :as m]
|
||||
[metabase-enterprise.advanced-config.file.interface :as advanced-config.file.i]
|
||||
[metabase.driver.util :as driver.u]
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.models.setting :refer [defsetting]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.quick-task :as quick-task]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[metabase-enterprise.advanced-config.file.interface :as advanced-config.file.i]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.log :as log]))
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
(ns metabase-enterprise.advanced-config.models.pulse-channel
|
||||
(:require
|
||||
[clojure.string :as str]
|
||||
[metabase.models.setting :refer [defsetting]]
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]))
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
[metabase-enterprise.serialization.cmd :as serialization.cmd]
|
||||
[metabase.audit :as audit]
|
||||
[metabase.db :as mdb]
|
||||
[metabase.models.setting :refer [defsetting]]
|
||||
[metabase.plugins :as plugins]
|
||||
[metabase.premium-features.core :refer [defenterprise]]
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.sync.util :as sync-util]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.files :as u.files]
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
(ns metabase-enterprise.cache.init
|
||||
(:require
|
||||
[metabase-enterprise.cache.task.refresh-cache-configs]))
|
||||
@@ -1,8 +1,8 @@
|
||||
(ns metabase-enterprise.cache.strategies
|
||||
(:require
|
||||
[java-time.api :as t]
|
||||
[metabase.cache.api]
|
||||
[metabase.cache.core :as cache]
|
||||
[metabase.api.cache]
|
||||
[metabase.models.cache-config :as cache-config]
|
||||
[metabase.premium-features.core :refer [defenterprise defenterprise-schema]]
|
||||
[metabase.query-processor.middleware.cache-backend.db :as backend.db]
|
||||
[metabase.util.log :as log]
|
||||
@@ -11,26 +11,26 @@
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(comment metabase.cache.api/keep-me)
|
||||
(comment metabase.api.cache/keep-me)
|
||||
|
||||
;; Data shape
|
||||
|
||||
(mr/def ::cache-strategy
|
||||
"Schema for a caching strategy used internally"
|
||||
[:and
|
||||
:metabase.cache.api/cache-strategy.base
|
||||
:metabase.api.cache/cache-strategy.base
|
||||
[:multi {:dispatch :type}
|
||||
[:nocache :metabase.cache.api/cache-strategy.nocache]
|
||||
[:nocache :metabase.api.cache/cache-strategy.nocache]
|
||||
[:ttl [:merge
|
||||
:metabase.cache.api/cache-strategy.ttl
|
||||
:metabase.api.cache/cache-strategy.ttl
|
||||
[:map
|
||||
[:invalidated-at {:optional true} some?]]]]
|
||||
[:duration [:merge
|
||||
:metabase.cache.api/cache-strategy.ee.duration
|
||||
:metabase.api.cache/cache-strategy.ee.duration
|
||||
[:map
|
||||
[:invalidated-at {:optional true} some?]]]]
|
||||
[:schedule [:merge
|
||||
:metabase.cache.api/cache-strategy.ee.schedule
|
||||
:metabase.api.cache/cache-strategy.ee.schedule
|
||||
[:map
|
||||
[:invalidated-at {:optional true} some?]]]]]])
|
||||
|
||||
@@ -56,30 +56,30 @@
|
||||
:order-by :ordering
|
||||
:limit [:inline 1]}
|
||||
item (t2/select-one :model/CacheConfig :id q)]
|
||||
(cache/card-strategy item card)))
|
||||
(cache-config/card-strategy item card)))
|
||||
|
||||
;;; Strategy execution
|
||||
|
||||
(defmulti ^:private fetch-cache-stmt-ee*
|
||||
"Generate prepared statement for a db cache backend for a given strategy"
|
||||
{:arglists '([strategy query-hash])}
|
||||
(fn [strategy _hash] (:type strategy)))
|
||||
{:arglists '([strategy query-hash conn])}
|
||||
(fn [strategy _hash _conn] (:type strategy)))
|
||||
|
||||
(defmethod fetch-cache-stmt-ee* :ttl [strategy query-hash]
|
||||
(backend.db/fetch-cache-stmt-ttl strategy query-hash))
|
||||
(defmethod fetch-cache-stmt-ee* :ttl [strategy query-hash conn]
|
||||
(backend.db/fetch-cache-stmt-ttl strategy query-hash conn))
|
||||
|
||||
(defmethod fetch-cache-stmt-ee* :duration [strategy query-hash]
|
||||
(defmethod fetch-cache-stmt-ee* :duration [strategy query-hash conn]
|
||||
(if-not (and (:duration strategy) (:unit strategy))
|
||||
(log/debugf "Caching strategy %s should have :duration and :unit" (pr-str strategy))
|
||||
(let [duration (t/duration (:duration strategy) (keyword (:unit strategy)))
|
||||
duration-ago (t/minus (t/offset-date-time) duration)
|
||||
invalidated-at (t/max duration-ago (:invalidated-at strategy))]
|
||||
(backend.db/select-cache query-hash invalidated-at))))
|
||||
(backend.db/prepare-statement conn query-hash invalidated-at))))
|
||||
|
||||
(defmethod fetch-cache-stmt-ee* :schedule [{:keys [invalidated-at] :as strategy} query-hash]
|
||||
(defmethod fetch-cache-stmt-ee* :schedule [{:keys [invalidated-at] :as strategy} query-hash conn]
|
||||
(if-not invalidated-at
|
||||
(log/debugf "Caching strategy %s has not run yet" (pr-str strategy))
|
||||
(backend.db/select-cache query-hash invalidated-at)))
|
||||
(backend.db/prepare-statement conn query-hash invalidated-at)))
|
||||
|
||||
(defmethod fetch-cache-stmt-ee* :nocache [_ _ _]
|
||||
nil)
|
||||
@@ -87,5 +87,5 @@
|
||||
(defenterprise fetch-cache-stmt
|
||||
"Returns prepared statement to query for db cache backend."
|
||||
:feature :cache-granular-controls
|
||||
[strategy query-hash]
|
||||
(fetch-cache-stmt-ee* strategy query-hash))
|
||||
[strategy query-hash conn]
|
||||
(fetch-cache-stmt-ee* strategy query-hash conn))
|
||||
|
||||
@@ -6,5 +6,4 @@
|
||||
|
||||
See https://metaboat.slack.com/archives/CKZEMT1MJ/p1736556522733279 for rationale behind this pattern."
|
||||
(:require
|
||||
[metabase-enterprise.cache.init]
|
||||
[metabase-enterprise.enhancements.init]))
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[metabase.api.macros :as api.macros]
|
||||
[metabase.api.routes.common :refer [+auth]]
|
||||
[metabase.events :as events]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]))
|
||||
@@ -94,7 +94,7 @@
|
||||
(api/check-404 db)
|
||||
(api/check-400 (not (:router_database_id db)) "Cannot make a destination database a router database")
|
||||
(api/check-400 (not (:uploads_enabled db)) "Cannot enable database routing for a database with uploads enabled")
|
||||
(setting/with-database-local-values (:settings db)
|
||||
(binding [setting/*database-local-values* (:settings db)]
|
||||
(api/check-400 (not (setting/get :persist-models-enabled)) "Cannot enable database routing for a database with model persistence enabled")
|
||||
(api/check-400 (not (setting/get :database-enable-actions)) "Cannot enable database routing for a database with actions enabled")))
|
||||
(if (nil? user_attribute)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns metabase-enterprise.enhancements.integrations.google
|
||||
(:require
|
||||
[metabase.settings.core :as setting :refer [define-multi-setting-impl]]))
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.models.setting.multi-setting :refer [define-multi-setting-impl]]))
|
||||
|
||||
(define-multi-setting-impl google-auth-auto-create-accounts-domain :ee
|
||||
:getter (fn [] (setting/get-value-of-type :string :google-auth-auto-create-accounts-domain))
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
"The Enterprise version of the LDAP integration is basically the same but also supports syncing user attributes."
|
||||
(:require
|
||||
[metabase-enterprise.sso.integrations.sso-utils :as sso-utils]
|
||||
[metabase.models.setting :refer [defsetting]]
|
||||
[metabase.models.user :as user]
|
||||
[metabase.premium-features.core :refer [defenterprise-schema]]
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.sso.core :as sso]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
|
||||
@@ -167,14 +167,6 @@
|
||||
(when-not (= delete-status :ok)
|
||||
(log/debugf "Unable to delete gdrive connection %s." id))))))
|
||||
|
||||
(mu/defn hm-get-all-connections :- :hm-client/http-reply
|
||||
"Get all connections from harbormaster."
|
||||
[]
|
||||
(hm.client/make-request :get "/api/v2/mb/connections"))
|
||||
|
||||
(comment
|
||||
(hm-get-all-connections))
|
||||
|
||||
(mu/defn hm-get-gdrive-conn :- :hm-client/http-reply
|
||||
"Get a specific gdrive connection by id."
|
||||
[id]
|
||||
@@ -277,7 +269,7 @@
|
||||
cannot-check-message
|
||||
{:gdrive/conn-id conn-id
|
||||
:hm/exception e})))))
|
||||
[hm-status {hm-status-code :status hm-body :body}] hm-response]
|
||||
[hm-status {hm-body :body}] hm-response]
|
||||
(if (= :ok hm-status)
|
||||
(let [{:keys [status status-reason error last-sync-at last-sync-started-at]
|
||||
:as _} (normalize-gdrive-conn hm-body)]
|
||||
@@ -304,30 +296,15 @@
|
||||
:last_sync_at (.getEpochSecond ^Instant (t/instant last-sync-at))
|
||||
:hm/response (loggable-response hm-response))
|
||||
(analytics/inc! :metabase-gsheets/connection-creation-error {:reason "status_error"})
|
||||
(log/errorf "Error getting status of connection %s: status-reason=`%s` error-detail=`%s`" conn-id (:status-reason hm-body) (:error-detail hm-body)))))
|
||||
(cond
|
||||
(empty? saved-setting)
|
||||
(log/errorf "Error getting status of connection %s: %s %s" conn-id (:status-reason hm-body) (:error-detail hm-body)))))
|
||||
(if (empty? saved-setting)
|
||||
{:status "not-connected"}
|
||||
|
||||
(= 403 hm-status-code)
|
||||
(let [[list-status list-response] (hm-get-all-connections)]
|
||||
(if (and (= :ok list-status) (not (some (partial = conn-id) (set (map :id (:body list-response))))))
|
||||
(u/prog1 {:status "not-connected"}
|
||||
(log/warnf "Removing google drive connection %s because harbormaster gives a 403 error for it." conn-id)
|
||||
(reset-gsheets-status!))
|
||||
;; It doesn't look like a spot where we can remove the connection, so we just return the error
|
||||
(assoc (setting->response saved-setting)
|
||||
:status "error"
|
||||
:error_message cannot-check-message
|
||||
:hm/response (loggable-response hm-response))))
|
||||
|
||||
:else
|
||||
(u/prog1 (assoc (setting->response saved-setting)
|
||||
:status "error"
|
||||
:error_message cannot-check-message
|
||||
:hm/response (loggable-response hm-response))
|
||||
(analytics/inc! :metabase-gsheets/connection-creation-error {:reason "status_error"})
|
||||
(log/errorf "Error getting status of connection %s: status-reason=`%s` error-detail=`%s`" conn-id (:status-reason hm-body) (:error-detail hm-body)))))))
|
||||
(log/errorf "Error getting status of connection %s: %s %s" conn-id (:status-reason hm-body) (:error-detail hm-body)))))))
|
||||
|
||||
(api.macros/defendpoint :get "/connection" :- :gsheets/response
|
||||
"Check the status of a connection. This endpoint gets polled by FE to determine when to
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[metabase-enterprise.gsheets.constants :as gsheets.constants]
|
||||
[metabase.models.setting :as setting :refer [defsetting]]
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.json :as json]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase-enterprise.internal-stats.core
|
||||
(ns metabase-enterprise.internal-stats
|
||||
(:require
|
||||
[metabase.premium-features.core :refer [defenterprise]]
|
||||
[metabase.settings.core :as setting]))
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.premium-features.core :refer [defenterprise]]))
|
||||
|
||||
(defenterprise embedding-settings
|
||||
"Boolean values that report on the state of different embedding configurations."
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns metabase-enterprise.llm.settings
|
||||
(:require
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.models.setting :as setting :refer [defsetting]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]))
|
||||
|
||||
(defsetting ee-openai-model
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
[metabase.api.open-api :as open-api]
|
||||
[metabase.api.routes.common :refer [+auth]]
|
||||
[metabase.models.collection :as collection]
|
||||
[metabase.query-analysis.core :as query-analysis]
|
||||
[metabase.models.query-analysis :as query-analysis]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.request.core :as request]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]))
|
||||
@@ -120,7 +121,7 @@
|
||||
[handler]
|
||||
(open-api/handler-with-open-api-spec
|
||||
(fn [request respond raise]
|
||||
(if (query-analysis/query-analysis-enabled)
|
||||
(if (public-settings/query-analysis-enabled)
|
||||
(handler request respond raise)
|
||||
(respond {:status 429 :body "Query Analysis must be enabled to use the Query Reference Validator"})))
|
||||
(fn [prefix]
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
[metabase.api.common :as api]
|
||||
[metabase.api.macros :as api.macros]
|
||||
[metabase.models.api-key :as api-key]
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.settings.deprecated-grab-bag :as public-settings]
|
||||
[metabase.models.setting :refer [defsetting]]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.secret :as u.secret]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
[metabase.api.routes.common :refer [+auth]]
|
||||
[metabase.logger :as logger]
|
||||
[metabase.models.serialization :as serdes]
|
||||
[metabase.settings.deprecated-grab-bag :as public-settings]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.compress :as u.compress]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[metabase-enterprise.serialization.serialize :as serialize]
|
||||
[metabase.config :as config]
|
||||
[metabase.models.interface :as mi]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.yaml :as yaml]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
[metabase.legacy-mbql.normalize :as mbql.normalize]
|
||||
[metabase.legacy-mbql.util :as mbql.u]
|
||||
[metabase.lib.util.match :as lib.util.match]
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.models.visualization-settings :as mb.viz]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.i18n :refer [trs]]
|
||||
[metabase.util.log :as log]
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
[clojure.string :as str]
|
||||
[metabase.api.common :as api]
|
||||
[metabase.api.macros :as api.macros]
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[saml20-clj.core :as saml]))
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[metabase-enterprise.sso.api.interface :as sso.i]
|
||||
[metabase-enterprise.sso.integrations.sso-settings :as sso-settings]
|
||||
[metabase-enterprise.sso.integrations.sso-utils :as sso-utils]
|
||||
[metabase.embedding.settings :as embed.settings]
|
||||
[metabase.embed.settings :as embed.settings]
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.request.core :as request]
|
||||
[metabase.session.models.session :as session]
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
[metabase-enterprise.sso.integrations.sso-utils :as sso-utils]
|
||||
[metabase.api.common :as api]
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.request.core :as request]
|
||||
[metabase.session.core :as session]
|
||||
[metabase.settings.deprecated-grab-bag :as public-settings]
|
||||
[metabase.sso.core :as sso]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [trs tru]]
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
information. Separating out this information creates a better dependency graph and avoids circular dependencies."
|
||||
(:require
|
||||
[metabase-enterprise.scim.api :as scim]
|
||||
[metabase.settings.core :as setting :refer [defsetting define-multi-setting-impl]]
|
||||
[metabase.settings.deprecated-grab-bag :as public-settings]
|
||||
[metabase.models.setting :as setting :refer [defsetting]]
|
||||
[metabase.models.setting.multi-setting :refer [define-multi-setting-impl]]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[metabase.channel.email.messages :as messages]
|
||||
[metabase.events :as events]
|
||||
[metabase.events.notification :as events.notification]
|
||||
[metabase.settings.deprecated-grab-bag :as public-settings]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.sso.core :as sso]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [trs tru]]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
(ns metabase-enterprise.stale
|
||||
(:require
|
||||
[malli.experimental.time]
|
||||
[metabase.embedding.settings :as embed.settings]
|
||||
[metabase.settings.core :as setting :refer [defsetting]]
|
||||
[metabase.embed.settings :as embed.settings]
|
||||
[metabase.models.setting :as setting :refer [defsetting]]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.malli :as mu]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns metabase-enterprise.cache.task.refresh-cache-configs
|
||||
(ns metabase-enterprise.task.cache
|
||||
(:require
|
||||
[clojurewerkz.quartzite.jobs :as jobs]
|
||||
[clojurewerkz.quartzite.schedule.cron :as cron]
|
||||
@@ -11,7 +11,7 @@
|
||||
[metabase.util.log :as log]
|
||||
[toucan2.core :as t2])
|
||||
(:import
|
||||
(java.util.concurrent Callable ExecutorService SynchronousQueue ThreadPoolExecutor TimeUnit)
|
||||
(java.util.concurrent Callable ExecutorService ThreadPoolExecutor TimeUnit SynchronousQueue)
|
||||
(org.apache.commons.lang3.concurrent BasicThreadFactory$Builder)
|
||||
(org.quartz.spi MutableTrigger)))
|
||||
|
||||
@@ -317,6 +317,8 @@
|
||||
(triggers/with-schedule
|
||||
(cron/cron-schedule "0 * * * * ? *"))))
|
||||
|
||||
(defmethod task/init! ::RefreshCacheConfigs [_]
|
||||
(when (premium-features/has-feature? :cache-granular-controls)
|
||||
(task/schedule-task! cache-job cache-trigger)))
|
||||
(defenterprise init-cache-task!
|
||||
"Inits periodical task checking for cache expiration"
|
||||
:feature :cache-granular-controls
|
||||
[]
|
||||
(task/schedule-task! cache-job cache-trigger))
|
||||
@@ -1,45 +1,13 @@
|
||||
(ns metabase.embedding.settings-test
|
||||
(ns metabase.embed.settings-test
|
||||
(:require
|
||||
[clojure.string :as str]
|
||||
[clojure.test :refer :all]
|
||||
[metabase.analytics.snowplow-test :as snowplow-test]
|
||||
[metabase.config :as config]
|
||||
[metabase.embedding.app-origins-sdk :as aos]
|
||||
[metabase.embedding.settings :as embed.settings]
|
||||
[metabase.premium-features.token-check :as token-check]
|
||||
[metabase.premium-features.token-check-test :as token-check-test]
|
||||
[metabase.embed.app-origins-sdk :as aos]
|
||||
[metabase.embed.settings :as embed.settings]
|
||||
[metabase.test :as mt]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(deftest show-static-embed-terms-test
|
||||
(mt/with-test-user :crowberto
|
||||
(mt/with-temporary-setting-values [show-static-embed-terms nil]
|
||||
(testing "Check if the user needs to accept the embedding licensing terms before static embedding"
|
||||
(when-not config/ee-available?
|
||||
(testing "should return true when user is OSS and has not accepted licensing terms"
|
||||
(is (embed.settings/show-static-embed-terms)))
|
||||
(testing "should return false when user is OSS and has already accepted licensing terms"
|
||||
(embed.settings/show-static-embed-terms! false)
|
||||
(is (not (embed.settings/show-static-embed-terms)))))
|
||||
(when config/ee-available?
|
||||
(testing "should return false when an EE user has a valid token"
|
||||
(with-redefs [token-check/fetch-token-status (fn [_x]
|
||||
{:valid true
|
||||
:status "fake"
|
||||
:features ["test" "fixture"]
|
||||
:trial false})]
|
||||
(mt/with-temporary-setting-values [premium-embedding-token (token-check-test/random-token)]
|
||||
(is (not (embed.settings/show-static-embed-terms)))
|
||||
(embed.settings/show-static-embed-terms! false)
|
||||
(is (not (embed.settings/show-static-embed-terms))))))
|
||||
(testing "when an EE user doesn't have a valid token"
|
||||
(mt/with-temporary-setting-values [premium-embedding-token nil show-static-embed-terms nil]
|
||||
(testing "should return true when the user has not accepted licensing terms"
|
||||
(is (embed.settings/show-static-embed-terms)))
|
||||
(testing "should return false when the user has already accepted licensing terms"
|
||||
(embed.settings/show-static-embed-terms! false)
|
||||
(is (not (embed.settings/show-static-embed-terms)))))))))))
|
||||
|
||||
(defn- embedding-event?
|
||||
"Used to make sure we only test against embedding-events in `snowplow-test/pop-event-data-and-user-id!`."
|
||||
[event]
|
||||
@@ -198,8 +166,7 @@
|
||||
:else (throw (ex-info "Invalid expected-behavior in test-origin-sync." {:expected-behavior expected-behavior}))))))
|
||||
|
||||
(deftest sync-origins-test
|
||||
;; n.b. illegal combinations will be disallowed by [[embed.settings/check-and-sync-settings-on-startup!]], so we don't
|
||||
;; test syncing for them.
|
||||
;; n.b. illegal combinations will be disallowed by [[embed.settings/check-and-sync-settings-on-startup!]], so we don't test syncing for them.
|
||||
(mt/with-premium-features #{:embedding :embedding-sdk}
|
||||
(mt/with-temporary-setting-values [enable-embedding true
|
||||
enable-embedding-sdk true
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require
|
||||
[clojure.test :refer :all]
|
||||
[metabase-enterprise.advanced-config.file :as advanced-config.file]
|
||||
[metabase.settings.core :refer [defsetting]]
|
||||
[metabase.models.setting :refer [defsetting]]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util :as u]))
|
||||
|
||||
|
||||
@@ -122,11 +122,6 @@
|
||||
"A 400 response from HM. nb: if you change this, change it in test_resources/gsheets/mock_hm_responses.edn"
|
||||
"93662bf7-b1c7-442b-80ec-18dee23894fa")
|
||||
|
||||
(def ^:private
|
||||
gdrive-403-error-link
|
||||
"A 403 response from HM. nb: if you change this, change it in test_resources/gsheets/mock_hm_responses.edn"
|
||||
"e5b50d83-c1d6-4382-8351-ff95a23af60e")
|
||||
|
||||
(def ^:private
|
||||
gdrive-200-error-link
|
||||
"A 200 'error' response from HM. nb: if you change this, change it in test_resources/gsheets/mock_hm_responses.edn"
|
||||
@@ -267,41 +262,6 @@
|
||||
(is (partial= {:status "error", :url "test-url" :created_by_id 2} response))
|
||||
(is (pos-int? (:db_id response)))))))))))
|
||||
|
||||
(deftest get-folder-test-invalid-connections
|
||||
(with-sample-db-as-dwh
|
||||
(let [mock-gsheet {:created-by-id 2
|
||||
:url "test-url",
|
||||
:created-at 15
|
||||
:db-id 1}]
|
||||
(mt/with-premium-features #{:etl-connections :attached-dwh :hosting}
|
||||
(testing "when the connection does not exist, it is deleted"
|
||||
(mt/with-temporary-setting-values [gsheets (assoc mock-gsheet :gdrive/conn-id gdrive-403-error-link)]
|
||||
(with-redefs [hm.client/make-request (partial mock-make-request happy-responses)]
|
||||
(let [response (mt/user-http-request :crowberto :get 200 "ee/gsheets/connection")]
|
||||
(is (= {:status "not-connected"} response))
|
||||
(is (= {} (gsheets)))))))
|
||||
(testing "when the HM gives a 403 response for the connection, but it shows in the connection list then it is not deleted"
|
||||
(mt/with-temporary-setting-values [gsheets (assoc mock-gsheet :gdrive/conn-id gdrive-active-link)]
|
||||
(with-redefs [hm.client/make-request (partial mock-make-request (assoc happy-responses
|
||||
{:method :get, :url (str "/api/v2/mb/connections/" gdrive-active-link), :body nil}
|
||||
[:error
|
||||
{:status 403,
|
||||
:body {:error "User not authorized to act over resource."}}]))]
|
||||
(let [response (mt/user-http-request :crowberto :get 200 "ee/gsheets/connection")]
|
||||
(is (= "error" (:status response)))
|
||||
(is (= 15 (:created-at (gsheets))))))))
|
||||
(testing "when the HM gives a 403 response for the connection, and the connection list fails, then it is not deleted"
|
||||
(mt/with-temporary-setting-values [gsheets (assoc mock-gsheet :gdrive/conn-id gdrive-403-error-link)]
|
||||
(with-redefs [hm.client/make-request (partial mock-make-request
|
||||
(assoc happy-responses
|
||||
{:method :get, :url "/api/v2/mb/connections", :body nil}
|
||||
[:error
|
||||
{:status 403,
|
||||
:body {:error "User not authorized to act over resource."}}]))]
|
||||
(let [response (mt/user-http-request :crowberto :get 200 "ee/gsheets/connection")]
|
||||
(is (= "error" (:status response)))
|
||||
(is (= 15 (:created-at (gsheets))))))))))))
|
||||
|
||||
(deftest delete-folder-test
|
||||
(with-sample-db-as-dwh
|
||||
(mt/with-premium-features #{:etl-connections :attached-dwh :hosting}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[clojure.test :refer :all]
|
||||
[java-time.api :as t]
|
||||
[metabase-enterprise.cache.strategies :as strategies]
|
||||
[metabase-enterprise.cache.task.refresh-cache-configs :as task.cache]
|
||||
[metabase-enterprise.task.cache :as task.cache]
|
||||
[metabase.models.query :as query]
|
||||
[metabase.query-processor :as qp]
|
||||
[metabase.query-processor.card :as qp.card]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[clojure.test :refer :all]
|
||||
[metabase-enterprise.enhancements.integrations.ldap :as ldap-ee]
|
||||
[metabase-enterprise.sso.integrations.sso-settings :as sso-settings]
|
||||
[metabase.settings.deprecated-grab-bag :as public-settings]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.sso.ldap :as ldap]
|
||||
[metabase.sso.ldap-test-util :as ldap.test]
|
||||
[metabase.test :as mt]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require
|
||||
[clojure.test :refer [deftest is testing]]
|
||||
[metabase-enterprise.gsheets.settings :as gsettings]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.models.setting :as setting]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(defmacro with-sample-db-as-dwh [& body]
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
(:require
|
||||
[clojure.test :refer [deftest is testing]]
|
||||
[metabase-enterprise.harbormaster.client :as hm.client]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.settings.models.setting]
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.test.util :as mt]))
|
||||
|
||||
(deftest ->config-good-test
|
||||
@@ -25,11 +24,11 @@
|
||||
;; mt/with-temporary-setting-values is not used here because we want to test the behavior of the function when the
|
||||
;; api-key is blank or nil, and mt/with-temporary-setting-values will not allow us to set the api-key to blank
|
||||
;; or nil.
|
||||
(with-redefs [metabase.settings.models.setting/get-raw-value (+value-for-setting grv :api-key "")]
|
||||
(with-redefs [setting/get-raw-value (+value-for-setting grv :api-key "")]
|
||||
(is (thrown-with-msg? Exception
|
||||
#"Missing api-key."
|
||||
(#'hm.client/->config))))
|
||||
(with-redefs [metabase.settings.models.setting/get-raw-value (+value-for-setting grv :api-key nil)]
|
||||
(with-redefs [setting/get-raw-value (+value-for-setting grv :api-key nil)]
|
||||
(is (thrown-with-msg? Exception
|
||||
#"Missing api-key."
|
||||
(#'hm.client/->config))))))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase-enterprise.internal-stats.core-test
|
||||
(ns metabase-enterprise.internal-stats-test
|
||||
(:require
|
||||
[clojure.test :refer [deftest testing is]]
|
||||
[metabase-enterprise.internal-stats.core :as sut]
|
||||
[metabase-enterprise.internal-stats :as sut]
|
||||
[metabase.test :as mt]))
|
||||
|
||||
(deftest enabled-embedding-static-test
|
||||
@@ -1,8 +1,8 @@
|
||||
(ns metabase-enterprise.public-settings-test
|
||||
(:require
|
||||
[clojure.test :refer :all]
|
||||
[metabase.embedding.settings :as embed.settings]
|
||||
[metabase.settings.deprecated-grab-bag :as public-settings]
|
||||
[metabase.embed.settings :as embed.settings]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.test :as mt]
|
||||
[metabase.test.fixtures :as fixtures]
|
||||
[metabase.test.util :as tu]))
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
[metabase-enterprise.serialization.v2.load :as serdes.load]
|
||||
[metabase-enterprise.serialization.v2.storage :as storage]
|
||||
[metabase.models.serialization :as serdes]
|
||||
[metabase.settings.core :as setting]
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.test :as mt]
|
||||
[metabase.test.generate :as test-gen]
|
||||
[metabase.util.yaml :as yaml]
|
||||
@@ -358,7 +358,7 @@
|
||||
|
||||
(testing "for settings"
|
||||
(let [settings (get @entities "Setting")]
|
||||
(is (every? setting/export?
|
||||
(is (every? @#'setting/export?
|
||||
(set (map (comp symbol :key) settings))))
|
||||
(is (= (into {} (for [{:keys [key value]} settings]
|
||||
[key value]))
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
[metabase.config :as config]
|
||||
[metabase.http-client :as client]
|
||||
[metabase.premium-features.token-check :as token-check]
|
||||
[metabase.settings.deprecated-grab-bag :as public-settings]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.test :as mt]
|
||||
[metabase.test.fixtures :as fixtures]
|
||||
[metabase.util :as u]
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
[metabase-enterprise.sso.integrations.sso-settings :as sso-settings]
|
||||
[metabase.http-client :as client]
|
||||
[metabase.premium-features.token-check :as token-check]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.request.core :as request]
|
||||
[metabase.session.core :as session]
|
||||
[metabase.settings.deprecated-grab-bag :as public-settings]
|
||||
[metabase.sso.init]
|
||||
[metabase.test :as mt]
|
||||
[metabase.test.fixtures :as fixtures]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
(ns metabase-enterprise.cache.task.refresh-cache-configs-test
|
||||
(ns metabase-enterprise.task.cache-test
|
||||
(:require
|
||||
[clojure.test :refer :all]
|
||||
[java-time.api :as t]
|
||||
[medley.core :as m]
|
||||
[metabase-enterprise.cache.task.refresh-cache-configs :as task.cache]
|
||||
[metabase-enterprise.task.cache :as task.cache]
|
||||
[metabase.premium-features.core :as premium-features]
|
||||
[metabase.query-processor :as qp]
|
||||
[metabase.query-processor.card :as qp.card]
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
setupDashboardEndpoints,
|
||||
setupDashboardQueryMetadataEndpoint,
|
||||
setupDatabasesEndpoints,
|
||||
setupLastDownloadFormatEndpoints,
|
||||
} from "__support__/server-mocks";
|
||||
import { setupDashcardQueryEndpoints } from "__support__/server-mocks/dashcard";
|
||||
import { setupNotificationChannelsEndpoints } from "__support__/server-mocks/pulse";
|
||||
@@ -151,8 +150,6 @@ const setup = async ({
|
||||
|
||||
setupDatabasesEndpoints([createMockDatabase()]);
|
||||
|
||||
setupLastDownloadFormatEndpoints();
|
||||
|
||||
const user = createMockUser();
|
||||
|
||||
const state = setupSdkState({
|
||||
|
||||
@@ -53,22 +53,15 @@ export const storybookSdkAuthDefaultConfig =
|
||||
export const CommonSdkStoryWrapper = (Story: StoryFn, context: any) => {
|
||||
const sdkTheme = context.globals.sdkTheme;
|
||||
const theme = sdkTheme ? storybookThemes[sdkTheme] : undefined;
|
||||
const locale = context.globals.locale;
|
||||
const user = context.globals.user;
|
||||
|
||||
const key = `${user}-${locale}`;
|
||||
const user = context.globals.user;
|
||||
|
||||
const authConfig = useMemo(() => {
|
||||
return getStorybookSdkAuthConfigForUser(user);
|
||||
}, [user]);
|
||||
|
||||
return (
|
||||
<MetabaseProvider
|
||||
authConfig={authConfig}
|
||||
theme={theme}
|
||||
key={key}
|
||||
locale={locale}
|
||||
>
|
||||
<MetabaseProvider authConfig={authConfig} theme={theme} key={user}>
|
||||
<Story />
|
||||
</MetabaseProvider>
|
||||
);
|
||||
|
||||
@@ -411,15 +411,14 @@ const HELPER_TEXT_STRINGS: HelpTextConfig[] = [
|
||||
name: "integer",
|
||||
structure: "integer",
|
||||
category: "conversion",
|
||||
description: () =>
|
||||
t`Converts a string or float value to an integer number.`,
|
||||
description: () => t`Converts a string to an integer.`,
|
||||
args: [
|
||||
{
|
||||
get name() {
|
||||
return t`value`;
|
||||
},
|
||||
get description() {
|
||||
return t`The string or float column to convert to integers. Float values are rounded.`;
|
||||
return t`The string column to convert to integers.`;
|
||||
},
|
||||
example: ["dimension", "User ID"],
|
||||
},
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import type {
|
||||
Parameter,
|
||||
ParameterValues,
|
||||
SearchParameterValuesRequest,
|
||||
} from "metabase-types/api";
|
||||
import type { Parameter, ParameterValues } from "metabase-types/api";
|
||||
|
||||
export const createMockParameter = (opts?: Partial<Parameter>): Parameter => ({
|
||||
id: "1",
|
||||
@@ -19,12 +15,3 @@ export const createMockParameterValues = (
|
||||
has_more_values: false,
|
||||
...opts,
|
||||
});
|
||||
|
||||
export const createMockSearchParameterValuesRequest = (
|
||||
opts?: Partial<SearchParameterValuesRequest>,
|
||||
): SearchParameterValuesRequest => ({
|
||||
parameter: createMockParameter(),
|
||||
field_ids: [],
|
||||
query: "",
|
||||
...opts,
|
||||
});
|
||||
|
||||
@@ -4,10 +4,10 @@ import type {
|
||||
Engine,
|
||||
EngineField,
|
||||
EngineSource,
|
||||
EnterpriseSettingKey,
|
||||
EnterpriseSettings,
|
||||
FontFile,
|
||||
SettingDefinition,
|
||||
SettingKey,
|
||||
Settings,
|
||||
TokenFeatures,
|
||||
TokenStatus,
|
||||
@@ -129,7 +129,7 @@ export const createMockTokenFeatures = (
|
||||
});
|
||||
|
||||
export const createMockSettingDefinition = <
|
||||
Key extends EnterpriseSettingKey = EnterpriseSettingKey,
|
||||
Key extends SettingKey = SettingKey,
|
||||
>(
|
||||
opts: SettingDefinition<Key>,
|
||||
): SettingDefinition<Key> => ({
|
||||
|
||||
@@ -255,25 +255,17 @@ export type PasswordComplexity = {
|
||||
|
||||
export type SessionCookieSameSite = "lax" | "strict" | "none";
|
||||
|
||||
export interface SettingDefinition<
|
||||
Key extends EnterpriseSettingKey = EnterpriseSettingKey,
|
||||
> {
|
||||
export interface SettingDefinition<Key extends SettingKey = SettingKey> {
|
||||
key: Key;
|
||||
env_name?: string;
|
||||
is_env_setting?: boolean;
|
||||
value?: EnterpriseSettingValue<Key>;
|
||||
default?: EnterpriseSettingValue<Key>;
|
||||
value?: SettingValue<Key>;
|
||||
default?: SettingValue<Key>;
|
||||
display_name?: string;
|
||||
description?: string | ReactNode | null;
|
||||
type?: InputSettingType;
|
||||
}
|
||||
|
||||
export type SettingDefinitionMap<
|
||||
T extends EnterpriseSettingKey = EnterpriseSettingKey,
|
||||
> = {
|
||||
[K in T]: SettingDefinition<K>;
|
||||
};
|
||||
|
||||
export type UpdateChannel = "latest" | "beta" | "nightly";
|
||||
|
||||
export interface OpenAiModel {
|
||||
|
||||
@@ -121,14 +121,6 @@ export type UserKeyValue =
|
||||
namespace: "user_acknowledgement";
|
||||
key: string;
|
||||
value: boolean;
|
||||
}
|
||||
| {
|
||||
namespace: "last_download_format";
|
||||
key: string;
|
||||
value: {
|
||||
last_download_format: "csv" | "xlsx" | "json" | "png";
|
||||
last_table_download_format: "csv" | "xlsx" | "json";
|
||||
};
|
||||
};
|
||||
|
||||
export type UserKeyValueKey = Pick<UserKeyValue, "namespace" | "key">;
|
||||
|
||||
@@ -245,15 +245,11 @@ describe("MetadataFieldSettings", () => {
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should display type casting settings for float fields", async () => {
|
||||
it("should not display type casting settings for non-supported fields", async () => {
|
||||
await setup({ field: ORDERS_DISCOUNT_FIELD });
|
||||
expect(
|
||||
screen.getByText("Cast to a specific data type"),
|
||||
).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByText("Don't cast"));
|
||||
await userEvent.type(screen.getByPlaceholderText("Find..."), "Float");
|
||||
expect(screen.getByText("Float → Integer")).toBeInTheDocument();
|
||||
screen.queryByText("Cast to a specific data type"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should show an access denied error if the foreign key field has an inaccessible target", async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import cx from "classnames";
|
||||
import PropTypes from "prop-types";
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import { t } from "ttag";
|
||||
|
||||
@@ -8,37 +9,29 @@ import CS from "metabase/css/core/index.css";
|
||||
import Typeahead from "metabase/hoc/Typeahead";
|
||||
import { color } from "metabase/lib/colors";
|
||||
import { Icon } from "metabase/ui";
|
||||
import type { User } from "metabase-types/api";
|
||||
|
||||
import { AddMemberAutocompleteSuggestionRoot } from "./AddMemberRow.styled";
|
||||
import { AddRow } from "./AddRow";
|
||||
|
||||
interface AddMemberRowProps {
|
||||
users: User[];
|
||||
excludeIds: Set<number>;
|
||||
onCancel: () => void;
|
||||
onDone: (userIds: number[]) => void;
|
||||
}
|
||||
AddMemberRow.propTypes = {
|
||||
users: PropTypes.array.isRequired,
|
||||
excludeIds: PropTypes.object,
|
||||
onCancel: PropTypes.func.isRequired,
|
||||
onDone: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export function AddMemberRow({
|
||||
users,
|
||||
excludeIds,
|
||||
onCancel,
|
||||
onDone,
|
||||
}: AddMemberRowProps) {
|
||||
const rowRef = useRef<HTMLDivElement>(null);
|
||||
export default function AddMemberRow({ users, excludeIds, onCancel, onDone }) {
|
||||
const rowRef = useRef(null);
|
||||
const [text, setText] = useState("");
|
||||
const [selectedUsersById, setSelectedUsersById] = useState<Map<number, User>>(
|
||||
new Map(),
|
||||
);
|
||||
const [selectedUsersById, setSelectedUsersById] = useState(new Map());
|
||||
|
||||
const handleRemoveUser = (user: User) => {
|
||||
const handleRemoveUser = (user) => {
|
||||
const newSelectedUsersById = new Map(selectedUsersById);
|
||||
newSelectedUsersById.delete(user.id);
|
||||
setSelectedUsersById(newSelectedUsersById);
|
||||
};
|
||||
|
||||
const handleAddUser = (user: User) => {
|
||||
const handleAddUser = (user) => {
|
||||
const newSelectedUsersById = new Map(selectedUsersById);
|
||||
newSelectedUsersById.set(user.id, user);
|
||||
setSelectedUsersById(newSelectedUsersById);
|
||||
@@ -59,7 +52,7 @@ export function AddMemberRow({
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td colSpan={4} style={{ padding: 0 }}>
|
||||
<td colSpan="4" style={{ padding: 0 }}>
|
||||
<AddRow
|
||||
ref={rowRef}
|
||||
value={text}
|
||||
@@ -115,40 +108,42 @@ const getColorPalette = () => [
|
||||
color("accent4"),
|
||||
];
|
||||
|
||||
interface AddMemberTypeaheadPopoverProps {
|
||||
suggestions: User[];
|
||||
selectedSuggestion: User | null;
|
||||
onSuggestionAccepted: (user: User) => void;
|
||||
target: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
const AddMemberTypeaheadPopoverPropTypes = {
|
||||
suggestions: PropTypes.array,
|
||||
selectedSuggestion: PropTypes.object,
|
||||
onSuggestionAccepted: PropTypes.func.isRequired,
|
||||
target: PropTypes.shape({
|
||||
current: PropTypes.instanceOf(Element),
|
||||
}),
|
||||
};
|
||||
|
||||
const AddMemberTypeaheadPopover = Typeahead({
|
||||
optionFilter: (text: string, user: User) =>
|
||||
optionFilter: (text, user) =>
|
||||
(user.common_name || "").toLowerCase().includes(text.toLowerCase()),
|
||||
optionIsEqual: (userA: User, userB: User) => userA.id === userB.id,
|
||||
optionIsEqual: (userA, userB) => userA.id === userB.id,
|
||||
})(function AddMemberTypeaheadPopover({
|
||||
suggestions,
|
||||
selectedSuggestion,
|
||||
onSuggestionAccepted,
|
||||
target,
|
||||
}: AddMemberTypeaheadPopoverProps) {
|
||||
}) {
|
||||
const colors = useMemo(getColorPalette, []);
|
||||
|
||||
return (
|
||||
<TippyPopover
|
||||
className={CS.bordered}
|
||||
offset={[0, 0]}
|
||||
offset={0}
|
||||
placement="bottom-start"
|
||||
visible={suggestions.length > 0}
|
||||
reference={target}
|
||||
content={
|
||||
suggestions &&
|
||||
suggestions.map((user: User, index: number) => (
|
||||
suggestions.map((user, index) => (
|
||||
<AddMemberAutocompleteSuggestion
|
||||
key={index}
|
||||
user={user}
|
||||
color={colors[index % colors.length]}
|
||||
selected={!!selectedSuggestion && user.id === selectedSuggestion.id}
|
||||
selected={selectedSuggestion && user.id === selectedSuggestion.id}
|
||||
onClick={onSuggestionAccepted.bind(null, user)}
|
||||
/>
|
||||
))
|
||||
@@ -157,19 +152,16 @@ const AddMemberTypeaheadPopover = Typeahead({
|
||||
);
|
||||
});
|
||||
|
||||
interface AddMemberAutocompleteSuggestionProps {
|
||||
user: User;
|
||||
color: string;
|
||||
selected: boolean;
|
||||
onClick: () => void;
|
||||
}
|
||||
AddMemberTypeaheadPopover.propTypes = AddMemberTypeaheadPopoverPropTypes;
|
||||
|
||||
function AddMemberAutocompleteSuggestion({
|
||||
user,
|
||||
color,
|
||||
selected,
|
||||
onClick,
|
||||
}: AddMemberAutocompleteSuggestionProps) {
|
||||
AddMemberAutocompleteSuggestion.propTypes = {
|
||||
user: PropTypes.object.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
selected: PropTypes.bool,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
function AddMemberAutocompleteSuggestion({ user, color, selected, onClick }) {
|
||||
return (
|
||||
<AddMemberAutocompleteSuggestionRoot
|
||||
isSelected={selected}
|
||||
@@ -1,21 +1,11 @@
|
||||
import cx from "classnames";
|
||||
import { type ChangeEvent, type Ref, forwardRef } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { forwardRef } from "react";
|
||||
import { t } from "ttag";
|
||||
|
||||
import ButtonsS from "metabase/css/components/buttons.module.css";
|
||||
import CS from "metabase/css/core/index.css";
|
||||
|
||||
interface AddRowProps {
|
||||
value: string;
|
||||
isValid: boolean;
|
||||
placeholder?: string;
|
||||
onKeyDown?: (event: React.KeyboardEvent) => void;
|
||||
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
onDone: () => void;
|
||||
onCancel: () => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const AddRow = forwardRef(function AddRow(
|
||||
{
|
||||
value,
|
||||
@@ -26,8 +16,8 @@ export const AddRow = forwardRef(function AddRow(
|
||||
onDone,
|
||||
onCancel,
|
||||
children,
|
||||
}: AddRowProps,
|
||||
ref: Ref<HTMLDivElement>,
|
||||
},
|
||||
ref,
|
||||
) {
|
||||
return (
|
||||
<div
|
||||
@@ -69,3 +59,14 @@ export const AddRow = forwardRef(function AddRow(
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
AddRow.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
isValid: PropTypes.bool.isRequired,
|
||||
placeholder: PropTypes.string,
|
||||
onKeyDown: PropTypes.func,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onDone: PropTypes.func.isRequired,
|
||||
onCancel: PropTypes.func.isRequired,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import cx from "classnames";
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
import { msgid, ngettext, t } from "ttag";
|
||||
@@ -15,8 +16,6 @@ import {
|
||||
import { connect } from "metabase/lib/redux";
|
||||
import { PLUGIN_GROUP_MANAGERS } from "metabase/plugins";
|
||||
import { getUser } from "metabase/selectors/user";
|
||||
import type { Group, Member, User } from "metabase-types/api";
|
||||
import type { State } from "metabase-types/store";
|
||||
|
||||
import {
|
||||
createMembership,
|
||||
@@ -28,11 +27,7 @@ import { getGroupMemberships, getMembershipsByUser } from "../selectors";
|
||||
|
||||
import GroupMembersTable from "./GroupMembersTable";
|
||||
|
||||
interface GroupDescriptionProps {
|
||||
group: Group;
|
||||
}
|
||||
|
||||
const GroupDescription = ({ group }: GroupDescriptionProps) =>
|
||||
const GroupDescription = ({ group }) =>
|
||||
isDefaultGroup(group) ? (
|
||||
<div className={cx(CS.px2, CS.textMeasure)}>
|
||||
<p>
|
||||
@@ -54,43 +49,13 @@ const GroupDescription = ({ group }: GroupDescriptionProps) =>
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
interface GroupDetailStateProps {
|
||||
groupMemberships: Member[];
|
||||
membershipsByUser: Record<User["id"], Member[]>;
|
||||
currentUser: User | null;
|
||||
}
|
||||
|
||||
interface GroupDetailOwnProps {
|
||||
group: Group;
|
||||
users: User[];
|
||||
}
|
||||
|
||||
const mapStateToProps = (
|
||||
state: State,
|
||||
props: GroupDetailOwnProps,
|
||||
): GroupDetailStateProps => ({
|
||||
// @ts-expect-error -- .js file imports with wrong type here, not worth fixing as we should just move to RTKQuery
|
||||
const mapStateToProps = (state, props) => ({
|
||||
groupMemberships: getGroupMemberships(state, props),
|
||||
membershipsByUser: getMembershipsByUser(state),
|
||||
currentUser: getUser(state),
|
||||
});
|
||||
|
||||
interface GroupDetailDispatchProps {
|
||||
createMembership: (membership: { groupId: number; userId: number }) => void;
|
||||
updateMembership: (membership: Member) => void;
|
||||
deleteMembership: (membershipId: number) => void;
|
||||
loadMemberships: () => void;
|
||||
confirmDeleteMembershipAction: (
|
||||
membershipId: number,
|
||||
userMemberships: Member[],
|
||||
) => void;
|
||||
confirmUpdateMembershipAction: (
|
||||
membership: Member,
|
||||
userMemberships: Member[],
|
||||
) => void;
|
||||
}
|
||||
|
||||
const mapDispatchToProps: GroupDetailDispatchProps = {
|
||||
const mapDispatchToProps = {
|
||||
createMembership,
|
||||
deleteMembership,
|
||||
updateMembership,
|
||||
@@ -107,11 +72,7 @@ const mapDispatchToProps: GroupDetailDispatchProps = {
|
||||
),
|
||||
};
|
||||
|
||||
type GroupDetailProps = GroupDetailStateProps &
|
||||
GroupDetailOwnProps &
|
||||
GroupDetailDispatchProps;
|
||||
|
||||
const GroupDetailInner = ({
|
||||
const GroupDetail = ({
|
||||
currentUser,
|
||||
group,
|
||||
users,
|
||||
@@ -123,22 +84,22 @@ const GroupDetailInner = ({
|
||||
loadMemberships,
|
||||
confirmDeleteMembershipAction,
|
||||
confirmUpdateMembershipAction,
|
||||
}: GroupDetailProps) => {
|
||||
}) => {
|
||||
const { modalContent, show } = useConfirmation();
|
||||
const [addUserVisible, setAddUserVisible] = useState(false);
|
||||
const [alertMessage, setAlertMessage] = useState<string | null>(null);
|
||||
const [alertMessage, setAlertMessage] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
loadMemberships();
|
||||
}, [loadMemberships]);
|
||||
|
||||
const alert = (message: string | null) => setAlertMessage(message);
|
||||
const alert = (alertMessage) => setAlertMessage(alertMessage);
|
||||
|
||||
const onAddUsersClicked = () => setAddUserVisible(true);
|
||||
|
||||
const onAddUserCanceled = () => setAddUserVisible(false);
|
||||
|
||||
const onAddUserDone = async (userIds: number[]) => {
|
||||
const onAddUserDone = async (userIds) => {
|
||||
setAddUserVisible(false);
|
||||
try {
|
||||
await Promise.all(
|
||||
@@ -150,18 +111,11 @@ const GroupDetailInner = ({
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
alert(errorMessage);
|
||||
alert(error && typeof error.data ? error.data : error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = async (membership: Member) => {
|
||||
if (!currentUser) {
|
||||
throw new Error("currentUser is not defined");
|
||||
return;
|
||||
}
|
||||
|
||||
const handleChange = async (membership) => {
|
||||
const confirmation = PLUGIN_GROUP_MANAGERS.getChangeMembershipConfirmation(
|
||||
currentUser,
|
||||
membership,
|
||||
@@ -173,7 +127,6 @@ const GroupDetailInner = ({
|
||||
|
||||
show({
|
||||
...confirmation,
|
||||
title: confirmation.title ?? "",
|
||||
onConfirm: () =>
|
||||
confirmUpdateMembershipAction(
|
||||
membership,
|
||||
@@ -182,12 +135,7 @@ const GroupDetailInner = ({
|
||||
});
|
||||
};
|
||||
|
||||
const handleRemove = async (membershipId: number) => {
|
||||
if (!currentUser) {
|
||||
throw new Error("currentUser is not defined");
|
||||
return;
|
||||
}
|
||||
|
||||
const handleRemove = async (membershipId) => {
|
||||
const confirmation = PLUGIN_GROUP_MANAGERS.getRemoveMembershipConfirmation(
|
||||
currentUser,
|
||||
membershipsByUser[currentUser.id],
|
||||
@@ -200,7 +148,6 @@ const GroupDetailInner = ({
|
||||
|
||||
show({
|
||||
...confirmation,
|
||||
title: confirmation.title ?? "",
|
||||
onConfirm: () =>
|
||||
confirmDeleteMembershipAction(
|
||||
membershipId,
|
||||
@@ -224,7 +171,7 @@ const GroupDetailInner = ({
|
||||
</Fragment>
|
||||
}
|
||||
buttonText={t`Add members`}
|
||||
buttonAction={canEditMembership(group) ? onAddUsersClicked : undefined}
|
||||
buttonAction={canEditMembership(group) ? onAddUsersClicked : null}
|
||||
buttonDisabled={addUserVisible}
|
||||
>
|
||||
<GroupDescription group={group} />
|
||||
@@ -246,7 +193,4 @@ const GroupDetailInner = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const GroupDetail = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(GroupDetailInner);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(GroupDetail);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user